commit c70248a520408d876a49d9b428b5f4313b34fcea Author: Devin Jankowski Date: Wed Jun 21 12:46:23 2023 -0400 Initial Commit diff --git a/Ionic/Ionic.Zip.dll b/Ionic/Ionic.Zip.dll new file mode 100644 index 0000000..1dc0338 Binary files /dev/null and b/Ionic/Ionic.Zip.dll differ diff --git a/Ionic/Ionic.Zip.pdb b/Ionic/Ionic.Zip.pdb new file mode 100644 index 0000000..553bd4b Binary files /dev/null and b/Ionic/Ionic.Zip.pdb differ diff --git a/Ionic/Ionic.Zip.xml b/Ionic/Ionic.Zip.xml new file mode 100644 index 0000000..a90fbe0 --- /dev/null +++ b/Ionic/Ionic.Zip.xml @@ -0,0 +1,18132 @@ + + + + Ionic.Zip + + + + + An enum that specifies the source of the ZipEntry. + + + + + Default value. Invalid on a bonafide ZipEntry. + + + + + The entry was instantiated by calling AddFile() or another method that + added an entry from the filesystem. + + + + + The entry was instantiated via or + . + + + + + The ZipEntry was instantiated by reading a zipfile. + + + + + The content for the ZipEntry will be or was provided by the WriteDelegate. + + + + + The content for the ZipEntry will be obtained from the stream dispensed by the OpenDelegate. + The entry was instantiated via . + + + + + The content for the ZipEntry will be or was obtained from a ZipOutputStream. + + + + + Provides a stream metaphor for generating zip files. + + + + + This class writes zip files, as defined in the specification + for zip files described by PKWare. The compression for this + implementation is provided by a managed-code version of Zlib, included with + DotNetZip in the classes in the Ionic.Zlib namespace. + + + + This class provides an alternative programming model to the one enabled by the + class. Use this when creating zip files, as an + alternative to the class, when you would like to use a + Stream type to write the zip file. + + + + Both the ZipOutputStream class and the ZipFile class can be used + to create zip files. Both of them support many of the common zip features, + including Unicode, different compression levels, and ZIP64. They provide + very similar performance when creating zip files. + + + + The ZipFile class is generally easier to use than + ZipOutputStream and should be considered a higher-level interface. For + example, when creating a zip file via calls to the PutNextEntry() and + Write() methods on the ZipOutputStream class, the caller is + responsible for opening the file, reading the bytes from the file, writing + those bytes into the ZipOutputStream, setting the attributes on the + ZipEntry, and setting the created, last modified, and last accessed + timestamps on the zip entry. All of these things are done automatically by a + call to ZipFile.AddFile(). + For this reason, the ZipOutputStream is generally recommended for use + only when your application emits arbitrary data, not necessarily data from a + filesystem file, directly into a zip file, and does so using a Stream + metaphor. + + + + Aside from the differences in programming model, there are other + differences in capability between the two classes. + + + + + ZipFile can be used to read and extract zip files, in addition to + creating zip files. ZipOutputStream cannot read zip files. If you want + to use a stream to read zip files, check out the class. + + + + ZipOutputStream does not support the creation of segmented or spanned + zip files. + + + + ZipOutputStream cannot produce a self-extracting archive. + + + + + Be aware that the ZipOutputStream class implements the interface. In order for + ZipOutputStream to produce a valid zip file, you use use it within + a using clause (Using in VB), or call the Dispose() method + explicitly. See the examples for how to employ a using clause. + + + + Also, a note regarding compression performance: On the desktop .NET + Framework, DotNetZip can use a multi-threaded compression implementation + that provides significant speed increases on large files, over 300k or so, + at the cost of increased memory use at runtime. (The output of the + compression is almost exactly the same size). But, the multi-threaded + approach incurs a performance hit on smaller files. There's no way for the + ZipOutputStream to know whether parallel compression will be beneficial, + because the ZipOutputStream does not know how much data you will write + through the stream. You may wish to set the property to zero, if you are compressing + large files through ZipOutputStream. This will cause parallel + compression to be used, always. + + + + + + Create a ZipOutputStream, wrapping an existing stream. + + + + + The class is generally easier to use when creating + zip files. The ZipOutputStream offers a different metaphor for creating a + zip file, based on the class. + + + + + + The stream to wrap. It must be writable. This stream will be closed at + the time the ZipOutputStream is closed. + + + + + This example shows how to create a zip file, using the + ZipOutputStream class. + + + private void Zipup() + { + if (filesToZip.Count == 0) + { + System.Console.WriteLine("Nothing to do."); + return; + } + + using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) + { + using (var output= new ZipOutputStream(raw)) + { + output.Password = "VerySecret!"; + output.Encryption = EncryptionAlgorithm.WinZipAes256; + + foreach (string inputFileName in filesToZip) + { + System.Console.WriteLine("file: {0}", inputFileName); + + output.PutNextEntry(inputFileName); + using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write )) + { + byte[] buffer= new byte[2048]; + int n; + while ((n= input.Read(buffer,0,buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + } + + + + Private Sub Zipup() + Dim outputFileName As String = "XmlData.zip" + Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") + If (filesToZip.Length = 0) Then + Console.WriteLine("Nothing to do.") + Else + Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite) + Using output As ZipOutputStream = New ZipOutputStream(raw) + output.Password = "VerySecret!" + output.Encryption = EncryptionAlgorithm.WinZipAes256 + Dim inputFileName As String + For Each inputFileName In filesToZip + Console.WriteLine("file: {0}", inputFileName) + output.PutNextEntry(inputFileName) + Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) + Dim n As Integer + Dim buffer As Byte() = New Byte(2048) {} + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + Next + End Using + End Using + End If + End Sub + + + + + + Create a ZipOutputStream that writes to a filesystem file. + + + + The class is generally easier to use when creating + zip files. The ZipOutputStream offers a different metaphor for creating a + zip file, based on the class. + + + + The name of the zip file to create. + + + + + This example shows how to create a zip file, using the + ZipOutputStream class. + + + private void Zipup() + { + if (filesToZip.Count == 0) + { + System.Console.WriteLine("Nothing to do."); + return; + } + + using (var output= new ZipOutputStream(outputFileName)) + { + output.Password = "VerySecret!"; + output.Encryption = EncryptionAlgorithm.WinZipAes256; + + foreach (string inputFileName in filesToZip) + { + System.Console.WriteLine("file: {0}", inputFileName); + + output.PutNextEntry(inputFileName); + using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, + FileShare.Read | FileShare.Write )) + { + byte[] buffer= new byte[2048]; + int n; + while ((n= input.Read(buffer,0,buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + + + + Private Sub Zipup() + Dim outputFileName As String = "XmlData.zip" + Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") + If (filesToZip.Length = 0) Then + Console.WriteLine("Nothing to do.") + Else + Using output As ZipOutputStream = New ZipOutputStream(outputFileName) + output.Password = "VerySecret!" + output.Encryption = EncryptionAlgorithm.WinZipAes256 + Dim inputFileName As String + For Each inputFileName In filesToZip + Console.WriteLine("file: {0}", inputFileName) + output.PutNextEntry(inputFileName) + Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) + Dim n As Integer + Dim buffer As Byte() = New Byte(2048) {} + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + Next + End Using + End If + End Sub + + + + + + Create a ZipOutputStream. + + + + See the documentation for the ZipOutputStream(Stream) + constructor for an example. + + + + The stream to wrap. It must be writable. + + + + true if the application would like the stream + to remain open after the ZipOutputStream has been closed. + + + + Provides a string representation of the instance. + + + This can be useful for debugging purposes. + + + a string representation of the instance. + + + + Returns true if an entry by the given name has already been written + to the ZipOutputStream. + + + + The name of the entry to scan for. + + + + true if an entry by the given name has already been written. + + + + + Write the data from the buffer to the stream. + + + + As the application writes data into this stream, the data may be + compressed and encrypted before being written out to the underlying + stream, depending on the settings of the + and the properties. + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Specify the name of the next entry that will be written to the zip file. + + + + + Call this method just before calling , to + specify the name of the entry that the next set of bytes written to + the ZipOutputStream belongs to. All subsequent calls to Write, + until the next call to PutNextEntry, + will be inserted into the named entry in the zip file. + + + + If the used in PutNextEntry() ends in + a slash, then the entry added is marked as a directory. Because directory + entries do not contain data, a call to Write(), before an + intervening additional call to PutNextEntry(), will throw an + exception. + + + + If you don't call Write() between two calls to + PutNextEntry(), the first entry is inserted into the zip file as a + file of zero size. This may be what you want. + + + + Because PutNextEntry() closes out the prior entry, if any, this + method may throw if there is a problem with the prior entry. + + + + This method returns the ZipEntry. You can modify public properties + on the ZipEntry, such as , , and so on, until the first call to + ZipOutputStream.Write(), or until the next call to + PutNextEntry(). If you modify the ZipEntry after + having called Write(), you may get a runtime exception, or you may + silently get an invalid zip archive. + + + + + + + This example shows how to create a zip file, using the + ZipOutputStream class. + + + private void Zipup() + { + using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) + { + using (var output= new ZipOutputStream(fs)) + { + output.Password = "VerySecret!"; + output.Encryption = EncryptionAlgorithm.WinZipAes256; + output.PutNextEntry("entry1.txt"); + byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1."); + output.Write(buffer,0,buffer.Length); + output.PutNextEntry("entry2.txt"); // this will be zero length + output.PutNextEntry("entry3.txt"); + buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3."); + output.Write(buffer,0,buffer.Length); + } + } + } + + + + + The name of the entry to be added, including any path to be used + within the zip file. + + + + The ZipEntry created. + + + + + + Dispose the stream + + + + + This method writes the Zip Central directory, then closes the stream. The + application must call Dispose() (or Close) in order to produce a valid zip file. + + + + Typically the application will call Dispose() implicitly, via a using + statement in C#, or a Using statement in VB. + + + + + set this to true, always. + + + + This is a no-op. + + + + + This method always throws a NotSupportedException. + + ignored + ignored + ignored + nothing + + + + This method always throws a NotSupportedException. + + ignored + ignored + nothing + + + + This method always throws a NotSupportedException. + + ignored + + + + Sets the password to be used on the ZipOutputStream instance. + + + + + + When writing a zip archive, this password is applied to the entries, not + to the zip archive itself. It applies to any ZipEntry subsequently + written to the ZipOutputStream. + + + + Using a password does not encrypt or protect the "directory" of the + archive - the list of entries contained in the archive. If you set the + Password property, the password actually applies to individual + entries that are added to the archive, subsequent to the setting of this + property. The list of filenames in the archive that is eventually created + will appear in clear text, but the contents of the individual files are + encrypted. This is how Zip encryption works. + + + + If you set this property, and then add a set of entries to the archive via + calls to PutNextEntry, then each entry is encrypted with that + password. You may also want to change the password between adding + different entries. If you set the password, add an entry, then set the + password to null (Nothing in VB), and add another entry, the + first entry is encrypted and the second is not. + + + + When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added + to the ZipFile. If you set the Password to a non-null value and do not + set , then PKZip 2.0 ("Weak") encryption is used. + This encryption is relatively weak but is very interoperable. If + you set the password to a null value (Nothing in VB), + Encryption is reset to None. + + + + Special case: if you wrap a ZipOutputStream around a non-seekable stream, + and use encryption, and emit an entry of zero bytes, the Close() or + PutNextEntry() following the entry will throw an exception. + + + + + + + The Encryption to use for entries added to the ZipOutputStream. + + + + + The specified Encryption is applied to the entries subsequently + written to the ZipOutputStream instance. + + + + If you set this to something other than + EncryptionAlgorithm.None, you will also need to set the + to a non-null, non-empty value in + order to actually get encryption on the entry. + + + + + ZipOutputStream.Password + ZipEntry.Encryption + + + + Size of the work buffer to use for the ZLIB codec during compression. + + + + Setting this may affect performance. For larger files, setting this to a + larger size may improve performance, but I'm not sure. Sorry, I don't + currently have good recommendations on how to set it. You can test it if + you like. + + + + + The compression strategy to use for all entries. + + + + Set the Strategy used by the ZLIB-compatible compressor, when compressing + data for the entries in the zip archive. Different compression strategies + work better on different sorts of data. The strategy parameter can affect + the compression ratio and the speed of compression but not the correctness + of the compresssion. For more information see . + + + + + The type of timestamp attached to the ZipEntry. + + + + Set this in order to specify the kind of timestamp that should be emitted + into the zip file for each entry. + + + + + Sets the compression level to be used for entries subsequently added to + the zip archive. + + + + + Varying the compression level used on entries can affect the + size-vs-speed tradeoff when compression and decompressing data streams + or files. + + + + As with some other properties on the ZipOutputStream class, like , and , + setting this property on a ZipOutputStream + instance will cause the specified CompressionLevel to be used on all + items that are subsequently added to the + ZipOutputStream instance. + + + + If you do not set this property, the default compression level is used, + which normally gives a good balance of compression efficiency and + compression speed. In some tests, using BestCompression can + double the time it takes to compress, while delivering just a small + increase in compression efficiency. This behavior will vary with the + type of data you compress. If you are in doubt, just leave this setting + alone, and accept the default. + + + + + + The compression method used on each entry added to the ZipOutputStream. + + + + + A comment attached to the zip archive. + + + + + + The application sets this property to specify a comment to be embedded + into the generated zip archive. + + + + According to PKWARE's + zip specification, the comment is not encrypted, even if there is a + password set on the zip file. + + + + The specification does not describe how to indicate the encoding used + on a comment string. Many "compliant" zip tools and libraries use + IBM437 as the code page for comments; DotNetZip, too, follows that + practice. On the other hand, there are situations where you want a + Comment to be encoded with something else, for example using code page + 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the + comment following the same procedure it follows for encoding + filenames: (a) if is + Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the + alternate encoding (). (c) if is AsNecessary, it uses the + alternate encoding only if the default encoding is not sufficient for + encoding the comment - in other words if decoding the result does not + produce the original string. This decision is taken at the time of + the call to ZipFile.Save(). + + + + + + + Specify whether to use ZIP64 extensions when saving a zip archive. + + + + + The default value for the property is . is + safest, in the sense that you will not get an Exception if a + pre-ZIP64 limit is exceeded. + + + + You must set this property before calling Write(). + + + + + + + Indicates whether ZIP64 extensions were used when saving the zip archive. + + + + The value is defined only after the ZipOutputStream has been closed. + + + + + Whether the ZipOutputStream should use case-insensitive comparisons when + checking for uniqueness of zip entries. + + + + + Though the zip specification doesn't prohibit zipfiles with duplicate + entries, Sane zip files have no duplicates, and the DotNetZip library + cannot create zip files with duplicate entries. If an application attempts + to call with a name that duplicates one + already used within the archive, the library will throw an Exception. + + + This property allows the application to specify whether the + ZipOutputStream instance considers ordinal case when checking for + uniqueness of zip entries. + + + + + + Indicates whether to encode entry filenames and entry comments using + Unicode (UTF-8). + + + + + The + PKWare zip specification provides for encoding file names and file + comments in either the IBM437 code page, or in UTF-8. This flag selects + the encoding according to that specification. By default, this flag is + false, and filenames and comments are encoded into the zip file in the + IBM437 codepage. Setting this flag to true will specify that filenames + and comments that cannot be encoded with IBM437 will be encoded with + UTF-8. + + + + Zip files created with strict adherence to the PKWare specification with + respect to UTF-8 encoding can contain entries with filenames containing + any combination of Unicode characters, including the full range of + characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other + alphabets. However, because at this time, the UTF-8 portion of the PKWare + specification is not broadly supported by other zip libraries and + utilities, such zip files may not be readable by your favorite zip tool or + archiver. In other words, interoperability will decrease if you set this + flag to true. + + + + In particular, Zip files created with strict adherence to the PKWare + specification with respect to UTF-8 encoding will not work well with + Explorer in Windows XP or Windows Vista, because Windows compressed + folders, as far as I know, do not support UTF-8 in zip files. Vista can + read the zip files, but shows the filenames incorrectly. Unpacking from + Windows Vista Explorer will result in filenames that have rubbish + characters in place of the high-order UTF-8 bytes. + + + + Also, zip files that use UTF-8 encoding will not work well with Java + applications that use the java.util.zip classes, as of v5.0 of the Java + runtime. The Java runtime does not correctly implement the PKWare + specification in this regard. + + + + As a result, we have the unfortunate situation that "correct" behavior by + the DotNetZip library with regard to Unicode encoding of filenames during + zip creation will result in zip files that are readable by strictly + compliant and current tools (for example the most recent release of the + commercial WinZip tool); but these zip files will not be readable by + various other tools or libraries, including Windows Explorer. + + + + The DotNetZip library can read and write zip files with UTF8-encoded + entries, according to the PKware spec. If you use DotNetZip for both + creating and reading the zip file, and you use UTF-8, there will be no + loss of information in the filenames. For example, using a self-extractor + created by this library will allow you to unpack files correctly with no + loss of information in the filenames. + + + + If you do not set this flag, it will remain false. If this flag is false, + the ZipOutputStream will encode all filenames and comments using + the IBM437 codepage. This can cause "loss of information" on some + filenames, but the resulting zipfile will be more interoperable with other + utilities. As an example of the loss of information, diacritics can be + lost. The o-tilde character will be down-coded to plain o. The c with a + cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. + Likewise, the O-stroke character (Unicode 248), used in Danish and + Norwegian, will be down-coded to plain o. Chinese characters cannot be + represented in codepage IBM437; when using the default encoding, Chinese + characters in filenames will be represented as ?. These are all examples + of "information loss". + + + + The loss of information associated to the use of the IBM437 encoding is + inconvenient, and can also lead to runtime errors. For example, using + IBM437, any sequence of 4 Chinese characters will be encoded as ????. If + your application creates a ZipOutputStream, does not set the + encoding, then adds two files, each with names of four Chinese characters + each, this will result in a duplicate filename exception. In the case + where you add a single file with a name containing four Chinese + characters, the zipfile will save properly, but extracting that file + later, with any zip tool, will result in an error, because the question + mark is not legal for use within filenames on Windows. These are just a + few examples of the problems associated to loss of information. + + + + This flag is independent of the encoding of the content within the entries + in the zip file. Think of the zip file as a container - it supports an + encoding. Within the container are other "containers" - the file entries + themselves. The encoding within those entries is independent of the + encoding of the zip archive container for those entries. + + + + Rather than specify the encoding in a binary fashion using this flag, an + application can specify an arbitrary encoding via the property. Setting the encoding + explicitly when creating zip archives will result in non-compliant zip + files that, curiously, are fairly interoperable. The challenge is, the + PKWare specification does not provide for a way to specify that an entry + in a zip archive uses a code page that is neither IBM437 nor UTF-8. + Therefore if you set the encoding explicitly when creating a zip archive, + you must take care upon reading the zip archive to use the same code page. + If you get it wrong, the behavior is undefined and may result in incorrect + filenames, exceptions, stomach upset, hair loss, and acne. + + + + + + + The text encoding to use when emitting entries into the zip archive, for + those entries whose filenames or comments cannot be encoded with the + default (IBM437) encoding. + + + + + In its + zip specification, PKWare describes two options for encoding + filenames and comments: using IBM437 or UTF-8. But, some archiving tools + or libraries do not follow the specification, and instead encode + characters using the system default code page. For example, WinRAR when + run on a machine in Shanghai may encode filenames with the Big-5 Chinese + (950) code page. This behavior is contrary to the Zip specification, but + it occurs anyway. + + + + When using DotNetZip to write zip archives that will be read by one of + these other archivers, set this property to specify the code page to use + when encoding the and for each ZipEntry in the zip file, for + values that cannot be encoded with the default codepage for zip files, + IBM437. This is why this property is "provisional". In all cases, IBM437 + is used where possible, in other words, where no loss of data would + result. It is possible, therefore, to have a given entry with a + Comment encoded in IBM437 and a FileName encoded with the + specified "provisional" codepage. + + + + Be aware that a zip file created after you've explicitly set the + ProvisionalAlternateEncoding property to a value other than + IBM437 may not be compliant to the PKWare specification, and may not be + readable by compliant archivers. On the other hand, many (most?) + archivers are non-compliant and can read zip files created in arbitrary + code pages. The trick is to use or specify the proper codepage when + reading the zip. + + + + When creating a zip archive using this library, it is possible to change + the value of ProvisionalAlternateEncoding between each entry you + add, and between adding entries and the call to Close(). Don't do + this. It will likely result in a zipfile that is not readable. For best + interoperability, either leave ProvisionalAlternateEncoding + alone, or specify it only once, before adding any entries to the + ZipOutputStream instance. There is one exception to this + recommendation, described later. + + + + When using an arbitrary, non-UTF8 code page for encoding, there is no + standard way for the creator application - whether DotNetZip, WinZip, + WinRar, or something else - to formally specify in the zip file which + codepage has been used for the entries. As a result, readers of zip files + are not able to inspect the zip file and determine the codepage that was + used for the entries contained within it. It is left to the application + or user to determine the necessary codepage when reading zip files encoded + this way. If you use an incorrect codepage when reading a zipfile, you + will get entries with filenames that are incorrect, and the incorrect + filenames may even contain characters that are not legal for use within + filenames in Windows. Extracting entries with illegal characters in the + filenames will lead to exceptions. It's too bad, but this is just the way + things are with code pages in zip files. Caveat Emptor. + + + + One possible approach for specifying the code page for a given zip file is + to describe the code page in a human-readable form in the Zip comment. For + example, the comment may read "Entries in this archive are encoded in the + Big5 code page". For maximum interoperability, the zip comment in this + case should be encoded in the default, IBM437 code page. In this case, + the zip comment is encoded using a different page than the filenames. To + do this, Specify ProvisionalAlternateEncoding to your desired + region-specific code page, once before adding any entries, and then set + the property and reset + ProvisionalAlternateEncoding to IBM437 before calling Close(). + + + + + + A Text Encoding to use when encoding the filenames and comments for + all the ZipEntry items, during a ZipFile.Save() operation. + + + + Whether the encoding specified here is used during the save depends + on . + + + + + + A flag that tells if and when this instance should apply + AlternateEncoding to encode the filenames and comments associated to + of ZipEntry objects contained within this instance. + + + + + The default text encoding used in zip archives. It is numeric 437, also + known as IBM437. + + + + + + The size threshold for an entry, above which a parallel deflate is used. + + + + + + DotNetZip will use multiple threads to compress any ZipEntry, when + the CompressionMethod is Deflate, and if the entry is + larger than the given size. Zero means "always use parallel + deflate", while -1 means "never use parallel deflate". + + + + If the entry size cannot be known before compression, as with any entry + added via a ZipOutputStream, then Parallel deflate will never be + performed, unless the value of this property is zero. + + + + A parallel deflate operations will speed up the compression of + large files, on computers with multiple CPUs or multiple CPU + cores. For files above 1mb, on a dual core or dual-cpu (2p) + machine, the time required to compress the file can be 70% of the + single-threaded deflate. For very large files on 4p machines the + compression can be done in 30% of the normal time. The downside + is that parallel deflate consumes extra memory during the deflate, + and the deflation is slightly less effective. + + + + Parallel deflate tends to not be as effective as single-threaded deflate + because the original data stream is split into multiple independent + buffers, each of which is compressed in parallel. But because they are + treated independently, there is no opportunity to share compression + dictionaries, and additional framing bytes must be added to the output + stream. For that reason, a deflated stream may be slightly larger when + compressed using parallel deflate, as compared to a traditional + single-threaded deflate. For files of about 512k, the increase over the + normal deflate is as much as 5% of the total compressed size. For larger + files, the difference can be as small as 0.1%. + + + + Multi-threaded compression does not give as much an advantage when using + Encryption. This is primarily because encryption tends to slow down + the entire pipeline. Also, multi-threaded compression gives less of an + advantage when using lower compression levels, for example . You may have to perform + some tests to determine the best approach for your situation. + + + + The default value for this property is -1, which means parallel + compression will not be performed unless you set it to zero. + + + + + + + The maximum number of buffer pairs to use when performing + parallel compression. + + + + + This property sets an upper limit on the number of memory + buffer pairs to create when performing parallel + compression. The implementation of the parallel + compression stream allocates multiple buffers to + facilitate parallel compression. As each buffer fills up, + the stream uses + ThreadPool.QueueUserWorkItem() to compress those + buffers in a background threadpool thread. After a buffer + is compressed, it is re-ordered and written to the output + stream. + + + + A higher number of buffer pairs enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + For each compression "task" that occurs in parallel, there are 2 + buffers allocated: one for input and one for output. This property + sets a limit for the number of pairs. The total amount of storage + space allocated for buffering will then be (N*S*2), where N is the + number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer + pairs per CPU core, so if your machine has 4 cores, and you retain + the default buffer size of 128k, then the + ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer + memory in total, or 4mb, in blocks of 128kb. If you then set this + property to 8, then the number will be 8 * 2 * 128kb of buffer + memory, or 2mb. + + + + CPU utilization will also go up with additional buffers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + This property is not the number of buffer pairs to use; it is an + upper limit. An illustration: Suppose you have an application that + uses the default value of this property (which is 16), and it runs + on a machine with 2 CPU cores. In that case, DotNetZip will allocate + 4 buffer pairs per CPU core, for a total of 8 pairs. The upper + limit specified by this property has no effect. + + + + The application can set this value at any time, but it is + effective only if set before calling + ZipOutputStream.Write() for the first time. + + + + + + + + + Always returns false. + + + + + Always returns false. + + + + + Always returns true. + + + + + Always returns a NotSupportedException. + + + + + Setting this property always returns a NotSupportedException. Getting it + returns the value of the Position on the underlying stream. + + + + + Provides a stream metaphor for reading zip files. + + + + + This class provides an alternative programming model for reading zip files to + the one enabled by the class. Use this when reading zip + files, as an alternative to the class, when you would + like to use a Stream class to read the file. + + + + Some application designs require a readable stream for input. This stream can + be used to read a zip file, and extract entries. + + + + Both the ZipInputStream class and the ZipFile class can be used + to read and extract zip files. Both of them support many of the common zip + features, including Unicode, different compression levels, and ZIP64. The + programming models differ. For example, when extracting entries via calls to + the GetNextEntry() and Read() methods on the + ZipInputStream class, the caller is responsible for creating the file, + writing the bytes into the file, setting the attributes on the file, and + setting the created, last modified, and last accessed timestamps on the + file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the + ZipInputStream is generally recommended for when your application wants + to extract the data, without storing that data into a file. + + + + Aside from the obvious differences in programming model, there are some + differences in capability between the ZipFile class and the + ZipInputStream class. + + + + + ZipFile can be used to create or update zip files, or read and + extract zip files. ZipInputStream can be used only to read and + extract zip files. If you want to use a stream to create zip files, check + out the . + + + + ZipInputStream cannot read segmented or spanned + zip files. + + + + ZipInputStream will not read Zip file comments. + + + + When reading larger files, ZipInputStream will always underperform + ZipFile. This is because the ZipInputStream does a full scan on the + zip file, while the ZipFile class reads the central directory of the + zip file. + + + + + + + + + Create a ZipInputStream, wrapping it around an existing stream. + + + + + + While the class is generally easier + to use, this class provides an alternative to those + applications that want to read from a zipfile directly, + using a . + + + + Both the ZipInputStream class and the ZipFile class can be used + to read and extract zip files. Both of them support many of the common zip + features, including Unicode, different compression levels, and ZIP64. The + programming models differ. For example, when extracting entries via calls to + the GetNextEntry() and Read() methods on the + ZipInputStream class, the caller is responsible for creating the file, + writing the bytes into the file, setting the attributes on the file, and + setting the created, last modified, and last accessed timestamps on the + file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the + ZipInputStream is generally recommended for when your application wants + to extract the data, without storing that data into a file. + + + + Aside from the obvious differences in programming model, there are some + differences in capability between the ZipFile class and the + ZipInputStream class. + + + + + ZipFile can be used to create or update zip files, or read and extract + zip files. ZipInputStream can be used only to read and extract zip + files. If you want to use a stream to create zip files, check out the . + + + + ZipInputStream cannot read segmented or spanned + zip files. + + + + ZipInputStream will not read Zip file comments. + + + + When reading larger files, ZipInputStream will always underperform + ZipFile. This is because the ZipInputStream does a full scan on the + zip file, while the ZipFile class reads the central directory of the + zip file. + + + + + + + + The stream to read. It must be readable. This stream will be closed at + the time the ZipInputStream is closed. + + + + + This example shows how to read a zip file, and extract entries, using the + ZipInputStream class. + + + private void Unzip() + { + byte[] buffer= new byte[2048]; + int n; + using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read)) + { + using (var input= new ZipInputStream(raw)) + { + ZipEntry e; + while (( e = input.GetNextEntry()) != null) + { + if (e.IsDirectory) continue; + string outputPath = Path.Combine(extractDir, e.FileName); + using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) + { + while ((n= input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + } + + + + Private Sub UnZip() + Dim inputFileName As String = "MyArchive.zip" + Dim extractDir As String = "extract" + Dim buffer As Byte() = New Byte(2048) {} + Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read) + Using input As ZipInputStream = New ZipInputStream(raw) + Dim e As ZipEntry + Do While (Not e = input.GetNextEntry Is Nothing) + If Not e.IsDirectory Then + Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ + FileMode.Create, FileAccess.ReadWrite) + Dim n As Integer + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + End If + Loop + End Using + End Using + End Sub + + + + + + Create a ZipInputStream, given the name of an existing zip file. + + + + + + This constructor opens a FileStream for the given zipfile, and + wraps a ZipInputStream around that. See the documentation for the + constructor for full details. + + + + While the class is generally easier + to use, this class provides an alternative to those + applications that want to read from a zipfile directly, + using a . + + + + + + The name of the filesystem file to read. + + + + + This example shows how to read a zip file, and extract entries, using the + ZipInputStream class. + + + private void Unzip() + { + byte[] buffer= new byte[2048]; + int n; + using (var input= new ZipInputStream(inputFileName)) + { + ZipEntry e; + while (( e = input.GetNextEntry()) != null) + { + if (e.IsDirectory) continue; + string outputPath = Path.Combine(extractDir, e.FileName); + using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) + { + while ((n= input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + + + + Private Sub UnZip() + Dim inputFileName As String = "MyArchive.zip" + Dim extractDir As String = "extract" + Dim buffer As Byte() = New Byte(2048) {} + Using input As ZipInputStream = New ZipInputStream(inputFileName) + Dim e As ZipEntry + Do While (Not e = input.GetNextEntry Is Nothing) + If Not e.IsDirectory Then + Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ + FileMode.Create, FileAccess.ReadWrite) + Dim n As Integer + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + End If + Loop + End Using + End Sub + + + + + + Create a ZipInputStream, explicitly specifying whether to + keep the underlying stream open. + + + + See the documentation for the ZipInputStream(Stream) + constructor for a discussion of the class, and an example of how to use the class. + + + + The stream to read from. It must be readable. + + + + true if the application would like the stream + to remain open after the ZipInputStream has been closed. + + + + Provides a string representation of the instance. + + + This can be useful for debugging purposes. + + + a string representation of the instance. + + + + Read the data from the stream into the buffer. + + + + + The data for the zipentry will be decrypted and uncompressed, as + necessary, before being copied into the buffer. + + + + You must set the property before calling + Read() the first time for an encrypted entry. To determine if an + entry is encrypted and requires a password, check the ZipEntry.Encryption property. + + + + The buffer to hold the data read from the stream. + the offset within the buffer to copy the first byte read. + the number of bytes to read. + the number of bytes read, after decryption and decompression. + + + + Read the next entry from the zip file. + + + + + Call this method just before calling , + to position the pointer in the zip file to the next entry that can be + read. Subsequent calls to Read(), will decrypt and decompress the + data in the zip file, until Read() returns 0. + + + + Each time you call GetNextEntry(), the pointer in the wrapped + stream is moved to the next entry in the zip file. If you call , and thus re-position the pointer within + the file, you will need to call GetNextEntry() again, to insure + that the file pointer is positioned at the beginning of a zip entry. + + + + This method returns the ZipEntry. Using a stream approach, you will + read the raw bytes for an entry in a zip file via calls to Read(). + Alternatively, you can extract an entry into a file, or a stream, by + calling , or one of its siblings. + + + + + + The ZipEntry read. Returns null (or Nothing in VB) if there are no more + entries in the zip file. + + + + + + Dispose the stream. + + + + + This method disposes the ZipInputStream. It may also close the + underlying stream, depending on which constructor was used. + + + + Typically the application will call Dispose() implicitly, via + a using statement in C#, or a Using statement in VB. + + + + Application code won't call this code directly. This method may + be invoked in two distinct scenarios. If disposing == true, the + method has been called directly or indirectly by a user's code, + for example via the public Dispose() method. In this case, both + managed and unmanaged resources can be referenced and disposed. + If disposing == false, the method has been called by the runtime + from inside the object finalizer and this method should not + reference other objects; in that case only unmanaged resources + must be referenced or disposed. + + + + + true if the Dispose method was invoked by user code. + + + + + This is a no-op. + + + + + This method always throws a NotSupportedException. + + ignored + ignored + ignored + + + + This method seeks in the underlying stream. + + + + + Call this method if you want to seek around within the zip file for random access. + + + + Applications can intermix calls to Seek() with calls to . After a call to Seek(), + GetNextEntry() will get the next ZipEntry that falls after + the current position in the input stream. You're on your own for finding + out just where to seek in the stream, to get to the various entries. + + + + + the offset point to seek to + the reference point from which to seek + The new position + + + + This method always throws a NotSupportedException. + + ignored + + + + The text encoding to use when reading entries into the zip archive, for + those entries whose filenames or comments cannot be encoded with the + default (IBM437) encoding. + + + + + In its + zip specification, PKWare describes two options for encoding + filenames and comments: using IBM437 or UTF-8. But, some archiving tools + or libraries do not follow the specification, and instead encode + characters using the system default code page. For example, WinRAR when + run on a machine in Shanghai may encode filenames with the Big-5 Chinese + (950) code page. This behavior is contrary to the Zip specification, but + it occurs anyway. + + + + When using DotNetZip to read zip archives that use something other than + UTF-8 or IBM437, set this property to specify the code page to use when + reading encoded filenames and comments for each ZipEntry in the zip + file. + + + + This property is "provisional". When the entry in the zip archive is not + explicitly marked as using UTF-8, then IBM437 is used to decode filenames + and comments. If a loss of data would result from using IBM436 - + specifically when encoding and decoding is not reflexive - the codepage + specified here is used. It is possible, therefore, to have a given entry + with a Comment encoded in IBM437 and a FileName encoded with + the specified "provisional" codepage. + + + + When a zip file uses an arbitrary, non-UTF8 code page for encoding, there + is no standard way for the reader application - whether DotNetZip, WinZip, + WinRar, or something else - to know which codepage has been used for the + entries. Readers of zip files are not able to inspect the zip file and + determine the codepage that was used for the entries contained within it. + It is left to the application or user to determine the necessary codepage + when reading zip files encoded this way. If you use an incorrect codepage + when reading a zipfile, you will get entries with filenames that are + incorrect, and the incorrect filenames may even contain characters that + are not legal for use within filenames in Windows. Extracting entries with + illegal characters in the filenames will lead to exceptions. It's too bad, + but this is just the way things are with code pages in zip files. Caveat + Emptor. + + + + + + + Size of the work buffer to use for the ZLIB codec during decompression. + + + + Setting this affects the performance and memory efficiency of compression + and decompression. For larger files, setting this to a larger size may + improve performance, but the exact numbers vary depending on available + memory, and a bunch of other variables. I don't have good firm + recommendations on how to set it. You'll have to test it yourself. Or + just leave it alone and accept the default. + + + + + Sets the password to be used on the ZipInputStream instance. + + + + + + When reading a zip archive, this password is used to read and decrypt the + entries that are encrypted within the zip file. When entries within a zip + file use different passwords, set the appropriate password for the entry + before the first call to Read() for each entry. + + + + When reading an entry that is not encrypted, the value of this property is + ignored. + + + + + + + This example uses the ZipInputStream to read and extract entries from a + zip file, using a potentially different password for each entry. + + + byte[] buffer= new byte[2048]; + int n; + using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read )) + { + using (var input= new ZipInputStream(raw)) + { + ZipEntry e; + while (( e = input.GetNextEntry()) != null) + { + input.Password = PasswordForEntry(e.FileName); + if (e.IsDirectory) continue; + string outputPath = Path.Combine(_extractDir, e.FileName); + using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) + { + while ((n= input.Read(buffer,0,buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + + + + + + + Always returns true. + + + + + Returns the value of CanSeek for the underlying (wrapped) stream. + + + + + Always returns false. + + + + + Returns the length of the underlying stream. + + + + + Gets or sets the position of the underlying stream. + + + Setting the position is equivalent to calling Seek(value, SeekOrigin.Begin). + + + + + Sort-of like a factory method, ForUpdate is used only when + the application needs to update the zip entry metadata for + a segmented zip file, when the starting segment is earlier + than the ending segment, for a particular entry. + + + + The update is always contiguous, never rolls over. As a + result, this method doesn't need to return a ZSS; it can + simply return a FileStream. That's why it's "sort of" + like a Factory method. + + + Caller must Close/Dispose the stream object returned by + this method. + + + + + + Read from the stream + + the buffer to read + the offset at which to start + the number of bytes to read + the number of bytes actually read + + + + Write to the stream. + + the buffer from which to write + the offset at which to start writing + the number of bytes to write + + + + Name of the filesystem file corresponding to the current segment. + + + + The name is not always the name currently being used in the + filesystem. When rwMode is RwMode.Write, the filesystem file has a + temporary name until the stream is closed or until the next segment is + started. + + + + + + This class exposes a set of COM-accessible wrappers for static + methods available on the ZipFile class. You don't need this + class unless you are using DotNetZip from a COM environment. + + + + + A wrapper for ZipFile.IsZipFile(string) + + The filename to of the zip file to check. + true if the file contains a valid zip file. + + + + A wrapper for ZipFile.IsZipFile(string, bool) + + + We cannot use "overloaded" Method names in COM interop. + So, here, we use a unique name. + + The filename to of the zip file to check. + true if the file contains a valid zip file. + + + + A wrapper for ZipFile.CheckZip(string) + + The filename to of the zip file to check. + + true if the named zip file checks OK. Otherwise, false. + + + + A COM-friendly wrapper for the static method . + + + The filename to of the zip file to check. + + The password to check. + + true if the named zip file checks OK. Otherwise, false. + + + + A wrapper for ZipFile.FixZipDirectory(string) + + The filename to of the zip file to fix. + + + + A wrapper for ZipFile.LibraryVersion + + + the version number on the DotNetZip assembly, formatted as a string. + + + + + An enum providing the options when an error occurs during opening or reading + of a file or directory that is being saved to a zip file. + + + + + This enum describes the actions that the library can take when an error occurs + opening or reading a file, as it is being saved into a Zip archive. + + + + In some cases an error will occur when DotNetZip tries to open a file to be + added to the zip archive. In other cases, an error might occur after the + file has been successfully opened, while DotNetZip is reading the file. + + + + The first problem might occur when calling AddDirectory() on a directory + that contains a Clipper .dbf file; the file is locked by Clipper and + cannot be opened by another process. An example of the second problem is + the ERROR_LOCK_VIOLATION that results when a file is opened by another + process, but not locked, and a range lock has been taken on the file. + Microsoft Outlook takes range locks on .PST files. + + + + + + Throw an exception when an error occurs while zipping. This is the default + behavior. (For COM clients, this is a 0 (zero).) + + + + + When an error occurs during zipping, for example a file cannot be opened, + skip the file causing the error, and continue zipping. (For COM clients, + this is a 1.) + + + + + When an error occurs during zipping, for example a file cannot be opened, + retry the operation that caused the error. Be careful with this option. If + the error is not temporary, the library will retry forever. (For COM + clients, this is a 2.) + + + + + When an error occurs, invoke the zipError event. The event type used is + . A typical use of this option: + a GUI application may wish to pop up a dialog to allow the user to view the + error that occurred, and choose an appropriate action. After your + processing in the error event, if you want to skip the file, set on the + ZipProgressEventArgs.CurrentEntry to Skip. If you want the + exception to be thrown, set ZipErrorAction on the CurrentEntry + to Throw. If you want to cancel the zip, set + ZipProgressEventArgs.Cancel to true. Cancelling differs from using + Skip in that a cancel will not save any further entries, if there are any. + (For COM clients, the value of this enum is a 3.) + + + + + An enum that provides the various encryption algorithms supported by this + library. + + + + + + PkzipWeak implies the use of Zip 2.0 encryption, which is known to be + weak and subvertible. + + + + A note on interoperability: Values of PkzipWeak and None are + specified in PKWARE's zip + specification, and are considered to be "standard". Zip archives + produced using these options will be interoperable with many other zip tools + and libraries, including Windows Explorer. + + + + Values of WinZipAes128 and WinZipAes256 are not part of the Zip + specification, but rather imply the use of a vendor-specific extension from + WinZip. If you want to produce interoperable Zip archives, do not use these + values. For example, if you produce a zip archive using WinZipAes256, you + will be able to open it in Windows Explorer on Windows XP and Vista, but you + will not be able to extract entries; trying this will lead to an "unspecified + error". For this reason, some people have said that a zip archive that uses + WinZip's AES encryption is not actually a zip archive at all. A zip archive + produced this way will be readable with the WinZip tool (Version 11 and + beyond). + + + + There are other third-party tools and libraries, both commercial and + otherwise, that support WinZip's AES encryption. These will be able to read + AES-encrypted zip archives produced by DotNetZip, and conversely applications + that use DotNetZip to read zip archives will be able to read AES-encrypted + archives produced by those tools or libraries. Consult the documentation for + those other tools and libraries to find out if WinZip's AES encryption is + supported. + + + + In case you care: According to the WinZip specification, the + actual AES key used is derived from the via an + algorithm that complies with RFC 2898, using an iteration + count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands + for "Password Based Key Derivation Function #2". + + + + A word about password strength and length: The AES encryption technology is + very good, but any system is only as secure as the weakest link. If you want + to secure your data, be sure to use a password that is hard to guess. To make + it harder to guess (increase its "entropy"), you should make it longer. If + you use normal characters from an ASCII keyboard, a password of length 20 will + be strong enough that it will be impossible to guess. For more information on + that, I'd encourage you to read this + article. + + + + The WinZip AES algorithms are not supported with the version of DotNetZip that + runs on the .NET Compact Framework. This is because .NET CF lacks the + HMACSHA1 class that is required for producing the archive. + + + + + + No encryption at all. + + + + + Traditional or Classic pkzip encryption. + + + + + WinZip AES encryption (128 key bits). + + + + + WinZip AES encryption (256 key bits). + + + + + An encryption algorithm that is not supported by DotNetZip. + + + + + An enum for the options when extracting an entry would overwrite an existing file. + + + + + This enum describes the actions that the library can take when an + Extract() or ExtractWithPassword() method is called to extract an + entry to a filesystem, and the extraction would overwrite an existing filesystem + file. + + + + + + + Throw an exception when extraction would overwrite an existing file. (For + COM clients, this is a 0 (zero).) + + + + + When extraction would overwrite an existing file, overwrite the file silently. + The overwrite will happen even if the target file is marked as read-only. + (For COM clients, this is a 1.) + + + + + When extraction would overwrite an existing file, don't overwrite the file, silently. + (For COM clients, this is a 2.) + + + + + When extraction would overwrite an existing file, invoke the ExtractProgress + event, using an event type of . In + this way, the application can decide, just-in-time, whether to overwrite the + file. For example, a GUI application may wish to pop up a dialog to allow + the user to choose. You may want to examine the property before making + the decision. If, after your processing in the Extract progress event, you + want to NOT extract the file, set + on the ZipProgressEventArgs.CurrentEntry to DoNotOverwrite. + If you do want to extract the file, set ZipEntry.ExtractExistingFile + to OverwriteSilently. If you want to cancel the Extraction, set + ZipProgressEventArgs.Cancel to true. Cancelling differs from using + DoNotOverwrite in that a cancel will not extract any further entries, if + there are any. (For COM clients, the value of this enum is a 3.) + + + + + Enumerates the options for a logical conjunction. This enum is intended for use + internally by the FileSelector class. + + + + + FileSelector encapsulates logic that selects files from a source - a zip file + or the filesystem - based on a set of criteria. This class is used internally + by the DotNetZip library, in particular for the AddSelectedFiles() methods. + This class can also be used independently of the zip capability in DotNetZip. + + + + + + The FileSelector class is used internally by the ZipFile class for selecting + files for inclusion into the ZipFile, when the method, or one of + its overloads, is called. It's also used for the methods. Typically, an + application that creates or manipulates Zip archives will not directly + interact with the FileSelector class. + + + + Some applications may wish to use the FileSelector class directly, to + select files from disk volumes based on a set of criteria, without creating or + querying Zip archives. The file selection criteria include: a pattern to + match the filename; the last modified, created, or last accessed time of the + file; the size of the file; and the attributes of the file. + + + + Consult the documentation for + for more information on specifying the selection criteria. + + + + + + + Constructor that allows the caller to specify file selection criteria. + + + + + This constructor allows the caller to specify a set of criteria for + selection of files. + + + + See for a description of + the syntax of the selectionCriteria string. + + + + By default the FileSelector will traverse NTFS Reparse Points. To + change this, use FileSelector(String, bool). + + + + The criteria for file selection. + + + + Constructor that allows the caller to specify file selection criteria. + + + + + This constructor allows the caller to specify a set of criteria for + selection of files. + + + + See for a description of + the syntax of the selectionCriteria string. + + + + The criteria for file selection. + + whether to traverse NTFS reparse points (junctions). + + + + + Returns a string representation of the FileSelector object. + + The string representation of the boolean logic statement of the file + selection criteria for this instance. + + + + Returns the names of the files in the specified directory + that fit the selection criteria specified in the FileSelector. + + + + This is equivalent to calling + with recurseDirectories = false. + + + + The name of the directory over which to apply the FileSelector + criteria. + + + + A collection of strings containing fully-qualified pathnames of files + that match the criteria specified in the FileSelector instance. + + + + + Returns the names of the files in the specified directory that fit the + selection criteria specified in the FileSelector, optionally recursing + through subdirectories. + + + + This method applies the file selection criteria contained in the + FileSelector to the files contained in the given directory, and + returns the names of files that conform to the criteria. + + + + The name of the directory over which to apply the FileSelector + criteria. + + + + Whether to recurse through subdirectories when applying the file + selection criteria. + + + + A collection of strings containing fully-qualified pathnames of files + that match the criteria specified in the FileSelector instance. + + + + + Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. + + + + + This method applies the criteria set in the FileSelector instance (as described in + the ) to the specified ZipFile. Using this + method, for example, you can retrieve all entries from the given ZipFile that + have filenames ending in .txt. + + + + Normally, applications would not call this method directly. This method is used + by the ZipFile class. + + + + Using the appropriate SelectionCriteria, you can retrieve entries based on size, + time, and attributes. See for a + description of the syntax of the SelectionCriteria string. + + + + + The ZipFile from which to retrieve entries. + + a collection of ZipEntry objects that conform to the criteria. + + + + Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. + + + + + This method applies the criteria set in the FileSelector instance (as described in + the ) to the specified ZipFile. Using this + method, for example, you can retrieve all entries from the given ZipFile that + have filenames ending in .txt. + + + + Normally, applications would not call this method directly. This method is used + by the ZipFile class. + + + + This overload allows the selection of ZipEntry instances from the ZipFile to be restricted + to entries contained within a particular directory in the ZipFile. + + + + Using the appropriate SelectionCriteria, you can retrieve entries based on size, + time, and attributes. See for a + description of the syntax of the SelectionCriteria string. + + + + + The ZipFile from which to retrieve entries. + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + a collection of ZipEntry objects that conform to the criteria. + + + + The string specifying which files to include when retrieving. + + + + + Specify the criteria in statements of 3 elements: a noun, an operator, + and a value. Consider the string "name != *.doc" . The noun is + "name". The operator is "!=", implying "Not Equal". The value is + "*.doc". That criterion, in English, says "all files with a name that + does not end in the .doc extension." + + + + Supported nouns include "name" (or "filename") for the filename; + "atime", "mtime", and "ctime" for last access time, last modfied time, + and created time of the file, respectively; "attributes" (or "attrs") + for the file attributes; "size" (or "length") for the file length + (uncompressed); and "type" for the type of object, either a file or a + directory. The "attributes", "type", and "name" nouns all support = + and != as operators. The "size", "atime", "mtime", and "ctime" nouns + support = and !=, and >, >=, <, <= as well. The times are + taken to be expressed in local time. + + + + Specify values for the file attributes as a string with one or more of + the characters H,R,S,A,I,L in any order, implying file attributes of + Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint + (symbolic link) respectively. + + + + To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as + the format. If you omit the HH:mm:ss portion, it is assumed to be + 00:00:00 (midnight). + + + + The value for a size criterion is expressed in integer quantities of + bytes, kilobytes (use k or kb after the number), megabytes (m or mb), + or gigabytes (g or gb). + + + + The value for a name is a pattern to match against the filename, + potentially including wildcards. The pattern follows CMD.exe glob + rules: * implies one or more of any character, while ? implies one + character. If the name pattern contains any slashes, it is matched to + the entire filename, including the path; otherwise, it is matched + against only the filename without the path. This means a pattern of + "*\*.*" matches all files one directory level deep, while a pattern of + "*.*" matches all files in all directories. + + + + To specify a name pattern that includes spaces, use single quotes + around the pattern. A pattern of "'* *.*'" will match all files that + have spaces in the filename. The full criteria string for that would + be "name = '* *.*'" . + + + + The value for a type criterion is either F (implying a file) or D + (implying a directory). + + + + Some examples: + + + + + criteria + Files retrieved + + + + name != *.xls + any file with an extension that is not .xls + + + + + name = *.mp3 + any file with a .mp3 extension. + + + + + *.mp3 + (same as above) any file with a .mp3 extension. + + + + + attributes = A + all files whose attributes include the Archive bit. + + + + + attributes != H + all files whose attributes do not include the Hidden bit. + + + + + mtime > 2009-01-01 + all files with a last modified time after January 1st, 2009. + + + + + ctime > 2009/01/01-03:00:00 + all files with a created time after 3am (local time), + on January 1st, 2009. + + + + + size > 2gb + all files whose uncompressed size is greater than 2gb. + + + + + type = D + all directories in the filesystem. + + + + + + You can combine criteria with the conjunctions AND, OR, and XOR. Using + a string like "name = *.txt AND size >= 100k" for the + selectionCriteria retrieves entries whose names end in .txt, and whose + uncompressed size is greater than or equal to 100 kilobytes. + + + + For more complex combinations of criteria, you can use parenthesis to + group clauses in the boolean logic. Absent parenthesis, the + precedence of the criterion atoms is determined by order of + appearance. Unlike the C# language, the AND conjunction does not take + precendence over the logical OR. This is important only in strings + that contain 3 or more criterion atoms. In other words, "name = *.txt + and size > 1000 or attributes = H" implies "((name = *.txt AND size + > 1000) OR attributes = H)" while "attributes = H OR name = *.txt + and size > 1000" evaluates to "((attributes = H OR name = *.txt) + AND size > 1000)". When in doubt, use parenthesis. + + + + Using time properties requires some extra care. If you want to + retrieve all entries that were last updated on 2009 February 14, + specify "mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this + to say: all files updated after 12:00am on February 14th, until + 12:00am on February 15th. You can use the same bracketing approach to + specify any time period - a year, a month, a week, and so on. + + + + The syntax allows one special case: if you provide a string with no + spaces, it is treated as a pattern to match for the filename. + Therefore a string like "*.xls" will be equivalent to specifying "name + = *.xls". This "shorthand" notation does not work with compound + criteria. + + + + There is no logic in this class that insures that the inclusion + criteria are internally consistent. For example, it's possible to + specify criteria that says the file must have a size of less than 100 + bytes, as well as a size that is greater than 1000 bytes. Obviously + no file will ever satisfy such criteria, but this class does not check + for or detect such inconsistencies. + + + + + + Thrown in the setter if the value has an invalid syntax. + + + + + Indicates whether searches will traverse NTFS reparse points, like Junctions. + + + + + Summary description for EnumUtil. + + + + + Returns the value of the DescriptionAttribute if the specified Enum + value has one. If not, returns the ToString() representation of the + Enum value. + + The Enum to get the description for + + + + + Converts the string representation of the name or numeric value of one + or more enumerated constants to an equivalent enumerated object. + Note: use the DescriptionAttribute on enum values to enable this. + + The System.Type of the enumeration. + + A string containing the name or value to convert. + + + + + + Converts the string representation of the name or numeric value of one + or more enumerated constants to an equivalent enumerated object. A + parameter specified whether the operation is case-sensitive. Note: + use the DescriptionAttribute on enum values to enable this. + + The System.Type of the enumeration. + + A string containing the name or value to convert. + + + Whether the operation is case-sensitive or not. + + + + + This is a helper class supporting WinZip AES encryption. + This class is intended for use only by the DotNetZip library. + + + + Most uses of the DotNetZip library will not involve direct calls into + the WinZipAesCrypto class. Instead, the WinZipAesCrypto class is + instantiated and used by the ZipEntry() class when WinZip AES + encryption or decryption on an entry is employed. + + + + + A stream that encrypts as it writes, or decrypts as it reads. The + Crypto is AES in CTR (counter) mode, which is compatible with the AES + encryption employed by WinZip 12.0. + + + + The AES/CTR encryption protocol used by WinZip works like this: + + - start with a counter, initialized to zero. + + - to encrypt, take the data by 16-byte blocks. For each block: + - apply the transform to the counter + - increement the counter + - XOR the result of the transform with the plaintext to + get the ciphertext. + - compute the mac on the encrypted bytes + - when finished with all blocks, store the computed MAC. + + - to decrypt, take the data by 16-byte blocks. For each block: + - compute the mac on the encrypted bytes, + - apply the transform to the counter + - increement the counter + - XOR the result of the transform with the ciphertext to + get the plaintext. + - when finished with all blocks, compare the computed MAC against + the stored MAC + + + + + + + The constructor. + + The underlying stream + To either encrypt or decrypt. + The pre-initialized WinZipAesCrypto object. + The maximum number of bytes to read from the stream. + + + + Close the stream. + + + + + Flush the content in the stream. + + + + + This method throws a NotImplementedException. + + + + + This method throws a NotImplementedException. + + + + + Returns the final HMAC-SHA1-80 for the data that was encrypted. + + + + + Returns true if the stream can be read. + + + + + Always returns false. + + + + + Returns true if the CryptoMode is Encrypt. + + + + + Getting this property throws a NotImplementedException. + + + + + Getting or Setting this property throws a NotImplementedException. + + + + + Issued when an ZipEntry.ExtractWithPassword() method is invoked + with an incorrect password. + + + + + Base class for all exceptions defined by and throw by the Zip library. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Indicates that a read was attempted on a stream, and bad or incomplete data was + received. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Issued when an CRC check fails upon extracting an entry from a zip archive. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Issued when errors occur saving a self-extracting archive. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Indicates that an operation was attempted on a ZipFile which was not possible + given the state of the instance. For example, if you call Save() on a ZipFile + which has no filename set, you can get this exception. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Collects general purpose utility methods. + + + + private null constructor + + + + Utility routine for transforming path names from filesystem format (on Windows that means backslashes) to + a format suitable for use within zipfiles. This means trimming the volume letter and colon (if any) And + swapping backslashes for forward slashes. + + source path. + transformed path + + + + Finds a signature in the zip stream. This is useful for finding + the end of a zip entry, for example, or the beginning of the next ZipEntry. + + + + + Scans through 64k at a time. + + + + If the method fails to find the requested signature, the stream Position + after completion of this method is unchanged. If the method succeeds in + finding the requested signature, the stream position after completion is + direct AFTER the signature found in the stream. + + + + The stream to search + The 4-byte signature to find + The number of bytes read + + + + Create a pseudo-random filename, suitable for use as a temporary + file, and open it. + + + + The System.IO.Path.GetRandomFileName() method is not available on + the Compact Framework, so this library provides its own substitute + on NETCF. + + + This method produces a filename of the form + DotNetZip-xxxxxxxx.tmp, where xxxxxxxx is replaced by randomly + chosen characters, and creates that file. + + + + + + Workitem 7889: handle ERROR_LOCK_VIOLATION during read + + + This could be gracefully handled with an extension attribute, but + This assembly is built for .NET 2.0, so I cannot use them. + + + + + A decorator stream. It wraps another stream, and performs bookkeeping + to keep track of the stream Position. + + + + In some cases, it is not possible to get the Position of a stream, let's + say, on a write-only output stream like ASP.NET's + Response.OutputStream, or on a different write-only stream + provided as the destination for the zip by the application. In this + case, programmers can use this counting stream to count the bytes read + or written. + + + Consider the scenario of an application that saves a self-extracting + archive (SFX), that uses a custom SFX stub. + + + Saving to a filesystem file, the application would open the + filesystem file (getting a FileStream), save the custom sfx stub + into it, and then call ZipFile.Save(), specifying the same + FileStream. ZipFile.Save() does the right thing for the zipentry + offsets, by inquiring the Position of the FileStream before writing + any data, and then adding that initial offset into any ZipEntry + offsets in the zip directory. Everything works fine. + + + Now suppose the application is an ASPNET application and it saves + directly to Response.OutputStream. It's not possible for DotNetZip to + inquire the Position, so the offsets for the SFX will be wrong. + + + The workaround is for the application to use this class to wrap + HttpResponse.OutputStream, then write the SFX stub and the ZipFile + into that wrapper stream. Because ZipFile.Save() can inquire the + Position, it will then do the right thing with the offsets. + + + + + + The constructor. + + The underlying stream + + + + Adjust the byte count on the stream. + + + + the number of bytes to subtract from the count. + + + + + Subtract delta from the count of bytes written to the stream. + This is necessary when seeking back, and writing additional data, + as happens in some cases when saving Zip files. + + + + + + The read method. + + The buffer to hold the data read from the stream. + the offset within the buffer to copy the first byte read. + the number of bytes to read. + the number of bytes read, after decryption and decompression. + + + + Write data into the stream. + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Flushes the underlying stream. + + + + + Seek in the stream. + + the offset point to seek to + the reference point from which to seek + The new position + + + + Set the length of the underlying stream. Be careful with this! + + + the length to set on the underlying stream. + + + + Gets the wrapped stream. + + + + + The count of bytes written out to the stream. + + + + + the count of bytes that have been read from the stream. + + + + + Whether the stream can be read. + + + + + Whether it is possible to call Seek() on the stream. + + + + + Whether it is possible to call Write() on the stream. + + + + + The length of the underlying stream. + + + + + Returns the sum of number of bytes written, plus the initial + offset before writing. + + + + + The Position of the stream. + + + + + This class implements the "traditional" or "classic" PKZip encryption, + which today is considered to be weak. On the other hand it is + ubiquitous. This class is intended for use only by the DotNetZip + library. + + + + Most uses of the DotNetZip library will not involve direct calls into + the ZipCrypto class. Instead, the ZipCrypto class is instantiated and + used by the ZipEntry() class when encryption or decryption on an entry + is employed. If for some reason you really wanted to use a weak + encryption algorithm in some other application, you might use this + library. But you would be much better off using one of the built-in + strong encryption libraries in the .NET Framework, like the AES + algorithm or SHA. + + + + + The default constructor for ZipCrypto. + + + + This class is intended for internal use by the library only. It's + probably not useful to you. Seriously. Stop reading this + documentation. It's a waste of your time. Go do something else. + Check the football scores. Go get an ice cream with a friend. + Seriously. + + + + + + Call this method on a cipher text to render the plaintext. You must + first initialize the cipher with a call to InitCipher. + + + + + var cipher = new ZipCrypto(); + cipher.InitCipher(Password); + // Decrypt the header. This has a side effect of "further initializing the + // encryption keys" in the traditional zip encryption. + byte[] DecryptedMessage = cipher.DecryptMessage(EncryptedMessage); + + + + The encrypted buffer. + + The number of bytes to encrypt. + Should be less than or equal to CipherText.Length. + + + The plaintext. + + + + This is the converse of DecryptMessage. It encrypts the plaintext + and produces a ciphertext. + + + The plain text buffer. + + + The number of bytes to encrypt. + Should be less than or equal to plainText.Length. + + + The ciphertext. + + + + This initializes the cipher with the given password. + See AppNote.txt for details. + + + + The passphrase for encrypting or decrypting with this cipher. + + + + + Step 1 - Initializing the encryption keys + ----------------------------------------- + Start with these keys: + Key(0) := 305419896 (0x12345678) + Key(1) := 591751049 (0x23456789) + Key(2) := 878082192 (0x34567890) + + Then, initialize the keys with a password: + + loop for i from 0 to length(password)-1 + update_keys(password(i)) + end loop + + Where update_keys() is defined as: + + update_keys(char): + Key(0) := crc32(key(0),char) + Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH) + Key(1) := Key(1) * 134775813 + 1 + Key(2) := crc32(key(2),key(1) rightshift 24) + end update_keys + + Where crc32(old_crc,char) is a routine that given a CRC value and a + character, returns an updated CRC value after applying the CRC-32 + algorithm described elsewhere in this document. + + + + + After the keys are initialized, then you can use the cipher to + encrypt the plaintext. + + + + Essentially we encrypt the password with the keys, then discard the + ciphertext for the password. This initializes the keys for later use. + + + + + + + From AppNote.txt: + unsigned char decrypt_byte() + local unsigned short temp + temp :=- Key(2) | 2 + decrypt_byte := (temp * (temp ^ 1)) bitshift-right 8 + end decrypt_byte + + + + + A Stream for reading and concurrently decrypting data from a zip file, + or for writing and concurrently encrypting data to a zip file. + + + + The constructor. + The underlying stream + To either encrypt or decrypt. + The pre-initialized ZipCrypto object. + + + + Delegate in which the application writes the ZipEntry content for the named entry. + + + The name of the entry that must be written. + The stream to which the entry data should be written. + + + When you add an entry and specify a WriteDelegate, via , the application + code provides the logic that writes the entry data directly into the zip file. + + + + + This example shows how to define a WriteDelegate that obtains a DataSet, and then + writes the XML for the DataSet into the zip archive. There's no need to + save the XML to a disk file first. + + + private void WriteEntry (String filename, Stream output) + { + DataSet ds1 = ObtainDataSet(); + ds1.WriteXml(output); + } + + private void Run() + { + using (var zip = new ZipFile()) + { + zip.AddEntry(zipEntryName, WriteEntry); + zip.Save(zipFileName); + } + } + + + + Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream) + DataSet ds1 = ObtainDataSet() + ds1.WriteXml(stream) + End Sub + + Public Sub Run() + Using zip = New ZipFile + zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) + zip.Save(zipFileName) + End Using + End Sub + + + + + + + Delegate in which the application opens the stream, just-in-time, for the named entry. + + + + The name of the ZipEntry that the application should open the stream for. + + + + When you add an entry via , the application code provides the logic that + opens and closes the stream for the given ZipEntry. + + + + + + + Delegate in which the application closes the stream, just-in-time, for the named entry. + + + + The name of the ZipEntry that the application should close the stream for. + + + The stream to be closed. + + + When you add an entry via , the application code provides the logic that + opens and closes the stream for the given ZipEntry. + + + + + + + Delegate for the callback by which the application tells the + library the CompressionLevel to use for a file. + + + + + Using this callback, the application can, for example, specify that + previously-compressed files (.mp3, .png, .docx, etc) should use a + CompressionLevel of None, or can set the compression level based + on any other factor. + + + + + + + In an EventArgs type, indicates which sort of progress event is being + reported. + + + There are events for reading, events for saving, and events for + extracting. This enumeration allows a single EventArgs type to be sued to + describe one of multiple subevents. For example, a SaveProgress event is + invoked before, after, and during the saving of a single entry. The value + of an enum with this type, specifies which event is being triggered. The + same applies to Extraction, Reading and Adding events. + + + + + Indicates that a Add() operation has started. + + + + + Indicates that an individual entry in the archive has been added. + + + + + Indicates that a Add() operation has completed. + + + + + Indicates that a Read() operation has started. + + + + + Indicates that an individual entry in the archive is about to be read. + + + + + Indicates that an individual entry in the archive has just been read. + + + + + Indicates that a Read() operation has completed. + + + + + The given event reports the number of bytes read so far + during a Read() operation. + + + + + Indicates that a Save() operation has started. + + + + + Indicates that an individual entry in the archive is about to be written. + + + + + Indicates that an individual entry in the archive has just been saved. + + + + + Indicates that a Save() operation has completed. + + + + + Indicates that the zip archive has been created in a + temporary location during a Save() operation. + + + + + Indicates that the temporary file is about to be renamed to the final archive + name during a Save() operation. + + + + + Indicates that the temporary file is has just been renamed to the final archive + name during a Save() operation. + + + + + Indicates that the self-extracting archive has been compiled + during a Save() operation. + + + + + The given event is reporting the number of source bytes that have run through the compressor so far + during a Save() operation. + + + + + Indicates that an entry is about to be extracted. + + + + + Indicates that an entry has just been extracted. + + + + + Indicates that extraction of an entry would overwrite an existing + filesystem file. You must use + + ExtractExistingFileAction.InvokeExtractProgressEvent in the call + to ZipEntry.Extract() in order to receive this event. + + + + + The given event is reporting the number of bytes written so far for + the current entry during an Extract() operation. + + + + + Indicates that an ExtractAll operation is about to begin. + + + + + Indicates that an ExtractAll operation has completed. + + + + + Indicates that an error has occurred while saving a zip file. + This generally means the file cannot be opened, because it has been + removed, or because it is locked by another process. It can also + mean that the file cannot be Read, because of a range lock conflict. + + + + + Provides information about the progress of a save, read, or extract operation. + This is a base class; you will probably use one of the classes derived from this one. + + + + + The total number of entries to be saved or extracted. + + + + + The name of the last entry saved or extracted. + + + + + In an event handler, set this to cancel the save or extract + operation that is in progress. + + + + + The type of event being reported. + + + + + Returns the archive name associated to this event. + + + + + The number of bytes read or written so far for this entry. + + + + + Total number of bytes that will be read or written for this entry. + This number will be -1 if the value cannot be determined. + + + + + Provides information about the progress of a Read operation. + + + + + Provides information about the progress of a Add operation. + + + + + Provides information about the progress of a save operation. + + + + + Constructor for the SaveProgressEventArgs. + + the name of the zip archive. + whether this is before saving the entry, or after + The total number of entries in the zip archive. + Number of entries that have been saved. + The entry involved in the event. + + + + Number of entries saved so far. + + + + + Provides information about the progress of the extract operation. + + + + + Constructor for the ExtractProgressEventArgs. + + the name of the zip archive. + whether this is before saving the entry, or after + The total number of entries in the zip archive. + Number of entries that have been extracted. + The entry involved in the event. + The location to which entries are extracted. + + + + Number of entries extracted so far. This is set only if the + EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and + the Extract() is occurring witin the scope of a call to ExtractAll(). + + + + + Returns the extraction target location, a filesystem path. + + + + + Provides information about the an error that occurred while zipping. + + + + + Returns the exception that occurred, if any. + + + + + Returns the name of the file that caused the exception, if any. + + + + + Represents a single entry in a ZipFile. Typically, applications get a ZipEntry + by enumerating the entries within a ZipFile, or by adding an entry to a ZipFile. + + + + + Reads one entry from the zip directory structure in the zip file. + + + + The zipfile for which a directory entry will be read. From this param, the + method gets the ReadStream and the expected text encoding + (ProvisionalAlternateEncoding) which is used if the entry is not marked + UTF-8. + + + + a list of previously seen entry names; used to prevent duplicates. + + + the entry read from the archive. + + + + Returns true if the passed-in value is a valid signature for a ZipDirEntry. + + the candidate 4-byte signature value. + true, if the signature is valid according to the PKWare spec. + + + + Default constructor. + + + Applications should never need to call this directly. It is exposed to + support COM Automation environments. + + + + + Sets the NTFS Creation, Access, and Modified times for the given entry. + + + + + When adding an entry from a file or directory, the Creation, Access, and + Modified times for the given entry are automatically set from the + filesystem values. When adding an entry from a stream or string, the + values are implicitly set to DateTime.Now. The application may wish to + set these values to some arbitrary value, before saving the archive, and + can do so using the various setters. If you want to set all of the times, + this method is more efficient. + + + + The values you set here will be retrievable with the , and properties. + + + + When this method is called, if both and are false, then the + EmitTimesInWindowsFormatWhenSaving flag is automatically set. + + + + DateTime values provided here without a DateTimeKind are assumed to be Local Time. + + + + the creation time of the entry. + the last access time of the entry. + the last modified time of the entry. + + + + + + + + + Provides a string representation of the instance. + a string representation of the instance. + + + + Extract the entry to the filesystem, starting at the current + working directory. + + + + This method has a bunch of overloads! One of them is sure to + be the right one for you... If you don't like these, check + out the ExtractWithPassword() methods. + + + + + + + + + This method extracts an entry from a zip file into the current + working directory. The path of the entry as extracted is the full + path as specified in the zip archive, relative to the current + working directory. After the file is extracted successfully, the + file attributes and timestamps are set. + + + + The action taken when extraction an entry would overwrite an + existing file is determined by the property. + + + + Within the call to Extract(), the content for the entry is + written into a filesystem file, and then the last modified time of the + file is set according to the property on + the entry. See the remarks the property for + some details about the last modified time. + + + + + + + Extract the entry to a file in the filesystem, using the specified + behavior when extraction would overwrite an existing file. + + + + + See the remarks on the property, for some + details about how the last modified time of the file is set after + extraction. + + + + + The action to take if extraction would overwrite an existing file. + + + + + Extracts the entry to the specified stream. + + + + + The caller can specify any write-able stream, for example a , a , or ASP.NET's + Response.OutputStream. The content will be decrypted and + decompressed as necessary. If the entry is encrypted and no password + is provided, this method will throw. + + + The position on the stream is not reset by this method before it extracts. + You may want to call stream.Seek() before calling ZipEntry.Extract(). + + + + + the stream to which the entry should be extracted. + + + + + + Extract the entry to the filesystem, starting at the specified base + directory. + + + the pathname of the base directory + + + + + + This example extracts only the entries in a zip file that are .txt files, + into a directory called "textfiles". + + using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) + { + foreach (string s1 in zip.EntryFilenames) + { + if (s1.EndsWith(".txt")) + { + zip[s1].Extract("textfiles"); + } + } + } + + + Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") + Dim s1 As String + For Each s1 In zip.EntryFilenames + If s1.EndsWith(".txt") Then + zip(s1).Extract("textfiles") + End If + Next + End Using + + + + + + + Using this method, existing entries in the filesystem will not be + overwritten. If you would like to force the overwrite of existing + files, see the property, or call + . + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + + + Extract the entry to the filesystem, starting at the specified base + directory, and using the specified behavior when extraction would + overwrite an existing file. + + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + + + String sZipPath = "Airborne.zip"; + String sFilePath = "Readme.txt"; + String sRootFolder = "Digado"; + using (ZipFile zip = ZipFile.Read(sZipPath)) + { + if (zip.EntryFileNames.Contains(sFilePath)) + { + // use the string indexer on the zip file + zip[sFileName].Extract(sRootFolder, + ExtractExistingFileAction.OverwriteSilently); + } + } + + + + Dim sZipPath as String = "Airborne.zip" + Dim sFilePath As String = "Readme.txt" + Dim sRootFolder As String = "Digado" + Using zip As ZipFile = ZipFile.Read(sZipPath) + If zip.EntryFileNames.Contains(sFilePath) + ' use the string indexer on the zip file + zip(sFilePath).Extract(sRootFolder, _ + ExtractExistingFileAction.OverwriteSilently) + End If + End Using + + + + the pathname of the base directory + + The action to take if extraction would overwrite an existing file. + + + + + Extract the entry to the filesystem, using the current working directory + and the specified password. + + + + This method has a bunch of overloads! One of them is sure to be + the right one for you... + + + + + + + + + Existing entries in the filesystem will not be overwritten. If you + would like to force the overwrite of existing files, see the property, or call + . + + + + See the remarks on the property for some + details about how the "last modified" time of the created file is + set. + + + + + In this example, entries that use encryption are extracted using a + particular password. + + using (var zip = ZipFile.Read(FilePath)) + { + foreach (ZipEntry e in zip) + { + if (e.UsesEncryption) + e.ExtractWithPassword("Secret!"); + else + e.Extract(); + } + } + + + Using zip As ZipFile = ZipFile.Read(FilePath) + Dim e As ZipEntry + For Each e In zip + If (e.UsesEncryption) + e.ExtractWithPassword("Secret!") + Else + e.Extract + End If + Next + End Using + + + The Password to use for decrypting the entry. + + + + Extract the entry to the filesystem, starting at the specified base + directory, and using the specified password. + + + + + + + + Existing entries in the filesystem will not be overwritten. If you + would like to force the overwrite of existing files, see the property, or call + . + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + The pathname of the base directory. + The Password to use for decrypting the entry. + + + + Extract the entry to a file in the filesystem, relative to the + current directory, using the specified behavior when extraction + would overwrite an existing file. + + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + The Password to use for decrypting the entry. + + + The action to take if extraction would overwrite an existing file. + + + + + Extract the entry to the filesystem, starting at the specified base + directory, and using the specified behavior when extraction would + overwrite an existing file. + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + the pathname of the base directory + + The action to take if extraction would + overwrite an existing file. + + The Password to use for decrypting the entry. + + + + Extracts the entry to the specified stream, using the specified + Password. For example, the caller could extract to Console.Out, or + to a MemoryStream. + + + + + The caller can specify any write-able stream, for example a , a , or ASP.NET's + Response.OutputStream. The content will be decrypted and + decompressed as necessary. If the entry is encrypted and no password + is provided, this method will throw. + + + The position on the stream is not reset by this method before it extracts. + You may want to call stream.Seek() before calling ZipEntry.Extract(). + + + + + + the stream to which the entry should be extracted. + + + The password to use for decrypting the entry. + + + + + Opens a readable stream corresponding to the zip entry in the + archive. The stream decompresses and decrypts as necessary, as it + is read. + + + + + + DotNetZip offers a variety of ways to extract entries from a zip + file. This method allows an application to extract an entry by + reading a . + + + + The return value is of type . Use it as you would any + stream for reading. When an application calls on that stream, it will + receive data from the zip entry that is decrypted and decompressed + as necessary. + + + + CrcCalculatorStream adds one additional feature: it keeps a + CRC32 checksum on the bytes of the stream as it is read. The CRC + value is available in the property on the + CrcCalculatorStream. When the read is complete, your + application + should check this CRC against the + property on the ZipEntry to validate the content of the + ZipEntry. You don't have to validate the entry using the CRC, but + you should, to verify integrity. Check the example for how to do + this. + + + + If the entry is protected with a password, then you need to provide + a password prior to calling , either by + setting the property on the entry, or the + property on the ZipFile + itself. Or, you can use , the + overload of OpenReader that accepts a password parameter. + + + + If you want to extract entry data into a write-able stream that is + already opened, like a , do not + use this method. Instead, use . + + + + Your application may use only one stream created by OpenReader() at + a time, and you should not call other Extract methods before + completing your reads on a stream obtained from OpenReader(). This + is because there is really only one source stream for the compressed + content. A call to OpenReader() seeks in the source stream, to the + beginning of the compressed content. A subsequent call to + OpenReader() on a different entry will seek to a different position + in the source stream, as will a call to Extract() or one of its + overloads. This will corrupt the state for the decompressing stream + from the original call to OpenReader(). + + + + The OpenReader() method works only when the ZipEntry is + obtained from an instance of ZipFile. This method will throw + an exception if the ZipEntry is obtained from a . + + + + + This example shows how to open a zip archive, then read in a named + entry via a stream. After the read loop is complete, the code + compares the calculated during the read loop with the expected CRC + on the ZipEntry, to verify the extraction. + + using (ZipFile zip = new ZipFile(ZipFileToRead)) + { + ZipEntry e1= zip["Elevation.mp3"]; + using (Ionic.Zlib.CrcCalculatorStream s = e1.OpenReader()) + { + byte[] buffer = new byte[4096]; + int n, totalBytesRead= 0; + do { + n = s.Read(buffer,0, buffer.Length); + totalBytesRead+=n; + } while (n>0); + if (s.Crc32 != e1.Crc32) + throw new Exception(string.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)); + if (totalBytesRead != e1.UncompressedSize) + throw new Exception(string.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)); + } + } + + + Using zip As New ZipFile(ZipFileToRead) + Dim e1 As ZipEntry = zip.Item("Elevation.mp3") + Using s As Ionic.Zlib.CrcCalculatorStream = e1.OpenReader + Dim n As Integer + Dim buffer As Byte() = New Byte(4096) {} + Dim totalBytesRead As Integer = 0 + Do + n = s.Read(buffer, 0, buffer.Length) + totalBytesRead = (totalBytesRead + n) + Loop While (n > 0) + If (s.Crc32 <> e1.Crc32) Then + Throw New Exception(String.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)) + End If + If (totalBytesRead <> e1.UncompressedSize) Then + Throw New Exception(String.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)) + End If + End Using + End Using + + + + The Stream for reading. + + + + Opens a readable stream for an encrypted zip entry in the archive. + The stream decompresses and decrypts as necessary, as it is read. + + + + + See the documentation on the method for + full details. This overload allows the application to specify a + password for the ZipEntry to be read. + + + + The password to use for decrypting the entry. + The Stream for reading. + + + + Validates that the args are consistent. + + + Only one of {baseDir, outStream} can be non-null. + If baseDir is non-null, then the outputFile is created. + + + + + Reads one ZipEntry from the given stream. The content for + the entry does not get decompressed or decrypted. This method + basically reads metadata, and seeks. + + the ZipContainer this entry belongs to. + + true of this is the first entry being read from the stream. + + the ZipEntry read from the stream. + + + + Finds a particular segment in the given extra field. + This is used when modifying a previously-generated + extra field, in particular when removing the AES crypto + segment in the extra field. + + + + + At current cursor position in the stream, read the extra + field, and set the properties on the ZipEntry instance + appropriately. This can be called when processing the + Extra field in the Central Directory, or in the local + header. + + + + + generate and return a byte array that encodes the filename + for the entry. + + + + side effects: generate and store into _CommentBytes the + byte array for any comment attached to the entry. Also + sets _actualEncoding to indicate the actual encoding + used. The same encoding is used for both filename and + comment. + + + + + + Stores the position of the entry source stream, or, if the position is + already stored, seeks to that position. + + + + + This method is called in prep for reading the source stream. If PKZIP + encryption is used, then we need to calc the CRC32 before doing the + encryption, because the CRC is used in the 12th byte of the PKZIP + encryption header. So, we need to be able to seek backward in the source + when saving the ZipEntry. This method is called from the place that + calculates the CRC, and also from the method that does the encryption of + the file data. + + + + The first time through, this method sets the _sourceStreamOriginalPosition + field. Subsequent calls to this method seek to that position. + + + + + + Copy metadata that may have been changed by the app. We do this when + resetting the zipFile instance. If the app calls Save() on a ZipFile, then + tries to party on that file some more, we may need to Reset() it , which + means re-reading the entries and then copying the metadata. I think. + + + + + Set the input stream and get its length, if possible. The length is + used for progress updates, AND, to allow an optimization in case of + a stream/file of zero length. In that case we skip the Encrypt and + compression Stream. (like DeflateStream or BZip2OutputStream) + + + + + Prepare the given stream for output - wrap it in a CountingStream, and + then in a CRC stream, and an encryptor and deflator as appropriate. + + + + Previously this was used in ZipEntry.Write(), but in an effort to + introduce some efficiencies in that method I've refactored to put the + code inline. This method still gets called by ZipOutputStream. + + + + + + True if the referenced entry is a directory. + + + + + Provides a human-readable string with information about the ZipEntry. + + + + + The time and date at which the file indicated by the ZipEntry was + last modified. + + + + + The DotNetZip library sets the LastModified value for an entry, equal to + the Last Modified time of the file in the filesystem. If an entry is + added from a stream, the library uses System.DateTime.Now for this + value, for the given entry. + + + + This property allows the application to retrieve and possibly set the + LastModified value on an entry, to an arbitrary value. values with a + setting of DateTimeKind.Unspecified are taken to be expressed as + DateTimeKind.Local. + + + + Be aware that because of the way PKWare's + Zip specification describes how times are stored in the zip file, + the full precision of the System.DateTime datatype is not stored + for the last modified time when saving zip files. For more information on + how times are formatted, see the PKZip specification. + + + + The actual last modified time of a file can be stored in multiple ways in + the zip file, and they are not mutually exclusive: + + + + + In the so-called "DOS" format, which has a 2-second precision. Values + are rounded to the nearest even second. For example, if the time on the + file is 12:34:43, then it will be stored as 12:34:44. This first value + is accessible via the LastModified property. This value is always + present in the metadata for each zip entry. In some cases the value is + invalid, or zero. + + + + In the so-called "Windows" or "NTFS" format, as an 8-byte integer + quantity expressed as the number of 1/10 milliseconds (in other words + the number of 100 nanosecond units) since January 1, 1601 (UTC). This + format is how Windows represents file times. This time is accessible + via the ModifiedTime property. + + + + In the "Unix" format, a 4-byte quantity specifying the number of seconds since + January 1, 1970 UTC. + + + + In an older format, now deprecated but still used by some current + tools. This format is also a 4-byte quantity specifying the number of + seconds since January 1, 1970 UTC. + + + + + + Zip tools and libraries will always at least handle (read or write) the + DOS time, and may also handle the other time formats. Keep in mind that + while the names refer to particular operating systems, there is nothing in + the time formats themselves that prevents their use on other operating + systems. + + + + When reading ZIP files, the DotNetZip library reads the Windows-formatted + time, if it is stored in the entry, and sets both LastModified and + ModifiedTime to that value. When writing ZIP files, the DotNetZip + library by default will write both time quantities. It can also emit the + Unix-formatted time if desired (See .) + + + + The last modified time of the file created upon a call to + ZipEntry.Extract() may be adjusted during extraction to compensate + for differences in how the .NET Base Class Library deals with daylight + saving time (DST) versus how the Windows filesystem deals with daylight + saving time. Raymond Chen provides + some good context. + + + + In a nutshell: Daylight savings time rules change regularly. In 2007, for + example, the inception week of DST changed. In 1977, DST was in place all + year round. In 1945, likewise. And so on. Win32 does not attempt to + guess which time zone rules were in effect at the time in question. It + will render a time as "standard time" and allow the app to change to DST + as necessary. .NET makes a different choice. + + + + Compare the output of FileInfo.LastWriteTime.ToString("f") with what you + see in the Windows Explorer property sheet for a file that was last + written to on the other side of the DST transition. For example, suppose + the file was last modified on October 17, 2003, during DST but DST is not + currently in effect. Explorer's file properties reports Thursday, October + 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, + 2003, 9:45 AM. + + + + Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific + STANDARD Time. Even though October 17 of that year occurred during Pacific + Daylight Time, Win32 displays the time as standard time because that's + what time it is NOW. + + + + .NET BCL assumes that the current DST rules were in place at the time in + question. So, .NET says, "Well, if the rules in effect now were also in + effect on October 17, 2003, then that would be daylight time" so it + displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time. + + + + So .NET gives a value which is more intuitively correct, but is also + potentially incorrect, and which is not invertible. Win32 gives a value + which is intuitively incorrect, but is strictly correct. + + + + Because of this funkiness, this library adds one hour to the LastModified + time on the extracted file, if necessary. That is to say, if the time in + question had occurred in what the .NET Base Class Library assumed to be + DST. This assumption may be wrong given the constantly changing DST rules, + but it is the best we can do. + + + + + + + + Last Modified time for the file represented by the entry. + + + + + + This value corresponds to the "last modified" time in the NTFS file times + as described in the Zip + specification. When getting this property, the value may be + different from . When setting the property, + the property also gets set, but with a lower + precision. + + + + Let me explain. It's going to take a while, so get + comfortable. Originally, waaaaay back in 1989 when the ZIP specification + was originally described by the esteemed Mr. Phil Katz, the dominant + operating system of the time was MS-DOS. MSDOS stored file times with a + 2-second precision, because, c'mon, who is ever going to need better + resolution than THAT? And so ZIP files, regardless of the platform on + which the zip file was created, store file times in exactly the same format that DOS used + in 1989. + + + + Since then, the ZIP spec has evolved, but the internal format for file + timestamps remains the same. Despite the fact that the way times are + stored in a zip file is rooted in DOS heritage, any program on any + operating system can format a time in this way, and most zip tools and + libraries DO - they round file times to the nearest even second and store + it just like DOS did 25+ years ago. + + + + PKWare extended the ZIP specification to allow a zip file to store what + are called "NTFS Times" and "Unix(tm) times" for a file. These are the + last write, last access, and file creation + times of a particular file. These metadata are not actually specific + to NTFS or Unix. They are tracked for each file by NTFS and by various + Unix filesystems, but they are also tracked by other filesystems, too. + The key point is that the times are formatted in the zip file + in the same way that NTFS formats the time (ticks since win32 epoch), + or in the same way that Unix formats the time (seconds since Unix + epoch). As with the DOS time, any tool or library running on any + operating system is capable of formatting a time in one of these ways + and embedding it into the zip file. + + + + These extended times are higher precision quantities than the DOS time. + As described above, the (DOS) LastModified has a precision of 2 seconds. + The Unix time is stored with a precision of 1 second. The NTFS time is + stored with a precision of 0.0000001 seconds. The quantities are easily + convertible, except for the loss of precision you may incur. + + + + A zip archive can store the {C,A,M} times in NTFS format, in Unix format, + or not at all. Often a tool running on Unix or Mac will embed the times + in Unix format (1 second precision), while WinZip running on Windows might + embed the times in NTFS format (precision of of 0.0000001 seconds). When + reading a zip file with these "extended" times, in either format, + DotNetZip represents the values with the + ModifiedTime, AccessedTime and CreationTime + properties on the ZipEntry. + + + + While any zip application or library, regardless of the platform it + runs on, could use any of the time formats allowed by the ZIP + specification, not all zip tools or libraries do support all these + formats. Storing the higher-precision times for each entry is + optional for zip files, and many tools and libraries don't use the + higher precision quantities at all. The old DOS time, represented by + , is guaranteed to be present, though it + sometimes unset. + + + + Ok, getting back to the question about how the LastModified + property relates to this ModifiedTime + property... LastModified is always set, while + ModifiedTime is not. (The other times stored in the NTFS + times extension, CreationTime and AccessedTime also + may not be set on an entry that is read from an existing zip file.) + When reading a zip file, then LastModified takes the DOS time + that is stored with the file. If the DOS time has been stored as zero + in the zipfile, then this library will use DateTime.Now for the + LastModified value. If the ZIP file was created by an evolved + tool, then there will also be higher precision NTFS or Unix times in + the zip file. In that case, this library will read those times, and + set LastModified and ModifiedTime to the same value, the + one corresponding to the last write time of the file. If there are no + higher precision times stored for the entry, then ModifiedTime + remains unset (likewise AccessedTime and CreationTime), + and LastModified keeps its DOS time. + + + + When creating zip files with this library, by default the extended time + properties (ModifiedTime, AccessedTime, and + CreationTime) are set on the ZipEntry instance, and these data are + stored in the zip archive for each entry, in NTFS format. If you add an + entry from an actual filesystem file, then the entry gets the actual file + times for that file, to NTFS-level precision. If you add an entry from a + stream, or a string, then the times get the value DateTime.Now. In + this case LastModified and ModifiedTime will be identical, + to 2 seconds of precision. You can explicitly set the + CreationTime, AccessedTime, and ModifiedTime of an + entry using the property setters. If you want to set all of those + quantities, it's more efficient to use the method. Those + changes are not made permanent in the zip file until you call or one of its cousins. + + + + When creating a zip file, you can override the default behavior of + this library for formatting times in the zip file, disabling the + embedding of file times in NTFS format or enabling the storage of file + times in Unix format, or both. You may want to do this, for example, + when creating a zip file on Windows, that will be consumed on a Mac, + by an application that is not hip to the "NTFS times" format. To do + this, use the and + properties. A valid zip + file may store the file times in both formats. But, there are no + guarantees that a program running on Mac or Linux will gracefully + handle the NTFS-formatted times when Unix times are present, or that a + non-DotNetZip-powered application running on Windows will be able to + handle file times in Unix format. DotNetZip will always do something + reasonable; other libraries or tools may not. When in doubt, test. + + + + I'll bet you didn't think one person could type so much about time, eh? + And reading it was so enjoyable, too! Well, in appreciation, maybe you + should donate? + + + + + + + + + + + Last Access time for the file represented by the entry. + + + This value may or may not be meaningful. If the ZipEntry was read from an existing + Zip archive, this information may not be available. For an explanation of why, see + . + + + + + + + + The file creation time for the file represented by the entry. + + + + This value may or may not be meaningful. If the ZipEntry was read + from an existing zip archive, and the creation time was not set on the entry + when the zip file was created, then this property may be meaningless. For an + explanation of why, see . + + + + + + + + Specifies whether the Creation, Access, and Modified times for the given + entry will be emitted in "Windows format" when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entry should or should not be stored + in the zip archive in the format used by Windows. The default value of + this property is true. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified + () times for the given entry are automatically + set from the filesystem values. When adding an entry from a stream or + string, all three values are implicitly set to DateTime.Now. Applications + can also explicitly set those times by calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since Jan 1, 1601 UTC. The other is a format Unix applications typically + use: seconds since January 1, 1970 UTC. Each format can be stored in an + "extra field" in the zip entry when saving the zip archive. The former + uses an extra field with a Header Id of 0x000A, while the latter uses a + header ID of 0x5455. + + + + Not all zip tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Although the time values are + easily convertible, subject to a loss of precision, some tools and + libraries may be able to read only one or the other. DotNetZip can read or + write times in either or both formats. + + + + The times stored are taken from , , and . + + + + This property is not mutually exclusive from the property. It is + possible that a zip entry can embed the timestamps in both forms, one + form, or neither. But, there are no guarantees that a program running on + Mac or Linux will gracefully handle NTFS Formatted times, or that a + non-DotNetZip-powered application running on Windows will be able to + handle file times in Unix format. When in doubt, test. + + + + Normally you will use the ZipFile.EmitTimesInWindowsFormatWhenSaving + property, to specify the behavior for all entries in a zip, rather than + the property on each individual entry. + + + + + + + + + + + + + Specifies whether the Creation, Access, and Modified times for the given + entry will be emitted in "Unix(tm) format" when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entry should or should not be stored + in the zip archive in the format used by Unix. By default this flag is + false, meaning the Unix-format times are not stored in the zip + archive. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified + () times for the given entry are automatically + set from the filesystem values. When adding an entry from a stream or + string, all three values are implicitly set to DateTime.Now. Applications + can also explicitly set those times by calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since Jan 1, 1601 UTC. The other is a format Unix applications typically + use: seconds since Jan 1, 1970 UTC. Each format can be stored in an + "extra field" in the zip entry when saving the zip archive. The former + uses an extra field with a Header Id of 0x000A, while the latter uses a + header ID of 0x5455. + + + + Not all tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Although the time values are + easily convertible, subject to a loss of precision, some tools and + libraries may be able to read only one or the other. DotNetZip can read or + write times in either or both formats. + + + + The times stored are taken from , , and . + + + + This property is not mutually exclusive from the property. It is + possible that a zip entry can embed the timestamps in both forms, one + form, or neither. But, there are no guarantees that a program running on + Mac or Linux will gracefully handle NTFS Formatted times, or that a + non-DotNetZip-powered application running on Windows will be able to + handle file times in Unix format. When in doubt, test. + + + + Normally you will use the ZipFile.EmitTimesInUnixFormatWhenSaving + property, to specify the behavior for all entries, rather than the + property on each individual entry. + + + + + + + + + + + + + The type of timestamp attached to the ZipEntry. + + + + This property is valid only for a ZipEntry that was read from a zip archive. + It indicates the type of timestamp attached to the entry. + + + + + + + + The file attributes for the entry. + + + + + + The attributes in NTFS include + ReadOnly, Archive, Hidden, System, and Indexed. When adding a + ZipEntry to a ZipFile, these attributes are set implicitly when + adding an entry from the filesystem. When adding an entry from a stream + or string, the Attributes are not set implicitly. Regardless of the way + an entry was added to a ZipFile, you can set the attributes + explicitly if you like. + + + + When reading a ZipEntry from a ZipFile, the attributes are + set according to the data stored in the ZipFile. If you extract the + entry from the archive to a filesystem file, DotNetZip will set the + attributes on the resulting file accordingly. + + + + The attributes can be set explicitly by the application. For example the + application may wish to set the FileAttributes.ReadOnly bit for all + entries added to an archive, so that on unpack, this attribute will be set + on the extracted file. Any changes you make to this property are made + permanent only when you call a Save() method on the ZipFile + instance that contains the ZipEntry. + + + + For example, an application may wish to zip up a directory and set the + ReadOnly bit on every file in the archive, so that upon later extraction, + the resulting files will be marked as ReadOnly. Not every extraction tool + respects these attributes, but if you unpack with DotNetZip, as for + example in a self-extracting archive, then the attributes will be set as + they are stored in the ZipFile. + + + + These attributes may not be interesting or useful if the resulting archive + is extracted on a non-Windows platform. How these attributes get used + upon extraction depends on the platform and tool used. + + + + This property is only partially supported in the Silverlight version + of the library: applications can read attributes on entries within + ZipFiles. But extracting entries within Silverlight will not set the + attributes on the extracted files. + + + + + + + The name of the filesystem file, referred to by the ZipEntry. + + + + + This property specifies the thing-to-be-zipped on disk, and is set only + when the ZipEntry is being created from a filesystem file. If the + ZipFile is instantiated by reading an existing .zip archive, then + the LocalFileName will be null (Nothing in VB). + + + + When it is set, the value of this property may be different than , which is the path used in the archive itself. If you + call Zip.AddFile("foop.txt", AlternativeDirectory), then the path + used for the ZipEntry within the zip archive will be different + than this path. + + + + If the entry is being added from a stream, then this is null (Nothing in VB). + + + + + + + + The name of the file contained in the ZipEntry. + + + + + + This is the name of the entry in the ZipFile itself. When creating + a zip archive, if the ZipEntry has been created from a filesystem + file, via a call to or , or a related overload, the value + of this property is derived from the name of that file. The + FileName property does not include drive letters, and may include a + different directory path, depending on the value of the + directoryPathInArchive parameter used when adding the entry into + the ZipFile. + + + + In some cases there is no related filesystem file - for example when a + ZipEntry is created using or one of the similar overloads. In this case, the value of + this property is derived from the fileName and the directory path passed + to that method. + + + + When reading a zip file, this property takes the value of the entry name + as stored in the zip file. If you extract such an entry, the extracted + file will take the name given by this property. + + + + Applications can set this property when creating new zip archives or when + reading existing archives. When setting this property, the actual value + that is set will replace backslashes with forward slashes, in accordance + with the Zip + specification, for compatibility with Unix(tm) and ... get + this.... Amiga! + + + + If an application reads a ZipFile via or a related overload, and then explicitly + sets the FileName on an entry contained within the ZipFile, and + then calls , the application will effectively + rename the entry within the zip archive. + + + + If an application sets the value of FileName, then calls + Extract() on the entry, the entry is extracted to a file using the + newly set value as the filename. The FileName value is made + permanent in the zip archive only after a call to one of the + ZipFile.Save() methods on the ZipFile that contains the + ZipEntry. + + + + If an application attempts to set the FileName to a value that + would result in a duplicate entry in the ZipFile, an exception is + thrown. + + + + When a ZipEntry is contained within a ZipFile, applications + cannot rename the entry within the context of a foreach (For + Each in VB) loop, because of the way the ZipFile stores + entries. If you need to enumerate through all the entries and rename one + or more of them, use ZipFile.EntriesSorted as the + collection. See also, ZipFile.GetEnumerator(). + + + + + + + The stream that provides content for the ZipEntry. + + + + + + The application can use this property to set the input stream for an + entry on a just-in-time basis. Imagine a scenario where the application + creates a ZipFile comprised of content obtained from hundreds of + files, via calls to AddFile(). The DotNetZip library opens streams + on these files on a just-in-time basis, only when writing the entry out to + an external store within the scope of a ZipFile.Save() call. Only + one input stream is opened at a time, as each entry is being written out. + + + + Now imagine a different application that creates a ZipFile + with content obtained from hundreds of streams, added through . Normally the + application would supply an open stream to that call. But when large + numbers of streams are being added, this can mean many open streams at one + time, unnecessarily. + + + + To avoid this, call and specify delegates that open and close the stream at + the time of Save. + + + + + Setting the value of this property when the entry was not added from a + stream (for example, when the ZipEntry was added with or , or when the entry was added by + reading an existing zip archive) will throw an exception. + + + + + + + + A flag indicating whether the InputStream was provided Just-in-time. + + + + + + When creating a zip archive, an application can obtain content for one or + more of the ZipEntry instances from streams, using the method. At the time + of calling that method, the application can supply null as the value of + the stream parameter. By doing so, the application indicates to the + library that it will provide a stream for the entry on a just-in-time + basis, at the time one of the ZipFile.Save() methods is called and + the data for the various entries are being compressed and written out. + + + + In this case, the application can set the + property, typically within the SaveProgress event (event type: ) for that entry. + + + + The application will later want to call Close() and Dispose() on that + stream. In the SaveProgress event, when the event type is , the application can + do so. This flag indicates that the stream has been provided by the + application on a just-in-time basis and that it is the application's + responsibility to call Close/Dispose on that stream. + + + + + + + + An enum indicating the source of the ZipEntry. + + + + + The version of the zip engine needed to read the ZipEntry. + + + + + This is a readonly property, indicating the version of the Zip + specification that the extracting tool or library must support to + extract the given entry. Generally higher versions indicate newer + features. Older zip engines obviously won't know about new features, and + won't be able to extract entries that depend on those newer features. + + + + + value + Features + + + + 20 + a basic Zip Entry, potentially using PKZIP encryption. + + + + + 45 + The ZIP64 extension is used on the entry. + + + + + 46 + File is compressed using BZIP2 compression* + + + + 50 + File is encrypted using PkWare's DES, 3DES, (broken) RC2 or RC4 + + + + 51 + File is encrypted using PKWare's AES encryption or corrected RC2 encryption. + + + + 52 + File is encrypted using corrected RC2-64 encryption** + + + + 61 + File is encrypted using non-OAEP key wrapping*** + + + + 63 + File is compressed using LZMA, PPMd+, Blowfish, or Twofish + + + + + + There are other values possible, not listed here. DotNetZip supports + regular PKZip encryption, and ZIP64 extensions. DotNetZip cannot extract + entries that require a zip engine higher than 45. + + + + This value is set upon reading an existing zip file, or after saving a zip + archive. + + + + + + The comment attached to the ZipEntry. + + + + + Each entry in a zip file can optionally have a comment associated to + it. The comment might be displayed by a zip tool during extraction, for + example. + + + + By default, the Comment is encoded in IBM437 code page. You can + specify an alternative with and + . + + + + + + + + Indicates whether the entry requires ZIP64 extensions. + + + + + + This property is null (Nothing in VB) until a Save() method on the + containing instance has been called. The property is + non-null (HasValue is true) only after a Save() method has + been called. + + + + After the containing ZipFile has been saved, the Value of this + property is true if any of the following three conditions holds: the + uncompressed size of the entry is larger than 0xFFFFFFFF; the compressed + size of the entry is larger than 0xFFFFFFFF; the relative offset of the + entry within the zip archive is larger than 0xFFFFFFFF. These quantities + are not known until a Save() is attempted on the zip archive and + the compression is applied. + + + + If none of the three conditions holds, then the Value is false. + + + + A Value of false does not indicate that the entry, as saved in the + zip archive, does not use ZIP64. It merely indicates that ZIP64 is + not required. An entry may use ZIP64 even when not required if + the property on the containing + ZipFile instance is set to , or if + the property on the containing + ZipFile instance is set to + and the output stream was not seekable. + + + + + + + + Indicates whether the entry actually used ZIP64 extensions, as it was most + recently written to the output file or stream. + + + + + + This Nullable property is null (Nothing in VB) until a Save() + method on the containing instance has been + called. HasValue is true only after a Save() method has been + called. + + + + The value of this property for a particular ZipEntry may change + over successive calls to Save() methods on the containing ZipFile, + even if the file that corresponds to the ZipEntry does not. This + may happen if other entries contained in the ZipFile expand, + causing the offset for this particular entry to exceed 0xFFFFFFFF. + + + + + + + The bitfield for the entry as defined in the zip spec. You probably + never need to look at this. + + + + + You probably do not need to concern yourself with the contents of this + property, but in case you do: + + + + + bit + meaning + + + + 0 + set if encryption is used. + + + + 1-2 + + set to determine whether normal, max, fast deflation. DotNetZip library + always leaves these bits unset when writing (indicating "normal" + deflation"), but can read an entry with any value here. + + + + + 3 + + Indicates that the Crc32, Compressed and Uncompressed sizes are zero in the + local header. This bit gets set on an entry during writing a zip file, when + it is saved to a non-seekable output stream. + + + + + + 4 + reserved for "enhanced deflating". This library doesn't do enhanced deflating. + + + + 5 + set to indicate the zip is compressed patched data. This library doesn't do that. + + + + 6 + + set if PKWare's strong encryption is used (must also set bit 1 if bit 6 is + set). This bit is not set if WinZip's AES encryption is set. + + + + 7 + not used + + + + 8 + not used + + + + 9 + not used + + + + 10 + not used + + + + 11 + + Language encoding flag (EFS). If this bit is set, the filename and comment + fields for this file must be encoded using UTF-8. This library currently + does not support UTF-8. + + + + + 12 + Reserved by PKWARE for enhanced compression. + + + + 13 + + Used when encrypting the Central Directory to indicate selected data + values in the Local Header are masked to hide their actual values. See + the section in the Zip + specification describing the Strong Encryption Specification for + details. + + + + + 14 + Reserved by PKWARE. + + + + 15 + Reserved by PKWARE. + + + + + + + + + The compression method employed for this ZipEntry. + + + + + + The + Zip specification allows a variety of compression methods. This + library supports just two: 0x08 = Deflate. 0x00 = Store (no compression), + for reading or writing. + + + + When reading an entry from an existing zipfile, the value you retrieve + here indicates the compression method used on the entry by the original + creator of the zip. When writing a zipfile, you can specify either 0x08 + (Deflate) or 0x00 (None). If you try setting something else, you will get + an exception. + + + + You may wish to set CompressionMethod to CompressionMethod.None (0) + when zipping already-compressed data like a jpg, png, or mp3 file. + This can save time and cpu cycles. + + + + When setting this property on a ZipEntry that is read from an + existing zip file, calling ZipFile.Save() will cause the new + CompressionMethod to be used on the entry in the newly saved zip file. + + + + Setting this property may have the side effect of modifying the + CompressionLevel property. If you set the CompressionMethod to a + value other than None, and CompressionLevel is previously + set to None, then CompressionLevel will be set to + Default. + + + + + + + In this example, the first entry added to the zip archive uses the default + behavior - compression is used where it makes sense. The second entry, + the MP3 file, is added to the archive without being compressed. + + using (ZipFile zip = new ZipFile(ZipFileToCreate)) + { + ZipEntry e1= zip.AddFile(@"notes\Readme.txt"); + ZipEntry e2= zip.AddFile(@"music\StopThisTrain.mp3"); + e2.CompressionMethod = CompressionMethod.None; + zip.Save(); + } + + + + Using zip As New ZipFile(ZipFileToCreate) + zip.AddFile("notes\Readme.txt") + Dim e2 as ZipEntry = zip.AddFile("music\StopThisTrain.mp3") + e2.CompressionMethod = CompressionMethod.None + zip.Save + End Using + + + + + + Sets the compression level to be used for the entry when saving the zip + archive. This applies only for CompressionMethod = DEFLATE. + + + + + When using the DEFLATE compression method, Varying the compression + level used on entries can affect the size-vs-speed tradeoff when + compression and decompressing data streams or files. + + + + If you do not set this property, the default compression level is used, + which normally gives a good balance of compression efficiency and + compression speed. In some tests, using BestCompression can + double the time it takes to compress, while delivering just a small + increase in compression efficiency. This behavior will vary with the + type of data you compress. If you are in doubt, just leave this setting + alone, and accept the default. + + + + When setting this property on a ZipEntry that is read from an + existing zip file, calling ZipFile.Save() will cause the new + CompressionLevel to be used on the entry in the newly saved zip file. + + + + Setting this property may have the side effect of modifying the + CompressionMethod property. If you set the CompressionLevel + to a value other than None, CompressionMethod will be set + to Deflate, if it was previously None. + + + + Setting this property has no effect if the CompressionMethod is something + other than Deflate or None. + + + + + + + + The compressed size of the file, in bytes, within the zip archive. + + + + When reading a ZipFile, this value is read in from the existing + zip file. When creating or updating a ZipFile, the compressed + size is computed during compression. Therefore the value on a + ZipEntry is valid after a call to Save() (or one of its + overloads) in that case. + + + + + + + The size of the file, in bytes, before compression, or after extraction. + + + + When reading a ZipFile, this value is read in from the existing + zip file. When creating or updating a ZipFile, the uncompressed + size is computed during compression. Therefore the value on a + ZipEntry is valid after a call to Save() (or one of its + overloads) in that case. + + + + + + + The ratio of compressed size to uncompressed size of the ZipEntry. + + + + + This is a ratio of the compressed size to the uncompressed size of the + entry, expressed as a double in the range of 0 to 100+. A value of 100 + indicates no compression at all. It could be higher than 100 when the + compression algorithm actually inflates the data, as may occur for small + files, or uncompressible data that is encrypted. + + + + You could format it for presentation to a user via a format string of + "{3,5:F0}%" to see it as a percentage. + + + + If the size of the original uncompressed file is 0, implying a + denominator of 0, the return value will be zero. + + + + This property is valid after reading in an existing zip file, or after + saving the ZipFile that contains the ZipEntry. You cannot know the + effect of a compression transform until you try it. + + + + + + + The 32-bit CRC (Cyclic Redundancy Check) on the contents of the ZipEntry. + + + + + You probably don't need to concern yourself with this. It is used + internally by DotNetZip to verify files or streams upon extraction. + + The value is a 32-bit + CRC using 0xEDB88320 for the polynomial. This is the same CRC-32 used in + PNG, MPEG-2, and other protocols and formats. It is a read-only property; when + creating a Zip archive, the CRC for each entry is set only after a call to + Save() on the containing ZipFile. When reading an existing zip file, the value + of this property reflects the stored CRC for the entry. + + + + + + True if the entry is a directory (not a file). + This is a readonly property on the entry. + + + + + A derived property that is true if the entry uses encryption. + + + + + This is a readonly property on the entry. When reading a zip file, + the value for the ZipEntry is determined by the data read + from the zip file. After saving a ZipFile, the value of this + property for each ZipEntry indicates whether encryption was + actually used (which will have been true if the was set and the property + was something other than . + + + + + + Set this to specify which encryption algorithm to use for the entry when + saving it to a zip archive. + + + + + + Set this property in order to encrypt the entry when the ZipFile is + saved. When setting this property, you must also set a on the entry. If you set a value other than on this property and do not set a + Password then the entry will not be encrypted. The ZipEntry + data is encrypted as the ZipFile is saved, when you call or one of its cousins on the containing + ZipFile instance. You do not need to specify the Encryption + when extracting entries from an archive. + + + + The Zip specification from PKWare defines a set of encryption algorithms, + and the data formats for the zip archive that support them, and PKWare + supports those algorithms in the tools it produces. Other vendors of tools + and libraries, such as WinZip or Xceed, typically support a + subset of the algorithms specified by PKWare. These tools can + sometimes support additional different encryption algorithms and data + formats, not specified by PKWare. The AES Encryption specified and + supported by WinZip is the most popular example. This library supports a + subset of the complete set of algorithms specified by PKWare and other + vendors. + + + + There is no common, ubiquitous multi-vendor standard for strong encryption + within zip files. There is broad support for so-called "traditional" Zip + encryption, sometimes called Zip 2.0 encryption, as specified + by PKWare, but this encryption is considered weak and + breakable. This library currently supports the Zip 2.0 "weak" encryption, + and also a stronger WinZip-compatible AES encryption, using either 128-bit + or 256-bit key strength. If you want DotNetZip to support an algorithm + that is not currently supported, call the author of this library and maybe + we can talk business. + + + + The class also has a property. In most cases you will use + that property when setting encryption. This property takes + precedence over any Encryption set on the ZipFile itself. + Typically, you would use the per-entry Encryption when most entries in the + zip archive use one encryption algorithm, and a few entries use a + different one. If all entries in the zip file use the same Encryption, + then it is simpler to just set this property on the ZipFile itself, when + creating a zip archive. + + + + Some comments on updating archives: If you read a ZipFile, you can + modify the Encryption on an encrypted entry: you can remove encryption + from an entry that was encrypted; you can encrypt an entry that was not + encrypted previously; or, you can change the encryption algorithm. The + changes in encryption are not made permanent until you call Save() on the + ZipFile. To effect changes in encryption, the entry content is + streamed through several transformations, depending on the modification + the application has requested. For example if the entry is not encrypted + and the application sets Encryption to PkzipWeak, then at + the time of Save(), the original entry is read and decompressed, + then re-compressed and encrypted. Conversely, if the original entry is + encrypted with PkzipWeak encryption, and the application sets the + Encryption property to WinZipAes128, then at the time of + Save(), the original entry is decrypted via PKZIP encryption and + decompressed, then re-compressed and re-encrypted with AES. This all + happens automatically within the library, but it can be time-consuming for + large entries. + + + + Additionally, when updating archives, it is not possible to change the + password when changing the encryption algorithm. To change both the + algorithm and the password, you need to Save() the zipfile twice. First + set the Encryption to None, then call Save(). Then set the + Encryption to the new value (not "None"), then call Save() + once again. + + + + The WinZip AES encryption algorithms are not supported on the .NET Compact + Framework. + + + + + + This example creates a zip archive that uses encryption, and then extracts + entries from the archive. When creating the zip archive, the ReadMe.txt + file is zipped without using a password or encryption. The other file + uses encryption. + + + // Create a zip archive with AES Encryption. + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("ReadMe.txt") + ZipEntry e1= zip.AddFile("2008-Regional-Sales-Report.pdf"); + e1.Encryption= EncryptionAlgorithm.WinZipAes256; + e1.Password= "Top.Secret.No.Peeking!"; + zip.Save("EncryptedArchive.zip"); + } + + // Extract a zip archive that uses AES Encryption. + // You do not need to specify the algorithm during extraction. + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + // Specify the password that is used during extraction, for + // all entries that require a password: + zip.Password= "Top.Secret.No.Peeking!"; + zip.ExtractAll("extractDirectory"); + } + + + + ' Create a zip that uses Encryption. + Using zip As New ZipFile() + zip.AddFile("ReadMe.txt") + Dim e1 as ZipEntry + e1= zip.AddFile("2008-Regional-Sales-Report.pdf") + e1.Encryption= EncryptionAlgorithm.WinZipAes256 + e1.Password= "Top.Secret.No.Peeking!" + zip.Save("EncryptedArchive.zip") + End Using + + ' Extract a zip archive that uses AES Encryption. + ' You do not need to specify the algorithm during extraction. + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + ' Specify the password that is used during extraction, for + ' all entries that require a password: + zip.Password= "Top.Secret.No.Peeking!" + zip.ExtractAll("extractDirectory") + End Using + + + + + + Thrown in the setter if EncryptionAlgorithm.Unsupported is specified. + + + ZipEntry.Password + ZipFile.Encryption + + + + The Password to be used when encrypting a ZipEntry upon + ZipFile.Save(), or when decrypting an entry upon Extract(). + + + + + This is a write-only property on the entry. Set this to request that the + entry be encrypted when writing the zip archive, or set it to specify the + password to be used when extracting an existing entry that is encrypted. + + + + The password set here is implicitly used to encrypt the entry during the + operation, or to decrypt during the or operation. If you set + the Password on a ZipEntry after calling Save(), there is no + effect. + + + + Consider setting the property when using a + password. Answering concerns that the standard password protection + supported by all zip tools is weak, WinZip has extended the ZIP + specification with a way to use AES Encryption to protect entries in the + Zip file. Unlike the "PKZIP 2.0" encryption specified in the PKZIP + specification, AES + Encryption uses a standard, strong, tested, encryption + algorithm. DotNetZip can create zip archives that use WinZip-compatible + AES encryption, if you set the property. But, + archives created that use AES encryption may not be readable by all other + tools and libraries. For example, Windows Explorer cannot read a + "compressed folder" (a zip file) that uses AES encryption, though it can + read a zip file that uses "PKZIP encryption." + + + + The class also has a + property. This property takes precedence over any password set on the + ZipFile itself. Typically, you would use the per-entry Password when most + entries in the zip archive use one password, and a few entries use a + different password. If all entries in the zip file use the same password, + then it is simpler to just set this property on the ZipFile itself, + whether creating a zip archive or extracting a zip archive. + + + + Some comments on updating archives: If you read a ZipFile, you + cannot modify the password on any encrypted entry, except by extracting + the entry with the original password (if any), removing the original entry + via , and then adding a new + entry with a new Password. + + + + For example, suppose you read a ZipFile, and there is an encrypted + entry. Setting the Password property on that ZipEntry and then + calling Save() on the ZipFile does not update the password + on that entry in the archive. Neither is an exception thrown. Instead, + what happens during the Save() is the existing entry is copied + through to the new zip archive, in its original encrypted form. Upon + re-reading that archive, the entry can be decrypted with its original + password. + + + + If you read a ZipFile, and there is an un-encrypted entry, you can set the + Password on the entry and then call Save() on the ZipFile, and get + encryption on that entry. + + + + + + + This example creates a zip file with two entries, and then extracts the + entries from the zip file. When creating the zip file, the two files are + added to the zip file using password protection. Each entry uses a + different password. During extraction, each file is extracted with the + appropriate password. + + + // create a file with encryption + using (ZipFile zip = new ZipFile()) + { + ZipEntry entry; + entry= zip.AddFile("Declaration.txt"); + entry.Password= "123456!"; + entry = zip.AddFile("Report.xls"); + entry.Password= "1Secret!"; + zip.Save("EncryptedArchive.zip"); + } + + // extract entries that use encryption + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + ZipEntry entry; + entry = zip["Declaration.txt"]; + entry.Password = "123456!"; + entry.Extract("extractDir"); + entry = zip["Report.xls"]; + entry.Password = "1Secret!"; + entry.Extract("extractDir"); + } + + + + + Using zip As New ZipFile + Dim entry as ZipEntry + entry= zip.AddFile("Declaration.txt") + entry.Password= "123456!" + entry = zip.AddFile("Report.xls") + entry.Password= "1Secret!" + zip.Save("EncryptedArchive.zip") + End Using + + + ' extract entries that use encryption + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + Dim entry as ZipEntry + entry = zip("Declaration.txt") + entry.Password = "123456!" + entry.Extract("extractDir") + entry = zip("Report.xls") + entry.Password = "1Secret!" + entry.Extract("extractDir") + End Using + + + + + + + ZipFile.Password + + + + The action the library should take when extracting a file that already exists. + + + + + This property affects the behavior of the Extract methods (one of the + Extract() or ExtractWithPassword() overloads), when + extraction would would overwrite an existing filesystem file. If you do + not set this property, the library throws an exception when extracting + an entry would overwrite an existing file. + + + + This property has no effect when extracting to a stream, or when the file to be + extracted does not already exist. + + + + + + + This example shows how to set the ExtractExistingFile property in + an ExtractProgress event, in response to user input. The + ExtractProgress event is invoked if and only if the + ExtractExistingFile property was previously set to + ExtractExistingFileAction.InvokeExtractProgressEvent. + + public static void ExtractProgress(object sender, ExtractProgressEventArgs e) + { + if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) + Console.WriteLine("extract {0} ", e.CurrentEntry.FileName); + + else if (e.EventType == ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite) + { + ZipEntry entry = e.CurrentEntry; + string response = null; + // Ask the user if he wants overwrite the file + do + { + Console.Write("Overwrite {0} in {1} ? (y/n/C) ", entry.FileName, e.ExtractLocation); + response = Console.ReadLine(); + Console.WriteLine(); + + } while (response != null && response[0]!='Y' && + response[0]!='N' && response[0]!='C'); + + if (response[0]=='C') + e.Cancel = true; + else if (response[0]=='Y') + entry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently; + else + entry.ExtractExistingFile= ExtractExistingFileAction.DoNotOverwrite; + } + } + + + + + + The action to take when an error is encountered while + opening or reading files as they are saved into a zip archive. + + + + + Errors can occur within a call to ZipFile.Save, as the various files contained + in a ZipFile are being saved into the zip archive. During the + Save, DotNetZip will perform a File.Open on the file + associated to the ZipEntry, and then will read the entire contents of + the file as it is zipped. Either the open or the Read may fail, because + of lock conflicts or other reasons. Using this property, you can + specify the action to take when such errors occur. + + + + Typically you will NOT set this property on individual ZipEntry + instances. Instead, you will set the ZipFile.ZipErrorAction property on + the ZipFile instance, before adding any entries to the + ZipFile. If you do this, errors encountered on behalf of any of + the entries in the ZipFile will be handled the same way. + + + + But, if you use a handler, you will want + to set this property on the ZipEntry within the handler, to + communicate back to DotNetZip what you would like to do with the + particular error. + + + + + + + + + Indicates whether the entry was included in the most recent save. + + + An entry can be excluded or skipped from a save if there is an error + opening or reading the entry. + + + + + + A callback that allows the application to specify the compression to use + for a given entry that is about to be added to the zip archive. + + + + + See + + + + + + Set to indicate whether to use UTF-8 encoding for filenames and comments. + + + + + + If this flag is set, the comment and filename for the entry will be + encoded with UTF-8, as described in the Zip + specification, if necessary. "Necessary" means, the filename or + entry comment (if any) cannot be reflexively encoded and decoded using the + default code page, IBM437. + + + + Setting this flag to true is equivalent to setting to System.Text.Encoding.UTF8. + + + + This flag has no effect or relation to the text encoding used within the + file itself. + + + + + + + The text encoding to use for the FileName and Comment on this ZipEntry, + when the default encoding is insufficient. + + + + + + Don't use this property. See . + + + + + + + Specifies the alternate text encoding used by this ZipEntry + + + + The default text encoding used in Zip files for encoding filenames and + comments is IBM437, which is something like a superset of ASCII. In + cases where this is insufficient, applications can specify an + alternate encoding. + + + When creating a zip file, the usage of the alternate encoding is + governed by the property. + Typically you would set both properties to tell DotNetZip to employ an + encoding that is not IBM437 in the zipfile you are creating. + + + Keep in mind that because the ZIP specification states that the only + valid encodings to use are IBM437 and UTF-8, if you use something + other than that, then zip tools and libraries may not be able to + successfully read the zip archive you generate. + + + The zip specification states that applications should presume that + IBM437 is in use, except when a special bit is set, which indicates + UTF-8. There is no way to specify an arbitrary code page, within the + zip file itself. When you create a zip file encoded with gb2312 or + ibm861 or anything other than IBM437 or UTF-8, then the application + that reads the zip file needs to "know" which code page to use. In + some cases, the code page used when reading is chosen implicitly. For + example, WinRar uses the ambient code page for the host desktop + operating system. The pitfall here is that if you create a zip in + Copenhagen and send it to Tokyo, the reader of the zipfile may not be + able to decode successfully. + + + + This example shows how to create a zipfile encoded with a + language-specific encoding: + + using (var zip = new ZipFile()) + { + zip.AlternateEnoding = System.Text.Encoding.GetEncoding("ibm861"); + zip.AlternateEnodingUsage = ZipOption.Always; + zip.AddFileS(arrayOfFiles); + zip.Save("Myarchive-Encoded-in-IBM861.zip"); + } + + + + + + + Describes if and when this instance should apply + AlternateEncoding to encode the FileName and Comment, when + saving. + + + + + + Indicates whether an entry is marked as a text file. Be careful when + using on this property. Unless you have a good reason, you should + probably ignore this property. + + + + + The ZIP format includes a provision for specifying whether an entry in + the zip archive is a text or binary file. This property exposes that + metadata item. Be careful when using this property: It's not clear + that this property as a firm meaning, across tools and libraries. + + + + To be clear, when reading a zip file, the property value may or may + not be set, and its value may or may not be valid. Not all entries + that you may think of as "text" entries will be so marked, and entries + marked as "text" are not guaranteed in any way to be text entries. + Whether the value is set and set correctly depends entirely on the + application that produced the zip file. + + + + There are many zip tools available, and when creating zip files, some + of them "respect" the IsText metadata field, and some of them do not. + Unfortunately, even when an application tries to do "the right thing", + it's not always clear what "the right thing" is. + + + + There's no firm definition of just what it means to be "a text file", + and the zip specification does not help in this regard. Twenty years + ago, text was ASCII, each byte was less than 127. IsText meant, all + bytes in the file were less than 127. These days, it is not the case + that all text files have all bytes less than 127. Any unicode file + may have bytes that are above 0x7f. The zip specification has nothing + to say on this topic. Therefore, it's not clear what IsText really + means. + + + + This property merely tells a reading application what is stored in the + metadata for an entry, without guaranteeing its validity or its + meaning. + + + + When DotNetZip is used to create a zipfile, it attempts to set this + field "correctly." For example, if a file ends in ".txt", this field + will be set. Your application may override that default setting. When + writing a zip file, you must set the property before calling + Save() on the ZipFile. + + + + When reading a zip file, a more general way to decide just what kind + of file is contained in a particular entry is to use the file type + database stored in the operating system. The operating system stores + a table that says, a file with .jpg extension is a JPG image file, a + file with a .xml extension is an XML document, a file with a .txt is a + pure ASCII text document, and so on. To get this information on + Windows, you + need to read and parse the registry. + + + + + using (var zip = new ZipFile()) + { + var e = zip.UpdateFile("Descriptions.mme", ""); + e.IsText = true; + zip.Save(zipPath); + } + + + + Using zip As New ZipFile + Dim e2 as ZipEntry = zip.AddFile("Descriptions.mme", "") + e.IsText= True + zip.Save(zipPath) + End Using + + + + + + An enum that specifies the type of timestamp available on the ZipEntry. + + + + + + The last modified time of a file can be stored in multiple ways in + a zip file, and they are not mutually exclusive: + + + + + In the so-called "DOS" format, which has a 2-second precision. Values + are rounded to the nearest even second. For example, if the time on the + file is 12:34:43, then it will be stored as 12:34:44. This first value + is accessible via the LastModified property. This value is always + present in the metadata for each zip entry. In some cases the value is + invalid, or zero. + + + + In the so-called "Windows" or "NTFS" format, as an 8-byte integer + quantity expressed as the number of 1/10 milliseconds (in other words + the number of 100 nanosecond units) since January 1, 1601 (UTC). This + format is how Windows represents file times. This time is accessible + via the ModifiedTime property. + + + + In the "Unix" format, a 4-byte quantity specifying the number of seconds since + January 1, 1970 UTC. + + + + In an older format, now deprecated but still used by some current + tools. This format is also a 4-byte quantity specifying the number of + seconds since January 1, 1970 UTC. + + + + + + This bit field describes which of the formats were found in a ZipEntry that was read. + + + + + + + Default value. + + + + + A DOS timestamp with 2-second precision. + + + + + A Windows timestamp with 100-ns precision. + + + + + A Unix timestamp with 1-second precision. + + + + + A Unix timestamp with 1-second precision, stored in InfoZip v1 format. This + format is outdated and is supported for reading archives only. + + + + + The method of compression to use for a particular ZipEntry. + + + + PKWare's + ZIP Specification describes a number of distinct + cmopression methods that can be used within a zip + file. DotNetZip supports a subset of them. + + + + + No compression at all. For COM environments, the value is 0 (zero). + + + + + DEFLATE compression, as described in IETF RFC + 1951. This is the "normal" compression used in zip + files. For COM environments, the value is 8. + + + + + BZip2 compression, a compression algorithm developed by Julian Seward. + For COM environments, the value is 12. + + + + + The ZipFile type represents a zip archive file. + + + + + This is the main type in the DotNetZip class library. This class reads and + writes zip files, as defined in the specification + for zip files described by PKWare. The compression for this + implementation is provided by a managed-code version of Zlib, included with + DotNetZip in the classes in the Ionic.Zlib namespace. + + + + This class provides a general purpose zip file capability. Use it to read, + create, or update zip files. When you want to create zip files using a + Stream type to write the zip file, you may want to consider the class. + + + + Both the ZipOutputStream class and the ZipFile class can + be used to create zip files. Both of them support many of the common zip + features, including Unicode, different compression methods and levels, + and ZIP64. They provide very similar performance when creating zip + files. + + + + The ZipFile class is generally easier to use than + ZipOutputStream and should be considered a higher-level interface. For + example, when creating a zip file via calls to the PutNextEntry() and + Write() methods on the ZipOutputStream class, the caller is + responsible for opening the file, reading the bytes from the file, writing + those bytes into the ZipOutputStream, setting the attributes on the + ZipEntry, and setting the created, last modified, and last accessed + timestamps on the zip entry. All of these things are done automatically by a + call to ZipFile.AddFile(). + For this reason, the ZipOutputStream is generally recommended for use + only when your application emits arbitrary data, not necessarily data from a + filesystem file, directly into a zip file, and does so using a Stream + metaphor. + + + + Aside from the differences in programming model, there are other + differences in capability between the two classes. + + + + + ZipFile can be used to read and extract zip files, in addition to + creating zip files. ZipOutputStream cannot read zip files. If you want + to use a stream to read zip files, check out the class. + + + + ZipOutputStream does not support the creation of segmented or spanned + zip files. + + + + ZipOutputStream cannot produce a self-extracting archive. + + + + + Be aware that the ZipFile class implements the interface. In order for ZipFile to + produce a valid zip file, you use use it within a using clause (Using + in VB), or call the Dispose() method explicitly. See the examples + for how to employ a using clause. + + + + + + + Adds an item, either a file or a directory, to a zip file archive. + + + + + This method is handy if you are adding things to zip archive and don't + want to bother distinguishing between directories or files. Any files are + added as single entries. A directory added through this method is added + recursively: all files and subdirectories contained within the directory + are added to the ZipFile. + + + + The name of the item may be a relative path or a fully-qualified + path. Remember, the items contained in ZipFile instance get written + to the disk only when you call or a similar + save method. + + + + The directory name used for the file within the archive is the same + as the directory name (potentially a relative path) specified in the + . + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + This method has two overloads. + + the name of the file or directory to add. + + The ZipEntry added. + + + + Adds an item, either a file or a directory, to a zip file archive, + explicitly specifying the directory path to be used in the archive. + + + + + If adding a directory, the add is recursive on all files and + subdirectories contained within it. + + + The name of the item may be a relative path or a fully-qualified path. + The item added by this call to the ZipFile is not read from the + disk nor written to the zip file archive until the application calls + Save() on the ZipFile. + + + + This version of the method allows the caller to explicitly specify the + directory path to be used in the archive, which would override the + "natural" path of the filesystem file. + + + + Encryption will be used on the file data if the Password has + been set on the ZipFile object, prior to calling this method. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + Thrown if the file or directory passed in does not exist. + + + the name of the file or directory to add. + + + + The name of the directory path to use within the zip archive. This path + need not refer to an extant directory in the current filesystem. If the + files within the zip are later extracted, this is the path used for the + extracted file. Passing null (Nothing in VB) will use the + path on the fileOrDirectoryName. Passing the empty string ("") will + insert the item at the root path within the archive. + + + + + + + + This example shows how to zip up a set of files into a flat hierarchy, + regardless of where in the filesystem the files originated. The resulting + zip archive will contain a toplevel directory named "flat", which itself + will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A + subdirectory under "flat" called SupportFiles will contain all the files + in the "c:\SupportFiles" directory on disk. + + + String[] itemnames= { + "c:\\fixedContent\\Readme.txt", + "MyProposal.docx", + "c:\\SupportFiles", // a directory + "images\\Image1.jpg" + }; + + try + { + using (ZipFile zip = new ZipFile()) + { + for (int i = 1; i < itemnames.Length; i++) + { + // will add Files or Dirs, recurses and flattens subdirectories + zip.AddItem(itemnames[i],"flat"); + } + zip.Save(ZipToCreate); + } + } + catch (System.Exception ex1) + { + System.Console.Error.WriteLine("exception: {0}", ex1); + } + + + + Dim itemnames As String() = _ + New String() { "c:\fixedContent\Readme.txt", _ + "MyProposal.docx", _ + "SupportFiles", _ + "images\Image1.jpg" } + Try + Using zip As New ZipFile + Dim i As Integer + For i = 1 To itemnames.Length - 1 + ' will add Files or Dirs, recursing and flattening subdirectories. + zip.AddItem(itemnames(i), "flat") + Next i + zip.Save(ZipToCreate) + End Using + Catch ex1 As Exception + Console.Error.WriteLine("exception: {0}", ex1.ToString()) + End Try + + + The ZipEntry added. + + + + Adds a File to a Zip file archive. + + + + + This call collects metadata for the named file in the filesystem, + including the file attributes and the timestamp, and inserts that metadata + into the resulting ZipEntry. Only when the application calls Save() on + the ZipFile, does DotNetZip read the file from the filesystem and + then write the content to the zip file archive. + + + + This method will throw an exception if an entry with the same name already + exists in the ZipFile. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + In this example, three files are added to a Zip archive. The ReadMe.txt + file will be placed in the root of the archive. The .png file will be + placed in a folder within the zip called photos\personal. The pdf file + will be included into a folder within the zip called Desktop. + + + try + { + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("c:\\photos\\personal\\7440-N49th.png"); + zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf"); + zip.AddFile("ReadMe.txt"); + + zip.Save("Package.zip"); + } + } + catch (System.Exception ex1) + { + System.Console.Error.WriteLine("exception: " + ex1); + } + + + + Try + Using zip As ZipFile = New ZipFile + zip.AddFile("c:\photos\personal\7440-N49th.png") + zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf") + zip.AddFile("ReadMe.txt") + zip.Save("Package.zip") + End Using + Catch ex1 As Exception + Console.Error.WriteLine("exception: {0}", ex1.ToString) + End Try + + + + This method has two overloads. + + + + + + + The name of the file to add. It should refer to a file in the filesystem. + The name of the file may be a relative path or a fully-qualified path. + + The ZipEntry corresponding to the File added. + + + + Adds a File to a Zip file archive, potentially overriding the path to be + used within the zip archive. + + + + + The file added by this call to the ZipFile is not written to the + zip file archive until the application calls Save() on the ZipFile. + + + + This method will throw an exception if an entry with the same name already + exists in the ZipFile. + + + + This version of the method allows the caller to explicitly specify the + directory path to be used in the archive. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + In this example, three files are added to a Zip archive. The ReadMe.txt + file will be placed in the root of the archive. The .png file will be + placed in a folder within the zip called images. The pdf file will be + included into a folder within the zip called files\docs, and will be + encrypted with the given password. + + + try + { + using (ZipFile zip = new ZipFile()) + { + // the following entry will be inserted at the root in the archive. + zip.AddFile("c:\\datafiles\\ReadMe.txt", ""); + // this image file will be inserted into the "images" directory in the archive. + zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images"); + // the following will result in a password-protected file called + // files\\docs\\2008-Regional-Sales-Report.pdf in the archive. + zip.Password = "EncryptMe!"; + zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs"); + zip.Save("Archive.zip"); + } + } + catch (System.Exception ex1) + { + System.Console.Error.WriteLine("exception: {0}", ex1); + } + + + + Try + Using zip As ZipFile = New ZipFile + ' the following entry will be inserted at the root in the archive. + zip.AddFile("c:\datafiles\ReadMe.txt", "") + ' this image file will be inserted into the "images" directory in the archive. + zip.AddFile("c:\photos\personal\7440-N49th.png", "images") + ' the following will result in a password-protected file called + ' files\\docs\\2008-Regional-Sales-Report.pdf in the archive. + zip.Password = "EncryptMe!" + zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents") + zip.Save("Archive.zip") + End Using + Catch ex1 As Exception + Console.Error.WriteLine("exception: {0}", ex1) + End Try + + + + + + + + + The name of the file to add. The name of the file may be a relative path + or a fully-qualified path. + + + + Specifies a directory path to use to override any path in the fileName. + This path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on the fileName, if any. Passing the empty string + ("") will insert the item at the root path within the archive. + + + The ZipEntry corresponding to the file added. + + + + This method removes a collection of entries from the ZipFile. + + + + A collection of ZipEntry instances from this zip file to be removed. For + example, you can pass in an array of ZipEntry instances; or you can call + SelectEntries(), and then add or remove entries from that + ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass + that ICollection to this method. + + + + + + + + This method removes a collection of entries from the ZipFile, by name. + + + + A collection of strings that refer to names of entries to be removed + from the ZipFile. For example, you can pass in an array or a + List of Strings that provide the names of entries to be removed. + + + + + + + + This method adds a set of files to the ZipFile. + + + + + Use this method to add a set of files to the zip archive, in one call. + For example, a list of files received from + System.IO.Directory.GetFiles() can be added to a zip archive in one + call. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + The collection of names of the files to add. Each string should refer to a + file in the filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + This example shows how to create a zip file, and add a few files into it. + + String ZipFileToCreate = "archive1.zip"; + String DirectoryToZip = "c:\\reports"; + using (ZipFile zip = new ZipFile()) + { + // Store all files found in the top level directory, into the zip archive. + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames); + zip.Save(ZipFileToCreate); + } + + + + Dim ZipFileToCreate As String = "archive1.zip" + Dim DirectoryToZip As String = "c:\reports" + Using zip As ZipFile = New ZipFile + ' Store all files found in the top level directory, into the zip archive. + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames) + zip.Save(ZipFileToCreate) + End Using + + + + + + + + Adds or updates a set of files in the ZipFile. + + + + + Any files that already exist in the archive are updated. Any files that + don't yet exist in the archive are added. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + The collection of names of the files to update. Each string should refer to a file in + the filesystem. The name of the file may be a relative path or a fully-qualified path. + + + + + + Adds a set of files to the ZipFile, using the + specified directory path in the archive. + + + + + Any directory structure that may be present in the + filenames contained in the list is "flattened" in the + archive. Each file in the list is added to the archive in + the specified top-level directory. + + + + For ZipFile properties including , , , , , , and , their respective values at the + time of this call will be applied to each ZipEntry added. + + + + + The names of the files to add. Each string should refer to + a file in the filesystem. The name of the file may be a + relative path or a fully-qualified path. + + + + Specifies a directory path to use to override any path in the file name. + Th is path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on each of the fileNames, if any. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + + + + Adds a set of files to the ZipFile, using the specified directory + path in the archive, and preserving the full directory structure in the + filenames. + + + + + If preserveDirHierarchy is true, any directory structure present in the + filenames contained in the list is preserved in the archive. On the other + hand, if preserveDirHierarchy is false, any directory structure that may + be present in the filenames contained in the list is "flattened" in the + archive; Each file in the list is added to the archive in the specified + top-level directory. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + + The names of the files to add. Each string should refer to a file in the + filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + Specifies a directory path to use to override any path in the file name. + This path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on each of the fileNames, if any. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + whether the entries in the zip archive will reflect the directory + hierarchy that is present in the various filenames. For example, if + includes two paths, \Animalia\Chordata\Mammalia\Info.txt and + \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method with + = false will result in an + exception because of a duplicate entry name, while calling this method + with = true will result in the + full direcory paths being included in the entries added to the ZipFile. + + + + + + Adds or updates a set of files to the ZipFile, using the specified + directory path in the archive. + + + + + + Any files that already exist in the archive are updated. Any files that + don't yet exist in the archive are added. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + The names of the files to add or update. Each string should refer to a + file in the filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + Specifies a directory path to use to override any path in the file name. + This path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on each of the fileNames, if any. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + + + + Adds or Updates a File in a Zip file archive. + + + + + This method adds a file to a zip archive, or, if the file already exists + in the zip archive, this method Updates the content of that given filename + in the zip archive. The UpdateFile method might more accurately be + called "AddOrUpdateFile". + + + + Upon success, there is no way for the application to learn whether the file + was added versus updated. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + This example shows how to Update an existing entry in a zipfile. The first + call to UpdateFile adds the file to the newly-created zip archive. The + second call to UpdateFile updates the content for that file in the zip + archive. + + + using (ZipFile zip1 = new ZipFile()) + { + // UpdateFile might more accurately be called "AddOrUpdateFile" + zip1.UpdateFile("MyDocuments\\Readme.txt"); + zip1.UpdateFile("CustomerList.csv"); + zip1.Comment = "This zip archive has been created."; + zip1.Save("Content.zip"); + } + + using (ZipFile zip2 = ZipFile.Read("Content.zip")) + { + zip2.UpdateFile("Updates\\Readme.txt"); + zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."; + zip2.Save(); + } + + + + Using zip1 As New ZipFile + ' UpdateFile might more accurately be called "AddOrUpdateFile" + zip1.UpdateFile("MyDocuments\Readme.txt") + zip1.UpdateFile("CustomerList.csv") + zip1.Comment = "This zip archive has been created." + zip1.Save("Content.zip") + End Using + + Using zip2 As ZipFile = ZipFile.Read("Content.zip") + zip2.UpdateFile("Updates\Readme.txt") + zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed." + zip2.Save + End Using + + + + + + + + + The name of the file to add or update. It should refer to a file in the + filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + The ZipEntry corresponding to the File that was added or updated. + + + + + Adds or Updates a File in a Zip file archive. + + + + + This method adds a file to a zip archive, or, if the file already exists + in the zip archive, this method Updates the content of that given filename + in the zip archive. + + + + This version of the method allows the caller to explicitly specify the + directory path to be used in the archive. The entry to be added or + updated is found by using the specified directory path, combined with the + basename of the specified filename. + + + + Upon success, there is no way for the application to learn if the file was + added versus updated. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + The name of the file to add or update. It should refer to a file in the + filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + Specifies a directory path to use to override any path in the + fileName. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (Nothing in VB) will use the path on the + fileName, if any. Passing the empty string ("") will insert the + item at the root path within the archive. + + + + The ZipEntry corresponding to the File that was added or updated. + + + + + Add or update a directory in a zip archive. + + + + If the specified directory does not exist in the archive, then this method + is equivalent to calling AddDirectory(). If the specified + directory already exists in the archive, then this method updates any + existing entries, and adds any new entries. Any entries that are in the + zip archive but not in the specified directory, are left alone. In other + words, the contents of the zip file will be a union of the previous + contents and the new files. + + + + + + + + The path to the directory to be added to the zip archive, or updated in + the zip archive. + + + + The ZipEntry corresponding to the Directory that was added or updated. + + + + + Add or update a directory in the zip archive at the specified root + directory in the archive. + + + + If the specified directory does not exist in the archive, then this method + is equivalent to calling AddDirectory(). If the specified + directory already exists in the archive, then this method updates any + existing entries, and adds any new entries. Any entries that are in the + zip archive but not in the specified directory, are left alone. In other + words, the contents of the zip file will be a union of the previous + contents and the new files. + + + + + + + + The path to the directory to be added to the zip archive, or updated + in the zip archive. + + + + Specifies a directory path to use to override any path in the + directoryName. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (Nothing in VB) will use the path on the + directoryName, if any. Passing the empty string ("") will insert + the item at the root path within the archive. + + + + The ZipEntry corresponding to the Directory that was added or updated. + + + + + Add or update a file or directory in the zip archive. + + + + + This is useful when the application is not sure or does not care if the + item to be added is a file or directory, and does not know or does not + care if the item already exists in the ZipFile. Calling this method + is equivalent to calling RemoveEntry() if an entry by the same name + already exists, followed calling by AddItem(). + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + the path to the file or directory to be added or updated. + + + + + Add or update a file or directory. + + + + + This method is useful when the application is not sure or does not care if + the item to be added is a file or directory, and does not know or does not + care if the item already exists in the ZipFile. Calling this method + is equivalent to calling RemoveEntry(), if an entry by that name + exists, and then calling AddItem(). + + + + This version of the method allows the caller to explicitly specify the + directory path to be used for the item being added to the archive. The + entry or entries that are added or updated will use the specified + DirectoryPathInArchive. Extracting the entry from the archive will + result in a file stored in that directory path. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + The path for the File or Directory to be added or updated. + + + Specifies a directory path to use to override any path in the + itemName. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (Nothing in VB) will use the path on the + itemName, if any. Passing the empty string ("") will insert the + item at the root path within the archive. + + + + + Adds a named entry into the zip archive, taking content for the entry + from a string. + + + + Calling this method creates an entry using the given fileName and + directory path within the archive. There is no need for a file by the + given name to exist in the filesystem; the name is used within the zip + archive only. The content for the entry is encoded using the default text + encoding for the machine, or on Silverlight, using UTF-8. + + + + The content of the file, should it be extracted from the zip. + + + + The name, including any path, to use for the entry within the archive. + + + The ZipEntry added. + + + + This example shows how to add an entry to the zipfile, using a string as + content for that entry. + + + string Content = "This string will be the content of the Readme.txt file in the zip archive."; + using (ZipFile zip1 = new ZipFile()) + { + zip1.AddFile("MyDocuments\\Resume.doc", "files"); + zip1.AddEntry("Readme.txt", Content); + zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G"); + zip1.Save("Content.zip"); + } + + + + Public Sub Run() + Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive." + Using zip1 As ZipFile = New ZipFile + zip1.AddEntry("Readme.txt", Content) + zip1.AddFile("MyDocuments\Resume.doc", "files") + zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G")) + zip1.Save("Content.zip") + End Using + End Sub + + + + + + Adds a named entry into the zip archive, taking content for the entry + from a string, and using the specified text encoding. + + + + + + Calling this method creates an entry using the given fileName and + directory path within the archive. There is no need for a file by the + given name to exist in the filesystem; the name is used within the zip + archive only. + + + + The content for the entry, a string value, is encoded using the given + text encoding. A BOM (byte-order-mark) is emitted into the file, if the + Encoding parameter is set for that. + + + + Most Encoding classes support a constructor that accepts a boolean, + indicating whether to emit a BOM or not. For example see . + + + + + + The name, including any path, to use within the archive for the entry. + + + + The content of the file, should it be extracted from the zip. + + + + The text encoding to use when encoding the string. Be aware: This is + distinct from the text encoding used to encode the fileName, as specified + in . + + + The ZipEntry added. + + + + + Create an entry in the ZipFile using the given Stream + as input. The entry will have the given filename. + + + + + + The application should provide an open, readable stream; in this case it + will be read during the call to or one of + its overloads. + + + + The passed stream will be read from its current position. If + necessary, callers should set the position in the stream before + calling AddEntry(). This might be appropriate when using this method + with a MemoryStream, for example. + + + + In cases where a large number of streams will be added to the + ZipFile, the application may wish to avoid maintaining all of the + streams open simultaneously. To handle this situation, the application + should use the + overload. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + This example adds a single entry to a ZipFile via a Stream. + + + + String zipToCreate = "Content.zip"; + String fileNameInArchive = "Content-From-Stream.bin"; + using (System.IO.Stream streamToRead = MyStreamOpener()) + { + using (ZipFile zip = new ZipFile()) + { + ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead); + zip.AddFile("Readme.txt"); + zip.Save(zipToCreate); // the stream is read implicitly here + } + } + + + + Dim zipToCreate As String = "Content.zip" + Dim fileNameInArchive As String = "Content-From-Stream.bin" + Using streamToRead as System.IO.Stream = MyStreamOpener() + Using zip As ZipFile = New ZipFile() + Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead) + zip.AddFile("Readme.txt") + zip.Save(zipToCreate) '' the stream is read implicitly, here + End Using + End Using + + + + + + + The name, including any path, which is shown in the zip file for the added + entry. + + + The input stream from which to grab content for the file + + The ZipEntry added. + + + + Add a ZipEntry for which content is written directly by the application. + + + + + When the application needs to write the zip entry data, use this + method to add the ZipEntry. For example, in the case that the + application wishes to write the XML representation of a DataSet into + a ZipEntry, the application can use this method to do so. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + About progress events: When using the WriteDelegate, DotNetZip does + not issue any SaveProgress events with EventType = + Saving_EntryBytesRead. (This is because it is the + application's code that runs in WriteDelegate - there's no way for + DotNetZip to know when to issue a EntryBytesRead event.) + Applications that want to update a progress bar or similar status + indicator should do so from within the WriteDelegate + itself. DotNetZip will issue the other SaveProgress events, + including + Saving_Started, + + Saving_BeforeWriteEntry, and + Saving_AfterWriteEntry. + + + + Note: When you use PKZip encryption, it's normally necessary to + compute the CRC of the content to be encrypted, before compressing or + encrypting it. Therefore, when using PKZip encryption with a + WriteDelegate, the WriteDelegate CAN BE called twice: once to compute + the CRC, and the second time to potentially compress and + encrypt. Surprising, but true. This is because PKWARE specified that + the encryption initialization data depends on the CRC. + If this happens, for each call of the delegate, your + application must stream the same entry data in its entirety. If your + application writes different data during the second call, it will + result in a corrupt zip file. + + + + The double-read behavior happens with all types of entries, not only + those that use WriteDelegate. It happens if you add an entry from a + filesystem file, or using a string, or a stream, or an opener/closer + pair. But in those cases, DotNetZip takes care of reading twice; in + the case of the WriteDelegate, the application code gets invoked + twice. Be aware. + + + + As you can imagine, this can cause performance problems for large + streams, and it can lead to correctness problems when you use a + WriteDelegate. This is a pretty big pitfall. There are two + ways to avoid it. First, and most preferred: don't use PKZIP + encryption. If you use the WinZip AES encryption, this problem + doesn't occur, because the encryption protocol doesn't require the CRC + up front. Second: if you do choose to use PKZIP encryption, write out + to a non-seekable stream (like standard output, or the + Response.OutputStream in an ASP.NET application). In this case, + DotNetZip will use an alternative encryption protocol that does not + rely on the CRC of the content. This also implies setting bit 3 in + the zip entry, which still presents problems for some zip tools. + + + + In the future I may modify DotNetZip to *always* use bit 3 when PKZIP + encryption is in use. This seems like a win overall, but there will + be some work involved. If you feel strongly about it, visit the + DotNetZip forums and vote up the Workitem + tracking this issue. + + + + + the name of the entry to add + the delegate which will write the entry content + the ZipEntry added + + + + This example shows an application filling a DataSet, then saving the + contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an + anonymous delegate in C#. The DataSet XML is never saved to a disk file. + + + var c1= new System.Data.SqlClient.SqlConnection(connstring1); + var da = new System.Data.SqlClient.SqlDataAdapter() + { + SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1) + }; + + DataSet ds1 = new DataSet(); + da.Fill(ds1, "Invoices"); + + using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) + { + zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) ); + zip.Save(zipFileName); + } + + + + + + This example uses an anonymous method in C# as the WriteDelegate to provide + the data for the ZipEntry. The example is a bit contrived - the + AddFile() method is a simpler way to insert the contents of a file + into an entry in a zip file. On the other hand, if there is some sort of + processing or transformation of the file contents required before writing, + the application could use the WriteDelegate to do it, in this way. + + + using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite )) + { + using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) + { + zip.AddEntry(zipEntryName, (name,output) => + { + byte[] buffer = new byte[BufferSize]; + int n; + while ((n = input.Read(buffer, 0, buffer.Length)) != 0) + { + // could transform the data here... + output.Write(buffer, 0, n); + // could update a progress bar here + } + }); + + zip.Save(zipFileName); + } + } + + + + + + This example uses a named delegate in VB to write data for the given + ZipEntry (VB9 does not have anonymous delegates). The example here is a bit + contrived - a simpler way to add the contents of a file to a ZipEntry is to + simply use the appropriate AddFile() method. The key scenario for + which the WriteDelegate makes sense is saving a DataSet, in XML + format, to the zip file. The DataSet can write XML to a stream, and the + WriteDelegate is the perfect place to write into the zip file. There may be + other data structures that can write to a stream, but cannot be read as a + stream. The WriteDelegate would be appropriate for those cases as + well. + + + Private Sub WriteEntry (ByVal name As String, ByVal output As Stream) + Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) + Dim n As Integer = -1 + Dim buffer As Byte() = New Byte(BufferSize){} + Do While n <> 0 + n = input.Read(buffer, 0, buffer.Length) + output.Write(buffer, 0, n) + Loop + End Using + End Sub + + Public Sub Run() + Using zip = New ZipFile + zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) + zip.Save(zipFileName) + End Using + End Sub + + + + + + Add an entry, for which the application will provide a stream, + just-in-time. + + + + + In cases where the application wishes to open the stream that holds + the content for the ZipEntry, on a just-in-time basis, the application + can use this method and provide delegates to open and close the + stream. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + This example uses anonymous methods in C# to open and close the + source stream for the content for a zip entry. In a real + application, the logic for the OpenDelegate would probably be more + involved. + + + using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) + { + zip.AddEntry(zipEntryName, + (name) => File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ), + (name, stream) => stream.Close() + ); + + zip.Save(zipFileName); + } + + + + + + + This example uses delegates in VB.NET to open and close the + the source stream for the content for a zip entry. VB 9.0 lacks + support for "Sub" lambda expressions, and so the CloseDelegate must + be an actual, named Sub. + + + + Function MyStreamOpener(ByVal entryName As String) As Stream + '' This simply opens a file. You probably want to do somethinig + '' more involved here: open a stream to read from a database, + '' open a stream on an HTTP connection, and so on. + Return File.OpenRead(entryName) + End Function + + Sub MyStreamCloser(entryName As String, stream As Stream) + stream.Close() + End Sub + + Public Sub Run() + Dim dirToZip As String = "fodder" + Dim zipFileToCreate As String = "Archive.zip" + Dim opener As OpenDelegate = AddressOf MyStreamOpener + Dim closer As CloseDelegate = AddressOf MyStreamCloser + Dim numFilestoAdd As Int32 = 4 + Using zip As ZipFile = New ZipFile + Dim i As Integer + For i = 0 To numFilesToAdd - 1 + zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer) + Next i + zip.Save(zipFileToCreate) + End Using + End Sub + + + + + the name of the entry to add + + the delegate that will be invoked to open the stream + + + the delegate that will be invoked to close the stream + + the ZipEntry added + + + + + Updates the given entry in the ZipFile, using the given + string as content for the ZipEntry. + + + + + + Calling this method is equivalent to removing the ZipEntry for + the given file name and directory path, if it exists, and then calling + . See the documentation for + that method for further explanation. The string content is encoded + using the default encoding for the machine, or on Silverlight, using + UTF-8. This encoding is distinct from the encoding used for the + filename itself. See . + + + + + + The name, including any path, to use within the archive for the entry. + + + + The content of the file, should it be extracted from the zip. + + + The ZipEntry added. + + + + + Updates the given entry in the ZipFile, using the given string as + content for the ZipEntry. + + + + Calling this method is equivalent to removing the ZipEntry for the + given file name and directory path, if it exists, and then calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + + The content of the file, should it be extracted from the zip. + + + + The text encoding to use when encoding the string. Be aware: This is + distinct from the text encoding used to encode the filename. See . + + + The ZipEntry added. + + + + + Updates the given entry in the ZipFile, using the given delegate + as the source for content for the ZipEntry. + + + + Calling this method is equivalent to removing the ZipEntry for the + given file name and directory path, if it exists, and then calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + the delegate which will write the entry content. + + The ZipEntry added. + + + + + Updates the given entry in the ZipFile, using the given delegates + to open and close the stream that provides the content for the ZipEntry. + + + + Calling this method is equivalent to removing the ZipEntry for the + given file name and directory path, if it exists, and then calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + + the delegate that will be invoked to open the stream + + + the delegate that will be invoked to close the stream + + + The ZipEntry added or updated. + + + + + Updates the given entry in the ZipFile, using the given stream as + input, and the given filename and given directory Path. + + + + + Calling the method is equivalent to calling RemoveEntry() if an + entry by the same name already exists, and then calling AddEntry() + with the given fileName and stream. + + + + The stream must be open and readable during the call to + ZipFile.Save. You can dispense the stream on a just-in-time basis + using the property. Check the + documentation of that property for more information. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + The name, including any path, to use within the archive for the entry. + + + The input stream from which to read file data. + The ZipEntry added. + + + + Add an entry into the zip archive using the given filename and + directory path within the archive, and the given content for the + file. No file is created in the filesystem. + + + The data to use for the entry. + + + The name, including any path, to use within the archive for the entry. + + + The ZipEntry added. + + + + Updates the given entry in the ZipFile, using the given byte + array as content for the entry. + + + + Calling this method is equivalent to removing the ZipEntry + for the given filename and directory path, if it exists, and then + calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + The content to use for the ZipEntry. + + The ZipEntry added. + + + + + Adds the contents of a filesystem directory to a Zip file archive. + + + + + + The name of the directory may be a relative path or a fully-qualified + path. Any files within the named directory are added to the archive. Any + subdirectories within the named directory are also added to the archive, + recursively. + + + + Top-level entries in the named directory will appear as top-level entries + in the zip archive. Entries in subdirectories in the named directory will + result in entries in subdirectories in the zip archive. + + + + If you want the entries to appear in a containing directory in the zip + archive itself, then you should call the AddDirectory() overload that + allows you to explicitly specify a directory path for use in the archive. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + + + + + + This method has 2 overloads. + + The name of the directory to add. + The ZipEntry added. + + + + Adds the contents of a filesystem directory to a Zip file archive, + overriding the path to be used for entries in the archive. + + + + + The name of the directory may be a relative path or a fully-qualified + path. The add operation is recursive, so that any files or subdirectories + within the name directory are also added to the archive. + + + + Top-level entries in the named directory will appear as top-level entries + in the zip archive. Entries in subdirectories in the named directory will + result in entries in subdirectories in the zip archive. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + + + In this code, calling the ZipUp() method with a value of "c:\reports" for + the directory parameter will result in a zip file structure in which all + entries are contained in a toplevel "reports" directory. + + + + public void ZipUp(string targetZip, string directory) + { + using (var zip = new ZipFile()) + { + zip.AddDirectory(directory, System.IO.Path.GetFileName(directory)); + zip.Save(targetZip); + } + } + + + + + + + + The name of the directory to add. + + + Specifies a directory path to use to override any path in the + DirectoryName. This path may, or may not, correspond to a real directory + in the current filesystem. If the zip is later extracted, this is the + path used for the extracted file or directory. Passing null + (Nothing in VB) or the empty string ("") will insert the items at + the root path within the archive. + + + The ZipEntry added. + + + + Creates a directory in the zip archive. + + + + + + Use this when you want to create a directory in the archive but there is + no corresponding filesystem representation for that directory. + + + + You will probably not need to do this in your code. One of the only times + you will want to do this is if you want an empty directory in the zip + archive. The reason: if you add a file to a zip archive that is stored + within a multi-level directory, all of the directory tree is implicitly + created in the zip archive. + + + + + + The name of the directory to create in the archive. + + The ZipEntry added. + + + + Checks a zip file to see if its directory is consistent. + + + + + + In cases of data error, the directory within a zip file can get out + of synch with the entries in the zip file. This method checks the + given zip file and returns true if this has occurred. + + + This method may take a long time to run for large zip files. + + + This method is not supported in the Reduced or Compact Framework + versions of DotNetZip. + + + + Developers using COM can use the ComHelper.CheckZip(String) + method. + + + + + The filename to of the zip file to check. + + true if the named zip file checks OK. Otherwise, false. + + + + + + + Checks a zip file to see if its directory is consistent, + and optionally fixes the directory if necessary. + + + + + + In cases of data error, the directory within a zip file can get out of + synch with the entries in the zip file. This method checks the given + zip file, and returns true if this has occurred. It also optionally + fixes the zipfile, saving the fixed copy in Name_Fixed.zip. + + + + This method may take a long time to run for large zip files. It + will take even longer if the file actually needs to be fixed, and if + fixIfNecessary is true. + + + + This method is not supported in the Reduced or Compact + Framework versions of DotNetZip. + + + + + The filename to of the zip file to check. + + If true, the method will fix the zip file if + necessary. + + + a TextWriter in which messages generated while checking will be written. + + + true if the named zip is OK; false if the file needs to be fixed. + + + + + + + Rewrite the directory within a zipfile. + + + + + + In cases of data error, the directory in a zip file can get out of + synch with the entries in the zip file. This method attempts to fix + the zip file if this has occurred. + + + This can take a long time for large zip files. + + This won't work if the zip file uses a non-standard + code page - neither IBM437 nor UTF-8. + + + This method is not supported in the Reduced or Compact Framework + versions of DotNetZip. + + + + Developers using COM can use the ComHelper.FixZipDirectory(String) + method. + + + + + The filename to of the zip file to fix. + + + + + + + Verify the password on a zip file. + + + + + Keep in mind that passwords in zipfiles are applied to + zip entries, not to the entire zip file. So testing a + zipfile for a particular password doesn't work in the + general case. On the other hand, it's often the case + that a single password will be used on all entries in a + zip file. This method works for that case. + + + There is no way to check a password without doing the + decryption. So this code decrypts and extracts the given + zipfile into + + + + The filename to of the zip file to fix. + + The password to check. + + a bool indicating whether the password matches. + + + + Returns true if an entry by the given name exists in the ZipFile. + + + the name of the entry to find + true if an entry with the given name exists; otherwise false. + + + + Provides a string representation of the instance. + a string representation of the instance. + + + + Creates a new ZipFile instance, using the specified filename. + + + + + Applications can use this constructor to create a new ZipFile for writing, + or to slurp in an existing zip archive for read and update purposes. + + + + To create a new zip archive, an application can call this constructor, + passing the name of a file that does not exist. The name may be a fully + qualified path. Then the application can add directories or files to the + ZipFile via AddDirectory(), AddFile(), AddItem() + and then write the zip archive to the disk by calling Save(). The + zip file is not actually opened and written to the disk until the + application calls ZipFile.Save(). At that point the new zip file + with the given name is created. + + + + If you won't know the name of the Zipfile until the time you call + ZipFile.Save(), or if you plan to save to a stream (which has no + name), then you should use the no-argument constructor. + + + + The application can also call this constructor to read an existing zip + archive. passing the name of a valid zip file that does exist. But, it's + better form to use the static method, + passing the name of the zip file, because using ZipFile.Read() in + your code communicates very clearly what you are doing. In either case, + the file is then read into the ZipFile instance. The app can then + enumerate the entries or can modify the zip file, for example adding + entries, removing entries, changing comments, and so on. + + + + One advantage to this parameterized constructor: it allows applications to + use the same code to add items to a zip archive, regardless of whether the + zip file exists. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + By the way, since DotNetZip is so easy to use, don't you think you should + donate $5 or $10? + + + + + + Thrown if name refers to an existing file that is not a valid zip file. + + + + This example shows how to create a zipfile, and add a few files into it. + + String ZipFileToCreate = "archive1.zip"; + String DirectoryToZip = "c:\\reports"; + using (ZipFile zip = new ZipFile()) + { + // Store all files found in the top level directory, into the zip archive. + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames, "files"); + zip.Save(ZipFileToCreate); + } + + + + Dim ZipFileToCreate As String = "archive1.zip" + Dim DirectoryToZip As String = "c:\reports" + Using zip As ZipFile = New ZipFile() + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames, "files") + zip.Save(ZipFileToCreate) + End Using + + + + The filename to use for the new zip archive. + + + + + Creates a new ZipFile instance, using the specified name for the + filename, and the specified Encoding. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + The Encoding is used as the default alternate encoding for entries with + filenames or comments that cannot be encoded with the IBM437 code page. + This is equivalent to setting the property on the ZipFile + instance after construction. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + + + Thrown if name refers to an existing file that is not a valid zip file. + + + The filename to use for the new zip archive. + The Encoding is used as the default alternate + encoding for entries with filenames or comments that cannot be encoded + with the IBM437 code page. + + + + Create a zip file, without specifying a target filename or stream to save to. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + After instantiating with this constructor and adding entries to the + archive, the application should call or + to save to a file or a + stream, respectively. The application can also set the + property and then call the no-argument method. (This + is the preferred approach for applications that use the library through + COM interop.) If you call the no-argument method + without having set the Name of the ZipFile, either through + the parameterized constructor or through the explicit property , the + Save() will throw, because there is no place to save the file. + + + Instances of the ZipFile class are not multi-thread safe. You may + have multiple threads that each use a distinct ZipFile instance, or + you can synchronize multi-thread access to a single instance. + + + + + This example creates a Zip archive called Backup.zip, containing all the files + in the directory DirectoryToZip. Files within subdirectories are not zipped up. + + using (ZipFile zip = new ZipFile()) + { + // Store all files found in the top level directory, into the zip archive. + // note: this code does not recurse subdirectories! + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames, "files"); + zip.Save("Backup.zip"); + } + + + + Using zip As New ZipFile + ' Store all files found in the top level directory, into the zip archive. + ' note: this code does not recurse subdirectories! + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames, "files") + zip.Save("Backup.zip") + End Using + + + + + + Create a zip file, specifying a text Encoding, but without specifying a + target filename or stream to save to. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + + + The Encoding is used as the default alternate encoding for entries with + filenames or comments that cannot be encoded with the IBM437 code page. + + + + + Creates a new ZipFile instance, using the specified name for the + filename, and the specified status message writer. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + This version of the constructor allows the caller to pass in a TextWriter, + to which verbose messages will be written during extraction or creation of + the zip archive. A console application may wish to pass + System.Console.Out to get messages on the Console. A graphical or headless + application may wish to capture the messages in a different + TextWriter, for example, a StringWriter, and then display + the messages in a TextBox, or generate an audit log of ZipFile operations. + + + + To encrypt the data for the files added to the ZipFile instance, + set the Password property after creating the ZipFile instance. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + + + Thrown if name refers to an existing file that is not a valid zip file. + + + + + using (ZipFile zip = new ZipFile("Backup.zip", Console.Out)) + { + // Store all files found in the top level directory, into the zip archive. + // note: this code does not recurse subdirectories! + // Status messages will be written to Console.Out + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames); + zip.Save(); + } + + + + Using zip As New ZipFile("Backup.zip", Console.Out) + ' Store all files found in the top level directory, into the zip archive. + ' note: this code does not recurse subdirectories! + ' Status messages will be written to Console.Out + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames) + zip.Save() + End Using + + + + The filename to use for the new zip archive. + A TextWriter to use for writing + verbose status messages. + + + + Creates a new ZipFile instance, using the specified name for the + filename, the specified status message writer, and the specified Encoding. + + + + + This constructor works like the ZipFile + constructor that accepts a single string argument. See that + reference for detail on what this constructor does. + + + + This version of the constructor allows the caller to pass in a + TextWriter, and an Encoding. The TextWriter will collect + verbose messages that are generated by the library during extraction or + creation of the zip archive. A console application may wish to pass + System.Console.Out to get messages on the Console. A graphical or + headless application may wish to capture the messages in a different + TextWriter, for example, a StringWriter, and then display + the messages in a TextBox, or generate an audit log of + ZipFile operations. + + + + The Encoding is used as the default alternate encoding for entries + with filenames or comments that cannot be encoded with the IBM437 code + page. This is a equivalent to setting the property on the ZipFile + instance after construction. + + + + To encrypt the data for the files added to the ZipFile instance, + set the Password property after creating the ZipFile + instance. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + + + Thrown if fileName refers to an existing file that is not a valid zip file. + + + The filename to use for the new zip archive. + A TextWriter to use for writing verbose + status messages. + + The Encoding is used as the default alternate encoding for entries with + filenames or comments that cannot be encoded with the IBM437 code page. + + + + + Initialize a ZipFile instance by reading in a zip file. + + + + + + This method is primarily useful from COM Automation environments, when + reading or extracting zip files. In COM, it is not possible to invoke + parameterized constructors for a class. A COM Automation application can + update a zip file by using the default (no argument) + constructor, then calling Initialize() to read the contents + of an on-disk zip archive into the ZipFile instance. + + + + .NET applications are encouraged to use the ZipFile.Read() methods + for better clarity. + + + + the name of the existing zip file to read in. + + + + Removes the given ZipEntry from the zip archive. + + + + + After calling RemoveEntry, the application must call Save to + make the changes permanent. + + + + + Thrown if the specified ZipEntry does not exist in the ZipFile. + + + + In this example, all entries in the zip archive dating from before + December 31st, 2007, are removed from the archive. This is actually much + easier if you use the RemoveSelectedEntries method. But I needed an + example for RemoveEntry, so here it is. + + String ZipFileToRead = "ArchiveToModify.zip"; + System.DateTime Threshold = new System.DateTime(2007,12,31); + using (ZipFile zip = ZipFile.Read(ZipFileToRead)) + { + var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>(); + foreach (ZipEntry e in zip) + { + if (e.LastModified < Threshold) + { + // We cannot remove the entry from the list, within the context of + // an enumeration of said list. + // So we add the doomed entry to a list to be removed later. + EntriesToRemove.Add(e); + } + } + + // actually remove the doomed entries. + foreach (ZipEntry zombie in EntriesToRemove) + zip.RemoveEntry(zombie); + + zip.Comment= String.Format("This zip archive was updated at {0}.", + System.DateTime.Now.ToString("G")); + + // save with a different name + zip.Save("Archive-Updated.zip"); + } + + + + Dim ZipFileToRead As String = "ArchiveToModify.zip" + Dim Threshold As New DateTime(2007, 12, 31) + Using zip As ZipFile = ZipFile.Read(ZipFileToRead) + Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry) + Dim e As ZipEntry + For Each e In zip + If (e.LastModified < Threshold) Then + ' We cannot remove the entry from the list, within the context of + ' an enumeration of said list. + ' So we add the doomed entry to a list to be removed later. + EntriesToRemove.Add(e) + End If + Next + + ' actually remove the doomed entries. + Dim zombie As ZipEntry + For Each zombie In EntriesToRemove + zip.RemoveEntry(zombie) + Next + zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G")) + 'save as a different name + zip.Save("Archive-Updated.zip") + End Using + + + + + The ZipEntry to remove from the zip. + + + + + + + + Removes the ZipEntry with the given filename from the zip archive. + + + + + After calling RemoveEntry, the application must call Save to + make the changes permanent. + + + + + + Thrown if the ZipFile is not updatable. + + + + Thrown if a ZipEntry with the specified filename does not exist in + the ZipFile. + + + + + This example shows one way to remove an entry with a given filename from + an existing zip archive. + + + String zipFileToRead= "PackedDocuments.zip"; + string candidate = "DatedMaterial.xps"; + using (ZipFile zip = ZipFile.Read(zipFileToRead)) + { + if (zip.EntryFilenames.Contains(candidate)) + { + zip.RemoveEntry(candidate); + zip.Comment= String.Format("The file '{0}' has been removed from this archive.", + Candidate); + zip.Save(); + } + } + + + Dim zipFileToRead As String = "PackedDocuments.zip" + Dim candidate As String = "DatedMaterial.xps" + Using zip As ZipFile = ZipFile.Read(zipFileToRead) + If zip.EntryFilenames.Contains(candidate) Then + zip.RemoveEntry(candidate) + zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate) + zip.Save + End If + End Using + + + + + The name of the file, including any directory path, to remove from the zip. + The filename match is not case-sensitive by default; you can use the + CaseSensitiveRetrieval property to change this behavior. The + pathname can use forward-slashes or backward slashes. + + + + + + Closes the read and write streams associated + to the ZipFile, if necessary. + + + + The Dispose() method is generally employed implicitly, via a using(..) {..} + statement. (Using...End Using in VB) If you do not employ a using + statement, insure that your application calls Dispose() explicitly. For + example, in a Powershell application, or an application that uses the COM + interop interface, you must call Dispose() explicitly. + + + + This example extracts an entry selected by name, from the Zip file to the + Console. + + using (ZipFile zip = ZipFile.Read(zipfile)) + { + foreach (ZipEntry e in zip) + { + if (WantThisEntry(e.FileName)) + zip.Extract(e.FileName, Console.OpenStandardOutput()); + } + } // Dispose() is called implicitly here. + + + + Using zip As ZipFile = ZipFile.Read(zipfile) + Dim e As ZipEntry + For Each e In zip + If WantThisEntry(e.FileName) Then + zip.Extract(e.FileName, Console.OpenStandardOutput()) + End If + Next + End Using ' Dispose is implicity called here + + + + + + Disposes any managed resources, if the flag is set, then marks the + instance disposed. This method is typically not called explicitly from + application code. + + + + Applications should call the no-arg Dispose method. + + + + indicates whether the method should dispose streams or not. + + + + + Default size of the buffer used for IO. + + + + + Extracts all of the items in the zip archive, to the specified path in the + filesystem. The path can be relative or fully-qualified. + + + + + This method will extract all entries in the ZipFile to the + specified path. + + + + If an extraction of a file from the zip archive would overwrite an + existing file in the filesystem, the action taken is dictated by the + ExtractExistingFile property, which overrides any setting you may have + made on individual ZipEntry instances. By default, if you have not + set that property on the ZipFile instance, the entry will not + be extracted, the existing file will not be overwritten and an + exception will be thrown. To change this, set the property, or use the + overload that allows you to + specify an ExtractExistingFileAction parameter. + + + + The action to take when an extract would overwrite an existing file + applies to all entries. If you want to set this on a per-entry basis, + then you must use one of the ZipEntry.Extract methods. + + + + This method will send verbose output messages to the , if it is set on the ZipFile + instance. + + + + You may wish to take advantage of the ExtractProgress event. + + + + About timestamps: When extracting a file entry from a zip archive, the + extracted file gets the last modified time of the entry as stored in + the archive. The archive may also store extended file timestamp + information, including last accessed and created times. If these are + present in the ZipEntry, then the extracted file will also get + these times. + + + + A Directory entry is somewhat different. It will get the times as + described for a file entry, but, if there are file entries in the zip + archive that, when extracted, appear in the just-created directory, + then when those file entries are extracted, the last modified and last + accessed times of the directory will change, as a side effect. The + result is that after an extraction of a directory and a number of + files within the directory, the last modified and last accessed + timestamps on the directory will reflect the time that the last file + was extracted into the directory, rather than the time stored in the + zip archive for the directory. + + + + To compensate, when extracting an archive with ExtractAll, + DotNetZip will extract all the file and directory entries as described + above, but it will then make a second pass on the directories, and + reset the times on the directories to reflect what is stored in the + zip archive. + + + + This compensation is performed only within the context of an + ExtractAll. If you call ZipEntry.Extract on a directory + entry, the timestamps on directory in the filesystem will reflect the + times stored in the zip. If you then call ZipEntry.Extract on + a file entry, which is extracted into the directory, the timestamps on + the directory will be updated to the current time. + + + + + This example extracts all the entries in a zip archive file, to the + specified target directory. The extraction will overwrite any + existing files silently. + + + String TargetDirectory= "unpack"; + using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) + { + zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently; + zip.ExtractAll(TargetDirectory); + } + + + + Dim TargetDirectory As String = "unpack" + Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) + zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently + zip.ExtractAll(TargetDirectory) + End Using + + + + + + + + The path to which the contents of the zipfile will be extracted. + The path can be relative or fully-qualified. + + + + + + Extracts all of the items in the zip archive, to the specified path in the + filesystem, using the specified behavior when extraction would overwrite an + existing file. + + + + + + This method will extract all entries in the ZipFile to the specified + path. For an extraction that would overwrite an existing file, the behavior + is dictated by , which overrides any + setting you may have made on individual ZipEntry instances. + + + + The action to take when an extract would overwrite an existing file + applies to all entries. If you want to set this on a per-entry basis, + then you must use or one of the similar methods. + + + + Calling this method is equivalent to setting the property and then calling . + + + + This method will send verbose output messages to the + , if it is set on the ZipFile instance. + + + + + This example extracts all the entries in a zip archive file, to the + specified target directory. It does not overwrite any existing files. + + String TargetDirectory= "c:\\unpack"; + using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) + { + zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite); + } + + + + Dim TargetDirectory As String = "c:\unpack" + Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) + zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite) + End Using + + + + + The path to which the contents of the zipfile will be extracted. + The path can be relative or fully-qualified. + + + + The action to take if extraction would overwrite an existing file. + + + + + + Reads a zip file archive and returns the instance. + + + + + The stream is read using the default System.Text.Encoding, which is the + IBM437 codepage. + + + + + Thrown if the ZipFile cannot be read. The implementation of this method + relies on System.IO.File.OpenRead, which can throw a variety of exceptions, + including specific exceptions if a file is not found, an unauthorized access + exception, exceptions for poorly formatted filenames, and so on. + + + + The name of the zip archive to open. This can be a fully-qualified or relative + pathname. + + + . + + The instance read from the zip archive. + + + + + Reads a zip file archive from the named filesystem file using the + specified options. + + + + + This version of the Read() method allows the caller to pass + in a TextWriter an Encoding, via an instance of the + ReadOptions class. The ZipFile is read in using the + specified encoding for entries where UTF-8 encoding is not + explicitly specified. + + + + + + + This example shows how to read a zip file using the Big-5 Chinese + code page (950), and extract each entry in the zip file, while + sending status messages out to the Console. + + + + For this code to work as intended, the zipfile must have been + created using the big5 code page (CP950). This is typical, for + example, when using WinRar on a machine with CP950 set as the + default code page. In that case, the names of entries within the + Zip archive will be stored in that code page, and reading the zip + archive must be done using that code page. If the application did + not use the correct code page in ZipFile.Read(), then names of + entries within the zip archive would not be correctly retrieved. + + + + string zipToExtract = "MyArchive.zip"; + string extractDirectory = "extract"; + var options = new ReadOptions + { + StatusMessageWriter = System.Console.Out, + Encoding = System.Text.Encoding.GetEncoding(950) + }; + using (ZipFile zip = ZipFile.Read(zipToExtract, options)) + { + foreach (ZipEntry e in zip) + { + e.Extract(extractDirectory); + } + } + + + + + Dim zipToExtract as String = "MyArchive.zip" + Dim extractDirectory as String = "extract" + Dim options as New ReadOptions + options.Encoding = System.Text.Encoding.GetEncoding(950) + options.StatusMessageWriter = System.Console.Out + Using zip As ZipFile = ZipFile.Read(zipToExtract, options) + Dim e As ZipEntry + For Each e In zip + e.Extract(extractDirectory) + Next + End Using + + + + + + + + This example shows how to read a zip file using the default + code page, to remove entries that have a modified date before a given threshold, + sending status messages out to a StringWriter. + + + + var options = new ReadOptions + { + StatusMessageWriter = new System.IO.StringWriter() + }; + using (ZipFile zip = ZipFile.Read("PackedDocuments.zip", options)) + { + var Threshold = new DateTime(2007,7,4); + // We cannot remove the entry from the list, within the context of + // an enumeration of said list. + // So we add the doomed entry to a list to be removed later. + // pass 1: mark the entries for removal + var MarkedEntries = new System.Collections.Generic.List<ZipEntry>(); + foreach (ZipEntry e in zip) + { + if (e.LastModified < Threshold) + MarkedEntries.Add(e); + } + // pass 2: actually remove the entry. + foreach (ZipEntry zombie in MarkedEntries) + zip.RemoveEntry(zombie); + zip.Comment = "This archive has been updated."; + zip.Save(); + } + // can now use contents of sw, eg store in an audit log + + + + Dim options as New ReadOptions + options.StatusMessageWriter = New System.IO.StringWriter + Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options) + Dim Threshold As New DateTime(2007, 7, 4) + ' We cannot remove the entry from the list, within the context of + ' an enumeration of said list. + ' So we add the doomed entry to a list to be removed later. + ' pass 1: mark the entries for removal + Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry) + Dim e As ZipEntry + For Each e In zip + If (e.LastModified < Threshold) Then + MarkedEntries.Add(e) + End If + Next + ' pass 2: actually remove the entry. + Dim zombie As ZipEntry + For Each zombie In MarkedEntries + zip.RemoveEntry(zombie) + Next + zip.Comment = "This archive has been updated." + zip.Save + End Using + ' can now use contents of sw, eg store in an audit log + + + + + Thrown if the zipfile cannot be read. The implementation of + this method relies on System.IO.File.OpenRead, which + can throw a variety of exceptions, including specific + exceptions if a file is not found, an unauthorized access + exception, exceptions for poorly formatted filenames, and so + on. + + + + The name of the zip archive to open. + This can be a fully-qualified or relative pathname. + + + + The set of options to use when reading the zip file. + + + The ZipFile instance read from the zip archive. + + + + + + + Reads a zip file archive using the specified text encoding, the specified + TextWriter for status messages, and the specified ReadProgress event handler, + and returns the instance. + + + + The name of the zip archive to open. + This can be a fully-qualified or relative pathname. + + + + An event handler for Read operations. + + + + The System.IO.TextWriter to use for writing verbose status messages + during operations on the zip archive. A console application may wish to + pass System.Console.Out to get messages on the Console. A graphical + or headless application may wish to capture the messages in a different + TextWriter, such as a System.IO.StringWriter. + + + + The System.Text.Encoding to use when reading in the zip archive. Be + careful specifying the encoding. If the value you use here is not the same + as the Encoding used when the zip archive was created (possibly by a + different archiver) you will get unexpected results and possibly exceptions. + + + The instance read from the zip archive. + + + + + Reads a zip archive from a stream. + + + + + + When reading from a file, it's probably easier to just use + ZipFile.Read(String, ReadOptions). This + overload is useful when when the zip archive content is + available from an already-open stream. The stream must be + open and readable and seekable when calling this method. The + stream is left open when the reading is completed. + + + + Using this overload, the stream is read using the default + System.Text.Encoding, which is the IBM437 + codepage. If you want to specify the encoding to use when + reading the zipfile content, see + ZipFile.Read(Stream, ReadOptions). This + + + + Reading of zip content begins at the current position in the + stream. This means if you have a stream that concatenates + regular data and zip data, if you position the open, readable + stream at the start of the zip data, you will be able to read + the zip archive using this constructor, or any of the ZipFile + constructors that accept a as + input. Some examples of where this might be useful: the zip + content is concatenated at the end of a regular EXE file, as + some self-extracting archives do. (Note: SFX files produced + by DotNetZip do not work this way; they can be read as normal + ZIP files). Another example might be a stream being read from + a database, where the zip content is embedded within an + aggregate stream of data. + + + + + + + This example shows how to Read zip content from a stream, and + extract one entry into a different stream. In this example, + the filename "NameOfEntryInArchive.doc", refers only to the + name of the entry within the zip archive. A file by that + name is not created in the filesystem. The I/O is done + strictly with the given streams. + + + + using (ZipFile zip = ZipFile.Read(InputStream)) + { + zip.Extract("NameOfEntryInArchive.doc", OutputStream); + } + + + + Using zip as ZipFile = ZipFile.Read(InputStream) + zip.Extract("NameOfEntryInArchive.doc", OutputStream) + End Using + + + + the stream containing the zip data. + + The ZipFile instance read from the stream + + + + + Reads a zip file archive from the given stream using the + specified options. + + + + + + When reading from a file, it's probably easier to just use + ZipFile.Read(String, ReadOptions). This + overload is useful when when the zip archive content is + available from an already-open stream. The stream must be + open and readable and seekable when calling this method. The + stream is left open when the reading is completed. + + + + Reading of zip content begins at the current position in the + stream. This means if you have a stream that concatenates + regular data and zip data, if you position the open, readable + stream at the start of the zip data, you will be able to read + the zip archive using this constructor, or any of the ZipFile + constructors that accept a as + input. Some examples of where this might be useful: the zip + content is concatenated at the end of a regular EXE file, as + some self-extracting archives do. (Note: SFX files produced + by DotNetZip do not work this way; they can be read as normal + ZIP files). Another example might be a stream being read from + a database, where the zip content is embedded within an + aggregate stream of data. + + + + the stream containing the zip data. + + + The set of options to use when reading the zip file. + + + + Thrown if the zip archive cannot be read. + + + The ZipFile instance read from the stream. + + + + + + + Reads a zip archive from a stream, using the specified text Encoding, the + specified TextWriter for status messages, + and the specified ReadProgress event handler. + + + + + Reading of zip content begins at the current position in the stream. This + means if you have a stream that concatenates regular data and zip data, if + you position the open, readable stream at the start of the zip data, you + will be able to read the zip archive using this constructor, or any of the + ZipFile constructors that accept a as + input. Some examples of where this might be useful: the zip content is + concatenated at the end of a regular EXE file, as some self-extracting + archives do. (Note: SFX files produced by DotNetZip do not work this + way). Another example might be a stream being read from a database, where + the zip content is embedded within an aggregate stream of data. + + + + the stream containing the zip data. + + + The System.IO.TextWriter to which verbose status messages are written + during operations on the ZipFile. For example, in a console + application, System.Console.Out works, and will get a message for each entry + added to the ZipFile. If the TextWriter is null, no verbose messages + are written. + + + + The text encoding to use when reading entries that do not have the UTF-8 + encoding bit set. Be careful specifying the encoding. If the value you use + here is not the same as the Encoding used when the zip archive was created + (possibly by a different archiver) you will get unexpected results and + possibly exceptions. See the + property for more information. + + + + An event handler for Read operations. + + + an instance of ZipFile + + + + Checks the given file to see if it appears to be a valid zip file. + + + + + Calling this method is equivalent to calling with the testExtract parameter set to false. + + + + The file to check. + true if the file appears to be a zip file. + + + + Checks a file to see if it is a valid zip file. + + + + + This method opens the specified zip file, reads in the zip archive, + verifying the ZIP metadata as it reads. + + + + If everything succeeds, then the method returns true. If anything fails - + for example if an incorrect signature or CRC is found, indicating a + corrupt file, the the method returns false. This method also returns + false for a file that does not exist. + + + + If is true, as part of its check, this + method reads in the content for each entry, expands it, and checks CRCs. + This provides an additional check beyond verifying the zip header and + directory data. + + + + If is true, and if any of the zip entries + are protected with a password, this method will return false. If you want + to verify a ZipFile that has entries which are protected with a + password, you will need to do that manually. + + + + + The zip file to check. + true if the caller wants to extract each entry. + true if the file contains a valid zip file. + + + + Checks a stream to see if it contains a valid zip archive. + + + + + This method reads the zip archive contained in the specified stream, verifying + the ZIP metadata as it reads. If testExtract is true, this method also extracts + each entry in the archive, dumping all the bits into . + + + + If everything succeeds, then the method returns true. If anything fails - + for example if an incorrect signature or CRC is found, indicating a corrupt + file, the the method returns false. This method also returns false for a + file that does not exist. + + + + If testExtract is true, this method reads in the content for each + entry, expands it, and checks CRCs. This provides an additional check + beyond verifying the zip header data. + + + + If testExtract is true, and if any of the zip entries are protected + with a password, this method will return false. If you want to verify a + ZipFile that has entries which are protected with a password, you will need + to do that manually. + + + + + + The stream to check. + true if the caller wants to extract each entry. + true if the stream contains a valid zip archive. + + + + Delete file with retry on UnauthorizedAccessException. + + + + + When calling File.Delete() on a file that has been "recently" + created, the call sometimes fails with + UnauthorizedAccessException. This method simply retries the Delete 3 + times with a sleep between tries. + + + + the name of the file to be deleted + + + + Saves the Zip archive to a file, specified by the Name property of the + ZipFile. + + + + + The ZipFile instance is written to storage, typically a zip file + in a filesystem, only when the caller calls Save. In the typical + case, the Save operation writes the zip content to a temporary file, and + then renames the temporary file to the desired name. If necessary, this + method will delete a pre-existing file before the rename. + + + + The property is specified either explicitly, + or implicitly using one of the parameterized ZipFile constructors. For + COM Automation clients, the Name property must be set explicitly, + because COM Automation clients cannot call parameterized constructors. + + + + When using a filesystem file for the Zip output, it is possible to call + Save multiple times on the ZipFile instance. With each + call the zip content is re-written to the same output file. + + + + Data for entries that have been added to the ZipFile instance is + written to the output when the Save method is called. This means + that the input streams for those entries must be available at the time + the application calls Save. If, for example, the application + adds entries with AddEntry using a dynamically-allocated + MemoryStream, the memory stream must not have been disposed + before the call to Save. See the property for more discussion of the + availability requirements of the input stream for an entry, and an + approach for providing just-in-time stream lifecycle management. + + + + + + + + Thrown if you haven't specified a location or stream for saving the zip, + either in the constructor or by setting the Name property, or if you try + to save a regular zip archive to a filename with a .exe extension. + + + + Thrown if is non-zero, and the number + of segments that would be generated for the spanned zip file during the + save operation exceeds 99. If this happens, you need to increase the + segment size. + + + + + + Save the file to a new zipfile, with the given name. + + + + + This method allows the application to explicitly specify the name of the zip + file when saving. Use this when creating a new zip file, or when + updating a zip archive. + + + + An application can also save a zip archive in several places by calling this + method multiple times in succession, with different filenames. + + + + The ZipFile instance is written to storage, typically a zip file in a + filesystem, only when the caller calls Save. The Save operation writes + the zip content to a temporary file, and then renames the temporary file + to the desired name. If necessary, this method will delete a pre-existing file + before the rename. + + + + + + Thrown if you specify a directory for the filename. + + + + The name of the zip archive to save to. Existing files will + be overwritten with great prejudice. + + + + This example shows how to create and Save a zip file. + + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(@"c:\reports\January"); + zip.Save("January.zip"); + } + + + + Using zip As New ZipFile() + zip.AddDirectory("c:\reports\January") + zip.Save("January.zip") + End Using + + + + + + This example shows how to update a zip file. + + using (ZipFile zip = ZipFile.Read("ExistingArchive.zip")) + { + zip.AddFile("NewData.csv"); + zip.Save("UpdatedArchive.zip"); + } + + + + Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip") + zip.AddFile("NewData.csv") + zip.Save("UpdatedArchive.zip") + End Using + + + + + + + Save the zip archive to the specified stream. + + + + + The ZipFile instance is written to storage - typically a zip file + in a filesystem, but using this overload, the storage can be anything + accessible via a writable stream - only when the caller calls Save. + + + + Use this method to save the zip content to a stream directly. A common + scenario is an ASP.NET application that dynamically generates a zip file + and allows the browser to download it. The application can call + Save(Response.OutputStream) to write a zipfile directly to the + output stream, without creating a zip file on the disk on the ASP.NET + server. + + + + Be careful when saving a file to a non-seekable stream, including + Response.OutputStream. When DotNetZip writes to a non-seekable + stream, the zip archive is formatted in such a way that may not be + compatible with all zip tools on all platforms. It's a perfectly legal + and compliant zip file, but some people have reported problems opening + files produced this way using the Mac OS archive utility. + + + + + + + This example saves the zipfile content into a MemoryStream, and + then gets the array of bytes from that MemoryStream. + + + using (var zip = new Ionic.Zip.ZipFile()) + { + zip.CompressionLevel= Ionic.Zlib.CompressionLevel.BestCompression; + zip.Password = "VerySecret."; + zip.Encryption = EncryptionAlgorithm.WinZipAes128; + zip.AddFile(sourceFileName); + MemoryStream output = new MemoryStream(); + zip.Save(output); + + byte[] zipbytes = output.ToArray(); + } + + + + + + This example shows a pitfall you should avoid. DO NOT read + from a stream, then try to save to the same stream. DO + NOT DO THIS: + + + + using (var fs = new FileSteeam(filename, FileMode.Open)) + { + using (var zip = Ionic.Zip.ZipFile.Read(inputStream)) + { + zip.AddEntry("Name1.txt", "this is the content"); + zip.Save(inputStream); // NO NO NO!! + } + } + + + + Better like this: + + + + using (var zip = Ionic.Zip.ZipFile.Read(filename)) + { + zip.AddEntry("Name1.txt", "this is the content"); + zip.Save(); // YES! + } + + + + + + The System.IO.Stream to write to. It must be + writable. If you created the ZipFile instanct by calling + ZipFile.Read(), this stream must not be the same stream + you passed to ZipFile.Read(). + + + + + Adds to the ZipFile a set of files from the current working directory on + disk, that conform to the specified criteria. + + + + + This method selects files from the the current working directory matching + the specified criteria, and adds them to the ZipFile. + + + + Specify the criteria in statements of 3 elements: a noun, an operator, and + a value. Consider the string "name != *.doc" . The noun is "name". The + operator is "!=", implying "Not Equal". The value is "*.doc". That + criterion, in English, says "all files with a name that does not end in + the .doc extension." + + + + Supported nouns include "name" (or "filename") for the filename; "atime", + "mtime", and "ctime" for last access time, last modfied time, and created + time of the file, respectively; "attributes" (or "attrs") for the file + attributes; "size" (or "length") for the file length (uncompressed), and + "type" for the type of object, either a file or a directory. The + "attributes", "name" and "type" nouns both support = and != as operators. + The "size", "atime", "mtime", and "ctime" nouns support = and !=, and + >, >=, <, <= as well. The times are taken to be expressed in + local time. + + + + Specify values for the file attributes as a string with one or more of the + characters H,R,S,A,I,L in any order, implying file attributes of Hidden, + ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic + link) respectively. + + + + To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the + format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00 + (midnight). + + + + The value for a size criterion is expressed in integer quantities of bytes, + kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes + (g or gb). + + + + The value for a name is a pattern to match against the filename, potentially + including wildcards. The pattern follows CMD.exe glob rules: * implies one + or more of any character, while ? implies one character. If the name + pattern contains any slashes, it is matched to the entire filename, + including the path; otherwise, it is matched against only the filename + without the path. This means a pattern of "*\*.*" matches all files one + directory level deep, while a pattern of "*.*" matches all files in all + directories. + + + + To specify a name pattern that includes spaces, use single quotes around the + pattern. A pattern of "'* *.*'" will match all files that have spaces in + the filename. The full criteria string for that would be "name = '* *.*'" . + + + + The value for a type criterion is either F (implying a file) or D (implying + a directory). + + + + Some examples: + + + + + criteria + Files retrieved + + + + name != *.xls + any file with an extension that is not .xls + + + + + name = *.mp3 + any file with a .mp3 extension. + + + + + *.mp3 + (same as above) any file with a .mp3 extension. + + + + + attributes = A + all files whose attributes include the Archive bit. + + + + + attributes != H + all files whose attributes do not include the Hidden bit. + + + + + mtime > 2009-01-01 + all files with a last modified time after January 1st, 2009. + + + + + size > 2gb + all files whose uncompressed size is greater than 2gb. + + + + + type = D + all directories in the filesystem. + + + + + + You can combine criteria with the conjunctions AND or OR. Using a string + like "name = *.txt AND size >= 100k" for the selectionCriteria retrieves + entries whose names end in .txt, and whose uncompressed size is greater than + or equal to 100 kilobytes. + + + + For more complex combinations of criteria, you can use parenthesis to group + clauses in the boolean logic. Without parenthesis, the precedence of the + criterion atoms is determined by order of appearance. Unlike the C# + language, the AND conjunction does not take precendence over the logical OR. + This is important only in strings that contain 3 or more criterion atoms. + In other words, "name = *.txt and size > 1000 or attributes = H" implies + "((name = *.txt AND size > 1000) OR attributes = H)" while "attributes = + H OR name = *.txt and size > 1000" evaluates to "((attributes = H OR name + = *.txt) AND size > 1000)". When in doubt, use parenthesis. + + + + Using time properties requires some extra care. If you want to retrieve all + entries that were last updated on 2009 February 14, specify a time range + like so:"mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this to + say: all files updated after 12:00am on February 14th, until 12:00am on + February 15th. You can use the same bracketing approach to specify any time + period - a year, a month, a week, and so on. + + + + The syntax allows one special case: if you provide a string with no spaces, it is + treated as a pattern to match for the filename. Therefore a string like "*.xls" + will be equivalent to specifying "name = *.xls". + + + + There is no logic in this method that insures that the file inclusion + criteria are internally consistent. For example, it's possible to specify + criteria that says the file must have a size of less than 100 bytes, as well + as a size that is greater than 1000 bytes. Obviously no file will ever + satisfy such criteria, but this method does not detect such logical + inconsistencies. The caller is responsible for insuring the criteria are + sensible. + + + + Using this method, the file selection does not recurse into + subdirectories, and the full path of the selected files is included in the + entries added into the zip archive. If you don't like these behaviors, + see the other overloads of this method. + + + + + This example zips up all *.csv files in the current working directory. + + using (ZipFile zip = new ZipFile()) + { + // To just match on filename wildcards, + // use the shorthand form of the selectionCriteria string. + zip.AddSelectedFiles("*.csv"); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile() + zip.AddSelectedFiles("*.csv") + zip.Save(PathToZipArchive) + End Using + + + + The criteria for file selection + + + + Adds to the ZipFile a set of files from the disk that conform to the + specified criteria, optionally recursing into subdirectories. + + + + + This method selects files from the the current working directory matching + the specified criteria, and adds them to the ZipFile. If + recurseDirectories is true, files are also selected from + subdirectories, and the directory structure in the filesystem is + reproduced in the zip archive, rooted at the current working directory. + + + + Using this method, the full path of the selected files is included in the + entries added into the zip archive. If you don't want this behavior, use + one of the overloads of this method that allows the specification of a + directoryInArchive. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + + + + This example zips up all *.xml files in the current working directory, or any + subdirectory, that are larger than 1mb. + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", true); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile() + ' Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", true) + zip.Save(PathToZipArchive) + End Using + + + + The criteria for file selection + + + If true, the file selection will recurse into subdirectories. + + + + + Adds to the ZipFile a set of files from a specified directory in the + filesystem, that conform to the specified criteria. + + + + + This method selects files that conform to the specified criteria, from the + the specified directory on disk, and adds them to the ZipFile. The search + does not recurse into subdirectores. + + + + Using this method, the full filesystem path of the files on disk is + reproduced on the entries added to the zip file. If you don't want this + behavior, use one of the other overloads of this method. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + + + + This example zips up all *.xml files larger than 1mb in the directory + given by "d:\rawdata". + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\\rawdata"); + zip.Save(PathToZipArchive); + } + + + + Using zip As ZipFile = New ZipFile() + ' Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\rawdata) + zip.Save(PathToZipArchive) + End Using + + + + The criteria for file selection + + + The name of the directory on the disk from which to select files. + + + + + Adds to the ZipFile a set of files from the specified directory on disk, + that conform to the specified criteria. + + + + + + This method selects files from the the specified disk directory matching + the specified selection criteria, and adds them to the ZipFile. If + recurseDirectories is true, files are also selected from + subdirectories. + + + + The full directory structure in the filesystem is reproduced on the + entries added to the zip archive. If you don't want this behavior, use + one of the overloads of this method that allows the specification of a + directoryInArchive. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + + + This example zips up all *.csv files in the "files" directory, or any + subdirectory, that have been saved since 2009 February 14th. + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile() + ' Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true) + zip.Save(PathToZipArchive) + End Using + + + + + This example zips up all files in the current working + directory, and all its child directories, except those in + the excludethis subdirectory. + + Using Zip As ZipFile = New ZipFile(zipfile) + Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True) + Zip.Save() + End Using + + + + The criteria for file selection + + + The filesystem path from which to select files. + + + + If true, the file selection will recurse into subdirectories. + + + + + Adds to the ZipFile a selection of files from the specified directory on + disk, that conform to the specified criteria, and using a specified root + path for entries added to the zip archive. + + + + + This method selects files from the specified disk directory matching the + specified selection criteria, and adds those files to the ZipFile, using + the specified directory path in the archive. The search does not recurse + into subdirectories. For details on the syntax for the selectionCriteria + parameter, see . + + + + + + + This example zips up all *.psd files in the "photos" directory that have + been saved since 2009 February 14th, and puts them all in a zip file, + using the directory name of "content" in the zip archive itself. When the + zip archive is unzipped, the folder containing the .psd files will be + named "content". + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content"); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile + zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content") + zip.Save(PathToZipArchive) + End Using + + + + + The criteria for selection of files to add to the ZipFile. + + + + The path to the directory in the filesystem from which to select files. + + + + Specifies a directory path to use to in place of the + directoryOnDisk. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (nothing in VB) will use the path on the file name, if any; in other + words it would use directoryOnDisk, plus any subdirectory. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + + Adds to the ZipFile a selection of files from the specified directory on + disk, that conform to the specified criteria, optionally recursing through + subdirectories, and using a specified root path for entries added to the + zip archive. + + + + This method selects files from the specified disk directory that match the + specified selection criteria, and adds those files to the ZipFile, using + the specified directory path in the archive. If recurseDirectories + is true, files are also selected from subdirectories, and the directory + structure in the filesystem is reproduced in the zip archive, rooted at + the directory specified by directoryOnDisk. For details on the + syntax for the selectionCriteria parameter, see . + + + + + This example zips up all files that are NOT *.pst files, in the current + working directory and any subdirectories. + + + using (ZipFile zip = new ZipFile()) + { + zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile + zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true) + zip.Save(PathToZipArchive) + End Using + + + + + The criteria for selection of files to add to the ZipFile. + + + + The path to the directory in the filesystem from which to select files. + + + + Specifies a directory path to use to in place of the + directoryOnDisk. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (nothing in VB) will use the path on the file name, if any; in other + words it would use directoryOnDisk, plus any subdirectory. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + If true, the method also scans subdirectories for files matching the + criteria. + + + + + Updates the ZipFile with a selection of files from the disk that conform + to the specified criteria. + + + + This method selects files from the specified disk directory that match the + specified selection criteria, and Updates the ZipFile with those + files, using the specified directory path in the archive. If + recurseDirectories is true, files are also selected from + subdirectories, and the directory structure in the filesystem is + reproduced in the zip archive, rooted at the directory specified by + directoryOnDisk. For details on the syntax for the + selectionCriteria parameter, see . + + + + The criteria for selection of files to add to the ZipFile. + + + + The path to the directory in the filesystem from which to select files. + + + + Specifies a directory path to use to in place of the + directoryOnDisk. This path may, or may not, correspond to a + real directory in the current filesystem. If the files within the zip + are later extracted, this is the path used for the extracted file. + Passing null (nothing in VB) will use the path on the file name, if + any; in other words it would use directoryOnDisk, plus any + subdirectory. Passing the empty string ("") will insert the item at + the root path within the archive. + + + + If true, the method also scans subdirectories for files matching the criteria. + + + + + + + Retrieve entries from the zipfile by specified criteria. + + + + + This method allows callers to retrieve the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + This example selects all the PhotoShop files from within an archive, and extracts them + to the current working directory. + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + var PhotoShopFiles = zip1.SelectEntries("*.psd"); + foreach (ZipEntry psd in PhotoShopFiles) + { + psd.Extract(); + } + } + + + Using zip1 As ZipFile = ZipFile.Read(ZipFileName) + Dim PhotoShopFiles as ICollection(Of ZipEntry) + PhotoShopFiles = zip1.SelectEntries("*.psd") + Dim psd As ZipEntry + For Each psd In PhotoShopFiles + psd.Extract + Next + End Using + + + the string that specifies which entries to select + a collection of ZipEntry objects that conform to the inclusion spec + + + + Retrieve entries from the zipfile by specified criteria. + + + + + This method allows callers to retrieve the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles"); + foreach (ZipEntry e in UpdatedPhotoShopFiles) + { + // prompt for extract here + if (WantExtract(e.FileName)) + e.Extract(); + } + } + + + Using zip1 As ZipFile = ZipFile.Read(ZipFileName) + Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles") + Dim e As ZipEntry + For Each e In UpdatedPhotoShopFiles + ' prompt for extract here + If Me.WantExtract(e.FileName) Then + e.Extract + End If + Next + End Using + + + the string that specifies which entries to select + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + a collection of ZipEntry objects that conform to the inclusion spec + + + + Remove entries from the zipfile by specified criteria. + + + + + This method allows callers to remove the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + This example removes all entries in a zip file that were modified prior to January 1st, 2008. + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + // remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01"); + // don't forget to save the archive! + zip1.Save(); + } + + + Using zip As ZipFile = ZipFile.Read(ZipFileName) + ' remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01") + ' do not forget to save the archive! + zip1.Save + End Using + + + the string that specifies which entries to select + the number of entries removed + + + + Remove entries from the zipfile by specified criteria, and within the specified + path in the archive. + + + + + This method allows callers to remove the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + // remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01", "documents"); + // a call to ZipFile.Save will make the modifications permanent + zip1.Save(); + } + + + Using zip As ZipFile = ZipFile.Read(ZipFileName) + ' remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01", "documents") + ' a call to ZipFile.Save will make the modifications permanent + zip1.Save + End Using + + + + the string that specifies which entries to select + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + the number of entries removed + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the current working directory. + + + + If any of the files to be extracted already exist, then the action taken is as + specified in the property on the + corresponding ZipEntry instance. By default, the action taken in this case is to + throw an exception. + + + + For information on the syntax of the selectionCriteria string, + see . + + + + + This example shows how extract all XML files modified after 15 January 2009. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15"); + } + + + the selection criteria for entries to extract. + + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the current working directory. When extraction would would + overwrite an existing filesystem file, the action taken is as specified in the + parameter. + + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + + This example shows how extract all XML files modified after 15 January 2009, + overwriting any existing files. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15", + ExtractExistingFileAction.OverwriteSilently); + } + + + + the selection criteria for entries to extract. + + + The action to take if extraction would overwrite an existing file. + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are selected from the specified directory within the archive, and then + extracted into the current working directory. + + + + If any of the files to be extracted already exist, then the action taken is as + specified in the property on the + corresponding ZipEntry instance. By default, the action taken in this case is to + throw an exception. + + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + + This example shows how extract all XML files modified after 15 January 2009, + and writes them to the "unpack" directory. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15","unpack"); + } + + + + the selection criteria for entries to extract. + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the specified directory. If any of the files to be + extracted already exist, an exception will be thrown. + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + the selection criteria for entries to extract. + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + + the directory on the disk into which to extract. It will be created + if it does not exist. + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the specified directory. When extraction would would + overwrite an existing filesystem file, the action taken is as specified in the + parameter. + + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + + This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes, + and puts them in the unpack directory. For any files that already exist in + that destination directory, they will not be overwritten. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml or size > 100000", + null, + "unpack", + ExtractExistingFileAction.DontOverwrite); + } + + + + the selection criteria for entries to extract. + + + The directory on the disk into which to extract. It will be created if it does not exist. + + + + The directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + + The action to take if extraction would overwrite an existing file. + + + + + + Saves the ZipFile instance to a self-extracting zip archive. + + + + + + The generated exe image will execute on any machine that has the .NET + Framework 2.0 installed on it. The generated exe image is also a + valid ZIP file, readable with DotNetZip or another Zip library or tool + such as WinZip. + + + + There are two "flavors" of self-extracting archive. The + WinFormsApplication version will pop up a GUI and allow the + user to select a target directory into which to extract. There's also + a checkbox allowing the user to specify to overwrite existing files, + and another checkbox to allow the user to request that Explorer be + opened to see the extracted files after extraction. The other flavor + is ConsoleApplication. A self-extractor generated with that + flavor setting will run from the command line. It accepts command-line + options to set the overwrite behavior, and to specify the target + extraction directory. + + + + There are a few temporary files created during the saving to a + self-extracting zip. These files are created in the directory pointed + to by , which defaults to . These temporary files are + removed upon successful completion of this method. + + + + When a user runs the WinForms SFX, the user's personal directory (Environment.SpecialFolder.Personal) + will be used as the default extract location. If you want to set the + default extract location, you should use the other overload of + SaveSelfExtractor()/ The user who runs the SFX will have the + opportunity to change the extract directory before extracting. When + the user runs the Command-Line SFX, the user must explicitly specify + the directory to which to extract. The .NET Framework 2.0 is required + on the computer when the self-extracting archive is run. + + + + NB: This method is not available in the version of DotNetZip build for + the .NET Compact Framework, nor in the "Reduced" DotNetZip library. + + + + + + + string DirectoryPath = "c:\\Documents\\Project7"; + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)); + zip.Comment = "This will be embedded into a self-extracting console-based exe"; + zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication); + } + + + Dim DirectoryPath As String = "c:\Documents\Project7" + Using zip As New ZipFile() + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)) + zip.Comment = "This will be embedded into a self-extracting console-based exe" + zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication) + End Using + + + + + a pathname, possibly fully qualified, to be created. Typically it + will end in an .exe extension. + + Indicates whether a Winforms or Console self-extractor is + desired. + + + + Saves the ZipFile instance to a self-extracting zip archive, using + the specified save options. + + + + + This method saves a self extracting archive, using the specified save + options. These options include the flavor of the SFX, the default extract + directory, the icon file, and so on. See the documentation + for for more + details. + + + + The user who runs the SFX will have the opportunity to change the extract + directory before extracting. If at the time of extraction, the specified + directory does not exist, the SFX will create the directory before + extracting the files. + + + + + + This example saves a WinForms-based self-extracting archive EXE that + will use c:\ExtractHere as the default extract location. The C# code + shows syntax for .NET 3.0, which uses an object initializer for + the SelfExtractorOptions object. + + string DirectoryPath = "c:\\Documents\\Project7"; + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)); + zip.Comment = "This will be embedded into a self-extracting WinForms-based exe"; + var options = new SelfExtractorOptions + { + Flavor = SelfExtractorFlavor.WinFormsApplication, + DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere", + PostExtractCommandLine = ExeToRunAfterExtract, + SfxExeWindowTitle = "My Custom Window Title", + RemoveUnpackedFilesAfterExecute = true + }; + zip.SaveSelfExtractor("archive.exe", options); + } + + + Dim DirectoryPath As String = "c:\Documents\Project7" + Using zip As New ZipFile() + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)) + zip.Comment = "This will be embedded into a self-extracting console-based exe" + Dim options As New SelfExtractorOptions() + options.Flavor = SelfExtractorFlavor.WinFormsApplication + options.DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere" + options.PostExtractCommandLine = ExeToRunAfterExtract + options.SfxExeWindowTitle = "My Custom Window Title" + options.RemoveUnpackedFilesAfterExecute = True + zip.SaveSelfExtractor("archive.exe", options) + End Using + + + + The name of the EXE to generate. + provides the options for creating the + Self-extracting archive. + + + + Generic IEnumerator support, for use of a ZipFile in an enumeration. + + + + You probably do not want to call GetEnumerator explicitly. Instead + it is implicitly called when you use a loop in C#, or a + For Each loop in VB.NET. + + + + This example reads a zipfile of a given name, then enumerates the + entries in that zip file, and displays the information about each + entry on the Console. + + using (ZipFile zip = ZipFile.Read(zipfile)) + { + bool header = true; + foreach (ZipEntry e in zip) + { + if (header) + { + System.Console.WriteLine("Zipfile: {0}", zip.Name); + System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded); + System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField); + System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod); + System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}", + "Filename", "Modified", "Size", "Ratio", "Packed"); + System.Console.WriteLine(new System.String('-', 72)); + header = false; + } + + System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", + e.FileName, + e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), + e.UncompressedSize, + e.CompressionRatio, + e.CompressedSize); + + e.Extract(); + } + } + + + + Dim ZipFileToExtract As String = "c:\foo.zip" + Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) + Dim header As Boolean = True + Dim e As ZipEntry + For Each e In zip + If header Then + Console.WriteLine("Zipfile: {0}", zip.Name) + Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded) + Console.WriteLine("BitField: 0x{0:X2}", e.BitField) + Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod) + Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4} {4,-8} {0}", _ + "Filename", "Modified", "Size", "Ratio", "Packed" ) + Console.WriteLine(New String("-"c, 72)) + header = False + End If + Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", _ + e.FileName, _ + e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _ + e.UncompressedSize, _ + e.CompressionRatio, _ + e.CompressedSize ) + e.Extract + Next + End Using + + + + A generic enumerator suitable for use within a foreach loop. + + + + An IEnumerator, for use of a ZipFile in a foreach construct. + + + + This method is included for COM support. An application generally does not call + this method directly. It is called implicitly by COM clients when enumerating + the entries in the ZipFile instance. In VBScript, this is done with a For Each + statement. In Javascript, this is done with new Enumerator(zipfile). + + + + The IEnumerator over the entries in the ZipFile. + + + + + Provides a human-readable string with information about the ZipFile. + + + + + The information string contains 10 lines or so, about each ZipEntry, + describing whether encryption is in use, the compressed and uncompressed + length of the entry, the offset of the entry, and so on. As a result the + information string can be very long for zip files that contain many + entries. + + + This information is mostly useful for diagnostic purposes. + + + + + + Indicates whether to perform a full scan of the zip file when reading it. + + + + + + You almost never want to use this property. + + + + When reading a zip file, if this flag is true (True in + VB), the entire zip archive will be scanned and searched for entries. + For large archives, this can take a very, long time. The much more + efficient default behavior is to read the zip directory, which is + stored at the end of the zip file. But, in some cases the directory is + corrupted and you need to perform a full scan of the zip file to + determine the contents of the zip file. This property lets you do + that, when necessary. + + + + This flag is effective only when calling . Normally you would read a ZipFile with the + static ZipFile.Read + method. But you can't set the FullScan property on the + ZipFile instance when you use a static factory method like + ZipFile.Read. + + + + + + + This example shows how to read a zip file using the full scan approach, + and then save it, thereby producing a corrected zip file. + + + using (var zip = new ZipFile()) + { + zip.FullScan = true; + zip.Initialize(zipFileName); + zip.Save(newName); + } + + + + Using zip As New ZipFile + zip.FullScan = True + zip.Initialize(zipFileName) + zip.Save(newName) + End Using + + + + + + + Whether to sort the ZipEntries before saving the file. + + + + The default is false. If you have a large number of zip entries, the sort + alone can consume significant time. + + + + + using (var zip = new ZipFile()) + { + zip.AddFiles(filesToAdd); + zip.SortEntriesBeforeSaving = true; + zip.Save(name); + } + + + + Using zip As New ZipFile + zip.AddFiles(filesToAdd) + zip.SortEntriesBeforeSaving = True + zip.Save(name) + End Using + + + + + + + Indicates whether NTFS Reparse Points, like junctions, should be + traversed during calls to AddDirectory(). + + + + By default, calls to AddDirectory() will traverse NTFS reparse + points, like mounted volumes, and directory junctions. An example + of a junction is the "My Music" directory in Windows Vista. In some + cases you may not want DotNetZip to traverse those directories. In + that case, set this property to false. + + + + + using (var zip = new ZipFile()) + { + zip.AddDirectoryWillTraverseReparsePoints = false; + zip.AddDirectory(dirToZip,"fodder"); + zip.Save(zipFileToCreate); + } + + + + + + Size of the IO buffer used while saving. + + + + + + First, let me say that you really don't need to bother with this. It is + here to allow for optimizations that you probably won't make! It will work + fine if you don't set or get this property at all. Ok? + + + + Now that we have that out of the way, the fine print: This + property affects the size of the buffer that is used for I/O for each + entry contained in the zip file. When a file is read in to be compressed, + it uses a buffer given by the size here. When you update a zip file, the + data for unmodified entries is copied from the first zip file to the + other, through a buffer given by the size here. + + + + Changing the buffer size affects a few things: first, for larger buffer + sizes, the memory used by the ZipFile, obviously, will be larger + during I/O operations. This may make operations faster for very much + larger files. Last, for any given entry, when you use a larger buffer + there will be fewer progress events during I/O operations, because there's + one progress event generated for each time the buffer is filled and then + emptied. + + + + The default buffer size is 8k. Increasing the buffer size may speed + things up as you compress larger files. But there are no hard-and-fast + rules here, eh? You won't know til you test it. And there will be a + limit where ever larger buffers actually slow things down. So as I said + in the beginning, it's probably best if you don't set or get this property + at all. + + + + + + This example shows how you might set a large buffer size for efficiency when + dealing with zip entries that are larger than 1gb. + + using (ZipFile zip = new ZipFile()) + { + zip.SaveProgress += this.zip1_SaveProgress; + zip.AddDirectory(directoryToZip, ""); + zip.UseZip64WhenSaving = Zip64Option.Always; + zip.BufferSize = 65536*8; // 65536 * 8 = 512k + zip.Save(ZipFileToCreate); + } + + + + + + Size of the work buffer to use for the ZLIB codec during compression. + + + + + When doing ZLIB or Deflate compression, the library fills a buffer, + then passes it to the compressor for compression. Then the library + reads out the compressed bytes. This happens repeatedly until there + is no more uncompressed data to compress. This property sets the + size of the buffer that will be used for chunk-wise compression. In + order for the setting to take effect, your application needs to set + this property before calling one of the ZipFile.Save() + overloads. + + + Setting this affects the performance and memory efficiency of + compression and decompression. For larger files, setting this to a + larger size may improve compression performance, but the exact + numbers vary depending on available memory, the size of the streams + you are compressing, and a bunch of other variables. I don't have + good firm recommendations on how to set it. You'll have to test it + yourself. Or just leave it alone and accept the default. + + + + + + Indicates whether extracted files should keep their paths as + stored in the zip archive. + + + + + This property affects Extraction. It is not used when creating zip + archives. + + + + With this property set to false, the default, extracting entries + from a zip file will create files in the filesystem that have the full + path associated to the entry within the zip file. With this property set + to true, extracting entries from the zip file results in files + with no path: the folders are "flattened." + + + + An example: suppose the zip file contains entries /directory1/file1.txt and + /directory2/file2.txt. With FlattenFoldersOnExtract set to false, + the files created will be \directory1\file1.txt and \directory2\file2.txt. + With the property set to true, the files created are file1.txt and file2.txt. + + + + + + + The compression strategy to use for all entries. + + + + Set the Strategy used by the ZLIB-compatible compressor, when + compressing entries using the DEFLATE method. Different compression + strategies work better on different sorts of data. The strategy + parameter can affect the compression ratio and the speed of + compression but not the correctness of the compresssion. For more + information see Ionic.Zlib.CompressionStrategy. + + + + + The name of the ZipFile, on disk. + + + + + + When the ZipFile instance was created by reading an archive using + one of the ZipFile.Read methods, this property represents the name + of the zip file that was read. When the ZipFile instance was + created by using the no-argument constructor, this value is null + (Nothing in VB). + + + + If you use the no-argument constructor, and you then explicitly set this + property, when you call , this name will + specify the name of the zip file created. Doing so is equivalent to + calling . When instantiating a + ZipFile by reading from a stream or byte array, the Name + property remains null. When saving to a stream, the Name + property is implicitly set to null. + + + + + + Sets the compression level to be used for entries subsequently added to + the zip archive. + + + + + Varying the compression level used on entries can affect the + size-vs-speed tradeoff when compression and decompressing data streams + or files. + + + + As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile + instance will cause the specified CompressionLevel to be used on all + items that are subsequently added to the + ZipFile instance. If you set this property after you have added + items to the ZipFile, but before you have called Save(), + those items will not use the specified compression level. + + + + If you do not set this property, the default compression level is used, + which normally gives a good balance of compression efficiency and + compression speed. In some tests, using BestCompression can + double the time it takes to compress, while delivering just a small + increase in compression efficiency. This behavior will vary with the + type of data you compress. If you are in doubt, just leave this setting + alone, and accept the default. + + + + + + The compression method for the zipfile. + + + + By default, the compression method is CompressionMethod.Deflate. + + + + + + + A comment attached to the zip archive. + + + + + + This property is read/write. It allows the application to specify a + comment for the ZipFile, or read the comment for the + ZipFile. After setting this property, changes are only made + permanent when you call a Save() method. + + + + According to PKWARE's + zip specification, the comment is not encrypted, even if there is a + password set on the zip file. + + + + The specification does not describe how to indicate the encoding used + on a comment string. Many "compliant" zip tools and libraries use + IBM437 as the code page for comments; DotNetZip, too, follows that + practice. On the other hand, there are situations where you want a + Comment to be encoded with something else, for example using code page + 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the + comment following the same procedure it follows for encoding + filenames: (a) if is + Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the + alternate encoding (). (c) if is AsNecessary, it uses the + alternate encoding only if the default encoding is not sufficient for + encoding the comment - in other words if decoding the result does not + produce the original string. This decision is taken at the time of + the call to ZipFile.Save(). + + + + When creating a zip archive using this library, it is possible to change + the value of between each + entry you add, and between adding entries and the call to + Save(). Don't do this. It will likely result in a zip file that is + not readable by any tool or application. For best interoperability, leave + alone, or specify it only + once, before adding any entries to the ZipFile instance. + + + + + + + Specifies whether the Creation, Access, and Modified times for entries + added to the zip file will be emitted in “Windows format” + when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entries should or should not be stored + in the zip archive in the format used by Windows. By default this flag is + true, meaning the Windows-format times are stored in the zip + archive. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are + automatically set from the filesystem values. When adding an entry from a + stream or string, all three values are implicitly set to + DateTime.Now. Applications can also explicitly set those times by + calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since January 1, 1601 UTC. The other is a format Unix applications typically + use: seconds since January 1, 1970 UTC. Each format can be stored in an + "extra field" in the zip entry when saving the zip archive. The former + uses an extra field with a Header Id of 0x000A, while the latter uses a + header ID of 0x5455, although you probably don't need to know that. + + + + Not all tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Some tools and libraries + may be able to read only one or the other. DotNetZip can read or write + times in either or both formats. + + + + The times stored are taken from , , and . + + + + The value set here applies to all entries subsequently added to the + ZipFile. + + + + This property is not mutually exclusive of the property. It is possible and + legal and valid to produce a zip file that contains timestamps encoded in + the Unix format as well as in the Windows format, in addition to the LastModified time attached to each + entry in the archive, a time that is always stored in "DOS format". And, + notwithstanding the names PKWare uses for these time formats, any of them + can be read and written by any computer, on any operating system. But, + there are no guarantees that a program running on Mac or Linux will + gracefully handle a zip file with "Windows" formatted times, or that an + application that does not use DotNetZip but runs on Windows will be able to + handle file times in Unix format. + + + + When in doubt, test. Sorry, I haven't got a complete list of tools and + which sort of timestamps they can use and will tolerate. If you get any + good information and would like to pass it on, please do so and I will + include that information in this documentation. + + + + + This example shows how to save a zip file that contains file timestamps + in a format normally used by Unix. + + using (var zip = new ZipFile()) + { + // produce a zip file the Mac will like + zip.EmitTimesInWindowsFormatWhenSaving = false; + zip.EmitTimesInUnixFormatWhenSaving = true; + zip.AddDirectory(directoryToZip, "files"); + zip.Save(outputFile); + } + + + + Using zip As New ZipFile + '' produce a zip file the Mac will like + zip.EmitTimesInWindowsFormatWhenSaving = False + zip.EmitTimesInUnixFormatWhenSaving = True + zip.AddDirectory(directoryToZip, "files") + zip.Save(outputFile) + End Using + + + + + + + + + Specifies whether the Creation, Access, and Modified times + for entries added to the zip file will be emitted in "Unix(tm) + format" when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entries should or should not be stored + in the zip archive in the format used by Unix. By default this flag is + false, meaning the Unix-format times are not stored in the zip + archive. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are + automatically set from the filesystem values. When adding an entry from a + stream or string, all three values are implicitly set to DateTime.Now. + Applications can also explicitly set those times by calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since January 1, 1601 UTC. The other is a format Unix applications + typically use: seconds since January 1, 1970 UTC. Each format can be + stored in an "extra field" in the zip entry when saving the zip + archive. The former uses an extra field with a Header Id of 0x000A, while + the latter uses a header ID of 0x5455, although you probably don't need to + know that. + + + + Not all tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Some tools and libraries may be + able to read only one or the other. DotNetZip can read or write times in + either or both formats. + + + + The times stored are taken from , , and . + + + + This property is not mutually exclusive of the property. It is possible and + legal and valid to produce a zip file that contains timestamps encoded in + the Unix format as well as in the Windows format, in addition to the LastModified time attached to each + entry in the zip archive, a time that is always stored in "DOS + format". And, notwithstanding the names PKWare uses for these time + formats, any of them can be read and written by any computer, on any + operating system. But, there are no guarantees that a program running on + Mac or Linux will gracefully handle a zip file with "Windows" formatted + times, or that an application that does not use DotNetZip but runs on + Windows will be able to handle file times in Unix format. + + + + When in doubt, test. Sorry, I haven't got a complete list of tools and + which sort of timestamps they can use and will tolerate. If you get any + good information and would like to pass it on, please do so and I will + include that information in this documentation. + + + + + + + + + Indicates whether verbose output is sent to the during AddXxx() and + ReadXxx() operations. + + + + This is a synthetic property. It returns true if the is non-null. + + + + + Indicates whether to perform case-sensitive matching on the filename when + retrieving entries in the zipfile via the string-based indexer. + + + + The default value is false, which means don't do case-sensitive + matching. In other words, retrieving zip["ReadMe.Txt"] is the same as + zip["readme.txt"]. It really makes sense to set this to true only + if you are not running on Windows, which has case-insensitive + filenames. But since this library is not built for non-Windows platforms, + in most cases you should just leave this property alone. + + + + + Indicates whether to encode entry filenames and entry comments using Unicode + (UTF-8). + + + + + The + PKWare zip specification provides for encoding file names and file + comments in either the IBM437 code page, or in UTF-8. This flag selects + the encoding according to that specification. By default, this flag is + false, and filenames and comments are encoded into the zip file in the + IBM437 codepage. Setting this flag to true will specify that filenames + and comments that cannot be encoded with IBM437 will be encoded with + UTF-8. + + + + Zip files created with strict adherence to the PKWare specification with + respect to UTF-8 encoding can contain entries with filenames containing + any combination of Unicode characters, including the full range of + characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other + alphabets. However, because at this time, the UTF-8 portion of the PKWare + specification is not broadly supported by other zip libraries and + utilities, such zip files may not be readable by your favorite zip tool or + archiver. In other words, interoperability will decrease if you set this + flag to true. + + + + In particular, Zip files created with strict adherence to the PKWare + specification with respect to UTF-8 encoding will not work well with + Explorer in Windows XP or Windows Vista, because Windows compressed + folders, as far as I know, do not support UTF-8 in zip files. Vista can + read the zip files, but shows the filenames incorrectly. Unpacking from + Windows Vista Explorer will result in filenames that have rubbish + characters in place of the high-order UTF-8 bytes. + + + + Also, zip files that use UTF-8 encoding will not work well with Java + applications that use the java.util.zip classes, as of v5.0 of the Java + runtime. The Java runtime does not correctly implement the PKWare + specification in this regard. + + + + As a result, we have the unfortunate situation that "correct" behavior by + the DotNetZip library with regard to Unicode encoding of filenames during + zip creation will result in zip files that are readable by strictly + compliant and current tools (for example the most recent release of the + commercial WinZip tool); but these zip files will not be readable by + various other tools or libraries, including Windows Explorer. + + + + The DotNetZip library can read and write zip files with UTF8-encoded + entries, according to the PKware spec. If you use DotNetZip for both + creating and reading the zip file, and you use UTF-8, there will be no + loss of information in the filenames. For example, using a self-extractor + created by this library will allow you to unpack files correctly with no + loss of information in the filenames. + + + + If you do not set this flag, it will remain false. If this flag is false, + your ZipFile will encode all filenames and comments using the + IBM437 codepage. This can cause "loss of information" on some filenames, + but the resulting zipfile will be more interoperable with other + utilities. As an example of the loss of information, diacritics can be + lost. The o-tilde character will be down-coded to plain o. The c with a + cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. + Likewise, the O-stroke character (Unicode 248), used in Danish and + Norwegian, will be down-coded to plain o. Chinese characters cannot be + represented in codepage IBM437; when using the default encoding, Chinese + characters in filenames will be represented as ?. These are all examples + of "information loss". + + + + The loss of information associated to the use of the IBM437 encoding is + inconvenient, and can also lead to runtime errors. For example, using + IBM437, any sequence of 4 Chinese characters will be encoded as ????. If + your application creates a ZipFile, then adds two files, each with + names of four Chinese characters each, this will result in a duplicate + filename exception. In the case where you add a single file with a name + containing four Chinese characters, calling Extract() on the entry that + has question marks in the filename will result in an exception, because + the question mark is not legal for use within filenames on Windows. These + are just a few examples of the problems associated to loss of information. + + + + This flag is independent of the encoding of the content within the entries + in the zip file. Think of the zip file as a container - it supports an + encoding. Within the container are other "containers" - the file entries + themselves. The encoding within those entries is independent of the + encoding of the zip archive container for those entries. + + + + Rather than specify the encoding in a binary fashion using this flag, an + application can specify an arbitrary encoding via the property. Setting the encoding + explicitly when creating zip archives will result in non-compliant zip + files that, curiously, are fairly interoperable. The challenge is, the + PKWare specification does not provide for a way to specify that an entry + in a zip archive uses a code page that is neither IBM437 nor UTF-8. + Therefore if you set the encoding explicitly when creating a zip archive, + you must take care upon reading the zip archive to use the same code page. + If you get it wrong, the behavior is undefined and may result in incorrect + filenames, exceptions, stomach upset, hair loss, and acne. + + + + + + + Specify whether to use ZIP64 extensions when saving a zip archive. + + + + + + When creating a zip file, the default value for the property is . is + safest, in the sense that you will not get an Exception if a pre-ZIP64 + limit is exceeded. + + + + You may set the property at any time before calling Save(). + + + + When reading a zip file via the Zipfile.Read() method, DotNetZip + will properly read ZIP64-endowed zip archives, regardless of the value of + this property. DotNetZip will always read ZIP64 archives. This property + governs only whether DotNetZip will write them. Therefore, when updating + archives, be careful about setting this property after reading an archive + that may use ZIP64 extensions. + + + + An interesting question is, if you have set this property to + AsNecessary, and then successfully saved, does the resulting + archive use ZIP64 extensions or not? To learn this, check the property, after calling Save(). + + + + Have you thought about + donating? + + + + + + + + Indicates whether the archive requires ZIP64 extensions. + + + + + + This property is null (or Nothing in VB) if the archive has + not been saved, and there are fewer than 65334 ZipEntry items + contained in the archive. + + + + The Value is true if any of the following four conditions holds: + the uncompressed size of any entry is larger than 0xFFFFFFFF; the + compressed size of any entry is larger than 0xFFFFFFFF; the relative + offset of any entry within the zip archive is larger than 0xFFFFFFFF; or + there are more than 65534 entries in the archive. (0xFFFFFFFF = + 4,294,967,295). The result may not be known until a Save() is attempted + on the zip archive. The Value of this + property may be set only AFTER one of the Save() methods has been called. + + + + If none of the four conditions holds, and the archive has been saved, then + the Value is false. + + + + A Value of false does not indicate that the zip archive, as saved, + does not use ZIP64. It merely indicates that ZIP64 is not required. An + archive may use ZIP64 even when not required if the property is set to , or if the property is set to and the output stream was not + seekable. Use the property to determine if + the most recent Save() method resulted in an archive that utilized + the ZIP64 extensions. + + + + + + + + + Indicates whether the most recent Save() operation used ZIP64 extensions. + + + + + The use of ZIP64 extensions within an archive is not always necessary, and + for interoperability concerns, it may be desired to NOT use ZIP64 if + possible. The property can be + set to use ZIP64 extensions only when necessary. In those cases, + Sometimes applications want to know whether a Save() actually used ZIP64 + extensions. Applications can query this read-only property to learn + whether ZIP64 has been used in a just-saved ZipFile. + + + + The value is null (or Nothing in VB) if the archive has not + been saved. + + + + Non-null values (HasValue is true) indicate whether ZIP64 + extensions were used during the most recent Save() operation. The + ZIP64 extensions may have been used as required by any particular entry + because of its uncompressed or compressed size, or because the archive is + larger than 4294967295 bytes, or because there are more than 65534 entries + in the archive, or because the UseZip64WhenSaving property was set + to , or because the + UseZip64WhenSaving property was set to and the output stream was not seekable. + The value of this property does not indicate the reason the ZIP64 + extensions were used. + + + + + + + + + Indicates whether the most recent Read() operation read a zip file that uses + ZIP64 extensions. + + + + This property will return null (Nothing in VB) if you've added an entry after reading + the zip file. + + + + + The text encoding to use when writing new entries to the ZipFile, + for those entries that cannot be encoded with the default (IBM437) + encoding; or, the text encoding that was used when reading the entries + from the ZipFile. + + + + + In its + zip specification, PKWare describes two options for encoding + filenames and comments: using IBM437 or UTF-8. But, some archiving tools + or libraries do not follow the specification, and instead encode + characters using the system default code page. For example, WinRAR when + run on a machine in Shanghai may encode filenames with the Big-5 Chinese + (950) code page. This behavior is contrary to the Zip specification, but + it occurs anyway. + + + + When using DotNetZip to write zip archives that will be read by one of + these other archivers, set this property to specify the code page to use + when encoding the and for each ZipEntry in the zip file, for + values that cannot be encoded with the default codepage for zip files, + IBM437. This is why this property is "provisional". In all cases, IBM437 + is used where possible, in other words, where no loss of data would + result. It is possible, therefore, to have a given entry with a + Comment encoded in IBM437 and a FileName encoded with the + specified "provisional" codepage. + + + + Be aware that a zip file created after you've explicitly set the property to a value other than + IBM437 may not be compliant to the PKWare specification, and may not be + readable by compliant archivers. On the other hand, many (most?) + archivers are non-compliant and can read zip files created in arbitrary + code pages. The trick is to use or specify the proper codepage when + reading the zip. + + + + When creating a zip archive using this library, it is possible to change + the value of between each + entry you add, and between adding entries and the call to + Save(). Don't do this. It will likely result in a zipfile that is + not readable. For best interoperability, either leave alone, or specify it only once, + before adding any entries to the ZipFile instance. There is one + exception to this recommendation, described later. + + + + When using an arbitrary, non-UTF8 code page for encoding, there is no + standard way for the creator application - whether DotNetZip, WinZip, + WinRar, or something else - to formally specify in the zip file which + codepage has been used for the entries. As a result, readers of zip files + are not able to inspect the zip file and determine the codepage that was + used for the entries contained within it. It is left to the application + or user to determine the necessary codepage when reading zip files encoded + this way. In other words, if you explicitly specify the codepage when you + create the zipfile, you must explicitly specify the same codepage when + reading the zipfile. + + + + The way you specify the code page to use when reading a zip file varies + depending on the tool or library you use to read the zip. In DotNetZip, + you use a ZipFile.Read() method that accepts an encoding parameter. It + isn't possible with Windows Explorer, as far as I know, to specify an + explicit codepage to use when reading a zip. If you use an incorrect + codepage when reading a zipfile, you will get entries with filenames that + are incorrect, and the incorrect filenames may even contain characters + that are not legal for use within filenames in Windows. Extracting entries + with illegal characters in the filenames will lead to exceptions. It's too + bad, but this is just the way things are with code pages in zip + files. Caveat Emptor. + + + + Example: Suppose you create a zipfile that contains entries with + filenames that have Danish characters. If you use equal to "iso-8859-1" (cp 28591), + the filenames will be correctly encoded in the zip. But, to read that + zipfile correctly, you have to specify the same codepage at the time you + read it. If try to read that zip file with Windows Explorer or another + application that is not flexible with respect to the codepage used to + decode filenames in zipfiles, you will get a filename like "Inf°.txt". + + + + When using DotNetZip to read a zip archive, and the zip archive uses an + arbitrary code page, you must specify the encoding to use before or when + the Zipfile is READ. This means you must use a ZipFile.Read() + method that allows you to specify a System.Text.Encoding parameter. Setting + the ProvisionalAlternateEncoding property after your application has read in + the zip archive will not affect the entry names of entries that have already + been read in. + + + + And now, the exception to the rule described above. One strategy for + specifying the code page for a given zip file is to describe the code page + in a human-readable form in the Zip comment. For example, the comment may + read "Entries in this archive are encoded in the Big5 code page". For + maximum interoperability, the zip comment in this case should be encoded + in the default, IBM437 code page. In this case, the zip comment is + encoded using a different page than the filenames. To do this, Specify + ProvisionalAlternateEncoding to your desired region-specific code + page, once before adding any entries, and then reset + ProvisionalAlternateEncoding to IBM437 before setting the property and calling Save(). + + + + + This example shows how to read a zip file using the Big-5 Chinese code page + (950), and extract each entry in the zip file. For this code to work as + desired, the Zipfile must have been created using the big5 code page + (CP950). This is typical, for example, when using WinRar on a machine with + CP950 set as the default code page. In that case, the names of entries + within the Zip archive will be stored in that code page, and reading the zip + archive must be done using that code page. If the application did not use + the correct code page in ZipFile.Read(), then names of entries within the + zip archive would not be correctly retrieved. + + using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5"))) + { + // retrieve and extract an entry using a name encoded with CP950 + zip[MyDesiredEntry].Extract("unpack"); + } + + + + Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5")) + ' retrieve and extract an entry using a name encoded with CP950 + zip(MyDesiredEntry).Extract("unpack") + End Using + + + + DefaultEncoding + + + + A Text Encoding to use when encoding the filenames and comments for + all the ZipEntry items, during a ZipFile.Save() operation. + + + + Whether the encoding specified here is used during the save depends + on . + + + + + + A flag that tells if and when this instance should apply + AlternateEncoding to encode the filenames and comments associated to + of ZipEntry objects contained within this instance. + + + + + The default text encoding used in zip archives. It is numeric 437, also + known as IBM437. + + + + + + Gets or sets the TextWriter to which status messages are delivered + for the instance. + + + + If the TextWriter is set to a non-null value, then verbose output is sent + to the TextWriter during Add, Read, Save and + Extract operations. Typically, console applications might use + Console.Out and graphical or headless applications might use a + System.IO.StringWriter. The output of this is suitable for viewing + by humans. + + + + + In this example, a console application instantiates a ZipFile, then + sets the StatusMessageTextWriter to Console.Out. At that + point, all verbose status messages for that ZipFile are sent to the + console. + + + + using (ZipFile zip= ZipFile.Read(FilePath)) + { + zip.StatusMessageTextWriter= System.Console.Out; + // messages are sent to the console during extraction + zip.ExtractAll(); + } + + + + Using zip As ZipFile = ZipFile.Read(FilePath) + zip.StatusMessageTextWriter= System.Console.Out + 'Status Messages will be sent to the console during extraction + zip.ExtractAll() + End Using + + + + In this example, a Windows Forms application instantiates a + ZipFile, then sets the StatusMessageTextWriter to a + StringWriter. At that point, all verbose status messages for that + ZipFile are sent to the StringWriter. + + + + var sw = new System.IO.StringWriter(); + using (ZipFile zip= ZipFile.Read(FilePath)) + { + zip.StatusMessageTextWriter= sw; + zip.ExtractAll(); + } + Console.WriteLine("{0}", sw.ToString()); + + + + Dim sw as New System.IO.StringWriter + Using zip As ZipFile = ZipFile.Read(FilePath) + zip.StatusMessageTextWriter= sw + zip.ExtractAll() + End Using + 'Status Messages are now available in sw + + + + + + + Gets or sets the name for the folder to store the temporary file + this library writes when saving a zip archive. + + + + + This library will create a temporary file when saving a Zip archive to a + file. This file is written when calling one of the Save() methods + that does not save to a stream, or one of the SaveSelfExtractor() + methods. + + + + By default, the library will create the temporary file in the directory + specified for the file itself, via the property or via + the method. + + + + Setting this property allows applications to override this default + behavior, so that the library will create the temporary file in the + specified folder. For example, to have the library create the temporary + file in the current working directory, regardless where the ZipFile + is saved, specfy ".". To revert to the default behavior, set this + property to null (Nothing in VB). + + + + When setting the property to a non-null value, the folder specified must + exist; if it does not an exception is thrown. The application should have + write and delete permissions on the folder. The permissions are not + explicitly checked ahead of time; if the application does not have the + appropriate rights, an exception will be thrown at the time Save() + is called. + + + + There is no temporary file created when reading a zip archive. When + saving to a Stream, there is no temporary file created. For example, if + the application is an ASP.NET application and calls Save() + specifying the Response.OutputStream as the output stream, there is + no temporary file created. + + + + + Thrown when setting the property if the directory does not exist. + + + + + + Sets the password to be used on the ZipFile instance. + + + + + + When writing a zip archive, this password is applied to the entries, not + to the zip archive itself. It applies to any ZipEntry subsequently + added to the ZipFile, using one of the AddFile, + AddDirectory, AddEntry, or AddItem methods, etc. + When reading a zip archive, this property applies to any entry + subsequently extracted from the ZipFile using one of the Extract + methods on the ZipFile class. + + + + When writing a zip archive, keep this in mind: though the password is set + on the ZipFile object, according to the Zip spec, the "directory" of the + archive - in other words the list of entries or files contained in the archive - is + not encrypted with the password, or protected in any way. If you set the + Password property, the password actually applies to individual entries + that are added to the archive, subsequent to the setting of this property. + The list of filenames in the archive that is eventually created will + appear in clear text, but the contents of the individual files are + encrypted. This is how Zip encryption works. + + + + One simple way around this limitation is to simply double-wrap sensitive + filenames: Store the files in a zip file, and then store that zip file + within a second, "outer" zip file. If you apply a password to the outer + zip file, then readers will be able to see that the outer zip file + contains an inner zip file. But readers will not be able to read the + directory or file list of the inner zip file. + + + + If you set the password on the ZipFile, and then add a set of files + to the archive, then each entry is encrypted with that password. You may + also want to change the password between adding different entries. If you + set the password, add an entry, then set the password to null + (Nothing in VB), and add another entry, the first entry is + encrypted and the second is not. If you call AddFile(), then set + the Password property, then call ZipFile.Save, the file + added will not be password-protected, and no warning will be generated. + + + + When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added + to the ZipFile. If you set the Password to a non-null value and do not + set , then PKZip 2.0 ("Weak") encryption is used. + This encryption is relatively weak but is very interoperable. If you set + the password to a null value (Nothing in VB), Encryption is + reset to None. + + + + All of the preceding applies to writing zip archives, in other words when + you use one of the Save methods. To use this property when reading or an + existing ZipFile, do the following: set the Password property on the + ZipFile, then call one of the Extract() overloads on the . In this case, the entry is extracted using the + Password that is specified on the ZipFile instance. If you + have not set the Password property, then the password is + null, and the entry is extracted with no password. + + + + If you set the Password property on the ZipFile, then call + Extract() an entry that has not been encrypted with a password, the + password is not used for that entry, and the ZipEntry is extracted + as normal. In other words, the password is used only if necessary. + + + + The class also has a Password property. It takes precedence + over this property on the ZipFile. Typically, you would use the + per-entry Password when most entries in the zip archive use one password, + and a few entries use a different password. If all entries in the zip + file use the same password, then it is simpler to just set this property + on the ZipFile itself, whether creating a zip archive or extracting + a zip archive. + + + + + + + This example creates a zip file, using password protection for the + entries, and then extracts the entries from the zip file. When creating + the zip file, the Readme.txt file is not protected with a password, but + the other two are password-protected as they are saved. During extraction, + each file is extracted with the appropriate password. + + + // create a file with encryption + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("ReadMe.txt"); + zip.Password= "!Secret1"; + zip.AddFile("MapToTheSite-7440-N49th.png"); + zip.AddFile("2008-Regional-Sales-Report.pdf"); + zip.Save("EncryptedArchive.zip"); + } + + // extract entries that use encryption + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + zip.Password= "!Secret1"; + zip.ExtractAll("extractDir"); + } + + + + + Using zip As New ZipFile + zip.AddFile("ReadMe.txt") + zip.Password = "123456!" + zip.AddFile("MapToTheSite-7440-N49th.png") + zip.Password= "!Secret1"; + zip.AddFile("2008-Regional-Sales-Report.pdf") + zip.Save("EncryptedArchive.zip") + End Using + + + ' extract entries that use encryption + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + zip.Password= "!Secret1" + zip.ExtractAll("extractDir") + End Using + + + + + + ZipFile.Encryption + ZipEntry.Password + + + + The action the library should take when extracting a file that already + exists. + + + + + This property affects the behavior of the Extract methods (one of the + Extract() or ExtractWithPassword() overloads), when + extraction would would overwrite an existing filesystem file. If you do + not set this property, the library throws an exception when extracting an + entry would overwrite an existing file. + + + + This property has no effect when extracting to a stream, or when the file + to be extracted does not already exist. + + + + + + + The action the library should take when an error is encountered while + opening or reading files as they are saved into a zip archive. + + + + + Errors can occur as a file is being saved to the zip archive. For + example, the File.Open may fail, or a File.Read may fail, because of + lock conflicts or other reasons. + + + + The first problem might occur after having called AddDirectory() on a + directory that contains a Clipper .dbf file; the file is locked by + Clipper and cannot be opened for read by another process. An example of + the second problem might occur when trying to zip a .pst file that is in + use by Microsoft Outlook. Outlook locks a range on the file, which allows + other processes to open the file, but not read it in its entirety. + + + + This property tells DotNetZip what you would like to do in the case of + these errors. The primary options are: ZipErrorAction.Throw to + throw an exception (this is the default behavior if you don't set this + property); ZipErrorAction.Skip to Skip the file for which there + was an error and continue saving; ZipErrorAction.Retry to Retry + the entry that caused the problem; or + ZipErrorAction.InvokeErrorEvent to invoke an event handler. + + + + This property is implicitly set to ZipErrorAction.InvokeErrorEvent + if you add a handler to the event. If you set + this property to something other than + ZipErrorAction.InvokeErrorEvent, then the ZipError + event is implicitly cleared. What it means is you can set one or the + other (or neither), depending on what you want, but you never need to set + both. + + + + As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile + instance will cause the specified ZipErrorAction to be used on all + items that are subsequently added to the + ZipFile instance. If you set this property after you have added + items to the ZipFile, but before you have called Save(), + those items will not use the specified error handling action. + + + + If you want to handle any errors that occur with any entry in the zip + file in the same way, then set this property once, before adding any + entries to the zip archive. + + + + If you set this property to ZipErrorAction.Skip and you'd like to + learn which files may have been skipped after a Save(), you can + set the on the ZipFile before + calling Save(). A message will be emitted into that writer for + each skipped file, if any. + + + + + + This example shows how to tell DotNetZip to skip any files for which an + error is generated during the Save(). + + Public Sub SaveZipFile() + Dim SourceFolder As String = "fodder" + Dim DestFile As String = "eHandler.zip" + Dim sw as New StringWriter + Using zipArchive As ZipFile = New ZipFile + ' Tell DotNetZip to skip any files for which it encounters an error + zipArchive.ZipErrorAction = ZipErrorAction.Skip + zipArchive.StatusMessageTextWriter = sw + zipArchive.AddDirectory(SourceFolder) + zipArchive.Save(DestFile) + End Using + ' examine sw here to see any messages + End Sub + + + + + + + + + + The Encryption to use for entries added to the ZipFile. + + + + + Set this when creating a zip archive, or when updating a zip archive. The + specified Encryption is applied to the entries subsequently added to the + ZipFile instance. Applications do not need to set the + Encryption property when reading or extracting a zip archive. + + + + If you set this to something other than EncryptionAlgorithm.None, you + will also need to set the . + + + + As with some other properties on the ZipFile class, like and , setting this + property on a ZipFile instance will cause the specified + EncryptionAlgorithm to be used on all items + that are subsequently added to the ZipFile instance. In other + words, if you set this property after you have added items to the + ZipFile, but before you have called Save(), those items will + not be encrypted or protected with a password in the resulting zip + archive. To get a zip archive with encrypted entries, set this property, + along with the property, before calling + AddFile, AddItem, or AddDirectory (etc.) on the + ZipFile instance. + + + + If you read a ZipFile, you can modify the Encryption on an + encrypted entry, only by setting the Encryption property on the + ZipEntry itself. Setting the Encryption property on the + ZipFile, once it has been created via a call to + ZipFile.Read(), does not affect entries that were previously read. + + + + For example, suppose you read a ZipFile, and there is an encrypted + entry. Setting the Encryption property on that ZipFile and + then calling Save() on the ZipFile does not update the + Encryption used for the entries in the archive. Neither is an + exception thrown. Instead, what happens during the Save() is that + all previously existing entries are copied through to the new zip archive, + with whatever encryption and password that was used when originally + creating the zip archive. Upon re-reading that archive, to extract + entries, applications should use the original password or passwords, if + any. + + + + Suppose an application reads a ZipFile, and there is an encrypted + entry. Setting the Encryption property on that ZipFile and + then adding new entries (via AddFile(), AddEntry(), etc) + and then calling Save() on the ZipFile does not update the + Encryption on any of the entries that had previously been in the + ZipFile. The Encryption property applies only to the + newly-added entries. + + + + + + + This example creates a zip archive that uses encryption, and then extracts + entries from the archive. When creating the zip archive, the ReadMe.txt + file is zipped without using a password or encryption. The other files + use encryption. + + + + // Create a zip archive with AES Encryption. + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("ReadMe.txt"); + zip.Encryption= EncryptionAlgorithm.WinZipAes256; + zip.Password= "Top.Secret.No.Peeking!"; + zip.AddFile("7440-N49th.png"); + zip.AddFile("2008-Regional-Sales-Report.pdf"); + zip.Save("EncryptedArchive.zip"); + } + + // Extract a zip archive that uses AES Encryption. + // You do not need to specify the algorithm during extraction. + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + zip.Password= "Top.Secret.No.Peeking!"; + zip.ExtractAll("extractDirectory"); + } + + + + ' Create a zip that uses Encryption. + Using zip As New ZipFile() + zip.Encryption= EncryptionAlgorithm.WinZipAes256 + zip.Password= "Top.Secret.No.Peeking!" + zip.AddFile("ReadMe.txt") + zip.AddFile("7440-N49th.png") + zip.AddFile("2008-Regional-Sales-Report.pdf") + zip.Save("EncryptedArchive.zip") + End Using + + ' Extract a zip archive that uses AES Encryption. + ' You do not need to specify the algorithm during extraction. + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + zip.Password= "Top.Secret.No.Peeking!" + zip.ExtractAll("extractDirectory") + End Using + + + + + ZipFile.Password + ZipEntry.Encryption + + + + A callback that allows the application to specify the compression level + to use for entries subsequently added to the zip archive. + + + + + + With this callback, the DotNetZip library allows the application to + determine whether compression will be used, at the time of the + Save. This may be useful if the application wants to favor + speed over size, and wants to defer the decision until the time of + Save. + + + + Typically applications set the property on + the ZipFile or on each ZipEntry to determine the level of + compression used. This is done at the time the entry is added to the + ZipFile. Setting the property to + Ionic.Zlib.CompressionLevel.None means no compression will be used. + + + + This callback allows the application to defer the decision on the + CompressionLevel to use, until the time of the call to + ZipFile.Save(). The callback is invoked once per ZipEntry, + at the time the data for the entry is being written out as part of a + Save() operation. The application can use whatever criteria it + likes in determining the level to return. For example, an application may + wish that no .mp3 files should be compressed, because they are already + compressed and the extra compression is not worth the CPU time incurred, + and so can return None for all .mp3 entries. + + + + The library determines whether compression will be attempted for an entry + this way: If the entry is a zero length file, or a directory, no + compression is used. Otherwise, if this callback is set, it is invoked + and the CompressionLevel is set to the return value. If this + callback has not been set, then the previously set value for + CompressionLevel is used. + + + + + + + The maximum size of an output segment, when saving a split Zip file. + + + + Set this to a non-zero value before calling or to specify that the ZipFile should be saved as a + split archive, also sometimes called a spanned archive. Some also + call them multi-file archives. + + + + A split zip archive is saved in a set of discrete filesystem files, + rather than in a single file. This is handy when transmitting the + archive in email or some other mechanism that has a limit to the size of + each file. The first file in a split archive will be named + basename.z01, the second will be named basename.z02, and + so on. The final file is named basename.zip. According to the zip + specification from PKWare, the minimum value is 65536, for a 64k segment + size. The maximum number of segments allows in a split archive is 99. + + + + The value of this property determines the maximum size of a split + segment when writing a split archive. For example, suppose you have a + ZipFile that would save to a single file of 200k. If you set the + MaxOutputSegmentSize to 65536 before calling Save(), you + will get four distinct output files. On the other hand if you set this + property to 256k, then you will get a single-file archive for that + ZipFile. + + + + The size of each split output file will be as large as possible, up to + the maximum size set here. The zip specification requires that some data + fields in a zip archive may not span a split boundary, and an output + segment may be smaller than the maximum if necessary to avoid that + problem. Also, obviously the final segment of the archive may be smaller + than the maximum segment size. Segments will never be larger than the + value set with this property. + + + + You can save a split Zip file only when saving to a regular filesystem + file. It's not possible to save a split zip file as a self-extracting + archive, nor is it possible to save a split zip file to a stream. When + saving to a SFX or to a Stream, this property is ignored. + + + + About interoperability: Split or spanned zip files produced by DotNetZip + can be read by WinZip or PKZip, and vice-versa. Segmented zip files may + not be readable by other tools, if those other tools don't support zip + spanning or splitting. When in doubt, test. I don't believe Windows + Explorer can extract a split archive. + + + + This property has no effect when reading a split archive. You can read + a split archive in the normal way with DotNetZip. + + + + When saving a zip file, if you want a regular zip file rather than a + split zip file, don't set this property, or set it to Zero. + + + + If you read a split archive, with and + then subsequently call ZipFile.Save(), unless you set this + property before calling Save(), you will get a normal, + single-file archive. + + + + + + + + Returns the number of segments used in the most recent Save() operation. + + + + This is normally zero, unless you have set the property. If you have set , and then you save a file, after the call to + Save() completes, you can read this value to learn the number of segments that + were created. + + + If you call Save("Archive.zip"), and it creates 5 segments, then you + will have filesystem files named Archive.z01, Archive.z02, Archive.z03, + Archive.z04, and Archive.zip, and the value of this property will be 5. + + + + + + + The size threshold for an entry, above which a parallel deflate is used. + + + + + + DotNetZip will use multiple threads to compress any ZipEntry, + if the entry is larger than the given size. Zero means "always + use parallel deflate", while -1 means "never use parallel + deflate". The default value for this property is 512k. Aside + from the special values of 0 and 1, the minimum value is 65536. + + + + If the entry size cannot be known before compression, as with a + read-forward stream, then Parallel deflate will never be + performed, unless the value of this property is zero. + + + + A parallel deflate operations will speed up the compression of + large files, on computers with multiple CPUs or multiple CPU + cores. For files above 1mb, on a dual core or dual-cpu (2p) + machine, the time required to compress the file can be 70% of the + single-threaded deflate. For very large files on 4p machines the + compression can be done in 30% of the normal time. The downside + is that parallel deflate consumes extra memory during the deflate, + and the deflation is not as effective. + + + + Parallel deflate tends to yield slightly less compression when + compared to as single-threaded deflate; this is because the original + data stream is split into multiple independent buffers, each of which + is compressed in parallel. But because they are treated + independently, there is no opportunity to share compression + dictionaries. For that reason, a deflated stream may be slightly + larger when compressed using parallel deflate, as compared to a + traditional single-threaded deflate. Sometimes the increase over the + normal deflate is as much as 5% of the total compressed size. For + larger files it can be as small as 0.1%. + + + + Multi-threaded compression does not give as much an advantage when + using Encryption. This is primarily because encryption tends to slow + down the entire pipeline. Also, multi-threaded compression gives less + of an advantage when using lower compression levels, for example . You may have to + perform some tests to determine the best approach for your situation. + + + + + + + + + + The maximum number of buffer pairs to use when performing + parallel compression. + + + + + This property sets an upper limit on the number of memory + buffer pairs to create when performing parallel + compression. The implementation of the parallel + compression stream allocates multiple buffers to + facilitate parallel compression. As each buffer fills up, + the stream uses + ThreadPool.QueueUserWorkItem() to compress those + buffers in a background threadpool thread. After a buffer + is compressed, it is re-ordered and written to the output + stream. + + + + A higher number of buffer pairs enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + For each compression "task" that occurs in parallel, there are 2 + buffers allocated: one for input and one for output. This property + sets a limit for the number of pairs. The total amount of storage + space allocated for buffering will then be (N*S*2), where N is the + number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer + pairs per CPU core, so if your machine has 4 cores, and you retain + the default buffer size of 128k, then the + ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer + memory in total, or 4mb, in blocks of 128kb. If you then set this + property to 8, then the number will be 8 * 2 * 128kb of buffer + memory, or 2mb. + + + + CPU utilization will also go up with additional buffers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + This property is not the number of buffer pairs to use; it is an + upper limit. An illustration: Suppose you have an application that + uses the default value of this property (which is 16), and it runs + on a machine with 2 CPU cores. In that case, DotNetZip will allocate + 4 buffer pairs per CPU core, for a total of 8 pairs. The upper + limit specified by this property has no effect. + + + + The application can set this value at any time + before calling ZipFile.Save(). + + + + + + + + + Returns the version number on the DotNetZip assembly. + + + + + This property is exposed as a convenience. Callers could also get the + version value by retrieving GetName().Version on the + System.Reflection.Assembly object pointing to the DotNetZip + assembly. But sometimes it is not clear which assembly is being loaded. + This property makes it clear. + + + This static property is primarily useful for diagnostic purposes. + + + + + + This is an integer indexer into the Zip archive. + + + + + This property is read-only. + + + + Internally, the ZipEntry instances that belong to the + ZipFile are stored in a Dictionary. When you use this + indexer the first time, it creates a read-only + List<ZipEntry> from the Dictionary.Values Collection. + If at any time you modify the set of entries in the ZipFile, + either by adding an entry, removing an entry, or renaming an + entry, a new List will be created, and the numeric indexes for the + remaining entries may be different. + + + + This means you cannot rename any ZipEntry from + inside an enumeration of the zip file. + + + + The index value. + + + + + + The ZipEntry within the Zip archive at the specified index. If the + entry does not exist in the archive, this indexer throws. + + + + + + This is a name-based indexer into the Zip archive. + + + + + This property is read-only. + + + + The property on the ZipFile + determines whether retrieval via this indexer is done via case-sensitive + comparisons. By default, retrieval is not case sensitive. This makes + sense on Windows, in which filesystems are not case sensitive. + + + + Regardless of case-sensitivity, it is not always the case that + this[value].FileName == value. In other words, the FileName + property of the ZipEntry retrieved with this indexer, may or may + not be equal to the index value. + + + + This is because DotNetZip performs a normalization of filenames passed to + this indexer, before attempting to retrieve the item. That normalization + includes: removal of a volume letter and colon, swapping backward slashes + for forward slashes. So, zip["dir1\\entry1.txt"].FileName == + "dir1/entry.txt". + + + + Directory entries in the zip file may be retrieved via this indexer only + with names that have a trailing slash. DotNetZip automatically appends a + trailing slash to the names of any directory entries added to a zip. + + + + + + This example extracts only the entries in a zip file that are .txt files. + + using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) + { + foreach (string s1 in zip.EntryFilenames) + { + if (s1.EndsWith(".txt")) + zip[s1].Extract("textfiles"); + } + } + + + Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") + Dim s1 As String + For Each s1 In zip.EntryFilenames + If s1.EndsWith(".txt") Then + zip(s1).Extract("textfiles") + End If + Next + End Using + + + + + + Thrown if the caller attempts to assign a non-null value to the indexer. + + + + The name of the file, including any directory path, to retrieve from the + zip. The filename match is not case-sensitive by default; you can use the + property to change this behavior. The + pathname can use forward-slashes or backward slashes. + + + + The ZipEntry within the Zip archive, given by the specified + filename. If the named entry does not exist in the archive, this indexer + returns null (Nothing in VB). + + + + + + The list of filenames for the entries contained within the zip archive. + + + + According to the ZIP specification, the names of the entries use forward + slashes in pathnames. If you are scanning through the list, you may have + to swap forward slashes for backslashes. + + + + + + This example shows one way to test if a filename is already contained + within a zip archive. + + String zipFileToRead= "PackedDocuments.zip"; + string candidate = "DatedMaterial.xps"; + using (ZipFile zip = new ZipFile(zipFileToRead)) + { + if (zip.EntryFilenames.Contains(candidate)) + Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", + candidate, + zipFileName); + else + Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", + candidate, + zipFileName); + Console.WriteLine(); + } + + + Dim zipFileToRead As String = "PackedDocuments.zip" + Dim candidate As String = "DatedMaterial.xps" + Using zip As ZipFile.Read(ZipFileToRead) + If zip.EntryFilenames.Contains(candidate) Then + Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _ + candidate, _ + zipFileName) + Else + Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _ + candidate, _ + zipFileName) + End If + Console.WriteLine + End Using + + + + + The list of strings for the filenames contained within the Zip archive. + + + + + + Returns the readonly collection of entries in the Zip archive. + + + + + + If there are no entries in the current ZipFile, the value returned is a + non-null zero-element collection. If there are entries in the zip file, + the elements are returned in no particular order. + + + This is the implied enumerator on the ZipFile class. If you use a + ZipFile instance in a context that expects an enumerator, you will + get this collection. + + + + + + + Returns a readonly collection of entries in the Zip archive, sorted by FileName. + + + + If there are no entries in the current ZipFile, the value returned + is a non-null zero-element collection. If there are entries in the zip + file, the elements are returned sorted by the name of the entry. + + + + + This example fills a Windows Forms ListView with the entries in a zip file. + + + using (ZipFile zip = ZipFile.Read(zipFile)) + { + foreach (ZipEntry entry in zip.EntriesSorted) + { + ListViewItem item = new ListViewItem(n.ToString()); + n++; + string[] subitems = new string[] { + entry.FileName.Replace("/","\\"), + entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), + entry.UncompressedSize.ToString(), + String.Format("{0,5:F0}%", entry.CompressionRatio), + entry.CompressedSize.ToString(), + (entry.UsesEncryption) ? "Y" : "N", + String.Format("{0:X8}", entry.Crc)}; + + foreach (String s in subitems) + { + ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem(); + subitem.Text = s; + item.SubItems.Add(subitem); + } + + this.listView1.Items.Add(item); + } + } + + + + + + + + Returns the number of entries in the Zip archive. + + + + + An event handler invoked when a Save() starts, before and after each + entry has been written to the archive, when a Save() completes, and + during other Save events. + + + + + Depending on the particular event, different properties on the parameter are set. The following + table summarizes the available EventTypes and the conditions under + which this event handler is invoked with a + SaveProgressEventArgs with the given EventType. + + + + + value of EntryType + Meaning and conditions + + + + ZipProgressEventType.Saving_Started + Fired when ZipFile.Save() begins. + + + + + ZipProgressEventType.Saving_BeforeSaveEntry + + Fired within ZipFile.Save(), just before writing data for each + particular entry. + + + + + ZipProgressEventType.Saving_AfterSaveEntry + + Fired within ZipFile.Save(), just after having finished writing data + for each particular entry. + + + + + ZipProgressEventType.Saving_Completed + Fired when ZipFile.Save() has completed. + + + + + ZipProgressEventType.Saving_AfterSaveTempArchive + + Fired after the temporary file has been created. This happens only + when saving to a disk file. This event will not be invoked when + saving to a stream. + + + + + ZipProgressEventType.Saving_BeforeRenameTempArchive + + Fired just before renaming the temporary file to the permanent + location. This happens only when saving to a disk file. This event + will not be invoked when saving to a stream. + + + + + ZipProgressEventType.Saving_AfterRenameTempArchive + + Fired just after renaming the temporary file to the permanent + location. This happens only when saving to a disk file. This event + will not be invoked when saving to a stream. + + + + + ZipProgressEventType.Saving_AfterCompileSelfExtractor + + Fired after a self-extracting archive has finished compiling. This + EventType is used only within SaveSelfExtractor(). + + + + + ZipProgressEventType.Saving_BytesRead + + Set during the save of a particular entry, to update progress of the + Save(). When this EventType is set, the BytesTransferred is the + number of bytes that have been read from the source stream. The + TotalBytesToTransfer is the number of bytes in the uncompressed + file. + + + + + + + + + This example uses an anonymous method to handle the + SaveProgress event, by updating a progress bar. + + + progressBar1.Value = 0; + progressBar1.Max = listbox1.Items.Count; + using (ZipFile zip = new ZipFile()) + { + // listbox1 contains a list of filenames + zip.AddFiles(listbox1.Items); + + // do the progress bar: + zip.SaveProgress += (sender, e) => { + if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) { + progressBar1.PerformStep(); + } + }; + + zip.Save(fs); + } + + + + + This example uses a named method as the + SaveProgress event handler, to update the user, in a + console-based application. + + + static bool justHadByteUpdate= false; + public static void SaveProgress(object sender, SaveProgressEventArgs e) + { + if (e.EventType == ZipProgressEventType.Saving_Started) + Console.WriteLine("Saving: {0}", e.ArchiveName); + + else if (e.EventType == ZipProgressEventType.Saving_Completed) + { + justHadByteUpdate= false; + Console.WriteLine(); + Console.WriteLine("Done: {0}", e.ArchiveName); + } + + else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) + { + if (justHadByteUpdate) + Console.WriteLine(); + Console.WriteLine(" Writing: {0} ({1}/{2})", + e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal); + justHadByteUpdate= false; + } + + else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead) + { + if (justHadByteUpdate) + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, + e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); + justHadByteUpdate= true; + } + } + + public static ZipUp(string targetZip, string directory) + { + using (var zip = new ZipFile()) { + zip.SaveProgress += SaveProgress; + zip.AddDirectory(directory); + zip.Save(targetZip); + } + } + + + + + Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String) + Using zip As ZipFile = New ZipFile + AddHandler zip.SaveProgress, AddressOf MySaveProgress + zip.AddDirectory(directory) + zip.Save(targetZip) + End Using + End Sub + + Private Shared justHadByteUpdate As Boolean = False + + Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal e As SaveProgressEventArgs) + If (e.EventType Is ZipProgressEventType.Saving_Started) Then + Console.WriteLine("Saving: {0}", e.ArchiveName) + + ElseIf (e.EventType Is ZipProgressEventType.Saving_Completed) Then + justHadByteUpdate = False + Console.WriteLine + Console.WriteLine("Done: {0}", e.ArchiveName) + + ElseIf (e.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then + If justHadByteUpdate Then + Console.WriteLine + End If + Console.WriteLine(" Writing: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal) + justHadByteUpdate = False + + ElseIf (e.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then + If justHadByteUpdate Then + Console.SetCursorPosition(0, Console.CursorTop) + End If + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, _ + e.TotalBytesToTransfer, _ + (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) + justHadByteUpdate = True + End If + End Sub + + + + + + This is a more complete example of using the SaveProgress + events in a Windows Forms application, with a + Thread object. + + + delegate void SaveEntryProgress(SaveProgressEventArgs e); + delegate void ButtonClick(object sender, EventArgs e); + + public class WorkerOptions + { + public string ZipName; + public string Folder; + public string Encoding; + public string Comment; + public int ZipFlavor; + public Zip64Option Zip64; + } + + private int _progress2MaxFactor; + private bool _saveCanceled; + private long _totalBytesBeforeCompress; + private long _totalBytesAfterCompress; + private Thread _workerThread; + + + private void btnZipup_Click(object sender, EventArgs e) + { + KickoffZipup(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + if (this.lblStatus.InvokeRequired) + { + this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, e }); + } + else + { + _saveCanceled = true; + lblStatus.Text = "Canceled..."; + ResetState(); + } + } + + private void KickoffZipup() + { + _folderName = tbDirName.Text; + + if (_folderName == null || _folderName == "") return; + if (this.tbZipName.Text == null || this.tbZipName.Text == "") return; + + // check for existence of the zip file: + if (System.IO.File.Exists(this.tbZipName.Text)) + { + var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." + + " Do you want to overwrite this file?", this.tbZipName.Text), + "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (dlgResult != DialogResult.Yes) return; + System.IO.File.Delete(this.tbZipName.Text); + } + + _saveCanceled = false; + _nFilesCompleted = 0; + _totalBytesAfterCompress = 0; + _totalBytesBeforeCompress = 0; + this.btnOk.Enabled = false; + this.btnOk.Text = "Zipping..."; + this.btnCancel.Enabled = true; + lblStatus.Text = "Zipping..."; + + var options = new WorkerOptions + { + ZipName = this.tbZipName.Text, + Folder = _folderName, + Encoding = "ibm437" + }; + + if (this.comboBox1.SelectedIndex != 0) + { + options.Encoding = this.comboBox1.SelectedItem.ToString(); + } + + if (this.radioFlavorSfxCmd.Checked) + options.ZipFlavor = 2; + else if (this.radioFlavorSfxGui.Checked) + options.ZipFlavor = 1; + else options.ZipFlavor = 0; + + if (this.radioZip64AsNecessary.Checked) + options.Zip64 = Zip64Option.AsNecessary; + else if (this.radioZip64Always.Checked) + options.Zip64 = Zip64Option.Always; + else options.Zip64 = Zip64Option.Never; + + options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n", + options.Encoding, + FlavorToString(options.ZipFlavor), + options.Zip64.ToString(), + System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"), + this.Text); + + if (this.tbComment.Text != TB_COMMENT_NOTE) + options.Comment += this.tbComment.Text; + + _workerThread = new Thread(this.DoSave); + _workerThread.Name = "Zip Saver thread"; + _workerThread.Start(options); + this.Cursor = Cursors.WaitCursor; + } + + + private void DoSave(Object p) + { + WorkerOptions options = p as WorkerOptions; + try + { + using (var zip1 = new ZipFile()) + { + zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding); + zip1.Comment = options.Comment; + zip1.AddDirectory(options.Folder); + _entriesToZip = zip1.EntryFileNames.Count; + SetProgressBars(); + zip1.SaveProgress += this.zip1_SaveProgress; + + zip1.UseZip64WhenSaving = options.Zip64; + + if (options.ZipFlavor == 1) + zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication); + else if (options.ZipFlavor == 2) + zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication); + else + zip1.Save(options.ZipName); + } + } + catch (System.Exception exc1) + { + MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message)); + btnCancel_Click(null, null); + } + } + + + + void zip1_SaveProgress(object sender, SaveProgressEventArgs e) + { + switch (e.EventType) + { + case ZipProgressEventType.Saving_AfterWriteEntry: + StepArchiveProgress(e); + break; + case ZipProgressEventType.Saving_EntryBytesRead: + StepEntryProgress(e); + break; + case ZipProgressEventType.Saving_Completed: + SaveCompleted(); + break; + case ZipProgressEventType.Saving_AfterSaveTempArchive: + // this event only occurs when saving an SFX file + TempArchiveSaved(); + break; + } + if (_saveCanceled) + e.Cancel = true; + } + + + + private void StepArchiveProgress(SaveProgressEventArgs e) + { + if (this.progressBar1.InvokeRequired) + { + this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { e }); + } + else + { + if (!_saveCanceled) + { + _nFilesCompleted++; + this.progressBar1.PerformStep(); + _totalBytesAfterCompress += e.CurrentEntry.CompressedSize; + _totalBytesBeforeCompress += e.CurrentEntry.UncompressedSize; + + // reset the progress bar for the entry: + this.progressBar2.Value = this.progressBar2.Maximum = 1; + + this.Update(); + } + } + } + + + private void StepEntryProgress(SaveProgressEventArgs e) + { + if (this.progressBar2.InvokeRequired) + { + this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { e }); + } + else + { + if (!_saveCanceled) + { + if (this.progressBar2.Maximum == 1) + { + // reset + Int64 max = e.TotalBytesToTransfer; + _progress2MaxFactor = 0; + while (max > System.Int32.MaxValue) + { + max /= 2; + _progress2MaxFactor++; + } + this.progressBar2.Maximum = (int)max; + lblStatus.Text = String.Format("{0} of {1} files...({2})", + _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName); + } + + int xferred = e.BytesTransferred >> _progress2MaxFactor; + + this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) + ? this.progressBar2.Maximum + : xferred; + + this.Update(); + } + } + } + + private void SaveCompleted() + { + if (this.lblStatus.InvokeRequired) + { + this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted)); + } + else + { + lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.", + _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress); + ResetState(); + } + } + + private void ResetState() + { + this.btnCancel.Enabled = false; + this.btnOk.Enabled = true; + this.btnOk.Text = "Zip it!"; + this.progressBar1.Value = 0; + this.progressBar2.Value = 0; + this.Cursor = Cursors.Default; + if (!_workerThread.IsAlive) + _workerThread.Join(); + } + + + + + + + + + + + An event handler invoked before, during, and after the reading of a zip archive. + + + + + Depending on the particular event being signaled, different properties on the + parameter are set. The following table + summarizes the available EventTypes and the conditions under which this + event handler is invoked with a ReadProgressEventArgs with the given EventType. + + + + + value of EntryType + Meaning and conditions + + + + ZipProgressEventType.Reading_Started + Fired just as ZipFile.Read() begins. Meaningful properties: ArchiveName. + + + + + ZipProgressEventType.Reading_Completed + Fired when ZipFile.Read() has completed. Meaningful properties: ArchiveName. + + + + + ZipProgressEventType.Reading_ArchiveBytesRead + Fired while reading, updates the number of bytes read for the entire archive. + Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. + + + + + ZipProgressEventType.Reading_BeforeReadEntry + Indicates an entry is about to be read from the archive. + Meaningful properties: ArchiveName, EntriesTotal. + + + + + ZipProgressEventType.Reading_AfterReadEntry + Indicates an entry has just been read from the archive. + Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry. + + + + + + + + + + + + + An event handler invoked before, during, and after extraction of + entries in the zip archive. + + + + + Depending on the particular event, different properties on the parameter are set. The following + table summarizes the available EventTypes and the conditions under + which this event handler is invoked with a + ExtractProgressEventArgs with the given EventType. + + + + + value of EntryType + Meaning and conditions + + + + ZipProgressEventType.Extracting_BeforeExtractAll + + Set when ExtractAll() begins. The ArchiveName, Overwrite, and + ExtractLocation properties are meaningful. + + + + ZipProgressEventType.Extracting_AfterExtractAll + + Set when ExtractAll() has completed. The ArchiveName, Overwrite, + and ExtractLocation properties are meaningful. + + + + + ZipProgressEventType.Extracting_BeforeExtractEntry + + Set when an Extract() on an entry in the ZipFile has begun. + Properties that are meaningful: ArchiveName, EntriesTotal, + CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. + + + + + ZipProgressEventType.Extracting_AfterExtractEntry + + Set when an Extract() on an entry in the ZipFile has completed. + Properties that are meaningful: ArchiveName, EntriesTotal, + CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. + + + + + ZipProgressEventType.Extracting_EntryBytesWritten + + Set within a call to Extract() on an entry in the ZipFile, as data + is extracted for the entry. Properties that are meaningful: + ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. + + + + + ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite + + Set within a call to Extract() on an entry in the ZipFile, when the + extraction would overwrite an existing file. This event type is used + only when ExtractExistingFileAction on the ZipFile or + ZipEntry is set to InvokeExtractProgressEvent. + + + + + + + + + + private static bool justHadByteUpdate = false; + public static void ExtractProgress(object sender, ExtractProgressEventArgs e) + { + if(e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) + { + if (justHadByteUpdate) + Console.SetCursorPosition(0, Console.CursorTop); + + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, + e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); + justHadByteUpdate = true; + } + else if(e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) + { + if (justHadByteUpdate) + Console.WriteLine(); + Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName); + justHadByteUpdate= false; + } + } + + public static ExtractZip(string zipToExtract, string directory) + { + string TargetDirectory= "extract"; + using (var zip = ZipFile.Read(zipToExtract)) { + zip.ExtractProgress += ExtractProgress; + foreach (var e in zip1) + { + e.Extract(TargetDirectory, true); + } + } + } + + + + Public Shared Sub Main(ByVal args As String()) + Dim ZipToUnpack As String = "C1P3SML.zip" + Dim TargetDir As String = "ExtractTest_Extract" + Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir) + Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack) + AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress + Dim e As ZipEntry + For Each e In zip1 + e.Extract(TargetDir, True) + Next + End Using + End Sub + + Private Shared justHadByteUpdate As Boolean = False + + Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal e As ExtractProgressEventArgs) + If (e.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then + If ExtractTest.justHadByteUpdate Then + Console.SetCursorPosition(0, Console.CursorTop) + End If + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) + ExtractTest.justHadByteUpdate = True + ElseIf (e.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then + If ExtractTest.justHadByteUpdate Then + Console.WriteLine + End If + Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName) + ExtractTest.justHadByteUpdate = False + End If + End Sub + + + + + + + + + + An event handler invoked before, during, and after Adding entries to a zip archive. + + + + Adding a large number of entries to a zip file can take a long + time. For example, when calling on a + directory that contains 50,000 files, it could take 3 minutes or so. + This event handler allws an application to track the progress of the Add + operation, and to optionally cancel a lengthy Add operation. + + + + + + int _numEntriesToAdd= 0; + int _numEntriesAdded= 0; + void AddProgressHandler(object sender, AddProgressEventArgs e) + { + switch (e.EventType) + { + case ZipProgressEventType.Adding_Started: + Console.WriteLine("Adding files to the zip..."); + break; + case ZipProgressEventType.Adding_AfterAddEntry: + _numEntriesAdded++; + Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}", + _numEntriesAdded, _numEntriesToAdd, e.CurrentEntry.FileName)); + break; + case ZipProgressEventType.Adding_Completed: + Console.WriteLine("Added all files"); + break; + } + } + + void CreateTheZip() + { + using (ZipFile zip = new ZipFile()) + { + zip.AddProgress += AddProgressHandler; + zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)); + zip.Save(ZipFileToCreate); + } + } + + + + + + Private Sub AddProgressHandler(ByVal sender As Object, ByVal e As AddProgressEventArgs) + Select Case e.EventType + Case ZipProgressEventType.Adding_Started + Console.WriteLine("Adding files to the zip...") + Exit Select + Case ZipProgressEventType.Adding_AfterAddEntry + Console.WriteLine(String.Format("Adding file {0}", e.CurrentEntry.FileName)) + Exit Select + Case ZipProgressEventType.Adding_Completed + Console.WriteLine("Added all files") + Exit Select + End Select + End Sub + + Sub CreateTheZip() + Using zip as ZipFile = New ZipFile + AddHandler zip.AddProgress, AddressOf AddProgressHandler + zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)) + zip.Save(ZipFileToCreate); + End Using + End Sub + + + + + + + + + + + + An event that is raised when an error occurs during open or read of files + while saving a zip archive. + + + + + Errors can occur as a file is being saved to the zip archive. For + example, the File.Open may fail, or a File.Read may fail, because of + lock conflicts or other reasons. If you add a handler to this event, + you can handle such errors in your own code. If you don't add a + handler, the library will throw an exception if it encounters an I/O + error during a call to Save(). + + + + Setting a handler implicitly sets to + ZipErrorAction.InvokeErrorEvent. + + + + The handler you add applies to all items that are + subsequently added to the ZipFile instance. If you set this + property after you have added items to the ZipFile, but before you + have called Save(), errors that occur while saving those items + will not cause the error handler to be invoked. + + + + If you want to handle any errors that occur with any entry in the zip + file using the same error handler, then add your error handler once, + before adding any entries to the zip archive. + + + + In the error handler method, you need to set the property on the + ZipErrorEventArgs.CurrentEntry. This communicates back to + DotNetZip what you would like to do with this particular error. Within + an error handler, if you set the ZipEntry.ZipErrorAction property + on the ZipEntry to ZipErrorAction.InvokeErrorEvent or if + you don't set it at all, the library will throw the exception. (It is the + same as if you had set the ZipEntry.ZipErrorAction property on the + ZipEntry to ZipErrorAction.Throw.) If you set the + ZipErrorEventArgs.Cancel to true, the entire Save() will be + canceled. + + + + In the case that you use ZipErrorAction.Skip, implying that + you want to skip the entry for which there's been an error, DotNetZip + tries to seek backwards in the output stream, and truncate all bytes + written on behalf of that particular entry. This works only if the + output stream is seekable. It will not work, for example, when using + ASPNET's Response.OutputStream. + + + + + + + This example shows how to use an event handler to handle + errors during save of the zip file. + + + public static void MyZipError(object sender, ZipErrorEventArgs e) + { + Console.WriteLine("Error saving {0}...", e.FileName); + Console.WriteLine(" Exception: {0}", e.exception); + ZipEntry entry = e.CurrentEntry; + string response = null; + // Ask the user whether he wants to skip this error or not + do + { + Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) "); + response = Console.ReadLine(); + Console.WriteLine(); + + } while (response != null && + response[0]!='S' && response[0]!='s' && + response[0]!='R' && response[0]!='r' && + response[0]!='T' && response[0]!='t' && + response[0]!='C' && response[0]!='c'); + + e.Cancel = (response[0]=='C' || response[0]=='c'); + + if (response[0]=='S' || response[0]=='s') + entry.ZipErrorAction = ZipErrorAction.Skip; + else if (response[0]=='R' || response[0]=='r') + entry.ZipErrorAction = ZipErrorAction.Retry; + else if (response[0]=='T' || response[0]=='t') + entry.ZipErrorAction = ZipErrorAction.Throw; + } + + public void SaveTheFile() + { + string directoryToZip = "fodder"; + string directoryInArchive = "files"; + string zipFileToCreate = "Archive.zip"; + using (var zip = new ZipFile()) + { + // set the event handler before adding any entries + zip.ZipError += MyZipError; + zip.AddDirectory(directoryToZip, directoryInArchive); + zip.Save(zipFileToCreate); + } + } + + + + Private Sub MyZipError(ByVal sender As Object, ByVal e As Ionic.Zip.ZipErrorEventArgs) + ' At this point, the application could prompt the user for an action to take. + ' But in this case, this application will simply automatically skip the file, in case of error. + Console.WriteLine("Zip Error, entry {0}", e.CurrentEntry.FileName) + Console.WriteLine(" Exception: {0}", e.exception) + ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip + e.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip + End Sub + + Public Sub SaveTheFile() + Dim directoryToZip As String = "fodder" + Dim directoryInArchive As String = "files" + Dim zipFileToCreate as String = "Archive.zip" + Using zipArchive As ZipFile = New ZipFile + ' set the event handler before adding any entries + AddHandler zipArchive.ZipError, AddressOf MyZipError + zipArchive.AddDirectory(directoryToZip, directoryInArchive) + zipArchive.Save(zipFileToCreate) + End Using + End Sub + + + + + + + + + Options for using ZIP64 extensions when saving zip archives. + + + + + + Designed many years ago, the original zip + specification from PKWARE allowed for 32-bit quantities for the + compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity + for specifying the length of the zip archive itself, and a maximum of 65535 + entries. These limits are now regularly exceeded in many backup and archival + scenarios. Recently, PKWare added extensions to the original zip spec, called + "ZIP64 extensions", to raise those limitations. This property governs whether + DotNetZip will use those extensions when writing zip archives. The use of + these extensions is optional and explicit in DotNetZip because, despite the + status of ZIP64 as a bona fide standard, many other zip tools and libraries do + not support ZIP64, and therefore a zip file with ZIP64 extensions may be + unreadable by some of those other tools. + + + + Set this property to to always use ZIP64 + extensions when saving, regardless of whether your zip archive needs it. + Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always + for this flag, you will get a ZIP64 archive, though the archive does not need + to use ZIP64 because none of the original zip limits had been exceeded. + + + + Set this property to to tell the DotNetZip + library to never use ZIP64 extensions. This is useful for maximum + compatibility and interoperability, at the expense of the capability of + handling large files or large archives. NB: Windows Explorer in Windows XP + and Windows Vista cannot currently extract files from a zip64 archive, so if + you want to guarantee that a zip archive produced by this library will work in + Windows Explorer, use Never. If you set this property to , and your application creates a zip that would + exceed one of the Zip limits, the library will throw an exception while saving + the zip file. + + + + Set this property to to tell the + DotNetZip library to use the ZIP64 extensions when required by the + entry. After the file is compressed, the original and compressed sizes are + checked, and if they exceed the limits described above, then zip64 can be + used. That is the general idea, but there is an additional wrinkle when saving + to a non-seekable device, like the ASP.NET Response.OutputStream, or + Console.Out. When using non-seekable streams for output, the entry + header - which indicates whether zip64 is in use - is emitted before it is + known if zip64 is necessary. It is only after all entries have been saved + that it can be known if ZIP64 will be required. On seekable output streams, + after saving all entries, the library can seek backward and re-emit the zip + file header to be consistent with the actual ZIP64 requirement. But using a + non-seekable output stream, the library cannot seek backward, so the header + can never be changed. In other words, the archive's use of ZIP64 extensions is + not alterable after the header is emitted. Therefore, when saving to + non-seekable streams, using is the same + as using : it will always produce a zip + archive that uses ZIP64 extensions. + + + + + + + The default behavior, which is "Never". + (For COM clients, this is a 0 (zero).) + + + + + Do not use ZIP64 extensions when writing zip archives. + (For COM clients, this is a 0 (zero).) + + + + + Use ZIP64 extensions when writing zip archives, as necessary. + For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole + exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive. + (For COM clients, this is a 1.) + + + + + Always use ZIP64 extensions when writing zip archives, even when unnecessary. + (For COM clients, this is a 2.) + + + + + An enum representing the values on a three-way toggle switch + for various options in the library. This might be used to + specify whether to employ a particular text encoding, or to use + ZIP64 extensions, or some other option. + + + + + The default behavior. This is the same as "Never". + (For COM clients, this is a 0 (zero).) + + + + + Never use the associated option. + (For COM clients, this is a 0 (zero).) + + + + + Use the associated behavior "as necessary." + (For COM clients, this is a 1.) + + + + + Use the associated behavior Always, whether necessary or not. + (For COM clients, this is a 2.) + + + + + A class for collecting the various options that can be used when + Reading zip files for extraction or update. + + + + + When reading a zip file, there are several options an + application can set, to modify how the file is read, or what + the library does while reading. This class collects those + options into one container. + + + + Pass an instance of the ReadOptions class into the + ZipFile.Read() method. + + + . + . + + + + + An event handler for Read operations. When opening large zip + archives, you may want to display a progress bar or other + indicator of status progress while reading. This parameter + allows you to specify a ReadProgress Event Handler directly. + When you call Read(), the progress event is invoked as + necessary. + + + + + The System.IO.TextWriter to use for writing verbose status messages + during operations on the zip archive. A console application may wish to + pass System.Console.Out to get messages on the Console. A graphical + or headless application may wish to capture the messages in a different + TextWriter, such as a System.IO.StringWriter. + + + + + The System.Text.Encoding to use when reading in the zip archive. Be + careful specifying the encoding. If the value you use here is not the same + as the Encoding used when the zip archive was created (possibly by a + different archiver) you will get unexpected results and possibly exceptions. + + + + + + + + An enum that provides the different self-extractor flavors + + + + + A self-extracting zip archive that runs from the console or + command line. + + + + + A self-extracting zip archive that presents a graphical user + interface when it is executed. + + + + + The options for generating a self-extracting archive. + + + + + The type of SFX to create. + + + + + The command to run after extraction. + + + + + This is optional. Leave it empty (null in C# or Nothing in + VB) to run no command after extraction. + + + + If it is non-empty, the SFX will execute the command specified in this + string on the user's machine, and using the extract directory as the + working directory for the process, after unpacking the archive. The + program to execute can include a path, if you like. If you want to execute + a program that accepts arguments, specify the program name, followed by a + space, and then the arguments for the program, each separated by a space, + just as you would on a normal command line. Example: program.exe arg1 + arg2. The string prior to the first space will be taken as the + program name, and the string following the first space specifies the + arguments to the program. + + + + If you want to execute a program that has a space in the name or path of + the file, surround the program name in double-quotes. The first character + of the command line should be a double-quote character, and there must be + a matching double-quote following the end of the program file name. Any + optional arguments to the program follow that, separated by + spaces. Example: "c:\project files\program name.exe" arg1 arg2. + + + + If the flavor of the SFX is SelfExtractorFlavor.ConsoleApplication, + then the SFX starts a new process, using this string as the post-extract + command line. The SFX waits for the process to exit. The exit code of + the post-extract command line is returned as the exit code of the + command-line self-extractor exe. A non-zero exit code is typically used to + indicated a failure by the program. In the case of an SFX, a non-zero exit + code may indicate a failure during extraction, OR, it may indicate a + failure of the run-after-extract program if specified, OR, it may indicate + the run-after-extract program could not be fuond. There is no way to + distinguish these conditions from the calling shell, aside from parsing + the output of the SFX. If you have Quiet set to true, you may not + see error messages, if a problem occurs. + + + + If the flavor of the SFX is + SelfExtractorFlavor.WinFormsApplication, then the SFX starts a new + process, using this string as the post-extract command line, and using the + extract directory as the working directory for the process. The SFX does + not wait for the command to complete, and does not check the exit code of + the program. If the run-after-extract program cannot be fuond, a message + box is displayed indicating that fact. + + + + You can specify environment variables within this string, with a format like + %NAME%. The value of these variables will be expanded at the time + the SFX is run. Example: %WINDIR%\system32\xcopy.exe may expand at + runtime to c:\Windows\System32\xcopy.exe. + + + + By combining this with the RemoveUnpackedFilesAfterExecute + flag, you can create an SFX that extracts itself, runs a file that + was extracted, then deletes all the files that were extracted. If + you want it to run "invisibly" then set Flavor to + SelfExtractorFlavor.ConsoleApplication, and set Quiet + to true. The user running such an EXE will see a console window + appear, then disappear quickly. You may also want to specify the + default extract location, with DefaultExtractDirectory. + + + + If you set Flavor to + SelfExtractorFlavor.WinFormsApplication, and set Quiet to + true, then a GUI with progressbars is displayed, but it is + "non-interactive" - it accepts no input from the user. Instead the SFX + just automatically unpacks and exits. + + + + + + + The default extract directory the user will see when + running the self-extracting archive. + + + + + Passing null (or Nothing in VB) here will cause the Self Extractor to use + the the user's personal directory () for the default extract + location. + + + + This is only a default location. The actual extract location will be + settable on the command line when the SFX is executed. + + + + You can specify environment variables within this string, + with %NAME%. The value of these variables will be + expanded at the time the SFX is run. Example: + %USERPROFILE%\Documents\unpack may expand at runtime to + c:\users\melvin\Documents\unpack. + + + + + + The name of an .ico file in the filesystem to use for the application icon + for the generated SFX. + + + + + Normally, DotNetZip will embed an "zipped folder" icon into the generated + SFX. If you prefer to use a different icon, you can specify it here. It + should be a .ico file. This file is passed as the /win32icon + option to the csc.exe compiler when constructing the SFX file. + + + + + + + Whether the ConsoleApplication SFX will be quiet during extraction. + + + + + This option affects the way the generated SFX runs. By default it is + false. When you set it to true,... + + + + + Flavor + Behavior + + + + ConsoleApplication + no messages will be emitted during successful + operation. Double-clicking the SFX in Windows + Explorer or as an attachment in an email will cause a console + window to appear briefly, before it disappears. If you run the + ConsoleApplication SFX from the cmd.exe prompt, it runs as a + normal console app; by default, because it is quiet, it displays + no messages to the console. If you pass the -v+ command line + argument to the Console SFX when you run it, you will get verbose + messages to the console. + + + + + WinFormsApplication + the SFX extracts automatically when the application + is launched, with no additional user input. + + + + + + + When you set it to false,... + + + + + Flavor + Behavior + + + + ConsoleApplication + the extractor will emit a + message to the console for each entry extracted. + + When double-clicking to launch the SFX, the console window will + remain, and the SFX will emit a message for each file as it + extracts. The messages fly by quickly, they won't be easily + readable, unless the extracted files are fairly large. + + + + + + WinFormsApplication + the SFX presents a forms UI and allows the user to select + options before extracting. + + + + + + + + + + Specify what the self-extractor will do when extracting an entry + would overwrite an existing file. + + + + The default behavvior is to Throw. + + + + + + Whether to remove the files that have been unpacked, after executing the + PostExtractCommandLine. + + + + + If true, and if there is a + PostExtractCommandLine, and if the command runs successfully, + then the files that the SFX unpacked will be removed, afterwards. If + the command does not complete successfully (non-zero return code), + that is interpreted as a failure, and the extracted files will not be + removed. + + + + Setting this flag, and setting Flavor to + SelfExtractorFlavor.ConsoleApplication, and setting Quiet to + true, results in an SFX that extracts itself, runs a file that was + extracted, then deletes all the files that were extracted, with no + intervention by the user. You may also want to specify the default + extract location, with DefaultExtractDirectory. + + + + + + + The file version number to embed into the generated EXE. It will show up, for + example, during a mouseover in Windows Explorer. + + + + + + The product version to embed into the generated EXE. It will show up, for + example, during a mouseover in Windows Explorer. + + + + You can use any arbitrary string, but a human-readable version number is + recommended. For example "v1.2 alpha" or "v4.2 RC2". If you specify nothing, + then there is no product version embedded into the EXE. + + + + + + The copyright notice, if any, to embed into the generated EXE. + + + + It will show up, for example, while viewing properties of the file in + Windows Explorer. You can use any arbitrary string, but typically you + want something like "Copyright © Dino Chiesa 2011". + + + + + + The description to embed into the generated EXE. + + + + Use any arbitrary string. This text will be displayed during a + mouseover in Windows Explorer. If you specify nothing, then the string + "DotNetZip SFX Archive" is embedded into the EXE as the description. + + + + + + The product name to embed into the generated EXE. + + + + Use any arbitrary string. This text will be displayed + while viewing properties of the EXE file in + Windows Explorer. + + + + + + The title to display in the Window of a GUI SFX, while it extracts. + + + + + By default the title show in the GUI window of a self-extractor + is "DotNetZip Self-extractor (http://DotNetZip.codeplex.com/)". + You can change that by setting this property before saving the SFX. + + + + This property has an effect only when producing a Self-extractor + of flavor SelfExtractorFlavor.WinFormsApplication. + + + + + + + Additional options for the csc.exe compiler, when producing the SFX + EXE. + + + + + + Reset the BitWriter. + + + + This is useful when the BitWriter writes into a MemoryStream, and + is used by a BZip2Compressor, which itself is re-used for multiple + distinct data blocks. + + + + + + Write some number of bits from the given value, into the output. + + + + The nbits value should be a max of 25, for safety. For performance + reasons, this method does not check! + + + + + + Write a full 8-bit byte into the output. + + + + + Write four 8-bit bytes into the output. + + + + + Write all available byte-aligned bytes. + + + + This method writes no new output, but flushes any accumulated + bits. At completion, the accumulator may contain up to 7 + bits. + + + This is necessary when re-assembling output from N independent + compressors, one for each of N blocks. The output of any + particular compressor will in general have some fragment of a byte + remaining. This fragment needs to be accumulated into the + parent BZip2OutputStream. + + + + + + Writes all available bytes, and emits padding for the final byte as + necessary. This must be the last method invoked on an instance of + BitWriter. + + + + + Delivers the remaining bits, left-aligned, in a byte. + + + + This is valid only if NumRemainingBits is less than 8; + in other words it is valid only after a call to Flush(). + + + + + Knuth's increments seem to work better than Incerpi-Sedgewick here. + Possibly because the number of elems to sort is usually small, typically + <= 20. + + + + BZip2Compressor writes its compressed data out via a BitWriter. This + is necessary because BZip2 does byte shredding. + + + + + Accept new bytes into the compressor data buffer + + + + This method does the first-level (cheap) run-length encoding, and + stores the encoded data into the rle block. + + + + + + Process one input byte into the block. + + + + + To "process" the byte means to do the run-length encoding. + There are 3 possible return values: + + 0 - the byte was not written, in other words, not + encoded into the block. This happens when the + byte b would require the start of a new run, and + the block has no more room for new runs. + + 1 - the byte was written, and the block is not full. + + 2 - the byte was written, and the block is full. + + + + 0 if the byte was not written, non-zero if written. + + + + Append one run to the output block. + + + + + This compressor does run-length-encoding before BWT and etc. This + method simply appends a run to the output block. The append always + succeeds. The return value indicates whether the block is full: + false (not full) implies that at least one additional run could be + processed. + + + true if the block is now full; otherwise false. + + + + Compress the data that has been placed (Run-length-encoded) into the + block. The compressed data goes into the CompressedBytes array. + + + + Side effects: 1. fills the CompressedBytes array. 2. sets the + AvailableBytesOut property. + + + + + This is the most hammered method of this class. + +

+ This is the version using unrolled loops. +

+
+ + Method "mainQSort3", file "blocksort.c", BZip2 1.0.2 + + + + The number of uncompressed bytes being held in the buffer. + + + + I am thinking this may be useful in a Stream that uses this + compressor class. In the Close() method on the stream it could + check this value to see if anything has been written at all. You + may think the stream could easily track the number of bytes it + wrote, which would eliminate the need for this. But, there is the + case where the stream writes a complete block, and it is full, and + then writes no more. In that case the stream may want to check. + + + + + Array instance identical to sfmap, both are used only + temporarily and independently, so we do not need to allocate + additional memory. + + + + A read-only decorator stream that performs BZip2 decompression on Read. + + + + + Create a BZip2InputStream, wrapping it around the given input Stream. + + + + The input stream will be closed when the BZip2InputStream is closed. + + + The stream from which to read compressed data + + + + Create a BZip2InputStream with the given stream, and + specifying whether to leave the wrapped stream open when + the BZip2InputStream is closed. + + The stream from which to read compressed data + + Whether to leave the input stream open, when the BZip2InputStream closes. + + + + + This example reads a bzip2-compressed file, decompresses it, + and writes the decompressed data into a newly created file. + + + var fname = "logfile.log.bz2"; + using (var fs = File.OpenRead(fname)) + { + using (var decompressor = new Ionic.BZip2.BZip2InputStream(fs)) + { + var outFname = fname + ".decompressed"; + using (var output = File.Create(outFname)) + { + byte[] buffer = new byte[2048]; + int n; + while ((n = decompressor.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, n); + } + } + } + } + + + + + + Read data from the stream. + + + + + To decompress a BZip2 data stream, create a BZip2InputStream, + providing a stream that reads compressed data. Then call Read() on + that BZip2InputStream, and the data read will be decompressed + as you read. + + + + A BZip2InputStream can be used only for Read(), not for Write(). + + + + The buffer into which the read data should be placed. + the offset within that data array to put the first byte read. + the number of bytes to read. + the number of bytes actually read + + + + Read a single byte from the stream. + + the byte read from the stream, or -1 if EOF + + + + Flush the stream. + + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Calling this method always throws a . + + this parameter is never used + this parameter is never used + this parameter is never used + + + + Dispose the stream. + + + indicates whether the Dispose method was invoked by user code. + + + + + Close the stream. + + + + + Read n bits from input, right justifying the result. + + + + For example, if you read 1 bit, the result is either 0 + or 1. + + + + The number of bits to read, always between 1 and 32. + + + + Called by createHuffmanDecodingTables() exclusively. + + + Called by recvDecodingTables() exclusively. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the + total number of uncompressed bytes read in. + + + + + Compressor State + + + + Freq table collected to save a pass over the data during + decompression. + + + Initializes the tt array. + + This method is called when the required length of the array is known. + I don't initialize it at construction time to avoid unneccessary + memory allocation when compressing small files. + + + + A write-only decorator stream that compresses data as it is + written using the BZip2 algorithm. + + + + + Constructs a new BZip2OutputStream, that sends its + compressed output to the given output stream. + + + + The destination stream, to which compressed output will be sent. + + + + + This example reads a file, then compresses it with bzip2 file, + and writes the compressed data into a newly created file. + + + var fname = "logfile.log"; + using (var fs = File.OpenRead(fname)) + { + var outFname = fname + ".bz2"; + using (var output = File.Create(outFname)) + { + using (var compressor = new Ionic.BZip2.BZip2OutputStream(output)) + { + byte[] buffer = new byte[2048]; + int n; + while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + + + Constructs a new BZip2OutputStream with specified blocksize. + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + + + Constructs a new BZip2OutputStream. + + the destination stream. + + whether to leave the captive stream open upon closing this stream. + + + + + Constructs a new BZip2OutputStream with specified blocksize, + and explicitly specifies whether to leave the wrapped stream open. + + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + whether to leave the captive stream open upon closing this stream. + + + + + Close the stream. + + + + This may or may not close the underlying stream. Check the + constructors that accept a bool value. + + + + + + Flush the stream. + + + + + Write data to the stream. + + + + + Use the BZip2OutputStream to compress data while writing: + create a BZip2OutputStream with a writable output stream. + Then call Write() on that BZip2OutputStream, providing + uncompressed data as input. The data sent to the output stream will + be the compressed form of the input data. + + + + A BZip2OutputStream can be used only for Write() not for Read(). + + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Calling this method always throws a . + + this parameter is never used + this parameter is never used + this parameter is never used + never returns anything; always throws + + + + The blocksize parameter specified at construction time. + + + + + Indicates whether the stream can be read. + + + The return value is always false. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value should always be true, unless and until the + object is disposed and closed. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the + total number of uncompressed bytes written through. + + + + + A write-only decorator stream that compresses data as it is + written using the BZip2 algorithm. This stream compresses by + block using multiple threads. + + + This class performs BZIP2 compression through writing. For + more information on the BZIP2 algorithm, see + . + + + + This class is similar to , + except that this implementation uses an approach that employs multiple + worker threads to perform the compression. On a multi-cpu or multi-core + computer, the performance of this class can be significantly higher than + the single-threaded BZip2OutputStream, particularly for larger streams. + How large? Anything over 10mb is a good candidate for parallel + compression. + + + + The tradeoff is that this class uses more memory and more CPU than the + vanilla BZip2OutputStream. Also, for small files, the + ParallelBZip2OutputStream can be much slower than the vanilla + BZip2OutputStream, because of the overhead associated to using the + thread pool. + + + + + + + Constructs a new ParallelBZip2OutputStream, that sends its + compressed output to the given output stream. + + + + The destination stream, to which compressed output will be sent. + + + + + This example reads a file, then compresses it with bzip2 file, + and writes the compressed data into a newly created file. + + + var fname = "logfile.log"; + using (var fs = File.OpenRead(fname)) + { + var outFname = fname + ".bz2"; + using (var output = File.Create(outFname)) + { + using (var compressor = new Ionic.BZip2.ParallelBZip2OutputStream(output)) + { + byte[] buffer = new byte[2048]; + int n; + while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + + + Constructs a new ParallelBZip2OutputStream with specified blocksize. + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + + + Constructs a new ParallelBZip2OutputStream. + + the destination stream. + + whether to leave the captive stream open upon closing this stream. + + + + + Constructs a new ParallelBZip2OutputStream with specified blocksize, + and explicitly specifies whether to leave the wrapped stream open. + + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + whether to leave the captive stream open upon closing this stream. + + + + + Close the stream. + + + + This may or may not close the underlying stream. Check the + constructors that accept a bool value. + + + + + + Flush the stream. + + + + + Write data to the stream. + + + + + Use the ParallelBZip2OutputStream to compress data while + writing: create a ParallelBZip2OutputStream with a writable + output stream. Then call Write() on that + ParallelBZip2OutputStream, providing uncompressed data as + input. The data sent to the output stream will be the compressed + form of the input data. + + + + A ParallelBZip2OutputStream can be used only for + Write() not for Read(). + + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Calling this method always throws a . + + this parameter is never used + this parameter is never used + this parameter is never used + never returns anything; always throws + + + + The maximum number of concurrent compression worker threads to use. + + + + + This property sets an upper limit on the number of concurrent worker + threads to employ for compression. The implementation of this stream + employs multiple threads from the .NET thread pool, via + ThreadPool.QueueUserWorkItem(), to compress the incoming data by + block. As each block of data is compressed, this stream re-orders the + compressed blocks and writes them to the output stream. + + + + A higher number of workers enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + By default, DotNetZip allocates 4 workers per CPU core, subject to the + upper limit specified in this property. For example, suppose the + application sets this property to 16. Then, on a machine with 2 + cores, DotNetZip will use 8 workers; that number does not exceed the + upper limit specified by this property, so the actual number of + workers used will be 4 * 2 = 8. On a machine with 4 cores, DotNetZip + will use 16 workers; again, the limit does not apply. On a machine + with 8 cores, DotNetZip will use 16 workers, because of the limit. + + + + For each compression "worker thread" that occurs in parallel, there is + up to 2mb of memory allocated, for buffering and processing. The + actual number depends on the property. + + + + CPU utilization will also go up with additional workers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + The application can set this value at any time, but it is effective + only before the first call to Write(), which is when the buffers are + allocated. + + + + + + The blocksize parameter specified at construction time. + + + + + Indicates whether the stream can be read. + + + The return value is always false. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the + total number of uncompressed bytes written through. + + + + + The total number of bytes written out by the stream. + + + This value is meaningful only after a call to Close(). + + + + + Returns the "random" number at a specific index. + + the index + the random number + + + + A class for compressing and decompressing streams using the Deflate algorithm. + + + + + + The DeflateStream is a Decorator on a . It adds DEFLATE compression or decompression to any + stream. + + + + Using this stream, applications can compress or decompress data via stream + Read and Write operations. Either compresssion or decompression + can occur through either reading or writing. The compression format used is + DEFLATE, which is documented in IETF RFC 1951, "DEFLATE + Compressed Data Format Specification version 1.3.". + + + + This class is similar to , except that + ZlibStream adds the RFC + 1950 - ZLIB framing bytes to a compressed stream when compressing, or + expects the RFC1950 framing bytes when decompressing. The DeflateStream + does not. + + + + + + + + + + Create a DeflateStream using the specified CompressionMode. + + + + When mode is CompressionMode.Compress, the DeflateStream will use + the default compression level. The "captive" stream will be closed when + the DeflateStream is closed. + + + + This example uses a DeflateStream to compress data from a file, and writes + the compressed data to another file. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) + { + using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".deflated") + Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream which will be read or written. + Indicates whether the DeflateStream will compress or decompress. + + + + Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel. + + + + + + When mode is CompressionMode.Decompress, the level parameter is + ignored. The "captive" stream will be closed when the DeflateStream is + closed. + + + + + + + This example uses a DeflateStream to compress data from a file, and writes + the compressed data to another file. + + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) + { + using (Stream compressor = new DeflateStream(raw, + CompressionMode.Compress, + CompressionLevel.BestCompression)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n= -1; + while (n != 0) + { + if (n > 0) + compressor.Write(buffer, 0, n); + n= input.Read(buffer, 0, buffer.Length); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".deflated") + Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream to be read or written while deflating or inflating. + Indicates whether the DeflateStream will compress or decompress. + A tuning knob to trade speed for effectiveness. + + + + Create a DeflateStream using the specified + CompressionMode, and explicitly specify whether the + stream should be left open after Deflation or Inflation. + + + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + memory stream that will be re-read after compression. Specify true for + the parameter to leave the stream open. + + + + The DeflateStream will use the default compression level. + + + + See the other overloads of this constructor for example code. + + + + + The stream which will be read or written. This is called the + "captive" stream in other places in this documentation. + + + + Indicates whether the DeflateStream will compress or decompress. + + + true if the application would like the stream to + remain open after inflation/deflation. + + + + Create a DeflateStream using the specified CompressionMode + and the specified CompressionLevel, and explicitly specify whether + the stream should be left open after Deflation or Inflation. + + + + + + When mode is CompressionMode.Decompress, the level parameter is ignored. + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + that will be re-read after + compression. Specify true for the parameter + to leave the stream open. + + + + + + + This example shows how to use a DeflateStream to compress data from + a file, and store the compressed data into another file. + + + using (var output = System.IO.File.Create(fileToCompress + ".deflated")) + { + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n= -1; + while (n != 0) + { + if (n > 0) + compressor.Write(buffer, 0, n); + n= input.Read(buffer, 0, buffer.Length); + } + } + } + // can write additional data to the output stream here + } + + + + Using output As FileStream = File.Create(fileToCompress & ".deflated") + Using input As Stream = File.OpenRead(fileToCompress) + Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + ' can write additional data to the output stream here. + End Using + + + The stream which will be read or written. + Indicates whether the DeflateStream will compress or decompress. + true if the application would like the stream to remain open after inflation/deflation. + A tuning knob to trade speed for effectiveness. + + + + Dispose the stream. + + + + This may or may not result in a Close() call on the captive + stream. See the constructors that have a leaveOpen parameter + for more information. + + + Application code won't call this code directly. This method may be + invoked in two distinct scenarios. If disposing == true, the method + has been called directly or indirectly by a user's code, for example + via the public Dispose() method. In this case, both managed and + unmanaged resources can be referenced and disposed. If disposing == + false, the method has been called by the runtime from inside the + object finalizer and this method should not reference other objects; + in that case only unmanaged resources must be referenced or + disposed. + + + + true if the Dispose method was invoked by user code. + + + + + Flush the stream. + + + + + Read data from the stream. + + + + + If you wish to use the DeflateStream to compress data while + reading, you can create a DeflateStream with + CompressionMode.Compress, providing an uncompressed data stream. + Then call Read() on that DeflateStream, and the data read will be + compressed as you read. If you wish to use the DeflateStream to + decompress data while reading, you can create a DeflateStream with + CompressionMode.Decompress, providing a readable compressed data + stream. Then call Read() on that DeflateStream, and the data read + will be decompressed as you read. + + + + A DeflateStream can be used for Read() or Write(), but not both. + + + + The buffer into which the read data should be placed. + the offset within that data array to put the first byte read. + the number of bytes to read. + the number of bytes actually read + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Write data to the stream. + + + + + If you wish to use the DeflateStream to compress data while + writing, you can create a DeflateStream with + CompressionMode.Compress, and a writable output stream. Then call + Write() on that DeflateStream, providing uncompressed data + as input. The data sent to the output stream will be the compressed form + of the data written. If you wish to use the DeflateStream to + decompress data while writing, you can create a DeflateStream with + CompressionMode.Decompress, and a writable output stream. Then + call Write() on that stream, providing previously compressed + data. The data sent to the output stream will be the decompressed form of + the data written. + + + + A DeflateStream can be used for Read() or Write(), + but not both. + + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Compress a string into a byte array using DEFLATE (RFC 1951). + + + + Uncompress it with . + + + DeflateStream.UncompressString(byte[]) + DeflateStream.CompressBuffer(byte[]) + GZipStream.CompressString(string) + ZlibStream.CompressString(string) + + + A string to compress. The string will first be encoded + using UTF8, then compressed. + + + The string in compressed form + + + + Compress a byte array into a new byte array using DEFLATE. + + + + Uncompress it with . + + + DeflateStream.CompressString(string) + DeflateStream.UncompressBuffer(byte[]) + GZipStream.CompressBuffer(byte[]) + ZlibStream.CompressBuffer(byte[]) + + + A buffer to compress. + + + The data in compressed form + + + + Uncompress a DEFLATE'd byte array into a single string. + + + DeflateStream.CompressString(String) + DeflateStream.UncompressBuffer(byte[]) + GZipStream.UncompressString(byte[]) + ZlibStream.UncompressString(byte[]) + + + A buffer containing DEFLATE-compressed data. + + + The uncompressed string + + + + Uncompress a DEFLATE'd byte array into a byte array. + + + DeflateStream.CompressBuffer(byte[]) + DeflateStream.UncompressString(byte[]) + GZipStream.UncompressBuffer(byte[]) + ZlibStream.UncompressBuffer(byte[]) + + + A buffer containing data that has been compressed with DEFLATE. + + + The data in uncompressed form + + + + This property sets the flush behavior on the stream. + + See the ZLIB documentation for the meaning of the flush behavior. + + + + + The size of the working buffer for the compression codec. + + + + + The working buffer is used for all stream operations. The default size is + 1024 bytes. The minimum size is 128 bytes. You may get better performance + with a larger buffer. Then again, you might not. You would have to test + it. + + + + Set this before the first call to Read() or Write() on the + stream. If you try to set it afterwards, it will throw. + + + + + + The ZLIB strategy to be used during compression. + + + + By tweaking this parameter, you may be able to optimize the compression for + data with particular characteristics. + + + + Returns the total number of bytes input so far. + + + Returns the total number of bytes output so far. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the total bytes + written out, if used in writing, or the total bytes read in, if used in + reading. The count may refer to compressed bytes or uncompressed bytes, + depending on how you've used the stream. + + + + + A class for compressing and decompressing GZIP streams. + + + + + The GZipStream is a Decorator on a + . It adds GZIP compression or decompression to any + stream. + + + + Like the System.IO.Compression.GZipStream in the .NET Base Class Library, the + Ionic.Zlib.GZipStream can compress while writing, or decompress while + reading, but not vice versa. The compression method used is GZIP, which is + documented in IETF RFC + 1952, "GZIP file format specification version 4.3". + + + A GZipStream can be used to decompress data (through Read()) or + to compress data (through Write()), but not both. + + + + If you wish to use the GZipStream to compress data, you must wrap it + around a write-able stream. As you call Write() on the GZipStream, the + data will be compressed into the GZIP format. If you want to decompress data, + you must wrap the GZipStream around a readable stream that contains an + IETF RFC 1952-compliant stream. The data will be decompressed as you call + Read() on the GZipStream. + + + + Though the GZIP format allows data from multiple files to be concatenated + together, this stream handles only a single segment of GZIP format, typically + representing a single file. + + + + This class is similar to and . + ZlibStream handles RFC1950-compliant streams. + handles RFC1951-compliant streams. This class handles RFC1952-compliant streams. + + + + + + + + + + The last modified time for the GZIP stream. + + + + GZIP allows the storage of a last modified time with each GZIP entry. + When compressing data, you can set this before the first call to + Write(). When decompressing, you can retrieve this value any time + after the first call to Read(). + + + + + Create a GZipStream using the specified CompressionMode. + + + + + When mode is CompressionMode.Compress, the GZipStream will use the + default compression level. + + + + As noted in the class documentation, the CompressionMode (Compress + or Decompress) also establishes the "direction" of the stream. A + GZipStream with CompressionMode.Compress works only through + Write(). A GZipStream with + CompressionMode.Decompress works only through Read(). + + + + + + This example shows how to use a GZipStream to compress data. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(outputFile)) + { + using (Stream compressor = new GZipStream(raw, CompressionMode.Compress)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Dim outputFile As String = (fileToCompress & ".compressed") + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(outputFile) + Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + + + This example shows how to use a GZipStream to uncompress a file. + + private void GunZipFile(string filename) + { + if (!filename.EndsWith(".gz)) + throw new ArgumentException("filename"); + var DecompressedFile = filename.Substring(0,filename.Length-3); + byte[] working = new byte[WORKING_BUFFER_SIZE]; + int n= 1; + using (System.IO.Stream input = System.IO.File.OpenRead(filename)) + { + using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) + { + using (var output = System.IO.File.Create(DecompressedFile)) + { + while (n !=0) + { + n= decompressor.Read(working, 0, working.Length); + if (n > 0) + { + output.Write(working, 0, n); + } + } + } + } + } + } + + + + Private Sub GunZipFile(ByVal filename as String) + If Not (filename.EndsWith(".gz)) Then + Throw New ArgumentException("filename") + End If + Dim DecompressedFile as String = filename.Substring(0,filename.Length-3) + Dim working(WORKING_BUFFER_SIZE) as Byte + Dim n As Integer = 1 + Using input As Stream = File.OpenRead(filename) + Using decompressor As Stream = new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, True) + Using output As Stream = File.Create(UncompressedFile) + Do + n= decompressor.Read(working, 0, working.Length) + If n > 0 Then + output.Write(working, 0, n) + End IF + Loop While (n > 0) + End Using + End Using + End Using + End Sub + + + + The stream which will be read or written. + Indicates whether the GZipStream will compress or decompress. + + + + Create a GZipStream using the specified CompressionMode and + the specified CompressionLevel. + + + + + The CompressionMode (Compress or Decompress) also establishes the + "direction" of the stream. A GZipStream with + CompressionMode.Compress works only through Write(). A + GZipStream with CompressionMode.Decompress works only + through Read(). + + + + + + + This example shows how to use a GZipStream to compress a file into a .gz file. + + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".gz")) + { + using (Stream compressor = new GZipStream(raw, + CompressionMode.Compress, + CompressionLevel.BestCompression)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".gz") + Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream to be read or written while deflating or inflating. + Indicates whether the GZipStream will compress or decompress. + A tuning knob to trade speed for effectiveness. + + + + Create a GZipStream using the specified CompressionMode, and + explicitly specify whether the stream should be left open after Deflation + or Inflation. + + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + memory stream that will be re-read after compressed data has been written + to it. Specify true for the parameter to leave + the stream open. + + + + The (Compress or Decompress) also + establishes the "direction" of the stream. A GZipStream with + CompressionMode.Compress works only through Write(). A GZipStream + with CompressionMode.Decompress works only through Read(). + + + + The GZipStream will use the default compression level. If you want + to specify the compression level, see . + + + + See the other overloads of this constructor for example code. + + + + + + The stream which will be read or written. This is called the "captive" + stream in other places in this documentation. + + + Indicates whether the GZipStream will compress or decompress. + + + + true if the application would like the base stream to remain open after + inflation/deflation. + + + + + Create a GZipStream using the specified CompressionMode and the + specified CompressionLevel, and explicitly specify whether the + stream should be left open after Deflation or Inflation. + + + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + memory stream that will be re-read after compressed data has been written + to it. Specify true for the parameter to + leave the stream open. + + + + As noted in the class documentation, the CompressionMode (Compress + or Decompress) also establishes the "direction" of the stream. A + GZipStream with CompressionMode.Compress works only through + Write(). A GZipStream with CompressionMode.Decompress works only + through Read(). + + + + + + This example shows how to use a GZipStream to compress data. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(outputFile)) + { + using (Stream compressor = new GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Dim outputFile As String = (fileToCompress & ".compressed") + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(outputFile) + Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, True) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream which will be read or written. + Indicates whether the GZipStream will compress or decompress. + true if the application would like the stream to remain open after inflation/deflation. + A tuning knob to trade speed for effectiveness. + + + + Dispose the stream. + + + + This may or may not result in a Close() call on the captive + stream. See the constructors that have a leaveOpen parameter + for more information. + + + This method may be invoked in two distinct scenarios. If disposing + == true, the method has been called directly or indirectly by a + user's code, for example via the public Dispose() method. In this + case, both managed and unmanaged resources can be referenced and + disposed. If disposing == false, the method has been called by the + runtime from inside the object finalizer and this method should not + reference other objects; in that case only unmanaged resources must + be referenced or disposed. + + + + indicates whether the Dispose method was invoked by user code. + + + + + Flush the stream. + + + + + Read and decompress data from the source stream. + + + + With a GZipStream, decompression is done through reading. + + + + + byte[] working = new byte[WORKING_BUFFER_SIZE]; + using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) + { + using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) + { + using (var output = System.IO.File.Create(_DecompressedFile)) + { + int n; + while ((n= decompressor.Read(working, 0, working.Length)) !=0) + { + output.Write(working, 0, n); + } + } + } + } + + + The buffer into which the decompressed data should be placed. + the offset within that data array to put the first byte read. + the number of bytes to read. + the number of bytes actually read + + + + Calling this method always throws a . + + irrelevant; it will always throw! + irrelevant; it will always throw! + irrelevant! + + + + Calling this method always throws a . + + irrelevant; this method will always throw! + + + + Write data to the stream. + + + + + If you wish to use the GZipStream to compress data while writing, + you can create a GZipStream with CompressionMode.Compress, and a + writable output stream. Then call Write() on that GZipStream, + providing uncompressed data as input. The data sent to the output stream + will be the compressed form of the data written. + + + + A GZipStream can be used for Read() or Write(), but not + both. Writing implies compression. Reading implies decompression. + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Compress a string into a byte array using GZip. + + + + Uncompress it with . + + + + + + + A string to compress. The string will first be encoded + using UTF8, then compressed. + + + The string in compressed form + + + + Compress a byte array into a new byte array using GZip. + + + + Uncompress it with . + + + + + + + A buffer to compress. + + + The data in compressed form + + + + Uncompress a GZip'ed byte array into a single string. + + + + + + + A buffer containing GZIP-compressed data. + + + The uncompressed string + + + + Uncompress a GZip'ed byte array into a byte array. + + + + + + + A buffer containing data that has been compressed with GZip. + + + The data in uncompressed form + + + + The comment on the GZIP stream. + + + + + The GZIP format allows for each file to optionally have an associated + comment stored with the file. The comment is encoded with the ISO-8859-1 + code page. To include a comment in a GZIP stream you create, set this + property before calling Write() for the first time on the + GZipStream. + + + + When using GZipStream to decompress, you can retrieve this property + after the first call to Read(). If no comment has been set in the + GZIP bytestream, the Comment property will return null + (Nothing in VB). + + + + + + The FileName for the GZIP stream. + + + + + + The GZIP format optionally allows each file to have an associated + filename. When compressing data (through Write()), set this + FileName before calling Write() the first time on the GZipStream. + The actual filename is encoded into the GZIP bytestream with the + ISO-8859-1 code page, according to RFC 1952. It is the application's + responsibility to insure that the FileName can be encoded and decoded + correctly with this code page. + + + + When decompressing (through Read()), you can retrieve this value + any time after the first Read(). In the case where there was no filename + encoded into the GZIP bytestream, the property will return null (Nothing + in VB). + + + + + + The CRC on the GZIP stream. + + + This is used for internal error checking. You probably don't need to look at this property. + + + + + This property sets the flush behavior on the stream. + + + + + The size of the working buffer for the compression codec. + + + + + The working buffer is used for all stream operations. The default size is + 1024 bytes. The minimum size is 128 bytes. You may get better performance + with a larger buffer. Then again, you might not. You would have to test + it. + + + + Set this before the first call to Read() or Write() on the + stream. If you try to set it afterwards, it will throw. + + + + + Returns the total number of bytes input so far. + + + Returns the total number of bytes output so far. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the total bytes + written out, if used in writing, or the total bytes read in, if used in + reading. The count may refer to compressed bytes or uncompressed bytes, + depending on how you've used the stream. + + + + + A class for compressing streams using the + Deflate algorithm with multiple threads. + + + + + This class performs DEFLATE compression through writing. For + more information on the Deflate algorithm, see IETF RFC 1951, + "DEFLATE Compressed Data Format Specification version 1.3." + + + + This class is similar to , except + that this class is for compression only, and this implementation uses an + approach that employs multiple worker threads to perform the DEFLATE. On + a multi-cpu or multi-core computer, the performance of this class can be + significantly higher than the single-threaded DeflateStream, particularly + for larger streams. How large? Anything over 10mb is a good candidate + for parallel compression. + + + + The tradeoff is that this class uses more memory and more CPU than the + vanilla DeflateStream, and also is less efficient as a compressor. For + large files the size of the compressed data stream can be less than 1% + larger than the size of a compressed data stream from the vanialla + DeflateStream. For smaller files the difference can be larger. The + difference will also be larger if you set the BufferSize to be lower than + the default value. Your mileage may vary. Finally, for small files, the + ParallelDeflateOutputStream can be much slower than the vanilla + DeflateStream, because of the overhead associated to using the thread + pool. + + + + + + + + Create a ParallelDeflateOutputStream. + + + + + This stream compresses data written into it via the DEFLATE + algorithm (see RFC 1951), and writes out the compressed byte stream. + + + + The instance will use the default compression level, the default + buffer sizes and the default number of threads and buffers per + thread. + + + + This class is similar to , + except that this implementation uses an approach that employs + multiple worker threads to perform the DEFLATE. On a multi-cpu or + multi-core computer, the performance of this class can be + significantly higher than the single-threaded DeflateStream, + particularly for larger streams. How large? Anything over 10mb is + a good candidate for parallel compression. + + + + + + + This example shows how to use a ParallelDeflateOutputStream to compress + data. It reads a file, compresses it, and writes the compressed data to + a second, output file. + + + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n= -1; + String outputFile = fileToCompress + ".compressed"; + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(outputFile)) + { + using (Stream compressor = new ParallelDeflateOutputStream(raw)) + { + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Dim outputFile As String = (fileToCompress & ".compressed") + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(outputFile) + Using compressor As Stream = New ParallelDeflateOutputStream(raw) + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream to which compressed data will be written. + + + + Create a ParallelDeflateOutputStream using the specified CompressionLevel. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + A tuning knob to trade speed for effectiveness. + + + + Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open + when the ParallelDeflateOutputStream is closed. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + + true if the application would like the stream to remain open after inflation/deflation. + + + + + Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open + when the ParallelDeflateOutputStream is closed. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + A tuning knob to trade speed for effectiveness. + + true if the application would like the stream to remain open after inflation/deflation. + + + + + Create a ParallelDeflateOutputStream using the specified + CompressionLevel and CompressionStrategy, and specifying whether to + leave the captive stream open when the ParallelDeflateOutputStream is + closed. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + A tuning knob to trade speed for effectiveness. + + By tweaking this parameter, you may be able to optimize the compression for + data with particular characteristics. + + + true if the application would like the stream to remain open after inflation/deflation. + + + + + Write data to the stream. + + + + + + To use the ParallelDeflateOutputStream to compress data, create a + ParallelDeflateOutputStream with CompressionMode.Compress, passing a + writable output stream. Then call Write() on that + ParallelDeflateOutputStream, providing uncompressed data as input. The + data sent to the output stream will be the compressed form of the data + written. + + + + To decompress data, use the class. + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Flush the stream. + + + + + Close the stream. + + + You must call Close on the stream to guarantee that all of the data written in has + been compressed, and the compressed data has been written out. + + + + Dispose the object + + + Because ParallelDeflateOutputStream is IDisposable, the + application must call this method when finished using the instance. + + + This method is generally called implicitly upon exit from + a using scope in C# (Using in VB). + + + + + The Dispose method + + indicates whether the Dispose method was invoked by user code. + + + + + Resets the stream for use with another stream. + + + Because the ParallelDeflateOutputStream is expensive to create, it + has been designed so that it can be recycled and re-used. You have + to call Close() on the stream first, then you can call Reset() on + it, to use it again on another stream. + + + + The new output stream for this era. + + + + + ParallelDeflateOutputStream deflater = null; + foreach (var inputFile in listOfFiles) + { + string outputFile = inputFile + ".compressed"; + using (System.IO.Stream input = System.IO.File.OpenRead(inputFile)) + { + using (var outStream = System.IO.File.Create(outputFile)) + { + if (deflater == null) + deflater = new ParallelDeflateOutputStream(outStream, + CompressionLevel.Best, + CompressionStrategy.Default, + true); + deflater.Reset(outStream); + + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + deflater.Write(buffer, 0, n); + } + } + } + } + + + + + + This method always throws a NotSupportedException. + + + The buffer into which data would be read, IF THIS METHOD + ACTUALLY DID ANYTHING. + + + The offset within that data array at which to insert the + data that is read, IF THIS METHOD ACTUALLY DID + ANYTHING. + + + The number of bytes to write, IF THIS METHOD ACTUALLY DID + ANYTHING. + + nothing. + + + + This method always throws a NotSupportedException. + + + The offset to seek to.... + IF THIS METHOD ACTUALLY DID ANYTHING. + + + The reference specifying how to apply the offset.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + nothing. It always throws. + + + + This method always throws a NotSupportedException. + + + The new value for the stream length.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + + + + The ZLIB strategy to be used during compression. + + + + + + The maximum number of buffer pairs to use. + + + + + This property sets an upper limit on the number of memory buffer + pairs to create. The implementation of this stream allocates + multiple buffers to facilitate parallel compression. As each buffer + fills up, this stream uses + ThreadPool.QueueUserWorkItem() + to compress those buffers in a background threadpool thread. After a + buffer is compressed, it is re-ordered and written to the output + stream. + + + + A higher number of buffer pairs enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + For each compression "task" that occurs in parallel, there are 2 + buffers allocated: one for input and one for output. This property + sets a limit for the number of pairs. The total amount of storage + space allocated for buffering will then be (N*S*2), where N is the + number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer + pairs per CPU core, so if your machine has 4 cores, and you retain + the default buffer size of 128k, then the + ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer + memory in total, or 4mb, in blocks of 128kb. If you then set this + property to 8, then the number will be 8 * 2 * 128kb of buffer + memory, or 2mb. + + + + CPU utilization will also go up with additional buffers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + This property is not the number of buffer pairs to use; it is an + upper limit. An illustration: Suppose you have an application that + uses the default value of this property (which is 16), and it runs + on a machine with 2 CPU cores. In that case, DotNetZip will allocate + 4 buffer pairs per CPU core, for a total of 8 pairs. The upper + limit specified by this property has no effect. + + + + The application can set this value at any time, but it is effective + only before the first call to Write(), which is when the buffers are + allocated. + + + + + + The size of the buffers used by the compressor threads. + + + + + The default buffer size is 128k. The application can set this value + at any time, but it is effective only before the first Write(). + + + + Larger buffer sizes implies larger memory consumption but allows + more efficient compression. Using smaller buffer sizes consumes less + memory but may result in less effective compression. For example, + using the default buffer size of 128k, the compression delivered is + within 1% of the compression delivered by the single-threaded . On the other hand, using a + BufferSize of 8k can result in a compressed data stream that is 5% + larger than that delivered by the single-threaded + DeflateStream. Excessively small buffer sizes can also cause + the speed of the ParallelDeflateOutputStream to drop, because of + larger thread scheduling overhead dealing with many many small + buffers. + + + + The total amount of storage space allocated for buffering will be + (N*S*2), where N is the number of buffer pairs, and S is the size of + each buffer (this property). There are 2 buffers used by the + compressor, one for input and one for output. By default, DotNetZip + allocates 4 buffer pairs per CPU core, so if your machine has 4 + cores, then the number of buffer pairs used will be 16. If you + accept the default value of this property, 128k, then the + ParallelDeflateOutputStream will use 16 * 2 * 128kb of buffer memory + in total, or 4mb, in blocks of 128kb. If you set this property to + 64kb, then the number will be 16 * 2 * 64kb of buffer memory, or + 2mb. + + + + + + + The CRC32 for the data that was written out, prior to compression. + + + This value is meaningful only after a call to Close(). + + + + + The total number of uncompressed bytes processed by the ParallelDeflateOutputStream. + + + This value is meaningful only after a call to Close(). + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream supports Read operations. + + + Always returns false. + + + + + Indicates whether the stream supports Write operations. + + + Returns true if the provided stream is writable. + + + + + Reading this property always throws a NotSupportedException. + + + + + Returns the current position of the output stream. + + + + Because the output gets written by a background thread, + the value may change asynchronously. Setting this + property always throws a NotSupportedException. + + + + + + Map from a distance to a distance code. + + + No side effects. _dist_code[256] and _dist_code[257] are never used. + + + + + Describes how to flush the current deflate operation. + + + The different FlushType values are useful when using a Deflate in a streaming application. + + + + No flush at all. + + + Closes the current block, but doesn't flush it to + the output. Used internally only in hypothetical + scenarios. This was supposed to be removed by Zlib, but it is + still in use in some edge cases. + + + + + Use this during compression to specify that all pending output should be + flushed to the output buffer and the output should be aligned on a byte + boundary. You might use this in a streaming communication scenario, so that + the decompressor can get all input data available so far. When using this + with a ZlibCodec, AvailableBytesIn will be zero after the call if + enough output space has been provided before the call. Flushing will + degrade compression and so it should be used only when necessary. + + + + + Use this during compression to specify that all output should be flushed, as + with FlushType.Sync, but also, the compression state should be reset + so that decompression can restart from this point if previous compressed + data has been damaged or if random access is desired. Using + FlushType.Full too often can significantly degrade the compression. + + + + Signals the end of the compression/decompression stream. + + + + The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. + + + + + None means that the data will be simply stored, with no change at all. + If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None + cannot be opened with the default zip reader. Use a different CompressionLevel. + + + + + Same as None. + + + + + The fastest but least effective compression. + + + + + A synonym for BestSpeed. + + + + + A little slower, but better, than level 1. + + + + + A little slower, but better, than level 2. + + + + + A little slower, but better, than level 3. + + + + + A little slower than level 4, but with better compression. + + + + + The default compression level, with a good balance of speed and compression efficiency. + + + + + A synonym for Default. + + + + + Pretty good compression! + + + + + Better compression than Level7! + + + + + The "best" compression, where best means greatest reduction in size of the input data stream. + This is also the slowest compression. + + + + + A synonym for BestCompression. + + + + + Describes options for how the compression algorithm is executed. Different strategies + work better on different sorts of data. The strategy parameter can affect the compression + ratio and the speed of compression but not the correctness of the compresssion. + + + + + The default strategy is probably the best for normal data. + + + + + The Filtered strategy is intended to be used most effectively with data produced by a + filter or predictor. By this definition, filtered data consists mostly of small + values with a somewhat random distribution. In this case, the compression algorithm + is tuned to compress them better. The effect of Filtered is to force more Huffman + coding and less string matching; it is a half-step between Default and HuffmanOnly. + + + + + Using HuffmanOnly will force the compressor to do Huffman encoding only, with no + string matching. + + + + + An enum to specify the direction of transcoding - whether to compress or decompress. + + + + + Used to specify that the stream should compress the data. + + + + + Used to specify that the stream should decompress the data. + + + + + A general purpose exception class for exceptions in the Zlib library. + + + + + The ZlibException class captures exception information generated + by the Zlib library. + + + + + This ctor collects a message attached to the exception. + + the message for the exception. + + + + Performs an unsigned bitwise right shift with the specified number + + Number to operate on + Ammount of bits to shift + The resulting number from the shift operation + + + + Reads a number of characters from the current source TextReader and writes + the data to the target array at the specified index. + + + The source TextReader to read from + Contains the array of characteres read from the source TextReader. + The starting index of the target array. + The maximum number of characters to read from the source TextReader. + + + The number of characters read. The number will be less than or equal to + count depending on the data available in the source TextReader. Returns -1 + if the end of the stream is reached. + + + + + Computes an Adler-32 checksum. + + + The Adler checksum is similar to a CRC checksum, but faster to compute, though less + reliable. It is used in producing RFC1950 compressed streams. The Adler checksum + is a required part of the "ZLIB" standard. Applications will almost never need to + use this class directly. + + + + + + + Calculates the Adler32 checksum. + + + + This is used within ZLIB. You probably don't need to use this directly. + + + + To compute an Adler32 checksum on a byte array: + + var adler = Adler.Adler32(0, null, 0, 0); + adler = Adler.Adler32(adler, buffer, index, length); + + + + + + Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). + + + + This class compresses and decompresses data according to the Deflate algorithm + and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. + + + + + The buffer from which data is taken. + + + + + An index into the InputBuffer array, indicating where to start reading. + + + + + The number of bytes available in the InputBuffer, starting at NextIn. + + + Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. + The class will update this number as calls to Inflate/Deflate are made. + + + + + Total number of bytes read so far, through all calls to Inflate()/Deflate(). + + + + + Buffer to store output data. + + + + + An index into the OutputBuffer array, indicating where to start writing. + + + + + The number of bytes available in the OutputBuffer, starting at NextOut. + + + Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. + The class will update this number as calls to Inflate/Deflate are made. + + + + + Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). + + + + + used for diagnostics, when something goes wrong! + + + + + The compression level to use in this codec. Useful only in compression mode. + + + + + The number of Window Bits to use. + + + This gauges the size of the sliding window, and hence the + compression effectiveness as well as memory consumption. It's best to just leave this + setting alone if you don't know what it is. The maximum value is 15 bits, which implies + a 32k window. + + + + + The compression strategy to use. + + + This is only effective in compression. The theory offered by ZLIB is that different + strategies could potentially produce significant differences in compression behavior + for different data sets. Unfortunately I don't have any good recommendations for how + to set it differently. When I tested changing the strategy I got minimally different + compression performance. It's best to leave this property alone if you don't have a + good feel for it. Or, you may want to produce a test harness that runs through the + different strategy options and evaluates them on different file types. If you do that, + let me know your results. + + + + + Create a ZlibCodec. + + + If you use this default constructor, you will later have to explicitly call + InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress + or decompress. + + + + + Create a ZlibCodec that either compresses or decompresses. + + + Indicates whether the codec should compress (deflate) or decompress (inflate). + + + + + Initialize the inflation state. + + + It is not necessary to call this before using the ZlibCodec to inflate data; + It is implicitly called when you call the constructor. + + Z_OK if everything goes well. + + + + Initialize the inflation state with an explicit flag to + govern the handling of RFC1950 header bytes. + + + + By default, the ZLIB header defined in RFC 1950 is expected. If + you want to read a zlib stream you should specify true for + expectRfc1950Header. If you have a deflate stream, you will want to specify + false. It is only necessary to invoke this initializer explicitly if you + want to specify false. + + + whether to expect an RFC1950 header byte + pair when reading the stream of data to be inflated. + + Z_OK if everything goes well. + + + + Initialize the ZlibCodec for inflation, with the specified number of window bits. + + The number of window bits to use. If you need to ask what that is, + then you shouldn't be calling this initializer. + Z_OK if all goes well. + + + + Initialize the inflation state with an explicit flag to govern the handling of + RFC1950 header bytes. + + + + If you want to read a zlib stream you should specify true for + expectRfc1950Header. In this case, the library will expect to find a ZLIB + header, as defined in RFC + 1950, in the compressed stream. If you will be reading a DEFLATE or + GZIP stream, which does not have such a header, you will want to specify + false. + + + whether to expect an RFC1950 header byte pair when reading + the stream of data to be inflated. + The number of window bits to use. If you need to ask what that is, + then you shouldn't be calling this initializer. + Z_OK if everything goes well. + + + + Inflate the data in the InputBuffer, placing the result in the OutputBuffer. + + + You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and + AvailableBytesOut before calling this method. + + + + private void InflateBuffer() + { + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + ZlibCodec decompressor = new ZlibCodec(); + + Console.WriteLine("\n============================================"); + Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); + MemoryStream ms = new MemoryStream(DecompressedBytes); + + int rc = decompressor.InitializeInflate(); + + decompressor.InputBuffer = CompressedBytes; + decompressor.NextIn = 0; + decompressor.AvailableBytesIn = CompressedBytes.Length; + + decompressor.OutputBuffer = buffer; + + // pass 1: inflate + do + { + decompressor.NextOut = 0; + decompressor.AvailableBytesOut = buffer.Length; + rc = decompressor.Inflate(FlushType.None); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new Exception("inflating: " + decompressor.Message); + + ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); + } + while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + + // pass 2: finish and flush + do + { + decompressor.NextOut = 0; + decompressor.AvailableBytesOut = buffer.Length; + rc = decompressor.Inflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + throw new Exception("inflating: " + decompressor.Message); + + if (buffer.Length - decompressor.AvailableBytesOut > 0) + ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); + } + while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + + decompressor.EndInflate(); + } + + + + The flush to use when inflating. + Z_OK if everything goes well. + + + + Ends an inflation session. + + + Call this after successively calling Inflate(). This will cause all buffers to be flushed. + After calling this you cannot call Inflate() without a intervening call to one of the + InitializeInflate() overloads. + + Z_OK if everything goes well. + + + + I don't know what this does! + + Z_OK if everything goes well. + + + + Initialize the ZlibCodec for deflation operation. + + + The codec will use the MAX window bits and the default level of compression. + + + + int bufferSize = 40000; + byte[] CompressedBytes = new byte[bufferSize]; + byte[] DecompressedBytes = new byte[bufferSize]; + + ZlibCodec compressor = new ZlibCodec(); + + compressor.InitializeDeflate(CompressionLevel.Default); + + compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); + compressor.NextIn = 0; + compressor.AvailableBytesIn = compressor.InputBuffer.Length; + + compressor.OutputBuffer = CompressedBytes; + compressor.NextOut = 0; + compressor.AvailableBytesOut = CompressedBytes.Length; + + while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) + { + compressor.Deflate(FlushType.None); + } + + while (true) + { + int rc= compressor.Deflate(FlushType.Finish); + if (rc == ZlibConstants.Z_STREAM_END) break; + } + + compressor.EndDeflate(); + + + + Z_OK if all goes well. You generally don't need to check the return code. + + + + Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. + + + The codec will use the maximum window bits (15) and the specified + CompressionLevel. It will emit a ZLIB stream as it compresses. + + The compression level for the codec. + Z_OK if all goes well. + + + + Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + and the explicit flag governing whether to emit an RFC1950 header byte pair. + + + The codec will use the maximum window bits (15) and the specified CompressionLevel. + If you want to generate a zlib stream, you should specify true for + wantRfc1950Header. In this case, the library will emit a ZLIB + header, as defined in RFC + 1950, in the compressed stream. + + The compression level for the codec. + whether to emit an initial RFC1950 byte pair in the compressed stream. + Z_OK if all goes well. + + + + Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + and the specified number of window bits. + + + The codec will use the specified number of window bits and the specified CompressionLevel. + + The compression level for the codec. + the number of window bits to use. If you don't know what this means, don't use this method. + Z_OK if all goes well. + + + + Initialize the ZlibCodec for deflation operation, using the specified + CompressionLevel, the specified number of window bits, and the explicit flag + governing whether to emit an RFC1950 header byte pair. + + + The compression level for the codec. + whether to emit an initial RFC1950 byte pair in the compressed stream. + the number of window bits to use. If you don't know what this means, don't use this method. + Z_OK if all goes well. + + + + Deflate one batch of data. + + + You must have set InputBuffer and OutputBuffer before calling this method. + + + + private void DeflateBuffer(CompressionLevel level) + { + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + ZlibCodec compressor = new ZlibCodec(); + + Console.WriteLine("\n============================================"); + Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); + MemoryStream ms = new MemoryStream(); + + int rc = compressor.InitializeDeflate(level); + + compressor.InputBuffer = UncompressedBytes; + compressor.NextIn = 0; + compressor.AvailableBytesIn = UncompressedBytes.Length; + + compressor.OutputBuffer = buffer; + + // pass 1: deflate + do + { + compressor.NextOut = 0; + compressor.AvailableBytesOut = buffer.Length; + rc = compressor.Deflate(FlushType.None); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new Exception("deflating: " + compressor.Message); + + ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); + } + while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + + // pass 2: finish and flush + do + { + compressor.NextOut = 0; + compressor.AvailableBytesOut = buffer.Length; + rc = compressor.Deflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + throw new Exception("deflating: " + compressor.Message); + + if (buffer.Length - compressor.AvailableBytesOut > 0) + ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); + } + while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + + compressor.EndDeflate(); + + ms.Seek(0, SeekOrigin.Begin); + CompressedBytes = new byte[compressor.TotalBytesOut]; + ms.Read(CompressedBytes, 0, CompressedBytes.Length); + } + + + whether to flush all data as you deflate. Generally you will want to + use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to + flush everything. + + Z_OK if all goes well. + + + + End a deflation session. + + + Call this after making a series of one or more calls to Deflate(). All buffers are flushed. + + Z_OK if all goes well. + + + + Reset a codec for another deflation session. + + + Call this to reset the deflation state. For example if a thread is deflating + non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first + block and before the next Deflate(None) of the second block. + + Z_OK if all goes well. + + + + Set the CompressionStrategy and CompressionLevel for a deflation session. + + the level of compression to use. + the strategy to use for compression. + Z_OK if all goes well. + + + + Set the dictionary to be used for either Inflation or Deflation. + + The dictionary bytes to use. + Z_OK if all goes well. + + + + The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. + + + + + A bunch of constants used in the Zlib interface. + + + + + The maximum number of window bits for the Deflate algorithm. + + + + + The default number of window bits for the Deflate algorithm. + + + + + indicates everything is A-OK + + + + + Indicates that the last operation reached the end of the stream. + + + + + The operation ended in need of a dictionary. + + + + + There was an error with the stream - not enough data, not open and readable, etc. + + + + + There was an error with the data - not enough data, bad data, etc. + + + + + There was an error with the working buffer. + + + + + The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. + + + + + The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. + + + + + Represents a Zlib stream for compression or decompression. + + + + + The ZlibStream is a Decorator on a . It adds ZLIB compression or decompression to any + stream. + + + Using this stream, applications can compress or decompress data via + stream Read() and Write() operations. Either compresssion or + decompression can occur through either reading or writing. The compression + format used is ZLIB, which is documented in IETF RFC 1950, "ZLIB Compressed + Data Format Specification version 3.3". This implementation of ZLIB always uses + DEFLATE as the compression method. (see IETF RFC 1951, "DEFLATE + Compressed Data Format Specification version 1.3.") + + + The ZLIB format allows for varying compression methods, window sizes, and dictionaries. + This implementation always uses the DEFLATE compression method, a preset dictionary, + and 15 window bits by default. + + + + This class is similar to , except that it adds the + RFC1950 header and trailer bytes to a compressed stream when compressing, or expects + the RFC1950 header and trailer bytes when decompressing. It is also similar to the + . + + + + + + + + Create a ZlibStream using the specified CompressionMode. + + + + + When mode is CompressionMode.Compress, the ZlibStream + will use the default compression level. The "captive" stream will be + closed when the ZlibStream is closed. + + + + + + This example uses a ZlibStream to compress a file, and writes the + compressed data to another file. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) + { + using (Stream compressor = new ZlibStream(raw, CompressionMode.Compress)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".zlib") + Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + + The stream which will be read or written. + Indicates whether the ZlibStream will compress or decompress. + + + + Create a ZlibStream using the specified CompressionMode and + the specified CompressionLevel. + + + + + + When mode is CompressionMode.Decompress, the level parameter is ignored. + The "captive" stream will be closed when the ZlibStream is closed. + + + + + + This example uses a ZlibStream to compress data from a file, and writes the + compressed data to another file. + + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) + { + using (Stream compressor = new ZlibStream(raw, + CompressionMode.Compress, + CompressionLevel.BestCompression)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".zlib") + Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + + The stream to be read or written while deflating or inflating. + Indicates whether the ZlibStream will compress or decompress. + A tuning knob to trade speed for effectiveness. + + + + Create a ZlibStream using the specified CompressionMode, and + explicitly specify whether the captive stream should be left open after + Deflation or Inflation. + + + + + + When mode is CompressionMode.Compress, the ZlibStream will use + the default compression level. + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + that will be re-read after + compression. Specify true for the parameter to leave the stream + open. + + + + See the other overloads of this constructor for example code. + + + + + The stream which will be read or written. This is called the + "captive" stream in other places in this documentation. + Indicates whether the ZlibStream will compress or decompress. + true if the application would like the stream to remain + open after inflation/deflation. + + + + Create a ZlibStream using the specified CompressionMode + and the specified CompressionLevel, and explicitly specify + whether the stream should be left open after Deflation or Inflation. + + + + + + This constructor allows the application to request that the captive + stream remain open after the deflation or inflation occurs. By + default, after Close() is called on the stream, the captive + stream is also closed. In some cases this is not desired, for example + if the stream is a that will be + re-read after compression. Specify true for the parameter to leave the stream open. + + + + When mode is CompressionMode.Decompress, the level parameter is + ignored. + + + + + + + This example shows how to use a ZlibStream to compress the data from a file, + and store the result into another file. The filestream remains open to allow + additional data to be written to it. + + + using (var output = System.IO.File.Create(fileToCompress + ".zlib")) + { + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (Stream compressor = new ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + // can write additional data to the output stream here + } + + + Using output As FileStream = File.Create(fileToCompress & ".zlib") + Using input As Stream = File.OpenRead(fileToCompress) + Using compressor As Stream = New ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + ' can write additional data to the output stream here. + End Using + + + + The stream which will be read or written. + + Indicates whether the ZlibStream will compress or decompress. + + + true if the application would like the stream to remain open after + inflation/deflation. + + + + A tuning knob to trade speed for effectiveness. This parameter is + effective only when mode is CompressionMode.Compress. + + + + + Dispose the stream. + + + + This may or may not result in a Close() call on the captive + stream. See the constructors that have a leaveOpen parameter + for more information. + + + This method may be invoked in two distinct scenarios. If disposing + == true, the method has been called directly or indirectly by a + user's code, for example via the public Dispose() method. In this + case, both managed and unmanaged resources can be referenced and + disposed. If disposing == false, the method has been called by the + runtime from inside the object finalizer and this method should not + reference other objects; in that case only unmanaged resources must + be referenced or disposed. + + + + indicates whether the Dispose method was invoked by user code. + + + + + Flush the stream. + + + + + Read data from the stream. + + + + + + If you wish to use the ZlibStream to compress data while reading, + you can create a ZlibStream with CompressionMode.Compress, + providing an uncompressed data stream. Then call Read() on that + ZlibStream, and the data read will be compressed. If you wish to + use the ZlibStream to decompress data while reading, you can create + a ZlibStream with CompressionMode.Decompress, providing a + readable compressed data stream. Then call Read() on that + ZlibStream, and the data will be decompressed as it is read. + + + + A ZlibStream can be used for Read() or Write(), but + not both. + + + + + + The buffer into which the read data should be placed. + + + the offset within that data array to put the first byte read. + + the number of bytes to read. + + the number of bytes read + + + + Calling this method always throws a . + + + The offset to seek to.... + IF THIS METHOD ACTUALLY DID ANYTHING. + + + The reference specifying how to apply the offset.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + + nothing. This method always throws. + + + + Calling this method always throws a . + + + The new value for the stream length.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + + + + Write data to the stream. + + + + + + If you wish to use the ZlibStream to compress data while writing, + you can create a ZlibStream with CompressionMode.Compress, + and a writable output stream. Then call Write() on that + ZlibStream, providing uncompressed data as input. The data sent to + the output stream will be the compressed form of the data written. If you + wish to use the ZlibStream to decompress data while writing, you + can create a ZlibStream with CompressionMode.Decompress, and a + writable output stream. Then call Write() on that stream, + providing previously compressed data. The data sent to the output stream + will be the decompressed form of the data written. + + + + A ZlibStream can be used for Read() or Write(), but not both. + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Compress a string into a byte array using ZLIB. + + + + Uncompress it with . + + + + + + + + A string to compress. The string will first be encoded + using UTF8, then compressed. + + + The string in compressed form + + + + Compress a byte array into a new byte array using ZLIB. + + + + Uncompress it with . + + + + + + + A buffer to compress. + + + The data in compressed form + + + + Uncompress a ZLIB-compressed byte array into a single string. + + + + + + + A buffer containing ZLIB-compressed data. + + + The uncompressed string + + + + Uncompress a ZLIB-compressed byte array into a byte array. + + + + + + + A buffer containing ZLIB-compressed data. + + + The data in uncompressed form + + + + This property sets the flush behavior on the stream. + Sorry, though, not sure exactly how to describe all the various settings. + + + + + The size of the working buffer for the compression codec. + + + + + The working buffer is used for all stream operations. The default size is + 1024 bytes. The minimum size is 128 bytes. You may get better performance + with a larger buffer. Then again, you might not. You would have to test + it. + + + + Set this before the first call to Read() or Write() on the + stream. If you try to set it afterwards, it will throw. + + + + + Returns the total number of bytes input so far. + + + Returns the total number of bytes output so far. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the total bytes + written out, if used in writing, or the total bytes read in, if used in + reading. The count may refer to compressed bytes or uncompressed bytes, + depending on how you've used the stream. + + + + + Computes a CRC-32. The CRC-32 algorithm is parameterized - you + can set the polynomial and enable or disable bit + reversal. This can be used for GZIP, BZip2, or ZIP. + + + This type is used internally by DotNetZip; it is generally not used + directly by applications wishing to create, read, or manipulate zip + archive files. + + + + + Returns the CRC32 for the specified stream. + + The stream over which to calculate the CRC32 + the CRC32 calculation + + + + Returns the CRC32 for the specified stream, and writes the input into the + output stream. + + The stream over which to calculate the CRC32 + The stream into which to deflate the input + the CRC32 calculation + + + + Get the CRC32 for the given (word,byte) combo. This is a + computation defined by PKzip for PKZIP 2.0 (weak) encryption. + + The word to start with. + The byte to combine it with. + The CRC-ized result. + + + + Update the value for the running CRC32 using the given block of bytes. + This is useful when using the CRC32() class in a Stream. + + block of bytes to slurp + starting point in the block + how many bytes within the block to slurp + + + + Process one byte in the CRC. + + the byte to include into the CRC . + + + + Process a run of N identical bytes into the CRC. + + + + This method serves as an optimization for updating the CRC when a + run of identical bytes is found. Rather than passing in a buffer of + length n, containing all identical bytes b, this method accepts the + byte value and the length of the (virtual) buffer - the length of + the run. + + + the byte to include into the CRC. + the number of times that byte should be repeated. + + + + Combines the given CRC32 value with the current running total. + + + This is useful when using a divide-and-conquer approach to + calculating a CRC. Multiple threads can each calculate a + CRC32 on a segment of the data, and then combine the + individual CRC32 values at the end. + + the crc value to be combined with this one + the length of data the CRC value was calculated on + + + + Create an instance of the CRC32 class using the default settings: no + bit reversal, and a polynomial of 0xEDB88320. + + + + + Create an instance of the CRC32 class, specifying whether to reverse + data bits or not. + + + specify true if the instance should reverse data bits. + + + + In the CRC-32 used by BZip2, the bits are reversed. Therefore if you + want a CRC32 with compatibility with BZip2, you should pass true + here. In the CRC-32 used by GZIP and PKZIP, the bits are not + reversed; Therefore if you want a CRC32 with compatibility with + those, you should pass false. + + + + + + Create an instance of the CRC32 class, specifying the polynomial and + whether to reverse data bits or not. + + + The polynomial to use for the CRC, expressed in the reversed (LSB) + format: the highest ordered bit in the polynomial value is the + coefficient of the 0th power; the second-highest order bit is the + coefficient of the 1 power, and so on. Expressed this way, the + polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320. + + + specify true if the instance should reverse data bits. + + + + + In the CRC-32 used by BZip2, the bits are reversed. Therefore if you + want a CRC32 with compatibility with BZip2, you should pass true + here for the reverseBits parameter. In the CRC-32 used by + GZIP and PKZIP, the bits are not reversed; Therefore if you want a + CRC32 with compatibility with those, you should pass false for the + reverseBits parameter. + + + + + + Reset the CRC-32 class - clear the CRC "remainder register." + + + + Use this when employing a single instance of this class to compute + multiple, distinct CRCs on multiple, distinct data blocks. + + + + + + Indicates the total number of bytes applied to the CRC. + + + + + Indicates the current CRC for all blocks slurped in. + + + + + A Stream that calculates a CRC32 (a checksum) on all bytes read, + or on all bytes written. + + + + + This class can be used to verify the CRC of a ZipEntry when + reading from a stream, or to calculate a CRC when writing to a + stream. The stream should be used to either read, or write, but + not both. If you intermix reads and writes, the results are not + defined. + + + + This class is intended primarily for use internally by the + DotNetZip library. + + + + + + The default constructor. + + + + Instances returned from this constructor will leave the underlying + stream open upon Close(). The stream uses the default CRC32 + algorithm, which implies a polynomial of 0xEDB88320. + + + The underlying stream + + + + The constructor allows the caller to specify how to handle the + underlying stream at close. + + + + The stream uses the default CRC32 algorithm, which implies a + polynomial of 0xEDB88320. + + + The underlying stream + true to leave the underlying stream + open upon close of the CrcCalculatorStream; false otherwise. + + + + A constructor allowing the specification of the length of the stream + to read. + + + + The stream uses the default CRC32 algorithm, which implies a + polynomial of 0xEDB88320. + + + Instances returned from this constructor will leave the underlying + stream open upon Close(). + + + The underlying stream + The length of the stream to slurp + + + + A constructor allowing the specification of the length of the stream + to read, as well as whether to keep the underlying stream open upon + Close(). + + + + The stream uses the default CRC32 algorithm, which implies a + polynomial of 0xEDB88320. + + + The underlying stream + The length of the stream to slurp + true to leave the underlying stream + open upon close of the CrcCalculatorStream; false otherwise. + + + + A constructor allowing the specification of the length of the stream + to read, as well as whether to keep the underlying stream open upon + Close(), and the CRC32 instance to use. + + + + The stream uses the specified CRC32 instance, which allows the + application to specify how the CRC gets calculated. + + + The underlying stream + The length of the stream to slurp + true to leave the underlying stream + open upon close of the CrcCalculatorStream; false otherwise. + the CRC32 instance to use to calculate the CRC32 + + + + Read from the stream + + the buffer to read + the offset at which to start + the number of bytes to read + the number of bytes actually read + + + + Write to the stream. + + the buffer from which to write + the offset at which to start writing + the number of bytes to write + + + + Flush the stream. + + + + + Seeking is not supported on this stream. This method always throws + + + N/A + N/A + N/A + + + + This method always throws + + + N/A + + + + Closes the stream. + + + + + Gets the total number of bytes run through the CRC32 calculator. + + + + This is either the total number of bytes read, or the total number of + bytes written, depending on the direction of this stream. + + + + + Provides the current CRC for all blocks slurped in. + + + + The running total of the CRC is kept as data is written or read + through the stream. read this property after all reads or writes to + get an accurate CRC for the entire stream. + + + + + + Indicates whether the underlying stream will be left open when the + CrcCalculatorStream is Closed. + + + + Set this at any point before calling . + + + + + + Indicates whether the stream supports reading. + + + + + Indicates whether the stream supports seeking. + + + + Always returns false. + + + + + + Indicates whether the stream supports writing. + + + + + Returns the length of the underlying stream. + + + + + The getter for this property returns the total bytes read. + If you use the setter, it will throw + . + + +
+
diff --git a/RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs b/RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs new file mode 100644 index 0000000..374b746 --- /dev/null +++ b/RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs @@ -0,0 +1,497 @@ +// -- FILE ------------------------------------------------------------------ +// name : RtfInterpreter.cs +// project : RTF Framelet +// created : Leon Poyyayil - 2008.05.20 +// language : c# +// environment: .NET 2.0 +// copyright : (c) 2004-2008 by Itenso GmbH, Switzerland +// -------------------------------------------------------------------------- +using System; +using Itenso.Rtf.Model; +using Itenso.Rtf.Support; + +namespace Itenso.Rtf.Interpreter +{ + + // ------------------------------------------------------------------------ + public sealed class RtfInterpreter : RtfInterpreterBase, IRtfElementVisitor + { + + // ---------------------------------------------------------------------- + public RtfInterpreter( params IRtfInterpreterListener[] listeners ) + : base( listeners ) + { + this.fontTableBuilder = new RtfFontTableBuilder( Context.WritableFontTable ); + this.colorTableBuilder = new RtfColorTableBuilder( Context.WritableColorTable ); + this.documentInfoBuilder = new RtfDocumentInfoBuilder( Context.WritableDocumentInfo ); + this.userPropertyBuilder = new RtfUserPropertyBuilder( Context.WritableUserProperties ); + this.imageBuilder = new RtfImageBuilder(); + } // RtfInterpreter + + // ---------------------------------------------------------------------- + public bool IsSupportedDocument( IRtfGroup rtfDocument ) + { + try + { + GetSupportedDocument( rtfDocument ); + } + catch ( RtfException ) + { + return false; + } + return true; + } // IsSupportedDocument + + // ---------------------------------------------------------------------- + public IRtfGroup GetSupportedDocument( IRtfGroup rtfDocument ) + { + if ( rtfDocument == null ) + { + throw new RtfException( "document is null" ); + } + if ( rtfDocument.Contents.Count == 0 ) + { + throw new RtfException( "document has not contents" ); + } + IRtfElement firstElement = rtfDocument.Contents[ 0 ]; + if ( firstElement.Kind != RtfElementKind.Tag ) + { + throw new RtfException( "first element in document is not a tag" ); + } + IRtfTag firstTag = (IRtfTag)firstElement; + if ( !RtfSpec.TagRtf.Equals( firstTag.Name ) ) + { + throw new RtfException( "first tag in document is not " + RtfSpec.TagRtf ); + } + if ( !firstTag.HasValue ) + { + throw new RtfException( "unspecified RTF version" ); + } + if ( firstTag.ValueAsNumber != RtfSpec.RtfVersion1 ) + { + throw new RtfException( "unsupported RTF version: " + firstTag.ValueAsText ); + } + return rtfDocument; + } // GetSupportedDocument + + // ---------------------------------------------------------------------- + protected override void DoInterpret( IRtfGroup rtfDocument ) + { + InterpretContents( GetSupportedDocument( rtfDocument ) ); + } // DoInterpret + + // ---------------------------------------------------------------------- + private void InterpretContents( IRtfGroup rtfDocument ) + { + // by getting here we already know that the given document is supported, and hence + // we know it has version 1 + Context.Reset(); // clears all previous content and sets the version to 1 + NotifyBeginDocument(); + VisitChildrenOf( rtfDocument ); + Context.State = RtfInterpreterState.Ended; + NotifyEndDocument(); + } // InterpretContents + + // ---------------------------------------------------------------------- + private void VisitChildrenOf( IRtfGroup group ) + { + bool pushedTextFormat = false; + if ( Context.State == RtfInterpreterState.InDocument ) + { + Context.PushCurrentTextFormat(); + pushedTextFormat = true; + } + try + { + foreach ( IRtfElement child in group.Contents ) + { + child.Visit( this ); + } + } + finally + { + if ( pushedTextFormat ) + { + Context.PopCurrentTextFormat(); + } + } + } // VisitChildrenOf + + // ---------------------------------------------------------------------- + void IRtfElementVisitor.VisitTag( IRtfTag tag ) + { + if ( Context.State != RtfInterpreterState.InDocument ) + { + if ( Context.FontTable.Count > 0 ) + { + // somewhat of a hack to detect state change from header to in-document for + // rtf-docs which do neither have a generator group nor encapsulate the + // actual document content in a group. + if ( Context.ColorTable.Count > 0 || RtfSpec.TagViewKind.Equals( tag.Name ) ) + { + Context.State = RtfInterpreterState.InDocument; + } + } + } + + switch ( Context.State ) + { + case RtfInterpreterState.Init: + if ( RtfSpec.TagRtf.Equals( tag.Name ) ) + { + Context.State = RtfInterpreterState.InHeader; + Context.RtfVersion = tag.ValueAsNumber; + } + else + { + throw new RtfException( "Init: illegal state for tag '" + tag + "'" ); + } + break; + case RtfInterpreterState.InHeader: + switch ( tag.Name ) + { + case RtfSpec.TagDefaultFont: + Context.DefaultFontId = RtfSpec.TagFont + tag.ValueAsNumber.ToString(); + break; + } + break; + case RtfInterpreterState.InDocument: + switch ( tag.Name ) + { + case RtfSpec.TagPlain: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveNormal(); + break; + case RtfSpec.TagParagraphDefaults: + case RtfSpec.TagSectionDefaults: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Left ); + break; + case RtfSpec.TagBold: + bool bold = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithBold( bold ); + break; + case RtfSpec.TagItalic: + bool italic = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithItalic( italic ); + break; + case RtfSpec.TagUnderLine: + bool underline = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithUnderline( underline ); + break; + case RtfSpec.TagUnderLineNone: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithUnderline( false ); + break; + case RtfSpec.TagStrikeThrough: + bool strikeThrough = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithStrikeThrough( strikeThrough ); + break; + case RtfSpec.TagHidden: + bool hidden = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithHidden( hidden ); + break; + case RtfSpec.TagFont: + string fontId = tag.FullName; + if ( Context.FontTable.ContainsFontWithId( fontId ) ) + { + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithFont( + Context.FontTable[ fontId ] ); + } + else + { + throw new RtfException( "undefined font: " + fontId ); + } + break; + case RtfSpec.TagFontSize: + int fontSize = tag.ValueAsNumber; + if ( fontSize > 0 ) + { + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithFontSize( fontSize ); + } + else + { + throw new RtfException( "invalid font size: " + fontSize ); + } + break; + case RtfSpec.TagFontSubscript: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( false ); + break; + case RtfSpec.TagFontSuperscript: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( true ); + break; + case RtfSpec.TagFontNoSuperSub: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( 0 ); + break; + case RtfSpec.TagFontDown: + int moveDown = tag.ValueAsNumber; + if ( moveDown == -1 ) + { + moveDown = 6; // the default value according to rtf spec + } + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( -moveDown ); + break; + case RtfSpec.TagFontUp: + int moveUp = tag.ValueAsNumber; + if ( moveUp == -1 ) + { + moveUp = 6; // the default value according to rtf spec + } + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( moveUp ); + break; + case RtfSpec.TagAlignLeft: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Left ); + break; + case RtfSpec.TagAlignCenter: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Center ); + break; + case RtfSpec.TagAlignRight: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Right ); + break; + case RtfSpec.TagAlignJustify: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Justify ); + break; + case RtfSpec.TagColorBackground: + case RtfSpec.TagColorBackgroundWord: + case RtfSpec.TagColorForeground: + int colorIndex = tag.ValueAsNumber; + if ( colorIndex >= 0 && colorIndex < Context.ColorTable.Count ) + { + IRtfColor newColor = Context.ColorTable[ colorIndex ]; + bool isForeground = RtfSpec.TagColorForeground.Equals( tag.Name ); + Context.WritableCurrentTextFormat = isForeground ? + Context.WritableCurrentTextFormat.DeriveWithForegroundColor( newColor ) : + Context.WritableCurrentTextFormat.DeriveWithBackgroundColor( newColor ); + } + else + { + throw new RtfException( "undefined color index: " + colorIndex ); + } + break; + case RtfSpec.TagSection: + NotifyInsertBreak( RtfVisualBreakKind.Section ); + break; + case RtfSpec.TagParagraph: + NotifyInsertBreak( RtfVisualBreakKind.Paragraph ); + break; + case RtfSpec.TagLine: + NotifyInsertBreak( RtfVisualBreakKind.Line ); + break; + case RtfSpec.TagPage: + NotifyInsertBreak( RtfVisualBreakKind.Page ); + break; + case RtfSpec.TagTabulator: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.Tabulator ); + break; + case RtfSpec.TagTilde: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.NonBreakingSpace ); + break; + case RtfSpec.TagEmDash: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EmDash ); + break; + case RtfSpec.TagEnDash: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EnDash ); + break; + case RtfSpec.TagEmSpace: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EmSpace ); + break; + case RtfSpec.TagEnSpace: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EnSpace ); + break; + case RtfSpec.TagQmSpace: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.QmSpace ); + break; + case RtfSpec.TagBulltet: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.Bullet ); + break; + case RtfSpec.TagLeftSingleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.LeftSingleQuote ); + break; + case RtfSpec.TagRightSingleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.RightSingleQuote ); + break; + case RtfSpec.TagLeftDoubleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.LeftDoubleQuote ); + break; + case RtfSpec.TagRightDoubleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.RightDoubleQuote ); + break; + case RtfSpec.TagHyphen: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.OptionalHyphen ); + break; + case RtfSpec.TagUnderscore: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.NonBreakingHyphen ); + break; + } + break; + } + } // IRtfElementVisitor.VisitTag + + // ---------------------------------------------------------------------- + void IRtfElementVisitor.VisitGroup( IRtfGroup group ) + { + string groupDestination = group.Destination; + switch ( Context.State ) + { + case RtfInterpreterState.Init: + if ( RtfSpec.TagRtf.Equals( groupDestination ) ) + { + VisitChildrenOf( group ); + } + else + { + throw new RtfException( "Init: illegal state for group '" + groupDestination + "'" ); + } + break; + case RtfInterpreterState.InHeader: + switch ( groupDestination ) + { + case RtfSpec.TagFontTable: + this.fontTableBuilder.VisitGroup( group ); + break; + case RtfSpec.TagColorTable: + this.colorTableBuilder.VisitGroup( group ); + break; + case RtfSpec.TagGenerator: + // last group with a destination in header, but no need to process its contents + Context.State = RtfInterpreterState.InDocument; + IRtfText generator = group.Contents.Count == 3 ? group.Contents[ 2 ] as IRtfText : null; + if ( generator != null ) + { + string generatorName = generator.Text; + Context.Generator = generatorName.EndsWith( ";" ) ? + generatorName.Substring( 0, generatorName.Length - 1 ) : generatorName; + } + else + { + throw new RtfException( "invalid generator group: " + group ); + } + break; + case null: + // group without destination cannot be part of header, but need to process its contents + Context.State = RtfInterpreterState.InDocument; + if ( !group.IsExtensionDestination ) + { + VisitChildrenOf( group ); + } + break; + } + break; + case RtfInterpreterState.InDocument: + switch ( groupDestination ) + { + case RtfSpec.TagUserProperties: + this.userPropertyBuilder.VisitGroup( group ); + break; + case RtfSpec.TagInfo: + this.documentInfoBuilder.VisitGroup( group ); + break; + case RtfSpec.TagUnicodeAlternativeChoices: + IRtfGroup alternativeWithUnicodeSupport = + group.SelectChildGroupWithDestination( RtfSpec.TagUnicodeAlternativeUnicode ); + if ( alternativeWithUnicodeSupport != null ) + { + // there is an alternative with unicode formatted content -> use this + VisitChildrenOf( alternativeWithUnicodeSupport ); + } + else + { + // try to locate the alternative without unicode -> only ANSI fallbacks + IRtfGroup alternativeWithoutUnicode = // must be the third element if present + group.Contents.Count > 2 ? group.Contents[ 2 ] as IRtfGroup : null; + if ( alternativeWithoutUnicode != null ) + { + VisitChildrenOf( alternativeWithoutUnicode ); + } + } + break; + case RtfSpec.TagHeader: + case RtfSpec.TagHeaderFirst: + case RtfSpec.TagHeaderLeft: + case RtfSpec.TagHeaderRight: + case RtfSpec.TagFooter: + case RtfSpec.TagFooterFirst: + case RtfSpec.TagFooterLeft: + case RtfSpec.TagFooterRight: + case RtfSpec.TagFootnote: + case RtfSpec.TagStyleSheet: + // groups we currently ignore, so their content doesn't intermix with + // the actual document content + break; + case RtfSpec.TagPictureWrapper: + VisitChildrenOf( group ); + break; + case RtfSpec.TagPicture: + this.imageBuilder.VisitGroup( group ); + NotifyInsertImage( + this.imageBuilder.Format, + this.imageBuilder.Width, + this.imageBuilder.Height, + this.imageBuilder.DesiredWidth, + this.imageBuilder.DesiredHeight, + this.imageBuilder.ScaleWidthPercent, + this.imageBuilder.ScaleHeightPercent, + this.imageBuilder.ImageDataHex ); + break; + case RtfSpec.TagParagraphNumberText: + case RtfSpec.TagListNumberText: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.ParagraphNumberBegin ); + VisitChildrenOf( group ); + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.ParagraphNumberEnd ); + break; + default: + if ( !group.IsExtensionDestination ) + { + // nested text group + VisitChildrenOf( group ); + } + break; + } + break; + } + } // IRtfElementVisitor.VisitGroup + + // ---------------------------------------------------------------------- + void IRtfElementVisitor.VisitText( IRtfText text ) + { + switch ( Context.State ) + { + case RtfInterpreterState.Init: + throw new RtfException( "Init: illegal state for text '" + text.Text + "'" ); + case RtfInterpreterState.InHeader: + Context.State = RtfInterpreterState.InDocument; + break; + case RtfInterpreterState.InDocument: + break; + } + NotifyInsertText( text.Text ); + } // IRtfElementVisitor.VisitText + + // ---------------------------------------------------------------------- + // members + private readonly RtfFontTableBuilder fontTableBuilder; + private readonly RtfColorTableBuilder colorTableBuilder; + private readonly RtfDocumentInfoBuilder documentInfoBuilder; + private readonly RtfUserPropertyBuilder userPropertyBuilder; + private readonly RtfImageBuilder imageBuilder; + + } // class RtfInterpreter + +} // namespace Itenso.Rtf.Interpreter +// -- EOF ------------------------------------------------------------------- diff --git a/RtfConverter/Interpreter/Interpreter2005.csproj b/RtfConverter/Interpreter/Interpreter2005.csproj new file mode 100644 index 0000000..29b144e --- /dev/null +++ b/RtfConverter/Interpreter/Interpreter2005.csproj @@ -0,0 +1,133 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {2A49B537-AFDB-4541-8683-468F2A0BE0AE} + Library + Properties + Itenso.Rtf.Interpreter + Itenso.Rtf.Interpreter + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {6FA3F1A8-4E10-459C-A8DC-C40A90D627B0} + Parser2005 + + + {0F203536-FF4F-4783-992D-1DE210C3C485} + Sys2005 + + + + + \ No newline at end of file diff --git a/RtfConverter/Parser/Parser2005.csproj b/RtfConverter/Parser/Parser2005.csproj new file mode 100644 index 0000000..ce1af43 --- /dev/null +++ b/RtfConverter/Parser/Parser2005.csproj @@ -0,0 +1,79 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {6FA3F1A8-4E10-459C-A8DC-C40A90D627B0} + Library + Properties + Itenso.Rtf.Parser + Itenso.Rtf.Parser + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0F203536-FF4F-4783-992D-1DE210C3C485} + Sys2005 + + + + + \ No newline at end of file diff --git a/RtfConverter/bin/Debug/Itenso.Rtf.Interpreter.dll b/RtfConverter/bin/Debug/Itenso.Rtf.Interpreter.dll new file mode 100644 index 0000000..e77226a Binary files /dev/null and b/RtfConverter/bin/Debug/Itenso.Rtf.Interpreter.dll differ diff --git a/RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll b/RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll new file mode 100644 index 0000000..03e7f70 Binary files /dev/null and b/RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll differ diff --git a/iTechSharp/AssemblyInfo.cs b/iTechSharp/AssemblyInfo.cs new file mode 100644 index 0000000..b275404 --- /dev/null +++ b/iTechSharp/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("iTextSharp")] +[assembly: AssemblyDescription("A free PDF library ported from Java iText.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Copyright (C) 1999-2008 by Bruno Lowagie and Paulo Soares. All Rights Reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("4.1.2")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("..\\..\\itextsharp.snk")] +[assembly: AssemblyKeyName("")] diff --git a/iTechSharp/System/Drawing/Dimension.cs b/iTechSharp/System/Drawing/Dimension.cs new file mode 100644 index 0000000..5526d6f --- /dev/null +++ b/iTechSharp/System/Drawing/Dimension.cs @@ -0,0 +1,158 @@ +using System; + +namespace System.Drawing { + /// + /// The Dimension class encapsulates the width and + /// height of a component (in int precision) in a single object. + /// + /// + /// The class is + /// associated with certain properties of components. Several methods + /// defined by the Component class and the + /// LayoutManager interface return a Dimension object. + ///

+ /// Normally the values of width + /// and height are non-negative ints. + /// The constructors that allow you to create a dimension do + /// not prevent you from setting a negative value for these properties. + /// If the value of width or height is + /// negative, the behavior of some methods defined by other objects is + /// undefined. + /// + public class Dimension : Dimension2D { + + ///

+ /// The width dimension. Negative values can be used. + /// + public int width; + + /// + /// The height dimension. Negative values can be used. + /// + public int height; + + /// + /// Creates an instance of Dimension with a width + /// of zero and a height of zero. + /// + public Dimension() : this(0, 0) {} + + /// + /// Creates an instance of Dimension whose width + /// and height are the same as for the specified dimension. + /// + /// + /// the specified dimension for the + /// width and + /// height values. + /// + public Dimension(Dimension d) : this(d.width, d.height) {} + + /// + /// Constructs a Dimension and initializes it to the specified width and + /// specified height. + /// + /// the specified width dimension + /// the specified height dimension + public Dimension(int width, int height) { + this.width = width; + this.height = height; + } + + /// + /// Returns the width of this dimension in double precision. + /// + /// the width + public override double Width { + get { + return width; + } + } + + /// + /// Returns the height of this dimension in double precision. + /// + /// the height + public override double Height { + get { + return height; + } + } + + /// + /// Set the size of this Dimension object to the specified width + /// and height in double precision. + /// + /// the new width for the Dimension object + /// the new height for the Dimension object + public override void SetSize(double width, double height) { + width = (int) Math.Ceiling(width); + height = (int) Math.Ceiling(height); + } + + /// + /// Get/set the size of this Dimension object. + /// + /// the size + public new Dimension Size { + get { + return new Dimension(width, height); + } + + set { + SetSize(value.width, value.height); + } + } + + /// + /// Set the size of this Dimension object + /// to the specified width and height. + /// + /// the new width for this Dimension object. + /// the new height for this Dimension object. + public void SetSize(int width, int height) { + this.width = width; + this.height = height; + } + + /// + /// Checks whether two dimension objects have equal values. + /// + /// + /// + public override bool Equals(Object obj) { + if (obj is Dimension) { + Dimension d = (Dimension)obj; + return (width == d.width) && (height == d.height); + } + return false; + } + + /// + /// Returns the hash code for this Dimension. + /// + /// a hash code + public override int GetHashCode() { + int sum = width + height; + return sum * (sum + 1)/2 + width; + } + + /// + /// Returns a string representation of the values of this + /// Dimension object's height and + /// width fields. + /// + /// + /// This method is intended to be used only + /// for debugging purposes, and the content and format of the returned + /// string may vary between implementations. The returned string may be + /// empty but may not be null. + /// + /// a string representation of this Dimension + /// object. + /// + public override string ToString() { + return this.GetType().Name + "[width=" + width + ",height=" + height + "]"; + } + } +} diff --git a/iTechSharp/System/Drawing/Dimension2D.cs b/iTechSharp/System/Drawing/Dimension2D.cs new file mode 100644 index 0000000..b0c710a --- /dev/null +++ b/iTechSharp/System/Drawing/Dimension2D.cs @@ -0,0 +1,69 @@ +using System; + +namespace System.Drawing { + /// + /// The Dimension2D class is to encapsulate a width + /// and a height dimension. + /// + /// + /// This class is only the abstract baseclass for all objects that + /// store a 2D dimension. + /// The actual storage representation of the sizes is left to + /// the subclass. + /// + public abstract class Dimension2D : ICloneable { + /// + /// This is an abstract class that cannot be instantiated directly. + /// Type-specific implementation subclasses are available for + /// instantiation and provide a number of formats for storing + /// the information necessary to satisfy the various accessor + /// methods below. + /// + /// + protected Dimension2D() { + } + + /// + /// Returns the width of this Dimension in double + /// precision. + /// + /// the width + public abstract double Width {get;} + + /// + /// Returns the height of this Dimension in double + /// precision. + /// + /// the height + public abstract double Height {get;} + + /// + /// Sets the size of this Dimension object to the + /// specified width and height. + /// + /// the new width for the Dimension + /// object + /// the new height for the Dimension + /// object + public abstract void SetSize(double width, double height); + + /// + /// Sets the size of this Dimension2D object to + /// match the specified size. + /// + /// the size + public Dimension2D Size { + set { + SetSize(value.Width, value.Height); + } + } + + /// + /// Creates a new object of the same class as this object. + /// + /// a clone of this instance + public Object Clone() { + throw new Exception("not implemented"); + } + } +} diff --git a/iTechSharp/System/util/ListIterator.cs b/iTechSharp/System/util/ListIterator.cs new file mode 100644 index 0000000..8596274 --- /dev/null +++ b/iTechSharp/System/util/ListIterator.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; + +namespace System.util { + /// + /// Summary description for ListIterator. + /// + public class ListIterator { + ArrayList col; + int cursor = 0; + int lastRet = -1; + + public ListIterator(ArrayList col) { + this.col = col; + } + + public bool HasNext() { + return cursor != col.Count; + } + + public object Next() { + Object next = col[cursor]; + lastRet = cursor++; + return next; + } + + public object Previous() { + int i = cursor - 1; + Object previous = col[i]; + lastRet = cursor = i; + return previous; + } + + public void Remove() { + if (lastRet == -1) + throw new InvalidOperationException(); + col.RemoveAt(lastRet); + if (lastRet < cursor) + cursor--; + lastRet = -1; + } + } +} diff --git a/iTechSharp/System/util/Properties.cs b/iTechSharp/System/util/Properties.cs new file mode 100644 index 0000000..47b10a8 --- /dev/null +++ b/iTechSharp/System/util/Properties.cs @@ -0,0 +1,209 @@ +using System; +using System.Text; +using System.IO; +using System.Collections; + +namespace System.util +{ + /// + /// Summary description for Properties. + /// + public class Properties + { + private Hashtable _col; + private const string whiteSpaceChars = " \t\r\n\f"; + private const string keyValueSeparators = "=: \t\r\n\f"; + private const string strictKeyValueSeparators = "=:"; + + public Properties() + { + _col = new Hashtable(); + } + + public string Remove(string key) { + string retval = (string)_col[key]; + _col.Remove(key); + return retval; + } + + public IEnumerator GetEnumerator() { + return _col.GetEnumerator(); + } + + public bool ContainsKey(string key) { + return _col.ContainsKey(key); + } + + public virtual void Add(string key, string value) { + _col[key] = value; + } + + public void AddAll(Properties col) { + foreach (string itm in col.Keys) { + _col[itm] = col[itm]; + } + } + + public int Count { + get { + return _col.Count; + } + } + + public virtual string this[string key] { + get { + return (string)_col[key]; + } + + set { + _col[key] = value; + } + } + + public ICollection Keys { + get { + return _col.Keys; + } + } + + public void Clear() { + _col.Clear(); + } + + public void Load(Stream inStream) { + StreamReader inp = new StreamReader(inStream, Encoding.GetEncoding(1252)); + while (true) { + // Get next line + String line = inp.ReadLine(); + if (line == null) + return; + + if (line.Length > 0) { + + // Find start of key + int len = line.Length; + int keyStart; + for (keyStart=0; keyStart= 0) && (line[index--] == '\\')) + slashCount++; + return (slashCount % 2 == 1); + } + } +} diff --git a/iTechSharp/System/util/StringTokenizer.cs b/iTechSharp/System/util/StringTokenizer.cs new file mode 100644 index 0000000..6257e31 --- /dev/null +++ b/iTechSharp/System/util/StringTokenizer.cs @@ -0,0 +1,130 @@ +using System; +/* + * $Id: StringTokenizer.cs,v 1.4 2006/06/16 10:52:26 psoares33 Exp $ + * + * Copyright 2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace System.util { + + // a replacement for the StringTokenizer java class + // it's more or less the same as the one in the GNU classpath + public class StringTokenizer { + private int pos; + private String str; + private int len; + private String delim; + private bool retDelims; + + public StringTokenizer(String str) : this(str, " \t\n\r\f", false) { + } + + public StringTokenizer(String str, String delim) : this(str, delim, false) { + } + + public StringTokenizer(String str, String delim, bool retDelims) { + len = str.Length; + this.str = str; + this.delim = delim; + this.retDelims = retDelims; + this.pos = 0; + } + + public bool HasMoreTokens() { + if (! retDelims) { + while (pos < len && delim.IndexOf(str[pos]) >= 0) + pos++; + } + return pos < len; + } + + public String NextToken(String delim) { + this.delim = delim; + return NextToken(); + } + + public String NextToken() { + if (pos < len && delim.IndexOf(str[pos]) >= 0) { + if (retDelims) + return str.Substring(pos++, 1); + while (++pos < len && delim.IndexOf(str[pos]) >= 0); + } + if (pos < len) { + int start = pos; + while (++pos < len && delim.IndexOf(str[pos]) < 0); + + return str.Substring(start, pos - start); + } + throw new IndexOutOfRangeException(); + } + + public int CountTokens() { + int count = 0; + int delimiterCount = 0; + bool tokenFound = false; + int tmpPos = pos; + + while (tmpPos < len) { + if (delim.IndexOf(str[tmpPos++]) >= 0) { + if (tokenFound) { + count++; + tokenFound = false; + } + delimiterCount++; + } + else { + tokenFound = true; + while (tmpPos < len + && delim.IndexOf(str[tmpPos]) < 0) + ++tmpPos; + } + } + if (tokenFound) + count++; + return retDelims ? count + delimiterCount : count; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/Util.cs b/iTechSharp/System/util/Util.cs new file mode 100644 index 0000000..2080d87 --- /dev/null +++ b/iTechSharp/System/util/Util.cs @@ -0,0 +1,27 @@ +using System; +using System.Globalization; + +namespace System.util +{ + /// + /// Summary description for Util. + /// + public class Util + { + public static int USR(int op1, int op2) { + if (op2 < 1) { + return op1; + } else { + return unchecked((int)((uint)op1 >> op2)); + } + } + + public static bool EqualsIgnoreCase(string s1, string s2) { + return CultureInfo.InvariantCulture.CompareInfo.Compare(s1, s2, CompareOptions.IgnoreCase) == 0; + } + + public static int CompareToIgnoreCase(string s1, string s2) { + return CultureInfo.InvariantCulture.CompareInfo.Compare(s1, s2, CompareOptions.IgnoreCase); + } + } +} diff --git a/iTechSharp/System/util/collections/Algorithm.cs b/iTechSharp/System/util/collections/Algorithm.cs new file mode 100644 index 0000000..fe4e74a --- /dev/null +++ b/iTechSharp/System/util/collections/Algorithm.cs @@ -0,0 +1,49 @@ +using System; + +namespace System.util.collections +{ + /// + /// Very basic algorithms tool class. + /// + public class k_Algorithm + { + public static k_Iterator Copy(k_Iterator ak_SrcFirst, k_Iterator ak_BehindSrcLast, k_Iterator ak_DstFirst) + { + k_Iterator lk_Src = ak_SrcFirst.Clone(), lk_Dst = ak_DstFirst.Clone(); + while (lk_Src != ak_BehindSrcLast) + { + lk_Dst.Current = lk_Src.Current; + lk_Src.Next(); lk_Dst.Next(); + } + return lk_Dst; + } + + public static k_Iterator CopyBackward(k_Iterator ak_SrcFirst, k_Iterator ak_BehindSrcLast, k_Iterator ak_BehindDstLast) + { + k_Iterator lk_Src = ak_BehindSrcLast.Clone(), lk_Dst = ak_BehindDstLast.Clone(); + while (lk_Src != ak_SrcFirst) + { + lk_Src.Prev(); lk_Dst.Prev(); + lk_Dst.Current = lk_Src.Current; + } + return lk_Dst; + } + + public static void Fill(k_Iterator ak_DstFirst, k_Iterator ak_BehindDstLast, object ak_Value) + { + for (k_Iterator lk_Iter = ak_DstFirst.Clone(); lk_Iter != ak_BehindDstLast; lk_Iter.Next()) + lk_Iter.Current = ak_Value; + } + + public static k_Iterator Find(k_Iterator ak_First, k_Iterator ak_Last, object ak_Value) + { + k_Iterator lk_Iter = ak_First.Clone(); + for (; lk_Iter != ak_Last; lk_Iter.Next()) + { + if (object.Equals(lk_Iter.Current, ak_Value)) + break; + } + return lk_Iter; + } + } +} diff --git a/iTechSharp/System/util/collections/Container.cs b/iTechSharp/System/util/collections/Container.cs new file mode 100644 index 0000000..b3913ca --- /dev/null +++ b/iTechSharp/System/util/collections/Container.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// Base interface for all containers + /// + public interface IContainer : ICollection, ICloneable + { + k_Iterator Begin { get; } + k_Iterator End { get; } + + bool IsEmpty { get; } + + k_Iterator Find(object ak_Value); + + k_Iterator Erase(k_Iterator ak_Where); + k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last); + } + + /// + /// Interface for non-associative sequential containers (k_Vector, k_Deque, k_List) + /// + public interface ISequence : IContainer, IList + { + object Front { get; set; } + object Back { get; set; } + + void PushFront(object ak_Value); + void PopFront(); + + void PushBack(object ak_Value); + void PopBack(); + + void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd); + void Assign(object ak_Value, int ai_Count); + + void Insert(k_Iterator ak_Where, object ak_Value); + void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd); + } + + /// + /// Interface for IDictionary derived containers which provide key to value mapping (k_HashTable) + /// + public interface IMap : IContainer, IDictionary + { + k_Iterator FindKey(object ak_Key); + + void Add(DictionaryEntry ar_Item); + void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd); + } + + /// + /// Interface for sorted mapping containers (k_SkipList, k_Tree) + /// + public interface ISortedMap : IMap + { + IComparer Comparer { get; } + + k_Iterator LowerBound(object ak_Key); + k_Iterator UpperBound(object ak_Key); + } +} diff --git a/iTechSharp/System/util/collections/Deque.cs b/iTechSharp/System/util/collections/Deque.cs new file mode 100644 index 0000000..53a2c4b --- /dev/null +++ b/iTechSharp/System/util/collections/Deque.cs @@ -0,0 +1,470 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// Circular buffer of arrays + /// + public class k_Deque : ISequence + { + #region k_BlockIterator Implementation + + private class k_BlockIterator : k_Iterator + { + private readonly k_Deque mk_Deque; + private int mi_Index; + private int mi_BlockIndex; + private int mi_BlockOffset; + + public k_BlockIterator(k_Deque ak_Deque, int ai_Index) + { + mk_Deque = ak_Deque; + mi_Index = ai_Index; + mi_BlockIndex = mk_Deque.CalcBlockAndPos(mi_Index, out mi_BlockOffset); + } + + public override void Move(int ai_Count) + { + int li_Index = mi_Index + ai_Count; + + if (li_Index > mk_Deque.Count) + throw new InvalidOperationException("Tried to move beyond end element."); + else if (li_Index < 0) + throw new InvalidOperationException("Tried to move before first element."); + + mi_Index = li_Index; + mi_BlockOffset += ai_Count; + + if (mi_BlockOffset >= k_Deque.mi_BlockSize || mi_BlockOffset < 0) + mi_BlockIndex = mk_Deque.CalcBlockAndPos(mi_Index, out mi_BlockOffset); + } + + public override int Distance(k_Iterator ak_Iter) + { + return mi_Index - ((k_BlockIterator)ak_Iter).mi_Index; + } + + public override object Collection + { + get { return mk_Deque; } + } + + public override object Current + { + get + { + if (mi_Index < 0 || mi_Index >= mk_Deque.mi_Count) + throw new k_InvalidPositionException(); + return mk_Deque.mk_Blocks[mi_BlockIndex][mi_BlockOffset]; + } + set + { + if (mi_Index < 0 || mi_Index >= mk_Deque.mi_Count) + throw new k_InvalidPositionException(); + mk_Deque.mk_Blocks[mi_BlockIndex][mi_BlockOffset] = value; + } + } + + public override bool Equals(object ak_Obj) + { + k_BlockIterator lk_Iter = ak_Obj as k_BlockIterator; + if (lk_Iter == null) + return false; + + return (mi_Index == lk_Iter.mi_Index) && object.ReferenceEquals(this.Collection, lk_Iter.Collection); + } + + public override int GetHashCode() + { + return mk_Deque.GetHashCode() ^ mi_Index; + } + + public override k_Iterator Clone() + { + return new k_BlockIterator(mk_Deque, mi_Index); + } + + internal int Index + { + get { return mi_Index; } + } + } + + private class k_PinnedBlockIterator : k_BlockIterator + { + public k_PinnedBlockIterator(k_Deque ak_Deque, int ai_Index) + : base(ak_Deque, ai_Index) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private const int mi_BlockSize = 16; + private object[][] mk_Blocks; + + private int mi_Offset; + private int mi_Count; + + public k_Deque() + : this(mi_BlockSize) + { + } + + public k_Deque(int ai_Capacity) + { + if (ai_Capacity < 0) + throw new ArgumentException("Capacity must be positive.", "ai_Capacity"); + mk_Blocks = new object[(ai_Capacity+mi_BlockSize-1)/mi_BlockSize][]; + for (int i=0; i= mk_Blocks.Length) + li_Block -= mk_Blocks.Length; + mk_Blocks[li_Block][li_Pos%mi_BlockSize] = ak_Value; + ++mi_Count; + } + + public void PopBack() + { + Erase(this.End-1); + } + + public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + Clear(); + Insert(this.End, ak_SrcBegin, ak_SrcEnd); + } + + public void Assign(object ak_Value, int ai_Count) + { + Clear(); + for (int i = 0; i < ai_Count; ++i) + Insert(this.End, ak_Value); + } + + public void Insert(k_Iterator ak_Where, object ak_Value) + { + if (ak_Where == this.Begin) + PushFront(ak_Value); + else if (ak_Where == this.End) + PushBack(ak_Value); + else + { + int li_Index = ((k_BlockIterator)ak_Where).Index; + if (mk_Blocks.Length * mi_BlockSize - mi_Count < mi_BlockSize) + AllocateBlock(mi_BlockSize); + + ++mi_Count; + if (li_Index < mi_Count/2) + { + if (mi_Offset == 0) + mi_Offset = mk_Blocks.Length * mi_BlockSize; + --mi_Offset; + k_Iterator lk_Dest = k_Algorithm.Copy(this.Begin+1, this.Begin+li_Index+1, this.Begin); + lk_Dest.Current = ak_Value; + } + else + { + // count has been incremented - there is a free element at the end + k_Iterator lk_Dest = this.Begin + li_Index; + k_Algorithm.CopyBackward(lk_Dest, this.End - 1, this.End); + lk_Dest.Current = ak_Value; + } + } + } + + public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + int li_FirstIndex = ((k_BlockIterator)ak_Where).Index; + int li_Count = ak_SrcEnd - ak_SrcBegin; + if (mk_Blocks.Length * mi_BlockSize <= mi_Count + li_Count + mi_BlockSize) + AllocateBlock(li_Count); + + mi_Count += li_Count; + + k_Iterator lk_Dest; + if (li_FirstIndex < li_Count/2) + { + if (mi_Offset == 0) + mi_Offset = mk_Blocks.Length * mi_BlockSize; + mi_Offset -= li_Count; + lk_Dest = k_Algorithm.Copy(this.Begin+li_Count, this.Begin+li_FirstIndex+li_Count, this.Begin); + } + else + { + // count has been incremented - there are li_Count free elements at the end + lk_Dest = this.Begin + li_FirstIndex; + k_Algorithm.CopyBackward(lk_Dest, this.End - li_Count, this.End); + } + + k_Algorithm.Copy(ak_SrcBegin, ak_SrcEnd, lk_Dest); + } + + #region IList Members + + public int Add(object ak_Value) + { + PushBack(ak_Value); + return mi_Count; + } + + public void Clear() + { + for (int i=0; i= mi_Count || ai_Index < 0) + throw new ArgumentOutOfRangeException("Position out of boundary"); + + int li_Pos, li_Block = CalcBlockAndPos(ai_Index, out li_Pos); + return mk_Blocks[li_Block][li_Pos]; + } + set + { + if (ai_Index >= mi_Count || ai_Index < 0) + throw new ArgumentOutOfRangeException("Position out of boundary"); + + int li_Pos, li_Block = CalcBlockAndPos(ai_Index, out li_Pos); + mk_Blocks[li_Block][li_Pos] = value; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + for (k_Iterator lk_Iter = this.Begin.Clone(); lk_Iter != this.End; lk_Iter.Next()) + ak_Array.SetValue(lk_Iter.Current, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_Deque lk_Clone = new k_Deque(this.Count); + lk_Clone.Insert(lk_Clone.End, this.Begin, this.End); + return lk_Clone; + } + + #endregion + + private void AllocateBlock(int ai_MinElements) + { + // number of new blocks - grow by half block count (150%) + int li_Increment = mk_Blocks.Length / 2; + if (ai_MinElements > li_Increment*mi_BlockSize) + li_Increment = (ai_MinElements + mi_BlockSize - 1)/mi_BlockSize; + + object[][] lk_NewBlocks = new object[mk_Blocks.Length + li_Increment][]; + + // first move all blocks after offset to front + int li_StartBlock = mi_Offset / mi_BlockSize; + int li_BackCount = mk_Blocks.Length - li_StartBlock; + Array.Copy(mk_Blocks, li_StartBlock, lk_NewBlocks, 0, li_BackCount); + + int li_TotalOld = li_BackCount; + + // second move all blocks before offset to end + int li_FrontCount = (mi_Offset + mi_Count + mi_BlockSize - 1) / mi_BlockSize - mk_Blocks.Length; + if (li_FrontCount > 0) + { + Array.Copy(mk_Blocks, 0, lk_NewBlocks, li_BackCount, li_FrontCount); + li_TotalOld += li_FrontCount; + } + + // actually create new empty blocks + for (int i=li_TotalOld; i < li_TotalOld+li_Increment; ++i) + lk_NewBlocks[i] = new object[mi_BlockSize]; + + mk_Blocks = lk_NewBlocks; + mi_Offset %= mi_BlockSize; + } + + private int CalcBlockAndPos(int ai_Index, out int ai_Pos) + { + ai_Pos = mi_Offset + ai_Index; + int li_BlockIndex = ai_Pos / mi_BlockSize; + if (li_BlockIndex >= mk_Blocks.Length) + li_BlockIndex -= mk_Blocks.Length; + ai_Pos %= mi_BlockSize; + return li_BlockIndex; + } + } +} diff --git a/iTechSharp/System/util/collections/HashTable.cs b/iTechSharp/System/util/collections/HashTable.cs new file mode 100644 index 0000000..f16a1a2 --- /dev/null +++ b/iTechSharp/System/util/collections/HashTable.cs @@ -0,0 +1,658 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A HashTable with iterators + /// + public class k_HashTable : IMap + { + #region static helper functions + + private readonly static int[] mk_Primes = + { + 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, + 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, + 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, + 4999559, 5999471, 7199369 + }; + + private static bool IsPrime(int ai_Number) + { + if ((ai_Number & 1) == 0) + return (ai_Number == 2); + + int li_Max = (int)Math.Sqrt(ai_Number); + for (int li_Div=3; li_Div < li_Max; li_Div+=2) + { + if ((ai_Number % li_Div) == 0) + return false; + } + return true; + } + + private static int FindPrimeGreater(int ai_Min) + { + if (ai_Min < 0) + throw new ArgumentException("k_HashTable capacity overflow."); + + // do binary search lookup in primes array + int li_Pos = Array.BinarySearch(mk_Primes, ai_Min); + if (li_Pos >= 0) + return mk_Primes[li_Pos]; + + li_Pos = ~li_Pos; + if (li_Pos < mk_Primes.Length) + return mk_Primes[li_Pos]; + + // ai_Min is greater than highest number in mk_Primes + for (int i = (ai_Min|1); i <= Int32.MaxValue; i+=2) + { + if (IsPrime(i)) + return i; + } + return ai_Min; + } + + #endregion + + #region Bucket Structure + + private struct r_Bucket + { + public object mk_Key; + public object mk_Value; + public int mi_HashCode; // MSB (sign bit) indicates a collision. + } + + #endregion + + #region k_BucketIterator Implementation + + private class k_BucketIterator : k_Iterator + { + private readonly k_HashTable mk_Table; + private int mi_Index; + + public k_BucketIterator(k_HashTable ak_Table, int ai_Index) + { + mk_Table = ak_Table; + mi_Index = -1; + if (ai_Index >= 0) + mi_Index = FindNext(ai_Index-1); + } + + public override object Current + { + get + { + if (mi_Index < 0 || mk_Table.mk_Buckets[mi_Index].mk_Key == null) + throw new k_InvalidPositionException(); + + r_Bucket lr_Bucket = mk_Table.mk_Buckets[mi_Index]; + return new DictionaryEntry(lr_Bucket.mk_Key, lr_Bucket.mk_Value); + } + set + { + if (mi_Index < 0 || mk_Table.mk_Buckets[mi_Index].mk_Key == null) + throw new k_InvalidPositionException(); + + DictionaryEntry lr_Entry = (DictionaryEntry)value; + r_Bucket lr_Bucket = mk_Table.mk_Buckets[mi_Index]; + if (mk_Table.mk_Comparer.Compare(lr_Entry.Key, lr_Bucket.mk_Key) != 0) + throw new ArgumentException("Key values must not be changed."); + mk_Table.mk_Buckets[mi_Index].mk_Value = lr_Entry.Value; + } + } + + public override void Move(int ai_Count) + { + int li_NewIndex = mi_Index; + + if (ai_Count > 0) + { + while (ai_Count-- > 0) + { + if (li_NewIndex < 0) + throw new InvalidOperationException("Tried to moved beyond end element."); + + li_NewIndex = FindNext(li_NewIndex); + } + } + else + { + while (ai_Count++ < 0) + { + if (li_NewIndex < 0) + li_NewIndex = FindPrev(mk_Table.mk_Buckets.Length); + else + li_NewIndex = FindPrev(li_NewIndex); + + if (li_NewIndex < 0) + throw new InvalidOperationException("Tried to move before first element."); + } + } + + mi_Index = li_NewIndex; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_BucketIterator lk_Iter = ak_Iter as k_BucketIterator; + if (lk_Iter == null || !object.ReferenceEquals(lk_Iter.Collection, this.Collection)) + throw new ArgumentException("Cannot determine distance of iterators belonging to different collections."); + + k_Iterator lk_End = mk_Table.End; + + int li_IndexDiff; + if (this != lk_End && ak_Iter != lk_End) + li_IndexDiff = mi_Index - lk_Iter.mi_Index; + else + li_IndexDiff = (this == lk_End) ? 1 : -1; // 1 is also fine when both are End + + if (li_IndexDiff < 0) + { + int li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != ak_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == ak_Iter) + return li_Diff; + } + else + { + int li_Diff = 0; + k_Iterator lk_Fwd = ak_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + } + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override object Collection + { + get { return mk_Table; } + } + + public override bool Equals(object ak_Obj) + { + k_BucketIterator lk_Iter = ak_Obj as k_BucketIterator; + if (lk_Iter == null) + return false; + + return (mi_Index == lk_Iter.mi_Index && object.ReferenceEquals(mk_Table, lk_Iter.mk_Table)); + } + + public override int GetHashCode() + { + return mk_Table.GetHashCode() ^ mi_Index; + } + + public override k_Iterator Clone() + { + return new k_BucketIterator(mk_Table, mi_Index); + } + + private int FindPrev(int ai_Index) + { + --ai_Index; + r_Bucket[] lk_Buckets = mk_Table.mk_Buckets; + while (ai_Index >= 0 && lk_Buckets[ai_Index].mk_Key == null) + --ai_Index; + if (ai_Index < -1) + return -1; + return ai_Index; + } + + private int FindNext(int ai_Index) + { + ++ai_Index; + r_Bucket[] lk_Buckets = mk_Table.mk_Buckets; + while (ai_Index < lk_Buckets.Length && lk_Buckets[ai_Index].mk_Key == null) + ++ai_Index; + + if (ai_Index >= lk_Buckets.Length) + return -1; + return ai_Index; + } + + internal int Index + { + get { return mi_Index; } + } + } + + private class k_PinnedBucketIterator : k_BucketIterator + { + public k_PinnedBucketIterator(k_HashTable ak_Table, int ai_Index) + : base(ak_Table, ai_Index) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private IHashCodeProvider mk_HashProvider; + private IComparer mk_Comparer; + private double md_LoadFactor; + private int mi_GrowSize; + private r_Bucket[] mk_Buckets; + private int mi_Count; + private readonly k_Iterator mk_End; + + public k_HashTable() + : this(0, 0.72) + { + } + + public k_HashTable(int ai_Capacity, double ad_LoadFactor) + : this(ai_Capacity, ad_LoadFactor, null, null) + { + } + + public k_HashTable(int ai_Capacity, double ad_LoadFactor, IHashCodeProvider ak_HashProvider, IComparer ak_Comparer) + { + if (ad_LoadFactor <= .0 || ad_LoadFactor > 1.0) + throw new ArgumentException("Load factor must be greater than .0 and smaller or equal to 1.0", "ad_LoadFactor"); + md_LoadFactor = ad_LoadFactor; + + double ld_Size = ai_Capacity/ad_LoadFactor; + if (ld_Size > int.MaxValue) + throw new ArgumentException("k_HashTable overflow"); + + int li_TableSize = FindPrimeGreater((int)ld_Size); + mk_Buckets = new r_Bucket[li_TableSize]; + mi_GrowSize = (md_LoadFactor < 1.0) ? (int)(md_LoadFactor * li_TableSize) : li_TableSize-1; + + mk_HashProvider = ak_HashProvider; + mk_Comparer = ak_Comparer; + + mk_End = new k_PinnedBucketIterator(this, -1); + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return mk_End; + return new k_PinnedBucketIterator(this, 0); + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + DictionaryEntry lr_Item = (DictionaryEntry)ak_Value; + int li_Index = FindBucket(lr_Item.Key); + if (li_Index < 0 || !object.Equals(mk_Buckets[li_Index].mk_Value, lr_Item.Value)) + return this.End; + return new k_BucketIterator(this, li_Index); + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + k_Iterator lk_Successor = ak_Where + 1; + EmptyBucket(((k_BucketIterator)ak_Where).Index); + return lk_Successor; + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + if (ak_First == this.Begin && ak_Last == this.End) + { + Clear(); + return ak_Last.Clone(); + } + + k_Iterator lk_Current = ak_First; + while (lk_Current != ak_Last) + lk_Current = Erase(lk_Current); + return lk_Current; + } + + // IMap Members + public k_Iterator FindKey(object ak_Key) + { + return new k_BucketIterator(this, FindBucket(ak_Key)); + } + + public void Add(DictionaryEntry ar_Item) + { + Add(ar_Item.Key, ar_Item.Value); + } + + public void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next()) + Add((DictionaryEntry)lk_Iter.Current); + } + + #region IDictionary Members + + public void Add(object ak_Key, object ak_Value) + { + SetValue(ak_Key, ak_Value, true); + } + + public void Clear() + { + if (mi_Count == 0) + return; + + for (int i=0; i < mk_Buckets.Length; ++i) + mk_Buckets[i] = new r_Bucket(); + + mi_Count = 0; + } + + public bool Contains(object ak_Key) + { + return (FindBucket(ak_Key) >= 0); + } + + public void Remove(object ak_Key) + { + EmptyBucket(FindBucket(ak_Key)); + } + + public IDictionaryEnumerator GetEnumerator() + { + return new k_IteratorDictEnumerator(this.Begin, this.End); + } + + public bool IsReadOnly + { + get { return false; } + + } + public bool IsFixedSize + { + get { return false; } + } + + public object this[object ak_Key] + { + get + { + int li_Index = FindBucket(ak_Key); + if (li_Index < 0) + return null; + + return mk_Buckets[li_Index].mk_Value; + } + set + { + SetValue(ak_Key, value, false); + } + } + + public ICollection Keys + { + get + { + int i = 0; + object[] lk_Keys = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Keys[i++] = lr_Entry.Key; + return lk_Keys; + } + } + + public ICollection Values + { + get + { + int i=0; + object[] lk_Values = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Values[i++] = lr_Entry.Value; + return lk_Values; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (DictionaryEntry lr_Entry in this) + ak_Array.SetValue(lr_Entry, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_HashTable lk_Clone = new k_HashTable(this.Count, md_LoadFactor, mk_HashProvider, mk_Comparer); + + int i = mk_Buckets.Length; + while (i-- > 0) + { + object lk_Key = mk_Buckets[i].mk_Key; + if (lk_Key != null) + lk_Clone[lk_Key] = mk_Buckets[i].mk_Value; + } + return lk_Clone; + } + + #endregion + + private void EmptyBucket(int ai_Index) + { + if (ai_Index < 0 || ai_Index >= mk_Buckets.Length) + return; + + if (mk_Buckets[ai_Index].mk_Key == null) + throw new InvalidOperationException("Key was removed earlier."); + + mk_Buckets[ai_Index].mi_HashCode &= unchecked((int)0x80000000); + mk_Buckets[ai_Index].mk_Key = null; + mk_Buckets[ai_Index].mk_Value = null; + --mi_Count; + } + + private int FindBucket(object ak_Key) + { + if (ak_Key == null) + throw new ArgumentException("Key must not be null.", "ak_Key"); + + uint lui_BucketCount = (uint)mk_Buckets.Length; + + uint lui_Increment; + uint lui_HashCode = ComputeHashAndStep(ak_Key, out lui_Increment); + + uint lui_Walker = lui_HashCode % lui_BucketCount; + r_Bucket lr_Bucket; + do + { + int li_Index = (int)lui_Walker; + lr_Bucket = mk_Buckets[li_Index]; + if (lr_Bucket.mk_Key == null && lr_Bucket.mi_HashCode >= 0) + break; // stop on empty non-duplicate + + if ((lr_Bucket.mi_HashCode & 0x7fffffff) == lui_HashCode + && EqualsHelper(lr_Bucket.mk_Key, ak_Key)) + return li_Index; + + lui_Walker += lui_Increment; + lui_Walker %= lui_BucketCount; + } + while (lr_Bucket.mi_HashCode < 0 && lui_Walker != lui_HashCode); + + return -1; // not found + } + + private void SetValue(object ak_Key, object ak_Value, bool ab_Add) + { + if (mi_Count >= mi_GrowSize) + ExpandBucketsArray(); + + uint lui_BucketCount = (uint)mk_Buckets.Length; + + uint lui_Increment; + uint lui_HashCode = ComputeHashAndStep(ak_Key, out lui_Increment); + + r_Bucket lr_Bucket; + int li_Free = -1; + uint lui_Walker = lui_HashCode % lui_BucketCount; + do + { + int li_Index = (int)lui_Walker; + lr_Bucket = mk_Buckets[li_Index]; + if (li_Free < 0 && lr_Bucket.mk_Key == null && lr_Bucket.mi_HashCode < 0) + li_Free = li_Index; + + if (lr_Bucket.mk_Key == null && (lr_Bucket.mi_HashCode & unchecked(0x80000000)) == 0) + { + if (li_Free >= 0) + li_Index = li_Free; + mk_Buckets[li_Index].mk_Key = ak_Key; + mk_Buckets[li_Index].mk_Value = ak_Value; + mk_Buckets[li_Index].mi_HashCode |= (int)lui_HashCode; + ++mi_Count; + return; + } + + if ((lr_Bucket.mi_HashCode & 0x7fffffff) == lui_HashCode + && EqualsHelper(lr_Bucket.mk_Key, ak_Key)) + { + if (ab_Add) + throw new ArgumentException("duplicate key"); + mk_Buckets[li_Index].mk_Value = ak_Value; + return; + } + + // mark all as dupes as long as we have not found a free bucket + if (li_Free == -1) + mk_Buckets[li_Index].mi_HashCode |= unchecked((int)0x80000000); + + lui_Walker += lui_Increment; + lui_Walker %= lui_BucketCount; + } + while (lui_Walker != lui_HashCode); + + if (li_Free == -1) + throw new InvalidOperationException("Corrupted hash table. Insert failed."); + + mk_Buckets[li_Free].mk_Key = ak_Key; + mk_Buckets[li_Free].mk_Value = ak_Value; + mk_Buckets[li_Free].mi_HashCode |= (int)lui_HashCode; + ++mi_Count; + } + + private static void InternalExpandInsert(r_Bucket[] ak_Buckets, r_Bucket ar_Bucket) + { + ar_Bucket.mi_HashCode &= 0x7fffffff; + uint lui_BucketCount = (uint)ak_Buckets.Length; + uint lui_Increment = (uint)(1 + ((((uint)ar_Bucket.mi_HashCode >> 5) + 1) % (lui_BucketCount - 1))); + + uint lui_Walker = (uint)ar_Bucket.mi_HashCode % lui_BucketCount; + for (;;) + { + int li_Index = (int)lui_Walker; + if (ak_Buckets[li_Index].mk_Key == null) + { + ak_Buckets[li_Index] = ar_Bucket; + return; + } + + // since current bucket is occupied mark it as duplicate + ak_Buckets[li_Index].mi_HashCode |= unchecked((int)0x80000000); + + lui_Walker += lui_Increment; + lui_Walker %= lui_BucketCount; + } + } + + private void ExpandBucketsArray() + { + int li_NewSize = FindPrimeGreater(mk_Buckets.Length * 2); + + r_Bucket[] lk_Buckets = new r_Bucket[li_NewSize]; + foreach (r_Bucket lr_Bucket in mk_Buckets) + { + if (lr_Bucket.mk_Key == null) + continue; + InternalExpandInsert(lk_Buckets, lr_Bucket); + } + + mk_Buckets = lk_Buckets; + mi_GrowSize = (md_LoadFactor < 1.0) ? (int)(md_LoadFactor * li_NewSize) : li_NewSize-1; + } + + private uint ComputeHashAndStep(object ak_Key, out uint aui_Increment) + { + // mask the sign bit (our collision indicator) + uint lui_HashCode = (uint)GetHashHelper(ak_Key) & 0x7fffffff; + // calc increment value relatively prime to mk_Buckets.Length + aui_Increment = (uint)(1 + (((lui_HashCode >> 5) + 1) % ((uint)mk_Buckets.Length - 1))); + return lui_HashCode; + } + + private int GetHashHelper(object ak_Key) + { + if (mk_HashProvider != null) + return mk_HashProvider.GetHashCode(ak_Key); + return ak_Key.GetHashCode(); + } + + private bool EqualsHelper(object ak_ObjA, object ak_ObjB) + { + if (mk_Comparer != null) + return (mk_Comparer.Compare(ak_ObjA, ak_ObjB) == 0); + return Object.Equals(ak_ObjA, ak_ObjB); + } + } +} diff --git a/iTechSharp/System/util/collections/Iterator.cs b/iTechSharp/System/util/collections/Iterator.cs new file mode 100644 index 0000000..aa2e7f1 --- /dev/null +++ b/iTechSharp/System/util/collections/Iterator.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + public abstract class k_Iterator : IComparable, ICloneable + { + public static k_Iterator operator ++(k_Iterator ak_Iter) + { + return ak_Iter + 1; + } + + public static k_Iterator operator --(k_Iterator ak_Iter) + { + return ak_Iter - 1; + } + + public static k_Iterator operator +(k_Iterator ak_Iter, int ai_Distance) + { + k_Iterator lk_Clone = ak_Iter.Clone(); + lk_Clone.Move(ai_Distance); + return lk_Clone; + } + + public static k_Iterator operator -(k_Iterator ak_Iter, int ai_Distance) + { + k_Iterator lk_Clone = ak_Iter.Clone(); + lk_Clone.Move(-ai_Distance); + return lk_Clone; + } + + public static int operator -(k_Iterator ak_Left, k_Iterator ak_Right) + { + return ak_Left.Distance(ak_Right); + } + + public static bool operator ==(k_Iterator ak_Left, k_Iterator ak_Right) + { + return object.Equals(ak_Left, ak_Right); + } + + public static bool operator !=(k_Iterator ak_Left, k_Iterator ak_Right) + { + return !object.Equals(ak_Left, ak_Right); + } + + public override bool Equals(object ak_Obj) + { + return base.Equals(ak_Obj); // implemented to avoid warning + } + + public override int GetHashCode() + { + return base.GetHashCode(); // implemented to avoid warning + } + + public int CompareTo(object ak_Obj) + { + k_Iterator lk_Iter = ak_Obj as k_Iterator; + if (lk_Iter == null || !object.ReferenceEquals(lk_Iter.Collection, this.Collection)) + throw new ArgumentException("Cannot compare iterators of different origin."); + + return Distance(lk_Iter); + } + + object ICloneable.Clone() + { + return this.Clone(); + } + + public void Next() + { + Move(1); + } + + public void Prev() + { + Move(-1); + } + + public abstract object Current { get; set; } + public abstract object Collection { get; } + public abstract k_Iterator Clone(); + + public abstract void Move(int ai_Count); + public abstract int Distance(k_Iterator ak_Iter); + } + + public class k_IteratorEnumerator : IEnumerator + { + protected k_Iterator mk_Current; + protected k_Iterator mk_Begin, mk_End; + protected bool mb_Fresh; + + public k_IteratorEnumerator(k_Iterator ak_Begin, k_Iterator ak_End) + { + mk_Begin = ak_Begin; + mk_End = ak_End; + mb_Fresh = true; + } + + #region IEnumerator Members + + public bool MoveNext() + { + if (mb_Fresh) + { + mk_Current = mk_Begin.Clone(); + mb_Fresh = false; + } + else if (mk_Current != mk_End) + mk_Current.Next(); + + return (mk_Current != mk_End); + } + + public void Reset() + { + mb_Fresh = true; + mk_Current = null; + } + + public object Current + { + get + { + if (mb_Fresh || mk_Current == mk_End) + throw new InvalidOperationException("The enumerator is positioned before the first element of the collection or after the last element."); + return mk_Current.Current; + } + } + + #endregion + } + + public class k_IteratorDictEnumerator : k_IteratorEnumerator, IDictionaryEnumerator + { + public k_IteratorDictEnumerator(k_Iterator ak_Begin, k_Iterator ak_End) + : base(ak_Begin, ak_End) + { + } + + #region IDictionaryEnumerator Members + + public object Key + { + get { return this.Entry.Key; } + } + + public object Value + { + get { return this.Entry.Value; } + } + + public DictionaryEntry Entry + { + get { return (DictionaryEntry)this.Current; } + } + + #endregion + } + + public class k_IListIterator : k_Iterator + { + private readonly IList mk_List; + private int mi_Index; + + public static k_IListIterator CreateBegin(IList ak_List) + { + return new k_PinnedIListIterator(ak_List, 0); + } + + public static k_IListIterator CreateEnd(IList ak_List) + { + return new k_PinnedIListIterator(ak_List, ak_List.Count); + } + + public k_IListIterator(IList ak_List, int ai_Index) + { + mk_List = ak_List; + mi_Index = ai_Index; + } + + public override void Move(int ai_Count) + { + int li_Index = mi_Index + ai_Count; + + if (li_Index < 0) + throw new InvalidOperationException("Tried to move before first element."); + else if (li_Index > mk_List.Count) + throw new InvalidOperationException("Tried to moved beyond end element."); + + mi_Index = li_Index; + } + + public override int Distance(k_Iterator ak_Iter) + { + return mi_Index - ((k_IListIterator)ak_Iter).mi_Index; + } + + public override object Collection + { + get { return mk_List; } + } + + public override object Current + { + get + { + if (mi_Index < 0 || mi_Index >= mk_List.Count) + throw new k_InvalidPositionException(); + return mk_List[mi_Index]; + } + set + { + if (mi_Index < 0 || mi_Index >= mk_List.Count) + throw new k_InvalidPositionException(); + mk_List[mi_Index] = value; + } + } + + public override bool Equals(object ak_Obj) + { + k_IListIterator lk_Iter = ak_Obj as k_IListIterator; + if (lk_Iter == null) + return false; + return (mi_Index == lk_Iter.mi_Index) && object.ReferenceEquals(this.Collection, lk_Iter.Collection); + } + + public override int GetHashCode() + { + return mk_List.GetHashCode() ^ mi_Index; + } + + public override k_Iterator Clone() + { + return new k_IListIterator(mk_List, mi_Index); + } + + internal int Index + { + get { return mi_Index; } + } + } + + internal class k_PinnedIListIterator : k_IListIterator + { + public k_PinnedIListIterator(IList ak_List, int ai_Index) + : base(ak_List, ai_Index) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + public class k_CollectionOnIterators : ICollection + { + private k_Iterator mk_Begin, mk_End; + private int mi_Count; + + public k_CollectionOnIterators(k_Iterator ak_Begin, k_Iterator ak_End) + { + mk_Begin = ak_Begin; + mk_End = ak_End; + mi_Count = mk_End - mk_Begin; + } + + #region ICollection Members + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return mk_Begin.Collection; } + } + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (object lk_Obj in this) + ak_Array.SetValue(lk_Obj, ai_Index++); + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(mk_Begin, mk_End); + } + + #endregion + } + + [Serializable] + public class k_IteratorPinnedException : InvalidOperationException + { + public k_IteratorPinnedException() + : base("Cannot move pinned iterator. Use Clone() to create a movable copy.") + { + } + } + + [Serializable] + public class k_InvalidPositionException : InvalidOperationException + { + public k_InvalidPositionException() + : base("Iterator positioned on End or invalid element.") + { + } + } +} diff --git a/iTechSharp/System/util/collections/List.cs b/iTechSharp/System/util/collections/List.cs new file mode 100644 index 0000000..53b15ee --- /dev/null +++ b/iTechSharp/System/util/collections/List.cs @@ -0,0 +1,537 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A doubly linked list + /// + public class k_List : ISequence + { + #region k_Node Implementation + + private class k_Node + { + private object mk_Value; + public k_Node mk_Prev, mk_Next; + + public k_Node(object ak_Value) + { + mk_Value = ak_Value; + } + + public object Value + { + get { return mk_Value; } + set { mk_Value = value; } + } + } + + #endregion + + #region k_NodeIterator Implementation + + private class k_NodeIterator : k_Iterator, ICloneable + { + private readonly k_List mk_List; + private k_Node mk_Current; + + public k_NodeIterator(k_List ak_List, k_Node ak_Node) + { + mk_List = ak_List; + mk_Current = ak_Node; + } + + public override object Current + { + get + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + return mk_Current.Value; + } + set + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + mk_Current.Value = value; + } + } + + public override object Collection + { + get { return mk_List; } + } + + public override void Move(int ai_Count) + { + k_Node lk_NewPos = mk_Current; + + int li_Count = ai_Count; + if (li_Count > 0) + { + while (li_Count-- > 0) + { + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to moved beyond end element."); + + lk_NewPos = lk_NewPos.mk_Next; + } + } + else + { + while (li_Count++ < 0) + { + if (lk_NewPos == null) + lk_NewPos = mk_List.mk_Tail; + else + lk_NewPos = lk_NewPos.mk_Prev; + + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to move before first element."); + } + } + +#if (DEBUG) + if (ai_Count != 0 && object.ReferenceEquals(mk_Current, lk_NewPos)) + throw new IndexOutOfRangeException("Iterator is positioned on invalid node."); +#endif + + mk_Current = lk_NewPos; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_NodeIterator lk_Iter = (k_NodeIterator)ak_Iter; + + if (!this.IsValid || !lk_Iter.IsValid) + throw new ArgumentException("Iterator is invalid."); + + int li_Diff = 0; + k_Iterator lk_End = mk_List.End; + k_Iterator lk_Fwd = lk_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + + li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != lk_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == lk_Iter) + return li_Diff; + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override bool Equals(object ak_Obj) + { + k_NodeIterator lk_Iter = ak_Obj as k_NodeIterator; + if (lk_Iter == null) + return false; + return object.ReferenceEquals(mk_Current, lk_Iter.mk_Current); + } + + public override int GetHashCode() + { + if (mk_Current == null) + return mk_List.GetHashCode(); + return mk_Current.GetHashCode(); + } + + public override k_Iterator Clone() + { + return new k_NodeIterator(mk_List, mk_Current); + } + + internal k_Node Node + { + get { return mk_Current; } + } + + internal bool IsValid + { + get { return (mk_Current == null || (!object.ReferenceEquals(mk_Current.mk_Next, mk_Current) && !object.ReferenceEquals(mk_Current.mk_Prev, mk_Current))); } + } + } + + private class k_PinnedNodeIterator : k_NodeIterator + { + public k_PinnedNodeIterator(k_List ak_List, k_Node ak_Node) + : base(ak_List, ak_Node) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private int mi_Count; + private k_Node mk_Head, mk_Tail; + private k_Iterator mk_Begin, mk_End; + + public k_List() + { + mk_End = new k_PinnedNodeIterator(this, null); + mk_Begin = mk_End; + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return mk_End; + if (mk_Begin == null) + mk_Begin = new k_PinnedNodeIterator(this, mk_Head); + return mk_Begin; + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + return k_Algorithm.Find(this.Begin, this.End, ak_Value); + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this list."); + if (ak_Where == this.End) + return this.End; + return Erase(ak_Where, ak_Where + 1); + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_First.Collection) && object.ReferenceEquals(this, ak_Last.Collection), "Iterators do not belong to this collection."); + int li_Distance = ak_Last - ak_First; + if (li_Distance == 0) + return ak_Last; + + k_Node lk_First = ((k_NodeIterator)ak_First).Node; + k_Node lk_Prev = lk_First.mk_Prev; + k_Node lk_Next = (ak_Last != this.End) ? ((k_NodeIterator)ak_Last).Node : null; + + if (lk_Prev != null) + lk_Prev.mk_Next = lk_Next; + else + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(mk_Head, lk_First), "Inconsistent list state"); + mk_Head = lk_Next; + mk_Begin = null; + } + + if (lk_Next != null) + lk_Next.mk_Prev = lk_Prev; + else + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(mk_Tail, ((k_NodeIterator)(ak_Last-1)).Node), "Inconsistent list state"); + mk_Tail = lk_Prev; + } + + mi_Count -= li_Distance; + +#if (DEBUG) + // create invalid nodes linking to itself + k_Node lk_Node = lk_First; + while (lk_Node != null && lk_Node != lk_Next) + { + k_Node lk_Tmp = lk_Node.mk_Next; + lk_Node.mk_Next = lk_Node; + lk_Node.mk_Prev = lk_Node; + + lk_Node = lk_Tmp; + } +#endif + + return ak_Last; + } + + // ISequence Members + public object Front + { + get + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + return mk_Head.Value; + } + set + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + mk_Head.Value = value; + } + } + + public object Back + { + get + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + return mk_Tail.Value; + } + set + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + mk_Tail.Value = value; + } + } + + public void PushFront(object ak_Value) + { + Insert(this.Begin, ak_Value); + } + + public void PopFront() + { + Erase(this.Begin); + } + + public void PushBack(object ak_Value) + { + Insert(this.End, ak_Value); + } + + public void PopBack() + { + Erase(this.End-1); + } + + public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + Clear(); + Insert(this.End, ak_SrcBegin, ak_SrcEnd); + } + + public void Assign(object ak_Value, int ai_Count) + { + Clear(); + Insert(this.End, ak_Value, ai_Count); + } + + public void Insert(k_Iterator ak_Where, object ak_Value) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + + k_Node lk_New = new k_Node(ak_Value); + PasteNodeRange((k_NodeIterator)ak_Where, lk_New, lk_New); + ++mi_Count; + } + + public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + + k_Node lk_Start = new k_Node(null), lk_End = lk_Start; + + int li_Count = 0; + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next(), ++li_Count) + { + k_Node lk_New = new k_Node(lk_Iter.Current); + lk_End.mk_Next = lk_New; + lk_New.mk_Prev = lk_End; + lk_End = lk_New; + } + + if (li_Count > 0) + { + PasteNodeRange((k_NodeIterator)ak_Where, lk_Start.mk_Next, lk_End); + mi_Count += li_Count; + } + } + + public void Insert(k_Iterator ak_Where, object ak_Value, int ai_Count) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + + k_Node lk_Start = new k_Node(null), lk_End = lk_Start; + + for (int i=0; i 0) + { + PasteNodeRange((k_NodeIterator)ak_Where, lk_Start.mk_Next, lk_End); + mi_Count += ai_Count; + } + } + + #region IList Members + + public int Add(object ak_Value) + { + Insert(this.End, ak_Value); + return mi_Count; + } + + public void Clear() + { + mk_Head = mk_Tail = null; + mk_Begin = mk_End; + mi_Count = 0; + } + + public bool Contains(object ak_Value) + { + return (this.Find(ak_Value) != this.End); + } + + public int IndexOf(object ak_Value) + { + int li_Index = 0; + foreach (object lk_Val in this) + { + if (object.Equals(lk_Val, ak_Value)) + return li_Index; + ++li_Index; + } + return -1; + } + + void IList.Insert(int ai_Index, object ak_Value) + { + this.Insert(this.Begin + ai_Index, ak_Value); + } + + void IList.Remove(object ak_Value) + { + k_NodeIterator lk_Found = (k_NodeIterator)this.Find(ak_Value); + if (lk_Found != this.End) + Erase(lk_Found); + } + + public void RemoveAt(int ai_Index) + { + Erase(this.Begin + ai_Index); + } + + public bool IsFixedSize + { + get { return false; } + } + + bool IList.IsReadOnly + { + get { return false; } + } + + public object this[int index] + { + get + { + k_Iterator lk_Iter = this.Begin + index; + return lk_Iter.Current; + } + set + { + k_Iterator lk_Iter = this.Begin + index; + lk_Iter.Current = value; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (object lk_Obj in this) + ak_Array.SetValue(lk_Obj, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_List lk_Clone = new k_List(); + for (k_Iterator lk_Iter = this.Begin.Clone(); lk_Iter != this.End; lk_Iter.Next()) + lk_Clone.Add(lk_Iter.Current); + return lk_Clone; + } + + #endregion + + private void PasteNodeRange(k_NodeIterator ak_Where, k_Node ak_First, k_Node ak_Last) + { + if (ak_Where != this.End) + { + k_Node lk_Next = ak_Where.Node; + k_Node lk_Prev = lk_Next.mk_Prev; + + ak_Last.mk_Next = lk_Next; + ak_First.mk_Prev = lk_Prev; + if (lk_Next != null) + lk_Next.mk_Prev = ak_Last; + if (lk_Prev != null) + lk_Prev.mk_Next = ak_First; + } + else + { + if (mk_Tail != null) + { + mk_Tail.mk_Next = ak_First; + ak_First.mk_Prev = mk_Tail; + } + mk_Tail = ak_Last; + } + + if (ak_Where == this.Begin) + { + mk_Head = ak_First; + mk_Begin = null; // recalc on next get + } + } + } +} diff --git a/iTechSharp/System/util/collections/Queue.cs b/iTechSharp/System/util/collections/Queue.cs new file mode 100644 index 0000000..f80d116 --- /dev/null +++ b/iTechSharp/System/util/collections/Queue.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// k_Queue is a first-in, first-out (FIFO) data structure. + /// It hides functionality of the underlying container (e.g. k_List, k_Deque) + /// and provides a a basic queue class. + /// + public class k_Queue : ICollection + { + private ISequence mk_Container; + + public k_Queue() + : this(typeof(k_Deque)) + { + } + + public k_Queue(Type ak_ContainerType) + { + mk_Container = Activator.CreateInstance(ak_ContainerType) as ISequence; + if (mk_Container == null) + throw new ArgumentException("Container type must implement ISequence.", "ak_ContainerType"); + } + + public k_Iterator Begin + { + get { return mk_Container.Begin; } + } + + public k_Iterator End + { + get { return mk_Container.End; } + } + + public object Front + { + get { return mk_Container.Front; } + } + + public object Back + { + get { return mk_Container.Back; } + } + + public bool IsEmpty + { + get { return mk_Container.IsEmpty; } + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + return mk_Container.Erase(ak_Where); + } + + public void Push(object ak_Value) + { + mk_Container.PushBack(ak_Value); + } + + public object Pop() + { + object lk_Obj = mk_Container.Front; + mk_Container.PopFront(); + return lk_Obj; + } + + public IContainer UnderlyingContainer + { + get { return mk_Container; } + } + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (object lk_Obj in this) + ak_Array.SetValue(lk_Obj, ai_Index++); + } + + public int Count + { + get { return mk_Container.Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(mk_Container.Begin, mk_Container.End); + } + + #endregion + } +} diff --git a/iTechSharp/System/util/collections/SkipList.cs b/iTechSharp/System/util/collections/SkipList.cs new file mode 100644 index 0000000..a04784c --- /dev/null +++ b/iTechSharp/System/util/collections/SkipList.cs @@ -0,0 +1,699 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A Skip List + /// + public class k_SkipList : ISortedMap + { + #region k_Node Implementation + + private class k_Node + { + private object mk_Key; + private object mk_Value; + + private k_Node[] mk_Next; + + public k_Node(object ak_Key, object ak_Value, int ai_Height) + { + mk_Next = new k_Node[ai_Height]; + mk_Key = ak_Key; + mk_Value = ak_Value; + } + + public object Key + { + get { return mk_Key; } + } + + public object Value + { + get { return mk_Value; } + set { mk_Value = Value; } + } + + public DictionaryEntry Item + { + get { return new DictionaryEntry(mk_Key, mk_Value); } + } + + public k_Node[] Next + { + get { return mk_Next; } + } + + public int Height + { + get { return mk_Next.Length; } + } + } + + #endregion + + #region k_NodeIterator Implementation + + private class k_NodeIterator : k_Iterator + { + private readonly k_SkipList mk_List; + private k_Node mk_Current; + + public k_NodeIterator(k_SkipList ak_List, k_Node ak_Node) + { + mk_List = ak_List; + mk_Current = ak_Node; + } + + public override object Current + { + get + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + return mk_Current.Item; + } + set + { + DictionaryEntry lr_Entry = (DictionaryEntry)value; + if (mk_List.mk_Comparer.Compare(lr_Entry.Key, mk_Current.Key) != 0) + throw new ArgumentException("Key values must not be changed."); + mk_Current.Value = lr_Entry.Value; + } + } + + public override object Collection + { + get { return mk_List; } + } + + public override void Move(int ai_Count) + { + k_Node lk_NewPos = mk_Current; + + if (ai_Count > 0) + { + while (ai_Count-- > 0) + { + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to moved beyond end element."); + + lk_NewPos = mk_List.Next(lk_NewPos); + } + } + else + { + while (ai_Count++ < 0) + { + if (lk_NewPos == null) + lk_NewPos = mk_List.RightMost(); + else + lk_NewPos = mk_List.Previous(lk_NewPos); + + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to move before first element."); + } + } + + mk_Current = lk_NewPos; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_NodeIterator lk_Iter = (k_NodeIterator)ak_Iter; + k_Iterator lk_End = mk_List.End; + + int li_KeyDiff; + if (this == lk_End || ak_Iter == lk_End) + li_KeyDiff = (this == lk_End && this != ak_Iter) ? 1 : 0; + else + li_KeyDiff = mk_List.mk_Comparer.Compare(mk_Current.Key, lk_Iter.mk_Current.Key); + + if (li_KeyDiff <= 0) + { + int li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != lk_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == lk_Iter) + return li_Diff; + } + + if (li_KeyDiff >= 0) + { + int li_Diff = 0; + k_Iterator lk_Fwd = lk_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + } + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override bool Equals(object ak_Obj) + { + k_NodeIterator lk_Iter = ak_Obj as k_NodeIterator; + if (lk_Iter == null) + return false; + return object.ReferenceEquals(mk_Current, lk_Iter.mk_Current); + } + + public override int GetHashCode() + { + if (mk_Current == null) + return mk_List.GetHashCode(); + return mk_Current.GetHashCode(); + } + + public override k_Iterator Clone() + { + return new k_NodeIterator(mk_List, mk_Current); + } + + internal k_Node Node + { + get { return mk_Current; } + } + } + + private class k_PinnedNodeIterator : k_NodeIterator + { + public k_PinnedNodeIterator(k_SkipList ak_List, k_Node ak_Node) + : base(ak_List, ak_Node) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private static Random mk_Rand = new Random(); + + private IComparer mk_Comparer; + private double md_Prob; + private int mi_MaxLevel; + private int mi_HighestNode; + private k_Node mk_Head; + private int mi_Count; + private k_Iterator mk_End; + + public k_SkipList() + : this(System.Collections.Comparer.Default) + { + } + + public k_SkipList(IComparer ak_Comparer) + : this(ak_Comparer, 1.0/Math.E, 16) + { + } + + public k_SkipList(IComparer ak_Comparer, double ad_Prob, int ai_MaxLevel) + { + if (ad_Prob >= 1.0 || ad_Prob <= 0) + throw new ArgumentException("Invalid probability. Must be (0-1).", "ad_Prob"); + md_Prob = ad_Prob; + mi_MaxLevel = ai_MaxLevel; + mk_Comparer = ak_Comparer; + mk_Head = new k_Node(null, null, ai_MaxLevel); + mk_End = new k_PinnedNodeIterator(this, null); + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return this.End; + return new k_NodeIterator(this, this.LeftMost()); + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + DictionaryEntry lr_Item = (DictionaryEntry)ak_Value; + k_NodeIterator lk_Found = (k_NodeIterator)LowerBound(lr_Item.Key); + if (lk_Found != this.End + && mk_Comparer.Compare(lr_Item.Key, lk_Found.Node.Key) == 0 && mk_Comparer.Compare(lr_Item.Value, lk_Found.Node.Value) == 0) + return lk_Found; + return this.End; + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + return Erase(ak_Where, ak_Where+1); + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + if (ak_First == ak_Last) + return ak_Last.Clone(); + + int li_Count = ak_Last - ak_First; + + k_Node lk_First = ((k_NodeIterator)ak_First).Node; + k_Node lk_Last = (ak_Last != this.End) ? ((k_NodeIterator)ak_Last).Node : null; + k_Node lk_Node = new k_Node(null, null, mi_HighestNode); + + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null) + { + if (ComparePos(lk_Current.Next[li_Level], lk_First) >= 0) + break; + lk_Current = lk_Current.Next[li_Level]; + } + lk_Node.Next[li_Level] = lk_Current; + } + + if (lk_Last == null) + { + for (int i=0; i= 0) + break; + lk_Current = lk_Current.Next[i]; + } + lk_Left.Next[i] = lk_Current; + } + } + + mi_Count -= li_Count; + + while (mi_HighestNode > 0 && mk_Head.Next[mi_HighestNode-1] == null) + --mi_HighestNode; + + return ak_Last; + } + + // IMap Members + public k_Iterator FindKey(object ak_Key) + { + k_NodeIterator lk_Found = (k_NodeIterator)LowerBound(ak_Key); + if (lk_Found != this.End && mk_Comparer.Compare(ak_Key, lk_Found.Node.Key) == 0) + return lk_Found; + return this.End; + } + + public void Add(DictionaryEntry ar_Entry) + { + Add(ar_Entry.Key, ar_Entry.Value); + } + + public void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next()) + Add((DictionaryEntry)lk_Iter.Current); + } + + // ISortedMap Members + public IComparer Comparer + { + get { return mk_Comparer; } + } + + /// + /// Returns an iterator to the first element in a list with a key value + /// that is equal to or greater than that of a specified key. + /// + /// + /// The argument key value to be compared with the sort key of an element + /// from the list being searched. + /// + /// + /// Location of an element in a list that with a key that is equal to + /// or greater than the argument key, or this.End if no match is found for the key. + /// + public k_Iterator LowerBound(object ak_Key) + { + k_Node lk_Found = null; + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + k_Node lk_Next = lk_Current.Next[li_Level]; + while (lk_Next != null) + { + int li_Diff = mk_Comparer.Compare(lk_Next.Key, ak_Key); + if (li_Diff >= 0) + { + lk_Found = lk_Next; + break; + } + + lk_Current = lk_Next; + lk_Next = lk_Next.Next[li_Level]; + } + } + + return new k_NodeIterator(this, lk_Found); + } + + /// + /// Returns an iterator to the first element in a list with a key value + /// that is greater than that of a specified key. + /// + /// + /// The argument key value to be compared with the sort key of an element + /// from the list being searched. + /// + /// + /// Location of an element in a list that with a key that is greater + /// than the argument key, or this.End if no match is found for the key. + /// + public k_Iterator UpperBound(object ak_Key) + { + k_Node lk_Found = null; + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + k_Node lk_Next = lk_Current.Next[li_Level]; + while (lk_Next != null) + { + int li_Diff = mk_Comparer.Compare(lk_Next.Key, ak_Key); + if (li_Diff > 0) + { + lk_Found = lk_Next; + break; + } + + lk_Current = lk_Next; + lk_Next = lk_Next.Next[li_Level]; + } + } + + return new k_NodeIterator(this, lk_Found); + } + + #region IDictionary Members + + public void Add(object ak_Key, object ak_Value) + { + k_Node lk_Node = new k_Node(ak_Key, ak_Value, CalcNewNodeHeight()); + if (lk_Node.Height > mi_HighestNode) + mi_HighestNode = lk_Node.Height; + + FindInsertPos(lk_Node); + for (int i=0; i= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null) + { + int li_Diff = mk_Comparer.Compare(lk_Current.Next[li_Level].Key, ak_Node.Key); + if (li_Diff > 0) + break; + if (li_Diff == 0) + { + k_Node lk_Next = lk_Current; + while (lk_Next != null && !object.ReferenceEquals(lk_Next.Next[0], ak_Node)) + { + if (mk_Comparer.Compare(lk_Next.Key, ak_Node.Key) > 0) + lk_Next = null; + else + lk_Next = lk_Next.Next[0]; + } + if (lk_Next == null) + break; + + return lk_Next; // found previous node during right-scan of nodes with equal key value + } + lk_Current = lk_Current.Next[li_Level]; + } + } + if (object.ReferenceEquals(mk_Head, lk_Current)) + return null; + return lk_Current; + } + + private k_Node Next(k_Node ak_Node) + { + return ak_Node.Next[0]; + } + + /// + /// Return leftmost node in list. + /// + /// Found node + private k_Node LeftMost() + { + return mk_Head.Next[0]; + } + + /// + /// Return rightmost node in list. + /// + /// Found node + private k_Node RightMost() + { + k_Node lk_Current = mk_Head.Next[mi_HighestNode-1]; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null) + lk_Current = lk_Current.Next[li_Level]; + } + return lk_Current; + } + + private void FindInsertPos(k_Node ak_Node) + { + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null && mk_Comparer.Compare(lk_Current.Next[li_Level].Key, ak_Node.Key) < 0) + lk_Current = lk_Current.Next[li_Level]; + + if (li_Level < ak_Node.Height) + ak_Node.Next[li_Level] = lk_Current; + } + } + + private int CalcNewNodeHeight() + { + double ld_Rnd = mk_Rand.NextDouble(); + + int li_Level = 1; + for (double ld_Pow = md_Prob; li_Level < mi_MaxLevel; ++li_Level, ld_Pow*=md_Prob) + { + if (ld_Pow < ld_Rnd) + break; + } + + return li_Level; + } + + private int ComparePos(k_Node ak_Left, k_Node ak_Right) + { + if (object.ReferenceEquals(ak_Left, ak_Right)) + return 0; + + int li_Diff = mk_Comparer.Compare(ak_Left.Key, ak_Right.Key); + if (li_Diff != 0) + return li_Diff; + + k_Node lk_Current = ak_Left; + for (;;) + { + if (lk_Current == null || mk_Comparer.Compare(lk_Current.Key, ak_Right.Key) > 0) + return 1; + else if (object.ReferenceEquals(lk_Current, ak_Right)) + return -1; + + lk_Current = lk_Current.Next[0]; + } + } + + private k_Node CloneR(k_Node ak_Node, k_Node ak_NextHigher) + { + k_Node lk_New = new k_Node(ak_Node.Key, ak_Node.Value, ak_Node.Height); + + for (int i=ak_Node.Height-1; i>=0; --i) + { + // simply copy two links with equal target next to each other + if (i < ak_Node.Height-1 && object.ReferenceEquals(ak_Node.Next[i], ak_Node.Next[i+1])) + { + lk_New.Next[i] = lk_New.Next[i+1]; + continue; + } + + k_Node lk_Next = ak_Node.Next[i]; + if (lk_Next != null && lk_Next.Height-1 <= i) + { + k_Node lk_Higher = (i < ak_Node.Height-1) ? ak_Node.Next[i+1] : ak_NextHigher; + lk_New.Next[i] = CloneR(lk_Next, lk_Higher); + } + else + lk_New.Next[i] = ak_NextHigher; + } + return lk_New; + } + } +} diff --git a/iTechSharp/System/util/collections/Stack.cs b/iTechSharp/System/util/collections/Stack.cs new file mode 100644 index 0000000..b378166 --- /dev/null +++ b/iTechSharp/System/util/collections/Stack.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A push-down stack using an underlying k_Vector. + /// Last in first out (LIFO). + /// + public class k_Stack : ICollection + { + private ISequence mk_Items; // stack container + private int mi_MaxSize; + + public k_Stack() + { + mk_Items = new k_Vector(); + mi_MaxSize = int.MaxValue; + } + + public k_Stack(int ai_Capacity, bool ab_FixedSize) + { + mk_Items = new k_Vector(ai_Capacity); + mi_MaxSize = (ab_FixedSize) ? ai_Capacity : int.MaxValue; + } + + public object Top + { + get { return mk_Items.Back; } + set { mk_Items.Back = value; } + } + + public object this[int ai_Index] + { + get { return (mk_Items.Begin+ai_Index).Current; } + set { (mk_Items.Begin+ai_Index).Current = value; } + } + + public void Push(object ak_Value) + { + if (mk_Items.Count >= mi_MaxSize) + throw new StackOverflowException("Stack overflow"); + + mk_Items.PushBack(ak_Value); + } + + public object Pop() + { + if (mk_Items.Count == 0) + throw new StackOverflowException("Stack underflow"); + + object lk_Obj = mk_Items.Back; + mk_Items.PopBack(); + return lk_Obj; + } + + public bool IsEmpty + { + get { return mk_Items.IsEmpty; } + } + + public void Clear() + { + mk_Items.Clear(); + } + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + for (k_Iterator lk_Iter = mk_Items.Begin.Clone(); lk_Iter != mk_Items.End; lk_Iter.Next()) + ak_Array.SetValue(lk_Iter.Current, ai_Index++); + } + + public int Count + { + get { return mk_Items.Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(mk_Items.Begin, mk_Items.End); + } + + #endregion + } +} diff --git a/iTechSharp/System/util/collections/Tree.cs b/iTechSharp/System/util/collections/Tree.cs new file mode 100644 index 0000000..0d43e82 --- /dev/null +++ b/iTechSharp/System/util/collections/Tree.cs @@ -0,0 +1,830 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// k_Tree is a red-black balanced search tree (BST) implementation. + /// Complexity of find, insert and erase operations is near O(lg n). + /// + public class k_Tree : ISortedMap + { + #region k_Node Implementation + + private class k_Node + { + private object mk_Key; + private object mk_Value; + private bool mb_Red; + public k_Node mk_Left, mk_Right, mk_Parent; // public to simplify fixup & clone (passing by ref) + + public k_Node(object ak_Key, object ak_Value, k_Node ak_Parent) + { + mk_Key = ak_Key; + mk_Value = ak_Value; + mk_Parent = ak_Parent; + mb_Red = true; + } + + public object Key + { + get { return mk_Key; } + } + + public object Value + { + get { return mk_Value; } + set { mk_Value = value; } + } + + public DictionaryEntry Item + { + get { return new DictionaryEntry(mk_Key, mk_Value); } + } + + public bool Red + { + get { return mb_Red; } + set { mb_Red = value; } + } + + public static void SwapItems(k_Node ak_A, k_Node ak_B) + { + object lk_Tmp = ak_A.mk_Key; + ak_A.mk_Key = ak_B.mk_Key; + ak_B.mk_Key = lk_Tmp; + + lk_Tmp = ak_A.mk_Value; + ak_A.mk_Value = ak_B.mk_Value; + ak_B.mk_Value = lk_Tmp; + } + } + + #endregion + + #region k_NodeIterator Implementation + + private class k_NodeIterator : k_Iterator + { + private readonly k_Tree mk_Tree; + private k_Node mk_Current; + + public k_NodeIterator(k_Tree ak_Tree, k_Node ak_Node) + { + mk_Tree = ak_Tree; + mk_Current = ak_Node; + } + + public override object Current + { + get + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + return mk_Current.Item; + } + set + { + DictionaryEntry lr_Entry = (DictionaryEntry)value; + if (mk_Tree.mk_Comparer.Compare(lr_Entry.Key, mk_Current.Key) != 0) + throw new ArgumentException("Key values must not be changed."); + mk_Current.Value = lr_Entry.Value; + } + } + + public override object Collection + { + get { return mk_Tree; } + } + + public override void Move(int ai_Count) + { + k_Node lk_NewPos = mk_Current; + + if (ai_Count > 0) + { + while (ai_Count-- > 0) + { + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to moved beyond end element."); + + lk_NewPos = k_Tree.Next(lk_NewPos); + } + } + else + { + while (ai_Count++ < 0) + { + if (lk_NewPos == null) + lk_NewPos = mk_Tree.mk_Right; + else + lk_NewPos = k_Tree.Previous(lk_NewPos); + + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to move before first element."); + } + } + + mk_Current = lk_NewPos; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_NodeIterator lk_Iter = ak_Iter as k_NodeIterator; + if (lk_Iter == null || !object.ReferenceEquals(lk_Iter.Collection, this.Collection)) + throw new ArgumentException("Cannot determine distance of iterators belonging to different collections."); + + k_Iterator lk_End = mk_Tree.End; + + int li_KeyDiff; + if (this == lk_End || ak_Iter == lk_End) + li_KeyDiff = (this == lk_End && this != ak_Iter) ? 1 : 0; + else + li_KeyDiff = mk_Tree.mk_Comparer.Compare(mk_Current.Key, lk_Iter.mk_Current.Key); + + if (li_KeyDiff <= 0) + { + int li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != ak_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == ak_Iter) + return li_Diff; + } + + if (li_KeyDiff >= 0) + { + int li_Diff = 0; + k_Iterator lk_Fwd = ak_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + } + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override bool Equals(object ak_Obj) + { + k_NodeIterator lk_Iter = ak_Obj as k_NodeIterator; + if (lk_Iter == null) + return false; + return object.ReferenceEquals(mk_Current, lk_Iter.mk_Current); + } + + public override int GetHashCode() + { + if (mk_Current == null) + return mk_Tree.GetHashCode(); + return mk_Current.GetHashCode(); + } + + public override k_Iterator Clone() + { + return new k_NodeIterator(mk_Tree, mk_Current); + } + + internal k_Node Node + { + get { return mk_Current; } + } + } + + private class k_PinnedNodeIterator : k_NodeIterator + { + public k_PinnedNodeIterator(k_Tree ak_Tree, k_Node ak_Node) + : base(ak_Tree, ak_Node) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private k_Node mk_Head, mk_Left, mk_Right; + private k_Iterator mk_End; + private int mi_Count; + private IComparer mk_Comparer; + private bool mb_AllowDuplicateKeys; + + public k_Tree() + : this(false) + { + } + + public k_Tree(bool ab_AllowDuplicateKeys) + : this(ab_AllowDuplicateKeys, System.Collections.Comparer.Default) + { + } + + public k_Tree(bool ab_AllowDuplicateKeys, IComparer ak_Comparer) + { + mb_AllowDuplicateKeys = ab_AllowDuplicateKeys; + mk_Comparer = ak_Comparer; + mk_End = new k_PinnedNodeIterator(this, null); + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return this.End; + return new k_NodeIterator(this, mk_Left); + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + DictionaryEntry lr_Item = (DictionaryEntry)ak_Value; + k_Node lk_Found = FindInternal(mk_Head, lr_Item.Key); + if (lk_Found != null && mk_Comparer.Compare(lk_Found.Value, lr_Item.Value) == 0) + return new k_NodeIterator(this, lk_Found); + return this.End; + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this tree."); + k_Iterator lk_Successor = ak_Where + 1; + RemoveNode(((k_NodeIterator)ak_Where).Node); + return lk_Successor; + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + if (ak_First == this.Begin && ak_Last == this.End) + { + Clear(); + return ak_Last.Clone(); + } + + k_Iterator lk_Current = ak_First; + while (lk_Current != ak_Last) + lk_Current = Erase(lk_Current); + return lk_Current; + } + + // IMap Members + public void Add(DictionaryEntry ar_Item) + { + Add(ar_Item.Key, ar_Item.Value); + } + + public k_Iterator FindKey(object ak_Key) + { + return new k_NodeIterator(this, FindInternal(mk_Head, ak_Key)); + } + + public void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next()) + Add((DictionaryEntry)lk_Iter.Current); + } + + // ISortedMap Members + public IComparer Comparer + { + get { return mk_Comparer; } + } + + public k_Iterator LowerBound(object ak_Key) + { + k_Node lk_Node = mk_Head; + k_Node lk_Found = null; + while (lk_Node != null) + { + if (mk_Comparer.Compare(lk_Node.Key, ak_Key) < 0) + lk_Node = lk_Node.mk_Right; + else + { + lk_Found = lk_Node; + lk_Node = lk_Node.mk_Left; + } + } + return new k_NodeIterator(this, lk_Found); + } + + public k_Iterator UpperBound(object ak_Key) + { + k_Node lk_Node = mk_Head; + k_Node lk_Found = null; + while (lk_Node != null) + { + if (mk_Comparer.Compare(lk_Node.Key, ak_Key) > 0) + { + lk_Found = lk_Node; + lk_Node = lk_Node.mk_Left; + } + else + lk_Node = lk_Node.mk_Right; + } + return new k_NodeIterator(this, lk_Found); + } + + #region IDictionary Members + + public void Add(object ak_Key, object ak_Value) + { + Insert(ref mk_Head, null, ak_Key, ak_Value, false); + mk_Head.Red = false; + ++mi_Count; + } + + public void Clear() + { + mi_Count = 0; + mk_Head = null; + mk_Left = null; + mk_Right = null; + } + + public bool Contains(object ak_Key) + { + return (FindInternal(mk_Head, ak_Key) != null); + } + + public IDictionaryEnumerator GetEnumerator() + { + return new k_IteratorDictEnumerator(this.Begin, this.End); + } + + public void Remove(object ak_Key) + { + RemoveNode(FindInternal(mk_Head, ak_Key)); + } + + public bool IsFixedSize + { + get { return false; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public object this[object ak_Key] + { + get + { + k_Node lk_Node = FindInternal(mk_Head, ak_Key); + if (lk_Node == null) + return null; + return lk_Node.Value; + } + set + { + k_Node lk_Node = FindInternal(mk_Head, ak_Key); + if (lk_Node == null) + Add(new DictionaryEntry(ak_Key, value)); + else + lk_Node.Value = value; + } + } + + public ICollection Keys + { + get + { + int i=0; + object[] lk_Keys = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Keys[i++] = lr_Entry.Key; + return lk_Keys; + } + } + + public ICollection Values + { + get + { + int i=0; + object[] lk_Values = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Values[i++] = lr_Entry.Value; + return lk_Values; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (DictionaryEntry lr_Entry in this) + ak_Array.SetValue(lr_Entry, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_Tree lk_Clone = new k_Tree(mb_AllowDuplicateKeys, mk_Comparer); + lk_Clone.mi_Count = mi_Count; + CloneRecursive(mk_Head, null, ref lk_Clone.mk_Head); + lk_Clone.mk_Left = k_Tree.LeftMost(lk_Clone.mk_Head); + lk_Clone.mk_Right = k_Tree.RightMost(lk_Clone.mk_Head); + + return lk_Clone; + } + + #endregion + + private void CloneRecursive(k_Node ak_Node, k_Node ak_Parent, ref k_Node ak_Link) + { + if (ak_Node == null) + return; + + ak_Link = new k_Node(ak_Node.Key, ak_Node.Value, ak_Parent); + ak_Link.Red = ak_Node.Red; + + CloneRecursive(ak_Node.mk_Left, ak_Link, ref ak_Link.mk_Left); + CloneRecursive(ak_Node.mk_Right, ak_Link, ref ak_Link.mk_Right); + } + + private bool IsRed(k_Node ak_Node) + { + return (ak_Node != null && ak_Node.Red); + } + + private k_Node FindInternal(k_Node ak_Node, object ak_Key) + { + while (ak_Node != null) + { + int li_Diff = mk_Comparer.Compare(ak_Key, ak_Node.Key); + if (li_Diff == 0) + return ak_Node; + ak_Node = (li_Diff < 0) ? ak_Node.mk_Left : ak_Node.mk_Right; + } + return null; + } + + /// + /// Return leftmost node in subtree. + /// + /// Node where to start search + /// Found node + private static k_Node LeftMost(k_Node ak_Node) + { + if (ak_Node == null) + return null; + while (ak_Node.mk_Left != null) + ak_Node = ak_Node.mk_Left; + return ak_Node; + } + + /// + /// Return rightmost node in subtree. + /// + /// Node where to start search + /// Found node + private static k_Node RightMost(k_Node ak_Node) + { + if (ak_Node == null) + return null; + while (ak_Node.mk_Right != null) + ak_Node = ak_Node.mk_Right; + return ak_Node; + } + + private static k_Node Previous(k_Node ak_Node) // the next smaller + { + if (ak_Node.mk_Left != null) + return RightMost(ak_Node.mk_Left); + + k_Node lk_Parent = ak_Node.mk_Parent; + while (lk_Parent != null && lk_Parent.mk_Left == ak_Node) + { + ak_Node = lk_Parent; + lk_Parent = lk_Parent.mk_Parent; + } + return lk_Parent; + } + + private static k_Node Next(k_Node ak_Node) + { + if (ak_Node.mk_Right != null) + return LeftMost(ak_Node.mk_Right); + + k_Node lk_Parent = ak_Node.mk_Parent; + while (lk_Parent != null && lk_Parent.mk_Right == ak_Node) + { + ak_Node = lk_Parent; + lk_Parent = lk_Parent.mk_Parent; + } + return lk_Parent; + } + + private void RemoveNode(k_Node ak_Node) + { + if (ak_Node == null) + return; + if (ak_Node == mk_Head) + UnlinkNode(ref mk_Head); + else if (ak_Node == ak_Node.mk_Parent.mk_Right) + UnlinkNode(ref ak_Node.mk_Parent.mk_Right); + else + UnlinkNode(ref ak_Node.mk_Parent.mk_Left); + } + + private void UnlinkNode(ref k_Node ak_Node) + { + bool lb_Red = ak_Node.Red; + k_Node lk_Erased = ak_Node; + + k_Node lk_PatchNode = null; + if (ak_Node.mk_Right == null) + lk_PatchNode = ak_Node.mk_Left; + else if (ak_Node.mk_Left == null) + lk_PatchNode = ak_Node.mk_Right; + else + lk_PatchNode = ak_Node; + + k_Node lk_PatchParent = null, lk_FixNode = null; + if (lk_PatchNode == null) + { + lk_PatchParent = ak_Node.mk_Parent; + ak_Node = null; + } + else if (lk_PatchNode != ak_Node) + { + lk_PatchNode.mk_Parent = ak_Node.mk_Parent; + ak_Node = lk_PatchNode; + lk_PatchParent = lk_PatchNode.mk_Parent; + } + else + { + // two subtrees + lk_PatchNode = RightMost(ak_Node.mk_Left); + if (lk_PatchNode.mk_Parent.mk_Right == lk_PatchNode) + lk_PatchNode.mk_Parent.mk_Right = lk_PatchNode.mk_Left; + else + lk_PatchNode.mk_Parent.mk_Left = lk_PatchNode.mk_Left; + + lb_Red = lk_PatchNode.Red; + if (lk_PatchNode.mk_Left != null) + lk_PatchNode.mk_Left.mk_Parent = lk_PatchNode.mk_Parent; + + lk_PatchParent = lk_PatchNode.mk_Parent; + lk_FixNode = lk_PatchNode.mk_Left; + + k_Node.SwapItems(ak_Node, lk_PatchNode); + + // ensure that mk_Left and/or mk_Right are corrected after unlink + lk_Erased = lk_PatchNode; + } + + if (!lb_Red && lk_PatchParent != null) + { + // erased node was black link - rebalance the tree + while (!IsRed(lk_FixNode) && lk_FixNode != mk_Head) + { + if (lk_PatchParent.mk_Left != null || lk_PatchParent.mk_Right != null) + { + if (lk_PatchParent.mk_Left == lk_FixNode) + { + // fixup right subtree + k_Node lk_Node = lk_PatchParent.mk_Right; + + if (IsRed(lk_Node)) + { + lk_Node.Red = false; + lk_PatchParent.Red = true; + RotateLeft(lk_PatchParent); + lk_Node = lk_PatchParent.mk_Right; + } + + if (lk_Node != null) + { + if (!IsRed(lk_Node.mk_Left) && !IsRed(lk_Node.mk_Right)) + lk_Node.Red = true; + else + { + if (!IsRed(lk_Node.mk_Right)) + { + lk_Node.Red = true; + lk_Node.mk_Left.Red = false; + RotateRight(lk_Node); + lk_Node = lk_PatchParent.mk_Right; + } + + lk_Node.Red = lk_PatchParent.Red; + lk_PatchParent.Red = false; + lk_Node.mk_Right.Red = false; + RotateLeft(lk_PatchParent); + break; + } + } + } + else + { + // fixup leftsubtree + k_Node lk_Node = lk_PatchParent.mk_Left; + + if (IsRed(lk_Node)) + { + lk_Node.Red = false; + lk_PatchParent.Red = true; + RotateRight(lk_PatchParent); + lk_Node = lk_PatchParent.mk_Left; + } + + if (lk_Node != null) + { + if (!IsRed(lk_Node.mk_Left) && !IsRed(lk_Node.mk_Right)) + lk_Node.Red = true; + else + { + if (!IsRed(lk_Node.mk_Left)) + { + lk_Node.Red = true; + lk_Node.mk_Right.Red = false; + RotateLeft(lk_Node); + lk_Node = lk_PatchParent.mk_Left; + } + + lk_Node.Red = lk_PatchParent.Red; + lk_PatchParent.Red = false; + lk_Node.mk_Left.Red = false; + RotateRight(lk_PatchParent); + break; + } + } + } + } + lk_FixNode = lk_PatchParent; + lk_PatchParent = lk_PatchParent.mk_Parent; + } + + if (lk_FixNode != null) + lk_FixNode.Red = false; + } + + --mi_Count; + + if (object.ReferenceEquals(lk_Erased, mk_Right)) + mk_Right = k_Tree.RightMost(mk_Head); + if (object.ReferenceEquals(lk_Erased, mk_Left)) + mk_Left = k_Tree.LeftMost(mk_Head); + } + + private void Insert(ref k_Node ak_Node, k_Node ak_Parent, object ak_Key, object ak_Value, bool ab_RightMove) + { + if (ak_Node == null) + { + ak_Node = new k_Node(ak_Key, ak_Value, ak_Parent); + if (object.ReferenceEquals(ak_Parent, mk_Right) && (ak_Parent == null || ab_RightMove)) + mk_Right = ak_Node; + if (object.ReferenceEquals(ak_Parent, mk_Left) && (ak_Parent == null || !ab_RightMove)) + mk_Left = ak_Node; + return; + } + + if (IsRed(ak_Node.mk_Left) && IsRed(ak_Node.mk_Right)) + { + ak_Node.Red = true; + ak_Node.mk_Left.Red = false; + ak_Node.mk_Right.Red = false; + } + + int li_Diff = mk_Comparer.Compare(ak_Key, ak_Node.Key); + if (!mb_AllowDuplicateKeys && li_Diff == 0) + throw new ArgumentException("An element with the same key already exists in the tree."); + + if (li_Diff < 0) + { + Insert(ref ak_Node.mk_Left, ak_Node, ak_Key, ak_Value, false); + if (IsRed(ak_Node) && IsRed(ak_Node.mk_Left) && ab_RightMove) + ak_Node = RotateRight(ak_Node); + if (IsRed(ak_Node.mk_Left) && IsRed(ak_Node.mk_Left.mk_Left)) + { + ak_Node = RotateRight(ak_Node); + ak_Node.Red = false; + ak_Node.mk_Right.Red = true; + } + } + else + { + Insert(ref ak_Node.mk_Right, ak_Node, ak_Key, ak_Value, true); + if (IsRed(ak_Node) && IsRed(ak_Node.mk_Right) && !ab_RightMove) + ak_Node = RotateLeft(ak_Node); + if (IsRed(ak_Node.mk_Right) && IsRed(ak_Node.mk_Right.mk_Right)) + { + ak_Node = RotateLeft(ak_Node); + ak_Node.Red = false; + ak_Node.mk_Left.Red = true; + } + } + } + + /* + A right rotation: ak_Node.Left takes old position of ak_Node. + Makes the old root the right subtree of the new root. + + 5 2 + 2 7 -> 1 5 + 1 3 6 8 3 7 + 6 8 + */ + private k_Node RotateRight(k_Node ak_Node) + { + k_Node lk_Tmp = ak_Node.mk_Left; + + lk_Tmp.mk_Parent = ak_Node.mk_Parent; + ak_Node.mk_Parent = lk_Tmp; + + ak_Node.mk_Left = lk_Tmp.mk_Right; + if (ak_Node.mk_Left != null) + ak_Node.mk_Left.mk_Parent = ak_Node; + lk_Tmp.mk_Right = ak_Node; + + // correct parent + if (lk_Tmp.mk_Parent == null) + mk_Head = lk_Tmp; + else if (lk_Tmp.mk_Parent.mk_Right == ak_Node) + lk_Tmp.mk_Parent.mk_Right = lk_Tmp; + else + lk_Tmp.mk_Parent.mk_Left = lk_Tmp; + + return lk_Tmp; + } + + /* + A left rotation: ak_Node.Right takes old position of ak_Node. + Makes the old root the left subtree of the new root. + + 5 7 + 2 7 -> 5 8 + 1 3 6 8 2 6 + 1 3 + */ + private k_Node RotateLeft(k_Node ak_Node) + { + k_Node lk_Tmp = ak_Node.mk_Right; + + lk_Tmp.mk_Parent = ak_Node.mk_Parent; + ak_Node.mk_Parent = lk_Tmp; + + ak_Node.mk_Right = lk_Tmp.mk_Left; + if (ak_Node.mk_Right != null) + ak_Node.mk_Right.mk_Parent = ak_Node; + lk_Tmp.mk_Left = ak_Node; + + // correct parent + if (lk_Tmp.mk_Parent == null) + mk_Head = lk_Tmp; + else if (lk_Tmp.mk_Parent.mk_Right == ak_Node) + lk_Tmp.mk_Parent.mk_Right = lk_Tmp; + else + lk_Tmp.mk_Parent.mk_Left = lk_Tmp; + + return lk_Tmp; + } + } +} diff --git a/iTechSharp/System/util/collections/Vector.cs b/iTechSharp/System/util/collections/Vector.cs new file mode 100644 index 0000000..0ab80d6 --- /dev/null +++ b/iTechSharp/System/util/collections/Vector.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// One dimensional array of variable size + /// + public class k_Vector : ArrayList, ISequence + { + public k_Vector() + : base() + { + } + + public k_Vector(int ai_Capacity) + : base(ai_Capacity) + { + } + + public k_Vector(ICollection ak_Collection) + : base(ak_Collection) + { + } + + // IContainer Members + public k_Iterator Begin + { + get { return k_IListIterator.CreateBegin(this); } + } + + public k_Iterator End + { + get { return k_IListIterator.CreateEnd(this); } + } + + public bool IsEmpty + { + get { return (this.Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + int li_Index = this.IndexOf(ak_Value); + if (li_Index < 0) + return this.End; + return new k_IListIterator(this, li_Index); + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + int li_Index = ((k_IListIterator)ak_Where).Index; + if (li_Index < this.Count) + base.RemoveAt(li_Index); + return new k_IListIterator(this, li_Index); + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_First.Collection) && object.ReferenceEquals(this, ak_Last.Collection), "Iterators do not belong to this collection."); + int li_FirstIndex = ((k_IListIterator)ak_First).Index; + int li_Count = ak_Last - ak_First; + + base.RemoveRange(li_FirstIndex, li_Count); + + return new k_IListIterator(this, li_FirstIndex); + } + + // ISequence Members + public object Front + { + get { return this.Begin.Current; } + set { this.Begin.Current = value; } + } + + public object Back + { + get { return (this.End-1).Current; } + set { (this.End-1).Current = value; } + } + + public void PushFront(object ak_Value) + { + Insert(this.Begin, ak_Value); + } + + public void PopFront() + { + Erase(this.Begin); + } + + public void PushBack(object ak_Value) + { + Insert(this.End, ak_Value); + } + + public void PopBack() + { + Erase(this.End-1); + } + + public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + Clear(); + Insert(this.End, ak_SrcBegin, ak_SrcEnd); + } + + public void Assign(object ak_Value, int ai_Count) + { + Clear(); + Insert(this.End, ak_Value, ai_Count); + } + + public void Insert(k_Iterator ak_Where, object ak_Value) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + this.Insert(((k_IListIterator)ak_Where).Index, ak_Value); + } + + public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + InsertRange(((k_IListIterator)ak_Where).Index, new k_CollectionOnIterators(ak_SrcBegin, ak_SrcEnd)); + } + + public void Insert(k_Iterator ak_Where, object ak_Value, int ai_Count) + { + int li_Pos = ((k_IListIterator)ak_Where).Index; + for (int i=0; i>16)&0xffff; + int k; + + while(len > 0) { + k=len=16){ + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + k-=16; + } + if(k!=0){ + do{ + s1+=buf[index++]&0xff; s2+=s1; + } + while(--k!=0); + } + s1%=BASE; + s2%=BASE; + } + return (s2<<16)|s1; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/Deflate.cs b/iTechSharp/System/util/zlib/Deflate.cs new file mode 100644 index 0000000..09353a8 --- /dev/null +++ b/iTechSharp/System/util/zlib/Deflate.cs @@ -0,0 +1,1639 @@ +using System; +/* + * $Id: Deflate.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + public sealed class Deflate{ + + private const int MAX_MEM_LEVEL=9; + + private const int Z_DEFAULT_COMPRESSION=-1; + + private const int MAX_WBITS=15; // 32K LZ77 window + private const int DEF_MEM_LEVEL=8; + + internal class Config{ + internal int good_length; // reduce lazy search above this match length + internal int max_lazy; // do not perform lazy search above this match length + internal int nice_length; // quit search above this match length + internal int max_chain; + internal int func; + internal Config(int good_length, int max_lazy, + int nice_length, int max_chain, int func){ + this.good_length=good_length; + this.max_lazy=max_lazy; + this.nice_length=nice_length; + this.max_chain=max_chain; + this.func=func; + } + } + + private const int STORED=0; + private const int FAST=1; + private const int SLOW=2; + private static Config[] config_table; + static Deflate(){ + config_table=new Config[10]; + // good lazy nice chain + config_table[0]=new Config(0, 0, 0, 0, STORED); + config_table[1]=new Config(4, 4, 8, 4, FAST); + config_table[2]=new Config(4, 5, 16, 8, FAST); + config_table[3]=new Config(4, 6, 32, 32, FAST); + + config_table[4]=new Config(4, 4, 16, 16, SLOW); + config_table[5]=new Config(8, 16, 32, 32, SLOW); + config_table[6]=new Config(8, 16, 128, 128, SLOW); + config_table[7]=new Config(8, 32, 128, 256, SLOW); + config_table[8]=new Config(32, 128, 258, 1024, SLOW); + config_table[9]=new Config(32, 258, 258, 4096, SLOW); + } + + private static String[] z_errmsg = { + "need dictionary", // Z_NEED_DICT 2 + "stream end", // Z_STREAM_END 1 + "", // Z_OK 0 + "file error", // Z_ERRNO (-1) + "stream error", // Z_STREAM_ERROR (-2) + "data error", // Z_DATA_ERROR (-3) + "insufficient memory", // Z_MEM_ERROR (-4) + "buffer error", // Z_BUF_ERROR (-5) + "incompatible version",// Z_VERSION_ERROR (-6) + "" + }; + + // block not completed, need more input or more output + private const int NeedMore=0; + + // block flush performed + private const int BlockDone=1; + + // finish started, need only more output at next deflate + private const int FinishStarted=2; + + // finish done, accept no more input or output + private const int FinishDone=3; + + // preset dictionary flag in zlib header + private const int PRESET_DICT=0x20; + + private const int Z_FILTERED=1; + private const int Z_HUFFMAN_ONLY=2; + private const int Z_DEFAULT_STRATEGY=0; + + private const int Z_NO_FLUSH=0; + private const int Z_PARTIAL_FLUSH=1; + private const int Z_SYNC_FLUSH=2; + private const int Z_FULL_FLUSH=3; + private const int Z_FINISH=4; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int INIT_STATE=42; + private const int BUSY_STATE=113; + private const int FINISH_STATE=666; + + // The deflate compression method + private const int Z_DEFLATED=8; + + private const int STORED_BLOCK=0; + private const int STATIC_TREES=1; + private const int DYN_TREES=2; + + // The three kinds of block type + private const int Z_BINARY=0; + private const int Z_ASCII=1; + private const int Z_UNKNOWN=2; + + private const int Buf_size=8*2; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + private const int REP_3_6=16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + private const int REPZ_3_10=17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + private const int REPZ_11_138=18; + + private const int MIN_MATCH=3; + private const int MAX_MATCH=258; + private const int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1); + + private const int MAX_BITS=15; + private const int D_CODES=30; + private const int BL_CODES=19; + private const int LENGTH_CODES=29; + private const int LITERALS=256; + private const int L_CODES=(LITERALS+1+LENGTH_CODES); + private const int HEAP_SIZE=(2*L_CODES+1); + + private const int END_BLOCK=256; + + internal ZStream strm; // pointer back to this zlib stream + internal int status; // as the name implies + internal byte[] pending_buf; // output still pending + internal int pending_buf_size; // size of pending_buf + internal int pending_out; // next pending byte to output to the stream + internal int pending; // nb of bytes in the pending buffer + internal int noheader; // suppress zlib header and adler32 + internal byte data_type; // UNKNOWN, BINARY or ASCII + internal byte method; // STORED (for zip only) or DEFLATED + internal int last_flush; // value of flush param for previous deflate call + + internal int w_size; // LZ77 window size (32K by default) + internal int w_bits; // log2(w_size) (8..16) + internal int w_mask; // w_size - 1 + + internal byte[] window; + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least wSize + // bytes. With this organization, matches are limited to a distance of + // wSize-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. Also, it limits + // the window size to 64K, which is quite useful on MSDOS. + // To do: use the user input buffer as sliding window. + + internal int window_size; + // Actual size of window: 2*wSize, except when the user input buffer + // is directly used as sliding window. + + internal short[] prev; + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + + internal short[] head; // Heads of the hash chains or NIL. + + internal int ins_h; // hash index of string to be inserted + internal int hash_size; // number of elements in hash table + internal int hash_bits; // log2(hash_size) + internal int hash_mask; // hash_size-1 + + // Number of bits by which ins_h must be shifted at each input + // step. It must be such that after MIN_MATCH steps, the oldest + // byte no longer takes part in the hash key, that is: + // hash_shift * MIN_MATCH >= hash_bits + internal int hash_shift; + + // Window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + internal int block_start; + + internal int match_length; // length of best match + internal int prev_match; // previous match + internal int match_available; // set if previous match exists + internal int strstart; // start of string to insert + internal int match_start; // start of matching string + internal int lookahead; // number of valid bytes ahead in window + + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + internal int prev_length; + + // To speed up deflation, hash chains are never searched beyond this + // length. A higher limit improves compression ratio but degrades the speed. + internal int max_chain_length; + + // Attempt to find a better match only when the current match is strictly + // smaller than this value. This mechanism is used only for compression + // levels >= 4. + internal int max_lazy_match; + + // Insert new strings in the hash table only if the match length is not + // greater than this length. This saves time but degrades compression. + // max_insert_length is used only for compression levels <= 3. + + internal int level; // compression level (1..9) + internal int strategy; // favor or force Huffman coding + + // Use a faster search when the previous match is longer than this + internal int good_match; + + // Stop searching when current match exceeds this + internal int nice_match; + + internal short[] dyn_ltree; // literal and length tree + internal short[] dyn_dtree; // distance tree + internal short[] bl_tree; // Huffman tree for bit lengths + + internal Tree l_desc=new Tree(); // desc for literal tree + internal Tree d_desc=new Tree(); // desc for distance tree + internal Tree bl_desc=new Tree(); // desc for bit length tree + + // number of codes at each bit length for an optimal tree + internal short[] bl_count=new short[MAX_BITS+1]; + + // heap used to build the Huffman trees + internal int[] heap=new int[2*L_CODES+1]; + + internal int heap_len; // number of elements in the heap + internal int heap_max; // element of largest frequency + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + // Depth of each subtree used as tie breaker for trees of equal frequency + internal byte[] depth=new byte[2*L_CODES+1]; + + internal int l_buf; // index for literals or lengths */ + + // Size of match buffer for literals/lengths. There are 4 reasons for + // limiting lit_bufsize to 64K: + // - frequencies can be kept in 16 bit counters + // - if compression is not successful for the first block, all input + // data is still in the window so we can still emit a stored block even + // when input comes from standard input. (This can also be done for + // all blocks if lit_bufsize is not greater than 32K.) + // - if compression is not successful for a file smaller than 64K, we can + // even emit a stored file instead of a stored block (saving 5 bytes). + // This is applicable only for zip (not gzip or zlib). + // - creating new Huffman trees less frequently may not provide fast + // adaptation to changes in the input data statistics. (Take for + // example a binary file with poorly compressible code followed by + // a highly compressible string table.) Smaller buffer sizes give + // fast adaptation but have of course the overhead of transmitting + // trees more frequently. + // - I can't count above 4 + internal int lit_bufsize; + + internal int last_lit; // running index in l_buf + + // Buffer for distances. To simplify the code, d_buf and l_buf have + // the same number of elements. To use different lengths, an extra flag + // array would be necessary. + + internal int d_buf; // index of pendig_buf + + internal int opt_len; // bit length of current block with optimal trees + internal int static_len; // bit length of current block with static trees + internal int matches; // number of string matches in current block + internal int last_eob_len; // bit length of EOB code for last block + + // Output buffer. bits are inserted starting at the bottom (least + // significant bits). + internal uint bi_buf; + + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + internal int bi_valid; + + internal Deflate(){ + dyn_ltree=new short[HEAP_SIZE*2]; + dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree + bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths + } + + internal void lm_init() { + window_size=2*w_size; + + head[hash_size-1]=0; + for(int i=0; i= 3; max_blindex--) { + if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break; + } + // Update opt_len to include the bit length tree and counts + opt_len += 3*(max_blindex+1) + 5+5+4; + + return max_blindex; + } + + + // Send the header for a block using dynamic Huffman trees: the counts, the + // lengths of the bit length codes, the literal tree and the distance tree. + // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + internal void send_all_trees(int lcodes, int dcodes, int blcodes){ + int rank; // index in bl_order + + send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes-1, 5); + send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) { + send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3); + } + send_tree(dyn_ltree, lcodes-1); // literal tree + send_tree(dyn_dtree, dcodes-1); // distance tree + } + + // Send a literal or distance tree in compressed form, using the codes in + // bl_tree. + internal void send_tree (short[] tree,// the tree to be sent + int max_code // and its largest code of non zero frequency + ){ + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0*2+1]; // length of next code + int count = 0; // repeat count of the current code + int max_count = 7; // max repeat count + int min_count = 4; // min repeat count + + if (nextlen == 0){ max_count = 138; min_count = 3; } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[(n+1)*2+1]; + if(++count < max_count && curlen == nextlen) { + continue; + } + else if(count < min_count) { + do { send_code(curlen, bl_tree); } while (--count != 0); + } + else if(curlen != 0){ + if(curlen != prevlen){ + send_code(curlen, bl_tree); count--; + } + send_code(REP_3_6, bl_tree); + send_bits(count-3, 2); + } + else if(count <= 10){ + send_code(REPZ_3_10, bl_tree); + send_bits(count-3, 3); + } + else{ + send_code(REPZ_11_138, bl_tree); + send_bits(count-11, 7); + } + count = 0; prevlen = curlen; + if(nextlen == 0){ + max_count = 138; min_count = 3; + } + else if(curlen == nextlen){ + max_count = 6; min_count = 3; + } + else{ + max_count = 7; min_count = 4; + } + } + } + + // Output a byte on the stream. + // IN assertion: there is enough room in pending_buf. + internal void put_byte(byte[] p, int start, int len){ + System.Array.Copy(p, start, pending_buf, pending, len); + pending+=len; + } + + internal void put_byte(byte c){ + pending_buf[pending++]=c; + } + internal void put_short(int w) { + pending_buf[pending++]=(byte)(w/*&0xff*/); + pending_buf[pending++]=(byte)(w>>8); + } + internal void putShortMSB(int b){ + pending_buf[pending++]=(byte)(b>>8); + pending_buf[pending++]=(byte)(b/*&0xff*/); + } + + internal void send_code(int c, short[] tree){ + int c2=c*2; + send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff)); + } + + internal void send_bits(int val, int length){ + if (bi_valid > Buf_size - length) { + bi_buf |= (uint)(val << bi_valid); + pending_buf[pending++]=(byte)(bi_buf/*&0xff*/); + pending_buf[pending++]=(byte)(bi_buf>>8); + bi_buf = ((uint)val) >> (Buf_size - bi_valid); + bi_valid += length - Buf_size; + } else { + bi_buf |= (uint)(val << bi_valid); + bi_valid += length; + } +// int len = length; +// if (bi_valid > (int)Buf_size - len) { +// int val = value; +// // bi_buf |= (val << bi_valid); +// bi_buf = (short)((ushort)bi_buf | (ushort)((val << bi_valid)&0xffff)); +// put_short(bi_buf); +// bi_buf = (short)(((uint)val) >> (Buf_size - bi_valid)); +// bi_valid += len - Buf_size; +// } else { +// // bi_buf |= (value) << bi_valid; +// bi_buf = (short)((ushort)bi_buf | (ushort)(((value) << bi_valid)&0xffff)); +// bi_valid += len; +// } + } + + // Send one empty static block to give enough lookahead for inflate. + // This takes 10 bits, of which 7 may remain in the bit buffer. + // The current inflate code requires 9 bits of lookahead. If the + // last two codes for the previous block (real code plus EOB) were coded + // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + // the last real code. In this case we send two empty static blocks instead + // of one. (There are no problems if the previous block is stored or fixed.) + // To simplify the code, we assume the worst case of last real code encoded + // on one bit only. + internal void _tr_align(){ + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + + bi_flush(); + + // Of the 10 bits for the empty block, we have already sent + // (10 - bi_valid) bits. The lookahead for the last real code (before + // the EOB of the previous block) was thus at least one plus the length + // of the EOB plus what we have just sent of the empty static block. + if (1 + last_eob_len + 10 - bi_valid < 9) { + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + bi_flush(); + } + last_eob_len = 7; + } + + + // Save the match info and tally the frequency counts. Return true if + // the current block must be flushed. + internal bool _tr_tally (int dist, // distance of matched string + int lc // match length-MIN_MATCH or unmatched char (if dist==0) + ){ + + pending_buf[d_buf+last_lit*2] = (byte)(dist>>8); + pending_buf[d_buf+last_lit*2+1] = (byte)dist; + + pending_buf[l_buf+last_lit] = (byte)lc; last_lit++; + + if (dist == 0) { + // lc is the unmatched char + dyn_ltree[lc*2]++; + } + else { + matches++; + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++; + dyn_dtree[Tree.d_code(dist)*2]++; + } + + if ((last_lit & 0x1fff) == 0 && level > 2) { + // Compute an upper bound for the compressed length + int out_length = last_lit*8; + int in_length = strstart - block_start; + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (int)((int)dyn_dtree[dcode*2] * + (5L+Tree.extra_dbits[dcode])); + } + out_length >>= 3; + if ((matches < (last_lit/2)) && out_length < in_length/2) return true; + } + + return (last_lit == lit_bufsize-1); + // We avoid equality with lit_bufsize because of wraparound at 64K + // on 16 bit machines and because stored blocks are restricted to + // 64K-1 bytes. + } + + // Send the block data compressed using the given Huffman trees + internal void compress_block(short[] ltree, short[] dtree){ + int dist; // distance of matched string + int lc; // match length or unmatched char (if dist == 0) + int lx = 0; // running index in l_buf + int code; // the code to send + int extra; // number of extra bits to send + + if (last_lit != 0){ + do{ + dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)| + (pending_buf[d_buf+lx*2+1]&0xff); + lc=(pending_buf[l_buf+lx])&0xff; lx++; + + if(dist == 0){ + send_code(lc, ltree); // send a literal byte + } + else{ + // Here, lc is the match length - MIN_MATCH + code = Tree._length_code[lc]; + + send_code(code+LITERALS+1, ltree); // send the length code + extra = Tree.extra_lbits[code]; + if(extra != 0){ + lc -= Tree.base_length[code]; + send_bits(lc, extra); // send the extra length bits + } + dist--; // dist is now the match distance - 1 + code = Tree.d_code(dist); + + send_code(code, dtree); // send the distance code + extra = Tree.extra_dbits[code]; + if (extra != 0) { + dist -= Tree.base_dist[code]; + send_bits(dist, extra); // send the extra distance bits + } + } // literal or match pair ? + + // Check that the overlay between pending_buf and d_buf+l_buf is ok: + } + while (lx < last_lit); + } + + send_code(END_BLOCK, ltree); + last_eob_len = ltree[END_BLOCK*2+1]; + } + + // Set the data type to ASCII or BINARY, using a crude approximation: + // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + // IN assertion: the fields freq of dyn_ltree are set and the total of all + // frequencies does not exceed 64K (to fit in an int on 16 bit machines). + internal void set_data_type(){ + int n = 0; + int ascii_freq = 0; + int bin_freq = 0; + while(n<7){ bin_freq += dyn_ltree[n*2]; n++;} + while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;} + while(n (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); + } + + // Flush the bit buffer, keeping at most 7 bits in it. + internal void bi_flush(){ + if (bi_valid == 16) { + pending_buf[pending++]=(byte)(bi_buf/*&0xff*/); + pending_buf[pending++]=(byte)(bi_buf>>8); + bi_buf=0; + bi_valid=0; + } + else if (bi_valid >= 8) { + pending_buf[pending++]=(byte)(bi_buf); + bi_buf>>=8; + bi_buf &= 0x00ff; + bi_valid-=8; + } + } + + // Flush the bit buffer and align the output on a byte boundary + internal void bi_windup(){ + if (bi_valid > 8) { + pending_buf[pending++]=(byte)(bi_buf); + pending_buf[pending++]=(byte)(bi_buf>>8); + } else if (bi_valid > 0) { + pending_buf[pending++]=(byte)(bi_buf); + } + bi_buf = 0; + bi_valid = 0; + } + + // Copy a stored block, storing first the length and its + // one's complement if requested. + internal void copy_block(int buf, // the input data + int len, // its length + bool header // true if block header must be written + ){ + //int index=0; + bi_windup(); // align on byte boundary + last_eob_len = 8; // enough lookahead for inflate + + if (header) { + put_short((short)len); + put_short((short)~len); + } + + // while(len--!=0) { + // put_byte(window[buf+index]); + // index++; + // } + put_byte(window, buf, len); + } + + internal void flush_block_only(bool eof){ + _tr_flush_block(block_start>=0 ? block_start : -1, + strstart-block_start, + eof); + block_start=strstart; + strm.flush_pending(); + } + + // Copy without compression as much as possible from the input stream, return + // the current block state. + // This function does not insert new strings in the dictionary since + // uncompressible data is probably not useful. This function is used + // only for the level=0 compression option. + // NOTE: this function should be optimized to avoid extra copying from + // window to pending_buf. + internal int deflate_stored(int flush){ + // Stored blocks are limited to 0xffff bytes, pending_buf is limited + // to pending_buf_size, and each stored block has a 5 byte header: + + int max_block_size = 0xffff; + int max_start; + + if(max_block_size > pending_buf_size - 5) { + max_block_size = pending_buf_size - 5; + } + + // Copy as much as possible from input to output: + while(true){ + // Fill the window as much as possible: + if(lookahead<=1){ + fill_window(); + if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore; + if(lookahead==0) break; // flush the current block + } + + strstart+=lookahead; + lookahead=0; + + // Emit a stored block if pending_buf will be full: + max_start=block_start+max_block_size; + if(strstart==0|| strstart>=max_start) { + // strstart == 0 is possible when wraparound on 16-bit machine + lookahead = (int)(strstart-max_start); + strstart = (int)max_start; + + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + + } + + // Flush if we may have to slide, otherwise block_start may become + // negative and the data will be gone: + if(strstart-block_start >= w_size-MIN_LOOKAHEAD) { + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + } + } + + flush_block_only(flush == Z_FINISH); + if(strm.avail_out==0) + return (flush == Z_FINISH) ? FinishStarted : NeedMore; + + return flush == Z_FINISH ? FinishDone : BlockDone; + } + + // Send a stored block + internal void _tr_stored_block(int buf, // input block + int stored_len, // length of input block + bool eof // true if this is the last block for a file + ){ + send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type + copy_block(buf, stored_len, true); // with header + } + + // Determine the best encoding for the current block: dynamic trees, static + // trees or store, and output the encoded block to the zip file. + internal void _tr_flush_block(int buf, // input block, or NULL if too old + int stored_len, // length of input block + bool eof // true if this is the last block for a file + ) { + int opt_lenb, static_lenb;// opt_len and static_len in bytes + int max_blindex = 0; // index of last bit length code of non zero freq + + // Build the Huffman trees unless a stored block is forced + if(level > 0) { + // Check if the file is ascii or binary + if(data_type == Z_UNKNOWN) set_data_type(); + + // Construct the literal and distance trees + l_desc.build_tree(this); + + d_desc.build_tree(this); + + // At this point, opt_len and static_len are the total bit lengths of + // the compressed block data, excluding the tree representations. + + // Build the bit length tree for the above two trees, and get the index + // in bl_order of the last bit length code to send. + max_blindex=build_bl_tree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb=(opt_len+3+7)>>3; + static_lenb=(static_len+3+7)>>3; + + if(static_lenb<=opt_lenb) opt_lenb=static_lenb; + } + else { + opt_lenb=static_lenb=stored_len+5; // force a stored block + } + + if(stored_len+4<=opt_lenb && buf != -1){ + // 4: two words for the lengths + // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + // Otherwise we can't have processed more than WSIZE input bytes since + // the last block flush, because compression would have been + // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + // transform a block into a stored block. + _tr_stored_block(buf, stored_len, eof); + } + else if(static_lenb == opt_lenb){ + send_bits((STATIC_TREES<<1)+(eof?1:0), 3); + compress_block(StaticTree.static_ltree, StaticTree.static_dtree); + } + else{ + send_bits((DYN_TREES<<1)+(eof?1:0), 3); + send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1); + compress_block(dyn_ltree, dyn_dtree); + } + + // The above check is made mod 2^32, for files larger than 512 MB + // and uLong implemented on 32 bits. + + init_block(); + + if(eof){ + bi_windup(); + } + } + + // Fill the window when the lookahead becomes insufficient. + // Updates strstart and lookahead. + // + // IN assertion: lookahead < MIN_LOOKAHEAD + // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + // At least one byte has been read, or avail_in == 0; reads are + // performed for at least two bytes (required for the zip translate_eol + // option -- not supported here). + internal void fill_window(){ + int n, m; + int p; + int more; // Amount of free space at the end of the window. + + do{ + more = (window_size-lookahead-strstart); + + // Deal with !@#$% 64K limit: + if(more==0 && strstart==0 && lookahead==0){ + more = w_size; + } + else if(more==-1) { + // Very unlikely, but possible on 16 bit machine if strstart == 0 + // and lookahead == 1 (input done one byte at time) + more--; + + // If the window is almost full and there is insufficient lookahead, + // move the upper half to the lower one to make room in the upper half. + } + else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) { + System.Array.Copy(window, w_size, window, 0, w_size); + match_start-=w_size; + strstart-=w_size; // we now have strstart >= MAX_DIST + block_start-=w_size; + + // Slide the hash table (could be avoided with 32 bit values + // at the expense of memory usage). We slide even when level == 0 + // to keep the hash table consistent if we switch back to level > 0 + // later. (Using level 0 permanently is not an optimal usage of + // zlib, so we don't care about this pathological case.) + + n = hash_size; + p=n; + do { + m = (head[--p]&0xffff); + head[p]=(short)(m>=w_size ? (m-w_size) : 0); + } + while (--n != 0); + + n = w_size; + p = n; + do { + m = (prev[--p]&0xffff); + prev[p] = (short)(m >= w_size ? (m-w_size) : 0); + // If n is not on any hash chain, prev[n] is garbage but + // its value will never be used. + } + while (--n!=0); + more += w_size; + } + + if (strm.avail_in == 0) return; + + // If there was no sliding: + // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + // more == window_size - lookahead - strstart + // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + // => more >= window_size - 2*WSIZE + 2 + // In the BIG_MEM or MMAP case (not yet supported), + // window_size == input_size + MIN_LOOKAHEAD && + // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + // Otherwise, window_size == 2*WSIZE so more >= 2. + // If there was sliding, more >= WSIZE. So in all cases, more >= 2. + + n = strm.read_buf(window, strstart + lookahead, more); + lookahead += n; + + // Initialize the hash value now that we have some input: + if(lookahead >= MIN_MATCH) { + ins_h = window[strstart]&0xff; + ins_h=(((ins_h)<= MIN_MATCH){ + ins_h=(((ins_h)<=MIN_MATCH){ + // check_match(strstart, match_start, match_length); + + bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if(match_length <= max_lazy_match && + lookahead >= MIN_MATCH) { + match_length--; // string at strstart already in hash table + do{ + strstart++; + + ins_h=((ins_h<= MIN_MATCH) { + ins_h=(((ins_h)< 4096))) { + + // If prev_match is also MIN_MATCH, match_start is garbage + // but we will ignore the current match anyway. + match_length = MIN_MATCH-1; + } + } + + // If there was a match at the previous step and the current + // match is not better, output the previous match: + if(prev_length >= MIN_MATCH && match_length <= prev_length) { + int max_insert = strstart + lookahead - MIN_MATCH; + // Do not insert strings in hash table beyond this. + + // check_match(strstart-1, prev_match, prev_length); + + bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH); + + // Insert in hash table all strings up to the end of the match. + // strstart-1 and strstart are already inserted. If there is not + // enough lookahead, the last two strings are not inserted in + // the hash table. + lookahead -= prev_length-1; + prev_length -= 2; + do{ + if(++strstart <= max_insert) { + ins_h=(((ins_h)<(w_size-MIN_LOOKAHEAD) ? + strstart-(w_size-MIN_LOOKAHEAD) : 0; + int nice_match=this.nice_match; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0. + + int wmask = w_mask; + + int strend = strstart + MAX_MATCH; + byte scan_end1 = window[scan+best_len-1]; + byte scan_end = window[scan+best_len]; + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + + // Do not waste too much time if we already have a good match: + if (prev_length >= good_match) { + chain_length >>= 2; + } + + // Do not look for matches beyond the end of the input. This is necessary + // to make deflate deterministic. + if (nice_match > lookahead) nice_match = lookahead; + + do { + match = cur_match; + + // Skip to next match if the match length cannot increase + // or if the match length is less than 2: + if (window[match+best_len] != scan_end || + window[match+best_len-1] != scan_end1 || + window[match] != window[scan] || + window[++match] != window[scan+1]) continue; + + // The check at best_len-1 can be removed because it will be made + // again later. (This heuristic is not always a win.) + // It is not necessary to compare scan[2] and match[2] since they + // are always equal when the other bytes match, given that + // the hash keys are equal and that HASH_BITS >= 8. + scan += 2; match++; + + // We check for insufficient lookahead only every 8th comparison; + // the 256th check will be made at strstart+258. + do { + } while (window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + scan < strend); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + + if(len>best_len) { + match_start = cur_match; + best_len = len; + if (len >= nice_match) break; + scan_end1 = window[scan+best_len-1]; + scan_end = window[scan+best_len]; + } + + } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit + && --chain_length != 0); + + if (best_len <= lookahead) return best_len; + return lookahead; + } + + internal int deflateInit(ZStream strm, int level, int bits){ + return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY); + } + internal int deflateInit(ZStream strm, int level){ + return deflateInit(strm, level, MAX_WBITS); + } + internal int deflateInit2(ZStream strm, int level, int method, int windowBits, + int memLevel, int strategy){ + int noheader = 0; + // byte[] my_version=ZLIB_VERSION; + + // + // if (version == null || version[0] != my_version[0] + // || stream_size != sizeof(z_stream)) { + // return Z_VERSION_ERROR; + // } + + strm.msg = null; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { // undocumented feature: suppress zlib header + noheader = 1; + windowBits = -windowBits; + } + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || + method != Z_DEFLATED || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + strm.dstate = (Deflate)this; + + this.noheader = noheader; + w_bits = windowBits; + w_size = 1 << w_bits; + w_mask = w_size - 1; + + hash_bits = memLevel + 7; + hash_size = 1 << hash_bits; + hash_mask = hash_size - 1; + hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH); + + window = new byte[w_size*2]; + prev = new short[w_size]; + head = new short[hash_size]; + + lit_bufsize = 1 << (memLevel + 6); // 16K elements by default + + // We overlay pending_buf and d_buf+l_buf. This works since the average + // output size for (length,distance) codes is <= 24 bits. + pending_buf = new byte[lit_bufsize*4]; + pending_buf_size = lit_bufsize*4; + + d_buf = lit_bufsize/2; + l_buf = (1+2)*lit_bufsize; + + this.level = level; + + //System.out.println("level="+level); + + this.strategy = strategy; + this.method = (byte)method; + + return deflateReset(strm); + } + + internal int deflateReset(ZStream strm){ + strm.total_in = strm.total_out = 0; + strm.msg = null; // + strm.data_type = Z_UNKNOWN; + + pending = 0; + pending_out = 0; + + if(noheader < 0) { + noheader = 0; // was set to -1 by deflate(..., Z_FINISH); + } + status = (noheader!=0) ? BUSY_STATE : INIT_STATE; + strm.adler=strm._adler.adler32(0, null, 0, 0); + + last_flush = Z_NO_FLUSH; + + tr_init(); + lm_init(); + return Z_OK; + } + + internal int deflateEnd(){ + if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){ + return Z_STREAM_ERROR; + } + // Deallocate in reverse order of allocations: + pending_buf=null; + head=null; + prev=null; + window=null; + // free + // dstate=null; + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; + } + + internal int deflateParams(ZStream strm, int _level, int _strategy){ + int err=Z_OK; + + if(_level == Z_DEFAULT_COMPRESSION){ + _level = 6; + } + if(_level < 0 || _level > 9 || + _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + if(config_table[level].func!=config_table[_level].func && + strm.total_in != 0) { + // Flush the last buffer: + err = strm.deflate(Z_PARTIAL_FLUSH); + } + + if(level != _level) { + level = _level; + max_lazy_match = config_table[level].max_lazy; + good_match = config_table[level].good_length; + nice_match = config_table[level].nice_length; + max_chain_length = config_table[level].max_chain; + } + strategy = _strategy; + return err; + } + + internal int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){ + int length = dictLength; + int index=0; + + if(dictionary == null || status != INIT_STATE) + return Z_STREAM_ERROR; + + strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength); + + if(length < MIN_MATCH) return Z_OK; + if(length > w_size-MIN_LOOKAHEAD){ + length = w_size-MIN_LOOKAHEAD; + index=dictLength-length; // use the tail of the dictionary + } + System.Array.Copy(dictionary, index, window, 0, length); + strstart = length; + block_start = length; + + // Insert all strings in the hash table (except for the last two bytes). + // s->lookahead stays null, so s->ins_h will be recomputed at the next + // call of fill_window. + + ins_h = window[0]&0xff; + ins_h=(((ins_h)<Z_FINISH || flush<0){ + return Z_STREAM_ERROR; + } + + if(strm.next_out == null || + (strm.next_in == null && strm.avail_in != 0) || + (status == FINISH_STATE && flush != Z_FINISH)) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)]; + return Z_STREAM_ERROR; + } + if(strm.avail_out == 0){ + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + this.strm = strm; // just in case + old_flush = last_flush; + last_flush = flush; + + // Write the zlib header + if(status == INIT_STATE) { + int header = (Z_DEFLATED+((w_bits-8)<<4))<<8; + int level_flags=((level-1)&0xff)>>1; + + if(level_flags>3) level_flags=3; + header |= (level_flags<<6); + if(strstart!=0) header |= PRESET_DICT; + header+=31-(header % 31); + + status=BUSY_STATE; + putShortMSB(header); + + + // Save the adler32 of the preset dictionary: + if(strstart!=0){ + putShortMSB((int)(strm.adler>>16)); + putShortMSB((int)(strm.adler&0xffff)); + } + strm.adler=strm._adler.adler32(0, null, 0, 0); + } + + // Flush as much pending output as possible + if(pending != 0) { + strm.flush_pending(); + if(strm.avail_out == 0) { + //System.out.println(" avail_out==0"); + // Since avail_out is 0, deflate will be called again with + // more output space, but possibly with both pending and + // avail_in equal to zero. There won't be anything to do, + // but this is not an error situation so make sure we + // return OK instead of BUF_ERROR at next call of deflate: + last_flush = -1; + return Z_OK; + } + + // Make sure there is something to do and avoid duplicate consecutive + // flushes. For repeated and useless calls with Z_FINISH, we keep + // returning Z_STREAM_END instead of Z_BUFF_ERROR. + } + else if(strm.avail_in==0 && flush <= old_flush && + flush != Z_FINISH) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // User must not provide more input after the first FINISH: + if(status == FINISH_STATE && strm.avail_in != 0) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // Start a new block or continue the current one. + if(strm.avail_in!=0 || lookahead!=0 || + (flush != Z_NO_FLUSH && status != FINISH_STATE)) { + int bstate=-1; + switch(config_table[level].func){ + case STORED: + bstate = deflate_stored(flush); + break; + case FAST: + bstate = deflate_fast(flush); + break; + case SLOW: + bstate = deflate_slow(flush); + break; + default: + break; + } + + if (bstate==FinishStarted || bstate==FinishDone) { + status = FINISH_STATE; + } + if (bstate==NeedMore || bstate==FinishStarted) { + if(strm.avail_out == 0) { + last_flush = -1; // avoid BUF_ERROR next call, see above + } + return Z_OK; + // If flush != Z_NO_FLUSH && avail_out == 0, the next call + // of deflate should use the same flush parameter to make sure + // that the flush is complete. So we don't have to output an + // empty block here, this will be done at next call. This also + // ensures that for a very small output buffer, we emit at most + // one empty block. + } + + if (bstate==BlockDone) { + if(flush == Z_PARTIAL_FLUSH) { + _tr_align(); + } + else { // FULL_FLUSH or SYNC_FLUSH + _tr_stored_block(0, 0, false); + // For a full flush, this empty block will be recognized + // as a special marker by inflate_sync(). + if(flush == Z_FULL_FLUSH) { + //state.head[s.hash_size-1]=0; + for(int i=0; i>16)); + putShortMSB((int)(strm.adler&0xffff)); + strm.flush_pending(); + + // If avail_out is zero, the application will call deflate again + // to flush the rest. + noheader = -1; // write the trailer only once! + return pending != 0 ? Z_OK : Z_STREAM_END; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/InfBlocks.cs b/iTechSharp/System/util/zlib/InfBlocks.cs new file mode 100644 index 0000000..d6a1599 --- /dev/null +++ b/iTechSharp/System/util/zlib/InfBlocks.cs @@ -0,0 +1,618 @@ +using System; +/* + * $Id: InfBlocks.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + internal sealed class InfBlocks{ + private const int MANY=1440; + + // And'ing with mask[n] masks the lower n bits + static private int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + // Table for deflate from PKZIP's appnote.txt. + static int[] border = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int TYPE=0; // get type bits (3, including end bit) + private const int LENS=1; // get lengths for stored + private const int STORED=2;// processing stored block + private const int TABLE=3; // get table lengths + private const int BTREE=4; // get bit lengths tree for a dynamic block + private const int DTREE=5; // get length, distance trees for a dynamic block + private const int CODES=6; // processing fixed or dynamic block + private const int DRY=7; // output remaining window bytes + private const int DONE=8; // finished last block, done + private const int BAD=9; // ot a data error--stuck here + + internal int mode; // current inflate_block mode + + internal int left; // if STORED, bytes left to copy + + internal int table; // table lengths (14 bits) + internal int index; // index into blens (or border) + internal int[] blens; // bit lengths of codes + internal int[] bb=new int[1]; // bit length tree depth + internal int[] tb=new int[1]; // bit length decoding tree + + internal InfCodes codes=new InfCodes(); // if CODES, current state + + int last; // true if this block is the last block + + // mode independent information + internal int bitk; // bits in bit buffer + internal int bitb; // bit buffer + internal int[] hufts; // single malloc for tree space + internal byte[] window; // sliding window + internal int end; // one byte after sliding window + internal int read; // window read pointer + internal int write; // window write pointer + internal Object checkfn; // check function + internal long check; // check on output + + internal InfTree inftree=new InfTree(); + + internal InfBlocks(ZStream z, Object checkfn, int w){ + hufts=new int[MANY*3]; + window=new byte[w]; + end=w; + this.checkfn = checkfn; + mode = TYPE; + reset(z, null); + } + + internal void reset(ZStream z, long[] c){ + if(c!=null) c[0]=check; + if(mode==BTREE || mode==DTREE){ + } + if(mode==CODES){ + codes.free(z); + } + mode=TYPE; + bitk=0; + bitb=0; + read=write=0; + + if(checkfn != null) + z.adler=check=z._adler.adler32(0L, null, 0, 0); + } + + internal int proc(ZStream z, int r){ + int t; // temporary storage + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; { // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} { + q=write;m=(int)(q> 1){ + case 0: { // stored + b>>=(3);k-=(3);} + t = k & 7; { // go to byte boundary + + b>>=(t);k-=(t);} + mode = LENS; // get length of stored block + break; + case 1: { // fixed + int[] bl=new int[1]; + int[] bd=new int[1]; + int[][] tl=new int[1][]; + int[][] td=new int[1][]; + + InfTree.inflate_trees_fixed(bl, bd, tl, td, z); + codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z); + } { + + b>>=(3);k-=(3);} + + mode = CODES; + break; + case 2: { // dynamic + + b>>=(3);k-=(3);} + + mode = TABLE; + break; + case 3: { // illegal + + b>>=(3);k-=(3);} + mode = BAD; + z.msg = "invalid block type"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + break; + case LENS: + + while(k<(32)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<> 16) & 0xffff) != (b & 0xffff)){ + mode = BAD; + z.msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE); + break; + case STORED: + if (n == 0){ + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + if(m==0){ + if(q==end&&read!=0){ + q=0; m=(int)(qn) t = n; + if(t>m) t = m; + System.Array.Copy(z.next_in, p, window, q, t); + p += t; n -= t; + q += t; m -= t; + if ((left -= t) != 0) + break; + mode = last!=0 ? DRY : TYPE; + break; + case TABLE: + + while(k<(14)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)< 29 || ((t >> 5) & 0x1f) > 29) { + mode = BAD; + z.msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if(blens==null || blens.Length>=(14);k-=(14);} + + index = 0; + mode = BTREE; + goto case BTREE; + case BTREE: + while (index < 4 + (table >> 10)){ + while(k<(3)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(3);k-=(3);} + } + + while(index < 19){ + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); + if (t != Z_OK){ + r = t; + if (r == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + index = 0; + mode = DTREE; + goto case DTREE; + case DTREE: + while (true){ + t = table; + if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){ + break; + } + + int i, j, c; + + t = bb[0]; + + while(k<(t)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(t);k-=(t); + blens[index++] = c; + } + else { // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + + while(k<(t+i)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(t);k-=(t); + + j += (b & inflate_mask[i]); + + b>>=(i);k-=(i); + + i = index; + t = table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)){ + blens=null; + mode = BAD; + z.msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + c = c == 16 ? blens[i-1] : 0; + do{ + blens[i++] = c; + } + while (--j!=0); + index = i; + } + } + + tb[0]=-1; { + int[] bl=new int[1]; + int[] bd=new int[1]; + int[] tl=new int[1]; + int[] td=new int[1]; + bl[0] = 9; // must be <= 9 for lookahead assumptions + bd[0] = 6; // must be <= 9 for lookahead assumptions + + t = table; + t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), + 1 + ((t >> 5) & 0x1f), + blens, bl, bd, tl, td, hufts, z); + + if (t != Z_OK){ + if (t == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + r = t; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z); + } + mode = CODES; + goto case CODES; + case CODES: + bitb=b; bitk=k; + z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + + if ((r = codes.proc(this, z, r)) != Z_STREAM_END){ + return inflate_flush(z, r); + } + r = Z_OK; + codes.free(z); + + p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk; + q=write;m=(int)(q z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(checkfn != null) + z.adler=check=z._adler.adler32(check, window, q, n); + + // copy as far as end of window + System.Array.Copy(window, q, z.next_out, p, n); + p += n; + q += n; + + // see if more to copy at beginning of window + if (q == end){ + // wrap pointers + q = 0; + if (write == end) + write = 0; + + // compute bytes to copy + n = write - q; + if (n > z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(checkfn != null) + z.adler=check=z._adler.adler32(check, window, q, n); + + // copy + System.Array.Copy(window, q, z.next_out, p, n); + p += n; + q += n; + } + + // update pointers + z.next_out_index = p; + read = q; + + // done + return r; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/InfCodes.cs b/iTechSharp/System/util/zlib/InfCodes.cs new file mode 100644 index 0000000..a70e4b0 --- /dev/null +++ b/iTechSharp/System/util/zlib/InfCodes.cs @@ -0,0 +1,611 @@ +using System; +/* + * $Id: InfCodes.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + internal sealed class InfCodes{ + + static private int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + private const int START=0; // x: set up for LEN + private const int LEN=1; // i: get length/literal/eob next + private const int LENEXT=2; // i: getting length extra (have base) + private const int DIST=3; // i: get distance next + private const int DISTEXT=4;// i: getting distance extra + private const int COPY=5; // o: copying bytes in window, waiting for space + private const int LIT=6; // o: got literal, waiting for output space + private const int WASH=7; // o: got eob, possibly still output waiting + private const int END=8; // x: got eob and all data flushed + private const int BADCODE=9;// x: got error + + int mode; // current inflate_codes mode + + // mode dependent information + int len; + + int[] tree; // pointer into tree + int tree_index=0; + int need; // bits needed + + int lit; + + // if EXT or COPY, where and how much + int get; // bits to get for extra + int dist; // distance back to copy from + + byte lbits; // ltree bits decoded per branch + byte dbits; // dtree bits decoder per branch + int[] ltree; // literal/length/eob tree + int ltree_index; // literal/length/eob tree + int[] dtree; // distance tree + int dtree_index; // distance tree + + internal InfCodes(){ + } + internal void init(int bl, int bd, + int[] tl, int tl_index, + int[] td, int td_index, ZStream z){ + mode=START; + lbits=(byte)bl; + dbits=(byte)bd; + ltree=tl; + ltree_index=tl_index; + dtree = td; + dtree_index=td_index; + tree=null; + } + + internal int proc(InfBlocks s, ZStream z, int r){ + int j; // temporary storage + int tindex; // temporary pointer + int e; // extra bits or operation + int b=0; // bit buffer + int k=0; // bits in bit buffer + int p=0; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int f; // pointer to copy strings from + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q= 258 && n >= 10){ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + r = inflate_fast(lbits, dbits, + ltree, ltree_index, + dtree, dtree_index, + s, z); + + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q>=(tree[tindex+1]); + k-=(tree[tindex+1]); + + e=tree[tindex]; + + if(e == 0){ // literal + lit = tree[tindex+2]; + mode = LIT; + break; + } + if((e & 16)!=0 ){ // length + get = e & 15; + len = tree[tindex+2]; + mode = LENEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3+tree[tindex+2]; + break; + } + if ((e & 32)!=0){ // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + + case LENEXT: // i: getting length extra (have base) + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + need = dbits; + tree = dtree; + tree_index=dtree_index; + mode = DIST; + goto case DIST; + case DIST: // i: get distance next + j = need; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1]; + k-=tree[tindex+1]; + + e = (tree[tindex]); + if((e & 16)!=0){ // distance + get = e & 15; + dist = tree[tindex+2]; + mode = DISTEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3 + tree[tindex+2]; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid distance code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + + case DISTEXT: // i: getting distance extra + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + mode = COPY; + goto case COPY; + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while(f < 0){ // modulo window size-"while" instead + f += s.end; // of "if" handles invalid distances + } + while (len!=0){ + + if(m==0){ + if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + s.write=q; r=s.inflate_flush(z,r); + q=s.write;m=q= 258 && n >= 10 + // get literal/length code + while(k<(20)){ // max bits for literal/length code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++] = (byte)tp[tp_index_t_3+2]; + m--; + continue; + } + do { + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + e &= 15; + c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]); + + b>>=e; k-=e; + + // decode distance base of block to copy + while(k<(15)){ // max bits for distance code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + // get extra bits to add to distance base + e &= 15; + while(k<(e)){ // get extra bits (up to 13) + n--; + b|=(z.next_in[p++]&0xff)<>=(e); k-=(e); + + // do the copy + m -= c; + if (q >= d){ // offset before dest + // just copy + r=q-d; + if(q-r>0 && 2>(q-r)){ + s.window[q++]=s.window[r++]; // minimum count is three, + s.window[q++]=s.window[r++]; // so unroll loop a little + c-=2; + } + else{ + System.Array.Copy(s.window, r, s.window, q, 2); + q+=2; r+=2; c-=2; + } + } + else{ // else offset after destination + r=q-d; + do{ + r+=s.end; // force pointer in window + }while(r<0); // covers invalid distances + e=s.end-r; + if(c>e){ // if source crosses, + c-=e; // wrapped copy + if(q-r>0 && e>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--e!=0); + } + else{ + System.Array.Copy(s.window, r, s.window, q, e); + q+=e; r+=e; e=0; + } + r = 0; // copy rest from start of window + } + + } + + // copy all or what's left + if(q-r>0 && c>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--c!=0); + } + else{ + System.Array.Copy(s.window, r, s.window, q, c); + q+=c; r+=c; c=0; + } + break; + } + else if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + e=tp[tp_index_t_3]; + } + else{ + z.msg = "invalid distance code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + break; + } + + if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + if((e=tp[tp_index_t_3])==0){ + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++]=(byte)tp[tp_index_t_3+2]; + m--; + break; + } + } + else if((e&32)!=0){ + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_STREAM_END; + } + else{ + z.msg="invalid literal/length code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + } + while(m>=258 && n>= 10); + + // not enough input or output--restore pointers and return + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_OK; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/InfTree.cs b/iTechSharp/System/util/zlib/InfTree.cs new file mode 100644 index 0000000..d7450d4 --- /dev/null +++ b/iTechSharp/System/util/zlib/InfTree.cs @@ -0,0 +1,523 @@ +using System; +/* + * $Id: InfTree.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + internal sealed class InfTree{ + + private const int MANY=1440; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int fixed_bl = 9; + private const int fixed_bd = 5; + + static int[] fixed_tl = { + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,192, + 80,7,10, 0,8,96, 0,8,32, 0,9,160, + 0,8,0, 0,8,128, 0,8,64, 0,9,224, + 80,7,6, 0,8,88, 0,8,24, 0,9,144, + 83,7,59, 0,8,120, 0,8,56, 0,9,208, + 81,7,17, 0,8,104, 0,8,40, 0,9,176, + 0,8,8, 0,8,136, 0,8,72, 0,9,240, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,200, + 81,7,13, 0,8,100, 0,8,36, 0,9,168, + 0,8,4, 0,8,132, 0,8,68, 0,9,232, + 80,7,8, 0,8,92, 0,8,28, 0,9,152, + 84,7,83, 0,8,124, 0,8,60, 0,9,216, + 82,7,23, 0,8,108, 0,8,44, 0,9,184, + 0,8,12, 0,8,140, 0,8,76, 0,9,248, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,196, + 81,7,11, 0,8,98, 0,8,34, 0,9,164, + 0,8,2, 0,8,130, 0,8,66, 0,9,228, + 80,7,7, 0,8,90, 0,8,26, 0,9,148, + 84,7,67, 0,8,122, 0,8,58, 0,9,212, + 82,7,19, 0,8,106, 0,8,42, 0,9,180, + 0,8,10, 0,8,138, 0,8,74, 0,9,244, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,204, + 81,7,15, 0,8,102, 0,8,38, 0,9,172, + 0,8,6, 0,8,134, 0,8,70, 0,9,236, + 80,7,9, 0,8,94, 0,8,30, 0,9,156, + 84,7,99, 0,8,126, 0,8,62, 0,9,220, + 82,7,27, 0,8,110, 0,8,46, 0,9,188, + 0,8,14, 0,8,142, 0,8,78, 0,9,252, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,194, + 80,7,10, 0,8,97, 0,8,33, 0,9,162, + 0,8,1, 0,8,129, 0,8,65, 0,9,226, + 80,7,6, 0,8,89, 0,8,25, 0,9,146, + 83,7,59, 0,8,121, 0,8,57, 0,9,210, + 81,7,17, 0,8,105, 0,8,41, 0,9,178, + 0,8,9, 0,8,137, 0,8,73, 0,9,242, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,202, + 81,7,13, 0,8,101, 0,8,37, 0,9,170, + 0,8,5, 0,8,133, 0,8,69, 0,9,234, + 80,7,8, 0,8,93, 0,8,29, 0,9,154, + 84,7,83, 0,8,125, 0,8,61, 0,9,218, + 82,7,23, 0,8,109, 0,8,45, 0,9,186, + 0,8,13, 0,8,141, 0,8,77, 0,9,250, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,198, + 81,7,11, 0,8,99, 0,8,35, 0,9,166, + 0,8,3, 0,8,131, 0,8,67, 0,9,230, + 80,7,7, 0,8,91, 0,8,27, 0,9,150, + 84,7,67, 0,8,123, 0,8,59, 0,9,214, + 82,7,19, 0,8,107, 0,8,43, 0,9,182, + 0,8,11, 0,8,139, 0,8,75, 0,9,246, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,206, + 81,7,15, 0,8,103, 0,8,39, 0,9,174, + 0,8,7, 0,8,135, 0,8,71, 0,9,238, + 80,7,9, 0,8,95, 0,8,31, 0,9,158, + 84,7,99, 0,8,127, 0,8,63, 0,9,222, + 82,7,27, 0,8,111, 0,8,47, 0,9,190, + 0,8,15, 0,8,143, 0,8,79, 0,9,254, + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,193, + + 80,7,10, 0,8,96, 0,8,32, 0,9,161, + 0,8,0, 0,8,128, 0,8,64, 0,9,225, + 80,7,6, 0,8,88, 0,8,24, 0,9,145, + 83,7,59, 0,8,120, 0,8,56, 0,9,209, + 81,7,17, 0,8,104, 0,8,40, 0,9,177, + 0,8,8, 0,8,136, 0,8,72, 0,9,241, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,201, + 81,7,13, 0,8,100, 0,8,36, 0,9,169, + 0,8,4, 0,8,132, 0,8,68, 0,9,233, + 80,7,8, 0,8,92, 0,8,28, 0,9,153, + 84,7,83, 0,8,124, 0,8,60, 0,9,217, + 82,7,23, 0,8,108, 0,8,44, 0,9,185, + 0,8,12, 0,8,140, 0,8,76, 0,9,249, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,197, + 81,7,11, 0,8,98, 0,8,34, 0,9,165, + 0,8,2, 0,8,130, 0,8,66, 0,9,229, + 80,7,7, 0,8,90, 0,8,26, 0,9,149, + 84,7,67, 0,8,122, 0,8,58, 0,9,213, + 82,7,19, 0,8,106, 0,8,42, 0,9,181, + 0,8,10, 0,8,138, 0,8,74, 0,9,245, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,205, + 81,7,15, 0,8,102, 0,8,38, 0,9,173, + 0,8,6, 0,8,134, 0,8,70, 0,9,237, + 80,7,9, 0,8,94, 0,8,30, 0,9,157, + 84,7,99, 0,8,126, 0,8,62, 0,9,221, + 82,7,27, 0,8,110, 0,8,46, 0,9,189, + 0,8,14, 0,8,142, 0,8,78, 0,9,253, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,195, + 80,7,10, 0,8,97, 0,8,33, 0,9,163, + 0,8,1, 0,8,129, 0,8,65, 0,9,227, + 80,7,6, 0,8,89, 0,8,25, 0,9,147, + 83,7,59, 0,8,121, 0,8,57, 0,9,211, + 81,7,17, 0,8,105, 0,8,41, 0,9,179, + 0,8,9, 0,8,137, 0,8,73, 0,9,243, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,203, + 81,7,13, 0,8,101, 0,8,37, 0,9,171, + 0,8,5, 0,8,133, 0,8,69, 0,9,235, + 80,7,8, 0,8,93, 0,8,29, 0,9,155, + 84,7,83, 0,8,125, 0,8,61, 0,9,219, + 82,7,23, 0,8,109, 0,8,45, 0,9,187, + 0,8,13, 0,8,141, 0,8,77, 0,9,251, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,199, + 81,7,11, 0,8,99, 0,8,35, 0,9,167, + 0,8,3, 0,8,131, 0,8,67, 0,9,231, + 80,7,7, 0,8,91, 0,8,27, 0,9,151, + 84,7,67, 0,8,123, 0,8,59, 0,9,215, + 82,7,19, 0,8,107, 0,8,43, 0,9,183, + 0,8,11, 0,8,139, 0,8,75, 0,9,247, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,207, + 81,7,15, 0,8,103, 0,8,39, 0,9,175, + 0,8,7, 0,8,135, 0,8,71, 0,9,239, + 80,7,9, 0,8,95, 0,8,31, 0,9,159, + 84,7,99, 0,8,127, 0,8,63, 0,9,223, + 82,7,27, 0,8,111, 0,8,47, 0,9,191, + 0,8,15, 0,8,143, 0,8,79, 0,9,255 + }; + static int[] fixed_td = { + 80,5,1, 87,5,257, 83,5,17, 91,5,4097, + 81,5,5, 89,5,1025, 85,5,65, 93,5,16385, + 80,5,3, 88,5,513, 84,5,33, 92,5,8193, + 82,5,9, 90,5,2049, 86,5,129, 192,5,24577, + 80,5,2, 87,5,385, 83,5,25, 91,5,6145, + 81,5,7, 89,5,1537, 85,5,97, 93,5,24577, + 80,5,4, 88,5,769, 84,5,49, 92,5,12289, + 82,5,13, 90,5,3073, 86,5,193, 192,5,24577 + }; + + // Tables for deflate from PKZIP's appnote.txt. + static int[] cplens = { // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + + // see note #13 above about 258 + static int[] cplext = { // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid + }; + + static int[] cpdist = { // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + + static int[] cpdext = { // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + const int BMAX=15; // maximum bit length of any code + + int[] hn = null; // hufts used in space + int[] v = null; // work area for huft_build + int[] c = null; // bit length count table + int[] r = null; // table entry for structure assignment + int[] u = null; // table stack + int[] x = null; // bit offsets, then code stack + + private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX) + int bindex, + int n, // number of codes (assumed <= 288) + int s, // number of simple-valued codes (0..s-1) + int[] d, // list of base values for non-simple codes + int[] e, // list of extra bits for non-simple codes + int[] t, // result: starting table + int[] m, // maximum lookup bits, returns actual + int[] hp,// space for trees + int[] hn,// hufts used in space + int[] v // working area: values in order of bit length + ){ + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + // lengths), or Z_MEM_ERROR if not enough memory. + + int a; // counter for codes of length k + int f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + int i; // counter, current code + int j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + int mask; // (1 << w) - 1, to avoid cc -O bug on HP + int p; // pointer into c[], b[], or v[] + int q; // points to current table + int w; // bits before this table == (l * h) + int xp; // pointer into x + int y; // number of dummy codes added + int z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; i = n; + do { + c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX + }while(i!=0); + + if(c[0] == n){ // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } + + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) + if(c[j]!=0) break; + k = j; // minimum code length + if(l < j){ + l = j; + } + for (i = BMAX; i!=0; i--){ + if(c[i]!=0) break; + } + g = i; // maximum code length + if(l > i){ + l = i; + } + m[0] = l; + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1){ + if ((y -= c[j]) < 0){ + return Z_DATA_ERROR; + } + } + if ((y -= c[i]) < 0){ + return Z_DATA_ERROR; + } + c[i] += y; + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; xp = 2; + while (--i!=0) { // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; p = 0; + do { + if ((j = b[bindex+p]) != 0){ + v[x[j]++] = i; + } + p++; + } + while (++i < n); + n = x[g]; // set n to length of v + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++){ + a = c[k]; + while (a--!=0){ + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l){ + h++; + w += l; // previous table always l bits + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if((f=1<<(j=k-w))>a+1){ // try a k-w bit table + // too few codes for k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = k; + if(j < z){ + while (++j < z){ // try smaller tables up to z bits + if((f <<= 1) <= c[++xp]) + break; // enough codes to use up j bits + f -= c[xp]; // else deduct codes from patterns + } + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (hn[0] + z > MANY){ // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + } + u[h] = q = /*hp+*/ hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if(h!=0){ + x[h]=i; // save pattern for backing up + r[0]=(byte)j; // bits in this table + r[1]=(byte)l; // bits to dump before this table + j=i>>(w - l); + r[2] = (int)(q - u[h-1] - j); // offset to this table + System.Array.Copy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table + } + else{ + t[0] = q; // first table is returned result + } + } + + // set up table entry in r + r[1] = (byte)(k - w); + if (p >= n){ + r[0] = 128 + 64; // out of values--invalid code + } + else if (v[p] < s){ + r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block + r[2] = v[p++]; // simple code is just the value + } + else{ + r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists + r[2]=d[v[p++] - s]; + } + + // fill code-like entries with r + f=1<<(k-w); + for (j=i>>w;j>= 1){ + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]){ + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + + internal int inflate_trees_bits(int[] c, // 19 code lengths + int[] bb, // bits tree desired/actual depth + int[] tb, // bits tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + initWorkArea(19); + hn[0]=0; + result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed dynamic bit lengths tree"; + } + else if(result == Z_BUF_ERROR || bb[0] == 0){ + z.msg = "incomplete dynamic bit lengths tree"; + result = Z_DATA_ERROR; + } + return result; + } + + internal int inflate_trees_dynamic(int nl, // number of literal/length codes + int nd, // number of distance codes + int[] c, // that many (total) code lengths + int[] bl, // literal desired/actual bit depth + int[] bd, // distance desired/actual bit depth + int[] tl, // literal/length tree result + int[] td, // distance tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + + // build literal/length tree + initWorkArea(288); + hn[0]=0; + result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); + if (result != Z_OK || bl[0] == 0){ + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed literal/length tree"; + } + else if (result != Z_MEM_ERROR){ + z.msg = "incomplete literal/length tree"; + result = Z_DATA_ERROR; + } + return result; + } + + // build distance tree + initWorkArea(288); + result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); + + if (result != Z_OK || (bd[0] == 0 && nl > 257)){ + if (result == Z_DATA_ERROR){ + z.msg = "oversubscribed distance tree"; + } + else if (result == Z_BUF_ERROR) { + z.msg = "incomplete distance tree"; + result = Z_DATA_ERROR; + } + else if (result != Z_MEM_ERROR){ + z.msg = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; + } + + return Z_OK; + } + + internal static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth + int[] bd, //distance desired/actual bit depth + int[][] tl,//literal/length tree result + int[][] td,//distance tree result + ZStream z //for memory allocation + ){ + bl[0]=fixed_bl; + bd[0]=fixed_bd; + tl[0]=fixed_tl; + td[0]=fixed_td; + return Z_OK; + } + + private void initWorkArea(int vsize){ + if(hn==null){ + hn=new int[1]; + v=new int[vsize]; + c=new int[BMAX+1]; + r=new int[3]; + u=new int[BMAX]; + x=new int[BMAX+1]; + } + if(v.Lengthstate); + return Z_OK; + } + + internal int inflateInit(ZStream z, int w){ + z.msg = null; + blocks = null; + + // handle undocumented nowrap option (no zlib header or check) + nowrap = 0; + if(w < 0){ + w = - w; + nowrap = 1; + } + + // set window size + if(w<8 ||w>15){ + inflateEnd(z); + return Z_STREAM_ERROR; + } + wbits=w; + + z.istate.blocks=new InfBlocks(z, + z.istate.nowrap!=0 ? null : this, + 1<>4)+8>z.istate.wbits){ + z.istate.mode = BAD; + z.msg="invalid window size"; + z.istate.marker = 5; // can't try inflateSync + break; + } + z.istate.mode=FLAG; + goto case FLAG; + case FLAG: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + b = (z.next_in[z.next_in_index++])&0xff; + + if((((z.istate.method << 8)+b) % 31)!=0){ + z.istate.mode = BAD; + z.msg = "incorrect header check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + if((b&PRESET_DICT)==0){ + z.istate.mode = BLOCKS; + break; + } + z.istate.mode = DICT4; + goto case DICT4; + case DICT4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + z.istate.mode=DICT3; + goto case DICT3; + case DICT3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + z.istate.mode=DICT2; + goto case DICT2; + case DICT2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + z.istate.mode=DICT1; + goto case DICT1; + case DICT1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need += (z.next_in[z.next_in_index++]&0xffL); + z.adler = z.istate.need; + z.istate.mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z.istate.mode = BAD; + z.msg = "need dictionary"; + z.istate.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case BLOCKS: + + r = z.istate.blocks.proc(z, r); + if(r == Z_DATA_ERROR){ + z.istate.mode = BAD; + z.istate.marker = 0; // can try inflateSync + break; + } + if(r == Z_OK){ + r = f; + } + if(r != Z_STREAM_END){ + return r; + } + r = f; + z.istate.blocks.reset(z, z.istate.was); + if(z.istate.nowrap!=0){ + z.istate.mode=DONE; + break; + } + z.istate.mode=CHECK4; + goto case CHECK4; + case CHECK4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + z.istate.mode=CHECK3; + goto case CHECK3; + case CHECK3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + z.istate.mode = CHECK2; + goto case CHECK2; + case CHECK2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + z.istate.mode = CHECK1; + goto case CHECK1; + case CHECK1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=(z.next_in[z.next_in_index++]&0xffL); + + if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){ + z.istate.mode = BAD; + z.msg = "incorrect data check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + z.istate.mode = DONE; + goto case DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + } + } + + + internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){ + int index=0; + int length = dictLength; + if(z==null || z.istate == null|| z.istate.mode != DICT0) + return Z_STREAM_ERROR; + + if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){ + return Z_DATA_ERROR; + } + + z.adler = z._adler.adler32(0, null, 0, 0); + + if(length >= (1<>7)]); + } + + internal short[] dyn_tree; // the dynamic tree + internal int max_code; // largest code with non zero frequency + internal StaticTree stat_desc; // the corresponding static tree + + // Compute the optimal bit lengths for a tree and update the total bit length + // for the current block. + // IN assertion: the fields freq and dad are set, heap[heap_max] and + // above are the tree nodes sorted by increasing frequency. + // OUT assertions: the field len is set to the optimal bit length, the + // array bl_count contains the frequencies for each bit length. + // The length opt_len is updated; static_len is also updated if stree is + // not null. + internal void gen_bitlen(Deflate s){ + short[] tree = dyn_tree; + short[] stree = stat_desc.static_tree; + int[] extra = stat_desc.extra_bits; + int based = stat_desc.extra_base; + int max_length = stat_desc.max_length; + int h; // heap index + int n, m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + short f; // frequency + int overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0; + + // In a first pass, compute the optimal bit lengths (which may + // overflow in the case of the bit length tree). + tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap + + for(h=s.heap_max+1; h max_length){ bits = max_length; overflow++; } + tree[n*2+1] = (short)bits; + // We overwrite tree[n*2+1] which is no longer needed + + if (n > max_code) continue; // not a leaf node + + s.bl_count[bits]++; + xbits = 0; + if (n >= based) xbits = extra[n-based]; + f = tree[n*2]; + s.opt_len += f * (bits + xbits); + if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits); + } + if (overflow == 0) return; + + // This happens for example on obj2 and pic of the Calgary corpus + // Find the first bit length which could increase: + do { + bits = max_length-1; + while(s.bl_count[bits]==0) bits--; + s.bl_count[bits]--; // move one leaf down the tree + s.bl_count[bits+1]+=2; // move one overflow item as its brother + s.bl_count[max_length]--; + // The brother of the overflow item also moves one step up, + // but this does not affect bl_count[max_length] + overflow -= 2; + } + while (overflow > 0); + + for (bits = max_length; bits != 0; bits--) { + n = s.bl_count[bits]; + while (n != 0) { + m = s.heap[--h]; + if (m > max_code) continue; + if (tree[m*2+1] != bits) { + s.opt_len += (int)(((long)bits - (long)tree[m*2+1])*(long)tree[m*2]); + tree[m*2+1] = (short)bits; + } + n--; + } + } + } + + // Construct one Huffman tree and assigns the code bit strings and lengths. + // Update the total bit length for the current block. + // IN assertion: the field freq is set for all tree elements. + // OUT assertions: the fields len and code are set to the optimal bit length + // and corresponding code. The length opt_len is updated; static_len is + // also updated if stree is not null. The field max_code is set. + internal void build_tree(Deflate s){ + short[] tree=dyn_tree; + short[] stree=stat_desc.static_tree; + int elems=stat_desc.elems; + int n, m; // iterate over heap elements + int max_code=-1; // largest code with non zero frequency + int node; // new node being created + + // Construct the initial heap, with least frequent element in + // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + // heap[0] is not used. + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for(n=0; n=1; n--) + s.pqdownheap(tree, n); + + // Construct the Huffman tree by repeatedly combining the least two + // frequent nodes. + + node=elems; // next internal node of the tree + do{ + // n = node of least frequency + n=s.heap[1]; + s.heap[1]=s.heap[s.heap_len--]; + s.pqdownheap(tree, 1); + m=s.heap[1]; // m = node of next least frequency + + s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency + s.heap[--s.heap_max] = m; + + // Create a new node father of n and m + tree[node*2] = (short)(tree[n*2] + tree[m*2]); + s.depth[node] = (byte)(System.Math.Max(s.depth[n],s.depth[m])+1); + tree[n*2+1] = tree[m*2+1] = (short)node; + + // and insert the new node in the heap + s.heap[1] = node++; + s.pqdownheap(tree, 1); + } + while(s.heap_len>=2); + + s.heap[--s.heap_max] = s.heap[1]; + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + + gen_bitlen(s); + + // The field len is now set, we can generate the bit codes + gen_codes(tree, max_code, s.bl_count); + } + + // Generate the codes for a given tree and bit counts (which need not be + // optimal). + // IN assertion: the array bl_count contains the bit length statistics for + // the given tree and the field len is set for all tree elements. + // OUT assertion: the field code is set for all tree elements of non + // zero code length. + internal static void gen_codes(short[] tree, // the tree to decorate + int max_code, // largest code with non zero frequency + short[] bl_count // number of codes at each bit length + ){ + short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length + short code = 0; // running code value + int bits; // bit index + int n; // code index + + // The distribution counts are first used to generate the code values + // without bit reversal. + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1); + } + + // Check that the bit counts in bl_count are consistent. The last code + // must be all ones. + //Assert (code + bl_count[MAX_BITS]-1 == (1<>=1; + res<<=1; + } + while(--len>0); + return res>>1; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs b/iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs new file mode 100644 index 0000000..dc5e75a --- /dev/null +++ b/iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs @@ -0,0 +1,196 @@ +using System; +using System.IO; +/* + * $Id: ZDeflaterOutputStream.cs,v 1.3 2007/06/22 14:14:13 psoares33 Exp $ + * + * Copyright 2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace System.util.zlib { + /// + /// Summary description for DeflaterOutputStream. + /// + public class ZDeflaterOutputStream : Stream { + protected ZStream z=new ZStream(); + protected int flushLevel=JZlib.Z_NO_FLUSH; + private const int BUFSIZE = 4192; + protected byte[] buf=new byte[BUFSIZE]; + private byte[] buf1=new byte[1]; + + protected Stream outp; + + public ZDeflaterOutputStream(Stream outp) : this(outp, 6, false) { + } + + public ZDeflaterOutputStream(Stream outp, int level) : this(outp, level, false) { + } + + public ZDeflaterOutputStream(Stream outp, int level, bool nowrap) { + this.outp=outp; + z.deflateInit(level, nowrap); + } + + + public override bool CanRead { + get { + // TODO: Add DeflaterOutputStream.CanRead getter implementation + return false; + } + } + + public override bool CanSeek { + get { + // TODO: Add DeflaterOutputStream.CanSeek getter implementation + return false; + } + } + + public override bool CanWrite { + get { + // TODO: Add DeflaterOutputStream.CanWrite getter implementation + return true; + } + } + + public override long Length { + get { + // TODO: Add DeflaterOutputStream.Length getter implementation + return 0; + } + } + + public override long Position { + get { + // TODO: Add DeflaterOutputStream.Position getter implementation + return 0; + } + set { + // TODO: Add DeflaterOutputStream.Position setter implementation + } + } + + public override void Write(byte[] b, int off, int len) { + if(len==0) + return; + int err; + z.next_in=b; + z.next_in_index=off; + z.avail_in=len; + do{ + z.next_out=buf; + z.next_out_index=0; + z.avail_out=BUFSIZE; + err=z.deflate(flushLevel); + if(err!=JZlib.Z_OK) + throw new IOException("deflating: "+z.msg); + if (z.avail_out < BUFSIZE) + outp.Write(buf, 0, BUFSIZE-z.avail_out); + } + while(z.avail_in>0 || z.avail_out==0); + } + + public override long Seek(long offset, SeekOrigin origin) { + // TODO: Add DeflaterOutputStream.Seek implementation + return 0; + } + + public override void SetLength(long value) { + // TODO: Add DeflaterOutputStream.SetLength implementation + + } + + public override int Read(byte[] buffer, int offset, int count) { + // TODO: Add DeflaterOutputStream.Read implementation + return 0; + } + + public override void Flush() { + outp.Flush(); + } + + public override void WriteByte(byte b) { + buf1[0]=(byte)b; + Write(buf1, 0, 1); + } + + public void Finish() { + int err; + do{ + z.next_out=buf; + z.next_out_index=0; + z.avail_out=BUFSIZE; + err=z.deflate(JZlib.Z_FINISH); + if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK) + throw new IOException("deflating: "+z.msg); + if(BUFSIZE-z.avail_out>0){ + outp.Write(buf, 0, BUFSIZE-z.avail_out); + } + } + while(z.avail_in>0 || z.avail_out==0); + Flush(); + } + + public void End() { + if(z==null) + return; + z.deflateEnd(); + z.free(); + z=null; + } + + public override void Close() { + try{ + try{Finish();} + catch (IOException) {} + } + finally{ + End(); + outp.Close(); + outp=null; + } + } + } +} diff --git a/iTechSharp/System/util/zlib/ZInflaterInputStream.cs b/iTechSharp/System/util/zlib/ZInflaterInputStream.cs new file mode 100644 index 0000000..c8ed40c --- /dev/null +++ b/iTechSharp/System/util/zlib/ZInflaterInputStream.cs @@ -0,0 +1,174 @@ +using System; +using System.IO; +/* + * $Id: ZInflaterInputStream.cs,v 1.4 2007/06/22 14:14:16 psoares33 Exp $ + * + * Copyright 2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace System.util.zlib { + /// + /// Summary description for DeflaterOutputStream. + /// + public class ZInflaterInputStream : Stream { + protected ZStream z=new ZStream(); + protected int flushLevel=JZlib.Z_NO_FLUSH; + private const int BUFSIZE = 4192; + protected byte[] buf=new byte[BUFSIZE]; + private byte[] buf1=new byte[1]; + + protected Stream inp=null; + private bool nomoreinput=false; + + public ZInflaterInputStream(Stream inp) : this(inp, false) { + } + + public ZInflaterInputStream(Stream inp, bool nowrap) { + this.inp=inp; + z.inflateInit(nowrap); + z.next_in=buf; + z.next_in_index=0; + z.avail_in=0; + } + + public override bool CanRead { + get { + // TODO: Add DeflaterOutputStream.CanRead getter implementation + return true; + } + } + + public override bool CanSeek { + get { + // TODO: Add DeflaterOutputStream.CanSeek getter implementation + return false; + } + } + + public override bool CanWrite { + get { + // TODO: Add DeflaterOutputStream.CanWrite getter implementation + return false; + } + } + + public override long Length { + get { + // TODO: Add DeflaterOutputStream.Length getter implementation + return 0; + } + } + + public override long Position { + get { + // TODO: Add DeflaterOutputStream.Position getter implementation + return 0; + } + set { + // TODO: Add DeflaterOutputStream.Position setter implementation + } + } + + public override void Write(byte[] b, int off, int len) { + } + + public override long Seek(long offset, SeekOrigin origin) { + // TODO: Add DeflaterOutputStream.Seek implementation + return 0; + } + + public override void SetLength(long value) { + // TODO: Add DeflaterOutputStream.SetLength implementation + + } + + public override int Read(byte[] b, int off, int len) { + if(len==0) + return(0); + int err; + z.next_out=b; + z.next_out_index=off; + z.avail_out=len; + do { + if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it + z.next_in_index=0; + z.avail_in=inp.Read(buf, 0, BUFSIZE);//(BUFSIZEnext_out buffer and copying into it. + // (See also read_buf()). + internal void flush_pending(){ + int len=dstate.pending; + + if(len>avail_out) len=avail_out; + if(len==0) return; + + if(dstate.pending_buf.Length<=dstate.pending_out || + next_out.Length<=next_out_index || + dstate.pending_buf.Length<(dstate.pending_out+len) || + next_out.Length<(next_out_index+len)){ + // System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+ + // ", "+next_out.length+", "+next_out_index+", "+len); + // System.out.println("avail_out="+avail_out); + } + + System.Array.Copy(dstate.pending_buf, dstate.pending_out, + next_out, next_out_index, len); + + next_out_index+=len; + dstate.pending_out+=len; + total_out+=len; + avail_out-=len; + dstate.pending-=len; + if(dstate.pending==0){ + dstate.pending_out=0; + } + } + + // Read a new buffer from the current input stream, update the adler32 + // and total number of bytes read. All deflate() input goes through + // this function so some applications may wish to modify it to avoid + // allocating a large strm->next_in buffer and copying from it. + // (See also flush_pending()). + internal int read_buf(byte[] buf, int start, int size) { + int len=avail_in; + + if(len>size) len=size; + if(len==0) return 0; + + avail_in-=len; + + if(dstate.noheader==0) { + adler=_adler.adler32(adler, next_in, next_in_index, len); + } + System.Array.Copy(next_in, next_in_index, buf, start, len); + next_in_index += len; + total_in += len; + return len; + } + + public void free(){ + next_in=null; + next_out=null; + msg=null; + _adler=null; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Anchor.cs b/iTechSharp/iTextSharp/text/Anchor.cs new file mode 100644 index 0000000..3b7849c --- /dev/null +++ b/iTechSharp/iTextSharp/text/Anchor.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text.html; +using iTextSharp.text.factories; + +/* + * $Id: Anchor.cs,v 1.9 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iTextSharp, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// An Anchor can be a reference or a destination of a reference. + /// + /// + /// An Anchor is a special kind of . + /// It is constructed in the same way. + /// + /// + /// + public class Anchor : Phrase + { + + // membervariables + + /// + /// This is the name of the Anchor. + /// + protected string name = null; + + /// + /// This is the reference of the Anchor. + /// + protected string reference = null; + + // constructors + + /// + /// Constructs an Anchor without specifying a leading. + /// + /// + /// Has nine overloads. + /// + public Anchor() : base(16) {} + + /// + /// Constructs an Anchor with a certain leading. + /// + /// the leading + public Anchor(float leading) : base(leading) {} + + /// + /// Constructs an Anchor with a certain Chunk. + /// + /// a Chunk + public Anchor(Chunk chunk) : base(chunk) {} + + /// + /// Constructs an Anchor with a certain string. + /// + /// a string + public Anchor(string str) : base(str) {} + + /// + /// Constructs an Anchor with a certain string + /// and a certain Font. + /// + /// a string + /// a Font + public Anchor(string str, Font font) : base(str, font) {} + + /// + /// Constructs an Anchor with a certain Chunk + /// and a certain leading. + /// + /// the leading + /// a Chunk + public Anchor(float leading, Chunk chunk) : base(leading, chunk) {} + + /// + /// Constructs an Anchor with a certain leading + /// and a certain string. + /// + /// the leading + /// a string + public Anchor(float leading, string str) : base(leading, str) {} + + /// + /// Constructs an Anchor with a certain leading, + /// a certain string and a certain Font. + /// + /// the leading + /// a string + /// a Font + public Anchor(float leading, string str, Font font) : base(leading, str, font) {} + + /** + * Constructs an Anchor with a certain Phrase. + * + * @param phrase a Phrase + */ + public Anchor(Phrase phrase) : base(phrase) { + if (phrase is Anchor) { + Anchor a = (Anchor) phrase; + Name = a.name; + Reference = a.reference; + } + } + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// + /// + /// an IElementListener + /// true if the element was processed successfully + public override bool Process(IElementListener listener) + { + try + { + bool localDestination = (reference != null && reference.StartsWith("#")); + bool notGotoOK = true; + foreach (Chunk chunk in this.Chunks) + { + if (name != null && notGotoOK && !chunk.IsEmpty()) + { + chunk.SetLocalDestination(name); + notGotoOK = false; + } + if (localDestination) + { + chunk.SetLocalGoto(reference.Substring(1)); + } + else if (reference != null) + chunk.SetAnchor(reference); + listener.Add(chunk); + } + return true; + } + catch (DocumentException) + { + return false; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public override ArrayList Chunks + { + get + { + ArrayList tmp = new ArrayList(); + bool localDestination = (reference != null && reference.StartsWith("#")); + bool notGotoOK = true; + foreach (Chunk chunk in this) + { + if (name != null && notGotoOK && !chunk.IsEmpty()) + { + chunk.SetLocalDestination(name); + notGotoOK = false; + } + if (localDestination) + { + chunk.SetLocalGoto(reference.Substring(1)); + } + else if (reference != null) + { + chunk.SetAnchor(reference); + } + + tmp.Add(chunk); + } + return tmp; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type + { + get + { + return Element.ANCHOR; + } + } + + // methods + + /// + /// Name of this Anchor. + /// + public string Name { + get { + return this.name; + } + + set { + this.name = value; + } + } + + // methods to retrieve information + + /// + /// reference of this Anchor. + /// + public string Reference { + get { + return reference; + } + + set { + this.reference = value; + } + } + + /// + /// reference of this Anchor. + /// + /// an Uri + public Uri Url { + get { + try { + return new Uri(reference); + } + catch { + return null; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Annotation.cs b/iTechSharp/iTextSharp/text/Annotation.cs new file mode 100644 index 0000000..dd61c44 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Annotation.cs @@ -0,0 +1,525 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Annotation.cs,v 1.12 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// An Annotation is a little note that can be added to a page + /// on a document. + /// + /// + /// + public class Annotation : IElement + { + + // membervariables + + /// This is a possible annotation type. + public const int TEXT = 0; + /// This is a possible annotation type. + public const int URL_NET = 1; + /// This is a possible annotation type. + public const int URL_AS_STRING = 2; + /// This is a possible annotation type. + public const int FILE_DEST = 3; + /// This is a possible annotation type. + public const int FILE_PAGE = 4; + /// This is a possible annotation type. + public const int NAMED_DEST = 5; + /// This is a possible annotation type. + public const int LAUNCH = 6; + /// This is a possible annotation type. + public const int SCREEN = 7; + + /// This is a possible attribute. + public const string TITLE = "title"; + /// This is a possible attribute. + public const string CONTENT = "content"; + /// This is a possible attribute. + public const string URL = "url"; + /// This is a possible attribute. + public const string FILE = "file"; + /// This is a possible attribute. + public const string DESTINATION = "destination"; + /// This is a possible attribute. + public const string PAGE = "page"; + /// This is a possible attribute. + public const string NAMED = "named"; + /// This is a possible attribute. + public const string APPLICATION = "application"; + /// This is a possible attribute. + public const string PARAMETERS = "parameters"; + /// This is a possible attribute. + public const string OPERATION = "operation"; + /// This is a possible attribute. + public const string DEFAULTDIR = "defaultdir"; + /// This is a possible attribute. + public const string LLX = "llx"; + /// This is a possible attribute. + public const string LLY = "lly"; + /// This is a possible attribute. + public const string URX = "urx"; + /// This is a possible attribute. + public const string URY = "ury"; + /// This is a possible attribute. + public const string MIMETYPE = "mime"; + + /// This is the type of annotation. + protected int annotationtype; + + /// This is the title of the Annotation. + protected Hashtable annotationAttributes = new Hashtable(); + + /// This is the lower left x-value + private float llx = float.NaN; + /// This is the lower left y-value + private float lly = float.NaN; + /// This is the upper right x-value + private float urx = float.NaN; + /// This is the upper right y-value + private float ury = float.NaN; + + // constructors + + /// + /// Constructs an Annotation with a certain title and some text. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + private Annotation(float llx, float lly, float urx, float ury) + { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + public Annotation(Annotation an) { + annotationtype = an.annotationtype; + annotationAttributes = an.annotationAttributes; + llx = an.llx; + lly = an.lly; + urx = an.urx; + ury = an.ury; + } + + /// + /// Constructs an Annotation with a certain title and some text. + /// + /// the title of the annotation + /// the content of the annotation + public Annotation(string title, string text) + { + annotationtype = TEXT; + annotationAttributes[TITLE] = title; + annotationAttributes[CONTENT] = text; + } + + /// + /// Constructs an Annotation with a certain title and some text. + /// + /// the title of the annotation + /// the content of the annotation + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + public Annotation(string title, string text, float llx, float lly, float urx, float ury) : this(llx, lly, urx, ury) + { + annotationtype = TEXT; + annotationAttributes[TITLE] = title; + annotationAttributes[CONTENT] = text; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// the external reference + public Annotation(float llx, float lly, float urx, float ury, Uri url) : this(llx, lly, urx, ury) + { + annotationtype = URL_NET; + annotationAttributes[URL] = url; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// the external reference + public Annotation(float llx, float lly, float urx, float ury, string url) : this(llx, lly, urx, ury) + { + annotationtype = URL_AS_STRING; + annotationAttributes[FILE] = url; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// an external PDF file + /// the destination in this file + public Annotation(float llx, float lly, float urx, float ury, string file, string dest) : this(llx, lly, urx, ury) + { + annotationtype = FILE_DEST; + annotationAttributes[FILE] = file; + annotationAttributes[DESTINATION] = dest; + } + + /// + /// Creates a Screen anotation to embed media clips + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// path to the media clip file + /// mime type of the media + /// if true play on display of the page + public Annotation(float llx, float lly, float urx, float ury, + string moviePath, string mimeType, bool showOnDisplay) : this(llx, lly, urx, ury) + { + annotationtype = SCREEN; + annotationAttributes[FILE] = moviePath; + annotationAttributes[MIMETYPE] = mimeType; + annotationAttributes[PARAMETERS] = new bool[] {false /* embedded */, showOnDisplay }; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// an external PDF file + /// a page number in this file + public Annotation(float llx, float lly, float urx, float ury, string file, int page) : this(llx, lly, urx, ury) + { + annotationtype = FILE_PAGE; + annotationAttributes[FILE] = file; + annotationAttributes[PAGE] = page; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// a named destination in this file + /// + /// Has nine overloads. + /// + public Annotation(float llx, float lly, float urx, float ury, int named) : this(llx, lly, urx, ury) + { + annotationtype = NAMED_DEST; + annotationAttributes[NAMED] = named; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// an external application + /// parameters to pass to this application + /// the operation to pass to this application + /// the default directory to run this application in + public Annotation(float llx, float lly, float urx, float ury, string application, string parameters, string operation, string defaultdir) : this(llx, lly, urx, ury) + { + annotationtype = LAUNCH; + annotationAttributes[APPLICATION] = application; + annotationAttributes[PARAMETERS] = parameters; + annotationAttributes[OPERATION] = operation; + annotationAttributes[DEFAULTDIR] = defaultdir; + } + + // implementation of the Element-methods + + /// + /// Gets the type of the text element + /// + public int Type + { + get + { + return Element.ANNOTATION; + } + } + + // methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was process successfully + public bool Process(IElementListener listener) + { + try + { + return listener.Add(this); + } + catch (DocumentException) + { + return false; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks + { + get + { + return new ArrayList(); + } + } + + // methods + + /// + /// Sets the dimensions of this annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + public void SetDimensions (float llx, float lly, float urx, float ury) + { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + // methods to retrieve information + + /// + /// Returns the lower left x-value. + /// + /// a value + public float GetLlx() + { + return llx; + } + + /// + /// Returns the lower left y-value. + /// + /// a value + public float GetLly() + { + return lly; + } + + /// + /// Returns the uppper right x-value. + /// + /// a value + public float GetUrx() + { + return urx; + } + + /// + /// Returns the uppper right y-value. + /// + /// a value + public float GetUry() + { + return ury; + } + + /// + /// Returns the lower left x-value. + /// + /// the default value + /// a value + public float GetLlx(float def) + { + if (float.IsNaN(llx)) + return def; + return llx; + } + + /// + /// Returns the lower left y-value. + /// + /// the default value + /// a value + public float GetLly(float def) + { + if (float.IsNaN(lly)) + return def; + return lly; + } + + /// + /// Returns the upper right x-value. + /// + /// the default value + /// a value + public float GetUrx(float def) + { + if (float.IsNaN(urx)) + return def; + return urx; + } + + /// + /// Returns the upper right y-value. + /// + /// the default value + /// a value + public float GetUry(float def) + { + if (float.IsNaN(ury)) + return def; + return ury; + } + + /// + /// Returns the type of this Annotation. + /// + /// a type + public int AnnotationType + { + get + { + return annotationtype; + } + } + + /// + /// Returns the title of this Annotation. + /// + /// a name + public string Title + { + get + { + string s = (string)annotationAttributes[TITLE]; + if (s == null) + s = ""; + return s; + } + } + + /// + /// Gets the content of this Annotation. + /// + /// a reference + public string Content + { + get + { + string s = (string)annotationAttributes[CONTENT]; + if (s == null) s = ""; + return s; + } + } + + /// + /// Gets the content of this Annotation. + /// + /// a reference + public Hashtable Attributes + { + get + { + return annotationAttributes; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + public override string ToString() { + return base.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/BadElementException.cs b/iTechSharp/iTextSharp/text/BadElementException.cs new file mode 100644 index 0000000..0c5c03d --- /dev/null +++ b/iTechSharp/iTextSharp/text/BadElementException.cs @@ -0,0 +1,66 @@ +using System; + +/* + * $Id: BadElementException.cs,v 1.3 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// Signals an attempt to create an Element that hasn't got the right form. + /// + /// + /// + public class BadElementException : DocumentException + { + public BadElementException() : base() {} + + public BadElementException(string message) : base(message) {} + } +} diff --git a/iTechSharp/iTextSharp/text/Cell.cs b/iTechSharp/iTextSharp/text/Cell.cs new file mode 100644 index 0000000..64cd0e3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Cell.cs @@ -0,0 +1,873 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text.factories; + +/* + * $Id: Cell.cs,v 1.17 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Cell is a Rectangle containing other Elements. + /// + /// + /// A Cell is a Rectangle containing other + /// Elements. + ///

+ /// A Cell must be added to a Table. + /// The Table will place the Cell in + /// a Row. + /// + /// + /// + /// Table table = new Table(3); + /// table.SetBorderWidth(1); + /// table.SetBorderColor(new Color(0, 0, 255)); + /// table.SetCellpadding(5); + /// table.SetCellspacing(5); + /// Cell cell = new Cell("header"); + /// cell.SetHeader(true); + /// cell.SetColspan(3); + /// table.AddCell(cell); + /// cell = new Cell("example cell with colspan 1 and rowspan 2"); + /// cell.SetRowspan(2); + /// cell.SetBorderColor(new Color(255, 0, 0)); + /// table.AddCell(cell); + /// table.AddCell("1.1"); + /// table.AddCell("2.1"); + /// table.AddCell("1.2"); + /// table.AddCell("2.2"); + /// + /// + /// + /// + /// + /// + public class Cell : Rectangle, ITextElementArray { + + // static membervariable + + public static Cell DummyCell { + get { + Cell cell = new Cell(true); + cell.Colspan = 3; + cell.Border = NO_BORDER; + return cell; + } + } + + // membervariables + + ///

This is the ArrayList of Elements. + protected ArrayList arrayList = null; + + /// This is the horizontal Element. + protected int horizontalAlignment = Element.ALIGN_UNDEFINED; + + /// This is the vertical Element. + protected int verticalAlignment = Element.ALIGN_UNDEFINED; + + /// This is the vertical Element. + protected float width; + protected bool percentage = false; + + /// This is the colspan. + protected int colspan = 1; + + /// This is the rowspan. + protected int rowspan = 1; + + /// This is the leading. + float leading = float.NaN; + + /// Is this Cell a header? + protected bool header; + + /// + /// Indicates that the largest ascender height should be used to determine the + /// height of the first line. Note that this only has an effect when rendered + /// to PDF. Setting this to true can help with vertical alignment problems. + /// + protected bool useAscender = false; + + /// + /// Indicates that the largest descender height should be added to the height of + /// the last line (so characters like y don't dip into the border). Note that + /// this only has an effect when rendered to PDF. + /// + protected bool useDescender = false; + + /// + /// Adjusts the cell contents to compensate for border widths. Note that + /// this only has an effect when rendered to PDF. + /// + protected bool useBorderPadding; + + /// Will the element have to be wrapped? + protected bool noWrap; + + // constructors + + /** + * Constructs an empty Cell. + */ + /// + /// Constructs an empty Cell. + /// + /// + /// Has five overloads. + /// + public Cell() : base(0, 0, 0, 0) { + // creates a Rectangle with BY DEFAULT a border of 0.5 + + this.Border = UNDEFINED; + this.BorderWidth = 0.5F; + + // initializes the arraylist and adds an element + arrayList = new ArrayList(); + } + + /// + /// Constructs an empty Cell (for internal use only). + /// + /// a dummy value + public Cell(bool dummy) : this() { + arrayList.Add(new Paragraph(0)); + } + + /// + /// Constructs a Cell with a certain content. + /// + /// + /// The string will be converted into a Paragraph. + /// + /// a string + public Cell(string content) : this() { + AddElement(new Paragraph(content)); + } + + /// + /// Constructs a Cell with a certain Element. + /// + /// + /// if the element is a ListItem, Row or + /// Cell, an exception will be thrown. + /// + /// the element + public Cell(IElement element) : this() { + if (element is Phrase) { + Leading = ((Phrase)element).Leading; + } + AddElement(element); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public override bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.CELL; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public override ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in arrayList) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + // methods to set the membervariables + + /** + * Adds an element to this Cell. + *

+ * Remark: you can't add ListItems, Rows, Cells, + * JPEGs, GIFs or PNGs to a Cell. + * + * @param element The Element to add + * @throws BadElementException if the method was called with a ListItem, Row or Cell + */ + ///

+ /// Adds an element to this Cell. + /// + /// + /// You can't add ListItems, Rows, Cells, + /// JPEGs, GIFs or PNGs to a Cell. + /// + /// the Element to add + public void AddElement(IElement element) { + if (IsTable()) { + Table table = (Table) arrayList[0]; + Cell tmp = new Cell(element); + tmp.Border = NO_BORDER; + tmp.Colspan = table.Columns; + table.AddCell(tmp); + return; + } + switch (element.Type) { + case Element.LISTITEM: + case Element.ROW: + case Element.CELL: + throw new BadElementException("You can't add listitems, rows or cells to a cell."); + case Element.JPEG: + case Element.IMGRAW: + case Element.IMGTEMPLATE: + arrayList.Add(element); + break; + case Element.LIST: + if (float.IsNaN(this.Leading)) { + leading = ((List) element).TotalLeading; + } + if (((List) element).IsEmpty()) return; + arrayList.Add(element); + return; + case Element.ANCHOR: + case Element.PARAGRAPH: + case Element.PHRASE: + if (float.IsNaN(leading)) { + leading = ((Phrase) element).Leading; + } + if (((Phrase) element).IsEmpty()) return; + arrayList.Add(element); + return; + case Element.CHUNK: + if (((Chunk) element).IsEmpty()) return; + arrayList.Add(element); + return; + case Element.TABLE: + Table table = new Table(3); + float[] widths = new float[3]; + widths[1] = ((Table)element).Width; + + switch (((Table)element).Alignment) { + case Element.ALIGN_LEFT: + widths[0] = 0f; + widths[2] = 100f - widths[1]; + break; + case Element.ALIGN_CENTER: + widths[0] = (100f - widths[1]) / 2f; + widths[2] = widths[0]; + break; + case Element.ALIGN_RIGHT: + widths[0] = 100f - widths[1]; + widths[2] = 0f; + break; + } + table.Widths = widths; + Cell tmp; + if (arrayList.Count == 0) { + table.AddCell(Cell.DummyCell); + } + else { + tmp = new Cell(); + tmp.Border = NO_BORDER; + tmp.Colspan = 3; + foreach (IElement ele in arrayList) { + tmp.Add(ele); + } + table.AddCell(tmp); + } + tmp = new Cell(); + tmp.Border = NO_BORDER; + table.AddCell(tmp); + table.InsertTable((Table)element); + tmp = new Cell(); + tmp.Border = NO_BORDER; + table.AddCell(tmp); + table.AddCell(Cell.DummyCell); + Clear(); + arrayList.Add(table); + return; + default: + arrayList.Add(element); + break; + } + } + + /// + /// Add an Object to this cell. + /// + /// the object to add + /// always true + public bool Add(Object o) { + try { + this.AddElement((IElement) o); + return true; + } + catch (BadElementException bee) { + throw new Exception(bee.Message); + } + catch { + throw new Exception("You can only add objects that implement the Element interface."); + } + } + + /// + /// Sets the alignment of this cell. + /// + /// the new alignment as a string + public void SetHorizontalAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_CENTER)) { + this.HorizontalAlignment = Element.ALIGN_CENTER; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.HorizontalAlignment = Element.ALIGN_RIGHT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED)) { + this.HorizontalAlignment = Element.ALIGN_JUSTIFIED; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED_ALL)) { + this.HorizontalAlignment = Element.ALIGN_JUSTIFIED_ALL; + return; + } + this.HorizontalAlignment = Element.ALIGN_LEFT; + } + + /// + /// Sets the alignment of this paragraph. + /// + /// the new alignment as a string + public void SetVerticalAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_MIDDLE)) { + this.VerticalAlignment = Element.ALIGN_MIDDLE; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_BOTTOM)) { + this.VerticalAlignment = Element.ALIGN_BOTTOM; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_BASELINE)) { + this.VerticalAlignment = Element.ALIGN_BASELINE; + return; + } + this.VerticalAlignment = Element.ALIGN_TOP; + } + + /// + /// Sets the width. + /// + /// the new value + public override float Width { + set { + width = value; + } + get { + return width; + } + } + + /** + * Sets the width. + * It can be an absolute value "100" or a percentage "20%" + * + * @param value the new value + */ + public void SetWidth(String value) { + if (value.EndsWith("%")) { + value = value.Substring(0, value.Length - 1); + percentage = true; + } + width = int.Parse(value); + } + + /** + * Gets the width as a String. + * + * @return a value + */ + public String GetWidthAsString() { + String w = width.ToString(System.Globalization.CultureInfo.InvariantCulture); + if (w.EndsWith(".0")) w = w.Substring(0, w.Length - 2); + if (percentage) w += "%"; + return w; + } + + // methods to retrieve information + + /// + /// Gets the number of Elements in the Cell. + /// + /// a size + public int Size { + get { + return arrayList.Count; + } + } + + /// + /// Checks if the Cell is empty. + /// + /// false if there are non-empty Elements in the Cell. + public bool IsEmpty() { + switch (this.Size) { + case 0: + return true; + case 1: + IElement element = (IElement)arrayList[0]; + switch (element.Type) { + case Element.CHUNK: + return ((Chunk) element).IsEmpty(); + case Element.ANCHOR: + case Element.PHRASE: + case Element.PARAGRAPH: + return ((Phrase) element).IsEmpty(); + case Element.LIST: + return ((List) element).IsEmpty(); + } + return false; + default: + return false; + } + } + + /// + /// Makes sure there is at least 1 object in the Cell. + /// Otherwise it might not be shown in the table. + /// + internal void Fill() { + if (this.Size == 0) arrayList.Add(new Paragraph(0)); + } + + /// + /// Checks if the Cell is empty. + /// + /// false if there are non-empty Elements in the Cell. + public bool IsTable() { + return (this.Size == 1) && (((IElement)arrayList[0]).Type == Element.TABLE); + } + + /// + /// Gets Elements. + /// + /// an ArrayList + public ArrayList Elements { + get { + return arrayList; + } + } + + /// + /// Gets/Sets the horizontal Element. + /// + /// a value + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + + set { + horizontalAlignment = value; + } + } + + /// + /// Gets/sets the vertical Element. + /// + /// a value + public int VerticalAlignment { + get { + return verticalAlignment; + } + + set { + verticalAlignment = value; + } + } + + /** + * Gets the colspan. + * + * @return a value + */ + /// + /// Gets/sets the colspan. + /// + /// a value + public int Colspan { + get { + return colspan; + } + + set { + colspan = value; + } + } + + /// + /// Gets/sets the rowspan. + /// + /// a value + public int Rowspan { + get { + return rowspan; + } + + set { + rowspan = value; + } + } + + /// + /// Gets/sets the leading. + /// + /// a value + public float Leading { + get { + if (float.IsNaN(leading)) { + return 16; + } + return leading; + } + + set { + leading = value; + } + } + + /// + /// Gets/sets header + /// + /// a value + public bool Header { + get { + return header; + } + + set { + header = value; + } + } + + /** + * Get nowrap. + * + * @return a value + */ + /// + /// Get/set nowrap. + /// + /// a value + public bool NoWrap { + get { + return (maxLines == 1); + } + + set { + maxLines = 1; + } + } + + /// + /// Clears all the Elements of this Cell. + /// + public void Clear() { + arrayList.Clear(); + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Top { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Bottom { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Left { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Right { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetTop(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetBottom(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetLeft(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetRight(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.CELL.Equals(tag); + } + + + ///Does this Cell force a group change? + protected bool groupChange = true; + + /// + /// Does this Cell force a group change? + /// + public bool GroupChange { + get { + return groupChange; + } + + set { + groupChange = value; + } + } + + /// + /// get/set maxLines value + /// + public int MaxLines { + get { + return maxLines; + } + + set { + maxLines = value; + } + } + + /// + /// Maximum number of lines allowed in the cell. + /// The default value of this property is not to limit the maximum number of lines + /// (contributed by dperezcar@fcc.es) + /// + protected int maxLines = int.MaxValue; + + /// + /// get/set showTruncation value + /// + public string ShowTruncation { + get { + return showTruncation; + } + + set { + showTruncation = value; + } + } + + /// + /// If a truncation happens due to the {@link #maxLines} property, then this text will + /// be added to indicate a truncation has happened. + /// Default value is null, and means avoiding marking the truncation. + /// A useful value of this property could be e.g. "..." + /// (contributed by dperezcar@fcc.es) + /// + private string showTruncation; + + /// + /// get/set useAscender value + /// + public bool UseAscender { + get { + return useAscender; + } + + set { + useAscender = value; + } + } + + /// + /// get/set useDescender value + /// + public bool UseDescender { + get { + return useDescender; + } + + set { + useDescender = value; + } + } + + /// + /// get/set useBorderPadding value + /// + public bool UseBorderPadding { + get { + return useBorderPadding; + } + + set { + useBorderPadding = value; + } + } + /** + * Creates a PdfPCell based on this Cell object. + * @return a PdfPCell + * @throws BadElementException + */ + public PdfPCell CreatePdfPCell() { + if (rowspan > 1) throw new BadElementException("PdfPCells can't have a rowspan > 1"); + if (IsTable()) return new PdfPCell(((Table)arrayList[0]).CreatePdfPTable()); + PdfPCell cell = new PdfPCell(); + cell.VerticalAlignment = verticalAlignment; + cell.HorizontalAlignment = horizontalAlignment; + cell.Colspan = colspan; + cell.UseBorderPadding = useBorderPadding; + cell.UseDescender = useDescender; + cell.SetLeading(Leading, 0); + cell.CloneNonPositionParameters(this); + cell.NoWrap = noWrap; + foreach (IElement i in Elements) { + if (i.Type == Element.PHRASE || i.Type == Element.PARAGRAPH) { + Paragraph p = new Paragraph((Phrase)i); + p.Alignment = horizontalAlignment; + cell.AddElement(p); + } + else + cell.AddElement(i); + } + return cell; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Chapter.cs b/iTechSharp/iTextSharp/text/Chapter.cs new file mode 100644 index 0000000..9a9f874 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Chapter.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Chapter.cs,v 1.10 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + */ + +namespace iTextSharp.text +{ + /// + /// A Chapter is a special Section. + /// + /// + /// A chapter number has to be created using a Paragraph as title + /// and an int as chapter number. The chapter number is shown be + /// default. If you don't want to see the chapter number, you have to set the + /// numberdepth to 0. + /// + /// + /// + /// Paragraph title2 = new Paragraph("This is Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// Chapter chapter2 = new Chapter(title2, 2); + /// chapter2.SetNumberDepth(0); + /// Paragraph someText = new Paragraph("This is some text"); + /// chapter2.Add(someText); + /// Paragraph title21 = new Paragraph("This is Section 1 in Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0))); + /// Section section1 = chapter2.AddSection(title21); + /// Paragraph someSectionText = new Paragraph("This is some silly paragraph in a chapter and/or section. It contains some text to test the functionality of Chapters and Section."); + /// section1.Add(someSectionText); + /// + /// + public class Chapter : Section + { + + // constructors + + /** + * Constructs a new Chapter. + * @param number the Chapter number + */ + + public Chapter(int number) : base (null, 1) { + numbers = new ArrayList(); + numbers.Add(number); + triggerNewPage = true; + } + + /// + /// Constructs a new Chapter. + /// + /// the Chapter title (as a Paragraph) + /// the Chapter number + /// + /// Has three overloads. + /// + public Chapter(Paragraph title, int number) : base(title, 1) + { + numbers = new ArrayList(); + numbers.Add(number); + triggerNewPage = true; + } + + /// + /// Constructs a new Chapter. + /// + /// the Chapter title (as a string) + /// the Chapter number + /// + /// Has three overloads. + /// + public Chapter(string title, int number) : this(new Paragraph(title), number) {} + + // implementation of the Element-methods + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.CHAPTER; + } + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ChapterAutoNumber.cs b/iTechSharp/iTextSharp/text/ChapterAutoNumber.cs new file mode 100644 index 0000000..e3ad8a6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ChapterAutoNumber.cs @@ -0,0 +1,101 @@ +using System; + +/* + * Copyright 2005 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Chapter with auto numbering. + * + * @author Michael Niedermair + */ + public class ChapterAutoNumber : Chapter { + + /** + * Create a new object. + * + * @param para the Chapter title (as a Paragraph) + */ + public ChapterAutoNumber(Paragraph para) : base(para, 0) { + } + + /** + * Create a new objet. + * + * @param title the Chapter title (as a String) + */ + public ChapterAutoNumber(String title) : base(title, 0) { + } + + /** + * Create a new section for this chapter and ad it. + * + * @param title the Section title (as a String) + * @return Returns the new section. + */ + public override Section AddSection(String title) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + return AddSection(title, 2); + } + + /** + * Create a new section for this chapter and add it. + * + * @param title the Section title (as a Paragraph) + * @return Returns the new section. + */ + public override Section AddSection(Paragraph title) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + return AddSection(title, 2); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Chunk.cs b/iTechSharp/iTextSharp/text/Chunk.cs new file mode 100644 index 0000000..ee7377b --- /dev/null +++ b/iTechSharp/iTextSharp/text/Chunk.cs @@ -0,0 +1,733 @@ +using System; +using System.Text; +using System.Collections; +using System.util; + +using iTextSharp.text.pdf; +using iTextSharp.text.html; +using iTextSharp.text.factories; +using iTextSharp.text.pdf.draw; + +/* + * $Id: Chunk.cs,v 1.20 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// This is the smallest significant part of text that can be added to a document. + /// + /// + /// Most elements can be divided in one or more Chunks. + /// A chunk is a string with a certain Font. + /// all other layoutparameters should be defined in the object to which + /// this chunk of text is added. + /// + /// + /// + /// Chunk chunk = new Chunk("Hello world", FontFactory.GetFont(FontFactory.COURIER, 20, Font.ITALIC, new Color(255, 0, 0))); + /// document.Add(chunk); + /// + /// + public class Chunk : IElement { + + // public static membervariables + + /** The character stand in for an image or a separator. */ + public const string OBJECT_REPLACEMENT_CHARACTER = "\ufffc"; + + /// This is a Chunk containing a newline. + public static readonly Chunk NEWLINE = new Chunk("\n"); + + /** This is a Chunk containing a newpage. */ + public static readonly Chunk NEXTPAGE = new Chunk(""); + static Chunk() { + NEXTPAGE.SetNewPage(); + } + + + // member variables + + /// This is the content of this chunk of text. + protected StringBuilder content = null; + + /// This is the Font of this chunk of text. + protected Font font = null; + + /// Contains some of the attributes for this Chunk. + protected Hashtable attributes = null; + + // constructors + + /// + /// Empty constructor. + /// + /// + /// Has six overloads. + /// + public Chunk() { + this.content = new StringBuilder(); + this.font = new Font(); + } + + /** + * A Chunk copy constructor. + * @param ck the Chunk to be copied + */ + public Chunk(Chunk ck) { + if (ck.content != null) { + content = new StringBuilder(ck.content.ToString()); + } + if (ck.font != null) { + font = new Font(ck.font); + } + } + + /// + /// Constructs a chunk of text with a certain content and a certain Font. + /// + /// the content + /// the font + public Chunk(string content, Font font) { + this.content = new StringBuilder(content); + this.font = font; + } + + /// + /// Constructs a chunk of text with a certain content, without specifying a Font. + /// + /// the content + public Chunk(string content) : this(content, new Font()) {} + + /** + * Constructs a chunk of text with a char and a certain Font. + * + * @param c the content + * @param font the font + */ + public Chunk(char c, Font font) { + this.content = new StringBuilder(); + this.content.Append(c); + this.font = font; + } + + /** + * Constructs a chunk of text with a char, without specifying a Font. + * + * @param c the content + */ + public Chunk(char c) : this(c, new Font()) { + } + + /// + /// Constructs a chunk containing an Image. + /// + /// the image + /// the image offset in the x direction + /// the image offset in the y direction + public Chunk(Image image, float offsetX, float offsetY) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + Image copyImage = Image.GetInstance(image); + copyImage.SetAbsolutePosition(float.NaN, float.NaN); + SetAttribute(IMAGE, new Object[]{copyImage, offsetX, offsetY, false}); + } + + /** + * Key for drawInterface of the Separator. + * @since 2.1.2 + */ + public const String SEPARATOR = "SEPARATOR"; + + /** + * Creates a separator Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the separator. + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator) : this(separator, false) { + } + + /** + * Creates a separator Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the separator. + * @param vertical true if this is a vertical separator + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator, bool vertical) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + SetAttribute(SEPARATOR, new Object[] {separator, vertical}); + } + + /** + * Key for drawInterface of the tab. + * @since 2.1.2 + */ + public const String TAB = "TAB"; + + /** + * Creates a tab Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the tab. + * @param tabPosition an X coordinate that will be used as start position for the next Chunk. + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator, float tabPosition) : this(separator, tabPosition, false) { + } + + /** + * Creates a tab Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the tab. + * @param tabPosition an X coordinate that will be used as start position for the next Chunk. + * @param newline if true, a newline will be added if the tabPosition has already been reached. + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator, float tabPosition, bool newline) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + if (tabPosition < 0) { + throw new ArgumentException("A tab position may not be lower than 0; yours is " + tabPosition); + } + SetAttribute(TAB, new Object[] {separator, tabPosition, newline, 0}); + } + + /// + /// Constructs a chunk containing an Image. + /// + /// the image + /// the image offset in the x direction + /// the image offset in the y direction + /// true if the leading has to be adapted to the image + public Chunk(Image image, float offsetX, float offsetY, bool changeLeading) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + SetAttribute(IMAGE, new Object[]{image, offsetX, offsetY, changeLeading}); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return Element.CHUNK; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + tmp.Add(this); + return tmp; + } + } + + // methods + + /// + /// appends some text to this Chunk. + /// + /// a string + /// a StringBuilder + public StringBuilder Append(string str) { + return content.Append(str); + } + + // methods to retrieve information + + /// + /// Get/set the font of this Chunk. + /// + /// a Font + public virtual Font Font { + get { + return font; + } + + set { + this.font = value; + } + } + + + /// + /// Returns the content of this Chunk. + /// + /// a string + public virtual string Content { + get { + return content.ToString(); + } + } + + public override string ToString() { + return content.ToString(); + } + + + /// + /// Checks is this Chunk is empty. + /// + /// false if the Chunk contains other characters than space. + public virtual bool IsEmpty() { + return (content.ToString().Trim().Length == 0) && (content.ToString().IndexOf("\n") == -1) && (attributes == null); + } + + /** + * Gets the width of the Chunk in points. + * @return a width in points + */ + public float GetWidthPoint() { + if (GetImage() != null) { + return GetImage().ScaledWidth; + } + return font.GetCalculatedBaseFont(true).GetWidthPoint(Content, font.CalculatedSize) * HorizontalScaling; + } + + /// + /// Checks the attributes of this Chunk. + /// + /// false if there aren't any. + public bool HasAttributes() { + return attributes != null; + } + + /// + /// Gets the attributes for this Chunk. + /// + /// + /// It may be null. + /// + /// a Hashtable + public Hashtable Attributes { + get { + return attributes; + } + set { + attributes = value; + } + } + + /// + /// Sets an arbitrary attribute. + /// + /// the key for the attribute + /// the value of the attribute + /// this Chunk + private Chunk SetAttribute(string name, Object obj) { + if (attributes == null) + attributes = new Hashtable(); + attributes[name] = obj; + return this; + } + + /** Key for text horizontal scaling. */ + public const string HSCALE = "HSCALE"; + + /** + * Sets the text horizontal scaling. A value of 1 is normal and a value of 0.5f + * shrinks the text to half it's width. + * @param scale the horizontal scaling factor + * @return this Chunk + */ + public Chunk SetHorizontalScaling(float scale) { + return SetAttribute(HSCALE, scale); + } + + /** + * Gets the horizontal scaling. + * @return a percentage in float + */ + public float HorizontalScaling { + get { + if (attributes == null) return 1f; + Object f = attributes[HSCALE]; + if (f == null) return 1f; + return (float)f; + } + } + + /// Key for underline. + public const string UNDERLINE = "UNDERLINE"; + + /** + * Sets an horizontal line that can be an underline or a strikethrough. + * Actually, the line can be anywhere vertically and has always the + * Chunk width. Multiple call to this method will + * produce multiple lines. + * @param thickness the absolute thickness of the line + * @param yPosition the absolute y position relative to the baseline + * @return this Chunk + */ + public Chunk SetUnderline(float thickness, float yPosition) { + return SetUnderline(null, thickness, 0f, yPosition, 0f, PdfContentByte.LINE_CAP_BUTT); + } + + /** + * Sets an horizontal line that can be an underline or a strikethrough. + * Actually, the line can be anywhere vertically and has always the + * Chunk width. Multiple call to this method will + * produce multiple lines. + * @param color the color of the line or null to follow + * the text color + * @param thickness the absolute thickness of the line + * @param thicknessMul the thickness multiplication factor with the font size + * @param yPosition the absolute y position relative to the baseline + * @param yPositionMul the position multiplication factor with the font size + * @param cap the end line cap. Allowed values are + * PdfContentByte.LINE_CAP_BUTT, PdfContentByte.LINE_CAP_ROUND and + * PdfContentByte.LINE_CAP_PROJECTING_SQUARE + * @return this Chunk + */ + public Chunk SetUnderline(Color color, float thickness, float thicknessMul, float yPosition, float yPositionMul, int cap) { + if (attributes == null) + attributes = new Hashtable(); + Object[] obj = {color, new float[]{thickness, thicknessMul, yPosition, yPositionMul, (float)cap}}; + Object[][] unders = Utilities.AddToArray((Object[][])attributes[UNDERLINE], obj); + return SetAttribute(UNDERLINE, unders); + } + + /// Key for sub/basescript. + public const string SUBSUPSCRIPT = "SUBSUPSCRIPT"; + + /// + /// Sets the text displacement relative to the baseline. Positive values rise the text, + /// negative values lower the text. + /// + /// + /// It can be used to implement sub/basescript. + /// + /// the displacement in points + /// this Chunk + public Chunk SetTextRise(float rise) { + return SetAttribute(SUBSUPSCRIPT, rise); + } + + public float GetTextRise() { + if (attributes != null && attributes.ContainsKey(SUBSUPSCRIPT)) { + return (float)attributes[SUBSUPSCRIPT]; + } + return 0.0f; + } + + /// Key for text skewing. + public const string SKEW = "SKEW"; + + /** + * Skews the text to simulate italic and other effects. + * Try alpha=0 and beta=12. + * @param alpha the first angle in degrees + * @param beta the second angle in degrees + * @return this Chunk + */ + public Chunk SetSkew(float alpha, float beta) { + alpha = (float)Math.Tan(alpha * Math.PI / 180); + beta = (float)Math.Tan(beta * Math.PI / 180); + return SetAttribute(SKEW, new float[]{alpha, beta}); + } + + /// Key for background. + public const string BACKGROUND = "BACKGROUND"; + + /// + /// Sets the color of the background Chunk. + /// + /// the color of the background + /// this Chunk + public Chunk SetBackground(Color color) { + return SetBackground(color, 0, 0, 0, 0); + } + + /** Sets the color and the size of the background Chunk. + * @param color the color of the background + * @param extraLeft increase the size of the rectangle in the left + * @param extraBottom increase the size of the rectangle in the bottom + * @param extraRight increase the size of the rectangle in the right + * @param extraTop increase the size of the rectangle in the top + * @return this Chunk + */ + public Chunk SetBackground(Color color, float extraLeft, float extraBottom, float extraRight, float extraTop) { + return SetAttribute(BACKGROUND, new Object[]{color, new float[]{extraLeft, extraBottom, extraRight, extraTop}}); + } + + /// Key for text rendering mode. + public const string TEXTRENDERMODE = "TEXTRENDERMODE"; + + /** Sets the text rendering mode. It can outline text, simulate bold and make + * text invisible. + * @param mode the text rendering mode. It can be PdfContentByte.TEXT_RENDER_MODE_FILL, + * PdfContentByte.TEXT_RENDER_MODE_STROKE, PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE + * and PdfContentByte.TEXT_RENDER_MODE_INVISIBLE. + * @param strokeWidth the stroke line width for the modes PdfContentByte.TEXT_RENDER_MODE_STROKE and + * PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE. + * @param strokeColor the stroke color or null to follow the text color + * @return this Chunk + */ + public Chunk SetTextRenderMode(int mode, float strokeWidth, Color strokeColor) { + return SetAttribute(TEXTRENDERMODE, new Object[]{mode, strokeWidth, strokeColor}); + } + + /// Key for split character. + public const string SPLITCHARACTER = "SPLITCHARACTER"; + + /// + /// Sets the split characters. + /// + /// the SplitCharacter interface + /// this Chunk + public Chunk SetSplitCharacter(ISplitCharacter splitCharacter) { + return SetAttribute(SPLITCHARACTER, splitCharacter); + } + + /// Key for hyphenation. + public const string HYPHENATION = "HYPHENATION"; + + /// + /// sets the hyphenation engine to this Chunk. + /// + /// the hyphenation engine + /// this Chunk + public Chunk SetHyphenation(IHyphenationEvent hyphenation) { + return SetAttribute(HYPHENATION, hyphenation); + } + + /// Key for remote goto. + public const string REMOTEGOTO = "REMOTEGOTO"; + + /// + /// Sets a goto for a remote destination for this Chunk. + /// + /// the file name of the destination document + /// the name of the destination to go to + /// this Chunk + public Chunk SetRemoteGoto(string filename, string name) { + return SetAttribute(REMOTEGOTO, new Object[]{filename, name}); + } + + /// + /// Sets a goto for a remote destination for this Chunk. + /// + /// the file name of the destination document + /// the page of the destination to go to. First page is 1 + /// this Chunk + public Chunk SetRemoteGoto(string filename, int page) { + return SetAttribute(REMOTEGOTO, new Object[]{filename, page}); + } + + /// Key for local goto. + public const string LOCALGOTO = "LOCALGOTO"; + + /// + /// Sets a local goto for this Chunk. + /// + /// + /// There must be a local destination matching the name. + /// + /// the name of the destination to go to + /// this Chunk + public Chunk SetLocalGoto(string name) { + return SetAttribute(LOCALGOTO, name); + } + + /// Key for local destination. + public const string LOCALDESTINATION = "LOCALDESTINATION"; + + /// + /// Sets a local destination for this Chunk. + /// + /// the name for this destination + /// this Chunk + public Chunk SetLocalDestination(string name) { + return SetAttribute(LOCALDESTINATION, name); + } + + /// Key for generic tag. + public const string GENERICTAG = "GENERICTAG"; + + /// + /// Sets the generic tag Chunk. + /// + /// + /// The text for this tag can be retrieved with PdfPageEvent. + /// + /// the text for the tag + /// this Chunk + public Chunk SetGenericTag(string text) { + return SetAttribute(GENERICTAG, text); + } + + /// Key for image. + public const string IMAGE = "IMAGE"; + + /// + /// Returns the image. + /// + /// an Image + public Image GetImage() { + if (attributes == null) return null; + Object[] obj = (Object[])attributes[Chunk.IMAGE]; + if (obj == null) + return null; + else { + return (Image)obj[0]; + } + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.CHUNK.Equals(tag); + } + + /// Key for Action. + public const string ACTION = "ACTION"; + + /// + /// Sets an action for this Chunk. + /// + /// the action + /// this Chunk + public Chunk SetAction(PdfAction action) { + return SetAttribute(ACTION, action); + } + + /// + /// Sets an anchor for this Chunk. + /// + /// the Uri to link to + /// this Chunk + public Chunk SetAnchor(Uri url) { + return SetAttribute(ACTION, new PdfAction(url)); + } + + /// + /// Sets an anchor for this Chunk. + /// + /// the url to link to + /// this Chunk + public Chunk SetAnchor(string url) { + return SetAttribute(ACTION, new PdfAction(url)); + } + + /// Key for newpage. + public const string NEWPAGE = "NEWPAGE"; + + /// + /// Sets a new page tag. + /// + /// this Chunk + public Chunk SetNewPage() { + return SetAttribute(NEWPAGE, null); + } + + /// Key for annotation. + public const string PDFANNOTATION = "PDFANNOTATION"; + + /// + /// Sets a generic annotation to this Chunk. + /// + /// the annotation + /// this Chunk + public Chunk SetAnnotation(PdfAnnotation annotation) { + return SetAttribute(PDFANNOTATION, annotation); + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + /** + * Returns the hyphenation (if present). + * @param hyphenation a HyphenationEvent instance + * @since 2.1.2 + */ + public IHyphenationEvent GetHyphenation() { + if (attributes == null) return null; + return (IHyphenationEvent) attributes[Chunk.HYPHENATION]; + } + + // keys used in PdfChunk + + /// Key for color. + public const string COLOR = "COLOR"; + + /// Key for encoding. + public const string ENCODING = "ENCODING"; + } +} diff --git a/iTechSharp/iTextSharp/text/Color.cs b/iTechSharp/iTextSharp/text/Color.cs new file mode 100644 index 0000000..0f593e6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Color.cs @@ -0,0 +1,150 @@ +using System; + +namespace iTextSharp.text { + /// + /// Base class for Color, serves as wrapper class for + /// to allow extension. + /// + public class Color { + public static readonly Color WHITE = new Color(255, 255, 255); + public static readonly Color LIGHT_GRAY = new Color(192, 192, 192); + public static readonly Color GRAY = new Color(128, 128, 128); + public static readonly Color DARK_GRAY = new Color(64, 64, 64); + public static readonly Color BLACK = new Color(0, 0, 0); + public static readonly Color RED = new Color(255, 0, 0); + public static readonly Color PINK = new Color(255, 175, 175); + public static readonly Color ORANGE = new Color(255, 200, 0); + public static readonly Color YELLOW = new Color(255, 255, 0); + public static readonly Color GREEN = new Color(0, 255, 0); + public static readonly Color MAGENTA = new Color(255, 0, 255); + public static readonly Color CYAN = new Color(0, 255, 255); + public static readonly Color BLUE = new Color(0, 0, 255); + private const double FACTOR = 0.7; + System.Drawing.Color color; + + /// + /// Constuctor for Color object. + /// + /// The red component value for the new Color structure. Valid values are 0 through 255. + /// The green component value for the new Color structure. Valid values are 0 through 255. + /// The blue component value for the new Color structure. Valid values are 0 through 255. + public Color(int red, int green, int blue) { + color = System.Drawing.Color.FromArgb(red, green, blue); + } + + /// + /// Constuctor for Color object. + /// + /// The red component value for the new Color structure. Valid values are 0 through 255. + /// The green component value for the new Color structure. Valid values are 0 through 255. + /// The blue component value for the new Color structure. Valid values are 0 through 255. + /// The transparency component value for the new Color structure. Valid values are 0 through 255. + public Color(int red, int green, int blue, int alpha) { + color = System.Drawing.Color.FromArgb(alpha, red, green, blue); + } + + /// + /// Constructor for Color object + /// + /// The red component value for the new Color structure. Valid values are 0 through 1. + /// The green component value for the new Color structure. Valid values are 0 through 1. + /// The blue component value for the new Color structure. Valid values are 0 through 1. + public Color(float red, float green, float blue) { + color = System.Drawing.Color.FromArgb((int)(red * 255 + .5), (int)(green * 255 + .5), (int)(blue * 255 + .5)); + } + + /// + /// Constructor for Color object + /// + /// The red component value for the new Color structure. Valid values are 0 through 1. + /// The green component value for the new Color structure. Valid values are 0 through 1. + /// The blue component value for the new Color structure. Valid values are 0 through 1. + /// The transparency component value for the new Color structure. Valid values are 0 through 1. + public Color(float red, float green, float blue, float alpha) { + color = System.Drawing.Color.FromArgb((int)(alpha * 255 + .5), (int)(red * 255 + .5), (int)(green * 255 + .5), (int)(blue * 255 + .5)); + } + + public Color(int argb) { + color = System.Drawing.Color.FromArgb(argb); + } + + /// + /// Constructor for Color object + /// + /// a Color object + /// + /// Has three overloads. + /// + public Color(System.Drawing.Color color) { + this.color = color; + } + + /// + /// Gets the red component value of this structure. + /// + /// The red component value of this structure. + public int R { + get { + return color.R; + } + } + + /// + /// Gets the green component value of this structure. + /// + /// The green component value of this structure. + public int G { + get { + return color.G; + } + } + + /// + /// Gets the blue component value of this structure. + /// + /// The blue component value of this structure. + public int B { + get { + return color.B; + } + } + + public Color Brighter() { + int r = color.R; + int g = color.G; + int b = color.B; + + int i = (int)(1.0/(1.0-FACTOR)); + if ( r == 0 && g == 0 && b == 0) { + return new Color(i, i, i); + } + if ( r > 0 && r < i ) r = i; + if ( g > 0 && g < i ) g = i; + if ( b > 0 && b < i ) b = i; + + return new Color(Math.Min((int)(r/FACTOR), 255), + Math.Min((int)(g/FACTOR), 255), + Math.Min((int)(b/FACTOR), 255)); + } + + public Color Darker() { + return new Color(Math.Max((int)(color.R * FACTOR), 0), + Math.Max((int)(color.G * FACTOR), 0), + Math.Max((int)(color.B * FACTOR), 0)); + } + + public override bool Equals(object obj) { + if (!(obj is Color)) + return false; + return color.Equals(((Color)obj).color); + } + + public override int GetHashCode() { + return color.GetHashCode(); + } + + public int ToArgb() { + return color.ToArgb(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/DocWriter.cs b/iTechSharp/iTextSharp/text/DocWriter.cs new file mode 100644 index 0000000..9e2b53f --- /dev/null +++ b/iTechSharp/iTextSharp/text/DocWriter.cs @@ -0,0 +1,416 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using iTextSharp.text.pdf; +/* + * $Id: DocWriter.cs,v 1.7 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// An abstract Writer class for documents. + /// + /// + /// DocWriter is the abstract class of several writers such + /// as PdfWriter and HtmlWriter. + /// A DocWriter can be added as a DocListener + /// to a certain Document by getting an instance (see method + /// GetInstance() in the specific writer-classes). + /// Every Element added to the original Document + /// will be written to the stream of the listening + /// DocWriter. + /// + /// + /// + public abstract class DocWriter : IDocListener { + + /// This is some byte that is often used. + public const byte NEWLINE = (byte)'\n'; + + /// This is some byte that is often used. + public const byte TAB = (byte)'\t'; + + /// This is some byte that is often used. + public const byte LT = (byte)'<'; + + /// This is some byte that is often used. + public const byte SPACE = (byte)' '; + + /// This is some byte that is often used. + public const byte EQUALS = (byte)'='; + + /// This is some byte that is often used. + public const byte QUOTE = (byte)'\"'; + + /// This is some byte that is often used. + public const byte GT = (byte)'>'; + + /// This is some byte that is often used. + public const byte FORWARD = (byte)'/'; + + // membervariables + + /// The pageSize. + protected Rectangle pageSize; + + /// This is the document that has to be written. + protected Document document; + + /// The stream of this writer. + protected OutputStreamCounter os; + + /// Is the writer open for writing? + protected bool open = false; + + /// Do we have to pause all writing actions? + protected bool pause = false; + + /** Closes the stream on document close */ + protected bool closeStream = true; + + // constructor + + protected DocWriter() { + } + /// + /// Constructs a DocWriter. + /// + /// The Document that has to be written + /// The Stream the writer has to write to. + protected DocWriter(Document document, Stream os) + { + this.document = document; + this.os = new OutputStreamCounter(os); + } + + // implementation of the DocListener methods + + /// + /// Signals that an Element was added to the Document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class. + /// + /// + /// false + public virtual bool Add(IElement element) { + return false; + } + + /// + /// Signals that the Document was opened. + /// + public virtual void Open() { + open = true; + } + + /// + /// Sets the pagesize. + /// + /// the new pagesize + /// a boolean + public virtual bool SetPageSize(Rectangle pageSize) { + this.pageSize = pageSize; + return true; + } + + /// + /// Sets the margins. + /// + /// + /// This does nothing. Has to be overridden if needed. + /// + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + /// + public virtual bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) { + return false; + } + + /// + /// Signals that an new page has to be started. + /// + /// + /// This does nothing. Has to be overridden if needed. + /// + /// true if the page was added, false if not. + public virtual bool NewPage() { + if (!open) { + return false; + } + return true; + } + + /// + /// Changes the header of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// headers. + /// + /// the new header + public virtual HeaderFooter Header { + set {} + } + + /// + /// Resets the header of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// headers. + /// + public virtual void ResetHeader() { + } + + /// + /// Changes the footer of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// footers. + /// + /// the new footer + public virtual HeaderFooter Footer { + set {} + } + + /// + /// Resets the footer of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// footers. + /// + public virtual void ResetFooter() { + } + + /// + /// Sets the page number to 0. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// pagenumbers. + /// + public virtual void ResetPageCount() { + } + + /// + /// Sets the page number. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// pagenumbers. + /// + public virtual int PageCount { + set {} + } + + /// + /// Signals that the Document was closed and that no other + /// Elements will be added. + /// + public virtual void Close() { + open = false; + os.Flush(); + if (closeStream) + os.Close(); + } + + // methods + + /// + /// Converts a string into a Byte array + /// according to the ISO-8859-1 codepage. + /// + /// the text to be converted + /// the conversion result + public static byte[] GetISOBytes(string text) { + if (text == null) + return null; + int len = text.Length; + byte[] b = new byte[len]; + for (int k = 0; k < len; ++k) + b[k] = (byte)text[k]; + return b; + } + + /// + /// Let the writer know that all writing has to be paused. + /// + public virtual void Pause() { + pause = true; + } + + /** + * Checks if writing is paused. + * + * @return true if writing temporarely has to be paused, false otherwise. + */ + + public bool IsPaused() { + return pause; + } + + /// + /// Let the writer know that writing may be resumed. + /// + public virtual void Resume() { + pause = false; + } + + /// + /// Flushes the Stream. + /// + public virtual void Flush() { + os.Flush(); + } + + /// + /// Writes a string to the stream. + /// + /// the string to write + protected void Write(string str) { + byte[] tmp = GetISOBytes(str); + os.Write(tmp, 0, tmp.Length); + } + + /// + /// Writes a number of tabs. + /// + /// the number of tabs to add + protected void AddTabs(int indent) { + os.WriteByte(NEWLINE); + for (int i = 0; i < indent; i++) { + os.WriteByte(TAB); + } + } + + /// + /// Writes a key-value pair to the stream. + /// + /// the name of an attribute + /// the value of an attribute + protected void Write(string key, string value) { + os.WriteByte(SPACE); + Write(key); + os.WriteByte(EQUALS); + os.WriteByte(QUOTE); + Write(value); + os.WriteByte(QUOTE); + } + + /// + /// Writes a starttag to the stream. + /// + /// the name of the tag + protected void WriteStart(string tag) { + os.WriteByte(LT); + Write(tag); + } + + /// + /// Writes an endtag to the stream. + /// + /// the name of the tag + protected void WriteEnd(string tag) { + os.WriteByte(LT); + os.WriteByte(FORWARD); + Write(tag); + os.WriteByte(GT); + } + + /// + /// Writes an endtag to the stream. + /// + protected void WriteEnd() { + os.WriteByte(SPACE); + os.WriteByte(FORWARD); + os.WriteByte(GT); + } + + /// + /// Writes the markup attributes of the specified MarkupAttributes + /// object to the stream. + /// + /// the MarkupAttributes to write. + /// + protected bool WriteMarkupAttributes(Properties markup) { + if (markup == null) return false; + foreach (String name in markup.Keys) { + Write(name, markup[name]); + } + markup.Clear(); + return true; + } + + public virtual bool CloseStream { + get { + return closeStream; + } + set { + closeStream = value; + } + } + + public virtual bool SetMarginMirroring(bool marginMirroring) { + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Document.cs b/iTechSharp/iTextSharp/text/Document.cs new file mode 100644 index 0000000..41ed30f --- /dev/null +++ b/iTechSharp/iTextSharp/text/Document.cs @@ -0,0 +1,684 @@ +using System; +using System.Collections; + +/* + * $Id: Document.cs,v 1.45 2008/05/25 13:08:44 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /// + /// A generic Document class. + /// + /// + /// All kinds of Text-elements can be added to a HTMLDocument. + /// The Document signals all the listeners when an element + /// has been added.

+ ///

    + ///
  1. Once a document is created you can add some meta information. + ///
  2. You can also set the headers/footers. + ///
  3. You have to open the document before you can write content. + ///
  4. You can only write content (no more meta-formation!) once a document is opened. + ///
  5. When you change the header/footer on a certain page, this will be effective starting on the next page. + ///
  6. Ater closing the document, every listener (as well as its OutputStream) is closed too. + ///
+ ///
+ /// + /// + /// // creation of the document with a certain size and certain margins + /// Document document = new Document(PageSize.A4, 50, 50, 50, 50); + /// try { + /// // creation of the different writers + /// HtmlWriter.GetInstance(document, System.out); + /// PdfWriter.GetInstance(document, new FileOutputStream("text.pdf")); + /// // we add some meta information to the document + /// document.AddAuthor("Bruno Lowagie"); + /// document.AddSubject("This is the result of a Test."); + /// + /// // we define a header and a footer + /// HeaderFooter header = new HeaderFooter(new Phrase("This is a header."), false); + /// HeaderFooter footer = new HeaderFooter(new Phrase("This is page "), new Phrase(".")); + /// footer.SetAlignment(Element.ALIGN_CENTER); + /// document.SetHeader(header); + /// document.SetFooter(footer); + /// // we open the document for writing + /// document.Open(); + /// document.Add(new Paragraph("Hello world")); + /// } + /// catch (DocumentException de) { + /// Console.Error.WriteLine(de.Message); + /// } + /// document.Close(); + /// + /// + public class Document : IDocListener { + + // membervariables + + /// This constant may only be changed by Paulo Soares and/or Bruno Lowagie. + private const string ITEXT_VERSION = "iTextSharp 4.1.2 (based on iText 2.1.2u)"; + + /// Allows the pdf documents to be produced without compression for debugging purposes. + public static bool Compress = true; + + /// Scales the WMF font size. The default value is 0.86. + public static float WmfFontCorrection = 0.86f; + + /// The IDocListener. + private ArrayList listeners = new ArrayList(); + + /// Is the document open or not? + protected bool open; + + /// Has the document allready been closed? + protected bool close; + + // membervariables concerning the layout + + /// The size of the page. + protected Rectangle pageSize; + + /// margin in x direction starting from the left + protected float marginLeft = 0; + + /// margin in x direction starting from the right + protected float marginRight = 0; + + /// margin in y direction starting from the top + protected float marginTop = 0; + + /// margin in y direction starting from the bottom + protected float marginBottom = 0; + + protected bool marginMirroring = false; + /// Content of JavaScript onLoad function + protected string javaScript_onLoad = null; + + /// Content of JavaScript onUnLoad function + protected string javaScript_onUnLoad = null; + + /// Style class in HTML body tag + protected string htmlStyleClass = null; + + // headers, footers + + /// Current pagenumber + protected int pageN = 0; + + /// This is the textual part of a Page; it can contain a header + protected HeaderFooter header = null; + + /// This is the textual part of the footer + protected HeaderFooter footer = null; + + // constructor + + /// + /// Constructs a new Document-object. + /// + /// + /// Has three overloads. + /// + public Document() : this(iTextSharp.text.PageSize.A4) {} + + /// + /// Constructs a new Document-object. + /// + /// the pageSize + public Document(Rectangle pageSize) : this(pageSize, 36, 36, 36, 36) {} + + /// + /// Constructs a new Document-object. + /// + /// the pageSize + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + public Document(Rectangle pageSize, float marginLeft, float marginRight, float marginTop, float marginBottom) { + this.pageSize = pageSize; + this.marginLeft = marginLeft; + this.marginRight = marginRight; + this.marginTop = marginTop; + this.marginBottom = marginBottom; + } + + // listener methods + + /// + /// Adds a IDocListener to the Document. + /// + /// the new IDocListener + public void AddDocListener(IDocListener listener) { + listeners.Add(listener); + } + + /// + /// Removes a IDocListener from the Document. + /// + /// the IDocListener that has to be removed. + public void RemoveIDocListener(IDocListener listener) { + listeners.Remove(listener); + } + + // methods implementing the IDocListener interface + + /// + /// Adds an Element to the Document. + /// + /// the Element to add + /// true if the element was added, false if not + public virtual bool Add(IElement element) { + if (close) { + throw new DocumentException("The document has been closed. You can't add any Elements."); + } + if (!open && element.IsContent()) { + throw new DocumentException("The document is not open yet; you can only add Meta information."); + } + bool success = false; + foreach (IDocListener listener in listeners) { + success |= listener.Add(element); + } + if (element is ILargeElement) { + ILargeElement e = (ILargeElement)element; + if (!e.ElementComplete) + e.FlushContent(); + } + return success; + } + + /// + /// Opens the document. + /// + /// + /// Once the document is opened, you can't write any Header- or Meta-information + /// anymore. You have to open the document before you can begin to add content + /// to the body of the document. + /// + public virtual void Open() { + if (! close) { + open = true; + } + foreach (IDocListener listener in listeners) { + listener.SetPageSize(pageSize); + listener.SetMargins(marginLeft, marginRight, marginTop, marginBottom); + listener.Open(); + } + } + + /// + /// Sets the pagesize. + /// + /// the new pagesize + /// a bool + public virtual bool SetPageSize(Rectangle pageSize) { + this.pageSize = pageSize; + foreach (IDocListener listener in listeners) { + listener.SetPageSize(pageSize); + } + return true; + } + + /// + /// Sets the margins. + /// + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + /// + public virtual bool SetMargins(float marginLeft,float marginRight,float marginTop,float marginBottom) { + this.marginLeft = marginLeft; + this.marginRight = marginRight; + this.marginTop = marginTop; + this.marginBottom = marginBottom; + foreach (IDocListener listener in listeners) { + listener.SetMargins(marginLeft, marginRight, marginTop, marginBottom); + } + return true; + } + + /// + /// Signals that an new page has to be started. + /// + /// true if the page was added, false if not. + public virtual bool NewPage() { + if (!open || close) { + return false; + } + foreach (IDocListener listener in listeners) { + listener.NewPage(); + } + return true; + } + + /// + /// Changes the header of this document. + /// + /// a HeaderFooter + public virtual HeaderFooter Header { + set { + this.header = value; + foreach (IDocListener listener in listeners) { + listener.Header = value; + } + } + } + + /// + /// Resets the header of this document. + /// + public virtual void ResetHeader() { + this.header = null; + foreach (IDocListener listener in listeners) { + listener.ResetHeader(); + } + } + + /// + /// Changes the footer of this document. + /// + /// a HeaderFooter + public virtual HeaderFooter Footer { + set { + this.footer = value; + foreach (IDocListener listener in listeners) { + listener.Footer = value; + } + } + } + + /// + /// Resets the footer of this document. + /// + public virtual void ResetFooter() { + this.footer = null; + foreach (IDocListener listener in listeners) { + listener.ResetFooter(); + } + } + + /// + /// Sets the page number to 0. + /// + public virtual void ResetPageCount() { + pageN = 0; + foreach (IDocListener listener in listeners) { + listener.ResetPageCount(); + } + } + + /// + /// Sets the page number. + /// + /// an int + public virtual int PageCount { + set { + this.pageN = value; + foreach (IDocListener listener in listeners) { + listener.PageCount = value; + } + } + } + + /// + /// Returns the current page number. + /// + /// an int + public int PageNumber { + get { + return this.pageN; + } + } + + /// + /// Closes the document. + /// + /// + /// Once all the content has been written in the body, you have to close + /// the body. After that nothing can be written to the body anymore. + /// + public virtual void Close() { + if (!close) { + open = false; + close = true; + } + foreach (IDocListener listener in listeners) { + listener.Close(); + } + } + + // methods concerning the header or some meta information + + /// + /// Adds a user defined header to the document. + /// + /// the name of the header + /// the content of the header + /// true if successful, false otherwise + public bool AddHeader(string name, string content) { + return Add(new Header(name, content)); + } + + /// + /// Adds the title to a Document. + /// + /// the title + /// true if successful, false otherwise + public bool AddTitle(string title) { + return Add(new Meta(Element.TITLE, title)); + } + + /// + /// Adds the subject to a Document. + /// + /// the subject + /// true if successful, false otherwise + public bool AddSubject(string subject) { + return Add(new Meta(Element.SUBJECT, subject)); + } + + /// + /// Adds the keywords to a Document. + /// + /// keywords to add + /// true if successful, false otherwise + public bool AddKeywords(string keywords) { + return Add(new Meta(Element.KEYWORDS, keywords)); + } + + /// + /// Adds the author to a Document. + /// + /// the name of the author + /// true if successful, false otherwise + public bool AddAuthor(string author) { + return Add(new Meta(Element.AUTHOR, author)); + } + + /// + /// Adds the creator to a Document. + /// + /// the name of the creator + /// true if successful, false otherwise + public bool AddCreator(string creator) { + return Add(new Meta(Element.CREATOR, creator)); + } + + /// + /// Adds the producer to a Document. + /// + /// true if successful, false otherwise + public bool AddProducer() { + return Add(new Meta(Element.PRODUCER, "iText# by lowagie.com")); + } + + /// + /// Adds the current date and time to a Document. + /// + /// true if successful, false otherwise + public bool AddCreationDate() { + return Add(new Meta(Element.CREATIONDATE, DateTime.Now.ToString("ddd MMM dd HH:mm:ss zzz yyyy"))); + } + + // methods to get the layout of the document. + + /// + /// Returns the left margin. + /// + /// the left margin + public float LeftMargin { + get { + return marginLeft; + } + } + + /// + /// Return the right margin. + /// + /// the right margin + public float RightMargin { + get { + return marginRight; + } + } + + /// + /// Returns the top margin. + /// + /// the top margin + public float TopMargin { + get { + return marginTop; + } + } + + /// + /// Returns the bottom margin. + /// + /// the bottom margin + public float BottomMargin { + get { + return marginBottom; + } + } + + /// + /// Returns the lower left x-coordinate. + /// + /// the lower left x-coordinate + public float Left { + get { + return pageSize.GetLeft(marginLeft); + } + } + + /// + /// Returns the upper right x-coordinate. + /// + /// the upper right x-coordinate. + public float Right { + get { + return pageSize.GetRight(marginRight); + } + } + + /// + /// Returns the upper right y-coordinate. + /// + /// the upper right y-coordinate. + public float Top { + get { + return pageSize.GetTop(marginTop); + } + } + + /// + /// Returns the lower left y-coordinate. + /// + /// the lower left y-coordinate. + public float Bottom { + get { + return pageSize.GetBottom(marginBottom); + } + } + + /// + /// Returns the lower left x-coordinate considering a given margin. + /// + /// a margin + /// the lower left x-coordinate + public float GetLeft(float margin) { + return pageSize.GetLeft(marginLeft + margin); + } + + /// + /// Returns the upper right x-coordinate, considering a given margin. + /// + /// a margin + /// the upper right x-coordinate + public float GetRight(float margin) { + return pageSize.GetRight(marginRight + margin); + } + + /// + /// Returns the upper right y-coordinate, considering a given margin. + /// + /// a margin + /// the upper right y-coordinate + public float GetTop(float margin) { + return pageSize.GetTop(marginTop + margin); + } + + /// + /// Returns the lower left y-coordinate, considering a given margin. + /// + /// a margin + /// the lower left y-coordinate + public float GetBottom(float margin) { + return pageSize.GetBottom(marginBottom + margin); + } + + /// + /// Gets the pagesize. + /// + /// the page size + public Rectangle PageSize { + get { + return this.pageSize; + } + } + + /// + /// Checks if the document is open. + /// + /// true if the document is open + public bool IsOpen() { + return open; + } + + /// + /// Gets the iText version. + /// + /// iText version + public static string Version { + get { + return ITEXT_VERSION; + } + } + + /// + /// Gets the JavaScript onLoad command. + /// + /// the JavaScript onLoad command. + public string JavaScript_onLoad { + get { + return this.javaScript_onLoad; + } + + set { + this.javaScript_onLoad = value; + } + } + + /// + /// Gets the JavaScript onUnLoad command. + /// + /// the JavaScript onUnLoad command + public string JavaScript_onUnLoad { + get { + return this.javaScript_onUnLoad; + } + + set { + this.javaScript_onUnLoad = value; + } + } + + /// + /// Gets the style class of the HTML body tag + /// + /// the style class of the HTML body tag + public string HtmlStyleClass { + get { + return this.htmlStyleClass; + } + + set { + this.htmlStyleClass = value; + } + } + + /** + * Set the margin mirroring. It will mirror margins for odd/even pages. + *

+ * Note: it will not work with {@link Table}. + * + * @param marginMirroring + * true to mirror the margins + * @return always true + */ + public virtual bool SetMarginMirroring(bool marginMirroring) { + this.marginMirroring = marginMirroring; + foreach (IDocListener listener in listeners) { + listener.SetMarginMirroring(marginMirroring); + } + return true; + } + + /** + * Gets the margin mirroring flag. + * + * @return the margin mirroring flag + */ + public bool IsMarginMirroring() { + return marginMirroring; + } + } +} diff --git a/iTechSharp/iTextSharp/text/DocumentException.cs b/iTechSharp/iTextSharp/text/DocumentException.cs new file mode 100644 index 0000000..1c2b689 --- /dev/null +++ b/iTechSharp/iTextSharp/text/DocumentException.cs @@ -0,0 +1,77 @@ +using System; + +/* + * $Id: DocumentException.cs,v 1.3 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + */ + +namespace iTextSharp.text { + ///

+ /// Signals that an error has occurred in a Document. + /// + /// + /// + /// + /// + public class DocumentException : Exception { + /// + /// Constructs a new DocumentException + /// + /// + /// Has two overloads. + /// + public DocumentException() : base() {} + + /// + /// Construct a new DocumentException + /// + /// error message + public DocumentException(string message) : base(message) {} + } +} diff --git a/iTechSharp/iTextSharp/text/Element.cs b/iTechSharp/iTextSharp/text/Element.cs new file mode 100644 index 0000000..cf4824f --- /dev/null +++ b/iTechSharp/iTextSharp/text/Element.cs @@ -0,0 +1,285 @@ +using System; + +/* + * $Id: Element.cs,v 1.7 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + + /// + /// Interface for a text element. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public class Element + { + + // static membervariables (meta information) + + /// This is a possible type of Element. + public const int HEADER = 0; + + /// This is a possible type of Element. + public const int TITLE = 1; + + /// This is a possible type of Element. + public const int SUBJECT = 2; + + /// This is a possible type of Element. + public const int KEYWORDS = 3; + + /// This is a possible type of Element. + public const int AUTHOR = 4; + + /// This is a possible type of Element. + public const int PRODUCER = 5; + + /// This is a possible type of Element. + public const int CREATIONDATE = 6; + + /// This is a possible type of Element. + public const int CREATOR = 7; + + // static membervariables (content) + + /// This is a possible type of Element. + public const int CHUNK = 10; + + /// This is a possible type of Element. + public const int PHRASE = 11; + + /// This is a possible type of Element. + public const int PARAGRAPH = 12; + + /// This is a possible type of Element + public const int SECTION = 13; + + /// This is a possible type of Element + public const int LIST = 14; + + /// This is a possible type of Element + public const int LISTITEM = 15; + + /// This is a possible type of Element + public const int CHAPTER = 16; + + /// This is a possible type of Element + public const int ANCHOR = 17; + + // static membervariables (tables) + + /// This is a possible type of Element. + public const int CELL = 20; + + /// This is a possible type of Element. + public const int ROW = 21; + + /// This is a possible type of Element. + public const int TABLE = 22; + + /// This is a possible type of Element. + public const int PTABLE = 23; + + // static membervariables (annotations) + + /// This is a possible type of Element. + public const int ANNOTATION = 29; + + // static membervariables (geometric figures) + + /// This is a possible type of Element. + public const int RECTANGLE = 30; + + /// This is a possible type of Element. + public const int JPEG = 32; + + /** This is a possible type of Element. */ + public const int JPEG2000 = 33; + + /// This is a possible type of Element. + public const int IMGRAW = 34; + + /// This is a possible type of Element. + public const int IMGTEMPLATE = 35; + + /// This is a possible type of Element. + public const int MULTI_COLUMN_TEXT = 40; + + /** This is a possible type of Element. */ + public const int MARKED = 50; + + /** This is a possible type of Element. + * @since 2.1.2 + */ + public const int YMARK = 55; + + // static membervariables (alignment) + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the left + /// indent and extra whitespace should be placed on + /// the right. + /// + public const int ALIGN_UNDEFINED = -1; + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the left + /// indent and extra whitespace should be placed on + /// the right. + /// + public const int ALIGN_LEFT = 0; + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the center + /// and extra whitespace should be placed equally on + /// the left and right. + /// + public const int ALIGN_CENTER = 1; + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the right + /// indent and extra whitespace should be placed on + /// the left. + /// + public const int ALIGN_RIGHT = 2; + + /// + /// A possible value for paragraph Element. This + /// specifies that extra whitespace should be spread + /// out through the rows of the paragraph with the + /// text lined up with the left and right indent + /// except on the last line which should be aligned + /// to the left. + /// + public const int ALIGN_JUSTIFIED = 3; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_TOP = 4; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_MIDDLE = 5; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_BOTTOM = 6; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_BASELINE = 7; + + /// + /// Does the same as ALIGN_JUSTIFIED but the last line is also spread out. + /// + public const int ALIGN_JUSTIFIED_ALL = 8; + + // static member variables for CCITT compression + + /// + /// Pure two-dimensional encoding (Group 4) + /// + public const int CCITTG4 = 0x100; + /// + /// Pure one-dimensional encoding (Group 3, 1-D) + /// + public const int CCITTG3_1D = 0x101; + /// + /// Mixed one- and two-dimensional encoding (Group 3, 2-D) + /// + public const int CCITTG3_2D = 0x102; + /// + /// A flag indicating whether 1-bits are to be interpreted as black pixels + /// and 0-bits as white pixels, + /// + public const int CCITT_BLACKIS1 = 1; + /// + /// A flag indicating whether the filter expects extra 0-bits before each + /// encoded line so that the line begins on a byte boundary. + /// + public const int CCITT_ENCODEDBYTEALIGN = 2; + /// + /// A flag indicating whether end-of-line bit patterns are required to be + /// present in the encoding. + /// + public const int CCITT_ENDOFLINE = 4; + /// + /// A flag indicating whether the filter expects the encoded data to be + /// terminated by an end-of-block pattern, overriding the Rows + /// parameter. The use of this flag will set the key /EndOfBlock to false. + /// + public const int CCITT_ENDOFBLOCK = 8; + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/ElementTags.cs b/iTechSharp/iTextSharp/text/ElementTags.cs new file mode 100644 index 0000000..29388ef --- /dev/null +++ b/iTechSharp/iTextSharp/text/ElementTags.cs @@ -0,0 +1,521 @@ +using System; +using System.util; + +/* + * $Id: ElementTags.cs,v 1.8 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright (c) 2001, 2002 Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// A class that contains all the possible tagnames and their attributes. + /// + public class ElementTags + { + + /// the root tag. + public const string ITEXT = "itext"; + + /// attribute of the root and annotation tag (also a special tag within a chapter or section) + public const string TITLE = "title"; + + /// attribute of the root tag + public const string SUBJECT = "subject"; + + /// attribute of the root tag + public const string KEYWORDS = "keywords"; + + /// attribute of the root tag + public const string AUTHOR = "author"; + + /// attribute of the root tag + public const string CREATIONDATE = "creationdate"; + + /// attribute of the root tag + public const string PRODUCER = "producer"; + + // Chapters and Sections + + /// the chapter tag + public const string CHAPTER = "chapter"; + + /// the section tag + public const string SECTION = "section"; + + /// attribute of section/chapter tag + public const string NUMBERDEPTH = "numberdepth"; + + /// attribute of section/chapter tag + public const string DEPTH = "depth"; + + /// attribute of section/chapter tag + public const string NUMBER = "number"; + + /// attribute of section/chapter tag + public const string INDENT = "indent"; + + /// attribute of chapter/section/paragraph/table/cell tag + public const string LEFT = "left"; + + /// attribute of chapter/section/paragraph/table/cell tag + public const string RIGHT = "right"; + + // Phrases, Anchors, Lists and Paragraphs + + /// the phrase tag + public const string PHRASE = "phrase"; + + /// the anchor tag + public const string ANCHOR = "anchor"; + + /// the list tag + public const string LIST = "list"; + + /// the listitem tag + public const string LISTITEM = "listitem"; + + /// the paragraph tag + public const string PARAGRAPH = "paragraph"; + + /// attribute of phrase/paragraph/cell tag + public const string LEADING = "leading"; + + /// attribute of paragraph/image/table tag + public const string ALIGN = "align"; + + /// attribute of paragraph + public const string KEEPTOGETHER = "keeptogether"; + + /// attribute of anchor tag + public const string NAME = "name"; + + /// attribute of anchor tag + public const string REFERENCE = "reference"; + + /// attribute of list tag + public const string LISTSYMBOL = "listsymbol"; + + /// attribute of list tag + public const string NUMBERED = "numbered"; + + /// attribute of the list tag + public const string LETTERED = "lettered"; + + /// attribute of list tag + public const string FIRST = "first"; + + /// attribute of list tag + public const string SYMBOLINDENT = "symbolindent"; + + /// attribute of list tag + public const string INDENTATIONLEFT = "indentationleft"; + + /// attribute of list tag + public const string INDENTATIONRIGHT = "indentationright"; + + // Chunks + + /// the chunk tag + public const string IGNORE = "ignore"; + + /// the chunk tag + public const string ENTITY = "entity"; + + /// the chunk tag + public const string ID = "id"; + + /// the chunk tag + public const string CHUNK = "chunk"; + + /// attribute of the chunk tag + public const string ENCODING = "encoding"; + + /// attribute of the chunk tag + public const string EMBEDDED = "embedded"; + + /// attribute of the chunk/table/cell tag + public const string COLOR = "color"; + + /// attribute of the chunk/table/cell tag + public const string RED = "red"; + + /// attribute of the chunk/table/cell tag + public const string GREEN = "green"; + + /// attribute of the chunk/table/cell tag + public const string BLUE = "blue"; + + /// attribute of the chunk tag + public static readonly string SUBSUPSCRIPT = Chunk.SUBSUPSCRIPT.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string LOCALGOTO = Chunk.LOCALGOTO.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string REMOTEGOTO = Chunk.REMOTEGOTO.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string LOCALDESTINATION = Chunk.LOCALDESTINATION.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string GENERICTAG = Chunk.GENERICTAG.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + // tables/cells + + /// the table tag + public const string TABLE = "table"; + + /// the cell tag + public const string ROW = "row"; + + /// the cell tag + public const string CELL = "cell"; + + /// attribute of the table tag + public const string COLUMNS = "columns"; + + /// attribute of the table tag + public const string LASTHEADERROW = "lastHeaderRow"; + + /// attribute of the table tag + public const string CELLPADDING = "cellpadding"; + + /// attribute of the table tag + public const string CELLSPACING = "cellspacing"; + + /// attribute of the table tag + public const string OFFSET = "offset"; + + /// attribute of the table tag + public const string WIDTHS = "widths"; + + /// attribute of the table tag + public const string TABLEFITSPAGE = "tablefitspage"; + + /// attribute of the table tag + public const string CELLSFITPAGE = "cellsfitpage"; + + /// attribute of the table tag + public const string CONVERT2PDFP = "convert2pdfp"; + + /// attribute of the cell tag + public const string HORIZONTALALIGN = "horizontalalign"; + + /// attribute of the cell tag + public const string VERTICALALIGN = "verticalalign"; + + /// attribute of the cell tag + public const string COLSPAN = "colspan"; + + /// attribute of the cell tag + public const string ROWSPAN = "rowspan"; + + /// attribute of the cell tag + public const string HEADER = "header"; + + /// attribute of the cell tag + public const string FOOTER = "footer"; + + /// attribute of the cell tag + public const string NOWRAP = "nowrap"; + + /// attribute of the table/cell tag + public const string BORDERWIDTH = "borderwidth"; + + /// attribute of the table/cell tag + public const string TOP = "top"; + + /// attribute of the table/cell tag + public const string BOTTOM = "bottom"; + + /// attribute of the table/cell tag + public const string WIDTH = "width"; + + /// attribute of the table/cell tag + public const string BORDERCOLOR = "bordercolor"; + + /// attribute of the table/cell tag + public const string BACKGROUNDCOLOR = "backgroundcolor"; + + /// attribute of the table/cell tag + public const string BGRED = "bgred"; + + /// attribute of the table/cell tag + public const string BGGREEN = "bggreen"; + + /// attribute of the table/cell tag + public const string BGBLUE = "bgblue"; + + /// attribute of the table/cell tag + public const string GRAYFILL = "grayfill"; + + // Misc + + /// the image tag + public const string IMAGE = "image"; + + /// the image tag + public const string BOOKMARKOPEN = "bookmarkopen"; + + /// attribute of the image and annotation tag + public const string URL = "url"; + + /// attribute of the image tag + public const string UNDERLYING = "underlying"; + + /// attribute of the image tag + public const string TEXTWRAP = "textwrap"; + + /// attribute of the image tag + public const string ALT = "alt"; + + /// attribute of the image tag + public const string ABSOLUTEX = "absolutex"; + + /// attribute of the image tag + public const string ABSOLUTEY = "absolutey"; + + /// attribute of the image tag + public const string PLAINWIDTH = "plainwidth"; + + /// attribute of the image tag + public const string PLAINHEIGHT = "plainheight"; + + /// attribute of the image tag + public const string SCALEDWIDTH = "scaledwidth"; + + /// attribute of the image tag + public const string SCALEDHEIGHT = "scaledheight"; + + /// attribute of the image tag + public const string ROTATION = "rotation"; + + /// the newpage tag + public const string NEWPAGE = "newpage"; + + /// the newpage tag + public const string NEWLINE = "newline"; + + /// the annotation tag + public const string ANNOTATION = "annotation"; + + /// attribute of the annotation tag + public const string FILE = "file"; + + /// attribute of the annotation tag + public const string DESTINATION = "destination"; + + /// attribute of the annotation tag + public const string PAGE = "page"; + + /// attribute of the annotation tag + public const string NAMED = "named"; + + /// attribute of the annotation tag + public const string APPLICATION = "application"; + + /// attribute of the annotation tag + public const string PARAMETERS = "parameters"; + + /// attribute of the annotation tag + public const string OPERATION = "operation"; + + /// attribute of the annotation tag + public const string DEFAULTDIR = "defaultdir"; + + /// attribute of the annotation tag + public const string LLX = "llx"; + + /// attribute of the annotation tag + public const string LLY = "lly"; + + /// attribute of the annotation tag + public const string URX = "urx"; + + /// attribute of the annotation tag + public const string URY = "ury"; + + /// attribute of the annotation tag + public const string CONTENT = "content"; + + // alignment attribute values + + /// the possible value of an alignment attribute + public const string ALIGN_LEFT = "Left"; + + /// the possible value of an alignment attribute + public const string ALIGN_CENTER = "Center"; + + /// the possible value of an alignment attribute + public const string ALIGN_RIGHT = "Right"; + + /// the possible value of an alignment attribute + public const string ALIGN_JUSTIFIED = "Justify"; + + /// the possible value of an alignment attribute + public const string ALIGN_JUSTIFIED_ALL = "JustifyAll"; + + /// the possible value of an alignment attribute + public const string ALIGN_TOP = "Top"; + + /// the possible value of an alignment attribute + public const string ALIGN_MIDDLE = "Middle"; + + /// the possible value of an alignment attribute + public const string ALIGN_BOTTOM = "Bottom"; + + /// the possible value of an alignment attribute + public const string ALIGN_BASELINE = "Baseline"; + + /// the possible value of an alignment attribute + public const string DEFAULT = "Default"; + + /// the possible value of an alignment attribute + public const string UNKNOWN = "unknown"; + + /// the possible value of an alignment attribute + public const string FONT = "font"; + + /// the possible value of an alignment attribute + public const string SIZE = "size"; + + /// the possible value of an alignment attribute + public const string STYLE = "fontstyle"; + + /// the possible value of a tag + public const string HORIZONTALRULE = "horizontalrule"; + /** the possible value of a tag */ + public const string PAGE_SIZE = "pagesize"; + + /** the possible value of a tag */ + public const string ORIENTATION = "orientation"; + + /** a possible list attribute */ + public const String ALIGN_INDENTATION_ITEMS = "alignindent"; + + /** a possible list attribute */ + public const String AUTO_INDENT_ITEMS = "autoindent"; + + /** a possible list attribute */ + public const String LOWERCASE = "lowercase"; + + // methods + + /// + /// Translates the alignment value to a String value. + /// + /// the alignment value + /// the translated value + public static string GetAlignment(int alignment) + { + switch (alignment) + { + case Element.ALIGN_LEFT: + return ALIGN_LEFT; + case Element.ALIGN_CENTER: + return ALIGN_CENTER; + case Element.ALIGN_RIGHT: + return ALIGN_RIGHT; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + return ALIGN_JUSTIFIED; + case Element.ALIGN_TOP: + return ALIGN_TOP; + case Element.ALIGN_MIDDLE: + return ALIGN_MIDDLE; + case Element.ALIGN_BOTTOM: + return ALIGN_BOTTOM; + case Element.ALIGN_BASELINE: + return ALIGN_BASELINE; + default: + return DEFAULT; + } + } + + /** + * Translates a String value to an alignment value. + * (written by Norman Richards, integrated into iText by Bruno) + * @param a String (one of the ALIGN_ constants of this class) + * @param an alignment value (one of the ALIGN_ constants of the Element interface) + */ + public static int AlignmentValue(String alignment) { + if (alignment == null) return Element.ALIGN_UNDEFINED; + if (Util.EqualsIgnoreCase(ALIGN_CENTER, alignment)) { + return Element.ALIGN_CENTER; + } + if (Util.EqualsIgnoreCase(ALIGN_LEFT, alignment)) { + return Element.ALIGN_LEFT; + } + if (Util.EqualsIgnoreCase(ALIGN_RIGHT, alignment)) { + return Element.ALIGN_RIGHT; + } + if (Util.EqualsIgnoreCase(ALIGN_JUSTIFIED, alignment)) { + return Element.ALIGN_JUSTIFIED; + } + if (Util.EqualsIgnoreCase(ALIGN_JUSTIFIED_ALL, alignment)) { + return Element.ALIGN_JUSTIFIED_ALL; + } + if (Util.EqualsIgnoreCase(ALIGN_TOP, alignment)) { + return Element.ALIGN_TOP; + } + if (Util.EqualsIgnoreCase(ALIGN_MIDDLE, alignment)) { + return Element.ALIGN_MIDDLE; + } + if (Util.EqualsIgnoreCase(ALIGN_BOTTOM, alignment)) { + return Element.ALIGN_BOTTOM; + } + if (Util.EqualsIgnoreCase(ALIGN_BASELINE, alignment)) { + return Element.ALIGN_BASELINE; + } + + return Element.ALIGN_UNDEFINED; + } + + } +} diff --git a/iTechSharp/iTextSharp/text/Font.cs b/iTechSharp/iTextSharp/text/Font.cs new file mode 100644 index 0000000..ee2a1ca --- /dev/null +++ b/iTechSharp/iTextSharp/text/Font.cs @@ -0,0 +1,698 @@ +using System; +using System.util; + +using iTextSharp.text.pdf; +using iTextSharp.text.html; + +/* + * $Id: Font.cs,v 1.11 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// Contains all the specifications of a font: fontfamily, size, style and color. + /// + /// + /// + /// Paragraph p = new Paragraph("This is a paragraph", + /// new Font(Font.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// + /// + public class Font : IComparable { + + // static membervariables for the different families + + /// a possible value of a font family. + public const int COURIER = 0; + + /// a possible value of a font family. + public const int HELVETICA = 1; + + /// a possible value of a font family. + public const int TIMES_ROMAN = 2; + + /// a possible value of a font family. + public const int SYMBOL = 3; + + /// a possible value of a font family. + public const int ZAPFDINGBATS = 4; + + // static membervariables for the different styles + + /// this is a possible style. + public const int NORMAL = 0; + + /// this is a possible style. + public const int BOLD = 1; + + /// this is a possible style. + public const int ITALIC = 2; + + /// this is a possible style. + public const int UNDERLINE = 4; + + /// this is a possible style. + public const int STRIKETHRU = 8; + + /// this is a possible style. + public const int BOLDITALIC = BOLD | ITALIC; + + // static membervariables + + /// the value of an undefined attribute. + public const int UNDEFINED = -1; + + /// the value of the default size. + public const int DEFAULTSIZE = 12; + + // membervariables + + /// the value of the fontfamily. + private int family = UNDEFINED; + + /// the value of the fontsize. + private float size = UNDEFINED; + + /// the value of the style. + private int style = UNDEFINED; + + /// the value of the color. + private Color color; + + /// the external font + private BaseFont baseFont = null; + + // constructors + + /** + * Copy constructor of a Font + * @param other the font that has to be copied + */ + public Font(Font other) { + this.color = other.color; + this.family = other.family; + this.size = other.size; + this.style = other.style; + this.baseFont = other.baseFont; + } + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + /// the size of this font + /// the style of this font + /// the Color of this font. + public Font(int family, float size, int style, Color color) { + this.family = family; + this.size = size; + this.style = style; + this.color = color; + } + + /// + /// Constructs a Font. + /// + /// the external font + /// the size of this font + /// the style of this font + /// the Color of this font. + public Font(BaseFont bf, float size, int style, Color color) { + this.baseFont = bf; + this.size = size; + this.style = style; + this.color = color; + } + + /// + /// Constructs a Font. + /// + /// the external font + /// the size of this font + /// the style of this font + public Font(BaseFont bf, float size, int style) : this(bf, size, style, null) {} + + /// + /// Constructs a Font. + /// + /// the external font + /// the size of this font + public Font(BaseFont bf, float size) : this(bf, size, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// the external font + public Font(BaseFont bf) : this(bf, UNDEFINED, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + /// the size of this font + /// the style of this font + public Font(int family, float size, int style) : this(family, size, style, null) {} + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + /// the size of this font + public Font(int family, float size) : this(family, size, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + public Font(int family) : this(family, UNDEFINED, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// + /// Has nine overloads. + /// + public Font() : this(UNDEFINED, UNDEFINED, UNDEFINED, null) {} + + // implementation of the Comparable interface + + /// + /// Compares this Font with another + /// + /// the other Font + /// a value + public virtual int CompareTo(Object obj) { + if (obj == null) { + return -1; + } + Font font; + try { + font = (Font) obj; + if (baseFont != null && !baseFont.Equals(font.BaseFont)) { + return -2; + } + if (this.family != font.Family) { + return 1; + } + if (this.size != font.Size) { + return 2; + } + if (this.style != font.Style) { + return 3; + } + if (this.color == null) { + if (font.Color == null) { + return 0; + } + return 4; + } + if (font.Color == null) { + return 4; + } + if (((Color)this.color).Equals(font.Color)) { + return 0; + } + return 4; + } + catch { + return -3; + } + } + + // FAMILY + + /// + /// Gets the family of this font. + /// + /// the value of the family + public int Family { + get { + return family; + } + } + + /// + /// Gets the familyname as a string. + /// + /// the familyname + public virtual string Familyname { + get { + string tmp = "unknown"; + switch (this.Family) { + case Font.COURIER: + return FontFactory.COURIER; + case Font.HELVETICA: + return FontFactory.HELVETICA; + case Font.TIMES_ROMAN: + return FontFactory.TIMES_ROMAN; + case Font.SYMBOL: + return FontFactory.SYMBOL; + case Font.ZAPFDINGBATS: + return FontFactory.ZAPFDINGBATS; + default: + if (baseFont != null) { + string[][] names = baseFont.FamilyFontName; + for (int i = 0; i < names.Length; i++) { + if ("0".Equals(names[i][2])) { + return names[i][3]; + } + if ("1033".Equals(names[i][2])) { + tmp = names[i][3]; + } + if ("".Equals(names[i][2])) { + tmp = names[i][3]; + } + } + } + break; + } + return tmp; + } + } + + /// + /// Sets the family using a String ("Courier", + /// "Helvetica", "Times New Roman", "Symbol" or "ZapfDingbats"). + /// + /// A String representing a certain font-family. + public virtual void SetFamily(String family) { + this.family = GetFamilyIndex(family); + } + + /// + /// Translates a string-value of a certain family + /// into the index that is used for this family in this class. + /// + /// A string representing a certain font-family + /// the corresponding index + public static int GetFamilyIndex(string family) { + if (Util.EqualsIgnoreCase(family, FontFactory.COURIER)) { + return COURIER; + } + if (Util.EqualsIgnoreCase(family, FontFactory.HELVETICA)) { + return HELVETICA; + } + if (Util.EqualsIgnoreCase(family, FontFactory.TIMES_ROMAN)) { + return TIMES_ROMAN; + } + if (Util.EqualsIgnoreCase(family, FontFactory.SYMBOL)) { + return SYMBOL; + } + if (Util.EqualsIgnoreCase(family, FontFactory.ZAPFDINGBATS)) { + return ZAPFDINGBATS; + } + return UNDEFINED; + } + + // SIZE + + /// + /// Get/set the size of this font. + /// + /// the size of this font + public virtual float Size { + get { + return size; + } + set { + this.size = value; + } + } + + /** Gets the size that can be used with the calculated BaseFont. + * @return the size that can be used with the calculated BaseFont + */ + public float CalculatedSize { + get { + float s = this.size; + if (s == UNDEFINED) { + s = DEFAULTSIZE; + } + return s; + } + } + + /** + * Gets the leading that can be used with this font. + * + * @param linespacing + * a certain linespacing + * @return the height of a line + */ + public float GetCalculatedLeading(float linespacing) { + return linespacing * CalculatedSize; + } + + // STYLE + + /// + /// Gets the style of this font. + /// + /// the style of this font + public int Style { + get { + return style; + } + } + + /** Gets the style that can be used with the calculated BaseFont. + * @return the style that can be used with the calculated BaseFont + */ + public int CalculatedStyle { + get { + int style = this.style; + if (style == UNDEFINED) { + style = NORMAL; + } + if (baseFont != null) + return style; + if (family == SYMBOL || family == ZAPFDINGBATS) + return style; + else + return style & (~BOLDITALIC); + } + } + + /// + /// checks if this font is Bold. + /// + /// a boolean + public bool IsBold() { + if (style == UNDEFINED) { + return false; + } + return (style & BOLD) == BOLD; + } + + /// + /// checks if this font is Bold. + /// + /// a boolean + public bool IsItalic() { + if (style == UNDEFINED) { + return false; + } + return (style & ITALIC) == ITALIC; + } + + /// + /// checks if this font is underlined. + /// + /// a boolean + public bool IsUnderlined() { + if (style == UNDEFINED) { + return false; + } + return (style & UNDERLINE) == UNDERLINE; + } + + /// + /// checks if the style of this font is STRIKETHRU. + /// + /// a boolean + public bool IsStrikethru() { + if (style == UNDEFINED) { + return false; + } + return (style & STRIKETHRU) == STRIKETHRU; + } + + /// + /// Sets the style using a String containing one of + /// more of the following values: normal, bold, italic, underline, strike. + /// + /// A String representing a certain style. + public virtual void SetStyle(String style) { + if (this.style == UNDEFINED) this.style = NORMAL; + this.style |= GetStyleValue(style); + } + + /** + * Sets the style. + * @param style the style. + */ + + public virtual void SetStyle(int style) { + if (this.style == UNDEFINED) this.style = NORMAL; + this.style |= style; + } + + /// + /// Translates a string-value of a certain style + /// into the index value is used for this style in this class. + /// + /// a string + /// the corresponding value + public static int GetStyleValue(string style) { + int s = 0; + if (style.IndexOf(Markup.CSS_VALUE_NORMAL) != -1) { + s |= NORMAL; + } + if (style.IndexOf(Markup.CSS_VALUE_BOLD) != -1) { + s |= BOLD; + } + if (style.IndexOf(Markup.CSS_VALUE_ITALIC) != -1) { + s |= ITALIC; + } + if (style.IndexOf(Markup.CSS_VALUE_OBLIQUE) != -1) { + s |= ITALIC; + } + if (style.IndexOf(Markup.CSS_VALUE_UNDERLINE) != -1) { + s |= UNDERLINE; + } + if (style.IndexOf(Markup.CSS_VALUE_LINETHROUGH) != -1) { + s |= STRIKETHRU; + } + return s; + } + + + // COLOR + + /// + /// Get/set the color of this font. + /// + /// the color of this font + public virtual Color Color { + get { + return color; + } + set { + this.color = value; + } + } + + /// + /// Sets the color. + /// + /// the red-value of the new color + /// the green-value of the new color + /// the blue-value of the new color + public virtual void SetColor(int red, int green, int blue) { + this.color = new Color(red, green, blue); + } + + // BASEFONT + + /// + /// Gets the BaseFont inside this object. + /// + /// the BaseFont + public BaseFont BaseFont { + get { + return baseFont; + } + } + + /** Gets the BaseFont this class represents. + * For the built-in fonts a BaseFont is calculated. + * @param specialEncoding true to use the special encoding for Symbol and ZapfDingbats, + * false to always use Cp1252 + * @return the BaseFont this class represents + */ + public BaseFont GetCalculatedBaseFont(bool specialEncoding) { + if (baseFont != null) + return baseFont; + int style = this.style; + if (style == UNDEFINED) { + style = NORMAL; + } + String fontName = BaseFont.HELVETICA; + String encoding = BaseFont.WINANSI; + BaseFont cfont = null; + switch (family) { + case COURIER: + switch (style & BOLDITALIC) { + case BOLD: + fontName = BaseFont.COURIER_BOLD; + break; + case ITALIC: + fontName = BaseFont.COURIER_OBLIQUE; + break; + case BOLDITALIC: + fontName = BaseFont.COURIER_BOLDOBLIQUE; + break; + default: + //case NORMAL: + fontName = BaseFont.COURIER; + break; + } + break; + case TIMES_ROMAN: + switch (style & BOLDITALIC) { + case BOLD: + fontName = BaseFont.TIMES_BOLD; + break; + case ITALIC: + fontName = BaseFont.TIMES_ITALIC; + break; + case BOLDITALIC: + fontName = BaseFont.TIMES_BOLDITALIC; + break; + default: + //case NORMAL: + fontName = BaseFont.TIMES_ROMAN; + break; + } + break; + case SYMBOL: + fontName = BaseFont.SYMBOL; + if (specialEncoding) + encoding = BaseFont.SYMBOL; + break; + case ZAPFDINGBATS: + fontName = BaseFont.ZAPFDINGBATS; + if (specialEncoding) + encoding = BaseFont.ZAPFDINGBATS; + break; + default: + //case Font.HELVETICA: + switch (style & BOLDITALIC) { + case BOLD: + fontName = BaseFont.HELVETICA_BOLD; + break; + case ITALIC: + fontName = BaseFont.HELVETICA_OBLIQUE; + break; + case BOLDITALIC: + fontName = BaseFont.HELVETICA_BOLDOBLIQUE; + break; + default: + //case NORMAL: + fontName = BaseFont.HELVETICA; + break; + } + break; + } + cfont = BaseFont.CreateFont(fontName, encoding, false); + return cfont; + } + + // Helper methods + + /// + /// Checks if the properties of this font are undefined or null. + ///

+ /// If so, the standard should be used. + ///

+ /// a boolean + public virtual bool IsStandardFont() { + return (family == UNDEFINED + && size == UNDEFINED + && style == UNDEFINED + && color == null + && baseFont == null); + } + + /// + /// Replaces the attributes that are equal to null with + /// the attributes of a given font. + /// + /// the font of a bigger element class + /// a Font + public virtual Font Difference(Font font) { + if (font == null) return this; + // size + float dSize = font.size; + if (dSize == UNDEFINED) { + dSize = this.size; + } + // style + int dStyle = UNDEFINED; + int style1 = this.Style; + int style2 = font.Style; + if (style1 != UNDEFINED || style2 != UNDEFINED) { + if (style1 == UNDEFINED) style1 = 0; + if (style2 == UNDEFINED) style2 = 0; + dStyle = style1 | style2; + } + // color + object dColor = (Color)font.Color; + if (dColor == null) { + dColor = this.Color; + } + // family + if (font.baseFont != null) { + return new Font(font.BaseFont, dSize, dStyle, (Color)dColor); + } + if (font.Family != UNDEFINED) { + return new Font(font.Family, dSize, dStyle, (Color)dColor); + } + if (this.baseFont != null) { + if (dStyle == style1) { + return new Font(this.BaseFont, dSize, dStyle, (Color)dColor); + } + else { + return FontFactory.GetFont(this.Familyname, dSize, dStyle, (Color)dColor); + } + } + return new Font(this.Family, dSize, dStyle, (Color)dColor); + } + } +} diff --git a/iTechSharp/iTextSharp/text/FontFactory.cs b/iTechSharp/iTextSharp/text/FontFactory.cs new file mode 100644 index 0000000..a90d249 --- /dev/null +++ b/iTechSharp/iTextSharp/text/FontFactory.cs @@ -0,0 +1,426 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using System.Globalization; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text; + +/* + * $Id: FontFactory.cs,v 1.16 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// If you are using True Type fonts, you can declare the paths of the different ttf- and ttc-files + /// to this static class first and then create fonts in your code using one of the static getFont-method + /// without having to enter a path as parameter. + /// + public sealed class FontFactory { + + /// This is a possible value of a base 14 type 1 font + public const string COURIER = BaseFont.COURIER; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_BOLD = BaseFont.COURIER_BOLD; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_OBLIQUE = BaseFont.COURIER_OBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_BOLDOBLIQUE = BaseFont.COURIER_BOLDOBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA = BaseFont.HELVETICA; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_BOLD = BaseFont.HELVETICA_BOLD; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_OBLIQUE = BaseFont.HELVETICA_OBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_BOLDOBLIQUE = BaseFont.HELVETICA_BOLDOBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string SYMBOL = BaseFont.SYMBOL; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES = "Times"; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_ROMAN = BaseFont.TIMES_ROMAN; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_BOLD = BaseFont.TIMES_BOLD; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_ITALIC = BaseFont.TIMES_ITALIC; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_BOLDITALIC = BaseFont.TIMES_BOLDITALIC; + + /// This is a possible value of a base 14 type 1 font + public const string ZAPFDINGBATS = BaseFont.ZAPFDINGBATS; + + private static FontFactoryImp fontImp = new FontFactoryImp(); + + /// This is the default encoding to use. + private static string defaultEncoding = BaseFont.WINANSI; + + /// This is the default value of the embedded variable. + private static bool defaultEmbedding = BaseFont.NOT_EMBEDDED; + + /// Creates new FontFactory + private FontFactory() { + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color) { + return fontImp.GetFont(fontname, encoding, embedded, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// true if the font comes from the cache or is added to the cache if new, false if the font is always created new + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color, bool cached) { + return fontImp.GetFont(fontname, encoding, embedded, size, style, color, cached); + } + + /// + /// Constructs a Font-object. + /// + /// the attributes of a Font object + /// a Font object + public static Font GetFont(Properties attributes) { + fontImp.DefaultEmbedding = defaultEmbedding; + fontImp.DefaultEncoding = defaultEncoding; + return fontImp.GetFont(attributes); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded, float size, int style) { + return GetFont(fontname, encoding, embedded, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// + public static Font GetFont(string fontname, string encoding, bool embedded, float size) { + return GetFont(fontname, encoding, embedded, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded) { + return GetFont(fontname, encoding, embedded, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, float size, int style, Color color) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, float size, int style) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, float size) { + return GetFont(fontname, encoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// a Font object + public static Font GetFont(string fontname, string encoding) { + return GetFont(fontname, encoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, float size, int style, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, float size, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// a Font object + public static Font GetFont(string fontname, float size, int style) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// a Font object + public static Font GetFont(string fontname, float size) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// a Font object + public static Font GetFont(string fontname) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /** + * Register a font by giving explicitly the font family and name. + * @param familyName the font family + * @param fullName the font name + * @param path the font path + */ + public void RegisterFamily(String familyName, String fullName, String path) { + fontImp.RegisterFamily(familyName, fullName, path); + } + + public static void Register(Properties attributes) { + string path; + string alias = null; + + path = attributes.Remove("path"); + alias = attributes.Remove("alias"); + + fontImp.Register(path, alias); + } + + /// + /// Register a ttf- or a ttc-file. + /// + /// the path to a ttf- or ttc-file + public static void Register(string path) { + Register(path, null); + } + + /// + /// Register a ttf- or a ttc-file and use an alias for the font contained in the ttf-file. + /// + /// the path to a ttf- or ttc-file + /// the alias you want to use for the font + public static void Register(string path, string alias) { + fontImp.Register(path, alias); + } + + /** Register all the fonts in a directory. + * @param dir the directory + * @return the number of fonts registered + */ + public static int RegisterDirectory(String dir) { + return fontImp.RegisterDirectory(dir); + } + + /** + * Register all the fonts in a directory and possibly its subdirectories. + * @param dir the directory + * @param scanSubdirectories recursively scan subdirectories if true + * @return the number of fonts registered + * @since 2.1.2 + */ + public static int RegisterDirectory(String dir, bool scanSubdirectories) { + return fontImp.RegisterDirectory(dir, scanSubdirectories); + } + + /** Register fonts in some probable directories. It usually works in Windows, + * Linux and Solaris. + * @return the number of fonts registered + */ + public static int RegisterDirectories() { + return fontImp.RegisterDirectories(); + } + + /// + /// Gets a set of registered fontnames. + /// + /// a set of registered fontnames + public static ICollection RegisteredFonts { + get { + return fontImp.RegisteredFonts; + } + } + + /// + /// Gets a set of registered font families. + /// + /// a set of registered font families + public static ICollection RegisteredFamilies { + get { + return fontImp.RegisteredFamilies; + } + } + + /// + /// Checks whether the given font is contained within the object + /// + /// the name of the font + /// true if font is contained within the object + public static bool Contains(string fontname) { + return fontImp.IsRegistered(fontname); + } + + /// + /// Checks if a certain font is registered. + /// + /// the name of the font that has to be checked + /// true if the font is found + public static bool IsRegistered(string fontname) { + return fontImp.IsRegistered(fontname); + } + + public static string DefaultEncoding { + get { + return defaultEncoding; + } + } + + public static bool DefaultEmbedding { + get { + return defaultEmbedding; + } + } + + + public static FontFactoryImp FontImp { + get { + return fontImp; + } + set { + if (value == null) + throw new ArgumentNullException("FontFactoryImp cannot be null."); + fontImp = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/FontFactoryImp.cs b/iTechSharp/iTextSharp/text/FontFactoryImp.cs new file mode 100644 index 0000000..2159137 --- /dev/null +++ b/iTechSharp/iTextSharp/text/FontFactoryImp.cs @@ -0,0 +1,677 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using System.Globalization; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text; + +/* + * $Id: FontFactoryImp.cs,v 1.13 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// If you are using True Type fonts, you can declare the paths of the different ttf- and ttc-files + /// to this class first and then create fonts in your code using one of the getFont method + /// without having to enter a path as parameter. + /// + public class FontFactoryImp { + + /// This is a map of postscriptfontnames of True Type fonts and the path of their ttf- or ttc-file. + private Properties trueTypeFonts = new Properties(); + + private static String[] TTFamilyOrder = { + "3", "1", "1033", + "3", "0", "1033", + "1", "0", "0", + "0", "3", "0" + }; + + /// This is a map of fontfamilies. + private Hashtable fontFamilies = new Hashtable(); + + /// This is the default encoding to use. + private string defaultEncoding = BaseFont.WINANSI; + + /// This is the default value of the embedded variable. + private bool defaultEmbedding = BaseFont.NOT_EMBEDDED; + + /// Creates new FontFactory + public FontFactoryImp() { + trueTypeFonts.Add(FontFactory.COURIER.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER); + trueTypeFonts.Add(FontFactory.COURIER_BOLD.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER_BOLD); + trueTypeFonts.Add(FontFactory.COURIER_OBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER_OBLIQUE); + trueTypeFonts.Add(FontFactory.COURIER_BOLDOBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER_BOLDOBLIQUE); + trueTypeFonts.Add(FontFactory.HELVETICA.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA); + trueTypeFonts.Add(FontFactory.HELVETICA_BOLD.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA_BOLD); + trueTypeFonts.Add(FontFactory.HELVETICA_OBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA_OBLIQUE); + trueTypeFonts.Add(FontFactory.HELVETICA_BOLDOBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA_BOLDOBLIQUE); + trueTypeFonts.Add(FontFactory.SYMBOL.ToLower(CultureInfo.InvariantCulture), FontFactory.SYMBOL); + trueTypeFonts.Add(FontFactory.TIMES_ROMAN.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_ROMAN); + trueTypeFonts.Add(FontFactory.TIMES_BOLD.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_BOLD); + trueTypeFonts.Add(FontFactory.TIMES_ITALIC.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_ITALIC); + trueTypeFonts.Add(FontFactory.TIMES_BOLDITALIC.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_BOLDITALIC); + trueTypeFonts.Add(FontFactory.ZAPFDINGBATS.ToLower(CultureInfo.InvariantCulture), FontFactory.ZAPFDINGBATS); + + ArrayList tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.COURIER); + tmp.Add(FontFactory.COURIER_BOLD); + tmp.Add(FontFactory.COURIER_OBLIQUE); + tmp.Add(FontFactory.COURIER_BOLDOBLIQUE); + fontFamilies[FontFactory.COURIER.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.HELVETICA); + tmp.Add(FontFactory.HELVETICA_BOLD); + tmp.Add(FontFactory.HELVETICA_OBLIQUE); + tmp.Add(FontFactory.HELVETICA_BOLDOBLIQUE); + fontFamilies[FontFactory.HELVETICA.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.SYMBOL); + fontFamilies[FontFactory.SYMBOL.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.TIMES_ROMAN); + tmp.Add(FontFactory.TIMES_BOLD); + tmp.Add(FontFactory.TIMES_ITALIC); + tmp.Add(FontFactory.TIMES_BOLDITALIC); + fontFamilies[FontFactory.TIMES.ToLower(CultureInfo.InvariantCulture)] = tmp; + fontFamilies[FontFactory.TIMES_ROMAN.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.ZAPFDINGBATS); + fontFamilies[FontFactory.ZAPFDINGBATS.ToLower(CultureInfo.InvariantCulture)] = tmp; + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color) { + return GetFont(fontname, encoding, embedded, size, style, color, true); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// true if the font comes from the cache or is added to the cache if new, false if the font is always created new + /// a Font object + public virtual Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color, bool cached) { + if (fontname == null) return new Font(Font.UNDEFINED, size, style, color); + string lowercasefontname = fontname.ToLower(CultureInfo.InvariantCulture); + ArrayList tmp = (ArrayList) fontFamilies[lowercasefontname]; + if (tmp != null) { + // some bugs were fixed here by Daniel Marczisovszky + int fs = Font.NORMAL; + bool found = false; + int s = style == Font.UNDEFINED ? Font.NORMAL : style; + foreach (string f in tmp) { + string lcf = f.ToLower(CultureInfo.InvariantCulture); + fs = Font.NORMAL; + if (lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("bold") != -1) fs |= Font.BOLD; + if (lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("italic") != -1 || lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("oblique") != -1) fs |= Font.ITALIC; + if ((s & Font.BOLDITALIC) == fs) { + fontname = f; + found = true; + break; + } + } + if (style != Font.UNDEFINED && found) { + style &= ~fs; + } + } + BaseFont basefont = null; + try { + try { + // the font is a type 1 font or CJK font + basefont = BaseFont.CreateFont(fontname, encoding, embedded, cached, null, null, true); + } + catch (DocumentException) { + } + if (basefont == null) { + // the font is a true type font or an unknown font + fontname = trueTypeFonts[fontname.ToLower(CultureInfo.InvariantCulture)]; + // the font is not registered as truetype font + if (fontname == null) return new Font(Font.UNDEFINED, size, style, color); + // the font is registered as truetype font + basefont = BaseFont.CreateFont(fontname, encoding, embedded, cached, null, null); + } + } + catch (DocumentException de) { + // this shouldn't happen + throw de; + } + catch (System.IO.IOException) { + // the font is registered as a true type font, but the path was wrong + return new Font(Font.UNDEFINED, size, style, color); + } + catch { + // null was entered as fontname and/or encoding + return new Font(Font.UNDEFINED, size, style, color); + } + return new Font(basefont, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the attributes of a Font object + /// a Font object + public virtual Font GetFont(Properties attributes) { + string fontname = null; + string encoding = defaultEncoding; + bool embedded = defaultEmbedding; + float size = Font.UNDEFINED; + int style = Font.NORMAL; + Color color = null; + string value = attributes[Markup.HTML_ATTR_STYLE]; + if (value != null && value.Length > 0) { + Properties styleAttributes = Markup.ParseAttributes(value); + if (styleAttributes.Count == 0) { + attributes.Add(Markup.HTML_ATTR_STYLE, value); + } + else { + fontname = styleAttributes[Markup.CSS_KEY_FONTFAMILY]; + if (fontname != null) { + string tmp; + while (fontname.IndexOf(',') != -1) { + tmp = fontname.Substring(0, fontname.IndexOf(',')); + if (IsRegistered(tmp)) { + fontname = tmp; + } + else { + fontname = fontname.Substring(fontname.IndexOf(',') + 1); + } + } + } + if ((value = styleAttributes[Markup.CSS_KEY_FONTSIZE]) != null) { + size = Markup.ParseLength(value); + } + if ((value = styleAttributes[Markup.CSS_KEY_FONTWEIGHT]) != null) { + style |= Font.GetStyleValue(value); + } + if ((value = styleAttributes[Markup.CSS_KEY_FONTSTYLE]) != null) { + style |= Font.GetStyleValue(value); + } + if ((value = styleAttributes[Markup.CSS_KEY_COLOR]) != null) { + color = Markup.DecodeColor(value); + } + attributes.AddAll(styleAttributes); + } + } + if ((value = attributes[ElementTags.ENCODING]) != null) { + encoding = value; + } + if ("true".Equals(attributes[ElementTags.EMBEDDED])) { + embedded = true; + } + if ((value = attributes[ElementTags.FONT]) != null) { + fontname = value; + } + if ((value = attributes[ElementTags.SIZE]) != null) { + size = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + if ((value = attributes[Markup.HTML_ATTR_STYLE]) != null) { + style |= Font.GetStyleValue(value); + } + if ((value = attributes[ElementTags.STYLE]) != null) { + style |= Font.GetStyleValue(value); + } + string r = attributes[ElementTags.RED]; + string g = attributes[ElementTags.GREEN]; + string b = attributes[ElementTags.BLUE]; + if (r != null || g != null || b != null) { + int red = 0; + int green = 0; + int blue = 0; + if (r != null) red = int.Parse(r); + if (g != null) green = int.Parse(g); + if (b != null) blue = int.Parse(b); + color = new Color(red, green, blue); + } + else if ((value = attributes[ElementTags.COLOR]) != null) { + color = Markup.DecodeColor(value); + } + if (fontname == null) { + return GetFont(null, encoding, embedded, size, style, color); + } + return GetFont(fontname, encoding, embedded, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// a Font object + public Font GetFont(string fontname, string encoding, bool embedded, float size, int style) { + return GetFont(fontname, encoding, embedded, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// + public virtual Font GetFont(string fontname, string encoding, bool embedded, float size) { + return GetFont(fontname, encoding, embedded, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// a Font object + public virtual Font GetFont(string fontname, string encoding, bool embedded) { + return GetFont(fontname, encoding, embedded, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, float size, int style, Color color) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, float size, int style) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, float size) { + return GetFont(fontname, encoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// a Font object + public virtual Font GetFont(string fontname, string encoding) { + return GetFont(fontname, encoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, float size, int style, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, float size, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// a Font object + public virtual Font GetFont(string fontname, float size, int style) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// a Font object + public virtual Font GetFont(string fontname, float size) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// a Font object + public virtual Font GetFont(string fontname) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + public virtual void Register(Properties attributes) { + string path; + string alias = null; + + path = attributes.Remove("path"); + alias = attributes.Remove("alias"); + + Register(path, alias); + } + + /** + * Register a font by giving explicitly the font family and name. + * @param familyName the font family + * @param fullName the font name + * @param path the font path + */ + public void RegisterFamily(String familyName, String fullName, String path) { + if (path != null) + trueTypeFonts.Add(fullName, path); + ArrayList tmp = (ArrayList) fontFamilies[familyName]; + if (tmp == null) { + tmp = new ArrayList(); + tmp.Add(fullName); + fontFamilies[familyName] = tmp; + } + else { + int fullNameLength = fullName.Length; + bool inserted = false; + for (int j = 0; j < tmp.Count; ++j) { + if (((String)tmp[j]).Length >= fullNameLength) { + tmp.Insert(j, fullName); + inserted = true; + break; + } + } + if (!inserted) + tmp.Add(fullName); + } + } + + /// + /// Register a ttf- or a ttc-file. + /// + /// the path to a ttf- or ttc-file + public virtual void Register(string path) { + Register(path, null); + } + + /// + /// Register a ttf- or a ttc-file and use an alias for the font contained in the ttf-file. + /// + /// the path to a ttf- or ttc-file + /// the alias you want to use for the font + public virtual void Register(string path, string alias) { + try { + if (path.ToLower(CultureInfo.InvariantCulture).EndsWith(".ttf") || path.ToLower(CultureInfo.InvariantCulture).EndsWith(".otf") || path.ToLower(CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) { + Object[] allNames = BaseFont.GetAllFontNames(path, BaseFont.WINANSI, null); + trueTypeFonts.Add(((string)allNames[0]).ToLower(CultureInfo.InvariantCulture), path); + if (alias != null) { + trueTypeFonts.Add(alias.ToLower(CultureInfo.InvariantCulture), path); + } + // register all the font names with all the locales + string[][] names = (string[][])allNames[2]; //full name + for (int i = 0; i < names.Length; i++) { + trueTypeFonts.Add(names[i][3].ToLower(CultureInfo.InvariantCulture), path); + } + string fullName = null; + string familyName = null; + names = (string[][])allNames[1]; //family name + for (int k = 0; k < TTFamilyOrder.Length; k += 3) { + for (int i = 0; i < names.Length; i++) { + if (TTFamilyOrder[k].Equals(names[i][0]) && TTFamilyOrder[k + 1].Equals(names[i][1]) && TTFamilyOrder[k + 2].Equals(names[i][2])) { + familyName = names[i][3].ToLower(CultureInfo.InvariantCulture); + k = TTFamilyOrder.Length; + break; + } + } + } + if (familyName != null) { + String lastName = ""; + names = (string[][])allNames[2]; //full name + for (int i = 0; i < names.Length; i++) { + for (int k = 0; k < TTFamilyOrder.Length; k += 3) { + if (TTFamilyOrder[k].Equals(names[i][0]) && TTFamilyOrder[k + 1].Equals(names[i][1]) && TTFamilyOrder[k + 2].Equals(names[i][2])) { + fullName = names[i][3]; + if (fullName.Equals(lastName)) + continue; + lastName = fullName; + RegisterFamily(familyName, fullName, null); + break; + } + } + } + } + } + else if (path.ToLower(CultureInfo.InvariantCulture).EndsWith(".ttc")) { + string[] names = BaseFont.EnumerateTTCNames(path); + for (int i = 0; i < names.Length; i++) { + Register(path + "," + i); + } + } + else if (path.ToLower(CultureInfo.InvariantCulture).EndsWith(".afm") || path.ToLower(CultureInfo.InvariantCulture).EndsWith(".pfm")) { + BaseFont bf = BaseFont.CreateFont(path, BaseFont.CP1252, false); + String fullName = (bf.FullFontName[0][3]).ToLower(CultureInfo.InvariantCulture); + String familyName = (bf.FamilyFontName[0][3]).ToLower(CultureInfo.InvariantCulture); + String psName = bf.PostscriptFontName.ToLower(CultureInfo.InvariantCulture); + RegisterFamily(familyName, fullName, null); + trueTypeFonts.Add(psName, path); + trueTypeFonts.Add(fullName, path); + } + } + catch (DocumentException de) { + // this shouldn't happen + throw de; + } + catch (System.IO.IOException ioe) { + throw ioe; + } + } + + /** Register all the fonts in a directory. + * @param dir the directory + * @return the number of fonts registered + */ + public virtual int RegisterDirectory(String dir) { + return RegisterDirectory(dir, false); + } + + /** + * Register all the fonts in a directory and possibly its subdirectories. + * @param dir the directory + * @param scanSubdirectories recursively scan subdirectories if true + * @return the number of fonts registered + * @since 2.1.2 + */ + public int RegisterDirectory(String dir, bool scanSubdirectories) { + int count = 0; + try { + if (!Directory.Exists(dir)) + return 0; + string[] files = Directory.GetFiles(dir); + if (files == null) + return 0; + for (int k = 0; k < files.Length; ++k) { + try { + if (Directory.Exists(files[k])) { + if (scanSubdirectories) { + count += RegisterDirectory(Path.GetFullPath(files[k]), true); + } + } else { + String name = Path.GetFullPath(files[k]); + String suffix = name.Length < 4 ? null : name.Substring(name.Length - 4).ToLower(CultureInfo.InvariantCulture); + if (".afm".Equals(suffix) || ".pfm".Equals(suffix)) { + /* Only register Type 1 fonts with matching .pfb files */ + string pfb = name.Substring(0, name.Length - 4) + ".pfb"; + if (File.Exists(pfb)) { + Register(name, null); + ++count; + } + } else if (".ttf".Equals(suffix) || ".otf".Equals(suffix) || ".ttc".Equals(suffix)) { + Register(name, null); + ++count; + } + } + } + catch { + //empty on purpose + } + } + } + catch { + //empty on purpose + } + return count; + } + + /** Register fonts in some probable directories. It usually works in Windows, + * Linux and Solaris. + * @return the number of fonts registered + */ + public virtual int RegisterDirectories() { + int count = 0; + count += RegisterDirectory("c:/windows/fonts"); + count += RegisterDirectory("c:/winnt/fonts"); + count += RegisterDirectory("d:/windows/fonts"); + count += RegisterDirectory("d:/winnt/fonts"); + count += RegisterDirectory("/usr/share/X11/fonts", true); + count += RegisterDirectory("/usr/X/lib/X11/fonts", true); + count += RegisterDirectory("/usr/openwin/lib/X11/fonts", true); + count += RegisterDirectory("/usr/share/fonts", true); + count += RegisterDirectory("/usr/X11R6/lib/X11/fonts", true); + count += RegisterDirectory("/Library/Fonts"); + count += RegisterDirectory("/System/Library/Fonts"); + return count; + } + + /// + /// Gets a set of registered fontnames. + /// + /// a set of registered fontnames + public virtual ICollection RegisteredFonts { + get { + return trueTypeFonts.Keys; + } + } + + /// + /// Gets a set of registered font families. + /// + /// a set of registered font families + public virtual ICollection RegisteredFamilies { + get { + return fontFamilies.Keys; + } + } + + /// + /// Checks if a certain font is registered. + /// + /// the name of the font that has to be checked + /// true if the font is found + public virtual bool IsRegistered(string fontname) { + return trueTypeFonts.ContainsKey(fontname.ToLower(CultureInfo.InvariantCulture)); + } + + public virtual string DefaultEncoding { + get { + return defaultEncoding; + } + set { + defaultEncoding = value; + } + } + + public virtual bool DefaultEmbedding { + get { + return defaultEmbedding; + } + set { + defaultEmbedding = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/GreekList.cs b/iTechSharp/iTextSharp/text/GreekList.cs new file mode 100644 index 0000000..dcb6965 --- /dev/null +++ b/iTechSharp/iTextSharp/text/GreekList.cs @@ -0,0 +1,124 @@ +using System; +using iTextSharp.text.factories; +/* + * Copyright 2003 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /** + * + * A special-version of LIST whitch use greek-letters. + * + * @see com.lowagie.text.List + */ + public class GreekList : List { + /** + * Initialization + * + * @param symbolIndent indent + */ + public GreekList() : base(true) { + SetGreekFont(); + } + + /** + * Initialisierung + * + * @param symbolIndent indent + */ + public GreekList(int symbolIndent) : base(true, symbolIndent) { + SetGreekFont(); + } + + /** + * Initialisierung + * @param greeklower greek-char in lowercase + * @param symbolIndent indent + */ + public GreekList(bool greeklower, int symbolIndent) : base(true, symbolIndent) { + lowercase = greeklower; + SetGreekFont(); + } + + /** + * change the font to SYMBOL + */ + protected void SetGreekFont() { + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.SYMBOL, fontsize, Font.NORMAL); + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + chunk.Append(GreekAlphabetFactory.GetString(first + list.Count, lowercase)); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is string) { + return this.Add(new ListItem((string)o)); + } + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Header.cs b/iTechSharp/iTextSharp/text/Header.cs new file mode 100644 index 0000000..e8a37eb --- /dev/null +++ b/iTechSharp/iTextSharp/text/Header.cs @@ -0,0 +1,94 @@ +using System; +using System.Text; + +/* + * $Id: Header.cs,v 1.4 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// This is an Element that contains + /// some userdefined meta information about the document. + /// + /// + /// + /// Header header = new Header("inspired by", "William Shakespeare"); + /// + /// + public class Header : Meta { + + // membervariables + + /// This is the content of this chunk of text. + private StringBuilder name; + + // constructors + + /// + /// Constructs a Header. + /// + /// the name of the meta-information + /// the content + public Header(string name, string content) : base(Element.HEADER, content) { + this.name = new StringBuilder(name); + } + + // methods to retrieve information + + /// + /// Returns the name of the meta information. + /// + /// a string + public override string Name { + get { + return name.ToString(); + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/HeaderFooter.cs b/iTechSharp/iTextSharp/text/HeaderFooter.cs new file mode 100644 index 0000000..8dfecd0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/HeaderFooter.cs @@ -0,0 +1,234 @@ +using System; +using System.util; +using System.Collections; + +/* + * $Id: HeaderFooter.cs,v 1.6 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A HeaderFooter-object is a Rectangle with text + /// that can be put above and/or below every page. + /// + /// + /// + /// HeaderFooter header = new HeaderFooter(new Phrase("This is a header."), false); + /// HeaderFooter footer = new HeaderFooter(new Phrase("This is page "), new Phrase(".")); + /// document.SetHeader(header); + /// document.SetFooter(footer); + /// + /// + public class HeaderFooter : Rectangle { + + // membervariables + + /// Does the page contain a pagenumber? + private bool numbered; + + /// This is the Phrase that comes before the pagenumber. + private Phrase before = null; + + /// This is number of the page. + private int pageN; + + /// This is the Phrase that comes after the pagenumber. + private Phrase after = null; + + /// This is alignment of the header/footer. + private int alignment; + + // constructors + + /// + /// Constructs a HeaderFooter-object. + /// + /// the Phrase before the pagenumber + /// the Phrase after the pagenumber + public HeaderFooter(Phrase before, Phrase after) : base(0, 0, 0, 0) { + this.Border = TOP_BORDER + BOTTOM_BORDER; + this.BorderWidth = 1; + + numbered = true; + this.before = before; + this.after = after; + } + + /// + /// Constructs a Header-object with a pagenumber at the end. + /// + /// the Phrase before the pagenumber + /// true if the page has to be numbered + public HeaderFooter(Phrase before, bool numbered) : base(0, 0, 0, 0) { + this.Border = TOP_BORDER + BOTTOM_BORDER; + this.BorderWidth = 1; + + this.numbered = numbered; + this.before = before; + } + + public HeaderFooter(Properties attributes) : base(0, 0, 0, 0) { + string value; + + if ((value = attributes.Remove(ElementTags.NUMBERED)) != null) { + this.numbered = bool.Parse(value); + } + if ((value = attributes.Remove(ElementTags.ALIGN)) != null) { + this.SetAlignment(value); + } + if ((value = attributes.Remove("border")) != null) { + this.Border = int.Parse(value); + } else { + this.Border = TOP_BORDER + BOTTOM_BORDER; + } + } + + // methods + + /// + /// Checks if the HeaderFooter contains a page number. + /// + /// true if the page has to be numbered + public bool IsNumbered() { + return numbered; + } + + /// + /// Get/set the part that comes before the pageNumber. + /// + /// a Phrase + public Phrase Before { + get { + return before; + } + + set { + this.before = value; + } + } + + /// + /// Get/set the part that comes after the pageNumber. + /// + /// a Phrase + public Phrase After { + get { + return after; + } + + set { + this.after = value; + } + } + + /// + /// Sets the page number. + /// + /// the new page number + public int PageNumber { + set { + this.pageN = value; + } + } + + /// + /// Sets the Element. + /// + /// the new alignment + public int Alignment{ + set { + this.alignment = value; + } + get { + return this.alignment; + } + } + + /// + /// Sets the alignment of this HeaderFooter. + /// + /// the new alignment as a string + public void SetAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_CENTER)) { + this.alignment = Element.ALIGN_CENTER; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.alignment = Element.ALIGN_RIGHT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED)) { + this.alignment = Element.ALIGN_JUSTIFIED; + return; + } + this.alignment = Element.ALIGN_LEFT; + } + + // methods to retrieve the membervariables + + /// + /// Gets the Paragraph that can be used as header or footer. + /// + /// a Paragraph + public Paragraph Paragraph { + get { + Paragraph paragraph = new Paragraph(before.Leading); + paragraph.Add(before); + if (numbered) { + paragraph.AddSpecial(new Chunk(pageN.ToString(), before.Font)); + } + if (after != null) { + paragraph.AddSpecial(after); + } + paragraph.Alignment = alignment; + return paragraph; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/IDocListener.cs b/iTechSharp/iTextSharp/text/IDocListener.cs new file mode 100644 index 0000000..9cdad26 --- /dev/null +++ b/iTechSharp/iTextSharp/text/IDocListener.cs @@ -0,0 +1,149 @@ +using System; + +/* + * $Id: IDocListener.cs,v 1.5 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright (c) 1999, 2000, 2001, 2002 Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A class that implements DocListener will perform some + /// actions when some actions are performed on a Document. + /// + /// + /// + /// + public interface IDocListener : IElementListener { + + // methods + + /// + /// Signals that the Document has been opened and that + /// Elements can be added. + /// + void Open(); + + /// + /// Signals that the Document was closed and that no other + /// Elements will be added. + /// + /// + /// The output stream of every writer implementing IDocListener will be closed. + /// + void Close(); + + /// + /// Signals that an new page has to be started. + /// + /// true if the page was added, false if not. + bool NewPage(); + + /// + /// Sets the pagesize. + /// + /// the new pagesize + /// a boolean + bool SetPageSize(Rectangle pageSize); + + /// + /// Sets the margins. + /// + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + /// + bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom); + + /** + * Parameter that allows you to do margin mirroring (odd/even pages) + * @param marginMirroring + * @return true if succesfull + */ + bool SetMarginMirroring(bool marginMirroring); + + /// + /// Sets the page number. + /// + /// the new page number + int PageCount { + set; + } + + /// + /// Sets the page number to 0. + /// + void ResetPageCount(); + + /// + /// Changes the header of this document. + /// + /// a Header + HeaderFooter Header { + set; + } + + /// + /// Resets the header of this document. + /// + void ResetHeader(); + + /// + /// Changes the footer of this document. + /// + /// a Footer + HeaderFooter Footer { + set; + } + + /// + /// Resets the footer of this document. + /// + void ResetFooter(); + } +} diff --git a/iTechSharp/iTextSharp/text/IElement.cs b/iTechSharp/iTextSharp/text/IElement.cs new file mode 100644 index 0000000..36f86cf --- /dev/null +++ b/iTechSharp/iTextSharp/text/IElement.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections; + +/* + * $Id: IElement.cs,v 1.4 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// Interface for a text element. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public interface IElement { + + // methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + bool Process(IElementListener listener); + + /// + /// Gets the type of the text element. + /// + /// a type + int Type { + get; + } + + /** + * Checks if this element is a content object. + * If not, it's a metadata object. + * @since iText 2.0.8 + * @return true if this is a 'content' element; false if this is a 'medadata' element + */ + + bool IsContent(); + + /** + * Checks if this element is nestable. + * @since iText 2.0.8 + * @return true if this element can be nested inside other elements. + */ + + bool IsNestable(); + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + ArrayList Chunks { + get; + } + + /// + /// Gets the content of the text element. + /// + /// the content of the text element + string ToString(); + } +} diff --git a/iTechSharp/iTextSharp/text/IElementListener.cs b/iTechSharp/iTextSharp/text/IElementListener.cs new file mode 100644 index 0000000..bbba509 --- /dev/null +++ b/iTechSharp/iTextSharp/text/IElementListener.cs @@ -0,0 +1,16 @@ +using System; + +namespace iTextSharp.text { + /// + /// A class that implements ElementListener will perform some + /// actions when an Element is added. + /// + public interface IElementListener { + /// + /// Signals that an Element was added to the Document. + /// + /// Element added + /// true if the element was added, false if not. + bool Add(IElement element); + } +} diff --git a/iTechSharp/iTextSharp/text/ILargeElement.cs b/iTechSharp/iTextSharp/text/ILargeElement.cs new file mode 100644 index 0000000..03e300e --- /dev/null +++ b/iTechSharp/iTextSharp/text/ILargeElement.cs @@ -0,0 +1,84 @@ +using System; +/* + * $Id: ILargeElement.cs,v 1.2 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Interface implemented by Element objects that can potentially consume + * a lot of memory. Objects implementing the LargeElement interface can + * be added to a Document more than once. If you have invoked setCompleted(false), + * they will be added partially and the content that was added will be + * removed until you've invoked setCompleted(true); + * @since iText 2.0.8 + */ + + public interface ILargeElement : IElement { + + /** + * If you invoke setCompleted(false), you indicate that the content + * of the object isn't complete yet; it can be added to the document + * partially, but more will follow. If you invoke setCompleted(true), + * you indicate that you won't add any more data to the object. + * @since iText 2.0.8 + * @param complete false if you'll be adding more data after + * adding the object to the document. + */ + bool ElementComplete { + get; + set; + } + + /** + * Flushes the content that has been added. + */ + void FlushContent(); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/IRtfElementInterface.cs b/iTechSharp/iTextSharp/text/IRtfElementInterface.cs new file mode 100644 index 0000000..0c2d792 --- /dev/null +++ b/iTechSharp/iTextSharp/text/IRtfElementInterface.cs @@ -0,0 +1,60 @@ +/* + * $Id: IRtfElementInterface.cs,v 1.2 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2008 by Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * The RTF jar depends on the iText jar, but the iText jar may not + * depend on the RTF jar. This interface offers a temporary solution + * until we find a more elegant way to solve this. + */ + public interface IRtfElementInterface { + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/ISplitCharacter.cs b/iTechSharp/iTextSharp/text/ISplitCharacter.cs new file mode 100644 index 0000000..191b1c1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ISplitCharacter.cs @@ -0,0 +1,94 @@ +using System; +using iTextSharp.text.pdf; +/* + * $Id: ISplitCharacter.cs,v 1.3 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// Interface for customizing the split character. + /// + public interface ISplitCharacter { + /** + * Returns true if the character can split a line. The splitting implementation + * is free to look ahead or look behind characters to make a decision. + *

+ * The default implementation is: + *

+ *

+        * public boolean IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) {
+        *    char c;
+        *    if (ck == null)
+        *        c = cc[current];
+        *    else
+        *        c = ck[Math.Min(current, ck.length - 1)].GetUnicodeEquivalent(cc[current]);
+        *    if (c <= ' ' || c == '-') {
+        *        return true;
+        *    }
+        *    if (c < 0x2e80)
+        *        return false;
+        *    return ((c >= 0x2e80 && c < 0xd7a0)
+        *    || (c >= 0xf900 && c < 0xfb00)
+        *    || (c >= 0xfe30 && c < 0xfe50)
+        *    || (c >= 0xff61 && c < 0xffa0));
+        * }
+        * 
+ * @param start the lower limit of cc inclusive + * @param current the pointer to the character in cc + * @param end the upper limit of cc exclusive + * @param cc an array of characters at least end sized + * @param ck an array of PdfChunk. The main use is to be able to call + * {@link PdfChunk#getUnicodeEquivalent(char)}. It may be null + * or shorter than end. If null no convertion takes place. + * If shorter than end the last element is used + * @return true if the Character(s) can split a line + */ + + bool IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck); + } +} diff --git a/iTechSharp/iTextSharp/text/ITextElementArray.cs b/iTechSharp/iTextSharp/text/ITextElementArray.cs new file mode 100644 index 0000000..8df3bf4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ITextElementArray.cs @@ -0,0 +1,22 @@ +using System; + +namespace iTextSharp.text { + /// + /// Interface for a text element to which other objects can be added. + /// + /// + /// + /// + /// + /// + /// + /// + public interface ITextElementArray : IElement { + /// + /// Adds an object to the TextElementArray. + /// + /// an object that has to be added + /// true if the addition succeeded; false otherwise + bool Add(Object o); + } +} diff --git a/iTechSharp/iTextSharp/text/Image.cs b/iTechSharp/iTextSharp/text/Image.cs new file mode 100644 index 0000000..a73249a --- /dev/null +++ b/iTechSharp/iTextSharp/text/Image.cs @@ -0,0 +1,1483 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Runtime.CompilerServices; +using System.Collections; +using System.util; +using System.Reflection; + +using iTextSharp.text.pdf; +using iTextSharp.text.factories; +using iTextSharp.text.pdf.codec; + +/* + * $Id: Image.cs,v 1.28 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// An Image is the representation of a graphic element (JPEG, PNG or GIF) + /// that has to be inserted into the document + /// + /// + /// + public abstract class Image : Rectangle { + + // static membervariables (concerning the presence of borders) + + /// this is a kind of image Element. + public const int DEFAULT = 0; + + /// this is a kind of image Element. + public const int RIGHT_ALIGN = 2; + + /// this is a kind of image Element. + public const int LEFT_ALIGN = 0; + + /// this is a kind of image Element. + public const int MIDDLE_ALIGN = 1; + + /// this is a kind of image Element. + public const int TEXTWRAP = 4; + + /// this is a kind of image Element. + public const int UNDERLYING = 8; + + /// This represents a coordinate in the transformation matrix. + public const int AX = 0; + + /// This represents a coordinate in the transformation matrix. + public const int AY = 1; + + /// This represents a coordinate in the transformation matrix. + public const int BX = 2; + + /// This represents a coordinate in the transformation matrix. + public const int BY = 3; + + /// This represents a coordinate in the transformation matrix. + public const int CX = 4; + + /// This represents a coordinate in the transformation matrix. + public const int CY = 5; + + /// This represents a coordinate in the transformation matrix. + public const int DX = 6; + + /// This represents a coordinate in the transformation matrix. + public const int DY = 7; + + /** type of image */ + public const int ORIGINAL_NONE = 0; + + /** type of image */ + public const int ORIGINAL_JPEG = 1; + + /** type of image */ + public const int ORIGINAL_PNG = 2; + + /** type of image */ + public const int ORIGINAL_GIF = 3; + + /** type of image */ + public const int ORIGINAL_BMP = 4; + + /** type of image */ + public const int ORIGINAL_TIFF = 5; + + /** type of image */ + public const int ORIGINAL_WMF = 6; + + /** type of image */ + public const int ORIGINAL_JPEG2000 = 8; + + /** Image color inversion */ + protected bool invert = false; + + /// The imagetype. + protected int type; + + /// The URL of the image. + protected Uri url; + + /// The raw data of the image. + protected byte[] rawData; + + /// The template to be treated as an image. + protected PdfTemplate[] template = new PdfTemplate[1]; + + /// The alignment of the Image. + protected int alignment; + + /// Text that can be shown instead of the image. + protected string alt; + + /// This is the absolute X-position of the image. + protected float absoluteX = float.NaN; + + /// This is the absolute Y-position of the image. + protected float absoluteY = float.NaN; + + /// This is the width of the image without rotation. + protected float plainWidth; + + /// This is the width of the image without rotation. + protected float plainHeight; + + /// This is the scaled width of the image taking rotation into account. + protected float scaledWidth; + + /// This is the original height of the image taking rotation into account. + protected float scaledHeight; + + /// This is the rotation of the image. + protected float rotationRadians; + + /// this is the colorspace of a jpeg-image. + protected int colorspace = -1; + + /// this is the bits per component of the raw image. It also flags a CCITT image. + protected int bpc = 1; + + /// this is the transparency information of the raw image + protected int[] transparency; + + // for the moment these variables are only used for Images in class Table + // code contributed by Pelikan Stephan + /** the indentation to the left. */ + protected float indentationLeft = 0; + + /** the indentation to the right. */ + protected float indentationRight = 0; + // serial stamping + + protected long mySerialId = GetSerialId(); + + static object serialId = 0L; + + /// Holds value of property dpiX. + protected int dpiX = 0; + + /// Holds value of property dpiY. + protected int dpiY = 0; + + protected bool mask = false; + + protected Image imageMask; + + /// Holds value of property interpolation. + protected bool interpolation; + + /// if the annotation is not null the image will be clickable. + protected Annotation annotation = null; + + /// ICC Profile attached + protected ICC_Profile profile = null; + + /** Holds value of property deflated. */ + protected bool deflated = false; + + private PdfDictionary additional = null; + + /** Holds value of property smask. */ + private bool smask; + + /** Holds value of property XYRatio. */ + private float xyRatio = 0; + + /** Holds value of property originalType. */ + protected int originalType = ORIGINAL_NONE; + + /** Holds value of property originalData. */ + protected byte[] originalData; + + /** The spacing before the image. */ + protected float spacingBefore; + + /** The spacing after the image. */ + protected float spacingAfter; + + /** + * Holds value of property widthPercentage. + */ + private float widthPercentage = 100; + + protected IPdfOCG layer; + + /** + * Holds value of property initialRotation. + */ + private float initialRotation; + + private PdfIndirectReference directReference; + + // constructors + + /// + /// Constructs an Image-object, using an url. + /// + /// the URL where the image can be found. + public Image(Uri url) : base(0, 0) { + this.url = url; + this.alignment = DEFAULT; + rotationRadians = 0; + } + + /// + /// Constructs an Image object duplicate. + /// + /// another Image object. + public Image(Image image) : base(image) { + this.type = image.type; + this.url = image.url; + this.alignment = image.alignment; + this.alt = image.alt; + this.absoluteX = image.absoluteX; + this.absoluteY = image.absoluteY; + this.plainWidth = image.plainWidth; + this.plainHeight = image.plainHeight; + this.scaledWidth = image.scaledWidth; + this.scaledHeight = image.scaledHeight; + this.rotationRadians = image.rotationRadians; + this.indentationLeft = image.indentationLeft; + this.indentationRight = image.indentationRight; + this.colorspace = image.colorspace; + this.rawData = image.rawData; + this.template = image.template; + this.bpc = image.bpc; + this.transparency = image.transparency; + this.mySerialId = image.mySerialId; + this.invert = image.invert; + this.dpiX = image.dpiX; + this.dpiY = image.dpiY; + this.mask = image.mask; + this.imageMask = image.imageMask; + this.interpolation = image.interpolation; + this.annotation = image.annotation; + this.profile = image.profile; + this.deflated = image.deflated; + this.additional = image.additional; + this.smask = image.smask; + this.XYRatio = image.XYRatio; + this.originalData = image.originalData; + this.originalType = image.originalType; + this.spacingAfter = image.spacingAfter; + this.spacingBefore = image.spacingBefore; + this.widthPercentage = image.widthPercentage; + this.layer = image.layer; + this.initialRotation = image.initialRotation; + this.directReference = image.directReference; + } + + /// + /// Gets an instance of an Image. + /// + /// an Image + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(Image image) { + if (image == null) + return null; + return (Image)image.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(Image)}, null).Invoke(new object[] {image}); + } + + /// + /// Gets an instance of an Image. + /// + /// an URL + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(Uri url) { + Stream istr = null; + try { + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + int c1 = istr.ReadByte(); + int c2 = istr.ReadByte(); + int c3 = istr.ReadByte(); + int c4 = istr.ReadByte(); + istr.Close(); + + istr = null; + if (c1 == 'G' && c2 == 'I' && c3 == 'F') { + GifImage gif = new GifImage(url); + Image img = gif.GetImage(1); + return img; + } + if (c1 == 0xFF && c2 == 0xD8) { + return new Jpeg(url); + } + if (c1 == 0x00 && c2 == 0x00 && c3 == 0x00 && c4 == 0x0c) { + return new Jpeg2000(url); + } + if (c1 == 0xff && c2 == 0x4f && c3 == 0xff && c4 == 0x51) { + return new Jpeg2000(url); + } + if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1] + && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) { + Image img = PngImage.GetImage(url); + return img; + } + if (c1 == 0xD7 && c2 == 0xCD) { + Image img = new ImgWMF(url); + return img; + } + if (c1 == 'B' && c2 == 'M') { + Image img = BmpImage.GetImage(url); + return img; + } + if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42) + || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) { + RandomAccessFileOrArray ra = null; + try { + if (url.IsFile) { + String file = url.LocalPath; + ra = new RandomAccessFileOrArray(file); + } else + ra = new RandomAccessFileOrArray(url); + Image img = TiffImage.GetTiffImage(ra, 1); + img.url = url; + return img; + } finally { + if (ra != null) + ra.Close(); + } + + } + throw new IOException(url.ToString() + + " is not a recognized imageformat."); + } finally { + if (istr != null) { + istr.Close(); + } + } + } + + public static Image GetInstance(Stream s) { + byte[] a = RandomAccessFileOrArray.InputStreamToArray(s); + s.Close(); + return GetInstance(a); + } + + /// + /// Gets an instance of an Image. + /// + /// a byte array + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(byte[] imgb) { + int c1 = imgb[0]; + int c2 = imgb[1]; + int c3 = imgb[2]; + int c4 = imgb[3]; + + if (c1 == 'G' && c2 == 'I' && c3 == 'F') { + GifImage gif = new GifImage(imgb); + return gif.GetImage(1); + } + if (c1 == 0xFF && c2 == 0xD8) { + return new Jpeg(imgb); + } + if (c1 == 0x00 && c2 == 0x00 && c3 == 0x00 && c4 == 0x0c) { + return new Jpeg2000(imgb); + } + if (c1 == 0xff && c2 == 0x4f && c3 == 0xff && c4 == 0x51) { + return new Jpeg2000(imgb); + } + if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1] + && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) { + return PngImage.GetImage(imgb); + } + if (c1 == 0xD7 && c2 == 0xCD) { + return new ImgWMF(imgb); + } + if (c1 == 'B' && c2 == 'M') { + return BmpImage.GetImage(imgb); + } + if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42) + || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) { + RandomAccessFileOrArray ra = null; + try { + ra = new RandomAccessFileOrArray(imgb); + Image img = TiffImage.GetTiffImage(ra, 1); + if (img.OriginalData == null) + img.OriginalData = imgb; + + return img; + } finally { + if (ra != null) + ra.Close(); + } + + } + throw new IOException("The byte array is not a recognized imageformat."); + } + /// + /// Converts a .NET image to a Native(PNG, JPG, GIF, WMF) image + /// + /// + /// + /// + public static Image GetInstance(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format) { + MemoryStream ms = new MemoryStream(); + image.Save(ms, format); + return GetInstance(ms.ToArray()); + } + + /// + /// Gets an instance of an Image from a System.Drwaing.Image. + /// + /// the System.Drawing.Image to convert + /// + /// if different from null the transparency + /// pixels are replaced by this color + /// + /// if true the image is treated as black and white + /// an object of type ImgRaw + public static Image GetInstance(System.Drawing.Image image, Color color, bool forceBW) { + System.Drawing.Bitmap bm = (System.Drawing.Bitmap)image; + int w = bm.Width; + int h = bm.Height; + int pxv = 0; + if (forceBW) { + int byteWidth = (w / 8) + ((w & 7) != 0 ? 1 : 0); + byte[] pixelsByte = new byte[byteWidth * h]; + + int index = 0; + int size = h * w; + int transColor = 1; + if (color != null) { + transColor = (color.R + color.G + color.B < 384) ? 0 : 1; + } + int[] transparency = null; + int cbyte = 0x80; + int wMarker = 0; + int currByte = 0; + if (color != null) { + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int alpha = bm.GetPixel(i, j).A; + if (alpha < 250) { + if (transColor == 1) + currByte |= cbyte; + } + else { + if ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) + currByte |= cbyte; + } + cbyte >>= 1; + if (cbyte == 0 || wMarker + 1 >= w) { + pixelsByte[index++] = (byte)currByte; + cbyte = 0x80; + currByte = 0; + } + ++wMarker; + if (wMarker >= w) + wMarker = 0; + } + } + } + else { + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + if (transparency == null) { + int alpha = bm.GetPixel(i, j).A; + if (alpha == 0) { + transparency = new int[2]; + transparency[0] = transparency[1] = ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) ? 1 : 0; + } + } + if ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) + currByte |= cbyte; + cbyte >>= 1; + if (cbyte == 0 || wMarker + 1 >= w) { + pixelsByte[index++] = (byte)currByte; + cbyte = 0x80; + currByte = 0; + } + ++wMarker; + if (wMarker >= w) + wMarker = 0; + } + } + } + return Image.GetInstance(w, h, 1, 1, pixelsByte, transparency); + } + else { + byte[] pixelsByte = new byte[w * h * 3]; + byte[] smask = null; + + int index = 0; + int size = h * w; + int red = 255; + int green = 255; + int blue = 255; + if (color != null) { + red = color.R; + green = color.G; + blue = color.B; + } + int[] transparency = null; + if (color != null) { + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int alpha = (bm.GetPixel(i, j).ToArgb() >> 24) & 0xff; + if (alpha < 250) { + pixelsByte[index++] = (byte) red; + pixelsByte[index++] = (byte) green; + pixelsByte[index++] = (byte) blue; + } + else { + pxv = bm.GetPixel(i, j).ToArgb(); + pixelsByte[index++] = (byte) ((pxv >> 16) & 0xff); + pixelsByte[index++] = (byte) ((pxv >> 8) & 0xff); + pixelsByte[index++] = (byte) ((pxv) & 0xff); + } + } + } + } + else { + int transparentPixel = 0; + smask = new byte[w * h]; + bool shades = false; + int smaskPtr = 0; + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + pxv = bm.GetPixel(i, j).ToArgb(); + byte alpha = smask[smaskPtr++] = (byte) ((pxv >> 24) & 0xff); + /* bugfix by Chris Nokleberg */ + if (!shades) { + if (alpha != 0 && alpha != 255) { + shades = true; + } else if (transparency == null) { + if (alpha == 0) { + transparentPixel = pxv & 0xffffff; + transparency = new int[6]; + transparency[0] = transparency[1] = (transparentPixel >> 16) & 0xff; + transparency[2] = transparency[3] = (transparentPixel >> 8) & 0xff; + transparency[4] = transparency[5] = transparentPixel & 0xff; + } + } else if ((pxv & 0xffffff) != transparentPixel) { + shades = true; + } + } + pixelsByte[index++] = (byte) ((pxv >> 16) & 0xff); + pixelsByte[index++] = (byte) ((pxv >> 8) & 0xff); + pixelsByte[index++] = (byte) (pxv & 0xff); + } + } + if (shades) + transparency = null; + else + smask = null; + } + Image img = Image.GetInstance(w, h, 3, 8, pixelsByte, transparency); + if (smask != null) { + Image sm = Image.GetInstance(w, h, 1, 8, smask); + sm.MakeMask(); + img.ImageMask = sm; + } + return img; + } + } + + /// + /// Gets an instance of an Image from a System.Drawing.Image. + /// + /// the System.Drawing.Image to convert + /// + /// if different from null the transparency + /// pixels are replaced by this color + /// + /// an object of type ImgRaw + public static Image GetInstance(System.Drawing.Image image, Color color) { + return Image.GetInstance(image, color, false); + } + + /// + /// Gets an instance of an Image. + /// + /// a filename + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(string filename) { + return GetInstance(Utilities.ToURL(filename)); + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// the width of the image in pixels + /// the height of the image in pixels + /// 1,3 or 4 for GrayScale, RGB and CMYK + /// bits per component + /// the image data + /// an object of type ImgRaw + public static Image GetInstance(int width, int height, int components, int bpc, byte[] data) { + return Image.GetInstance(width, height, components, bpc, data, null); + } + + /** + * Reuses an existing image. + * @param ref the reference to the image dictionary + * @throws BadElementException on error + * @return the image + */ + public static Image GetInstance(PRIndirectReference iref) { + PdfDictionary dic = (PdfDictionary)PdfReader.GetPdfObjectRelease(iref); + int width = ((PdfNumber)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.WIDTH))).IntValue; + int height = ((PdfNumber)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.HEIGHT))).IntValue; + Image imask = null; + PdfObject obj = dic.Get(PdfName.SMASK); + if (obj != null && obj.IsIndirect()) { + imask = GetInstance((PRIndirectReference)obj); + } + else { + obj = dic.Get(PdfName.MASK); + if (obj != null && obj.IsIndirect()) { + PdfObject obj2 = PdfReader.GetPdfObjectRelease(obj); + if (obj2 is PdfDictionary) + imask = GetInstance((PRIndirectReference)obj); + } + } + Image img = new ImgRaw(width, height, 1, 1, null); + img.imageMask = imask; + img.directReference = iref; + return img; + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// + /// + public static Image GetInstance(PdfTemplate template) { + return new ImgTemplate(template); + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// the width of the image in pixels + /// the height of the image in pixels + /// + /// + /// + /// + /// + public static Image GetInstance(int width, int height, bool reverseBits, int typeCCITT, int parameters, byte[] data) { + return Image.GetInstance(width, height, reverseBits, typeCCITT, parameters, data, null); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Image GetInstance(int width, int height, bool reverseBits, int typeCCITT, int parameters, byte[] data, int[] transparency) { + if (transparency != null && transparency.Length != 2) + throw new BadElementException("Transparency length must be equal to 2 with CCITT images"); + Image img = new ImgCCITT(width, height, reverseBits, typeCCITT, parameters, data); + img.transparency = transparency; + return img; + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// the width of the image in pixels + /// the height of the image in pixels + /// 1,3 or 4 for GrayScale, RGB and CMYK + /// bits per component + /// the image data + /// + /// transparency information in the Mask format of the + /// image dictionary + /// + /// an object of type ImgRaw + public static Image GetInstance(int width, int height, int components, int bpc, byte[] data, int[] transparency) { + if (transparency != null && transparency.Length != components * 2) + throw new BadElementException("Transparency length must be equal to (componentes * 2)"); + if (components == 1 && bpc == 1) { + byte[] g4 = CCITTG4Encoder.Compress(data, width, height); + return Image.GetInstance(width, height, false, Element.CCITTG4, Element.CCITT_BLACKIS1, g4, transparency); + } + Image img = new ImgRaw(width, height, components, bpc, data); + img.transparency = transparency; + return img; + } + + // methods to set information + + /// + /// Sets the absolute position of the Image. + /// + /// + /// + public void SetAbsolutePosition(float absoluteX, float absoluteY) { + this.absoluteX = absoluteX; + this.absoluteY = absoluteY; + } + + /// + /// Scale the image to an absolute width and an absolute height. + /// + /// the new width + /// the new height + public void ScaleAbsolute(float newWidth, float newHeight) { + plainWidth = newWidth; + plainHeight = newHeight; + float[] matrix = this.Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scale the image to an absolute width. + /// + /// the new width + public void ScaleAbsoluteWidth(float newWidth) { + plainWidth = newWidth; + float[] matrix = this.Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scale the image to an absolute height. + /// + /// the new height + public void ScaleAbsoluteHeight(float newHeight) { + plainHeight = newHeight; + float[] matrix = Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scale the image to a certain percentage. + /// + /// the scaling percentage + public void ScalePercent(float percent) { + ScalePercent(percent, percent); + } + + /// + /// Scale the width and height of an image to a certain percentage. + /// + /// the scaling percentage of the width + /// the scaling percentage of the height + public void ScalePercent(float percentX, float percentY) { + plainWidth = (this.Width * percentX) / 100f; + plainHeight = (this.Height * percentY) / 100f; + float[] matrix = Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scales the image so that it fits a certain width and height. + /// + /// the width to fit + /// the height to fit + public void ScaleToFit(float fitWidth, float fitHeight) { + ScalePercent(100); + float percentX = (fitWidth * 100) / this.ScaledWidth; + float percentY = (fitHeight * 100) / this.ScaledHeight; + ScalePercent(percentX < percentY ? percentX : percentY); + WidthPercentage = 0; + } + + /** + * Gets the current image rotation in radians. + * @return the current image rotation in radians + */ + public float GetImageRotation() { + float rot = (float) ((rotationRadians - initialRotation) % (2.0 * Math.PI)); + if (rot < 0) { + rot += (float)(2.0 * Math.PI); + } + return rot; + } + + /// + /// Sets the rotation of the image in radians. + /// + /// rotation in radians + public new float Rotation { + set { + double d=Math.PI; //__IDS__ + rotationRadians = (float) ((value + initialRotation) % (2.0 * d)); //__IDS__ + if (rotationRadians < 0) { + rotationRadians += (float)(2.0 * d); //__IDS__ + } + float[] matrix = Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + } + } + + /// + /// Sets the rotation of the image in degrees. + /// + /// rotation in degrees + public float RotationDegrees { + set { + Rotation = (value / 180 * (float)Math.PI); //__IDS__ + } + } + + /// + /// Get/set the annotation. + /// + /// the Annotation + public Annotation Annotation { + get { + return annotation; + } + + set { + this.annotation = value; + } + } + + // methods to retrieve information + + /// + /// Gets the bpc for the image. + /// + /// + /// this only makes sense for Images of the type RawImage. + /// + /// a bpc value + public int Bpc { + get { + return bpc; + } + } + + /// + /// Gets the raw data for the image. + /// + /// + /// this only makes sense for Images of the type RawImage. + /// + /// the raw data + public byte[] RawData { + get { + return rawData; + } + } + + /// + /// Get/set the template to be used as an image. + /// + /// + /// this only makes sense for Images of the type ImgTemplate. + /// + /// the template + public PdfTemplate TemplateData { + get { + return template[0]; + } + + set { + this.template[0] = value; + } + } + + /// + /// Checks if the Images has to be added at an absolute position. + /// + /// a bool + public bool HasAbsolutePosition() { + return !float.IsNaN(absoluteY); + } + + /// + /// Checks if the Images has to be added at an absolute X position. + /// + /// a bool + public bool HasAbsoluteX() { + return !float.IsNaN(absoluteX); + } + + /// + /// Returns the absolute X position. + /// + /// a position + public float AbsoluteX { + get { + return absoluteX; + } + } + + /// + /// Returns the absolute Y position. + /// + /// a position + public float AbsoluteY { + get { + return absoluteY; + } + } + + /// + /// Returns the type. + /// + /// a type + public override int Type { + get { + return type; + } + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return true; + } + + /// + /// Returns true if the image is a Jpeg-object. + /// + /// a bool + public bool IsJpeg() { + return type == Element.JPEG; + } + + /// + /// Returns true if the image is a ImgRaw-object. + /// + /// a bool + public bool IsImgRaw() { + return type == Element.IMGRAW; + } + + /// + /// Returns true if the image is an ImgTemplate-object. + /// + /// a bool + public bool IsImgTemplate() { + return type == Element.IMGTEMPLATE; + } + + /// + /// Gets the string-representation of the reference to the image. + /// + /// a string + public Uri Url { + get { + return url; + } + set { + url = value; + } + } + + /// + /// Get/set the alignment for the image. + /// + /// a value + public int Alignment { + get { + return alignment; + } + + set { + this.alignment = value; + } + } + + /// + /// Get/set the alternative text for the image. + /// + /// a string + public string Alt { + get { + return alt; + } + + set { + this.alt = value; + } + } + + /// + /// Gets the scaled width of the image. + /// + /// a value + public float ScaledWidth { + get { + return scaledWidth; + } + } + + /// + /// Gets the scaled height of the image. + /// + /// a value + public float ScaledHeight { + get { + return scaledHeight; + } + } + + /// + /// Gets the colorspace for the image. + /// + /// + /// this only makes sense for Images of the type Jpeg. + /// + /// a colorspace value + public int Colorspace { + get { + return colorspace; + } + } + + /// + /// Returns the transformation matrix of the image. + /// + /// an array [AX, AY, BX, BY, CX, CY, DX, DY] + public float[] Matrix { + get { + float[] matrix = new float[8]; + float cosX = (float)Math.Cos(rotationRadians); + float sinX = (float)Math.Sin(rotationRadians); + matrix[AX] = plainWidth * cosX; + matrix[AY] = plainWidth * sinX; + matrix[BX] = (- plainHeight) * sinX; + matrix[BY] = plainHeight * cosX; + if (rotationRadians < Math.PI / 2f) { + matrix[CX] = matrix[BX]; + matrix[CY] = 0; + matrix[DX] = matrix[AX]; + matrix[DY] = matrix[AY] + matrix[BY]; + } + else if (rotationRadians < Math.PI) { + matrix[CX] = matrix[AX] + matrix[BX]; + matrix[CY] = matrix[BY]; + matrix[DX] = 0; + matrix[DY] = matrix[AY]; + } + else if (rotationRadians < Math.PI * 1.5f) { + matrix[CX] = matrix[AX]; + matrix[CY] = matrix[AY] + matrix[BY]; + matrix[DX] = matrix[BX]; + matrix[DY] = 0; + } + else { + matrix[CX] = 0; + matrix[CY] = matrix[AY]; + matrix[DX] = matrix[AX] + matrix[BX]; + matrix[DY] = matrix[BY]; + } + return matrix; + } + } + + /// + /// Returns the transparency. + /// + /// the transparency + public int[] Transparency { + get { + return transparency; + } + set { + transparency = value; + } + } + + /// + /// Gets the plain width of the image. + /// + /// a value + public float PlainWidth { + get { + return plainWidth; + } + } + + /// + /// Gets the plain height of the image. + /// + /// a value + public float PlainHeight { + get { + return plainHeight; + } + } + + /// + /// generates new serial id + /// + static protected long GetSerialId() { + lock (serialId) { + serialId = (long)serialId + 1L; + return (long)serialId; + } + } + + /// + /// returns serial id for this object + /// + public long MySerialId { + get { + return mySerialId; + } + } + + /// + /// Gets the dots-per-inch in the X direction. Returns 0 if not available. + /// + /// the dots-per-inch in the X direction + public int DpiX { + get { + return dpiX; + } + } + + /// + /// Gets the dots-per-inch in the Y direction. Returns 0 if not available. + /// + /// the dots-per-inch in the Y direction + public int DpiY { + get { + return dpiY; + } + } + + /** + * Sets the dots per inch value + * + * @param dpiX + * dpi for x coordinates + * @param dpiY + * dpi for y coordinates + */ + public void SetDpi(int dpiX, int dpiY) { + this.dpiX = dpiX; + this.dpiY = dpiY; + } + + /// + /// Returns true if this Image has the + /// requisites to be a mask. + /// + /// true if this Image can be a mask + public bool IsMaskCandidate() { + if (type == Element.IMGRAW) { + if (bpc > 0xff) + return true; + } + return colorspace == 1; + } + + /// + /// Make this Image a mask. + /// + public void MakeMask() { + if (!IsMaskCandidate()) + throw new DocumentException("This image can not be an image mask."); + mask = true; + } + + /// + /// Get/set the explicit masking. + /// + /// the explicit masking + public Image ImageMask { + get { + return imageMask; + } + + set { + if (this.mask) + throw new DocumentException("An image mask cannot contain another image mask."); + if (!value.mask) + throw new DocumentException("The image mask is not a mask. Did you do MakeMask()?"); + imageMask = value; + smask = (value.bpc > 1 && value.bpc <= 8); + } + } + + /// + /// Returns true if this Image is a mask. + /// + /// true if this Image is a mask + public bool IsMask() { + return mask; + } + + /// + /// Inverts the meaning of the bits of a mask. + /// + /// true to invert the meaning of the bits of a mask + public bool Inverted { + set { + this.invert = value; + } + get { + return this.invert; + } + } + + /// + /// Sets the image interpolation. Image interpolation attempts to + /// produce a smooth transition between adjacent sample values. + /// + /// New value of property interpolation. + public bool Interpolation { + set { + this.interpolation = value; + } + get { + return this.interpolation; + } + } + + /** Tags this image with an ICC profile. + * @param profile the profile + */ + public ICC_Profile TagICC { + get { + return profile; + } + set { + this.profile = value; + } + } + + /** Checks is the image has an ICC profile. + * @return the ICC profile or null + */ + public bool HasICCProfile() { + return (this.profile != null); + } + + public bool Deflated { + get { + return deflated; + } + set { + deflated = value; + } + } + + public PdfDictionary Additional { + get { + return additional; + } + set { + additional = value; + } + } + + public bool Smask { + get { + return smask; + } + set { + smask = value; + } + } + + public float XYRatio { + get { + return xyRatio; + } + set { + xyRatio = value; + } + } + + public float IndentationLeft { + get { + return indentationLeft; + } + set { + indentationLeft = value; + } + } + + public float IndentationRight { + get { + return indentationRight; + } + set { + indentationRight = value; + } + } + + public int OriginalType { + get { + return originalType; + } + set { + originalType = value; + } + } + + public byte[] OriginalData { + get { + return originalData; + } + set { + originalData = value; + } + } + + public float SpacingBefore { + get { + return spacingBefore; + } + set { + spacingBefore = value; + } + } + + public float SpacingAfter { + get { + return spacingAfter; + } + set { + spacingAfter = value; + } + } + + public float WidthPercentage { + get { + return widthPercentage; + } + set { + widthPercentage = value; + } + } + + public IPdfOCG Layer { + get { + return layer; + } + set { + layer = value; + } + } + + private PdfObject SimplifyColorspace(PdfObject obj) { + if (obj == null || !obj.IsArray()) + return obj; + PdfObject first = (PdfObject)(((PdfArray)obj).ArrayList[0]); + if (PdfName.CALGRAY.Equals(first)) + return PdfName.DEVICEGRAY; + else if (PdfName.CALRGB.Equals(first)) + return PdfName.DEVICERGB; + else + return obj; + } + + /** + * Replaces CalRGB and CalGray colorspaces with DeviceRGB and DeviceGray. + */ + public void SimplifyColorspace() { + if (additional == null) + return; + PdfObject value = additional.Get(PdfName.COLORSPACE); + if (value == null || !value.IsArray()) + return; + PdfObject cs = SimplifyColorspace(value); + if (cs.IsName()) + value = cs; + else { + PdfObject first = (PdfObject)(((PdfArray)value).ArrayList[0]); + if (PdfName.INDEXED.Equals(first)) { + ArrayList array = ((PdfArray)value).ArrayList; + if (array.Count >= 2 && ((PdfObject)array[1]).IsArray()) { + array[1] = SimplifyColorspace((PdfObject)array[1]); + } + } + } + additional.Put(PdfName.COLORSPACE, value); + } + + /** + * Some image formats, like TIFF may present the images rotated that have + * to be compensated. + */ + public float InitialRotation { + get { + return initialRotation; + } + set { + float old_rot = rotationRadians - this.initialRotation; + this.initialRotation = value; + Rotation = old_rot; + } + } + + public PdfIndirectReference DirectReference { + set { + directReference = value; + } + get { + return directReference; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgCCITT.cs b/iTechSharp/iTextSharp/text/ImgCCITT.cs new file mode 100644 index 0000000..f8b7950 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgCCITT.cs @@ -0,0 +1,107 @@ +using System; +using iTextSharp.text.pdf.codec; + +/* + * $Id: ImgCCITT.cs,v 1.6 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /** + * CCITT Image data that has to be inserted into the document + * + * @see Element + * @see Image + * + * @author Paulo Soares + */ + /// + /// CCITT Image data that has to be inserted into the document + /// + /// + /// + public class ImgCCITT : Image { + public ImgCCITT(Image image) : base(image) {} + + /// + /// Creats an Image in CCITT mode. + /// + /// the exact width of the image + /// the exact height of the image + /// + /// reverses the bits in data. + /// Bit 0 is swapped with bit 7 and so on + /// + /// + /// the type of compression in data. It can be + /// CCITTG4, CCITTG31D, CCITTG32D + /// + /// + /// parameters associated with this stream. Possible values are + /// CCITT_BLACKIS1, CCITT_ENCODEDBYTEALIGN, CCITT_ENDOFLINE and CCITT_ENDOFBLOCK or a + /// combination of them + /// + /// the image data + public ImgCCITT(int width, int height, bool reverseBits, int typeCCITT, int parameters, byte[] data) : base((Uri)null) { + if (typeCCITT != Element.CCITTG4 && typeCCITT != Element.CCITTG3_1D && typeCCITT != Element.CCITTG3_2D) + throw new BadElementException("The CCITT compression type must be CCITTG4, CCITTG3_1D or CCITTG3_2D"); + if (reverseBits) + TIFFFaxDecoder.ReverseBits(data); + type = Element.IMGRAW; + scaledHeight = height; + this.Top = scaledHeight; + scaledWidth = width; + this.Right = scaledWidth; + colorspace = parameters; + bpc = typeCCITT; + rawData = data; + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgRaw.cs b/iTechSharp/iTextSharp/text/ImgRaw.cs new file mode 100644 index 0000000..2b97c96 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgRaw.cs @@ -0,0 +1,88 @@ +using System; + +/* + * $Id: ImgRaw.cs,v 1.5 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// Raw Image data that has to be inserted into the document + /// + /// + /// + public class ImgRaw : Image { + + public ImgRaw(Image image) : base(image) {} + + /// + /// Creats an Image in raw mode. + /// + /// the exact width of the image + /// the exact height of the image + /// 1,3 or 4 for GrayScale, RGB and CMYK + /// bits per component. Must be 1,2,4 or 8 + /// data the image data + public ImgRaw(int width, int height, int components, int bpc, byte[] data) : base((Uri)null) { + type = Element.IMGRAW; + scaledHeight = height; + this.Top = scaledHeight; + scaledWidth = width; + this.Right = scaledWidth; + if (components != 1 && components != 3 && components != 4) + throw new BadElementException("Components must be 1, 3, or 4."); + if (bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8) + throw new BadElementException("Bits-per-component must be 1, 2, 4, or 8."); + colorspace = components; + this.bpc = bpc; + rawData = data; + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgTemplate.cs b/iTechSharp/iTextSharp/text/ImgTemplate.cs new file mode 100644 index 0000000..4b60f04 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgTemplate.cs @@ -0,0 +1,88 @@ +using System; + +using iTextSharp.text.pdf; + +/* + * $Id: ImgTemplate.cs,v 1.5 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// PdfTemplate that has to be inserted into the document + /// + /// + /// + public class ImgTemplate : Image { + + /// + /// Creats an Image from a PdfTemplate. + /// + /// the Image + public ImgTemplate(Image image) : base(image) {} + + /// + /// Creats an Image from a PdfTemplate. + /// + /// the PdfTemplate + public ImgTemplate(PdfTemplate template) : base((Uri)null) { + if (template == null) + throw new BadElementException("The template can not be null."); + if (template.Type == PdfTemplate.TYPE_PATTERN) + throw new BadElementException("A pattern can not be used as a template to create an image."); + type = Element.IMGTEMPLATE; + scaledHeight = template.Height; + this.Top = scaledHeight; + scaledWidth = template.Width; + this.Right = scaledWidth; + TemplateData = template; + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgWMF.cs b/iTechSharp/iTextSharp/text/ImgWMF.cs new file mode 100644 index 0000000..6199fa0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgWMF.cs @@ -0,0 +1,176 @@ +using System; +using System.IO; +using System.Net; + +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.codec.wmf; + +/* + * $Id: ImgWMF.cs,v 1.7 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /** + * An ImgWMF is the representation of a windows metafile + * that has to be inserted into the document + * + * @see Element + * @see Image + * @see Gif + * @see Png + */ + /// + /// An ImgWMF is the representation of a windows metafile + /// that has to be inserted into the document + /// + public class ImgWMF : Image { + + // Constructors + /// + /// Constructs an ImgWMF-object + /// + /// a Image + public ImgWMF(Image image) : base(image) {} + + /// + /// Constructs an ImgWMF-object, using an url. + /// + /// the URL where the image can be found + public ImgWMF(Uri url) : base(url) { + ProcessParameters(); + } + + /// + /// Constructs an ImgWMF-object, using a filename. + /// + /// a string-representation of the file that contains the image. + public ImgWMF(string filename) : this(Utilities.ToURL(filename)) {} + + /// + /// Constructs an ImgWMF-object from memory. + /// + /// the memory image + public ImgWMF(byte[] img) : base((Uri)null) { + rawData = img; + originalData = img; + ProcessParameters(); + } + + /// + /// This method checks if the image is a valid WMF and processes some parameters. + /// + private void ProcessParameters() { + type = Element.IMGTEMPLATE; + originalType = ORIGINAL_WMF; + Stream istr = null; + try { + string errorID; + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + errorID = url.ToString(); + } + else{ + istr = new MemoryStream(rawData); + errorID = "Byte array"; + } + InputMeta im = new InputMeta(istr); + if (im.ReadInt() != unchecked((int)0x9AC6CDD7)) { + throw new BadElementException(errorID + " is not a valid placeable windows metafile."); + } + im.ReadWord(); + int left = im.ReadShort(); + int top = im.ReadShort(); + int right = im.ReadShort(); + int bottom = im.ReadShort(); + int inch = im.ReadWord(); + dpiX = 72; + dpiY = 72; + scaledHeight = (float)(bottom - top) / inch * 72f; + this.Top =scaledHeight; + scaledWidth = (float)(right - left) / inch * 72f; + this.Right = scaledWidth; + } + finally { + if (istr != null) { + istr.Close(); + } + plainWidth = this.Width; + plainHeight = this.Height; + } + } + + /// + /// Reads the WMF into a template. + /// + /// the template to read to + public void ReadWMF(PdfTemplate template) { + TemplateData = template; + template.Width = this.Width; + template.Height = this.Height; + Stream istr = null; + try { + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + } + else{ + istr = new MemoryStream(rawData); + } + MetaDo meta = new MetaDo(istr, template); + meta.ReadAll(); + } + finally { + if (istr != null) { + istr.Close(); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Jpeg.cs b/iTechSharp/iTextSharp/text/Jpeg.cs new file mode 100644 index 0000000..f0f524d --- /dev/null +++ b/iTechSharp/iTextSharp/text/Jpeg.cs @@ -0,0 +1,335 @@ +using System; +using System.IO; +using System.Net; +using System.util; +using iTextSharp.text.pdf; + +/* + * $Id: Jpeg.cs,v 1.11 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// An Jpeg is the representation of a graphic element (JPEG) + /// that has to be inserted into the document + /// + /// + /// + /// + /// + public class Jpeg : Image { + + // public static membervariables + + /// This is a type of marker. + public const int NOT_A_MARKER = -1; + + /// This is a type of marker. + public const int VALID_MARKER = 0; + + /// Acceptable Jpeg markers. + public static int[] VALID_MARKERS = {0xC0, 0xC1, 0xC2}; + + /// This is a type of marker. + public const int UNSUPPORTED_MARKER = 1; + + /// Unsupported Jpeg markers. + public static int[] UNSUPPORTED_MARKERS = {0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF}; + + /// This is a type of marker. + public const int NOPARAM_MARKER = 2; + + /// Jpeg markers without additional parameters. + public static int[] NOPARAM_MARKERS = {0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01}; + + public const int M_APP0 = 0xE0; + public const int M_APP2 = 0xE2; + public const int M_APPE = 0xEE; + + public static byte[] JFIF_ID = {0x4A, 0x46, 0x49, 0x46, 0x00}; + + private byte[][] icc; + + // Constructors + + /// + /// Construct a Jpeg-object, using a Image + /// + /// a Image + public Jpeg(Image image) : base(image) {} + + /// + /// Constructs a Jpeg-object, using an Uri. + /// + /// + /// Deprecated, use Image.GetInstance(...) to create an Image + /// + /// the Uri where the image can be found + public Jpeg(Uri Uri) : base(Uri) { + ProcessParameters(); + } + + /// + /// Constructs a Jpeg-object from memory. + /// + /// the memory image + public Jpeg(byte[] img) : base((Uri)null) { + rawData = img; + originalData = img; + ProcessParameters(); + } + + /// + /// Constructs a Jpeg-object from memory. + /// + /// the memory image. + /// the width you want the image to have + /// the height you want the image to have + public Jpeg(byte[] img, float width, float height) : this(img) { + scaledWidth = width; + scaledHeight = height; + } + + // private static methods + + /// + /// Reads a short from the Stream. + /// + /// the Stream + /// an int + private static int GetShort(Stream istr) { + return (istr.ReadByte() << 8) + istr.ReadByte(); + } + + /// + /// Reads an inverted short from the Stream. + /// + /// the Stream + /// an int + private static int GetShortInverted(Stream istr) { + return (istr.ReadByte() + istr.ReadByte() << 8); + } + + /// + /// Returns a type of marker. + /// + /// an int + /// a type: VALID_MARKER, UNSUPPORTED_MARKER or NOPARAM_MARKER + private static int MarkerType(int marker) { + for (int i = 0; i < VALID_MARKERS.Length; i++) { + if (marker == VALID_MARKERS[i]) { + return VALID_MARKER; + } + } + for (int i = 0; i < NOPARAM_MARKERS.Length; i++) { + if (marker == NOPARAM_MARKERS[i]) { + return NOPARAM_MARKER; + } + } + for (int i = 0; i < UNSUPPORTED_MARKERS.Length; i++) { + if (marker == UNSUPPORTED_MARKERS[i]) { + return UNSUPPORTED_MARKER; + } + } + return NOT_A_MARKER; + } + + // private methods + + /// + /// This method checks if the image is a valid JPEG and processes some parameters. + /// + private void ProcessParameters() { + type = Element.JPEG; + originalType = ORIGINAL_JPEG; + Stream istr = null; + try { + string errorID; + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + errorID = url.ToString(); + } + else{ + istr = new MemoryStream(rawData); + errorID = "Byte array"; + } + if (istr.ReadByte() != 0xFF || istr.ReadByte() != 0xD8) { + throw new BadElementException(errorID + " is not a valid JPEG-file."); + } + bool firstPass = true; + int len; + while (true) { + int v = istr.ReadByte(); + if (v < 0) + throw new IOException("Premature EOF while reading JPG."); + if (v == 0xFF) { + int marker = istr.ReadByte(); + if (firstPass && marker == M_APP0) { + firstPass = false; + len = GetShort(istr); + if (len < 16) { + Utilities.Skip(istr, len - 2); + continue; + } + byte[] bcomp = new byte[JFIF_ID.Length]; + int r = istr.Read(bcomp, 0, bcomp.Length); + if (r != bcomp.Length) + throw new BadElementException(errorID + " corrupted JFIF marker."); + bool found = true; + for (int k = 0; k < bcomp.Length; ++k) { + if (bcomp[k] != JFIF_ID[k]) { + found = false; + break; + } + } + if (!found) { + Utilities.Skip(istr, len - 2 - bcomp.Length); + continue; + } + Utilities.Skip(istr, 2); + int units = istr.ReadByte(); + int dx = GetShort(istr); + int dy = GetShort(istr); + if (units == 1) { + dpiX = dx; + dpiY = dy; + } + else if (units == 2) { + dpiX = (int)((float)dx * 2.54f + 0.5f); + dpiY = (int)((float)dy * 2.54f + 0.5f); + } + Utilities.Skip(istr, len - 2 - bcomp.Length - 7); + continue; + } + if (marker == M_APPE) { + len = GetShort(istr) - 2; + byte[] byteappe = new byte[len]; + for (int k = 0; k < len; ++k) { + byteappe[k] = (byte)istr.ReadByte(); + } + if (byteappe.Length >= 12) { + string appe = System.Text.ASCIIEncoding.ASCII.GetString(byteappe,0,5); + if (Util.EqualsIgnoreCase(appe, "adobe")) { + invert = true; + } + } + continue; + } + if (marker == M_APP2) { + len = GetShort(istr) - 2; + byte[] byteapp2 = new byte[len]; + for (int k = 0; k < len; ++k) { + byteapp2[k] = (byte)istr.ReadByte(); + } + if (byteapp2.Length >= 14) { + String app2 = System.Text.ASCIIEncoding.ASCII.GetString(byteapp2, 0, 11); + if (app2.Equals("ICC_PROFILE")) { + int order = byteapp2[12] & 0xff; + int count = byteapp2[13] & 0xff; + if (icc == null) + icc = new byte[count][]; + icc[order - 1] = byteapp2; + } + } + continue; + } + firstPass = false; + int markertype = MarkerType(marker); + if (markertype == VALID_MARKER) { + Utilities.Skip(istr, 2); + if (istr.ReadByte() != 0x08) { + throw new BadElementException(errorID + " must have 8 bits per component."); + } + scaledHeight = GetShort(istr); + Top = scaledHeight; + scaledWidth = GetShort(istr); + Right = scaledWidth; + colorspace = istr.ReadByte(); + bpc = 8; + break; + } + else if (markertype == UNSUPPORTED_MARKER) { + throw new BadElementException(errorID + ": unsupported JPEG marker: " + marker); + } + else if (markertype != NOPARAM_MARKER) { + Utilities.Skip(istr, GetShort(istr) - 2); + } + } + } + } + finally { + if (istr != null) { + istr.Close(); + } + } + plainWidth = this.Width; + plainHeight = this.Height; + if (icc != null) { + int total = 0; + for (int k = 0; k < icc.Length; ++k) { + if (icc[k] == null) { + icc = null; + return; + } + total += icc[k].Length - 14; + } + byte[] ficc = new byte[total]; + total = 0; + for (int k = 0; k < icc.Length; ++k) { + System.Array.Copy(icc[k], 14, ficc, total, icc[k].Length - 14); + total += icc[k].Length - 14; + } + ICC_Profile icc_prof = ICC_Profile.GetInstance(ficc); + TagICC = icc_prof; + icc = null; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Jpeg2000.cs b/iTechSharp/iTextSharp/text/Jpeg2000.cs new file mode 100644 index 0000000..029f9e4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Jpeg2000.cs @@ -0,0 +1,239 @@ +using System; +using System.IO; +using System.Net; +using System.util; +using iTextSharp.text.pdf; +/* + * $Id: Jpeg2000.cs,v 1.5 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * An Jpeg2000 is the representation of a graphic element (JPEG) + * that has to be inserted into the document + * + * @see Element + * @see Image + */ + + public class Jpeg2000 : Image { + + // public static final membervariables + + public const int JP2_JP = 0x6a502020; + public const int JP2_IHDR = 0x69686472; + public const int JPIP_JPIP = 0x6a706970; + + public const int JP2_FTYP = 0x66747970; + public const int JP2_JP2H = 0x6a703268; + public const int JP2_COLR = 0x636f6c72; + public const int JP2_JP2C = 0x6a703263; + public const int JP2_URL = 0x75726c20; + public const int JP2_DBTL = 0x6474626c; + public const int JP2_BPCC = 0x62706363; + public const int JP2_JP2 = 0x6a703220; + + private Stream inp; + private int boxLength; + private int boxType; + + // Constructors + + public Jpeg2000(Image image) : base(image) { + } + + /** + * Constructs a Jpeg2000-object, using an url. + * + * @param url the URL where the image can be found + * @throws BadElementException + * @throws IOException + */ + public Jpeg2000(Uri url) : base(url) { + ProcessParameters(); + } + + /** + * Constructs a Jpeg2000-object from memory. + * + * @param img the memory image + * @throws BadElementException + * @throws IOException + */ + + public Jpeg2000(byte[] img) : base((Uri)null) { + rawData = img; + originalData = img; + ProcessParameters(); + } + + /** + * Constructs a Jpeg2000-object from memory. + * + * @param img the memory image. + * @param width the width you want the image to have + * @param height the height you want the image to have + * @throws BadElementException + * @throws IOException + */ + + public Jpeg2000(byte[] img, float width, float height) : this(img) { + scaledWidth = width; + scaledHeight = height; + } + + private int Cio_read(int n) { + int v = 0; + for (int i = n - 1; i >= 0; i--) { + v += inp.ReadByte() << (i << 3); + } + return v; + } + + public void Jp2_read_boxhdr() { + boxLength = Cio_read(4); + boxType = Cio_read(4); + if (boxLength == 1) { + if (Cio_read(4) != 0) { + throw new IOException("Cannot handle box sizes higher than 2^32"); + } + boxLength = Cio_read(4); + if (boxLength == 0) + throw new IOException("Unsupported box size == 0"); + } + else if (boxLength == 0) { + throw new IOException("Unsupported box size == 0"); + } + } + + /** + * This method checks if the image is a valid JPEG and processes some parameters. + * @throws BadElementException + * @throws IOException + */ + private void ProcessParameters() { + type = JPEG2000; + originalType = ORIGINAL_JPEG2000; + inp = null; + try { + string errorID; + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + inp = w.GetResponse().GetResponseStream(); + errorID = url.ToString(); + } + else{ + inp = new MemoryStream(rawData); + errorID = "Byte array"; + } + boxLength = Cio_read(4); + if (boxLength == 0x0000000c) { + boxType = Cio_read(4); + if (JP2_JP != boxType) { + throw new IOException("Expected JP Marker"); + } + if (0x0d0a870a != Cio_read(4)) { + throw new IOException("Error with JP Marker"); + } + + Jp2_read_boxhdr(); + if (JP2_FTYP != boxType) { + throw new IOException("Expected FTYP Marker"); + } + Utilities.Skip(inp, boxLength - 8); + Jp2_read_boxhdr(); + do { + if (JP2_JP2H != boxType) { + if (boxType == JP2_JP2C) { + throw new IOException("Expected JP2H Marker"); + } + Utilities.Skip(inp, boxLength - 8); + Jp2_read_boxhdr(); + } + } while (JP2_JP2H != boxType); + Jp2_read_boxhdr(); + if (JP2_IHDR != boxType) { + throw new IOException("Expected IHDR Marker"); + } + scaledHeight = Cio_read(4); + Top = scaledHeight; + scaledWidth = Cio_read(4); + Right = scaledWidth; + bpc = -1; + } + else if ((uint)boxLength == 0xff4fff51) { + Utilities.Skip(inp, 4); + int x1 = Cio_read(4); + int y1 = Cio_read(4); + int x0 = Cio_read(4); + int y0 = Cio_read(4); + Utilities.Skip(inp, 16); + colorspace = Cio_read(2); + bpc = 8; + scaledHeight = y1 - y0; + Top = scaledHeight; + scaledWidth = x1 - x0; + Right = scaledWidth; + } + else { + throw new IOException("Not a valid Jpeg2000 file"); + } + } + finally { + if (inp != null) { + try{inp.Close();}catch{} + inp = null; + } + } + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/List.cs b/iTechSharp/iTextSharp/text/List.cs new file mode 100644 index 0000000..192cee2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/List.cs @@ -0,0 +1,555 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: List.cs,v 1.20 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A List contains several ListItems. + /// + /// + /// Example 1: + /// + /// List list = new List(true, 20); + /// list.Add(new ListItem("First line")); + /// list.Add(new ListItem("The second line is longer to see what happens once the end of the line is reached. Will it start on a new line?")); + /// list.Add(new ListItem("Third line")); + /// + /// + /// The result of this code looks like this: + ///
    + ///
  1. + /// First line + ///
  2. + ///
  3. + /// The second line is longer to see what happens once the end of the line is reached. Will it start on a new line? + ///
  4. + ///
  5. + /// Third line + ///
  6. + ///
+ /// + /// Example 2: + /// + /// List overview = new List(false, 10); + /// overview.Add(new ListItem("This is an item")); + /// overview.Add("This is another item"); + /// + /// + /// The result of this code looks like this: + ///
    + ///
  • + /// This is an item + ///
  • + ///
  • + /// This is another item + ///
  • + ///
+ ///
+ /// + /// + public class List : ITextElementArray { + + // membervariables + /** a possible value for the numbered parameter */ + public const bool ORDERED = true; + /** a possible value for the numbered parameter */ + public const bool UNORDERED = false; + /** a possible value for the lettered parameter */ + public const bool NUMERICAL = false; + /** a possible value for the lettered parameter */ + public const bool ALPHABETICAL = true; + /** a possible value for the lettered parameter */ + public const bool UPPERCASE = false; + /** a possible value for the lettered parameter */ + public const bool LOWERCASE = true; + + /// This is the ArrayList containing the different ListItems. + protected ArrayList list = new ArrayList(); + + /** Indicates if the list has to be numbered. */ + protected bool numbered = false; + /** Indicates if the listsymbols are numerical or alphabetical. */ + protected bool lettered = false; + /** Indicates if the listsymbols are lowercase or uppercase. */ + protected bool lowercase = false; + /** Indicates if the indentation has to be set automatically. */ + protected bool autoindent = false; + /** Indicates if the indentation of all the items has to be aligned. */ + protected bool alignindent = false; + + /// This variable indicates the first number of a numbered list. + protected int first = 1; + + /// This is the listsymbol of a list that is not numbered. + protected Chunk symbol = new Chunk("-"); + /** + * In case you are using numbered/lettered lists, this String is added before the number/letter. + * @since iText 2.1.1 + */ + protected String preSymbol = ""; + /** + * In case you are using numbered/lettered lists, this String is added after the number/letter. + * @since iText 2.1.1 + */ + protected String postSymbol = ". "; + + /// The indentation of this list on the left side. + protected float indentationLeft = 0; + + /// The indentation of this list on the right side. + protected float indentationRight = 0; + + /// The indentation of the listitems. + protected float symbolIndent = 0; + + // constructors + + /** + * Constructs a List. + */ + public List() : this(false, false) { + } + + /** + * Constructs a List with a specific symbol indentation. + * @param symbolIndent the symbol indentation + * @since iText 2.0.8 + */ + public List(float symbolIndent) { + this.symbolIndent = symbolIndent; + } + + /** + * Constructs a List. + * + * @param numbered a bool + */ + public List(bool numbered) : this(numbered, false) { + } + + /** + * Constructs a List. + * + * @param numbered a bool + * @param lettered has the list to be 'numbered' with letters + */ + public List(bool numbered, bool lettered) { + this.numbered = numbered; + this.lettered = lettered; + this.autoindent = true; + this.alignindent = true; + } + + + /// + /// Constructs a List. + /// + /// + /// the parameter symbolIndent is important for instance when + /// generating PDF-documents; it indicates the indentation of the listsymbol. + /// + /// a bool + /// the indentation that has to be used for the listsymbol + public List(bool numbered, float symbolIndent) : this(numbered, false, symbolIndent) { + } + + /// + /// Constructs a List. + /// + /// a bool + /// a bool + /// the indentation that has to be used for the listsymbol + public List(bool numbered, bool lettered, float symbolIndent ) { + this.numbered = numbered; + this.lettered = lettered; + this.symbolIndent = symbolIndent; + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + foreach (IElement ele in list) { + listener.Add(ele); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return Element.LIST; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in list) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + // methods to set the membervariables + + /// + /// Adds an Object to the List. + /// + /// the object to add + /// true is successful + public virtual bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + if (numbered || lettered) { + Chunk chunk = new Chunk(preSymbol, symbol.Font); + int index = first + list.Count; + if (lettered) + chunk.Append(RomanAlphabetFactory.GetString(index, lowercase)); + else + chunk.Append(index.ToString()); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + } + else { + item.ListSymbol = symbol; + } + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } + else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } + else if (o is string) { + return this.Add(new ListItem((string) o)); + } + return false; + } + + // extra methods + + /** Makes sure all the items in the list have the same indentation. */ + public void NormalizeIndentation() { + float max = 0; + foreach (IElement o in list) { + if (o is ListItem) { + max = Math.Max(max, ((ListItem)o).IndentationLeft); + } + } + foreach (IElement o in list) { + if (o is ListItem) { + ((ListItem)o).IndentationLeft = max; + } + } + } + + //setters/getters + + public bool Numbered { + set { + numbered = value; + } + get { + return numbered; + } + } + + public bool Lettered { + set { + lettered = value; + } + get { + return lettered; + } + } + + public bool Lowercase { + set { + lowercase = value; + } + get { + return lowercase; + } + } + + public bool Autoindent { + set { + autoindent = value; + } + get { + return autoindent; + } + } + + public bool Alignindent { + set { + alignindent = value; + } + get { + return alignindent; + } + } + + /// + /// Get/set the first number + /// + /// an int + public int First { + get { + return first; + } + + set { + this.first = value; + } + } + + /// + /// Sets the symbol + /// + /// a Chunk + public Chunk ListSymbol { + set { + this.symbol = value; + } + } + + /// + /// Sets the listsymbol. + /// + /// + /// This is a shortcut for SetListSymbol(Chunk symbol). + /// + /// a string + public void SetListSymbol(string symbol) { + this.symbol = new Chunk(symbol); + } + + /// + /// Get/set the indentation of this paragraph on the left side. + /// + /// the indentation + public float IndentationLeft { + get { + return indentationLeft; + } + + set { + this.indentationLeft = value; + } + } + + /// + /// Get/set the indentation of this paragraph on the right side. + /// + /// the indentation + public float IndentationRight { + get { + return indentationRight; + } + + set { + this.indentationRight = value; + } + } + + /// + /// Gets the symbol indentation. + /// + /// the symbol indentation + public float SymbolIndent { + set { + symbolIndent = value; + } + get { + return symbolIndent; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + // methods to retrieve information + + /// + /// Gets all the items in the list. + /// + /// an ArrayList containing ListItems + public ArrayList Items { + get { + return list; + } + } + + /// + /// Gets the size of the list. + /// + /// a size + public int Size { + get { + return list.Count; + } + } + + /** + * Returns true if the list is empty. + * + * @return true if the list is empty + */ + public virtual bool IsEmpty() { + return list.Count == 0; + } + + /// + /// Gets the leading of the first listitem. + /// + /// a leading + public float TotalLeading { + get { + if (list.Count < 1) { + return -1; + } + ListItem item = (ListItem)list[0]; + return item.TotalLeading; + } + } + + /// + /// Get/set the symbol indentation. + /// + /// a Chunk + public Chunk Symbol { + get { + return symbol; + } + set { + this.symbol = value; + } + } + + /** + * Returns the String that is after a number or letter in the list symbol. + * @return the String that is after a number or letter in the list symbol + * @since iText 2.1.1 + */ + public String getPostSymbol() { + return postSymbol; + } + + /** + * Sets the String that has to be added after a number or letter in the list symbol. + * @since iText 2.1.1 + * @param postSymbol the String that has to be added after a number or letter in the list symbol. + */ + public String PostSymbol { + set { + postSymbol = value; + } + get { + return postSymbol; + } + } + + /** + * Sets the String that has to be added before a number or letter in the list symbol. + * @since iText 2.1.1 + * @param preSymbol the String that has to be added before a number or letter in the list symbol. + */ + public String PreSymbol { + set { + preSymbol = value; + } + get { + return preSymbol; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/ListItem.cs b/iTechSharp/iTextSharp/text/ListItem.cs new file mode 100644 index 0000000..6df1365 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ListItem.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; +/* + * $Id: ListItem.cs,v 1.11 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A ListItem is a Paragraph + /// that can be added to a List. + /// + /// + /// Example 1: + /// + /// List list = new List(true, 20); + /// list.Add(new ListItem("First line")); + /// list.Add(new ListItem("The second line is longer to see what happens once the end of the line is reached. Will it start on a new line?")); + /// list.Add(new ListItem("Third line")); + /// + /// + /// The result of this code looks like this: + ///
    + ///
  1. + /// First line + ///
  2. + ///
  3. + /// The second line is longer to see what happens once the end of the line is reached. Will it start on a new line? + ///
  4. + ///
  5. + /// Third line + ///
  6. + ///
+ /// + /// Example 2: + /// + /// List overview = new List(false, 10); + /// overview.Add(new ListItem("This is an item")); + /// overview.Add("This is another item"); + /// + /// + /// The result of this code looks like this: + ///
    + ///
  • + /// This is an item + ///
  • + ///
  • + /// This is another item + ///
  • + ///
+ ///
+ /// + /// + /// + public class ListItem : Paragraph { + + // membervariables + + /// this is the symbol that wil proceed the listitem. + private Chunk symbol; + + // constructors + + /// + /// Constructs a ListItem. + /// + public ListItem() : base() {} + + /// + /// Constructs a ListItem with a certain leading. + /// + /// the leading + public ListItem(float leading) : base(leading) {} + + /// + /// Constructs a ListItem with a certain Chunk. + /// + /// a Chunk + public ListItem(Chunk chunk) : base(chunk) {} + + /// + /// Constructs a ListItem with a certain string. + /// + /// a string + public ListItem(string str) : base(str) {} + + /// + /// Constructs a ListItem with a certain string + /// and a certain Font. + /// + /// a string + /// a string + public ListItem(string str, Font font) : base(str, font) {} + + /// + /// Constructs a ListItem with a certain Chunk + /// and a certain leading. + /// + /// the leading + /// a Chunk + public ListItem(float leading, Chunk chunk) : base(leading, chunk) {} + + /// + /// Constructs a ListItem with a certain string + /// and a certain leading. + /// + /// the leading + /// a string + public ListItem(float leading, string str) : base(leading, str) {} + + /** + * Constructs a ListItem with a certain leading, string + * and Font. + * + * @param leading the leading + * @param string a string + * @param font a Font + */ + /// + /// Constructs a ListItem with a certain leading, string + /// and Font. + /// + /// the leading + /// a string + /// a Font + public ListItem(float leading, string str, Font font) : base(leading, str, font) {} + + /// + /// Constructs a ListItem with a certain Phrase. + /// + /// a Phrase + public ListItem(Phrase phrase) : base(phrase) {} + + // implementation of the Element-methods + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.LISTITEM; + } + } + + // methods + + // methods to retrieve information + + /// + /// Get/set the listsymbol. + /// + /// a Chunk + public Chunk ListSymbol { + get { + return symbol; + } + + set { + if (this.symbol == null) { + this.symbol = value; + if (this.symbol.Font.IsStandardFont()) { + this.symbol.Font = font; + } + } + } + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public new static bool IsTag(string tag) { + return ElementTags.LISTITEM.Equals(tag); + } + + /** + * Sets the indentation of this paragraph on the left side. + * + * @param indentation the new indentation + */ + public void SetIndentationLeft(float indentation, bool autoindent) { + if (autoindent) { + IndentationLeft = ListSymbol.GetWidthPoint(); + } + else { + IndentationLeft = indentation; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/MarkedObject.cs b/iTechSharp/iTextSharp/text/MarkedObject.cs new file mode 100644 index 0000000..f4885bd --- /dev/null +++ b/iTechSharp/iTextSharp/text/MarkedObject.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections; +using System.util; +/* + * $Id: MarkedObject.cs,v 1.4 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Wrapper that allows to add properties to 'basic building block' objects. + * Before iText 1.5 every 'basic building block' implemented the MarkupAttributes interface. + * By setting attributes, you could add markup to the corresponding XML and/or HTML tag. + * This functionality was hardly used by anyone, so it was removed, and replaced by + * the MarkedObject functionality. + */ + + public class MarkedObject : IElement { + + /** The element that is wrapped in a MarkedObject. */ + protected internal IElement element; + + /** Contains extra markupAttributes */ + protected internal Properties markupAttributes = new Properties(); + + /** + * This constructor is for internal use only. + */ + protected MarkedObject() { + element = null; + } + + /** + * Creates a MarkedObject. + */ + public MarkedObject(IElement element) { + this.element = element; + } + + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + public virtual ArrayList Chunks { + get { + return element.Chunks; + } + } + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public virtual bool Process(IElementListener listener) { + try { + return listener.Add(element); + } + catch (DocumentException) { + return false; + } + } + + /** + * Gets the type of the text element. + * + * @return a type + */ + public virtual int Type { + get { + return Element.MARKED; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + /** + * @return the markupAttributes + */ + public virtual Properties MarkupAttributes { + get { + return markupAttributes; + } + } + + public virtual void SetMarkupAttribute(String key, String value) { + markupAttributes.Add(key, value); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/MarkedSection.cs b/iTechSharp/iTextSharp/text/MarkedSection.cs new file mode 100644 index 0000000..9acff78 --- /dev/null +++ b/iTechSharp/iTextSharp/text/MarkedSection.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +/* + * $Id: MarkedSection.cs,v 1.7 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Wrapper that allows to add properties to a Chapter/Section object. + * Before iText 1.5 every 'basic building block' implemented the MarkupAttributes interface. + * By setting attributes, you could add markup to the corresponding XML and/or HTML tag. + * This functionality was hardly used by anyone, so it was removed, and replaced by + * the MarkedObject functionality. + */ + + public class MarkedSection : MarkedObject { + + /** This is the title of this section. */ + protected MarkedObject title = null; + + /** + * Creates a MarkedObject with a Section or Chapter object. + * @param section the marked section + */ + public MarkedSection(Section section) : base() { + if (section.Title != null) { + title = new MarkedObject(section.Title); + section.Title = null; + } + this.element = section; + } + + /** + * Adds a Paragraph, List or Table + * to this Section. + * + * @param index index at which the specified element is to be inserted + * @param o an object of type Paragraph, List or Table= + * @throws ClassCastException if the object is not a Paragraph, List or Table + */ + + public void Add(int index, Object o) { + ((Section)element).Add(index, o); + } + + /** + * Adds a Paragraph, List, Table or another Section + * to this Section. + * + * @param o an object of type Paragraph, List, Table or another Section + * @return a bool + * @throws ClassCastException if the object is not a Paragraph, List, Table or Section + */ + + public bool Add(Object o) { + return ((Section)element).Add(o); + } + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public override bool Process(IElementListener listener) { + try { + foreach (IElement element in ((Section)this.element)) { + listener.Add(element); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /** + * Adds a collection of Elements + * to this Section. + * + * @param collection a collection of Paragraphs, Lists and/or Tables + * @return true if the action succeeded, false if not. + * @throws ClassCastException if one of the objects isn't a Paragraph, List, Table + */ + + public bool AddAll(ICollection collection) { + return ((Section)element).AddAll(collection); + } + + /** + * Creates a Section, adds it to this Section and returns it. + * + * @param indentation the indentation of the new section + * @param numberDepth the numberDepth of the section + * @return a new Section object + */ + + public MarkedSection AddSection(float indentation, int numberDepth) { + MarkedSection section = ((Section)element).AddMarkedSection(); + section.Indentation = indentation; + section.NumberDepth = numberDepth; + return section; + } + + /** + * Creates a Section, adds it to this Section and returns it. + * + * @param indentation the indentation of the new section + * @return a new Section object + */ + + public MarkedSection AddSection(float indentation) { + MarkedSection section = ((Section)element).AddMarkedSection(); + section.Indentation = indentation; + return section; + } + + /** + * Creates a Section, add it to this Section and returns it. + * + * @param numberDepth the numberDepth of the section + * @return a new Section object + */ + public MarkedSection AddSection(int numberDepth) { + MarkedSection section = ((Section)element).AddMarkedSection(); + section.NumberDepth = numberDepth; + return section; + } + + /** + * Creates a Section, adds it to this Section and returns it. + * + * @return a new Section object + */ + public MarkedSection AddSection() { + return ((Section)element).AddMarkedSection(); + } + + // public methods + + /** + * Sets the title of this section. + * + * @param title the new title + */ + public MarkedObject Title { + set { + if (value.element is Paragraph) + this.title = value; + } + get { + Paragraph result = Section.ConstructTitle((Paragraph)title.element, ((Section)element).numbers, ((Section)element).NumberDepth, ((Section)element).NumberStyle); + MarkedObject mo = new MarkedObject(result); + mo.markupAttributes = title.MarkupAttributes; + return mo; + } + } + + /** + * Sets the depth of the sectionnumbers that will be shown preceding the title. + *

+ * If the numberdepth is 0, the sections will not be numbered. If the numberdepth + * is 1, the section will be numbered with their own number. If the numberdepth is + * higher (for instance x > 1), the numbers of x - 1 parents will be shown. + * + * @param numberDepth the new numberDepth + */ + public int NumberDepth { + set { + ((Section)element).NumberDepth = value; + } + } + + /** + * Sets the indentation of this Section on the left side. + * + * @param indentation the indentation + */ + public float IndentationLeft { + set { + ((Section)element).IndentationLeft = value; + } + } + + /** + * Sets the indentation of this Section on the right side. + * + * @param indentation the indentation + */ + + public float IndentationRight { + set { + ((Section)element).IndentationRight = value; + } + } + + /** + * Sets the indentation of the content of this Section. + * + * @param indentation the indentation + */ + public float Indentation { + set { + ((Section)element).Indentation = value; + } + } + + /** Setter for property bookmarkOpen. + * @param bookmarkOpen false if the bookmark children are not + * visible. + */ + public bool BookmarkOpen { + set { + ((Section)element).BookmarkOpen = value; + } + } + + /** + * Setter for property triggerNewPage. + * @param triggerNewPage true if a new page has to be triggered. + */ + public bool TriggerNewPage { + set { + ((Section)element).TriggerNewPage = value; + } + } + + /** + * Sets the bookmark title. The bookmark title is the same as the section title but + * can be changed with this method. + * @param bookmarkTitle the bookmark title + */ + public String BookmarkTitle { + set { + ((Section)element).BookmarkTitle = value; + } + } + + /** + * Adds a new page to the section. + * @since 2.1.1 + */ + public void NewPage() { + ((Section)element).NewPage(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Meta.cs b/iTechSharp/iTextSharp/text/Meta.cs new file mode 100644 index 0000000..130bd75 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Meta.cs @@ -0,0 +1,234 @@ +using System; +using System.Text; +using System.Collections; +using System.util; + +/* + * $Id: Meta.cs,v 1.6 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + ///

+ /// This is an Element that contains + /// some meta information about the document. + /// + /// + /// An object of type Meta can not be constructed by the user. + /// Userdefined meta information should be placed in a Header-object. + /// Meta is reserved for: Subject, Keywords, Author, Title, Producer + /// and Creationdate information. + /// + /// + /// + public class Meta : IElement { + + // membervariables + + /// This is the type of Meta-information this object contains. + private int type; + + /// This is the content of the Meta-information. + private StringBuilder content; + + // constructors + + /// + /// Constructs a Meta. + /// + /// the type of meta-information + /// the content + public Meta(int type, string content) { + this.type = type; + this.content = new StringBuilder(content); + } + + /// + /// Constructs a Meta. + /// + /// the tagname of the meta-information + /// the content + public Meta(string tag, string content) { + this.type = Meta.GetType(tag); + this.content = new StringBuilder(content); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to a + /// IElementListener. + /// + /// the IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return type; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return false; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return false; + } + + // methods + + /// + /// appends some text to this Meta. + /// + /// a string + /// a StringBuilder + public StringBuilder Append(string str) { + return content.Append(str); + } + + // methods to retrieve information + + /// + /// Returns the content of the meta information. + /// + /// a string + public string Content { + get { + return content.ToString(); + } + } + + /// + /// Returns the name of the meta information. + /// + /// a string + public virtual string Name { + get { + switch (type) { + case Element.SUBJECT: + return ElementTags.SUBJECT; + case Element.KEYWORDS: + return ElementTags.KEYWORDS; + case Element.AUTHOR: + return ElementTags.AUTHOR; + case Element.TITLE: + return ElementTags.TITLE; + case Element.PRODUCER: + return ElementTags.PRODUCER; + case Element.CREATIONDATE: + return ElementTags.CREATIONDATE; + default: + return ElementTags.UNKNOWN; + } + } + } + + /// + /// Returns the name of the meta information. + /// + /// name to match + /// a string + public static int GetType(string tag) { + if (ElementTags.SUBJECT.Equals(tag)) { + return Element.SUBJECT; + } + if (ElementTags.KEYWORDS.Equals(tag)) { + return Element.KEYWORDS; + } + if (ElementTags.AUTHOR.Equals(tag)) { + return Element.AUTHOR; + } + if (ElementTags.TITLE.Equals(tag)) { + return Element.TITLE; + } + if (ElementTags.PRODUCER.Equals(tag)) { + return Element.PRODUCER; + } + if (ElementTags.CREATIONDATE.Equals(tag)) { + return Element.CREATIONDATE; + } + return Element.HEADER; + } + + + public override string ToString() { + return base.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/PageSize.cs b/iTechSharp/iTextSharp/text/PageSize.cs new file mode 100644 index 0000000..749287f --- /dev/null +++ b/iTechSharp/iTextSharp/text/PageSize.cs @@ -0,0 +1,244 @@ +using System; + +/* + * $Id: PageSize.cs,v 1.9 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// The PageSize-object contains a number of read only rectangles representing the most common paper sizes. + /// + /// + public class PageSize { + + // membervariables + + /** This is the letter format */ + public static readonly Rectangle LETTER = new RectangleReadOnly(612,792); + + /** This is the note format */ + public static readonly Rectangle NOTE = new RectangleReadOnly(540,720); + + /** This is the legal format */ + public static readonly Rectangle LEGAL = new RectangleReadOnly(612,1008); + + /** This is the tabloid format */ + public static readonly Rectangle TABLOID = new RectangleReadOnly(792,1224); + + /** This is the executive format */ + public static readonly Rectangle EXECUTIVE = new RectangleReadOnly(522,756); + + /** This is the postcard format */ + public static readonly Rectangle POSTCARD = new RectangleReadOnly(283,416); + + /** This is the a0 format */ + public static readonly Rectangle A0 = new RectangleReadOnly(2384,3370); + + /** This is the a1 format */ + public static readonly Rectangle A1 = new RectangleReadOnly(1684,2384); + + /** This is the a2 format */ + public static readonly Rectangle A2 = new RectangleReadOnly(1191,1684); + + /** This is the a3 format */ + public static readonly Rectangle A3 = new RectangleReadOnly(842,1191); + + /** This is the a4 format */ + public static readonly Rectangle A4 = new RectangleReadOnly(595,842); + + /** This is the a5 format */ + public static readonly Rectangle A5 = new RectangleReadOnly(420,595); + + /** This is the a6 format */ + public static readonly Rectangle A6 = new RectangleReadOnly(297,420); + + /** This is the a7 format */ + public static readonly Rectangle A7 = new RectangleReadOnly(210,297); + + /** This is the a8 format */ + public static readonly Rectangle A8 = new RectangleReadOnly(148,210); + + /** This is the a9 format */ + public static readonly Rectangle A9 = new RectangleReadOnly(105,148); + + /** This is the a10 format */ + public static readonly Rectangle A10 = new RectangleReadOnly(73,105); + + /** This is the b0 format */ + public static readonly Rectangle B0 = new RectangleReadOnly(2834,4008); + + /** This is the b1 format */ + public static readonly Rectangle B1 = new RectangleReadOnly(2004,2834); + + /** This is the b2 format */ + public static readonly Rectangle B2 = new RectangleReadOnly(1417,2004); + + /** This is the b3 format */ + public static readonly Rectangle B3 = new RectangleReadOnly(1000,1417); + + /** This is the b4 format */ + public static readonly Rectangle B4 = new RectangleReadOnly(708,1000); + + /** This is the b5 format */ + public static readonly Rectangle B5 = new RectangleReadOnly(498,708); + + /** This is the b6 format */ + public static readonly Rectangle B6 = new RectangleReadOnly(354,498); + + /** This is the b7 format */ + public static readonly Rectangle B7 = new RectangleReadOnly(249,354); + + /** This is the b8 format */ + public static readonly Rectangle B8 = new RectangleReadOnly(175,249); + + /** This is the b9 format */ + public static readonly Rectangle B9 = new RectangleReadOnly(124,175); + + /** This is the b10 format */ + public static readonly Rectangle B10 = new RectangleReadOnly(87,124); + + /** This is the archE format */ + public static readonly Rectangle ARCH_E = new RectangleReadOnly(2592,3456); + + /** This is the archD format */ + public static readonly Rectangle ARCH_D = new RectangleReadOnly(1728,2592); + + /** This is the archC format */ + public static readonly Rectangle ARCH_C = new RectangleReadOnly(1296,1728); + + /** This is the archB format */ + public static readonly Rectangle ARCH_B = new RectangleReadOnly(864,1296); + + /** This is the archA format */ + public static readonly Rectangle ARCH_A = new RectangleReadOnly(648,864); + + /** This is the American Foolscap format */ + public static readonly Rectangle FLSA = new RectangleReadOnly(612,936); + + /** This is the European Foolscap format */ + public static readonly Rectangle FLSE = new RectangleReadOnly(648,936); + + /** This is the halfletter format */ + public static readonly Rectangle HALFLETTER = new RectangleReadOnly(396,612); + + /** This is the 11x17 format */ + public static readonly Rectangle _11X17 = new RectangleReadOnly(792,1224); + + /** This is the ISO 7810 ID-1 format (85.60 x 53.98 mm or 3.370 x 2.125 inch) */ + public static readonly Rectangle ID_1 = new RectangleReadOnly(242.65f,153); + + /** This is the ISO 7810 ID-2 format (A7 rotated) */ + public static readonly Rectangle ID_2 = new RectangleReadOnly(297,210); + + /** This is the ISO 7810 ID-3 format (B7 rotated) */ + public static readonly Rectangle ID_3 = new RectangleReadOnly(354,249); + + /** This is the ledger format */ + public static readonly Rectangle LEDGER = new RectangleReadOnly(1224,792); + + /** This is the Crown Quarto format */ + public static readonly Rectangle CROWN_QUARTO = new RectangleReadOnly(535,697); + + /** This is the Large Crown Quarto format */ + public static readonly Rectangle LARGE_CROWN_QUARTO = new RectangleReadOnly(569,731); + + /** This is the Demy Quarto format. */ + public static readonly Rectangle DEMY_QUARTO = new RectangleReadOnly(620,782); + + /** This is the Royal Quarto format. */ + public static readonly Rectangle ROYAL_QUARTO = new RectangleReadOnly(671,884); + + /** This is the Crown Octavo format */ + public static readonly Rectangle CROWN_OCTAVO = new RectangleReadOnly(348,527); + + /** This is the Large Crown Octavo format */ + public static readonly Rectangle LARGE_CROWN_OCTAVO = new RectangleReadOnly(365,561); + + /** This is the Demy Octavo format */ + public static readonly Rectangle DEMY_OCTAVO = new RectangleReadOnly(391,612); + + /** This is the Royal Octavo format. */ + public static readonly Rectangle ROYAL_OCTAVO = new RectangleReadOnly(442,663); + + /** This is the small paperback format. */ + public static readonly Rectangle SMALL_PAPERBACK = new RectangleReadOnly(314,504); + + /** This is the Pengiun small paperback format. */ + public static readonly Rectangle PENGUIN_SMALL_PAPERBACK = new RectangleReadOnly(314,513); + + /** This is the Penguin large paparback format. */ + public static readonly Rectangle PENGUIN_LARGE_PAPERBACK = new RectangleReadOnly(365,561); + + /** + * This method returns a Rectangle based on a String. + * Possible values are the the names of a constant in this class + * (for instance "A4", "LETTER",...) or a value like "595 842" + */ + public static Rectangle GetRectangle(String name) { + name = name.Trim().ToUpper(System.Globalization.CultureInfo.InvariantCulture); + int pos = name.IndexOf(' '); + if (pos == -1) { + try { + return (Rectangle)typeof(PageSize).GetField(name).GetValue(null); + } catch (Exception) { + throw new ArgumentException("Can't find page size " + name); + } + } + else { + try { + String width = name.Substring(0, pos); + String height = name.Substring(pos + 1); + return new Rectangle(float.Parse(width, System.Globalization.NumberFormatInfo.InvariantInfo), float.Parse(height, System.Globalization.NumberFormatInfo.InvariantInfo)); + } catch(Exception e) { + throw new ArgumentException(name + " is not a valid page size format: " + e.Message); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Paragraph.cs b/iTechSharp/iTextSharp/text/Paragraph.cs new file mode 100644 index 0000000..77047f9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Paragraph.cs @@ -0,0 +1,408 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Paragraph.cs,v 1.13 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Paragraph is a series of Chunks and/or Phrases. + /// + /// + /// A Paragraph has the same qualities of a Phrase, but also + /// some additional layout-parameters: + ///
    + ///
  • the indentation + ///
  • the alignment of the text + ///
+ ///
+ /// + /// + /// Paragraph p = new Paragraph("This is a paragraph", + /// FontFactory.GetFont(FontFactory.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// + /// + /// + /// + /// + public class Paragraph : Phrase { + + // membervariables + + /// The alignment of the text. + protected int alignment = Element.ALIGN_UNDEFINED; + + /** The text leading that is multiplied by the biggest font size in the line. */ + protected float multipliedLeading = 0; + + /// The indentation of this paragraph on the left side. + protected float indentationLeft; + + /// The indentation of this paragraph on the right side. + protected float indentationRight; + + /** + * Holds value of property firstLineIndent. + */ + private float firstLineIndent = 0; + + /** The spacing before the paragraph. */ + protected float spacingBefore; + + /** The spacing after the paragraph. */ + protected float spacingAfter; + + + /** + * Holds value of property extraParagraphSpace. + */ + private float extraParagraphSpace = 0; + + /// Does the paragraph has to be kept together on 1 page. + protected bool keeptogether = false; + + // constructors + + /// + /// Constructs a Paragraph. + /// + public Paragraph() : base() {} + + /// + /// Constructs a Paragraph with a certain leading. + /// + /// the leading + public Paragraph(float leading) : base(leading) {} + + /// + /// Constructs a Paragraph with a certain Chunk. + /// + /// a Chunk + public Paragraph(Chunk chunk) : base(chunk) {} + + /// + /// Constructs a Paragraph with a certain Chunk + /// and a certain leading. + /// + /// the leading + /// a Chunk + public Paragraph(float leading, Chunk chunk) : base(leading, chunk) {} + + /// + /// Constructs a Paragraph with a certain string. + /// + /// a string + public Paragraph(string str) : base(str) {} + + /// + /// Constructs a Paragraph with a certain string + /// and a certain Font. + /// + /// a string + /// a Font + public Paragraph(string str, Font font) : base(str, font) {} + + /// + /// Constructs a Paragraph with a certain string + /// and a certain leading. + /// + /// the leading + /// a string + public Paragraph(float leading, string str) : base(leading, str) {} + + /// + /// Constructs a Paragraph with a certain leading, string + /// and Font. + /// + /// the leading + /// a string + /// a Font + public Paragraph(float leading, string str, Font font) : base(leading, str, font) {} + + /// + /// Constructs a Paragraph with a certain Phrase. + /// + /// a Phrase + public Paragraph(Phrase phrase) : base(phrase) { + if (phrase is Paragraph) { + Paragraph p = (Paragraph)phrase; + Alignment = p.Alignment; + ExtraParagraphSpace = p.ExtraParagraphSpace; + FirstLineIndent = p.FirstLineIndent; + IndentationLeft = p.IndentationLeft; + IndentationRight = p.IndentationRight; + SpacingAfter = p.SpacingAfter; + SpacingBefore = p.SpacingBefore; + } + } + + // implementation of the Element-methods + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.PARAGRAPH; + } + } + + // methods + + /// + /// Adds an Object to the Paragraph. + /// + /// the object to add + /// a bool + public override bool Add(Object o) { + if (o is List) { + List list = (List) o; + list.IndentationLeft = list.IndentationLeft + indentationLeft; + list.IndentationRight = indentationRight; + base.Add(list); + return true; + } + else if (o is Image) { + base.AddSpecial((Image) o); + return true; + } + else if (o is Paragraph) { + base.Add(o); + base.Add(Chunk.NEWLINE); + return true; + } + base.Add(o); + return true; + } + + // setting the membervariables + + /// + /// Sets the alignment of this paragraph. + /// + /// the new alignment as a string + public void SetAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_CENTER)) { + this.alignment = Element.ALIGN_CENTER; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.alignment = Element.ALIGN_RIGHT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED)) { + this.alignment = Element.ALIGN_JUSTIFIED; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED_ALL)) { + this.alignment = Element.ALIGN_JUSTIFIED_ALL; + return; + } + this.alignment = Element.ALIGN_LEFT; + } + + public override float Leading { + set { + this.leading = value; + this.multipliedLeading = 0; + } + } + + /** + * Sets the leading fixed and variable. The resultant leading will be + * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param fixedLeading the fixed leading + * @param multipliedLeading the variable leading + */ + public void SetLeading(float fixedLeading, float multipliedLeading) { + this.leading = fixedLeading; + this.multipliedLeading = multipliedLeading; + } + + /** + * Sets the variable leading. The resultant leading will be + * multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param multipliedLeading the variable leading + */ + public float MultipliedLeading { + get { + return this.multipliedLeading; + } + set { + this.leading = 0; + this.multipliedLeading = value; + } + } + + + /// + /// Get/set the alignment of this paragraph. + /// + /// a integer + public int Alignment{ + get { + return alignment; + } + set { + this.alignment = value; + } + } + + /// + /// Get/set the indentation of this paragraph on the left side. + /// + /// a float + public float IndentationLeft { + get { + return indentationLeft; + } + + set { + this.indentationLeft = value; + } + } + + /// + /// Get/set the indentation of this paragraph on the right side. + /// + /// a float + public float IndentationRight { + get { + return indentationRight; + } + + set { + this.indentationRight = value; + } + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public new static bool IsTag(string tag) { + return ElementTags.PARAGRAPH.Equals(tag); + } + + public float SpacingBefore { + get { + return spacingBefore; + } + set { + spacingBefore = value; + } + } + + public float SpacingAfter { + get { + return spacingAfter; + } + set { + spacingAfter = value; + } + } + + /// + /// Set/get if this paragraph has to be kept together on one page. + /// + /// a bool + public bool KeepTogether { + get { + return keeptogether; + } + set { + this.keeptogether = value; + } + } + + /** + * Gets the total leading. + * This method is based on the assumption that the + * font of the Paragraph is the font of all the elements + * that make part of the paragraph. This isn't necessarily + * true. + * @return the total leading (fixed and multiplied) + */ + public float TotalLeading { + get { + float m = font == null ? + Font.DEFAULTSIZE * multipliedLeading : font.GetCalculatedLeading(multipliedLeading); + if (m > 0 && !HasLeading()) { + return m; + } + return Leading + m; + } + } + + public float FirstLineIndent { + get { + return this.firstLineIndent; + } + set { + this.firstLineIndent = value; + } + } + + public float ExtraParagraphSpace { + get { + return this.extraParagraphSpace; + } + set { + this.extraParagraphSpace = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Phrase.cs b/iTechSharp/iTextSharp/text/Phrase.cs new file mode 100644 index 0000000..b4124e9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Phrase.cs @@ -0,0 +1,509 @@ +using System; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text.factories; + +namespace iTextSharp.text { + /// + /// A Phrase is a series of Chunks. + /// + /// + /// A Phrase has a main Font, but some chunks + /// within the phrase can have a Font that differs from the + /// main Font. All the Chunks in a Phrase + /// have the same leading. + /// + /// + /// + /// // When no parameters are passed, the default leading = 16 + /// Phrase phrase0 = new Phrase(); + /// Phrase phrase1 = new Phrase("this is a phrase"); + /// // In this example the leading is passed as a parameter + /// Phrase phrase2 = new Phrase(16, "this is a phrase with leading 16"); + /// // When a Font is passed (explicitely or embedded in a chunk), the default leading = 1.5 * size of the font + /// Phrase phrase3 = new Phrase("this is a phrase with a red, normal font Courier, size 12", FontFactory.GetFont(FontFactory.COURIER, 12, Font.NORMAL, new Color(255, 0, 0))); + /// Phrase phrase4 = new Phrase(new Chunk("this is a phrase")); + /// Phrase phrase5 = new Phrase(18, new Chunk("this is a phrase", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0))); + /// + /// + public class Phrase : ArrayList, ITextElementArray { + + // membervariables + + /// This is the leading of this phrase. + protected Single leading = Single.NaN; + + /// This is the font of this phrase. + protected Font font; + + /** Null, unless the Phrase has to be hyphenated. + * @since 2.1.2 + */ + protected IHyphenationEvent hyphenation = null; + + // constructors + + /// + /// Constructs a Phrase without specifying a leading. + /// + /// + /// Has nine overloads. + /// + public Phrase() : this(16) {} + + /** + * Copy constructor for Phrase. + */ + public Phrase(Phrase phrase) : base() { + this.AddAll(phrase); + leading = phrase.Leading; + font = phrase.Font; + hyphenation = phrase.hyphenation; + } + + /// + /// Constructs a Phrase with a certain leading. + /// + /// the leading + public Phrase(float leading) { + this.leading = leading; + font = new Font(); + } + + /// + /// Constructs a Phrase with a certain Chunk. + /// + /// a Chunk + public Phrase(Chunk chunk) { + base.Add(chunk); + font = chunk.Font; + hyphenation = chunk.GetHyphenation(); + } + + /// + /// Constructs a Phrase with a certain Chunk and a certain leading. + /// + /// the leading + /// a Chunk + public Phrase(float leading, Chunk chunk) { + this.leading = leading; + base.Add(chunk); + font = chunk.Font; + hyphenation = chunk.GetHyphenation(); + } + + /// + /// Constructs a Phrase with a certain string. + /// + /// a string + public Phrase(string str) : this(float.NaN, str, new Font()) {} + + /// + /// Constructs a Phrase with a certain string and a certain Font. + /// + /// a string + /// a Font + public Phrase(string str, Font font) : this(float.NaN, str, font) { + } + + /// + /// Constructs a Phrase with a certain leading and a certain string. + /// + /// the leading + /// a string + public Phrase(float leading, string str) : this(leading, str, new Font()) {} + + public Phrase(float leading, string str, Font font) { + this.leading = leading; + this.font = font; + /* bugfix by August Detlefsen */ + if (str != null && str.Length != 0) { + base.Add(new Chunk(str, font)); + } + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// . + /// + /// an IElementListener + /// true if the element was processed successfully + public virtual bool Process(IElementListener listener) { + try { + foreach (IElement ele in this) { + listener.Add(ele); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public virtual int Type { + get { + return Element.PHRASE; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public virtual ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in this) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + // overriding some of the ArrayList-methods + + /// + /// Adds a Chunk, an Anchor or another Phrase + /// to this Phrase. + /// + /// index at which the specified element is to be inserted + /// an object of type Chunk, Anchor, or Phrase + public virtual void Add(int index, Object o) { + if (o == null) return; + try { + IElement element = (IElement) o; + if (element.Type == Element.CHUNK) { + Chunk chunk = (Chunk)element; + if (!font.IsStandardFont()) { + chunk.Font = font.Difference(chunk.Font); + } + if (hyphenation != null) { + chunk.SetHyphenation(hyphenation); + } + base.Insert(index, chunk); + } + else if (element.Type == Element.PHRASE || + element.Type == Element.ANCHOR || + element.Type == Element.ANNOTATION || + element.Type == Element.TABLE || // line added by David Freels + element.Type == Element.YMARK || + element.Type == Element.MARKED) { + base.Insert(index, element); + } + else { + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a Chunk, Anchor or another Phrase + /// to this Phrase. + /// + /// an object of type Chunk, Anchor or Phrase + /// a bool + public virtual new bool Add(Object o) { + if (o == null) return false; + if (o is string) { + base.Add(new Chunk((string) o, font)); + return true; + } + if (o is IRtfElementInterface) { + base.Add(o); + return true; + } + try { + IElement element = (IElement) o; + switch (element.Type) { + case Element.CHUNK: + return AddChunk((Chunk) o); + case Element.PHRASE: + case Element.PARAGRAPH: + Phrase phrase = (Phrase) o; + bool success = true; + foreach (IElement e in phrase) { + if (e is Chunk) { + success &= AddChunk((Chunk)e); + } + else { + success &= this.Add(e); + } + } + return success; + case Element.MARKED: + case Element.ANCHOR: + case Element.ANNOTATION: + case Element.TABLE: // case added by David Freels + case Element.PTABLE: // case added by Karen Vardanyan + // This will only work for PDF!!! Not for RTF/HTML + case Element.LIST: + case Element.YMARK: + base.Add(o); + return true; + default: + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a collection of Chunks + /// to this Phrase. + /// + /// a collection of Chunks, Anchors and Phrases. + /// true if the action succeeded, false if not. + public bool AddAll(ICollection collection) { + foreach (object itm in collection) { + this.Add(itm); + } + return true; + } + + /// + /// Adds a Chunk. + /// + /// + /// This method is a hack to solve a problem I had with phrases that were split between chunks + /// in the wrong place. + /// + /// a Chunk + /// a bool + protected bool AddChunk(Chunk chunk) { + Font f = chunk.Font; + String c = chunk.Content; + if (font != null && !font.IsStandardFont()) { + f = font.Difference(chunk.Font); + } + if (Count > 0 && !chunk.HasAttributes()) { + try { + Chunk previous = (Chunk) this[Count - 1]; + if (!previous.HasAttributes() + && (f == null + || f.CompareTo(previous.Font) == 0) + && previous.Font.CompareTo(f) == 0 + && !"".Equals(previous.Content.Trim()) + && !"".Equals(c.Trim())) { + previous.Append(c); + return true; + } + } + catch { + } + } + Chunk newChunk = new Chunk(c, f); + newChunk.Attributes = chunk.Attributes; + if (newChunk.GetHyphenation() == null) { + newChunk.SetHyphenation(hyphenation); + } + base.Add(newChunk); + return true; + } + + /// + /// Adds a Object to the Paragraph. + /// + /// the object to add. + public void AddSpecial(Object obj) { + base.Add(obj); + } + + // methods + + // methods to retrieve information + + /// + /// Checks is this Phrase contains no or 1 empty Chunk. + /// + /// + /// false if the Phrase + /// contains more than one or more non-emptyChunks. + /// + public bool IsEmpty() { + switch (Count) { + case 0: + return true; + case 1: + IElement element = (IElement) this[0]; + if (element.Type == Element.CHUNK && ((Chunk) element).IsEmpty()) { + return true; + } + return false; + default: + return false; + } + } + + public bool HasLeading() { + if (float.IsNaN(leading)) { + return false; + } + return true; + } + + /// + /// Gets/sets the leading of this phrase. + /// + /// the linespacing + public virtual float Leading { + get { + if (float.IsNaN(leading) && font != null) { + return font.GetCalculatedLeading(1.5f); + } + return leading; + } + + set { + this.leading = value; + } + } + + /// + /// Gets the font of the first Chunk that appears in this Phrase. + /// + /// a Font + public Font Font { + get { + return font; + } + set { + font = value; + } + } + + /** + * Returns the content as a String object. + * This method differs from toString because toString will return an ArrayList with the toString value of the Chunks in this Phrase. + */ + public String Content { + get { + StringBuilder buf = new StringBuilder(); + foreach (object obj in Chunks) + buf.Append(obj.ToString()); + return buf.ToString(); + } + } + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.PHRASE.Equals(tag); + } + + public override string ToString() { + return base.ToString(); + } + + /** + * Setter/getter for the hyphenation. + * @param hyphenation a HyphenationEvent instance + * @since 2.1.2 + */ + public IHyphenationEvent Hyphenation { + set { + hyphenation = value; + } + get { + return hyphenation; + } + } + + + // kept for historical reasons; people should use FontSelector + // eligable for deprecation, but the methods are mentioned in the book p277. + + /** + * Constructs a Phrase that can be used in the static GetInstance() method. + * @param dummy a dummy parameter + */ + private Phrase(bool dummy) { + } + + /** + * Gets a special kind of Phrase that changes some characters into corresponding symbols. + * @param string + * @return a newly constructed Phrase + */ + public static Phrase GetInstance(String str) { + return GetInstance(16, str, new Font()); + } + + /** + * Gets a special kind of Phrase that changes some characters into corresponding symbols. + * @param leading + * @param string + * @return a newly constructed Phrase + */ + public static Phrase GetInstance(int leading, String str) { + return GetInstance(leading, str, new Font()); + } + + /** + * Gets a special kind of Phrase that changes some characters into corresponding symbols. + * @param leading + * @param string + * @param font + * @return a newly constructed Phrase + */ + public static Phrase GetInstance(int leading, String str, Font font) { + Phrase p = new Phrase(true); + p.Leading = leading; + p.font = font; + if (font.Family != Font.SYMBOL && font.Family != Font.ZAPFDINGBATS && font.BaseFont == null) { + int index; + while ((index = SpecialSymbol.Index(str)) > -1) { + if (index > 0) { + String firstPart = str.Substring(0, index); + ((ArrayList)p).Add(new Chunk(firstPart, font)); + str = str.Substring(index); + } + Font symbol = new Font(Font.SYMBOL, font.Size, font.Style, font.Color); + StringBuilder buf = new StringBuilder(); + buf.Append(SpecialSymbol.GetCorrespondingSymbol(str[0])); + str = str.Substring(1); + while (SpecialSymbol.Index(str) == 0) { + buf.Append(SpecialSymbol.GetCorrespondingSymbol(str[0])); + str = str.Substring(1); + } + ((ArrayList)p).Add(new Chunk(buf.ToString(), symbol)); + } + } + if (str != null && str.Length != 0) { + ((ArrayList)p).Add(new Chunk(str, font)); + } + return p; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Rectangle.cs b/iTechSharp/iTextSharp/text/Rectangle.cs new file mode 100644 index 0000000..2663eef --- /dev/null +++ b/iTechSharp/iTextSharp/text/Rectangle.cs @@ -0,0 +1,733 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.pdf; + +/* + * $Id: Rectangle.cs,v 1.18 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Rectangle is the representation of a geometric figure. + /// + /// + /// + /// + /// + public class Rectangle : Element, IElement { + + // static membervariables (concerning the presence of borders) + + /// This is the value that will be used as undefined. + public const int UNDEFINED = -1; + + /// This represents one side of the border of the Rectangle. + public const int TOP_BORDER = 1; + + /// This represents one side of the border of the Rectangle. + public const int BOTTOM_BORDER = 2; + + /// This represents one side of the border of the Rectangle. + public const int LEFT_BORDER = 4; + + /// This represents one side of the border of the Rectangle. + public const int RIGHT_BORDER = 8; + + /// This represents a rectangle without borders. + public const int NO_BORDER = 0; + + /// This represents a type of border. + public const int BOX = TOP_BORDER + BOTTOM_BORDER + LEFT_BORDER + RIGHT_BORDER; + + // membervariables + + /// the lower left x-coordinate. + protected float llx; + + /// the lower left y-coordinate. + protected float lly; + + /// the upper right x-coordinate. + protected float urx; + + /// the upper right y-coordinate. + protected float ury; + + /// This represents the status of the 4 sides of the rectangle. + protected int border = UNDEFINED; + + /// This is the width of the border around this rectangle. + protected float borderWidth = UNDEFINED; + + /// This is the color of the border of this rectangle. + protected Color borderColor = null; + + /** The color of the left border of this rectangle. */ + protected Color borderColorLeft = null; + + /** The color of the right border of this rectangle. */ + protected Color borderColorRight = null; + + /** The color of the top border of this rectangle. */ + protected Color borderColorTop = null; + + /** The color of the bottom border of this rectangle. */ + protected Color borderColorBottom = null; + + /** The width of the left border of this rectangle. */ + protected float borderWidthLeft = UNDEFINED; + + /** The width of the right border of this rectangle. */ + protected float borderWidthRight = UNDEFINED; + + /** The width of the top border of this rectangle. */ + protected float borderWidthTop = UNDEFINED; + + /** The width of the bottom border of this rectangle. */ + protected float borderWidthBottom = UNDEFINED; + + /** Whether variable width borders are used. */ + protected bool useVariableBorders = false; + + /// This is the color of the background of this rectangle. + protected Color backgroundColor = null; + + /// This is the rotation value of this rectangle. + protected int rotation = 0; + + // constructors + + /// + /// Constructs a Rectangle-object. + /// + /// lower left x + /// lower left y + /// upper right x + /// upper right y + public Rectangle(float llx, float lly, float urx, float ury) { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + /// + /// Constructs a Rectangle-object starting from the origin (0, 0). + /// + /// upper right x + /// upper right y + public Rectangle(float urx, float ury) : this(0, 0, urx, ury) {} + + /// + /// Constructs a Rectangle-object. + /// + /// another Rectangle + public Rectangle(Rectangle rect) : this(rect.llx, rect.lly, rect.urx, rect.ury) { + CloneNonPositionParameters(rect); + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + + public virtual void CloneNonPositionParameters(Rectangle rect) { + this.rotation = rect.rotation; + this.border = rect.border; + this.borderWidth = rect.borderWidth; + this.borderColor = rect.borderColor; + this.backgroundColor = rect.backgroundColor; + this.borderColorLeft = rect.borderColorLeft; + this.borderColorRight = rect.borderColorRight; + this.borderColorTop = rect.borderColorTop; + this.borderColorBottom = rect.borderColorBottom; + this.borderWidthLeft = rect.borderWidthLeft; + this.borderWidthRight = rect.borderWidthRight; + this.borderWidthTop = rect.borderWidthTop; + this.borderWidthBottom = rect.borderWidthBottom; + this.useVariableBorders = rect.useVariableBorders; + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + + public virtual void SoftCloneNonPositionParameters(Rectangle rect) { + if (rect.rotation != 0) + this.rotation = rect.rotation; + if (rect.border != UNDEFINED) + this.border = rect.border; + if (rect.borderWidth != UNDEFINED) + this.borderWidth = rect.borderWidth; + if (rect.borderColor != null) + this.borderColor = rect.borderColor; + if (rect.backgroundColor != null) + this.backgroundColor = rect.backgroundColor; + if (rect.borderColorLeft != null) + this.borderColorLeft = rect.borderColorLeft; + if (rect.borderColorRight != null) + this.borderColorRight = rect.borderColorRight; + if (rect.borderColorTop != null) + this.borderColorTop = rect.borderColorTop; + if (rect.borderColorBottom != null) + this.borderColorBottom = rect.borderColorBottom; + if (rect.borderWidthLeft != UNDEFINED) + this.borderWidthLeft = rect.borderWidthLeft; + if (rect.borderWidthRight != UNDEFINED) + this.borderWidthRight = rect.borderWidthRight; + if (rect.borderWidthTop != UNDEFINED) + this.borderWidthTop = rect.borderWidthTop; + if (rect.borderWidthBottom != UNDEFINED) + this.borderWidthBottom = rect.borderWidthBottom; + if (useVariableBorders) + this.useVariableBorders = rect.useVariableBorders; + } + + // implementation of the Element interface + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public virtual bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public virtual int Type { + get { + return Element.RECTANGLE; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public virtual ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public virtual bool IsNestable() { + return false; + } + + // methods + + /** + * Switches lowerleft with upperright + */ + public virtual void Normalize() { + if (llx > urx) { + float a = llx; + llx = urx; + urx = a; + } + if (lly > ury) { + float a = lly; + lly = ury; + ury = a; + } + } + + /// + /// Gets a Rectangle that is altered to fit on the page. + /// + /// the top position + /// the bottom position + /// a Rectangle + public Rectangle GetRectangle(float top, float bottom) { + Rectangle tmp = new Rectangle(this); + if (this.Top > top) { + tmp.Top = top; + tmp.Border = border - (border & TOP_BORDER); + } + if (Bottom < bottom) { + tmp.Bottom = bottom; + tmp.Border = border - (border & BOTTOM_BORDER); + } + return tmp; + } + + /// + /// Swaps the values of urx and ury and of lly and llx in order to rotate the rectangle. + /// + /// a Rectangle + public Rectangle Rotate() { + Rectangle rect = new Rectangle(lly, llx, ury, urx); + rect.rotation = rotation + 90; + rect.rotation %= 360; + return rect; + } + + // methods to set the membervariables + + /// + /// Get/set the upper right y-coordinate. + /// + /// a float + public virtual float Top { + get { + return ury; + } + + set { + ury = value; + } + } + + /** + * Enables the border on the specified side. + * + * @param side + * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public virtual void EnableBorderSide(int side) { + if (border == UNDEFINED) { + border = 0; + } + border |= side; + } + + /** + * Disables the border on the specified side. + * + * @param side + * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public virtual void DisableBorderSide(int side) { + if (border == UNDEFINED) { + border = 0; + } + border &= ~side; + } + + + /// + /// Get/set the border + /// + /// a int + public virtual int Border { + get { + return this.border; + } + + set { + border = value; + } + } + + /// + /// Get/set the grayscale of the rectangle. + /// + /// a float + public virtual float GrayFill { + get { + if (backgroundColor is GrayColor) + return ((GrayColor)backgroundColor).Gray; + else + return 0; + } + set { + backgroundColor = new GrayColor(value); } + } + + // methods to get the membervariables + + /// + /// Get/set the lower left x-coordinate. + /// + /// a float + public virtual float Left { + get { + return llx; + } + + set { + llx = value; + } + } + + /// + /// Get/set the upper right x-coordinate. + /// + /// a float + public virtual float Right { + get { + return urx; + } + + set { + urx = value; + } + } + + /// + /// Get/set the lower left y-coordinate. + /// + /// a float + public virtual float Bottom { + get { + return lly; + } + set { + lly = value; + } + } + + public virtual Color BorderColorBottom { + get { + if (borderColorBottom == null) return borderColor; + return borderColorBottom; + } + set { + borderColorBottom = value; + } + } + + public virtual Color BorderColorTop { + get { + if (borderColorTop == null) return borderColor; + return borderColorTop; + } + set { + borderColorTop = value; + } + } + + public virtual Color BorderColorLeft { + get { + if (borderColorLeft == null) return borderColor; + return borderColorLeft; + } + set { + borderColorLeft = value; + } + } + + public virtual Color BorderColorRight { + get { + if (borderColorRight == null) return borderColor; + return borderColorRight; + } + set { + borderColorRight = value; + } + } + + /// + /// Returns the lower left x-coordinate, considering a given margin. + /// + /// a margin + /// the lower left x-coordinate + public virtual float GetLeft(float margin) { + return llx + margin; + } + + /// + /// Returns the upper right x-coordinate, considering a given margin. + /// + /// a margin + /// the upper right x-coordinate + public virtual float GetRight(float margin) { + return urx - margin; + } + + /// + /// Returns the upper right y-coordinate, considering a given margin. + /// + /// a margin + /// the upper right y-coordinate + public virtual float GetTop(float margin) { + return ury - margin; + } + + /// + /// Returns the lower left y-coordinate, considering a given margin. + /// + /// a margin + /// the lower left y-coordinate + public virtual float GetBottom(float margin) { + return lly + margin; + } + + /// + /// Returns the width of the rectangle. + /// + /// a width + public virtual float Width { + get { + return urx - llx; + } + set { + throw new InvalidOperationException("The width cannot be set."); + } + } + + /// + /// Returns the height of the rectangle. + /// + /// a height + public float Height { + get { + return ury - lly; + } + } + + /// + /// Indicates if the table has borders. + /// + /// a bool + public bool HasBorders() { + return (border > 0) + && ((borderWidth > 0) || (borderWidthLeft > 0) + || (borderWidthRight > 0) || (borderWidthTop > 0) || (borderWidthBottom > 0)); + } + + /// + /// Indicates if the table has a some type of border. + /// + /// the type of border + /// a bool + public bool HasBorder(int type) { + return border != UNDEFINED && (border & type) == type; + } + + /// + /// Get/set the borderwidth. + /// + /// a float + public virtual float BorderWidth { + get { + return borderWidth; + } + + set { + borderWidth = value; + } + } + + /** + * Gets the color of the border. + * + * @return a value + */ + /// + /// Get/set the color of the border. + /// + /// a Color + public virtual Color BorderColor { + get { + return borderColor; + } + + set { + borderColor = value; + } + } + + /** + * Gets the backgroundcolor. + * + * @return a value + */ + /// + /// Get/set the backgroundcolor. + /// + /// a Color + public virtual Color BackgroundColor { + get { + return backgroundColor; + } + + set { + backgroundColor = value; + } + } + + /// + /// Returns the rotation + /// + /// a int + public int Rotation { + get { + return rotation; + } + } + + public virtual float BorderWidthLeft { + get { + return GetVariableBorderWidth(borderWidthLeft, LEFT_BORDER); + } + set { + borderWidthLeft = value; + UpdateBorderBasedOnWidth(value, LEFT_BORDER); + } + } + + public virtual float BorderWidthRight { + get { + return GetVariableBorderWidth(borderWidthRight, RIGHT_BORDER); + } + set { + borderWidthRight = value; + UpdateBorderBasedOnWidth(value, RIGHT_BORDER); + } + } + + public virtual float BorderWidthTop { + get { + return GetVariableBorderWidth(borderWidthTop, TOP_BORDER); + } + set { + borderWidthTop = value; + UpdateBorderBasedOnWidth(value, TOP_BORDER); + } + } + + public virtual float BorderWidthBottom { + get { + return GetVariableBorderWidth(borderWidthBottom, BOTTOM_BORDER); + } + set { + borderWidthBottom = value; + UpdateBorderBasedOnWidth(value, BOTTOM_BORDER); + } + } + + /** + * Updates the border flag for a side based on the specified width. A width + * of 0 will disable the border on that side. Any other width enables it. + * + * @param width + * width of border + * @param side + * border side constant + */ + + private void UpdateBorderBasedOnWidth(float width, int side) { + useVariableBorders = true; + if (width > 0) { + EnableBorderSide(side); + } else { + DisableBorderSide(side); + } + } + + private float GetVariableBorderWidth(float variableWidthValue, int side) { + if ((border & side) != 0) { + return variableWidthValue != UNDEFINED ? variableWidthValue + : borderWidth; + } else { + return 0; + } + } + + /** + * Sets a parameter indicating if the rectangle has variable borders + * + * @param useVariableBorders + * indication if the rectangle has variable borders + */ + public virtual bool UseVariableBorders{ + get { + return useVariableBorders; + } + set { + useVariableBorders = value; + } + } + + public override String ToString() { + StringBuilder buf = new StringBuilder("Rectangle: "); + buf.Append(Width); + buf.Append('x'); + buf.Append(Height); + buf.Append(" (rot: "); + buf.Append(rotation); + buf.Append(" degrees)"); + return buf.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/RectangleReadOnly.cs b/iTechSharp/iTextSharp/text/RectangleReadOnly.cs new file mode 100644 index 0000000..b1e532d --- /dev/null +++ b/iTechSharp/iTextSharp/text/RectangleReadOnly.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.pdf; + +/* + * $Id: RectangleReadOnly.cs,v 1.2 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A RectangleReadOnly is the representation of a geometric figure. + /// It's the same as a Rectangle but immutable. + /// + /// + /// + /// + /// + public class RectangleReadOnly : Rectangle { + + // constructors + + /// + /// Constructs a RectangleReadOnly-object. + /// + /// lower left x + /// lower left y + /// upper right x + /// upper right y + public RectangleReadOnly(float llx, float lly, float urx, float ury) : base(llx, lly, urx, ury) { + } + + /// + /// Constructs a RectangleReadOnly-object starting from the origin (0, 0). + /// + /// upper right x + /// upper right y + public RectangleReadOnly(float urx, float ury) : base(0, 0, urx, ury) {} + + /// + /// Constructs a RectangleReadOnly-object. + /// + /// another Rectangle + public RectangleReadOnly(Rectangle rect) : base(rect.Left, rect.Bottom, rect.Right, rect.Top) { + base.CloneNonPositionParameters(rect); + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + public override void CloneNonPositionParameters(Rectangle rect) { + ThrowReadOnlyError(); + } + + private void ThrowReadOnlyError() { + throw new InvalidOperationException("RectangleReadOnly: this Rectangle is read only."); + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + + public override void SoftCloneNonPositionParameters(Rectangle rect) { + ThrowReadOnlyError(); + } + + // methods + + /** + * Switches lowerleft with upperright + */ + public override void Normalize() { + ThrowReadOnlyError(); + } + + // methods to set the membervariables + + /// + /// Get/set the upper right y-coordinate. + /// + /// a float + public override float Top { + set { + ThrowReadOnlyError(); + } + } + + /** + * Enables the border on the specified side. + * + * @param side + * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public override void EnableBorderSide(int side) { + ThrowReadOnlyError(); + } + + /** + * Disables the border on the specified side. + * + * @param side + * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public override void DisableBorderSide(int side) { + ThrowReadOnlyError(); + } + + + /// + /// Get/set the border + /// + /// a int + public override int Border { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the grayscale of the rectangle. + /// + /// a float + public override float GrayFill { + set { + ThrowReadOnlyError(); + } + } + + // methods to get the membervariables + + /// + /// Get/set the lower left x-coordinate. + /// + /// a float + public override float Left { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the upper right x-coordinate. + /// + /// a float + public override float Right { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the lower left y-coordinate. + /// + /// a float + public override float Bottom { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorBottom { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorTop { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorLeft { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorRight { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the borderwidth. + /// + /// a float + public override float BorderWidth { + set { + ThrowReadOnlyError(); + } + } + + /** + * Gets the color of the border. + * + * @return a value + */ + /// + /// Get/set the color of the border. + /// + /// a Color + public override Color BorderColor { + set { + ThrowReadOnlyError(); + } + } + + /** + * Gets the backgroundcolor. + * + * @return a value + */ + /// + /// Get/set the backgroundcolor. + /// + /// a Color + public override Color BackgroundColor { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthLeft { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthRight { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthTop { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthBottom { + set { + ThrowReadOnlyError(); + } + } + + /** + * Sets a parameter indicating if the rectangle has variable borders + * + * @param useVariableBorders + * indication if the rectangle has variable borders + */ + public override bool UseVariableBorders{ + set { + ThrowReadOnlyError(); + } + } + + public override String ToString() { + StringBuilder buf = new StringBuilder("RectangleReadOnly: "); + buf.Append(Width); + buf.Append('x'); + buf.Append(Height); + buf.Append(" (rot: "); + buf.Append(rotation); + buf.Append(" degrees)"); + return buf.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/RomanList.cs b/iTechSharp/iTextSharp/text/RomanList.cs new file mode 100644 index 0000000..0cd1bdb --- /dev/null +++ b/iTechSharp/iTextSharp/text/RomanList.cs @@ -0,0 +1,116 @@ +using System; +using System.Text; +using iTextSharp.text.factories; + +/* + * Copyright 2003 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + +/** + * + * A special-version of LIST which use roman-letters. + * + * @see com.lowagie.text.List + * @version 2003-06-22 + * @author Michael Niedermair + */ + + public class RomanList : List { + + /** + * Initialization + */ + public RomanList() : base(true) { + } + + /** + * Initialization + * + * @param symbolIndent indent + */ + public RomanList(int symbolIndent) : base(true, symbolIndent){ + } + + /** + * Initialization + * @param romanlower roman-char in lowercase + * @param symbolIndent indent + */ + public RomanList(bool romanlower, int symbolIndent) : base(true, symbolIndent) { + this.lowercase = romanlower; + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + chunk.Append(RomanNumberFactory.GetString(first + list.Count, lowercase)); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is string) { + return this.Add(new ListItem((string) o)); + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Row.cs b/iTechSharp/iTextSharp/text/Row.cs new file mode 100644 index 0000000..256542c --- /dev/null +++ b/iTechSharp/iTextSharp/text/Row.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections; +using System.util; + +/* + * $Id: Row.cs,v 1.10 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Row is part of a Table + /// and contains some Cells. + /// + /// + /// All Rows are constructed by a Table-object. + /// You don't have to construct any Row yourself. + /// In fact you can't construct a Row outside the package. + ///

+ /// Since a Cell can span several rows and/or columns + /// a row can contain reserved space without any content. + /// + /// + /// + /// + public class Row : IElement { + + // membervariables + + ///

id of a null element in a Row + public static int NULL = 0; + + /// id of the Cell element in a Row + public static int CELL = 1; + + /// id of the Table element in a Row + public static int TABLE = 2; + + /// This is the number of columns in the Row. + protected int columns; + + /// This is a valid position the Row. + protected int currentColumn; + + /// This is the array that keeps track of reserved cells. + protected bool[] reserved; + + /// This is the array of Objects (Cell or Table). + protected Object[] cells; + + /// This is the horizontal alignment. + protected int horizontalAlignment; + + // constructors + + /// + /// Constructs a Row with a certain number of columns. + /// + /// a number of columns + internal Row(int columns) { + this.columns = columns; + reserved = new bool[columns]; + cells = new Object[columns]; + currentColumn = 0; + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to a + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return Element.ROW; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return false; + } + + /// + /// Deletes a certain column has been deleted. + /// + /// the number of the column to delete + internal void DeleteColumn(int column) { + if ((column >= columns) || (column < 0)) { + throw new Exception("getCell at illegal index : " + column); + } + columns--; + bool[] newReserved = new bool[columns]; + Object[] newCells = new Cell[columns]; + + for (int i = 0; i < column; i++) { + newReserved[i] = reserved[i]; + newCells[i] = cells[i]; + if (newCells[i] != null && (i + ((Cell) newCells[i]).Colspan > column)) { + ((Cell) newCells[i]).Colspan = ((Cell) cells[i]).Colspan - 1; + } + } + for (int i = column; i < columns; i++) { + newReserved[i] = reserved[i + 1]; + newCells[i] = cells[i + 1]; + } + if (cells[column] != null && ((Cell) cells[column]).Colspan > 1) { + newCells[column] = cells[column]; + ((Cell) newCells[column]).Colspan = ((Cell) newCells[column]).Colspan - 1; + } + reserved = newReserved; + cells = newCells; + } + + // methods + + /// + /// Adds a Cell to the Row. + /// + /// the element to add (currently only Cells and Tables supported) + /// + /// the column position the Cell was added, + /// or -1 if the element couldn't be added. + /// + internal int AddElement(Object element) { + return AddElement(element, currentColumn); + } + + /// + /// Adds an element to the Row at the position given. + /// + /// the element to add. (currently only Cells and Tables supported + /// the position where to add the cell + /// + /// the column position the Cell was added, + /// or -1 if the Cell couldn't be added. + /// + internal int AddElement(Object element, int column) { + if (element == null) throw new Exception("addCell - null argument"); + if ((column < 0) || (column > columns)) throw new Exception("addCell - illegal column argument"); + if ( !((GetObjectID(element) == CELL) || (GetObjectID(element) == TABLE)) ) throw new ArgumentException("addCell - only Cells or Tables allowed"); + + int lColspan = ((element is Cell) ? ((Cell)element).Colspan : 1); + + if (!Reserve(column, lColspan)) { + return -1; + } + + cells[column] = element; + currentColumn += lColspan - 1; + + return column; + } + + /// + /// Puts Cell to the Row at the position given, doesn't reserve colspan. + /// + /// the cell to add. + /// the position where to add the cell. + internal void SetElement(Object aElement, int column) { + if (reserved[column]) throw new ArgumentException("setElement - position already taken"); + + cells[column] = aElement; + if (aElement != null) { + reserved[column] = true; + } + } + + /// + /// Reserves a Cell in the Row. + /// + /// the column that has to be reserved. + /// true if the column was reserved, false if not. + internal bool Reserve(int column) { + return Reserve(column, 1); + } + + + /// + /// Reserves a Cell in the Row. + /// + /// the column that has to be reserved. + /// the number of columns + /// true if the column was reserved, false if not. + internal bool Reserve(int column, int size) { + if ((column < 0) || ((column + size) > columns)) throw new Exception("reserve - incorrect column/size"); + + for (int i=column; i < column + size; i++) { + if (reserved[i]) { + // undo reserve + for (int j=i; j >= column; j--) { + reserved[j] = false; + } + return false; + } + reserved[i] = true; + } + return true; + } + + // methods to retrieve information + + /// + /// Returns true/false when this position in the Row has been reserved, either filled or through a colspan of an Element. + /// + /// the column. + /// true if the column was reserved, false if not. + internal bool IsReserved(int column) { + return reserved[column]; + } + + /// + /// Returns the type-id of the element in a Row. + /// + /// the column of which you'd like to know the type + /// the element id + int GetElementID(int column) { + if (cells[column] == null) return NULL; + else if (cells[column] is Cell) return CELL; + else if (cells[column] is Table) return TABLE; + + return -1; + } + + + /// + /// Returns the type-id of an Object. + /// + /// + /// the object of which you'd like to know the type-id, -1 if invalid + int GetObjectID(Object element) { + if (element == null) return NULL; + else if (element is Cell) return CELL; + else if (element is Table) return TABLE; + + return -1; + } + + + /// + /// Gets a Cell or Table from a certain column. + /// + /// the column the Cell/Table is in. + /// + /// the Cell,Table or Object if the column was + /// reserved or null if empty. + /// + public Object GetCell(int column) { + if ((column < 0) || (column > columns)) { + throw new Exception("getCell at illegal index :" + column + " max is " + columns); + } + return cells[column]; + } + + /// + /// Checks if the row is empty. + /// + /// true if none of the columns is reserved. + public bool IsEmpty() { + for (int i = 0; i < columns; i++) { + if (cells[i] != null) { + return false; + } + } + return true; + } + + /// + /// Gets the number of columns. + /// + /// a value + public int Columns { + get { + return columns; + } + } + + /// + /// Gets the horizontal Element. + /// + /// a value + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + set { + horizontalAlignment = value; + } + } + + public override string ToString() { + return base.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/Section.cs b/iTechSharp/iTextSharp/text/Section.cs new file mode 100644 index 0000000..10844e5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Section.cs @@ -0,0 +1,756 @@ +using System; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Section.cs,v 1.17 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Section is a part of a Document containing + /// other Sections, Paragraphs, List + /// and/or Tables. + /// + /// + /// You can not construct a Section yourself. + /// You will have to ask an instance of Section to the + /// Chapter or Section to which you want to + /// add the new Section. + /// + /// + /// + /// Paragraph title2 = new Paragraph("This is Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// Chapter chapter2 = new Chapter(title2, 2); + /// Paragraph someText = new Paragraph("This is some text"); + /// chapter2.Add(someText); + /// Paragraph title21 = new Paragraph("This is Section 1 in Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0))); + /// Section section1 = chapter2.AddSection(title21); + /// Paragraph someSectionText = new Paragraph("This is some silly paragraph in a chapter and/or section. It contains some text to test the functionality of Chapters and Section."); + /// section1.Add(someSectionText); + /// Paragraph title211 = new Paragraph("This is SubSection 1 in Section 1 in Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 14, Font.BOLD, new Color(255, 0, 0))); + /// Section section11 = section1.AddSection(40, title211, 2); + /// section11.Add(someSectionText);strong> + /// + /// + public class Section : ArrayList, ITextElementArray, ILargeElement { + + // constant + /** + * A possible number style. The default number style: "1.2.3." + * @since iText 2.0.8 + */ + public const int NUMBERSTYLE_DOTTED = 0; + /** + * A possible number style. For instance: "1.2.3" + * @since iText 2.0.8 + */ + public const int NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT = 1; + + // membervariables + + /// This is the title of this section. + protected Paragraph title; + + /// This is the number of sectionnumbers that has to be shown before the section title. + protected int numberDepth; + + /** + * The style for sectionnumbers. + * @since iText 2.0.8 + */ + protected int numberStyle = NUMBERSTYLE_DOTTED; + + /// The indentation of this section on the left side. + protected float indentationLeft; + + /// The indentation of this section on the right side. + protected float indentationRight; + + /// The additional indentation of the content of this section. + protected float indentation; + + /// This is the number of subsections. + protected int subsections = 0; + + /// This is the complete list of sectionnumbers of this section and the parents of this section. + protected internal ArrayList numbers = null; + + /** + * Indicates if the Section will be complete once added to the document. + * @since iText 2.0.8 + */ + protected bool complete = true; + + /** + * Indicates if the Section was added completely to the document. + * @since iText 2.0.8 + */ + protected bool addedCompletely = false; + + /** + * Indicates if this is the first time the section was added. + * @since iText 2.0.8 + */ + protected bool notAddedYet = true; + + /// false if the bookmark children are not visible + protected bool bookmarkOpen = true; + + /** true if the section has to trigger a new page */ + protected bool triggerNewPage = false; + + /** The bookmark title if different from the content title */ + protected string bookmarkTitle; + + // constructors + + /// + /// Constructs a new Section. + /// + /// + /// Has 2 overloads. + /// + protected internal Section() { + title = new Paragraph(); + numberDepth = 1; + } + + /// + /// Constructs a new Section. + /// + /// a Paragraph + /// the numberDepth + protected internal Section(Paragraph title, int numberDepth) { + this.numberDepth = numberDepth; + this.title = title; + } + + // private methods + + /// + /// Sets the number of this section. + /// + /// the number of this section + /// an ArrayList, containing the numbers of the Parent + private void SetNumbers(int number, ArrayList numbers) { + this.numbers = new ArrayList(); + this.numbers.Add(number); + this.numbers.AddRange(numbers); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// the IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + foreach (IElement ele in this) { + listener.Add(ele); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public virtual int Type { + get { + return Element.SECTION; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in this) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public virtual bool IsNestable() { + return false; + } + + // overriding some of the ArrayList-methods + + /// + /// Adds a Paragraph, List or Table + /// to this Section. + /// + /// index at which the specified element is to be inserted + /// an object of type Paragraph, List or Table + public void Add(int index, Object o) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + try { + IElement element = (IElement) o; + if (element.IsNestable()) { + base.Insert(index, element); + } + else { + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a Paragraph, List, Table or another Section + /// to this Section. + /// + /// an object of type Paragraph, List, Table or another Section + /// a bool + public new bool Add(Object o) { + try { + IElement element = (IElement) o; + if (element.Type == Element.SECTION) { + Section section = (Section) o; + section.SetNumbers(++subsections, numbers); + base.Add(section); + return true; + } + else if (o is MarkedSection && ((MarkedObject)o).element.Type == Element.SECTION) { + MarkedSection mo = (MarkedSection)o; + Section section = (Section)(mo.element); + section.SetNumbers(++subsections, numbers); + base.Add(mo); + return true; + } + else if (element.IsNestable()) { + base.Add(o); + return true; + } + else { + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a collection of Elements + /// to this Section. + /// + /// a collection of Paragraphs, Lists and/or Tables + /// true if the action succeeded, false if not. + public bool AddAll(ICollection collection) { + foreach (object itm in collection) { + this.Add(itm); + } + return true; + } + + // methods that return a Section + + /// + /// Creates a Section, adds it to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(float indentation, Paragraph title, int numberDepth) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + Section section = new Section(title, numberDepth); + section.Indentation = indentation; + Add(section); + return section; + } + + /// + /// Creates a Section, adds it to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(float indentation, Paragraph title) { + return AddSection(indentation, title, numberDepth + 1); + } + + /// + /// Creates a Section, add it to this Section and returns it. + /// + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(Paragraph title, int numberDepth) { + return AddSection(0, title, numberDepth); + } + + /** + * Adds a marked section. For use in class MarkedSection only! + */ + public MarkedSection AddMarkedSection() { + MarkedSection section = new MarkedSection(new Section(null, numberDepth + 1)); + Add(section); + return section; + } + + /// + /// Creates a Section, adds it to this Section and returns it. + /// + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(Paragraph title) { + return AddSection(0, title, numberDepth + 1); + } + + /** + * Adds a Section to this Section and returns it. + * + * @param indentation the indentation of the new section + * @param title the title of the new section + * @param numberDepth the numberDepth of the section + */ + /// + /// Adds a Section to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(float indentation, string title, int numberDepth) { + return AddSection(indentation, new Paragraph(title), numberDepth); + } + + /** + * Adds a Section to this Section and returns it. + * + * @param title the title of the new section + * @param numberDepth the numberDepth of the section + */ + /// + /// Adds a Section to this Section and returns it. + /// + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(string title, int numberDepth) { + return AddSection(new Paragraph(title), numberDepth); + } + + /// + /// Adds a Section to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(float indentation, string title) { + return AddSection(indentation, new Paragraph(title)); + } + + /// + /// Adds a Section to this Section and returns it. + /// + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(string title) { + return AddSection(new Paragraph(title)); + } + + // public methods + + /// + /// Alters the attributes of this Section. + /// + /// the attributes + public void Set(Properties attributes) { + string value; + if ((value = attributes.Remove(ElementTags.NUMBERDEPTH)) != null) { + NumberDepth = int.Parse(value); + } + if ((value = attributes.Remove(ElementTags.INDENT)) != null) { + Indentation = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + if ((value = attributes.Remove(ElementTags.INDENTATIONLEFT)) != null) { + IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + if ((value = attributes.Remove(ElementTags.INDENTATIONRIGHT)) != null) { + IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + + /// + /// Get/set the title of this section + /// + /// a Paragraph + public Paragraph Title { + get { + return ConstructTitle(title, numbers, numberDepth, numberStyle); + } + + set { + this.title = value; + } + } + + /** + * Sets the style for numbering sections. + * Possible values are NUMBERSTYLE_DOTTED: 1.2.3. (the default) + * or NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT: 1.2.3 + * @since iText 2.0.8 + */ + public int NumberStyle { + set { + numberStyle = value; + } + get { + return numberStyle; + } + } + + /** + * Constructs a Paragraph that will be used as title for a Section or Chapter. + * @param title the title of the section + * @param numbers a list of sectionnumbers + * @param numberDepth how many numbers have to be shown + * @param numberStyle the numbering style + * @return a Paragraph object + * @since iText 2.0.8 + */ + public static Paragraph ConstructTitle(Paragraph title, ArrayList numbers, int numberDepth, int numberStyle) { + if (title == null) { + return null; + } + int depth = Math.Min(numbers.Count, numberDepth); + if (depth < 1) { + return title; + } + StringBuilder buf = new StringBuilder(" "); + for (int i = 0; i < depth; i++) { + buf.Insert(0, "."); + buf.Insert(0, (int)numbers[i]); + } + if (numberStyle == NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT) { + buf.Remove(buf.Length - 2, 1); + } + Paragraph result = new Paragraph(title); + result.Insert(0, new Chunk(buf.ToString(), title.Font)); + return result; + } + + // methods to retrieve information + + /// + /// Checks if this object is a Chapter. + /// + /// + /// true if it is a Chapter, + /// false if it is a Section + /// + public bool IsChapter() { + return Type == Element.CHAPTER; + } + + /// + /// Checks if this object is a Section. + /// + /// + /// true if it is a Section, + /// false if it is a Chapter. + /// + public bool IsSection() { + return Type == Element.SECTION; + } + + /// + /// Get/set the numberdepth of this Section. + /// + /// a int + public int NumberDepth { + get { + return numberDepth; + } + + set { + this.numberDepth = value; + } + } + + /// + /// Get/set the indentation of this Section on the left side. + /// + /// the indentation + public float IndentationLeft { + get { + return indentationLeft; + } + + set { + indentationLeft = value; + } + } + + /// + /// Get/set the indentation of this Section on the right side. + /// + /// the indentation + public float IndentationRight { + get { + return indentationRight; + } + + set { + indentationRight = value; + } + } + + /// + /// Get/set the indentation of the content of this Section. + /// + /// the indentation + public float Indentation { + get { + return indentation; + } + + set { + indentation = value; + } + } + + /// + /// Returns the depth of this section. + /// + /// the depth + public int Depth { + get { + return numbers.Count; + } + } + + /// + /// Checks if a given tag corresponds with a title tag for this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTitle(string tag) { + return ElementTags.TITLE.Equals(tag); + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.SECTION.Equals(tag); + } + + /// + /// Get/set the bookmark + /// + /// a bool + public bool BookmarkOpen { + get { + return bookmarkOpen; + } + + set { + this.bookmarkOpen = value; + } + } + + /** + * Gets the bookmark title. + * @return the bookmark title + */ + public Paragraph GetBookmarkTitle() { + if (bookmarkTitle == null) + return Title; + else + return new Paragraph(bookmarkTitle); + } + + /** + * Sets the bookmark title. The bookmark title is the same as the section title but + * can be changed with this method. + * @param bookmarkTitle the bookmark title + */ + public String BookmarkTitle { + set { + this.bookmarkTitle = value; + } + } + + public override string ToString() { + return base.ToString(); + } + + public virtual bool TriggerNewPage { + get { + return triggerNewPage && notAddedYet; + } + set { + triggerNewPage = value; + } + } + + /** + * Changes the Chapter number. + */ + public void SetChapterNumber(int number) { + numbers[numbers.Count - 1] = number; + foreach (Object s in this) { + if (s is Section) { + ((Section)s).SetChapterNumber(number); + } + } + } + + /** + * Indicates if this is the first time the section is added. + * @since iText2.0.8 + * @return true if the section wasn't added yet + */ + public bool NotAddedYet { + get { + return notAddedYet; + } + set { + notAddedYet = value; + } + } + + /** + * @see com.lowagie.text.LargeElement#isAddedCompletely() + * @since iText 2.0.8 + */ + protected bool AddedCompletely { + get { + return addedCompletely; + } + set { + addedCompletely = value; + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#flushContent() + */ + public void FlushContent() { + NotAddedYet = false; + title = null; + for (int k = 0; k < Count; ++k) { + IElement element = (IElement)this[k]; + if (element is Section) { + Section s = (Section)element; + if (!s.ElementComplete && Count == 1) { + s.FlushContent(); + return; + } + else { + s.AddedCompletely = true; + } + } + this.RemoveAt(k); + --k; + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#isComplete() + */ + public bool ElementComplete { + get { + return complete; + } + set { + complete = value; + } + } + + /** + * Adds a new page to the section. + * @since 2.1.1 + */ + public void NewPage() { + this.Add(Chunk.NEXTPAGE); + } + } +} diff --git a/iTechSharp/iTextSharp/text/SimpleCell.cs b/iTechSharp/iTextSharp/text/SimpleCell.cs new file mode 100644 index 0000000..2849b13 --- /dev/null +++ b/iTechSharp/iTextSharp/text/SimpleCell.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; + +namespace iTextSharp.text +{ + /// + /// Summary description for SimpleCell. + /// + public class SimpleCell : Rectangle, IPdfPCellEvent, ITextElementArray { + + /** the CellAttributes object represents a row. */ + public new const bool ROW = true; + /** the CellAttributes object represents a cell. */ + public new const bool CELL = false; + /** the content of the Cell. */ + private ArrayList content = new ArrayList(); + /** the width of the Cell. */ + private float width = 0f; + /** the widthpercentage of the Cell. */ + private float widthpercentage = 0f; + /** an extra spacing variable */ + private float spacing_left = float.NaN; + /** an extra spacing variable */ + private float spacing_right = float.NaN; + /** an extra spacing variable */ + private float spacing_top = float.NaN; + /** an extra spacing variable */ + private float spacing_bottom = float.NaN; + /** an extra padding variable */ + private float padding_left = float.NaN; + /** an extra padding variable */ + private float padding_right = float.NaN; + /** an extra padding variable */ + private float padding_top = float.NaN; + /** an extra padding variable */ + private float padding_bottom = float.NaN; + /** the colspan of a Cell */ + private int colspan = 1; + /** horizontal alignment inside the Cell. */ + private int horizontalAlignment = Element.ALIGN_UNDEFINED; + /** vertical alignment inside the Cell. */ + private int verticalAlignment = Element.ALIGN_UNDEFINED; + /** indicates if these are the attributes of a single Cell (false) or a group of Cells (true). */ + private bool cellgroup = false; + /** Indicates that the largest ascender height should be used to determine the + * height of the first line. Note that this only has an effect when rendered + * to PDF. Setting this to true can help with vertical alignment problems. */ + protected bool useAscender = false; + /** Indicates that the largest descender height should be added to the height of + * the last line (so characters like y don't dip into the border). Note that + * this only has an effect when rendered to PDF. */ + protected bool useDescender = false; + /** + * Adjusts the cell contents to compensate for border widths. Note that + * this only has an effect when rendered to PDF. + */ + protected bool useBorderPadding; + + /** + * A CellAttributes object is always constructed without any dimensions. + * Dimensions are defined after creation. + * @param row only true if the CellAttributes object represents a row. + */ + public SimpleCell(bool row) : base (0f, 0f, 0f, 0f) { + cellgroup = row; + Border = BOX; + } + + /** + * Adds content to this object. + * @param element + * @throws BadElementException + */ + public void AddElement(IElement element) { + if (cellgroup) { + if (element is SimpleCell) { + if (((SimpleCell)element).Cellgroup) { + throw new BadElementException("You can't add one row to another row."); + } + content.Add(element); + return; + } + else { + throw new BadElementException("You can only add cells to rows, no objects of type " + element.GetType().ToString()); + } + } + if (element.Type == Element.PARAGRAPH + || element.Type == Element.PHRASE + || element.Type == Element.ANCHOR + || element.Type == Element.CHUNK + || element.Type == Element.LIST + || element.Type == Element.MARKED + || element.Type == Element.JPEG + || element.Type == Element.JPEG2000 + || element.Type == Element.IMGRAW + || element.Type == Element.IMGTEMPLATE) { + content.Add(element); + } + else { + throw new BadElementException("You can't add an element of type " + element.GetType().ToString() + " to a SimpleCell."); + } + } + + /** + * Creates a Cell with these attributes. + * @param rowAttributes + * @return a cell based on these attributes. + * @throws BadElementException + */ + public Cell CreateCell(SimpleCell rowAttributes) { + Cell cell = new Cell(); + cell.CloneNonPositionParameters(rowAttributes); + cell.SoftCloneNonPositionParameters(this); + cell.Colspan = colspan; + cell.HorizontalAlignment = horizontalAlignment; + cell.VerticalAlignment = verticalAlignment; + cell.UseAscender = useAscender; + cell.UseBorderPadding = useBorderPadding; + cell.UseDescender = useDescender; + foreach (IElement element in content) { + cell.AddElement(element); + } + return cell; + } + + /** + * Creates a PdfPCell with these attributes. + * @param rowAttributes + * @return a PdfPCell based on these attributes. + */ + public PdfPCell CreatePdfPCell(SimpleCell rowAttributes) { + PdfPCell cell = new PdfPCell(); + cell.Border = NO_BORDER; + SimpleCell tmp = new SimpleCell(CELL); + tmp.Spacing_left = spacing_left; + tmp.Spacing_right = spacing_right; + tmp.Spacing_top = spacing_top; + tmp.Spacing_bottom = spacing_bottom; + tmp.CloneNonPositionParameters(rowAttributes); + tmp.SoftCloneNonPositionParameters(this); + cell.CellEvent = tmp; + cell.HorizontalAlignment = rowAttributes.horizontalAlignment; + cell.VerticalAlignment = rowAttributes.verticalAlignment; + cell.UseAscender = rowAttributes.useAscender; + cell.UseBorderPadding = rowAttributes.useBorderPadding; + cell.UseDescender = rowAttributes.useDescender; + cell.Colspan = colspan; + if (horizontalAlignment != Element.ALIGN_UNDEFINED) + cell.HorizontalAlignment = horizontalAlignment; + if (verticalAlignment != Element.ALIGN_UNDEFINED) + cell.VerticalAlignment = verticalAlignment; + if (useAscender) + cell.UseAscender = useAscender; + if (useBorderPadding) + cell.UseBorderPadding = useBorderPadding; + if (useDescender) + cell.UseDescender = useDescender; + float p; + float sp_left = spacing_left; + if (float.IsNaN(sp_left)) sp_left = 0f; + float sp_right = spacing_right; + if (float.IsNaN(sp_right)) sp_right = 0f; + float sp_top = spacing_top; + if (float.IsNaN(sp_top)) sp_top = 0f; + float sp_bottom = spacing_bottom; + if (float.IsNaN(sp_bottom)) sp_bottom = 0f; + p = padding_left; + if (float.IsNaN(p)) p = 0f; + cell.PaddingLeft = p + sp_left; + p = padding_right; + if (float.IsNaN(p)) p = 0f; + cell.PaddingRight = p + sp_right; + p = padding_top; + if (float.IsNaN(p)) p = 0f; + cell.PaddingTop = p + sp_top; + p = padding_bottom; + if (float.IsNaN(p)) p = 0f; + cell.PaddingBottom = p + sp_bottom; + foreach (IElement element in content) { + cell.AddElement(element); + } + return cell; + } + + /** + * @param rectangle + * @param spacing + * @return a rectangle + */ + public static SimpleCell GetDimensionlessInstance(Rectangle rectangle, float spacing) { + SimpleCell cell = new SimpleCell(CELL); + cell.CloneNonPositionParameters(rectangle); + cell.Spacing = spacing * 2; + return cell; + } + + /** + * @see com.lowagie.text.pdf.PdfPCellEvent#cellLayout(com.lowagie.text.pdf.PdfPCell, com.lowagie.text.Rectangle, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) { + float sp_left = spacing_left; + if (float.IsNaN(sp_left)) sp_left = 0f; + float sp_right = spacing_right; + if (float.IsNaN(sp_right)) sp_right = 0f; + float sp_top = spacing_top; + if (float.IsNaN(sp_top)) sp_top = 0f; + float sp_bottom = spacing_bottom; + if (float.IsNaN(sp_bottom)) sp_bottom = 0f; + Rectangle rect = new Rectangle(position.GetLeft(sp_left), position.GetBottom(sp_bottom), position.GetRight(sp_right), position.GetTop(sp_top)); + rect.CloneNonPositionParameters(this); + canvases[PdfPTable.BACKGROUNDCANVAS].Rectangle(rect); + rect.BackgroundColor = null; + canvases[PdfPTable.LINECANVAS].Rectangle(rect); + } + + /** Sets the padding parameters if they are undefined. + * @param padding*/ + public float Padding { + set { + if (float.IsNaN(padding_right)) { + Padding_right = value; + } + if (float.IsNaN(padding_left)) { + Padding_left = value; + } + if (float.IsNaN(padding_bottom)) { + Padding_bottom = value; + } + if (float.IsNaN(padding_top)) { + Padding_top = value; + } + } + } + + /** + * @return Returns the colspan. + */ + public int Colspan { + get { + return colspan; + } + set { + if (value > 0) this.colspan = value; + } + } + + /** + * @param padding_bottom The padding_bottom to set. + */ + public float Padding_bottom { + get { + return padding_bottom; + } + set { + padding_bottom = value; + } + } + + public float Padding_left { + get { + return padding_left; + } + set { + padding_left = value; + } + } + + public float Padding_right { + get { + return padding_right; + } + set { + padding_right = value; + } + } + + public float Padding_top { + get { + return padding_top; + } + set { + padding_top = value; + } + } + + /** + * @return Returns the spacing. + */ + public float Spacing { + set { + this.spacing_left = value; + this.spacing_right = value; + this.spacing_top = value; + this.spacing_bottom = value; + } + + } + + public float Spacing_top { + get { + return spacing_top; + } + set { + spacing_top = value; + } + } + + public float Spacing_bottom { + get { + return spacing_bottom; + } + set { + spacing_bottom = value; + } + } + + public float Spacing_left { + get { + return spacing_left; + } + set { + spacing_left = value; + } + } + + public float Spacing_right { + get { + return spacing_right; + } + set { + spacing_right = value; + } + } + + /** + * @return Returns the cellgroup. + */ + public bool Cellgroup { + get { + return cellgroup; + } + set { + cellgroup = value; + } + } + + /** + * @return Returns the horizontal alignment. + */ + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + set { + horizontalAlignment = value; + } + } + + public int VerticalAlignment { + get { + return verticalAlignment; + } + set { + verticalAlignment = value; + } + } + /** + * @return Returns the width. + */ + public new float Width { + get { + return width; + } + set { + width = value; + } + } + + /** + * @return Returns the widthpercentage. + */ + public float Widthpercentage { + get { + return widthpercentage; + } + set { + widthpercentage = value; + } + } + + /** + * @return Returns the useAscender. + */ + public bool UseAscender { + get { + return useAscender; + } + set { + useAscender = value; + } + } + + public bool UseDescender { + get { + return useDescender; + } + set { + useDescender = value; + } + } + /** + * @return Returns the useBorderPadding. + */ + public bool UseBorderPadding { + get { + return useBorderPadding; + } + set { + useBorderPadding = value; + } + } + + /** + * @return Returns the content. + */ + internal ArrayList Content { + get { + return content; + } + } + + /** + * @see com.lowagie.text.TextElementArray#add(java.lang.Object) + */ + public bool Add(Object o) { + try { + AddElement((IElement)o); + return true; + } + catch (InvalidCastException) { + return false; + } + } + + public override int Type { + get { + return Element.CELL; + } + } + + } +} diff --git a/iTechSharp/iTextSharp/text/SimpleTable.cs b/iTechSharp/iTextSharp/text/SimpleTable.cs new file mode 100644 index 0000000..0416a8e --- /dev/null +++ b/iTechSharp/iTextSharp/text/SimpleTable.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; + +namespace iTextSharp.text +{ + /// + /// Summary description for SimpleTable. + /// + public class SimpleTable : Rectangle, IPdfPTableEvent, ITextElementArray { + + /** the content of a Table. */ + private ArrayList content = new ArrayList(); + /** the width of the Table. */ + private float width = 0f; + /** the widthpercentage of the Table. */ + private float widthpercentage = 0f; + /** the spacing of the Cells. */ + private float cellspacing; + /** the padding of the Cells. */ + private float cellpadding; + /** the alignment of the table. */ + private int alignment; + + /** + * A RectangleCell is always constructed without any dimensions. + * Dimensions are defined after creation. + */ + public SimpleTable() : base(0f, 0f, 0f, 0f) { + Border = BOX; + BorderWidth = 2f; + } + + /** + * Adds content to this object. + * @param element + * @throws BadElementException + */ + public void AddElement(SimpleCell element) { + if (!element.Cellgroup) { + throw new BadElementException("You can't add cells to a table directly, add them to a row first."); + } + content.Add(element); + } + + /** + * Creates a Table object based on this TableAttributes object. + * @return a com.lowagie.text.Table object + * @throws BadElementException + */ + public Table CreateTable() { + if (content.Count == 0) throw new BadElementException("Trying to create a table without rows."); + SimpleCell rowx = (SimpleCell)content[0]; + int columns = 0; + foreach (SimpleCell cell in rowx.Content) { + columns += cell.Colspan; + } + float[] widths = new float[columns]; + float[] widthpercentages = new float[columns]; + Table table = new Table(columns); + table.Alignment = alignment; + table.Spacing = cellspacing; + table.Padding = cellpadding; + table.CloneNonPositionParameters(this); + int pos; + foreach (SimpleCell row in content) { + pos = 0; + foreach (SimpleCell cell in row.Content) { + table.AddCell(cell.CreateCell(row)); + if (cell.Colspan == 1) { + if (cell.Width > 0) widths[pos] = cell.Width; + if (cell.Widthpercentage > 0) widthpercentages[pos] = cell.Widthpercentage; + } + pos += cell.Colspan; + } + } + float sumWidths = 0f; + for (int i = 0; i < columns; i++) { + if (widths[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widths[i]; + } + if (sumWidths > 0) { + table.Width = sumWidths; + table.Locked = true; + table.Widths = widths; + } + else { + for (int i = 0; i < columns; i++) { + if (widthpercentages[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widthpercentages[i]; + } + if (sumWidths > 0) { + table.Widths = widthpercentages; + } + } + if (width > 0) { + table.Width = width; + table.Locked = true; + } + else if (widthpercentage > 0) { + table.Width = widthpercentage; + } + return table; + } + + /** + * Creates a PdfPTable object based on this TableAttributes object. + * @return a com.lowagie.text.pdf.PdfPTable object + * @throws DocumentException + */ + public PdfPTable CreatePdfPTable() { + if (content.Count == 0) throw new BadElementException("Trying to create a table without rows."); + SimpleCell rowx = (SimpleCell)content[0]; + int columns = 0; + foreach (SimpleCell cell in rowx.Content) { + columns += cell.Colspan; + } + float[] widths = new float[columns]; + float[] widthpercentages = new float[columns]; + PdfPTable table = new PdfPTable(columns); + table.TableEvent = this; + table.HorizontalAlignment = alignment; + int pos; + foreach (SimpleCell row in content) { + pos = 0; + foreach (SimpleCell cell in row.Content) { + if (float.IsNaN(cell.Spacing_left)) { + cell.Spacing_left = cellspacing / 2f; + } + if (float.IsNaN(cell.Spacing_right)) { + cell.Spacing_right = cellspacing / 2f; + } + if (float.IsNaN(cell.Spacing_top)) { + cell.Spacing_top = cellspacing / 2f; + } + if (float.IsNaN(cell.Spacing_bottom)) { + cell.Spacing_bottom = cellspacing / 2f; + } + cell.Padding = cellpadding; + table.AddCell(cell.CreatePdfPCell(row)); + if (cell.Colspan == 1) { + if (cell.Width > 0) widths[pos] = cell.Width; + if (cell.Widthpercentage > 0) widthpercentages[pos] = cell.Widthpercentage; + } + pos += cell.Colspan; + } + } + float sumWidths = 0f; + for (int i = 0; i < columns; i++) { + if (widths[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widths[i]; + } + if (sumWidths > 0) { + table.TotalWidth = sumWidths; + table.SetWidths(widths); + } + else { + for (int i = 0; i < columns; i++) { + if (widthpercentages[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widthpercentages[i]; + } + if (sumWidths > 0) { + table.SetWidths(widthpercentages); + } + } + if (width > 0) { + table.TotalWidth = width; + } + if (widthpercentage > 0) { + table.WidthPercentage = widthpercentage; + } + return table; + } + + /** + * @param rectangle + * @param spacing + * @return a rectangle + */ + public static SimpleTable GetDimensionlessInstance(Rectangle rectangle, float spacing) { + SimpleTable ev = new SimpleTable(); + ev.CloneNonPositionParameters(rectangle); + ev.Cellspacing = spacing; + return ev; + } + + /** + * @see com.lowagie.text.pdf.PdfPTableEvent#tableLayout(com.lowagie.text.pdf.PdfPTable, float[][], float[], int, int, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void TableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases) { + float[] width = widths[0]; + Rectangle rect = new Rectangle(width[0], heights[heights.Length - 1], width[width.Length - 1], heights[0]); + rect.CloneNonPositionParameters(this); + int bd = rect.Border; + rect.Border = Rectangle.NO_BORDER; + canvases[PdfPTable.BACKGROUNDCANVAS].Rectangle(rect); + rect.Border = bd; + rect.BackgroundColor = null; + canvases[PdfPTable.LINECANVAS].Rectangle(rect); + } + + /** + * @return Returns the cellpadding. + */ + public float Cellpadding { + get { + return cellpadding; + } + set { + cellpadding = value; + } + } + + /** + * @return Returns the cellspacing. + */ + public float Cellspacing { + get { + return cellspacing; + } + set { + cellspacing = value; + } + } + + /** + * @return Returns the alignment. + */ + public int Alignment { + get { + return alignment; + } + set { + alignment = value; + } + } + + /** + * @return Returns the width. + */ + public override float Width { + get { + return width; + } + set { + width = value; + } + } + /** + * @return Returns the widthpercentage. + */ + public float Widthpercentage { + get { + return widthpercentage; + } + set { + widthpercentage = value; + } + } + /** + * @see com.lowagie.text.Element#type() + */ + public override int Type { + get { + return Element.TABLE; + } + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return true; + } + + /** + * @see com.lowagie.text.TextElementArray#add(java.lang.Object) + */ + public bool Add(Object o) { + try { + AddElement((SimpleCell)o); + return true; + } + catch (InvalidCastException) { + return false; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/SpecialSymbol.cs b/iTechSharp/iTextSharp/text/SpecialSymbol.cs new file mode 100644 index 0000000..d706298 --- /dev/null +++ b/iTechSharp/iTextSharp/text/SpecialSymbol.cs @@ -0,0 +1,202 @@ +using System; + +/* + * $Id: SpecialSymbol.cs,v 1.4 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + public class SpecialSymbol { + + /** + * Returns the first occurrence of a special symbol in a String. + * + * @param string a String + * @return an index of -1 if no special symbol was found + */ + + public static int Index(string str) { + int length = str.Length; + for (int i = 0; i < length; i++) { + if (GetCorrespondingSymbol(str[i]) != ' ') { + return i; + } + } + return -1; + } + + /** + * Gets a chunk with a symbol character. + * @param c a character that has to be changed into a symbol + * @param font Font if there is no SYMBOL character corresponding with c + * @return a SYMBOL version of a character + */ + + public static Chunk Get(char c, Font font) { + char greek = SpecialSymbol.GetCorrespondingSymbol(c); + if (greek == ' ') { + return new Chunk(c.ToString(), font); + } + Font symbol = new Font(Font.SYMBOL, font.Size, font.Style, font.Color); + return new Chunk(greek.ToString(), symbol); + } + + /** + * Looks for the corresponding symbol in the font Symbol. + * + * @param c the original ASCII-char + * @return the corresponding symbol in font Symbol + */ + + public static char GetCorrespondingSymbol(char c) { + switch (c) { + case (char)913: + return 'A'; // ALFA + case (char)914: + return 'B'; // BETA + case (char)915: + return 'G'; // GAMMA + case (char)916: + return 'D'; // DELTA + case (char)917: + return 'E'; // EPSILON + case (char)918: + return 'Z'; // ZETA + case (char)919: + return 'H'; // ETA + case (char)920: + return 'Q'; // THETA + case (char)921: + return 'I'; // IOTA + case (char)922: + return 'K'; // KAPPA + case (char)923: + return 'L'; // LAMBDA + case (char)924: + return 'M'; // MU + case (char)925: + return 'N'; // NU + case (char)926: + return 'X'; // XI + case (char)927: + return 'O'; // OMICRON + case (char)928: + return 'P'; // PI + case (char)929: + return 'R'; // RHO + case (char)931: + return 'S'; // SIGMA + case (char)932: + return 'T'; // TAU + case (char)933: + return 'U'; // UPSILON + case (char)934: + return 'J'; // PHI + case (char)935: + return 'C'; // CHI + case (char)936: + return 'Y'; // PSI + case (char)937: + return 'W'; // OMEGA + case (char)945: + return 'a'; // alfa + case (char)946: + return 'b'; // beta + case (char)947: + return 'g'; // gamma + case (char)948: + return 'd'; // delta + case (char)949: + return 'e'; // epsilon + case (char)950: + return 'z'; // zeta + case (char)951: + return 'h'; // eta + case (char)952: + return 'q'; // theta + case (char)953: + return 'i'; // iota + case (char)954: + return 'k'; // kappa + case (char)955: + return 'l'; // lambda + case (char)956: + return 'm'; // mu + case (char)957: + return 'n'; // nu + case (char)958: + return 'x'; // xi + case (char)959: + return 'o'; // omicron + case (char)960: + return 'p'; // pi + case (char)961: + return 'r'; // rho + case (char)962: + return 'V'; // sigma + case (char)963: + return 's'; // sigma + case (char)964: + return 't'; // tau + case (char)965: + return 'u'; // upsilon + case (char)966: + return 'j'; // phi + case (char)967: + return 'c'; // chi + case (char)968: + return 'y'; // psi + case (char)969: + return 'w'; // omega + default: + return ' '; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Table.cs b/iTechSharp/iTextSharp/text/Table.cs new file mode 100644 index 0000000..4699bca --- /dev/null +++ b/iTechSharp/iTextSharp/text/Table.cs @@ -0,0 +1,1577 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; + +/* + * $Id: Table.cs,v 1.23 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * Some methods in this class were contributed by Geert Poels, Kris Jespers and + * Steve Ogryzek. Check the CVS repository. + */ + +namespace iTextSharp.text { + /// + /// A Table is a Rectangle that contains Cells, + /// ordered in some kind of matrix. + /// + /// + /// Tables that span multiple pages are cut into different parts automatically. + /// If you want a table header to be repeated on every page, you may not forget to + /// mark the end of the header section by using the method EndHeaders(). + ///

+ /// The matrix of a table is not necessarily an m x n-matrix. It can contain holes + /// or cells that are bigger than the unit. Believe me or not, but it took some serious + /// thinking to make this as userfriendly as possible. I hope you wil find the result + /// quite simple (I love simple solutions, especially for complex problems). + /// + /// + /// + /// // Remark: You MUST know the number of columns when constructing a Table. + /// // The number of rows is not important. + /// Table table = new Table(3); + /// table.SetBorderWidth(1); + /// table.SetBorderColor(new Color(0, 0, 255)); + /// table.SetPadding(5); + /// table.SetSpacing(5); + /// Cell cell = new Cell("header"); + /// cell.SetHeader(true); + /// cell.SetColspan(3); + /// table.AddCell(cell); + /// table.EndHeaders(); + /// cell = new Cell("example cell with colspan 1 and rowspan 2"); + /// cell.SetRowspan(2); + /// cell.SetBorderColor(new Color(255, 0, 0)); + /// table.AddCell(cell); + /// table.AddCell("1.1"); + /// table.AddCell("2.1"); + /// table.AddCell("1.2"); + /// table.AddCell("2.2"); + /// table.AddCell("cell test1"); + /// cell = new Cell("big cell"); + /// cell.SetRowspan(2); + /// cell.SetColspan(2); + /// table.AddCell(cell); + /// table.AddCell("cell test2"); + /// + /// + /// The result of this code is a table: + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
+ /// header + ///
+ /// example cell with colspan 1 and rowspan 2 + /// + /// 1.1 + /// + /// 2.1 + ///
+ /// 1.2 + /// + /// 2.2 + ///
+ /// cell test1 + /// + /// big cell + ///
+ /// cell test2 + ///
+ ///
+ /// + /// + /// + /// + public class Table : Rectangle, ILargeElement { + + // membervariables + + // these variables contain the data of the table + + ///

This is the number of columns in the Table. + private int columns; + + // this is the current Position in the table + private System.Drawing.Point curPosition = new System.Drawing.Point(0, 0); + + /// This is the list of Rows. + private ArrayList rows = new ArrayList(); + + // these variables contain the layout of the table + + /// This Empty Cell contains the DEFAULT layout of each Cell added with the method AddCell(string content). + private Cell defaultCell = new Cell(true); + + /// This is the number of the last row of the table headers. + private int lastHeaderRow = -1; + + /// This is the horizontal Element. + private int alignment = Element.ALIGN_CENTER; + + /// This is cellpadding. + private float cellpadding; + + /// This is cellspacing. + private float cellspacing; + + /// This is the width of the table (in percent of the available space). + private float width = 80; + + /** Is the width a percentage (false) or an absolute width (true)? */ + private bool locked = false; + + /// This is an array containing the widths (in percentages) of every column. + private float[] widths; + + /// bool to track if a table was inserted (to avoid unnecessary computations afterwards) + private bool mTableInserted = false; + + /// + /// Boolean to automatically fill empty cells before a table is rendered + /// (takes CPU so may be set to false in case of certainty) + /// + protected internal bool autoFillEmptyCells = false; + + /// If true this table may not be split over two pages. + bool tableFitsPage = false; + + /// If true cells may not be split over two pages. + bool cellsFitPage = false; + + /// This is the offset of the table. + float offset = float.NaN; + + /** if you want to generate tables the old way, set this value to false. */ + protected bool convert2pdfptable = false; + + /** + * Indicates if this is the first time the section was added. + * @since iText 2.0.8 + */ + protected bool notAddedYet = true; + + /** + * Indicates if the PdfPTable is complete once added to the document. + * @since iText 2.0.8 + */ + protected bool complete = true; + + // constructors + + /// + /// Constructs a Table with a certain number of columns. + /// + /// The number of columns in the table + /// + /// Has three overloads + /// + public Table(int columns) : this(columns, 1) {} + + /// + /// Constructs a Table with a certain number of columns + /// and a certain number of Rows. + /// + /// The number of columns in the table + /// The number of rows + /// + /// Has three overloads + /// + public Table(int columns, int rows) : base(0, 0, 0, 0) { + Border = BOX; + BorderWidth = 1; + defaultCell.Border = BOX; + + // a table should have at least 1 column + if (columns <= 0) { + throw new BadElementException("A table should have at least 1 column."); + } + this.columns = columns; + + // a certain number of rows are created + for (int i = 0; i < rows; i++) { + this.rows.Add(new Row(columns)); + } + curPosition = new System.Drawing.Point(0, 0); + + // the DEFAULT widths are calculated + widths = new float[columns]; + float width = 100f / columns; + for (int i = 0; i < columns; i++) { + widths[i] = width; + } + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public override bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /** + * Sets the default layout of the Table to + * the provided Cell + * @param value a cell with all the defaults + */ + public Cell DefaultLayout { + set { + defaultCell = value; + } + get { + return defaultCell; + } + } + + /** + * Sets the default layout of the Table to + * the provided Cell + * @param value a cell with all the defaults + */ + public Cell DefaultCell { + set { + defaultCell = value; + } + get { + return defaultCell; + } + } + + /// + /// Enables/disables automatic insertion of empty cells before table is rendered. (default = false) + /// + /// + /// As some people may want to create a table, fill only a couple of the cells and don't bother with + /// investigating which empty ones need to be added, this default behaviour may be very welcome. + /// Disabling is recommended to increase speed. (empty cells should be added through extra code then) + /// + /// enable/disable autofill + public bool AutoFillEmptyCells { + set { + autoFillEmptyCells = value; + } + } + + /// + /// Allows you to control when a page break occurs. + /// + /// + /// When a table doesn't fit a page, it is split in two parts. + /// If you want to avoid this, you should set the tableFitsPage value to true. + /// + /// a value + public bool TableFitsPage { + set { + this.tableFitsPage = value; + if (value) CellsFitPage = true; + } + get { + return tableFitsPage; + } + } + + /// + /// Allows you to control when a page break occurs. + /// + /// + /// When a cell doesn't fit a page, it is split in two parts. + /// If you want to avoid this, you should set the cellsFitPage value to true. + /// + /// a value + public bool CellsFitPage { + set { + this.cellsFitPage = value; + } + get { + return cellsFitPage; + } + } + + /// + /// Get/set the offset of this table. + /// + /// the space between this table and the previous element. + public float Offset { + get { + return offset; + } + + set { + this.offset = value; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.TABLE; + } + } + + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + + // public ArrayList Chunks { + // get { + // return new ArrayList(); + // } + // } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return true; + } + + // methods to add content to the table + + /// + /// Adds a Cell to the Table at a certain row and column. + /// + /// The Cell to add + /// The row where the Cell will be added + /// The column where the Cell will be added + public void AddCell(Cell aCell, int row, int column) { + AddCell(aCell, new System.Drawing.Point(row,column)); + } + + /// + /// Adds a Cell to the Table at a certain location. + /// + /// The Cell to add + /// The location where the Cell will be added + public void AddCell(Cell aCell, object aLocation) { + System.Drawing.Point p; + if (aCell == null) throw new Exception("addCell - cell has null-value"); + if (aLocation == null) + throw new Exception("addCell - point has null-value"); + else + p = (System.Drawing.Point)aLocation; + + if (aCell.IsTable()) { + IEnumerator i = aCell.Elements.GetEnumerator(); + i.MoveNext(); + InsertTable((Table)i.Current, p); + } + if (p.X < 0) throw new BadElementException("row coordinate of location must be >= 0"); + if ((p.Y <= 0) && (p.Y > columns)) throw new BadElementException("column coordinate of location must be >= 0 and < nr of columns"); + if (!IsValidLocation(aCell, p)) throw new BadElementException("Adding a cell at the location (" + p.X + "," + p.Y + ") with a colspan of " + aCell.Colspan + " and a rowspan of " + aCell.Rowspan + " is illegal (beyond boundaries/overlapping)."); + if (aCell.Border == UNDEFINED) aCell.Border = defaultCell.Border; + aCell.Fill(); + PlaceCell(rows, aCell, p); + CurrentLocationToNextValidPosition = p; + } + + + /// + /// Adds a Cell to the Table. + /// + /// a Cell + public void AddCell(Cell cell) { + try { + AddCell(cell, curPosition); + } + catch (BadElementException) { + // don't add the cell + } + } + + /// + /// Adds a Cell to the Table. + /// + /// + /// This is a shortcut for AddCell(Cell cell). + /// The Phrase will be converted to a Cell. + /// + /// a Phrase + public void AddCell(Phrase content) { + AddCell(content, curPosition); + } + + /// + /// Adds a Cell to the Table. + /// + /// a Phrase + /// a System.Drawing.Point + public void AddCell(Phrase content, System.Drawing.Point location) { + Cell cell = new Cell(content); + cell.Border = defaultCell.Border; + cell.BorderWidth = defaultCell.BorderWidth; + cell.BorderColor = defaultCell.BorderColor; + cell.BackgroundColor = defaultCell.BackgroundColor; + cell.HorizontalAlignment = defaultCell.HorizontalAlignment; + cell.VerticalAlignment = defaultCell.VerticalAlignment; + cell.Colspan = defaultCell.Colspan; + cell.Rowspan = defaultCell.Rowspan; + AddCell(cell, location); + } + + /// + /// Adds a Cell to the Table. + /// + /// + /// This is a shortcut for AddCell(Cell cell). + /// The string will be converted to a Cell. + /// + /// a string + public void AddCell(string content) { + AddCell(new Phrase(content), curPosition); + } + + /// + /// Adds a Cell to the Table. + /// + /// + /// This is a shortcut for AddCell(Cell cell, System.Drawing.Point location). + /// The string will be converted to a Cell. + /// + /// a string + /// a point + public void AddCell(string content, System.Drawing.Point location) { + AddCell(new Phrase(content), location); + } + + /// + /// To put a table within the existing table at the current position + /// generateTable will of course re-arrange the widths of the columns. + /// + /// the table you want to insert + public void InsertTable(Table aTable) { + if (aTable == null) throw new Exception("insertTable - table has null-value"); + InsertTable(aTable, curPosition); + } + + /// + /// To put a table within the existing table at the given position + /// generateTable will of course re-arrange the widths of the columns. + /// + /// The Table to add + /// The row where the Cell will be added + /// The column where the Cell will be added + public void InsertTable(Table aTable, int row, int column) { + if (aTable == null) throw new Exception("insertTable - table has null-value"); + InsertTable(aTable, new System.Drawing.Point(row, column)); + } + + /// + /// To put a table within the existing table at the given position + /// generateTable will of course re-arrange the widths of the columns. + /// + /// the table you want to insert + /// a System.Drawing.Point + public void InsertTable(Table aTable, System.Drawing.Point p) { + if (aTable == null) throw new Exception("insertTable - table has null-value"); + + mTableInserted = true; + aTable.Complete(); + if (p.Y > columns) + throw new ArgumentException("insertTable -- wrong columnposition("+ p.Y + ") of location; max =" + columns); + int rowCount = p.X + 1 - rows.Count; + int i = 0; + if ( rowCount > 0 ) { //create new rows ? + for (; i < rowCount; i++) { + rows.Add(new Row(columns)); + } + } + + ((Row) rows[p.X]).SetElement(aTable,p.Y); + + CurrentLocationToNextValidPosition = p; + } + + /// + /// Will fill empty cells with valid blank Cells + /// + public void Complete() { + if (mTableInserted == true) { + MergeInsertedTables(); // integrate tables in the table + mTableInserted = false; + } + if (autoFillEmptyCells == true) { + FillEmptyMatrixCells(); + } + } + + /// + /// Changes the border in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new border value + public int DefaultCellBorder { + set { + defaultCell.Border = value; + } + } + + /// + /// Changes the width of the borders in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new width + public float DefaultCellBorderWidth { + set { + defaultCell.BorderWidth = value; + } + } + + /// + /// Changes the bordercolor in the default layout of the Cells + /// added with method AddCell(string content). + /// + public Color DefaultCellBorderColor { + set { + defaultCell.BorderColor = value; + } + } + + /// + /// Changes the backgroundcolor in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new color + public Color DefaultCellBackgroundColor { + set { + defaultCell.BackgroundColor = value; + } + } + + /// + /// Changes the grayfill in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new value + public float DefaultCellGrayFill { + set { + if (value >= 0 && value <= 1) { + defaultCell.GrayFill = value; + } + } + } + + /// + /// Changes the horizontalalignment in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new alignment value + public int DefaultHorizontalAlignment { + set { + defaultCell.HorizontalAlignment = value; + } + } + + /// + /// Changes the verticalAlignment in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new alignment value + public int DefaultVerticalAlignment { + set { + defaultCell.VerticalAlignment = value; + } + } + + /// + /// Changes the rowspan in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new rowspan value + public int DefaultRowspan { + set { + defaultCell.Rowspan = value; + } + } + + /// + /// Changes the colspan in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new colspan value + public int DefaultColspan { + set { + defaultCell.Colspan = value; + } + } + + // methods + + /// + /// Sets the unset cell properties to be the table defaults. + /// + /// The cell to set to table defaults as necessary. + private void AssumeTableDefaults(Cell aCell) { + + if (aCell.Border == Rectangle.UNDEFINED) { + aCell.Border = defaultCell.Border; + } + if (aCell.BorderWidth == Rectangle.UNDEFINED) { + aCell.BorderWidth = defaultCell.BorderWidth; + } + if (aCell.BorderColor == null) { + aCell.BorderColor = defaultCell.BorderColor; + } + if (aCell.BackgroundColor == null) { + aCell.BackgroundColor = defaultCell.BackgroundColor; + } + if (aCell.HorizontalAlignment == Element.ALIGN_UNDEFINED) { + aCell.HorizontalAlignment = defaultCell.HorizontalAlignment; + } + if (aCell.VerticalAlignment == Element.ALIGN_UNDEFINED) { + aCell.VerticalAlignment = defaultCell.VerticalAlignment; + } + } + + /// + /// Deletes a column in this table. + /// + /// the number of the column that has to be deleted + public void DeleteColumn(int column) { + float[] newWidths = new float[--columns]; + System.Array.Copy(widths, 0, newWidths, 0, column); + System.Array.Copy(widths, column + 1, newWidths, column, columns - column); + Widths = newWidths; + System.Array.Copy(widths, 0, newWidths, 0, columns); + widths = newWidths; + Row row; + int size = rows.Count; + for (int i = 0; i < size; i++) { + row = (Row) rows[i]; + row.DeleteColumn(column); + rows[i] = row; + } + if (column == columns) { + curPosition.X++; + curPosition.Y = 0; + } + } + + /// + /// Deletes a row. + /// + /// the number of the row to delete + /// true if the row was deleted; false if not + public bool DeleteRow(int row) { + if (row < 0 || row >= rows.Count) { + return false; + } + rows.RemoveAt(row); + curPosition.X--; + return true; + } + + /** + * Deletes all rows in this table. + * (contributed by dperezcar@fcc.es) + */ + + public void DeleteAllRows() { + rows.Clear(); + rows.Add(new Row(columns)); + curPosition.X = 0; + curPosition.Y = 0; + lastHeaderRow = -1; + } + + /// + /// Deletes the last row in this table. + /// + /// true if the row was deleted; false if not + public bool DeleteLastRow() { + return DeleteRow(rows.Count - 1); + } + + /// + /// Marks the last row of the table headers. + /// + /// the number of the last row of the table headers + public int EndHeaders() { + /* patch sep 8 2001 Francesco De Milato */ + lastHeaderRow = curPosition.X - 1; + return lastHeaderRow; + } + + // methods to set the membervariables + + /// + /// Sets the horizontal Element. + /// + /// the new value + public int LastHeaderRow { + set { + lastHeaderRow = value; + } + get { + return lastHeaderRow; + } + } + + /// + /// Sets the alignment of this paragraph. + /// + /// the new alignment as a string + public void SetAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_LEFT)) { + this.alignment = Element.ALIGN_LEFT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.alignment = Element.ALIGN_RIGHT; + return; + } + this.alignment = Element.ALIGN_CENTER; + } + + /// + /// Sets the cellpadding. + /// + /// the new value + public float Padding { + set { + cellpadding = value; + } + } + + /// + /// Sets the cellspacing. + /// + /// the new value + public float Spacing { + set { + cellspacing = value; + } + } + + /// + /// Sets the widths of the different columns (percentages). + /// + /// + /// You can give up relative values of borderwidths. + /// The sum of these values will be considered 100%. + /// The values will be recalculated as percentages of this sum. + /// + /// + ///
+        /// float[] widths = {2, 1, 1};
+        /// table.SetWidths(widths)
+        /// 
+ /// + /// The widths will be: a width of 50% for the first column, + /// 25% for the second and third column. + ///
+ /// an array with values + public float[] Widths { + set { + if (value.Length != columns) { + throw new BadElementException("Wrong number of columns."); + } + + // The sum of all values is 100% + float hundredPercent = 0; + for (int i = 0; i < columns; i++) { + hundredPercent += value[i]; + } + + // The different percentages are calculated + float width; + this.widths[columns - 1] = 100; + for (int i = 0; i < columns - 1; i++) { + width = (100.0f * value[i]) / hundredPercent; + this.widths[i] = width; + this.widths[columns - 1] -= width; + } + } + } + + /// + /// Sets the widths of the different columns (percentages). + /// + /// + /// You can give up relative values of borderwidths. + /// The sum of these values will be considered 100%. + /// The values will be recalculated as percentages of this sum. + /// + /// an array with values + public void SetWidths(int[] widths) { + float[] tb = new float[widths.Length]; + for (int k = 0; k < widths.Length; ++k) + tb[k] = widths[k]; + this.Widths = tb; + } + // methods to retrieve the membervariables + + /// + /// Gets the number of columns. + /// + /// a value + public int Columns { + get { + return columns; + } + } + + /// + /// Gets the number of rows in this Table. + /// + /// the number of rows in this Table + public int Size { + get { + return rows.Count; + } + } + + /// + /// Gets the proportional widths of the columns in this Table. + /// + /// the proportional widths of the columns in this Table + public float[] ProportionalWidths { + get { + return widths; + } + } + + /// + /// Gets an Iterator of all the Rows. + /// + /// an IEnumerator + public IEnumerator GetEnumerator() { + return rows.GetEnumerator(); + } + + /// + /// Get/set the horizontal Element. + /// + /// a value + public int Alignment{ + get { + return alignment; + } + + set { + alignment = value; + } + } + + /// + /// Get/set the cellpadding. + /// + /// the cellpadding + public float Cellpadding { + get { + return cellpadding; + } + + set { + this.cellpadding = value; + } + } + + /// + /// Get/set the cellspacing. + /// + /// the cellspacing + public float Cellspacing { + get { + return cellspacing; + } + + set { + this.cellspacing = value; + } + } + + /// + /// Get/set the table width (a percentage). + /// + /// the table width (a percentage) + public override float Width { + get { + return width; + } + set { + this.width = value; + } + } + + /// + /// Gets the dimension of this table + /// + /// the dimension + public System.Drawing.Dimension Dimension { + get { + return new System.Drawing.Dimension(columns, rows.Count); + } + } + + /// + /// returns the element at the position row, column + /// (Cast to Cell or Table) + /// + /// + /// + /// an object + public object GetElement(int row, int column) { + return ((Row) rows[row]).GetCell(column); + } + + /// + /// Integrates all added tables and recalculates column widths. + /// + private void MergeInsertedTables() { + int i=0, j=0; + float [] lNewWidths = null; + int [] lDummyWidths = new int[columns]; // to keep track in how many new cols this one will be split + float[][] lDummyColumnWidths = new float[columns][]; // bugfix Tony Copping + int [] lDummyHeights = new int[rows.Count]; // to keep track in how many new rows this one will be split + ArrayList newRows = null; + bool isTable=false; + int lTotalRows = 0, lTotalColumns = 0; + int lNewMaxRows = 0, lNewMaxColumns = 0; + + Table lDummyTable = null; + + // first we'll add new columns when needed + // check one column at a time, find maximum needed nr of cols + // Search internal tables and find one with max columns + for (j=0; j < columns; j++) { + lNewMaxColumns = 1; // value to hold in how many columns the current one will be split + float [] tmpWidths = null; + for (i=0; i < rows.Count; i++) { + if (((Row) rows[i]).GetCell(j) is Table) { + isTable=true; + lDummyTable = ((Table) ((Row) rows[i]).GetCell(j)); + if ( tmpWidths == null) { + tmpWidths = lDummyTable.widths; + lNewMaxColumns=tmpWidths.Length; + } + else { + int cols = lDummyTable.Dimension.width; + float [] tmpWidthsN = new float[ cols * tmpWidths.Length]; + float tpW=0, btW=0, totW=0; + int tpI=0, btI=0, totI=0; + tpW+=tmpWidths[0]; + btW+=lDummyTable.widths[0]; + while ( tpItpW) { + tmpWidthsN[totI] = tpW-totW; + tpI++; + if (tpI lNewMaxRows ) { + lNewMaxRows = lDummyTable.Dimension.height; + } + } + } + lTotalRows += lNewMaxRows; + lDummyHeights [i] = lNewMaxRows; + } + + if ( (lTotalColumns != columns) || (lTotalRows != rows.Count) || isTable) // NO ADJUSTMENT + { + // ** WIDTH + // set correct width for new columns + // divide width over new nr of columns + // Take new max columns of internal table and work out widths for each col + lNewWidths = new float [lTotalColumns]; + int lDummy = 0; + for (int tel=0; tel < widths.Length;tel++) { + if ( lDummyWidths[tel] != 1) { + // divide + for (int tel2 = 0; tel2 < lDummyWidths[tel]; tel2++) { + lNewWidths[lDummy] = widths[tel] * lDummyColumnWidths[tel][tel2] / 100f; // bugfix Tony Copping + lDummy++; + } + } + else { + lNewWidths[lDummy] = widths[tel]; + lDummy++; + } + } + + // ** FILL OUR NEW TABLE + // generate new table + // set new widths + // copy old values + newRows = new ArrayList(lTotalRows); + for (i = 0; i < lTotalRows; i++) { + newRows.Add(new Row(lTotalColumns)); + } + int lDummyRow = 0, lDummyColumn = 0; // to remember where we are in the new, larger table + Object lDummyElement = null; + for (i=0; i < rows.Count; i++) { + lDummyColumn = 0; + lNewMaxRows = 1; + for (j=0; j < columns; j++) { + if (((Row) rows[i]).GetCell(j) is Table ) // copy values from embedded table + { + lDummyTable = (Table) ((Row) rows[i]).GetCell(j); + + // Work out where columns in table table correspond to columns in current table + int[] colMap = new int[lDummyTable.widths.Length+1]; + int cb=0, ct=0; + + for ( ; cb + /// Integrates all added tables and recalculates column widths. + /// + private void FillEmptyMatrixCells() { + for (int i=0; i < rows.Count; i++) { + for (int j=0; j < columns; j++) { + if ( ((Row) rows[i]).IsReserved(j) == false) { + AddCell(defaultCell, new System.Drawing.Point(i, j)); + } + } + } + } + + /// + /// check if Cell 'fits' the table. + /// + /// + ///
  • rowspan/colspan not beyond borders + ///
  • spanned cell don't overlap existing cells
+ ///
+ /// the cell that has to be checked + /// the location where the cell has to be placed + /// + private bool IsValidLocation(Cell aCell, System.Drawing.Point aLocation) { + // rowspan not beyond last column + if ( aLocation.X < rows.Count ) { // if false : new location is already at new, not-yet-created area so no check + if ((aLocation.Y + aCell.Colspan) > columns) { + return false; + } + + int difx = ((rows.Count - aLocation.X) > aCell.Rowspan) ? aCell.Rowspan : rows.Count - aLocation.X; + int dify = ((columns - aLocation.Y) > aCell.Colspan) ? aCell.Colspan : columns - aLocation.Y; + // no other content at cells targetted by rowspan/colspan + for (int i=aLocation.X; i < (aLocation.X + difx); i++) { + for (int j=aLocation.Y; j < (aLocation.Y + dify); j++) { + if ( ((Row) rows[i]).IsReserved(j) == true ) { + return false; + } + } + } + } + else { + if ((aLocation.Y + aCell.Colspan) > columns) { + return false; + } + } + + return true; + } + + /// + /// Inserts a Cell in a cell-array and reserves cells defined by row-/colspan. + /// + /// some rows + /// the cell that has to be inserted + /// the position where the cell has to be placed + private void PlaceCell(ArrayList someRows, Cell aCell, System.Drawing.Point aPosition) { + int i; + Row row = null; + int rowCount = aPosition.X + aCell.Rowspan - someRows.Count; + AssumeTableDefaults(aCell); + if ( (aPosition.X + aCell.Rowspan) > someRows.Count ) { //create new rows ? + for (i = 0; i < rowCount; i++) { + row = new Row(columns); + someRows.Add(row); + } + } + + // reserve cell in rows below + for (i = aPosition.X + 1; i < (aPosition.X + aCell.Rowspan); i++) { + if ( !((Row) someRows[i]).Reserve(aPosition.Y, aCell.Colspan)) { + + // should be impossible to come here :-) + throw new Exception("addCell - error in reserve"); + } + } + row = (Row) someRows[aPosition.X]; + row.AddElement(aCell, aPosition.Y); + + } + + /// + /// Gives you the posibility to add columns. + /// + /// the number of columns to add + public void AddColumns(int aColumns) { + ArrayList newRows = new ArrayList(rows.Count); + + int newColumns = columns + aColumns; + Row row; + for (int i = 0; i < rows.Count; i++) { + row = new Row(newColumns); + for (int j = 0; j < columns; j++) { + row.SetElement(((Row) rows[i]).GetCell(j) ,j); + } + for (int j = columns; j < newColumns && i < curPosition.X; j++) { + row.SetElement(null, j); + } + newRows.Add(row); + } + + // applied 1 column-fix; last column needs to have a width of 0 + float [] newWidths = new float[newColumns]; + System.Array.Copy(widths, 0, newWidths, 0, columns); + for (int j = columns; j < newColumns ; j++) { + newWidths[j] = 0; + } + columns = newColumns; + widths = newWidths; + rows = newRows; + } + + /// + /// Gets an array with the positions of the borders between every column. + /// + /// + /// This method translates the widths expressed in percentages into the + /// x-coordinate of the borders of the columns on a real document. + /// + /// this is the position of the first border at the left (cellpadding not included) + /// + /// this is the space between the first border at the left + /// and the last border at the right (cellpadding not included) + /// + /// an array with borderpositions + public float[] GetWidths(float left, float totalWidth) { + // for x columns, there are x+1 borders + float[] w = new float[columns + 1]; + float wPercentage; + if (locked) { + wPercentage = 100 * width / totalWidth; + } + else { + wPercentage = width; + } + // the border at the left is calculated + switch (alignment) { + case Element.ALIGN_LEFT: + w[0] = left; + break; + case Element.ALIGN_RIGHT: + w[0] = left + (totalWidth * (100 - wPercentage)) / 100; + break; + case Element.ALIGN_CENTER: + default: + w[0] = left + (totalWidth * (100 - wPercentage)) / 200; + break; + } + // the total available width is changed + totalWidth = (totalWidth * wPercentage) / 100; + // the inner borders are calculated + for (int i = 1; i < columns; i++) { + w[i] = w[i - 1] + (widths[i - 1] * totalWidth / 100); + } + // the border at the right is calculated + w[columns] = w[0] + totalWidth; + return w; + } + + /// + /// Sets current col/row to Valid(empty) pos after addCell/Table + /// + /// a System.Drawing.Point + private System.Drawing.Point CurrentLocationToNextValidPosition { + set { + // set latest location to next valid position + int i, j; + i = value.X; + j = value.Y; + do { + if ( (j + 1) == columns ) { // goto next row + i++; + j = 0; + } + else { + j++; + } + } + while ( + (i < rows.Count) && (j < columns) && (((Row) rows[i]).IsReserved(j) == true) + ); + curPosition = new System.Drawing.Point(i, j); + } + } + + private void ErrorDimensions() { + throw new Exception("Dimensions of a Table can't be calculated. See the FAQ."); + } + + /** + * Returns the next row 0-based index where a new cell would be added. + * (contributed by dperezcar@fcc.es) + * @return x coordinate for the next row + */ + public int NextRow { + get { + return curPosition.X; + } + } + + /** + * Returns the next column 0-based index where a new cell would be added. + * (contributed by dperezcar@fcc.es) + * @return y coordinate for the next row + */ + public int NextColumn { + get { + return curPosition.Y; + } + } + + public override float Bottom { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float Left { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float Right { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float Top { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float GetBottom(float margin) { + ErrorDimensions(); + return 0; + } + + public override float GetLeft(float margin) { + ErrorDimensions(); + return 0; + } + + public override float GetRight(float margin) { + ErrorDimensions(); + return 0; + } + + public override float GetTop(float margin) { + ErrorDimensions(); + return 0; + } + + /** + * Create a PdfPTable based on this Table object. + * @return a PdfPTable object + * @throws BadElementException + */ + public PdfPTable CreatePdfPTable() { + if (!convert2pdfptable) { + throw new BadElementException("No error, just an old style table"); + } + AutoFillEmptyCells = true; + Complete(); + PdfPTable pdfptable = new PdfPTable(widths); + pdfptable.ElementComplete = complete; + if (NotAddedYet) + pdfptable.SkipFirstHeader = true; + pdfptable.TableEvent = SimpleTable.GetDimensionlessInstance(this, cellspacing); + pdfptable.HeaderRows = lastHeaderRow + 1; + pdfptable.SplitLate = cellsFitPage; + pdfptable.KeepTogether = tableFitsPage; + if (!float.IsNaN(offset)) { + pdfptable.SpacingBefore = offset; + } + pdfptable.HorizontalAlignment = alignment; + if (locked) { + pdfptable.TotalWidth = width; + pdfptable.LockedWidth = true; + } + else { + pdfptable.WidthPercentage = width; + } + foreach (Row row in this) { + IElement cell; + PdfPCell pcell; + for (int i = 0; i < row.Columns; i++) { + if ((cell = (IElement)row.GetCell(i)) != null) { + if (cell is Table) { + pcell = new PdfPCell(((Table)cell).CreatePdfPTable()); + } + else if (cell is Cell) { + pcell = ((Cell)cell).CreatePdfPCell(); + pcell.Padding = cellpadding + cellspacing / 2f; + pcell.CellEvent = SimpleCell.GetDimensionlessInstance((Cell)cell, cellspacing); + } + else { + pcell = new PdfPCell(); + } + pdfptable.AddCell(pcell); + } + } + } + return pdfptable; + } + + /** + * If set to true, iText will try to convert the Table to a PdfPTable. + * @param convert2pdfptable true if you want iText to try to convert the Table to a PdfPTable + */ + public bool Convert2pdfptable { + get { + return convert2pdfptable; + } + set { + this.convert2pdfptable = value; + } + } + + public bool Locked { + get { + return locked; + } + set { + locked = value; + } + } + + /** + * Indicates if this is the first time the section is added. + * @since iText2.0.8 + * @return true if the section wasn't added yet + */ + public bool NotAddedYet { + get { + return notAddedYet; + } + set { + notAddedYet = value; + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#flushContent() + */ + public void FlushContent() { + this.NotAddedYet = false; + ArrayList headerrows = new ArrayList(); + for (int i = 0; i < LastHeaderRow + 1; i++) { + headerrows.Add(rows[i]); + } + rows = headerrows; + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#isComplete() + */ + public bool ElementComplete { + get { + return complete; + } + set { + complete = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Utilities.cs b/iTechSharp/iTextSharp/text/Utilities.cs new file mode 100644 index 0000000..d4e1312 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Utilities.cs @@ -0,0 +1,267 @@ +using System; +using System.util; +using System.Collections; +using System.Text; +using System.IO; +using iTextSharp.text.pdf; +/* + * $Id: Utilities.cs,v 1.9 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + + /** + * A collection of convenience methods that were present in many different iText + * classes. + */ + + public class Utilities { + + /// + /// + /// + /// + /// + public static ICollection GetKeySet(Properties table) { + return (table == null) ? new Properties().Keys : table.Keys; + } + + /** + * Utility method to extend an array. + * @param original the original array or null + * @param item the item to be added to the array + * @return a new array with the item appended + */ + public static Object[][] AddToArray(Object[][] original, Object[] item) { + if (original == null) { + original = new Object[1][]; + original[0] = item; + return original; + } + else { + Object[][] original2 = new Object[original.Length + 1][]; + Array.Copy(original, 0, original2, 0, original.Length); + original2[original.Length] = item; + return original2; + } + } + + /** + * Checks for a true/false value of a key in a Properties object. + * @param attributes + * @param key + * @return + */ + public static bool CheckTrueOrFalse(Properties attributes, String key) { + return Util.EqualsIgnoreCase("true", attributes[key]); + } + + /// + /// This method makes a valid URL from a given filename. + /// + /// + /// + /// + /// a given filename + /// a valid URL + public static Uri ToURL(string filename) { + try { + return new Uri(filename); + } + catch { + return new Uri("file:///" + filename); + } + } + + /** + * Unescapes an URL. All the "%xx" are replaced by the 'xx' hex char value. + * @param src the url to unescape + * @return the eunescaped value + */ + public static String UnEscapeURL(String src) { + StringBuilder bf = new StringBuilder(); + char[] s = src.ToCharArray(); + for (int k = 0; k < s.Length; ++k) { + char c = s[k]; + if (c == '%') { + if (k + 2 >= s.Length) { + bf.Append(c); + continue; + } + int a0 = PRTokeniser.GetHex((int)s[k + 1]); + int a1 = PRTokeniser.GetHex((int)s[k + 2]); + if (a0 < 0 || a1 < 0) { + bf.Append(c); + continue; + } + bf.Append((char)(a0 * 16 + a1)); + k += 2; + } + else + bf.Append(c); + } + return bf.ToString(); + } + + private static byte[] skipBuffer = new byte[4096]; + + /// + /// This method is an alternative for the Stream.Skip()-method + /// that doesn't seem to work properly for big values of size. + /// + /// the stream + /// the number of bytes to skip + public static void Skip(Stream istr, int size) { + while (size > 0) { + int r = istr.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, size)); + if (r <= 0) + return; + size -= r; + } + } + + /** + * Measurement conversion from millimeters to points. + * @param value a value in millimeters + * @return a value in points + * @since 2.1.2 + */ + public static float MillimetersToPoints(float value) { + return InchesToPoints(MillimetersToInches(value)); + } + + /** + * Measurement conversion from millimeters to inches. + * @param value a value in millimeters + * @return a value in inches + * @since 2.1.2 + */ + public static float MillimetersToInches(float value) { + return value / 25.4f; + } + + /** + * Measurement conversion from points to millimeters. + * @param value a value in points + * @return a value in millimeters + * @since 2.1.2 + */ + public static float PointsToMillimeters(float value) { + return InchesToMillimeters(PointsToInches(value)); + } + + /** + * Measurement conversion from points to inches. + * @param value a value in points + * @return a value in inches + * @since 2.1.2 + */ + public static float PointsToInches(float value) { + return value / 72f; + } + + /** + * Measurement conversion from inches to millimeters. + * @param value a value in inches + * @return a value in millimeters + * @since 2.1.2 + */ + public static float InchesToMillimeters(float value) { + return value * 25.4f; + } + + /** + * Measurement conversion from inches to points. + * @param value a value in inches + * @return a value in points + * @since 2.1.2 + */ + public static float InchesToPoints(float value) { + return value * 72f; + } + + public static bool IsSurrogateHigh(char c) { + return c >= '\ud800' && c <= '\udbff'; + } + + public static bool IsSurrogateLow(char c) { + return c >= '\udc00' && c <= '\udfff'; + } + + public static bool IsSurrogatePair(string text, int idx) { + if (idx < 0 || idx > text.Length - 2) + return false; + return IsSurrogateHigh(text[idx]) && IsSurrogateLow(text[idx + 1]); + } + + public static bool IsSurrogatePair(char[] text, int idx) { + if (idx < 0 || idx > text.Length - 2) + return false; + return IsSurrogateHigh(text[idx]) && IsSurrogateLow(text[idx + 1]); + } + + public static int ConvertToUtf32(char highSurrogate, char lowSurrogate) { + return (((highSurrogate - 0xd800) * 0x400) + (lowSurrogate - 0xdc00)) + 0x10000; + } + + public static int ConvertToUtf32(char[] text, int idx) { + return (((text[idx] - 0xd800) * 0x400) + (text[idx + 1] - 0xdc00)) + 0x10000; + } + + public static int ConvertToUtf32(string text, int idx) { + return (((text[idx] - 0xd800) * 0x400) + (text[idx + 1] - 0xdc00)) + 0x10000; + } + + public static string ConvertFromUtf32(int codePoint) { + if (codePoint < 0x10000) + return Char.ToString((char)codePoint); + codePoint -= 0x10000; + return new string(new char[]{(char)((codePoint / 0x400) + 0xd800), (char)((codePoint % 0x400) + 0xdc00)}); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/ZapfDingbatsList.cs b/iTechSharp/iTextSharp/text/ZapfDingbatsList.cs new file mode 100644 index 0000000..eaf22cc --- /dev/null +++ b/iTechSharp/iTextSharp/text/ZapfDingbatsList.cs @@ -0,0 +1,85 @@ +using System; + +namespace iTextSharp.text +{ + /** + * + * A special-version of LIST whitch use zapfdingbats-letters. + * + * @see com.lowagie.text.List + * @author Michael Niedermair and Bruno Lowagie + */ + public class ZapfDingbatsList : List { + /** + * char-number in zapfdingbats + */ + protected int zn; + + /** + * Creates a ZapfDingbatsList + * + * @param zn a char-number + */ + public ZapfDingbatsList(int zn) : base(true) { + this.zn = zn; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * Creates a ZapfDingbatsList + * + * @param zn a char-number + * @param symbolIndent indent + */ + public ZapfDingbatsList(int zn, int symbolIndent) : base(true, symbolIndent) { + this.zn = zn; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * set the char-number + * @param zn a char-number + */ + public int CharNumber { + set { + this.zn = value; + } + get { + return this.zn; + } + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + chunk.Append(((char)zn).ToString()); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is String) { + return this.Add(new ListItem((string) o)); + } + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs b/iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs new file mode 100644 index 0000000..5b0d108 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs @@ -0,0 +1,100 @@ +using System; + +namespace iTextSharp.text +{ + /** + * + * A special-version of LIST whitch use zapfdingbats-numbers (1..10). + * + * @see com.lowagie.text.List + * @version 2003-06-22 + * @author Michael Niedermair + */ + public class ZapfDingbatsNumberList : List { + + /** + * which type + */ + protected int type; + + /** + * Creates a ZapdDingbatsNumberList + * @param type the type of list + * @param symbolIndent indent + */ + public ZapfDingbatsNumberList(int type) : base(true) { + this.type = type; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * Creates a ZapdDingbatsNumberList + * @param type the type of list + * @param symbolIndent indent + */ + public ZapfDingbatsNumberList(int type, int symbolIndent) : base(true, symbolIndent) { + this.type = type; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * get the type + * + * @return char-number + */ + public int NumberType { + get { + return type; + } + set { + type = value; + } + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + switch (type ) { + case 0: + chunk.Append(((char)(first + list.Count + 171)).ToString()); + break; + case 1: + chunk.Append(((char)(first + list.Count + 181)).ToString()); + break; + case 2: + chunk.Append(((char)(first + list.Count + 191)).ToString()); + break; + default: + chunk.Append(((char)(first + list.Count + 201)).ToString()); + break; + } + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is String) { + return this.Add(new ListItem((string) o)); + } + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/factories/ElementFactory.cs b/iTechSharp/iTextSharp/text/factories/ElementFactory.cs new file mode 100644 index 0000000..06e52b0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/ElementFactory.cs @@ -0,0 +1,533 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.html; +using iTextSharp.text.factories; +/* + * $Id: ElementFactory.cs,v 1.9 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.factories { + + /** + * This class is able to create Element objects based on a list of properties. + */ + + public class ElementFactory { + + public static Chunk GetChunk(Properties attributes) { + Chunk chunk = new Chunk(); + + chunk.Font = FontFactory.GetFont(attributes); + String value; + + value = attributes[ElementTags.ITEXT]; + if (value != null) { + chunk.Append(value); + } + value = attributes[ElementTags.LOCALGOTO]; + if (value != null) { + chunk.SetLocalGoto(value); + } + value = attributes[ElementTags.REMOTEGOTO]; + if (value != null) { + String page = attributes[ElementTags.PAGE]; + if (page != null) { + chunk.SetRemoteGoto(value, int.Parse(page)); + } + else { + String destination = attributes[ElementTags.DESTINATION]; + if (destination != null) { + chunk.SetRemoteGoto(value, destination); + } + } + } + value = attributes[ElementTags.LOCALDESTINATION]; + if (value != null) { + chunk.SetLocalDestination(value); + } + value = attributes[ElementTags.SUBSUPSCRIPT]; + if (value != null) { + chunk.SetTextRise(float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[Markup.CSS_KEY_VERTICALALIGN]; + if (value != null && value.EndsWith("%")) { + float p = float.Parse(value.Substring(0, value.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo) / 100f; + chunk.SetTextRise(p * chunk.Font.Size); + } + value = attributes[ElementTags.GENERICTAG]; + if (value != null) { + chunk.SetGenericTag(value); + } + value = attributes[ElementTags.BACKGROUNDCOLOR]; + if (value != null) { + chunk.SetBackground(Markup.DecodeColor(value)); + } + return chunk; + } + + public static Phrase GetPhrase(Properties attributes) { + Phrase phrase = new Phrase(); + phrase.Font = FontFactory.GetFont(attributes); + String value; + value = attributes[ElementTags.LEADING]; + if (value != null) { + phrase.Leading = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[Markup.CSS_KEY_LINEHEIGHT]; + if (value != null) { + phrase.Leading = Markup.ParseLength(value); + } + value = attributes[ElementTags.ITEXT]; + if (value != null) { + Chunk chunk = new Chunk(value); + if ((value = attributes[ElementTags.GENERICTAG]) != null) { + chunk.SetGenericTag(value); + } + phrase.Add(chunk); + } + return phrase; + } + + public static Anchor GetAnchor(Properties attributes) { + Anchor anchor = new Anchor(GetPhrase(attributes)); + String value; + value = attributes[ElementTags.NAME]; + if (value != null) { + anchor.Name = value; + } + value = (String)attributes.Remove(ElementTags.REFERENCE); + if (value != null) { + anchor.Reference = value; + } + return anchor; + } + + public static Paragraph GetParagraph(Properties attributes) { + Paragraph paragraph = new Paragraph(GetPhrase(attributes)); + String value; + value = attributes[ElementTags.ALIGN]; + if (value != null) { + paragraph.SetAlignment(value); + } + value = attributes[ElementTags.INDENTATIONLEFT]; + if (value != null) { + paragraph.IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.INDENTATIONRIGHT]; + if (value != null) { + paragraph.IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + return paragraph; + } + + public static ListItem GetListItem(Properties attributes) { + ListItem item = new ListItem(GetParagraph(attributes)); + return item; + } + + public static List GetList(Properties attributes) { + List list = new List(); + + list.Numbered = Utilities.CheckTrueOrFalse(attributes, ElementTags.NUMBERED); + list.Lettered = Utilities.CheckTrueOrFalse(attributes, ElementTags.LETTERED); + list.Lowercase = Utilities.CheckTrueOrFalse(attributes, ElementTags.LOWERCASE); + list.Autoindent = Utilities.CheckTrueOrFalse(attributes, ElementTags.AUTO_INDENT_ITEMS); + list.Alignindent = Utilities.CheckTrueOrFalse(attributes, ElementTags.ALIGN_INDENTATION_ITEMS); + + String value; + + value = attributes[ElementTags.FIRST]; + if (value != null) { + char character = value[0]; + if (char.IsLetter(character) ) { + list.First = (int)character; + } + else { + list.First = int.Parse(value); + } + } + + value = attributes[ElementTags.LISTSYMBOL]; + if (value != null) { + list.ListSymbol = new Chunk(value, FontFactory.GetFont(attributes)); + } + + value = attributes[ElementTags.INDENTATIONLEFT]; + if (value != null) { + list.IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + value = attributes[ElementTags.INDENTATIONRIGHT]; + if (value != null) { + list.IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + value = attributes[ElementTags.SYMBOLINDENT]; + if (value != null) { + list.SymbolIndent = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + return list; + } + + public static Cell GetCell(Properties attributes) { + Cell cell = new Cell(); + String value; + + cell.SetHorizontalAlignment(attributes[ElementTags.HORIZONTALALIGN]); + cell.SetVerticalAlignment(attributes[ElementTags.VERTICALALIGN]); + value = attributes[ElementTags.WIDTH]; + if (value != null) { + cell.SetWidth(value); + } + value = attributes[ElementTags.COLSPAN]; + if (value != null) { + cell.Colspan = int.Parse(value); + } + value = attributes[ElementTags.ROWSPAN]; + if (value != null) { + cell.Rowspan = int.Parse(value); + } + value = attributes[ElementTags.LEADING]; + if (value != null) { + cell.Leading = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + cell.Header = Utilities.CheckTrueOrFalse(attributes, ElementTags.HEADER); + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.NOWRAP)) { + cell.MaxLines = 1; + } + SetRectangleProperties(cell, attributes); + return cell; + } + + /** + * Creates an Table object based on a list of properties. + * @param attributes + * @return a Table + */ + public static Table GetTable(Properties attributes) { + String value; + Table table; + + value = attributes[ElementTags.WIDTHS]; + if (value != null) { + StringTokenizer widthTokens = new StringTokenizer(value, ";"); + ArrayList values = new ArrayList(); + while (widthTokens.HasMoreTokens()) { + values.Add(widthTokens.NextToken()); + } + table = new Table(values.Count); + float[] widths = new float[table.Columns]; + for (int i = 0; i < values.Count; i++) { + value = (String)values[i]; + widths[i] = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + table.Widths = widths; + } + else { + value = attributes[ElementTags.COLUMNS]; + try { + table = new Table(int.Parse(value)); + } + catch { + table = new Table(1); + } + } + + table.Border = Table.BOX; + table.BorderWidth = 1; + table.DefaultCell.Border = Table.BOX; + + value = attributes[ElementTags.LASTHEADERROW]; + if (value != null) { + table.LastHeaderRow = int.Parse(value); + } + value = attributes[ElementTags.ALIGN]; + if (value != null) { + table.SetAlignment(value); + } + value = attributes[ElementTags.CELLSPACING]; + if (value != null) { + table.Spacing = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.CELLPADDING]; + if (value != null) { + table.Padding = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.OFFSET]; + if (value != null) { + table.Offset = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.WIDTH]; + if (value != null) { + if (value.EndsWith("%")) + table.Width = float.Parse(value.Substring(0, value.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + else { + table.Width = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + table.Locked = true; + } + } + table.TableFitsPage = Utilities.CheckTrueOrFalse(attributes, ElementTags.TABLEFITSPAGE); + table.CellsFitPage = Utilities.CheckTrueOrFalse(attributes, ElementTags.CELLSFITPAGE); + table.Convert2pdfptable = Utilities.CheckTrueOrFalse(attributes, ElementTags.CONVERT2PDFP); + + SetRectangleProperties(table, attributes); + return table; + } + + /** + * Sets some Rectangle properties (for a Cell, Table,...). + */ + private static void SetRectangleProperties(Rectangle rect, Properties attributes) { + String value; + value = attributes[ElementTags.BORDERWIDTH]; + if (value != null) { + rect.BorderWidth = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + int border = 0; + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.LEFT)) { + border |= Rectangle.LEFT_BORDER; + } + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.RIGHT)) { + border |= Rectangle.RIGHT_BORDER; + } + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.TOP)) { + border |= Rectangle.TOP_BORDER; + } + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.BOTTOM)) { + border |= Rectangle.BOTTOM_BORDER; + } + rect.Border = border; + + String r = attributes[ElementTags.RED]; + String g = attributes[ElementTags.GREEN]; + String b = attributes[ElementTags.BLUE]; + if (r != null || g != null || b != null) { + int red = 0; + int green = 0; + int blue = 0; + if (r != null) red = int.Parse(r); + if (g != null) green = int.Parse(g); + if (b != null) blue = int.Parse(b); + rect.BorderColor = new Color(red, green, blue); + } + else { + rect.BorderColor = Markup.DecodeColor(attributes[ElementTags.BORDERCOLOR]); + } + r = (String)attributes.Remove(ElementTags.BGRED); + g = (String)attributes.Remove(ElementTags.BGGREEN); + b = (String)attributes.Remove(ElementTags.BGBLUE); + value = attributes[ElementTags.BACKGROUNDCOLOR]; + if (r != null || g != null || b != null) { + int red = 0; + int green = 0; + int blue = 0; + if (r != null) red = int.Parse(r); + if (g != null) green = int.Parse(g); + if (b != null) blue = int.Parse(b); + rect.BackgroundColor = new Color(red, green, blue); + } + else if (value != null) { + rect.BackgroundColor = Markup.DecodeColor(value); + } + else { + value = attributes[ElementTags.GRAYFILL]; + if (value != null) { + rect.GrayFill = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + } + + public static ChapterAutoNumber GetChapter(Properties attributes) { + ChapterAutoNumber chapter = new ChapterAutoNumber(""); + SetSectionParameters(chapter, attributes); + return chapter; + } + + public static Section GetSection(Section parent, Properties attributes) { + Section section = parent.AddSection(""); + SetSectionParameters(section, attributes); + return section; + } + + private static void SetSectionParameters(Section section, Properties attributes) { + String value; + value = attributes[ElementTags.NUMBERDEPTH]; + if (value != null) { + section.NumberDepth = int.Parse(value); + } + value = attributes[ElementTags.INDENT]; + if (value != null) { + section.Indentation = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.INDENTATIONLEFT]; + if (value != null) { + section.IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.INDENTATIONRIGHT]; + if (value != null) { + section.IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + + /// + /// Returns an Image that has been constructed taking in account + /// the value of some attributes. + /// + /// Some attributes + /// an Image + public static Image GetImage(Properties attributes) { + String value; + + value = attributes[ElementTags.URL]; + if (value == null) + throw new ArgumentException("The URL of the image is missing."); + Image image = Image.GetInstance(value); + + value = attributes[ElementTags.ALIGN]; + int align = 0; + if (value != null) { + if (Util.EqualsIgnoreCase(ElementTags.ALIGN_LEFT, value)) + align |= Image.ALIGN_LEFT; + else if (Util.EqualsIgnoreCase(ElementTags.ALIGN_RIGHT, value)) + align |= Image.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(ElementTags.ALIGN_MIDDLE, value)) + align |= Image.ALIGN_MIDDLE; + } + if (Util.EqualsIgnoreCase("true", attributes[ElementTags.UNDERLYING])) + align |= Image.UNDERLYING; + if (Util.EqualsIgnoreCase("true", attributes[ElementTags.TEXTWRAP])) + align |= Image.TEXTWRAP; + image.Alignment = align; + + value = attributes[ElementTags.ALT]; + if (value != null) { + image.Alt = value; + } + + String x = attributes[ElementTags.ABSOLUTEX]; + String y = attributes[ElementTags.ABSOLUTEY]; + if ((x != null) && (y != null)) { + image.SetAbsolutePosition(float.Parse(x, System.Globalization.NumberFormatInfo.InvariantInfo), + float.Parse(y, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[ElementTags.PLAINWIDTH]; + if (value != null) { + image.ScaleAbsoluteWidth(float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[ElementTags.PLAINHEIGHT]; + if (value != null) { + image.ScaleAbsoluteHeight(float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[ElementTags.ROTATION]; + if (value != null) { + image.Rotation = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + return image; + } + + /** + * Creates an Annotation object based on a list of properties. + * @param attributes + * @return an Annotation + */ + public static Annotation GetAnnotation(Properties attributes) { + float llx = 0, lly = 0, urx = 0, ury = 0; + String value; + + value = attributes[ElementTags.LLX]; + if (value != null) { + llx = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.LLY]; + if (value != null) { + lly = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.URX]; + if (value != null) { + urx = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.URY]; + if (value != null) { + ury = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + String title = attributes[ElementTags.TITLE]; + String text = attributes[ElementTags.CONTENT]; + if (title != null || text != null) { + return new Annotation(title, text, llx, lly, urx, ury); + } + value = attributes[ElementTags.URL]; + if (value != null) { + return new Annotation(llx, lly, urx, ury, value); + } + value = attributes[ElementTags.NAMED]; + if (value != null) { + return new Annotation(llx, lly, urx, ury, int.Parse(value)); + } + String file = attributes[ElementTags.FILE]; + String destination = attributes[ElementTags.DESTINATION]; + String page = (String) attributes.Remove(ElementTags.PAGE); + if (file != null) { + if (destination != null) { + return new Annotation(llx, lly, urx, ury, file, destination); + } + if (page != null) { + return new Annotation(llx, lly, urx, ury, file, int.Parse(page)); + } + } + if (title == null) + title = ""; + if (text == null) + text = ""; + return new Annotation(title, text, llx, lly, urx, ury); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs b/iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs new file mode 100644 index 0000000..13b9eda --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs @@ -0,0 +1,122 @@ +using System; +using iTextSharp.text; +/* + * $Id: GreekAlphabetFactory.cs,v 1.2 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.factories { + + /** + * This class can produce String combinations representing a number built with + * Greek letters (from alpha to omega, then alpha alpha, alpha beta, alpha gamma). + * We are aware of the fact that the original Greek numbering is different; + * See http://www.cogsci.indiana.edu/farg/harry/lan/grknum.htm#ancient + * but this isn't implemented yet; the main reason being the fact that we + * need a font that has the obsolete Greek characters qoppa and sampi. + */ + public class GreekAlphabetFactory { + /** + * Changes an int into a lower case Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetString(int index) { + return GetString(index, true); + } + + /** + * Changes an int into a lower case Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetLowerCaseString(int index) { + return GetString(index); + } + + /** + * Changes an int into a upper case Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetUpperCaseString(int index) { + return GetString(index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + /** + * Changes an int into a Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetString(int index, bool lowercase) { + if (index < 1) return ""; + index--; + + int bytes = 1; + int start = 0; + int symbols = 24; + while (index >= symbols + start) { + bytes++; + start += symbols; + symbols *= 24; + } + + int c = index - start; + char[] value = new char[bytes]; + while (bytes > 0) { + bytes--; + value[bytes] = (char)(c % 24); + if (value[bytes] > 16) value[bytes]++; + value[bytes] += (char)(lowercase ? 945 : 913); + value[bytes] = SpecialSymbol.GetCorrespondingSymbol(value[bytes]); + c /= 24; + } + + return new String(value); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs b/iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs new file mode 100644 index 0000000..f6d5f13 --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs @@ -0,0 +1,122 @@ +using System; +/* + * $Id: RomanAlphabetFactory.cs,v 1.2 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.factories { + + /** + * This class can produce String combinations representing a number. + * "a" to "z" represent 1 to 26, "AA" represents 27, "AB" represents 28, + * and so on; "ZZ" is followed by "AAA". + */ + public class RomanAlphabetFactory { + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'a' to 'z'; + * 1 = a, 2 = b, ..., 26 = z, 27 = aa, 28 = ab,... + */ + public static String GetString(int index) { + if (index < 1) throw new FormatException("You can't translate a negative number into an alphabetical value."); + + index--; + int bytes = 1; + int start = 0; + int symbols = 26; + while (index >= symbols + start) { + bytes++; + start += symbols; + symbols *= 26; + } + + int c = index - start; + char[] value = new char[bytes]; + while (bytes > 0) { + value[--bytes] = (char)( 'a' + (c % 26)); + c /= 26; + } + + return new String(value); + } + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'a' to 'z'; + * 1 = a, 2 = b, ..., 26 = z, 27 = aa, 28 = ab,... + */ + public static String GetLowerCaseString(int index) { + return GetString(index); + } + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'A' to 'Z'; + * 1 = A, 2 = B, ..., 26 = Z, 27 = AA, 28 = AB,... + */ + public static String GetUpperCaseString(int index) { + return GetString(index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'a' to 'z' + * (a = 1, b = 2, ..., z = 26, aa = 27, ab = 28,...). + */ + public static String GetString(int index, bool lowercase) { + if (lowercase) { + return GetLowerCaseString(index); + } + else { + return GetUpperCaseString(index); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs b/iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs new file mode 100644 index 0000000..566caad --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs @@ -0,0 +1,180 @@ +using System; +using System.Text; +/* + * $Id: RomanNumberFactory.cs,v 1.2 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.factories { + /** + * This class can produce String combinations representing a roman number. + */ + public class RomanNumberFactory { + /** + * Helper class for Roman Digits + */ + internal class RomanDigit { + + /** part of a roman number */ + public char digit; + + /** value of the roman digit */ + public int value; + + /** can the digit be used as a prefix */ + public bool pre; + + /** + * Constructs a roman digit + * @param digit the roman digit + * @param value the value + * @param pre can it be used as a prefix + */ + internal RomanDigit(char digit, int value, bool pre) { + this.digit = digit; + this.value = value; + this.pre = pre; + } + } + + /** + * Array with Roman digits. + */ + private static RomanDigit[] roman = { + new RomanDigit('m', 1000, false), + new RomanDigit('d', 500, false), + new RomanDigit('c', 100, true), + new RomanDigit('l', 50, false), + new RomanDigit('x', 10, true), + new RomanDigit('v', 5, false), + new RomanDigit('i', 1, true) + }; + + /** + * Changes an int into a lower case roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetString(int index) { + StringBuilder buf = new StringBuilder(); + + // lower than 0 ? Add minus + if (index < 0) { + buf.Append('-'); + index = -index; + } + + // greater than 3000 + if (index > 3000) { + buf.Append('|'); + buf.Append(GetString(index / 1000)); + buf.Append('|'); + // remainder + index = index - (index / 1000) * 1000; + } + + // number between 1 and 3000 + int pos = 0; + while (true) { + // loop over the array with values for m-d-c-l-x-v-i + RomanDigit dig = roman[pos]; + // adding as many digits as we can + while (index >= dig.value) { + buf.Append(dig.digit); + index -= dig.value; + } + // we have the complete number + if (index <= 0) { + break; + } + // look for the next digit that can be used in a special way + int j = pos; + while (!roman[++j].pre); + + // does the special notation apply? + if (index + roman[j].value >= dig.value) { + buf.Append(roman[j].digit).Append(dig.digit); + index -= dig.value - roman[j].value; + } + pos++; + } + return buf.ToString(); + } + + /** + * Changes an int into a lower case roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetLowerCaseString(int index) { + return GetString(index); + } + + /** + * Changes an int into an upper case roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetUpperCaseString(int index) { + return GetString(index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + /** + * Changes an int into a roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetString(int index, bool lowercase) { + if (lowercase) { + return GetLowerCaseString(index); + } + else { + return GetUpperCaseString(index); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlEncoder.cs b/iTechSharp/iTextSharp/text/html/HtmlEncoder.cs new file mode 100644 index 0000000..c87edbb --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlEncoder.cs @@ -0,0 +1,213 @@ +using System; +using System.Text; +using System.Drawing; + +using iTextSharp.text; + +/* + * $Id: HtmlEncoder.cs,v 1.6 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + /** + * This class converts a String to the HTML-format of a String. + *

+ * To convert the String, each character is examined: + *

    + *
  • ASCII-characters from 000 till 031 are represented as &#xxx;
    + * (with xxx = the value of the character) + *
  • ASCII-characters from 032 t/m 127 are represented by the character itself, except for: + *
      + *
    • '\n' becomes <BR>\n + *
    • " becomes &quot; + *
    • & becomes &amp; + *
    • < becomes &lt; + *
    • > becomes &gt; + *
    + *
  • ASCII-characters from 128 till 255 are represented as &#xxx;
    + * (with xxx = the value of the character) + *
+ *

+ * Example: + *

+     *    String htmlPresentation = HtmlEncoder.Encode("Marie-Thérèse Sørensen");
+     * 

+ * for more info: see O'Reilly; "HTML: The Definitive Guide" (page 164) + * + * @author mario.maccarini@rug.ac.be + */ + + public sealed class HtmlEncoder { + + // membervariables + + /** List with the HTML translation of all the characters. */ + private static String[] htmlCode = new String[256]; + + static HtmlEncoder() { + for (int i = 0; i < 10; i++) { + htmlCode[i] = "�" + i + ";"; + } + + for (int i = 10; i < 32; i++) { + htmlCode[i] = "�" + i + ";"; + } + + for (int i = 32; i < 128; i++) { + htmlCode[i] = ((char)i).ToString(); + } + + // Special characters + htmlCode['\t'] = "\t"; + htmlCode['\n'] = "<" + HtmlTags.NEWLINE + " />\n"; + htmlCode['\"'] = """; // double quote + htmlCode['&'] = "&"; // ampersand + htmlCode['<'] = "<"; // lower than + htmlCode['>'] = ">"; // greater than + + for (int i = 128; i < 256; i++) { + htmlCode[i] = "&#" + i + ";"; + } + } + + + // constructors + + /** + * This class will never be constructed. + *

+ * HtmlEncoder only contains static methods. + */ + + private HtmlEncoder () { } + + // methods + + /** + * Converts a String to the HTML-format of this String. + * + * @param string The String to convert + * @return a String + */ + + public static String Encode(String str) { + int n = str.Length; + char character; + StringBuilder buffer = new StringBuilder(); + // loop over all the characters of the String. + for (int i = 0; i < n; i++) { + character = str[i]; + // the Htmlcode of these characters are added to a StringBuilder one by one + if (character < 256) { + buffer.Append(htmlCode[character]); + } + else { + // Improvement posted by Joachim Eyrich + buffer.Append("&#").Append((int)character).Append(';'); + } + } + return buffer.ToString(); + } + + /** + * Converts a Color into a HTML representation of this Color. + * + * @param color the Color that has to be converted. + * @return the HTML representation of this Color + */ + + public static String Encode(Color color) { + StringBuilder buffer = new StringBuilder("#"); + if (color.R < 16) { + buffer.Append('0'); + } + buffer.Append(System.Convert.ToString(color.R, 16)); + if (color.G < 16) { + buffer.Append('0'); + } + buffer.Append(System.Convert.ToString(color.G, 16)); + if (color.B < 16) { + buffer.Append('0'); + } + buffer.Append(System.Convert.ToString(color.B, 16)); + return buffer.ToString(); + } + + /** + * Translates the alignment value. + * + * @param alignment the alignment value + * @return the translated value + */ + + public static String GetAlignment(int alignment) { + switch (alignment) { + case Element.ALIGN_LEFT: + return HtmlTags.ALIGN_LEFT; + case Element.ALIGN_CENTER: + return HtmlTags.ALIGN_CENTER; + case Element.ALIGN_RIGHT: + return HtmlTags.ALIGN_RIGHT; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + return HtmlTags.ALIGN_JUSTIFIED; + case Element.ALIGN_TOP: + return HtmlTags.ALIGN_TOP; + case Element.ALIGN_MIDDLE: + return HtmlTags.ALIGN_MIDDLE; + case Element.ALIGN_BOTTOM: + return HtmlTags.ALIGN_BOTTOM; + case Element.ALIGN_BASELINE: + return HtmlTags.ALIGN_BASELINE; + default: + return ""; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlParser.cs b/iTechSharp/iTextSharp/text/html/HtmlParser.cs new file mode 100644 index 0000000..293d61c --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlParser.cs @@ -0,0 +1,239 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; + +using iTextSharp.text; +using iTextSharp.text.xml; + +/* + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + ///

+ /// This class can be used to parse an XML file. + /// + public class HtmlParser : XmlParser{ + + /// + /// Constructs an XmlParser. + /// + public HtmlParser() { + } + + /// + /// Parses a given file. + /// + /// + /// + public override void Go(IDocListener document, XmlDocument xDoc) { + parser = new ITextmyHtmlHandler(document); + parser.Parse(xDoc); + } + + /// + /// Parses a given file. + /// + /// + /// + public override void Go(IDocListener document, String file) { + parser = new ITextmyHtmlHandler(document); + parser.Parse(file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + public override void Go(IDocListener document, XmlTextReader reader) { + parser = new ITextmyHtmlHandler(document); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public override void Go(IDocListener document, XmlDocument xDoc, XmlDocument xTagmap) { + parser = new ITextmyHtmlHandler(document, new TagMap(xTagmap)); + parser.Parse(xDoc); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public override void Go(IDocListener document, XmlTextReader reader, String tagmap) { + parser = new ITextmyHtmlHandler(document, new TagMap(tagmap)); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public override void Go(IDocListener document, String file, String tagmap) { + parser = new ITextmyHtmlHandler(document, new TagMap(tagmap)); + parser.Parse(file); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public override void Go(IDocListener document, String file, Hashtable tagmap) { + parser = new ITextmyHtmlHandler(document, tagmap); + parser.Parse(file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public override void Go(IDocListener document, XmlTextReader reader, Hashtable tagmap) { + parser = new ITextmyHtmlHandler(document, tagmap); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + public new static void Parse(IDocListener document, XmlDocument xDoc) { + HtmlParser p = new HtmlParser(); + p.Go(document, xDoc); + } + + /// + /// Parses a given file. + /// + /// + /// + public new static void Parse(IDocListener document, String file) { + HtmlParser p = new HtmlParser(); + p.Go(document, file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + public new static void Parse(IDocListener document, XmlTextReader reader) { + HtmlParser p = new HtmlParser(); + p.Go(document, reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public new static void Parse(IDocListener document, XmlDocument xDoc, XmlDocument xTagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, xDoc, xTagmap); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public new static void Parse(IDocListener document, String file, String tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, file, tagmap); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public new static void Parse(IDocListener document, String file, Hashtable tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, file, tagmap); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public new static void Parse(IDocListener document, XmlTextReader reader, String tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, reader, tagmap); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public new static void Parse(IDocListener document, XmlTextReader reader, Hashtable tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, reader, tagmap); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlPeer.cs b/iTechSharp/iTextSharp/text/html/HtmlPeer.cs new file mode 100644 index 0000000..c0bc0ac --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlPeer.cs @@ -0,0 +1,102 @@ +using System; +using System.Globalization; +using System.Collections; +using iTextSharp.text.xml; +using System.util; + +/* + * $Id: HtmlPeer.cs,v 1.4 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * This interface is implemented by the peer of all the iText objects. + */ + + public class HtmlPeer : XmlPeer { + + /** + * Creates a XmlPeer. + * @param name the iText name of the tag + * @param alias the Html name of the tag + */ + + public HtmlPeer(String name, String alias) : base(name, alias.ToLower(CultureInfo.InvariantCulture)) { + } + + /** + * Sets an alias for an attribute. + * + * @param name the iText tagname + * @param alias the custom tagname + */ + + public override void AddAlias(String name, String alias) { + attributeAliases.Add(alias.ToLower(CultureInfo.InvariantCulture), name); + } + + /** + * @see com.lowagie.text.xml.XmlPeer#getAttributes(org.xml.sax.Attributes) + */ + public override Properties GetAttributes(Hashtable attrs) { + Properties attributes = new Properties(); + attributes.AddAll(attributeValues); + if (defaultContent != null) { + attributes[ElementTags.ITEXT] = defaultContent; + } + if (attrs != null) { + foreach (string key in attrs.Keys) { + attributes.Add(GetName(key).ToLower(CultureInfo.InvariantCulture), (string)attrs[key]); + } + } + return attributes; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlTagMap.cs b/iTechSharp/iTextSharp/text/html/HtmlTagMap.cs new file mode 100644 index 0000000..5eb170f --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlTagMap.cs @@ -0,0 +1,289 @@ +using System; +using System.util; +using System.Collections; +using iTextSharp.text; + +/* + * $Id: HtmlTagMap.cs,v 1.4 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * The Tags-class maps several XHTML-tags to iText-objects. + */ + + public class HtmlTagMap : Hashtable { + + /** + * Constructs an HtmlTagMap. + */ + + public HtmlTagMap() { + HtmlPeer peer; + + peer = new HtmlPeer(ElementTags.ITEXT, HtmlTags.HTML); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.SPAN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CHUNK, HtmlTags.CHUNK); + peer.AddAlias(ElementTags.FONT, HtmlTags.FONT); + peer.AddAlias(ElementTags.SIZE, HtmlTags.SIZE); + peer.AddAlias(ElementTags.COLOR, HtmlTags.COLOR); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.ANCHOR, HtmlTags.ANCHOR); + peer.AddAlias(ElementTags.NAME, HtmlTags.NAME); + peer.AddAlias(ElementTags.REFERENCE, HtmlTags.REFERENCE); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.PARAGRAPH); + peer.AddAlias(ElementTags.ALIGN, HtmlTags.ALIGN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.DIV); + peer.AddAlias(ElementTags.ALIGN, HtmlTags.ALIGN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[0]); + peer.AddValue(ElementTags.SIZE, "20"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[1]); + peer.AddValue(ElementTags.SIZE, "18"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[2]); + peer.AddValue(ElementTags.SIZE, "16"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[3]); + peer.AddValue(ElementTags.SIZE, "14"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[4]); + peer.AddValue(ElementTags.SIZE, "12"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[5]); + peer.AddValue(ElementTags.SIZE, "10"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.LIST, HtmlTags.ORDEREDLIST); + peer.AddValue(ElementTags.NUMBERED, "true"); + peer.AddValue(ElementTags.SYMBOLINDENT, "20"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.LIST, HtmlTags.UNORDEREDLIST); + peer.AddValue(ElementTags.NUMBERED, "false"); + peer.AddValue(ElementTags.SYMBOLINDENT, "20"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.LISTITEM, HtmlTags.LISTITEM); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.I); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_ITALIC); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.EM); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_ITALIC); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.B); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_BOLD); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.STRONG); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_BOLD); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.S); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_LINETHROUGH); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.CODE); + peer.AddValue(ElementTags.FONT, FontFactory.COURIER); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.VAR); + peer.AddValue(ElementTags.FONT, FontFactory.COURIER); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_ITALIC); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.U); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_UNDERLINE); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CHUNK, HtmlTags.SUP); + peer.AddValue(ElementTags.SUBSUPSCRIPT, "6.0"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CHUNK, HtmlTags.SUB); + peer.AddValue(ElementTags.SUBSUPSCRIPT, "-6.0"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.HORIZONTALRULE, HtmlTags.HORIZONTALRULE); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.TABLE, HtmlTags.TABLE); + peer.AddAlias(ElementTags.WIDTH, HtmlTags.WIDTH); + peer.AddAlias(ElementTags.BACKGROUNDCOLOR, HtmlTags.BACKGROUNDCOLOR); + peer.AddAlias(ElementTags.BORDERCOLOR, HtmlTags.BORDERCOLOR); + peer.AddAlias(ElementTags.COLUMNS, HtmlTags.COLUMNS); + peer.AddAlias(ElementTags.CELLPADDING, HtmlTags.CELLPADDING); + peer.AddAlias(ElementTags.CELLSPACING, HtmlTags.CELLSPACING); + peer.AddAlias(ElementTags.BORDERWIDTH, HtmlTags.BORDERWIDTH); + peer.AddAlias(ElementTags.ALIGN, HtmlTags.ALIGN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.ROW, HtmlTags.ROW); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CELL, HtmlTags.CELL); + peer.AddAlias(ElementTags.WIDTH, HtmlTags.WIDTH); + peer.AddAlias(ElementTags.BACKGROUNDCOLOR, HtmlTags.BACKGROUNDCOLOR); + peer.AddAlias(ElementTags.BORDERCOLOR, HtmlTags.BORDERCOLOR); + peer.AddAlias(ElementTags.COLSPAN, HtmlTags.COLSPAN); + peer.AddAlias(ElementTags.ROWSPAN, HtmlTags.ROWSPAN); + peer.AddAlias(ElementTags.NOWRAP, HtmlTags.NOWRAP); + peer.AddAlias(ElementTags.HORIZONTALALIGN, HtmlTags.HORIZONTALALIGN); + peer.AddAlias(ElementTags.VERTICALALIGN, HtmlTags.VERTICALALIGN); + peer.AddValue(ElementTags.HEADER, "false"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CELL, HtmlTags.HEADERCELL); + peer.AddAlias(ElementTags.WIDTH, HtmlTags.WIDTH); + peer.AddAlias(ElementTags.BACKGROUNDCOLOR, HtmlTags.BACKGROUNDCOLOR); + peer.AddAlias(ElementTags.BORDERCOLOR, HtmlTags.BORDERCOLOR); + peer.AddAlias(ElementTags.COLSPAN, HtmlTags.COLSPAN); + peer.AddAlias(ElementTags.ROWSPAN, HtmlTags.ROWSPAN); + peer.AddAlias(ElementTags.NOWRAP, HtmlTags.NOWRAP); + peer.AddAlias(ElementTags.HORIZONTALALIGN, HtmlTags.HORIZONTALALIGN); + peer.AddAlias(ElementTags.VERTICALALIGN, HtmlTags.VERTICALALIGN); + peer.AddValue(ElementTags.HEADER, "true"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.IMAGE, HtmlTags.IMAGE); + peer.AddAlias(ElementTags.URL, HtmlTags.URL); + peer.AddAlias(ElementTags.ALT, HtmlTags.ALT); + peer.AddAlias(ElementTags.PLAINWIDTH, HtmlTags.PLAINWIDTH); + peer.AddAlias(ElementTags.PLAINHEIGHT, HtmlTags.PLAINHEIGHT); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.NEWLINE, HtmlTags.NEWLINE); + this[peer.Alias] = peer; + } + + /** + * Checks if this is the root tag. + * @param tag a tagvalue + * @return true if tag is HTML or html + */ + public static bool IsHtml(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.HTML, tag); + } + + /** + * Checks if this is the head tag. + * @param tag a tagvalue + * @return true if tag is HEAD or head + */ + public static bool IsHead(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.HEAD, tag); + } + + /** + * Checks if this is the meta tag. + * @param tag a tagvalue + * @return true if tag is META or meta + */ + public static bool IsMeta(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.META, tag); + } + + /** + * Checks if this is the linl tag. + * @param tag a tagvalue + * @return true if tag is LINK or link + */ + public static bool IsLink(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.LINK, tag); + } + + /** + * Checks if this is the title tag. + * @param tag a tagvalue + * @return true if tag is TITLE or title + */ + public static bool IsTitle(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.TITLE, tag); + } + + /** + * Checks if this is the root tag. + * @param tag a tagvalue + * @return true if tag is BODY or body + */ + public static bool IsBody(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.BODY, tag); + } + + /** + * Checks if this is a special tag. + * @param tag a tagvalue + * @return true if tag is a HTML, HEAD, META, LINK or BODY tag (case insensitive) + */ + public static bool IsSpecialTag(String tag) { + return IsHtml(tag) || IsHead(tag) || IsMeta(tag) || IsLink(tag) || IsBody(tag); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlTags.cs b/iTechSharp/iTextSharp/text/html/HtmlTags.cs new file mode 100644 index 0000000..760ba03 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlTags.cs @@ -0,0 +1,325 @@ +using System; + +/* + * $Id: HtmlTags.cs,v 1.4 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * A class that contains all the possible tagnames and their attributes. + */ + + public class HtmlTags { + + /** the root tag. */ + public const string HTML = "html"; + + /** the head tag */ + public const string HEAD = "head"; + + /** This is a possible HTML attribute for the HEAD tag. */ + public const string CONTENT = "content"; + + /** the meta tag */ + public const string META = "meta"; + + /** attribute of the root tag */ + public const string SUBJECT = "subject"; + + /** attribute of the root tag */ + public const string KEYWORDS = "keywords"; + + /** attribute of the root tag */ + public const string AUTHOR = "author"; + + /** the title tag. */ + public const string TITLE = "title"; + + /** the script tag. */ + public const string SCRIPT = "script"; + + /** This is a possible HTML attribute for the SCRIPT tag. */ + public const string LANGUAGE = "language"; + + /** This is a possible value for the LANGUAGE attribute. */ + public const string JAVASCRIPT = "JavaScript"; + + /** the body tag. */ + public const string BODY = "body"; + + /** This is a possible HTML attribute for the BODY tag */ + public const string JAVASCRIPT_ONLOAD = "onLoad"; + + /** This is a possible HTML attribute for the BODY tag */ + public const string JAVASCRIPT_ONUNLOAD = "onUnLoad"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string TOPMARGIN = "topmargin"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string BOTTOMMARGIN = "bottommargin"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string LEFTMARGIN = "leftmargin"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string RIGHTMARGIN = "rightmargin"; + + // Phrases, Anchors, Lists and Paragraphs + + /** the chunk tag */ + public const string CHUNK = "font"; + + /** the phrase tag */ + public const string CODE = "code"; + + /** the phrase tag */ + public const string VAR = "var"; + + /** the anchor tag */ + public const string ANCHOR = "a"; + + /** the list tag */ + public const string ORDEREDLIST = "ol"; + + /** the list tag */ + public const string UNORDEREDLIST = "ul"; + + /** the listitem tag */ + public const string LISTITEM = "li"; + + /** the paragraph tag */ + public const string PARAGRAPH = "p"; + + /** attribute of anchor tag */ + public const string NAME = "name"; + + /** attribute of anchor tag */ + public const string REFERENCE = "href"; + + /** attribute of anchor tag */ + public static string[] H = {"h1", "h2", "h3", "h4", "h5", "h6"}; + + // Chunks + + /** attribute of the chunk tag */ + public const string FONT = "face"; + + /** attribute of the chunk tag */ + public const string SIZE = "point-size"; + + /** attribute of the chunk/table/cell tag */ + public const string COLOR = "color"; + + /** some phrase tag */ + public const string EM = "em"; + + /** some phrase tag */ + public const string I = "i"; + + /** some phrase tag */ + public const string STRONG = "strong"; + + /** some phrase tag */ + public const string B = "b"; + + /** some phrase tag */ + public const string S = "s"; + + /** some phrase tag */ + public const string U = "u"; + + /** some phrase tag */ + public const string SUB = "sub"; + + /** some phrase tag */ + public const string SUP = "sup"; + + /** the possible value of a tag */ + public const string HORIZONTALRULE = "hr"; + + // tables/cells + + /** the table tag */ + public const string TABLE = "table"; + + /** the cell tag */ + public const string ROW = "tr"; + + /** the cell tag */ + public const string CELL = "td"; + + /** attribute of the cell tag */ + public const string HEADERCELL = "th"; + + /** attribute of the table tag */ + public const string COLUMNS = "cols"; + + /** attribute of the table tag */ + public const string CELLPADDING = "cellpadding"; + + /** attribute of the table tag */ + public const string CELLSPACING = "cellspacing"; + + /** attribute of the cell tag */ + public const string COLSPAN = "colspan"; + + /** attribute of the cell tag */ + public const string ROWSPAN = "rowspan"; + + /** attribute of the cell tag */ + public const string NOWRAP = "nowrap"; + + /** attribute of the table/cell tag */ + public const string BORDERWIDTH = "border"; + + /** attribute of the table/cell tag */ + public const string WIDTH = "width"; + + /** attribute of the table/cell tag */ + public const string BACKGROUNDCOLOR = "bgcolor"; + + /** attribute of the table/cell tag */ + public const string BORDERCOLOR = "bordercolor"; + + /** attribute of paragraph/image/table tag */ + public const string ALIGN = "align"; + + /** attribute of chapter/section/paragraph/table/cell tag */ + public const string LEFT = "left"; + + /** attribute of chapter/section/paragraph/table/cell tag */ + public const string RIGHT = "right"; + + /** attribute of the cell tag */ + public const string HORIZONTALALIGN = "align"; + + /** attribute of the cell tag */ + public const string VERTICALALIGN = "valign"; + + /** attribute of the table/cell tag */ + public const string TOP = "top"; + + /** attribute of the table/cell tag */ + public const string BOTTOM = "bottom"; + + // Misc + + /** the image tag */ + public const string IMAGE = "img"; + + /** attribute of the image tag */ + public const string URL = "src"; + + /** attribute of the image tag */ + public const string ALT = "alt"; + + /** attribute of the image tag */ + public const string PLAINWIDTH = "width"; + + /** attribute of the image tag */ + public const string PLAINHEIGHT = "height"; + + /** the newpage tag */ + public const string NEWLINE = "br"; + + // alignment attribute values + + /** the possible value of an alignment attribute */ + public const string ALIGN_LEFT = "Left"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_CENTER = "Center"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_RIGHT = "Right"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_JUSTIFIED = "Justify"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_TOP = "Top"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_MIDDLE = "Middle"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_BOTTOM = "Bottom"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_BASELINE = "Baseline"; + + /** the possible value of an alignment attribute */ + public const string DEFAULT = "Default"; + + /** The DIV tag. */ + public const string DIV = "div"; + + /** The SPAN tag. */ + public const string SPAN = "span"; + /** The LINK tag. */ + public const string LINK = "link"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string TEXT_CSS = "text/css"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string REL = "rel"; + + /** This is used for inline css style information */ + public const string STYLE = "style"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string TYPE = "type"; + + /** This is a possible HTML attribute. */ + public const string STYLESHEET = "stylesheet"; + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlWriter.cs b/iTechSharp/iTextSharp/text/html/HtmlWriter.cs new file mode 100644 index 0000000..4e6f8d9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlWriter.cs @@ -0,0 +1,1041 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using System.util; + +using iTextSharp.text; +using iTextSharp.text.pdf; + +/* + * $Id: HtmlWriter.cs,v 1.24 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + /** + * A DocWriter class for HTML. + *

+ * An HtmlWriter can be added as a DocListener + * to a certain Document by getting an instance. + * Every Element added to the original Document + * will be written to the Stream of this HtmlWriter. + *

+ * Example: + *

+     * // creation of the document with a certain size and certain margins
+     * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
+     * try {
+     *    // this will write HTML to the Standard Stream
+     *    HtmlWriter.GetInstance(document, System.out);
+     *    // this will write HTML to a file called text.html
+     *    HtmlWriter.GetInstance(document, new FileOutputStream("text.html"));
+     *    // this will write HTML to for instance the Stream of a HttpServletResponse-object
+     *    HtmlWriter.GetInstance(document, response.GetOutputStream());
+     * }
+     * catch (DocumentException de) {
+     *    System.err.Println(de.GetMessage());
+     * }
+     * // this will close the document and all the OutputStreams listening to it
+     * document.Close();
+     * 
+ */ + + public class HtmlWriter : DocWriter { + + // static membervariables (tags) + + /** This is a possible HTML-tag. */ + public static byte[] BEGINCOMMENT = GetISOBytes(""); + + /** This is a possible HTML-tag. */ + public const string NBSP = " "; + + // membervariables + + /** This is the current font of the HTML. */ + protected Stack currentfont = new Stack(); + + /** This is the standard font of the HTML. */ + protected Font standardfont = new Font(); + + /** This is a path for images. */ + protected String imagepath = null; + + /** Stores the page number. */ + protected int pageN = 0; + + /** This is the textual part of a header */ + protected HeaderFooter header = null; + + /** This is the textual part of the footer */ + protected HeaderFooter footer = null; + + /** Store the markup properties of a MarkedObject. */ + protected Properties markup = new Properties(); + + // constructor + + /** + * Constructs a HtmlWriter. + * + * @param doc The Document that has to be written as HTML + * @param os The Stream the writer has to write to. + */ + + protected HtmlWriter(Document doc, Stream os) : base(doc, os){ + + document.AddDocListener(this); + this.pageN = document.PageNumber; + os.WriteByte(LT); + byte[] tmp = GetISOBytes(HtmlTags.HTML); + os.Write(tmp, 0, tmp.Length); + os.WriteByte(GT); + os.WriteByte(NEWLINE); + os.WriteByte(TAB); + os.WriteByte(LT); + tmp = GetISOBytes(HtmlTags.HEAD); + os.Write(tmp, 0, tmp.Length); + os.WriteByte(GT); + } + + // get an instance of the HtmlWriter + + /** + * Gets an instance of the HtmlWriter. + * + * @param document The Document that has to be written + * @param os The Stream the writer has to write to. + * @return a new HtmlWriter + */ + + public static HtmlWriter GetInstance(Document document, Stream os) { + return new HtmlWriter(document, os); + } + + // implementation of the DocListener methods + + /** + * Signals that an new page has to be started. + * + * @return true if this action succeeded, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + + public override bool NewPage() { + try { + WriteStart(HtmlTags.DIV); + Write(" "); + Write(HtmlTags.STYLE); + Write("=\""); + WriteCssProperty(Markup.CSS_KEY_PAGE_BREAK_BEFORE, Markup.CSS_VALUE_ALWAYS); + Write("\" /"); + os.WriteByte(GT); + } + catch (IOException ioe) { + throw new DocumentException(ioe.Message); + } + return true; + } + + /** + * Signals that an Element was added to the Document. + * + * @return true if the element was added, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + + public override bool Add(IElement element) { + if (pause) { + return false; + } + if (open && !element.IsContent()) { + throw new DocumentException("The document is open; you can only add Elements with content."); + } + switch (element.Type) { + case Element.HEADER: + try { + Header h = (Header) element; + if (HtmlTags.STYLESHEET.Equals(h.Name)) { + WriteLink(h); + } + else if (HtmlTags.JAVASCRIPT.Equals(h.Name)) { + WriteJavaScript(h); + } + else { + WriteHeader(h); + } + } + catch (InvalidCastException) { + } + return true; + case Element.SUBJECT: + case Element.KEYWORDS: + case Element.AUTHOR: + Meta meta = (Meta) element; + WriteHeader(meta); + return true; + case Element.TITLE: + AddTabs(2); + WriteStart(HtmlTags.TITLE); + os.WriteByte(GT); + AddTabs(3); + Write(HtmlEncoder.Encode(((Meta)element).Content)); + AddTabs(2); + WriteEnd(HtmlTags.TITLE); + return true; + case Element.CREATOR: + WriteComment("Creator: " + HtmlEncoder.Encode(((Meta)element).Content)); + return true; + case Element.PRODUCER: + WriteComment("Producer: " + HtmlEncoder.Encode(((Meta)element).Content)); + return true; + case Element.CREATIONDATE: + WriteComment("Creationdate: " + HtmlEncoder.Encode(((Meta)element).Content)); + return true; + case Element.MARKED: + if (element is MarkedSection) { + MarkedSection ms = (MarkedSection)element; + AddTabs(1); + WriteStart(HtmlTags.DIV); + WriteMarkupAttributes(ms.MarkupAttributes); + os.WriteByte(GT); + MarkedObject mo = ((MarkedSection)element).Title; + if (mo != null) { + markup = mo.MarkupAttributes; + mo.Process(this); + } + ms.Process(this); + WriteEnd(HtmlTags.DIV); + return true; + } + else { + MarkedObject mo = (MarkedObject) element; + markup = mo.MarkupAttributes; + return mo.Process(this); + } + default: + Write(element, 2); + return true; + } + } + + /** + * Signals that the Document has been opened and that + * Elements can be added. + *

+ * The HEAD-section of the HTML-document is written. + */ + + public override void Open() { + base.Open(); + WriteComment(Document.Version); + WriteComment("CreationDate: " + DateTime.Now.ToString()); + AddTabs(1); + WriteEnd(HtmlTags.HEAD); + AddTabs(1); + WriteStart(HtmlTags.BODY); + if (document.LeftMargin > 0) { + Write(HtmlTags.LEFTMARGIN, document.LeftMargin.ToString()); + } + if (document.RightMargin > 0) { + Write(HtmlTags.RIGHTMARGIN, document.RightMargin.ToString()); + } + if (document.TopMargin > 0) { + Write(HtmlTags.TOPMARGIN, document.TopMargin.ToString()); + } + if (document.BottomMargin > 0) { + Write(HtmlTags.BOTTOMMARGIN, document.BottomMargin.ToString()); + } + if (pageSize.BackgroundColor != null) { + Write(HtmlTags.BACKGROUNDCOLOR, HtmlEncoder.Encode(pageSize.BackgroundColor)); + } + if (document.JavaScript_onLoad != null) { + Write(HtmlTags.JAVASCRIPT_ONLOAD, HtmlEncoder.Encode(document.JavaScript_onLoad)); + } + if (document.JavaScript_onUnLoad != null) { + Write(HtmlTags.JAVASCRIPT_ONUNLOAD, HtmlEncoder.Encode(document.JavaScript_onUnLoad)); + } + if (document.HtmlStyleClass != null) { + Write(Markup.HTML_ATTR_CSS_CLASS, document.HtmlStyleClass); + } + os.WriteByte(GT); + InitHeader(); // line added by David Freels + } + + /** + * Signals that the Document was closed and that no other + * Elements will be added. + */ + + public override void Close() { + InitFooter(); // line added by David Freels + AddTabs(1); + WriteEnd(HtmlTags.BODY); + os.WriteByte(NEWLINE); + WriteEnd(HtmlTags.HTML); + base.Close(); + } + + // some protected methods + + /** + * Adds the header to the top of the Document + */ + + protected void InitHeader() { + if (header != null) { + Add(header.Paragraph); + } + } + + /** + * Adds the header to the top of the Document + */ + + protected void InitFooter() { + if (footer != null) { + // Set the page number. HTML has no notion of a page, so it should always + // add up to 1 + footer.PageNumber = pageN + 1; + Add(footer.Paragraph); + } + } + + /** + * Writes a Metatag in the header. + * + * @param meta the element that has to be written + * @throws IOException + */ + + protected void WriteHeader(Meta meta) { + AddTabs(2); + WriteStart(HtmlTags.META); + switch (meta.Type) { + case Element.HEADER: + Write(HtmlTags.NAME, ((Header) meta).Name); + break; + case Element.SUBJECT: + Write(HtmlTags.NAME, HtmlTags.SUBJECT); + break; + case Element.KEYWORDS: + Write(HtmlTags.NAME, HtmlTags.KEYWORDS); + break; + case Element.AUTHOR: + Write(HtmlTags.NAME, HtmlTags.AUTHOR); + break; + } + Write(HtmlTags.CONTENT, HtmlEncoder.Encode(meta.Content)); + WriteEnd(); + } + + /** + * Writes a link in the header. + * + * @param header the element that has to be written + * @throws IOException + */ + + protected void WriteLink(Header header) { + AddTabs(2); + WriteStart(HtmlTags.LINK); + Write(HtmlTags.REL, header.Name); + Write(HtmlTags.TYPE, HtmlTags.TEXT_CSS); + Write(HtmlTags.REFERENCE, header.Content); + WriteEnd(); + } + + /** + * Writes a JavaScript section or, if the markup attribute HtmlTags.URL is set, a JavaScript reference in the header. + * + * @param header the element that has to be written + * @throws IOException + */ + + protected void WriteJavaScript(Header header) { + AddTabs(2); + WriteStart(HtmlTags.SCRIPT); + Write(HtmlTags.LANGUAGE, HtmlTags.JAVASCRIPT); + if (markup.Count > 0) { + /* JavaScript reference example: + * + * + */ + Write(HtmlTags.TYPE, Markup.HTML_VALUE_JAVASCRIPT); + os.WriteByte(GT); + AddTabs(2); + Write(Encoding.ASCII.GetString(BEGINCOMMENT) + "\n"); + Write(header.Content); + AddTabs(2); + Write("//" + Encoding.ASCII.GetString(ENDCOMMENT)); + AddTabs(2); + WriteEnd(HtmlTags.SCRIPT); + } + } + + /** + * Writes some comment. + *

+ * This method writes some comment. + * + * @param comment the comment that has to be written + * @throws IOException + */ + + protected void WriteComment(String comment) { + AddTabs(2); + os.Write(BEGINCOMMENT, 0, BEGINCOMMENT.Length); + Write(comment); + os.Write(ENDCOMMENT, 0, ENDCOMMENT.Length); + } + + // public methods + + /** + * Changes the standardfont. + * + * @param standardFont The font + */ + + public void SetStandardFont(Font standardFont) { + this.standardfont = standardFont; + } + + /** + * Checks if a given font is the same as the font that was last used. + * + * @param font the font of an object + * @return true if the font differs + */ + + public bool IsOtherFont(Font font) { + try { + Font cFont = (Font) currentfont.Peek(); + if (cFont.CompareTo(font) == 0) return false; + return true; + } + catch (InvalidOperationException) { + if (standardfont.CompareTo(font) == 0) return false; + return true; + } + } + + /** + * Sets the basepath for images. + *

+ * This is especially useful if you add images using a file, + * rather than an URL. In PDF there is no problem, since + * the images are added inline, but in HTML it is sometimes + * necessary to use a relative path or a special path to some + * images directory. + * + * @param imagepath the new imagepath + */ + + public void SetImagepath(String imagepath) { + this.imagepath = imagepath; + } + + /** + * Resets the imagepath. + */ + + public void ResetImagepath() { + imagepath = null; + } + + /** + * Changes the header of this document. + * + * @param header the new header + */ + + public void SetHeader(HeaderFooter header) { + this.header = header; + } + + /** + * Changes the footer of this document. + * + * @param footer the new footer + */ + + public void SetFooter(HeaderFooter footer) { + this.footer = footer; + } + + /** + * Signals that a String was added to the Document. + * + * @return true if the string was added, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + + public bool Add(String str) { + if (pause) { + return false; + } + Write(str); + return true; + } + + /** + * Writes the HTML representation of an element. + * + * @param element the element + * @param indent the indentation + */ + + protected void Write(IElement element, int indent) { + Properties styleAttributes = null; + switch (element.Type) { + case Element.MARKED: { + try { + Add(element); + } catch (DocumentException) { + } + return; + } + case Element.CHUNK: { + Chunk chunk = (Chunk) element; + // if the chunk contains an image, return the image representation + Image image = chunk.GetImage(); + if (image != null) { + Write(image, indent); + return; + } + + if (chunk.IsEmpty()) return; + Hashtable attributes = chunk.Attributes; + if (attributes != null && attributes[Chunk.NEWPAGE] != null) { + return; + } + bool tag = IsOtherFont(chunk.Font) || markup.Count > 0; + if (tag) { + // start span tag + AddTabs(indent); + WriteStart(HtmlTags.SPAN); + if (IsOtherFont(chunk.Font)) { + Write(chunk.Font, null); + } + WriteMarkupAttributes(markup); + os.WriteByte(GT); + } + if (attributes != null && attributes[Chunk.SUBSUPSCRIPT] != null) { + // start sup or sub tag + if ((float)attributes[Chunk.SUBSUPSCRIPT] > 0) { + WriteStart(HtmlTags.SUP); + } + else { + WriteStart(HtmlTags.SUB); + } + os.WriteByte(GT); + } + // contents + Write(HtmlEncoder.Encode(chunk.Content)); + if (attributes != null && attributes[Chunk.SUBSUPSCRIPT] != null) { + // end sup or sub tag + os.WriteByte(LT); + os.WriteByte(FORWARD); + if ((float)attributes[Chunk.SUBSUPSCRIPT] > 0) { + Write(HtmlTags.SUP); + } + else { + Write(HtmlTags.SUB); + } + os.WriteByte(GT); + } + if (tag) { + // end tag + WriteEnd(Markup.HTML_TAG_SPAN); + } + return; + } + case Element.PHRASE: { + Phrase phrase = (Phrase) element; + styleAttributes = new Properties(); + if (phrase.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = phrase.Leading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(Markup.HTML_TAG_SPAN); + WriteMarkupAttributes(markup); + Write(phrase.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(phrase.Font); + // contents + foreach (IElement i in phrase) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(Markup.HTML_TAG_SPAN); + currentfont.Pop(); + return; + } + case Element.ANCHOR: { + Anchor anchor = (Anchor) element; + styleAttributes = new Properties(); + if (anchor.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = anchor.Leading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.ANCHOR); + if (anchor.Name != null) { + Write(HtmlTags.NAME, anchor.Name); + } + if (anchor.Reference != null) { + Write(HtmlTags.REFERENCE, anchor.Reference); + } + WriteMarkupAttributes(markup); + Write(anchor.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(anchor.Font); + // contents + foreach (IElement i in anchor) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.ANCHOR); + currentfont.Pop(); + return; + } + case Element.PARAGRAPH: { + Paragraph paragraph = (Paragraph) element; + styleAttributes = new Properties(); + if (paragraph.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = paragraph.TotalLeading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.DIV); + WriteMarkupAttributes(markup); + String alignment = HtmlEncoder.GetAlignment(paragraph.Alignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.ALIGN, alignment); + } + Write(paragraph.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(paragraph.Font); + // contents + foreach (IElement i in paragraph) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.DIV); + currentfont.Pop(); + return; + } + case Element.SECTION: + case Element.CHAPTER: { + // part of the start tag + contents + WriteSection((Section) element, indent); + return; + } + case Element.LIST: { + List list = (List) element; + // start tag + AddTabs(indent); + if (list.Numbered) { + WriteStart(HtmlTags.ORDEREDLIST); + } + else { + WriteStart(HtmlTags.UNORDEREDLIST); + } + WriteMarkupAttributes(markup); + os.WriteByte(GT); + // contents + foreach (IElement i in list.Items) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + if (list.Numbered) { + WriteEnd(HtmlTags.ORDEREDLIST); + } + else { + WriteEnd(HtmlTags.UNORDEREDLIST); + } + return; + } + case Element.LISTITEM: { + ListItem listItem = (ListItem) element; + styleAttributes = new Properties(); + if (listItem.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = listItem.TotalLeading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.LISTITEM); + WriteMarkupAttributes(markup); + Write(listItem.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(listItem.Font); + // contents + foreach (IElement i in listItem) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.LISTITEM); + currentfont.Pop(); + return; + } + case Element.CELL: { + Cell cell = (Cell) element; + + // start tag + AddTabs(indent); + if (cell.Header) { + WriteStart(HtmlTags.HEADERCELL); + } + else { + WriteStart(HtmlTags.CELL); + } + WriteMarkupAttributes(markup); + if (cell.BorderWidth != Rectangle.UNDEFINED) { + Write(HtmlTags.BORDERWIDTH, cell.BorderWidth.ToString()); + } + if (cell.BorderColor != null) { + Write(HtmlTags.BORDERCOLOR, HtmlEncoder.Encode(cell.BorderColor)); + } + if (cell.BackgroundColor != null) { + Write(HtmlTags.BACKGROUNDCOLOR, HtmlEncoder.Encode(cell.BackgroundColor)); + } + String alignment = HtmlEncoder.GetAlignment(cell.HorizontalAlignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.HORIZONTALALIGN, alignment); + } + alignment = HtmlEncoder.GetAlignment(cell.VerticalAlignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.VERTICALALIGN, alignment); + } + if (cell.GetWidthAsString() != null) { + Write(HtmlTags.WIDTH, cell.GetWidthAsString()); + } + if (cell.Colspan != 1) { + Write(HtmlTags.COLSPAN, cell.Colspan.ToString()); + } + if (cell.Rowspan != 1) { + Write(HtmlTags.ROWSPAN, cell.Rowspan.ToString()); + } + if (cell.MaxLines == 1) { + Write(HtmlTags.STYLE, "white-space: nowrap;"); + } + os.WriteByte(GT); + // contents + if (cell.IsEmpty()) { + Write(NBSP); + } else { + foreach (IElement i in cell.Elements) { + Write(i, indent + 1); + } + } + // end tag + AddTabs(indent); + if (cell.Header) { + WriteEnd(HtmlTags.HEADERCELL); + } + else { + WriteEnd(HtmlTags.CELL); + } + return; + } + case Element.ROW: { + Row row = (Row) element; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.ROW); + WriteMarkupAttributes(markup); + os.WriteByte(GT); + // contents + IElement cell; + for (int i = 0; i < row.Columns; i++) { + if ((cell = (IElement)row.GetCell(i)) != null) { + Write(cell, indent + 1); + } + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.ROW); + return; + } + case Element.TABLE: { + Table table; + try { + table = (Table) element; + } + catch (InvalidCastException) { + table = ((SimpleTable)element).CreateTable(); + } + table.Complete(); + // start tag + AddTabs(indent); + WriteStart(HtmlTags.TABLE); + WriteMarkupAttributes(markup); + os.WriteByte(SPACE); + Write(HtmlTags.WIDTH); + os.WriteByte(EQUALS); + os.WriteByte(QUOTE); + Write(table.Width.ToString(System.Globalization.CultureInfo.InvariantCulture)); + if (!table.Locked){ + Write("%"); + } + os.WriteByte(QUOTE); + String alignment = HtmlEncoder.GetAlignment(table.Alignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.ALIGN, alignment); + } + Write(HtmlTags.CELLPADDING, table.Cellpadding.ToString(System.Globalization.CultureInfo.InvariantCulture)); + Write(HtmlTags.CELLSPACING, table.Cellspacing.ToString(System.Globalization.CultureInfo.InvariantCulture)); + if (table.BorderWidth != Rectangle.UNDEFINED) { + Write(HtmlTags.BORDERWIDTH, table.BorderWidth.ToString(System.Globalization.CultureInfo.InvariantCulture)); + } + if (table.BorderColor != null) { + Write(HtmlTags.BORDERCOLOR, HtmlEncoder.Encode(table.BorderColor)); + } + if (table.BackgroundColor != null) { + Write(HtmlTags.BACKGROUNDCOLOR, HtmlEncoder.Encode(table.BackgroundColor)); + } + os.WriteByte(GT); + // contents + foreach (Row row in table) { + Write(row, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.TABLE); + return; + } + case Element.ANNOTATION: { + Annotation annotation = (Annotation) element; + WriteComment(annotation.Title + ": " + annotation.Content); + return; + } + case Element.IMGRAW: + case Element.JPEG: + case Element.JPEG2000: + case Element.IMGTEMPLATE: { + Image image = (Image) element; + if (image.Url == null) { + return; + } + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.IMAGE); + String path = image.Url.ToString(); + if (imagepath != null) { + if (path.IndexOf('/') > 0) { + path = imagepath + path.Substring(path.LastIndexOf('/') + 1); + } + else { + path = imagepath + path; + } + } + Write(HtmlTags.URL, path); + if ((image.Alignment & Image.RIGHT_ALIGN) > 0) { + Write(HtmlTags.ALIGN, HtmlTags.ALIGN_RIGHT); + } + else if ((image.Alignment & Image.MIDDLE_ALIGN) > 0) { + Write(HtmlTags.ALIGN, HtmlTags.ALIGN_MIDDLE); + } + else { + Write(HtmlTags.ALIGN, HtmlTags.ALIGN_LEFT); + } + if (image.Alt != null) { + Write(HtmlTags.ALT, image.Alt); + } + Write(HtmlTags.PLAINWIDTH, image.ScaledWidth.ToString()); + Write(HtmlTags.PLAINHEIGHT, image.ScaledHeight.ToString()); + WriteMarkupAttributes(markup); + WriteEnd(); + return; + } + + default: + return; + } + } + + /** + * Writes the HTML representation of a section. + * + * @param section the section to write + * @param indent the indentation + */ + + protected void WriteSection(Section section, int indent) { + if (section.Title != null) { + int depth = section.Depth - 1; + if (depth > 5) { + depth = 5; + } + Properties styleAttributes = new Properties(); + if (section.Title.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = section.Title.TotalLeading.ToString() + "pt"; + // start tag + AddTabs(indent); + WriteStart(HtmlTags.H[depth]); + Write(section.Title.Font, styleAttributes); + String alignment = HtmlEncoder.GetAlignment(section.Title.Alignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.ALIGN, alignment); + } + WriteMarkupAttributes(markup); + os.WriteByte(GT); + currentfont.Push(section.Title.Font); + // contents + foreach (IElement i in section.Title) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.H[depth]); + currentfont.Pop(); + } + foreach (IElement i in section) { + Write(i, indent); + } + } + + /** + * Writes the representation of a Font. + * + * @param font a Font + * @param styleAttributes the style of the font + */ + + protected void Write(Font font, Properties styleAttributes) { + if (font == null || !IsOtherFont(font) /*|| styleAttributes == null*/) return; + Write(" "); + Write(HtmlTags.STYLE); + Write("=\""); + if (styleAttributes != null) { + foreach (String key in styleAttributes.Keys) { + WriteCssProperty(key, styleAttributes[key]); + } + } + if (IsOtherFont(font)) { + WriteCssProperty(Markup.CSS_KEY_FONTFAMILY, font.Familyname); + + if (font.Size != Font.UNDEFINED) { + WriteCssProperty(Markup.CSS_KEY_FONTSIZE, font.Size.ToString() + "pt"); + } + if (font.Color != null) { + WriteCssProperty(Markup.CSS_KEY_COLOR, HtmlEncoder.Encode(font.Color)); + } + + int fontstyle = font.Style; + BaseFont bf = font.BaseFont; + if (bf != null) { + String ps = bf.PostscriptFontName.ToLower(CultureInfo.InvariantCulture); + if (ps.IndexOf("bold") >= 0) { + if (fontstyle == Font.UNDEFINED) + fontstyle = 0; + fontstyle |= Font.BOLD; + } + if (ps.IndexOf("italic") >= 0 || ps.IndexOf("oblique") >= 0) { + if (fontstyle == Font.UNDEFINED) + fontstyle = 0; + fontstyle |= Font.ITALIC; + } + } + if (fontstyle != Font.UNDEFINED && fontstyle != Font.NORMAL) { + switch (fontstyle & Font.BOLDITALIC) { + case Font.BOLD: + WriteCssProperty(Markup.CSS_KEY_FONTWEIGHT, Markup.CSS_VALUE_BOLD); + break; + case Font.ITALIC: + WriteCssProperty(Markup.CSS_KEY_FONTSTYLE, Markup.CSS_VALUE_ITALIC); + break; + case Font.BOLDITALIC: + WriteCssProperty(Markup.CSS_KEY_FONTWEIGHT, Markup.CSS_VALUE_BOLD); + WriteCssProperty(Markup.CSS_KEY_FONTSTYLE, Markup.CSS_VALUE_ITALIC); + break; + } + + // CSS only supports one decoration tag so if both are specified + // only one of the two will display + if ((fontstyle & Font.UNDERLINE) > 0) { + WriteCssProperty(Markup.CSS_KEY_TEXTDECORATION, Markup.CSS_VALUE_UNDERLINE); + } + if ((fontstyle & Font.STRIKETHRU) > 0) { + WriteCssProperty(Markup.CSS_KEY_TEXTDECORATION, Markup.CSS_VALUE_LINETHROUGH); + } + } + } + Write("\""); + } + + /** + * Writes out a CSS property. + */ + protected void WriteCssProperty(String prop, String value) { + Write(new StringBuilder(prop).Append(": ").Append(value).Append("; ").ToString()); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs b/iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs new file mode 100644 index 0000000..2d6fa50 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections; +using System.Globalization; +using System.util; +using iTextSharp.text; +using iTextSharp.text.xml; +using iTextSharp.text.pdf; +using iTextSharp.text.factories; + +/* + * $Id: ITextmyHtmlHandler.cs,v 1.9 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * The Tags-class maps several XHTML-tags to iText-objects. + */ + + public class ITextmyHtmlHandler : ITextHandler { + + /** These are the properties of the body section. */ + private Properties bodyAttributes = new Properties(); + + /** This is the status of the table border. */ + private bool tableBorder = false; + + /** + * Constructs a new SAXiTextHandler that will translate all the events + * triggered by the parser to actions on the Document-object. + * + * @param document this is the document on which events must be triggered + */ + + public ITextmyHtmlHandler(IDocListener document) : base(document, new HtmlTagMap()) { + } + + public ITextmyHtmlHandler(IDocListener document, BaseFont bf) : base(document, new HtmlTagMap(), bf) { + } + + /** + * Constructs a new SAXiTextHandler that will translate all the events + * triggered by the parser to actions on the Document-object. + * + * @param document this is the document on which events must be triggered + * @param htmlTags a tagmap translating HTML tags to iText tags + */ + + public ITextmyHtmlHandler(IDocListener document, Hashtable htmlTags) : base(document, htmlTags) { + } + + /** + * This method gets called when a start tag is encountered. + * + * @param uri the Uniform Resource Identifier + * @param lname the local name (without prefix), or the empty string if Namespace processing is not being performed. + * @param name the name of the tag that is encountered + * @param attrs the list of attributes + */ + + public override void StartElement(String uri, String lname, String name, Hashtable attrs) { + //System.err.Println("Start: " + name); + + // super.handleStartingTags is replaced with handleStartingTags + // suggestion by Vu Ngoc Tan/Hop + name = name.ToLower(CultureInfo.InvariantCulture); + if (HtmlTagMap.IsHtml(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsHead(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsTitle(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsMeta(name)) { + // we look if we can change the body attributes + String meta = null; + String content = null; + if (attrs != null) { + foreach (String attribute in attrs.Keys) { + if (Util.EqualsIgnoreCase(attribute, HtmlTags.CONTENT)) + content = (String)attrs[attribute]; + else if (Util.EqualsIgnoreCase(attribute, HtmlTags.NAME)) + meta = (String)attrs[attribute]; + } + } + if (meta != null && content != null) { + bodyAttributes.Add(meta, content); + } + return; + } + if (HtmlTagMap.IsLink(name)) { + // we do nothing for the moment, in a later version we could extract the style sheet + return; + } + if (HtmlTagMap.IsBody(name)) { + // maybe we could extract some info about the document: color, margins,... + // but that's for a later version... + XmlPeer peer = new XmlPeer(ElementTags.ITEXT, name); + peer.AddAlias(ElementTags.TOP, HtmlTags.TOPMARGIN); + peer.AddAlias(ElementTags.BOTTOM, HtmlTags.BOTTOMMARGIN); + peer.AddAlias(ElementTags.RIGHT, HtmlTags.RIGHTMARGIN); + peer.AddAlias(ElementTags.LEFT, HtmlTags.LEFTMARGIN); + bodyAttributes.AddAll(peer.GetAttributes(attrs)); + HandleStartingTags(peer.Tag, bodyAttributes); + return; + } + if (myTags.ContainsKey(name)) { + XmlPeer peer = (XmlPeer) myTags[name]; + if (ElementTags.TABLE.Equals(peer.Tag) || ElementTags.CELL.Equals(peer.Tag)) { + Properties p = peer.GetAttributes(attrs); + String value; + if (ElementTags.TABLE.Equals(peer.Tag) && (value = p[ElementTags.BORDERWIDTH]) != null) { + if (float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo) > 0) { + tableBorder = true; + } + } + if (tableBorder) { + p.Add(ElementTags.LEFT, "true"); + p.Add(ElementTags.RIGHT, "true"); + p.Add(ElementTags.TOP, "true"); + p.Add(ElementTags.BOTTOM, "true"); + } + HandleStartingTags(peer.Tag, p); + return; + } + HandleStartingTags(peer.Tag, peer.GetAttributes(attrs)); + return; + } + Properties attributes = new Properties(); + if (attrs != null) { + foreach (String attribute in attrs.Keys) { + attributes.Add(attribute.ToLower(CultureInfo.InvariantCulture), ((String)attrs[attribute]).ToLower(CultureInfo.InvariantCulture)); + } + } + HandleStartingTags(name, attributes); + } + + /** + * This method gets called when an end tag is encountered. + * + * @param uri the Uniform Resource Identifier + * @param lname the local name (without prefix), or the empty string if Namespace processing is not being performed. + * @param name the name of the tag that ends + */ + + public override void EndElement(String uri, String lname, String name) { + //System.err.Println("End: " + name); + name = name.ToLower(CultureInfo.InvariantCulture); + if (ElementTags.PARAGRAPH.Equals(name)) { + document.Add((IElement) stack.Pop()); + return; + } + if (HtmlTagMap.IsHead(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsTitle(name)) { + if (currentChunk != null) { + bodyAttributes.Add(ElementTags.TITLE, currentChunk.Content); + } + return; + } + if (HtmlTagMap.IsMeta(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsLink(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsBody(name)) { + // we do nothing + return; + } + if (myTags.ContainsKey(name)) { + XmlPeer peer = (XmlPeer) myTags[name]; + if (ElementTags.TABLE.Equals(peer.Tag)) { + tableBorder = false; + } + base.HandleEndingTags(peer.Tag); + return; + } + // super.handleEndingTags is replaced with handleEndingTags + // suggestion by Ken Auer + HandleEndingTags(name); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/Markup.cs b/iTechSharp/iTextSharp/text/html/Markup.cs new file mode 100644 index 0000000..f2a56c4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/Markup.cs @@ -0,0 +1,427 @@ +using System; +using System.util; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using iTextSharp.text; + +/* + * $Id: Markup.cs,v 1.2 2008/05/13 11:25:16 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + ///

+ /// A class that contains all the possible tagnames and their attributes. + /// + public class Markup { + // iText specific + + /** the key for any tag */ + public const string ITEXT_TAG = "tag"; + + // HTML tags + + /** the markup for the body part of a file */ + public const string HTML_TAG_BODY = "body"; + + /** The DIV tag. */ + public const string HTML_TAG_DIV = "div"; + + /** This is a possible HTML-tag. */ + public const string HTML_TAG_LINK = "link"; + + /** The SPAN tag. */ + public const string HTML_TAG_SPAN = "span"; + + // HTML attributes + + /** the height attribute. */ + public const string HTML_ATTR_HEIGHT = "height"; + + /** the hyperlink reference attribute. */ + public const string HTML_ATTR_HREF = "href"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string HTML_ATTR_REL = "rel"; + + /** This is used for inline css style information */ + public const string HTML_ATTR_STYLE = "style"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string HTML_ATTR_TYPE = "type"; + + /** This is a possible HTML attribute. */ + public const string HTML_ATTR_STYLESHEET = "stylesheet"; + + /** the width attribute. */ + public const string HTML_ATTR_WIDTH = "width"; + + /** attribute for specifying externally defined CSS class */ + public const string HTML_ATTR_CSS_CLASS = "class"; + + /** The ID attribute. */ + public const string HTML_ATTR_CSS_ID = "id"; + + // HTML values + + /** This is a possible value for the language attribute (SCRIPT tag). */ + public const string HTML_VALUE_JAVASCRIPT = "text/javascript"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string HTML_VALUE_CSS = "text/css"; + + // CSS keys + + /** the CSS tag for background color */ + public const string CSS_KEY_BGCOLOR = "background-color"; + + /** the CSS tag for text color */ + public const string CSS_KEY_COLOR = "color"; + + /** CSS key that indicate the way something has to be displayed */ + public const string CSS_KEY_DISPLAY = "display"; + + /** the CSS tag for the font family */ + public const string CSS_KEY_FONTFAMILY = "font-family"; + + /** the CSS tag for the font size */ + public const string CSS_KEY_FONTSIZE = "font-size"; + + /** the CSS tag for the font style */ + public const string CSS_KEY_FONTSTYLE = "font-style"; + + /** the CSS tag for the font weight */ + public const string CSS_KEY_FONTWEIGHT = "font-weight"; + + /** the CSS tag for text decorations */ + public const string CSS_KEY_LINEHEIGHT = "line-height"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGIN = "margin"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINLEFT = "margin-left"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINRIGHT = "margin-right"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINTOP = "margin-top"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINBOTTOM = "margin-bottom"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDING = "padding"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGLEFT = "padding-left"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGRIGHT = "padding-right"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGTOP = "padding-top"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGBOTTOM = "padding-bottom"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERCOLOR = "border-color"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTH = "border-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHLEFT = "border-left-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHRIGHT = "border-right-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHTOP = "border-top-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHBOTTOM = "border-bottom-width"; + + /** the CSS tag for adding a page break when the document is printed */ + public const string CSS_KEY_PAGE_BREAK_AFTER = "page-break-after"; + + /** the CSS tag for adding a page break when the document is printed */ + public const string CSS_KEY_PAGE_BREAK_BEFORE = "page-break-before"; + + /** the CSS tag for the horizontal alignment of an object */ + public const string CSS_KEY_TEXTALIGN = "text-align"; + + /** the CSS tag for text decorations */ + public const string CSS_KEY_TEXTDECORATION = "text-decoration"; + + /** the CSS tag for text decorations */ + public const string CSS_KEY_VERTICALALIGN = "vertical-align"; + + /** the CSS tag for the visibility of objects */ + public const string CSS_KEY_VISIBILITY = "visibility"; + + // CSS values + + /** value for the CSS tag for adding a page break when the document is printed */ + public const string CSS_VALUE_ALWAYS = "always"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_BLOCK = "block"; + + /** a CSS value for text font weight */ + public const string CSS_VALUE_BOLD = "bold"; + + /** the value if you want to hide objects. */ + public const string CSS_VALUE_HIDDEN = "hidden"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_INLINE = "inline"; + + /** a CSS value for text font style */ + public const string CSS_VALUE_ITALIC = "italic"; + + /** a CSS value for text decoration */ + public const string CSS_VALUE_LINETHROUGH = "line-through"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_LISTITEM = "list-item"; + + /** a CSS value */ + public const string CSS_VALUE_NONE = "none"; + + /** a CSS value */ + public const string CSS_VALUE_NORMAL = "normal"; + + /** a CSS value for text font style */ + public const string CSS_VALUE_OBLIQUE = "oblique"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_TABLE = "table"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_TABLEROW = "table-row"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_TABLECELL = "table-cell"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNLEFT = "left"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNRIGHT = "right"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNCENTER = "center"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNJUSTIFY = "justify"; + + /** a CSS value for text decoration */ + public const string CSS_VALUE_UNDERLINE = "underline"; + + /// + /// Parses a length. + /// + /// a length in the form of an optional + or -, followed by a number and a unit. + /// a float + public static float ParseLength(string str) { + int pos = 0; + int length = str.Length; + bool ok = true; + while (ok && pos < length) { + switch (str[pos]) { + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + pos++; + break; + default: + ok = false; + break; + } + } + if (pos == 0) return 0f; + if (pos == length) return float.Parse(str, System.Globalization.NumberFormatInfo.InvariantInfo); + float f = float.Parse(str.Substring(0, pos), System.Globalization.NumberFormatInfo.InvariantInfo); + str = str.Substring(pos); + // inches + if (str.StartsWith("in")) { + return f * 72f; + } + // centimeters + if (str.StartsWith("cm")) { + return (f / 2.54f) * 72f; + } + // millimeters + if (str.StartsWith("mm")) { + return (f / 25.4f) * 72f; + } + // picas + if (str.StartsWith("pc")) { + return f * 12f; + } + // default: we assume the length was measured in points + return f; + } + + /// + /// Converts a Color into a HTML representation of this Color. + /// + /// the Color that has to be converted. + /// the HTML representation of this Color + public static Color DecodeColor(String s) { + if (s == null) + return null; + s = s.ToLower(CultureInfo.InvariantCulture).Trim(); + Color c = (Color)WebColors.GetRGBColor(s); + if (c != null) + return c; + try { + if (s.StartsWith("#")) { + if (s.Length == 4) + s = "#" + s.Substring(1, 1) + s.Substring(1, 1) + + s.Substring(2, 1) + s.Substring(2, 1) + + s.Substring(3, 1) + s.Substring(3, 1); + if (s.Length == 7) + return new Color(int.Parse(s.Substring(1), NumberStyles.HexNumber)); + } + else if (s.StartsWith("rgb")) { + StringTokenizer tk = new StringTokenizer(s.Substring(3), " \t\r\n\f(),"); + int[] cc = new int [3]; + for (int k = 0; k < 3; ++k) { + if (!tk.HasMoreTokens()) + return null; + String t = tk.NextToken(); + float n; + if (t.EndsWith("%")) { + n = float.Parse(t.Substring(0, t.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + n = n * 255f / 100f; + } + else + n = float.Parse(t, System.Globalization.NumberFormatInfo.InvariantInfo); + int ni = (int)n; + if (ni > 255) + ni = 255; + else if (ni < 0) + ni = 0; + cc[k] = ni; + } + return new Color(cc[0], cc[1], cc[2]); + } + } + catch { + } + return null; + } + + /// + /// This method parses a string with attributes and returns a Properties object. + /// + /// a string of this form: 'key1="value1"; key2="value2";... keyN="valueN" ' + /// a Properties object + public static Properties ParseAttributes(string str) { + Properties result = new Properties(); + if (str == null) return result; + StringTokenizer keyValuePairs = new StringTokenizer(str, ";"); + StringTokenizer keyValuePair; + string key; + string value; + while (keyValuePairs.HasMoreTokens()) { + keyValuePair = new StringTokenizer(keyValuePairs.NextToken(), ":"); + if (keyValuePair.HasMoreTokens()) key = keyValuePair.NextToken().Trim().Trim(); + else continue; + if (keyValuePair.HasMoreTokens()) value = keyValuePair.NextToken().Trim(); + else continue; + if (value.StartsWith("\"")) value = value.Substring(1); + if (value.EndsWith("\"")) value = value.Substring(0, value.Length - 1); + result.Add(key.ToLower(CultureInfo.InvariantCulture), value); + } + return result; + } + + /** + * Removes the comments sections of a String. + * + * @param string + * the original String + * @param startComment + * the String that marks the start of a Comment section + * @param endComment + * the String that marks the end of a Comment section. + * @return the String stripped of its comment section + */ + public static string RemoveComment(String str, String startComment, + String endComment) { + StringBuilder result = new StringBuilder(); + int pos = 0; + int end = endComment.Length; + int start = str.IndexOf(startComment, pos); + while (start > -1) { + result.Append(str.Substring(pos, start - pos)); + pos = str.IndexOf(endComment, start) + end; + start = str.IndexOf(startComment, pos); + } + result.Append(str.Substring(pos)); + return result.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/html/WebColors.cs b/iTechSharp/iTextSharp/text/html/WebColors.cs new file mode 100644 index 0000000..1e8323d --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/WebColors.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections; +using System.Globalization; +using iTextSharp.text; +using System.util; +/* + * $Id: WebColors.cs,v 1.3 2008/05/13 11:25:16 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * This class is a HashMap that contains the names of colors as a key and the + * corresponding Color as value. (Source: Wikipedia + * http://en.wikipedia.org/wiki/Web_colors ) + * + * @author blowagie + */ + public class WebColors : Hashtable { + + public static WebColors NAMES = new WebColors(); + static WebColors() { + NAMES["aliceblue"] = new int[] { 0xf0, 0xf8, 0xff, 0x00 }; + NAMES["antiquewhite"] = new int[] { 0xfa, 0xeb, 0xd7, 0x00 }; + NAMES["aqua"] = new int[] { 0x00, 0xff, 0xff, 0x00 }; + NAMES["aquamarine"] = new int[] { 0x7f, 0xff, 0xd4, 0x00 }; + NAMES["azure"] = new int[] { 0xf0, 0xff, 0xff, 0x00 }; + NAMES["beige"] = new int[] { 0xf5, 0xf5, 0xdc, 0x00 }; + NAMES["bisque"] = new int[] { 0xff, 0xe4, 0xc4, 0x00 }; + NAMES["black"] = new int[] { 0x00, 0x00, 0x00, 0x00 }; + NAMES["blanchedalmond"] = new int[] { 0xff, 0xeb, 0xcd, 0x00 }; + NAMES["blue"] = new int[] { 0x00, 0x00, 0xff, 0x00 }; + NAMES["blueviolet"] = new int[] { 0x8a, 0x2b, 0xe2, 0x00 }; + NAMES["brown"] = new int[] { 0xa5, 0x2a, 0x2a, 0x00 }; + NAMES["burlywood"] = new int[] { 0xde, 0xb8, 0x87, 0x00 }; + NAMES["cadetblue"] = new int[] { 0x5f, 0x9e, 0xa0, 0x00 }; + NAMES["chartreuse"] = new int[] { 0x7f, 0xff, 0x00, 0x00 }; + NAMES["chocolate"] = new int[] { 0xd2, 0x69, 0x1e, 0x00 }; + NAMES["coral"] = new int[] { 0xff, 0x7f, 0x50, 0x00 }; + NAMES["cornflowerblue"] = new int[] { 0x64, 0x95, 0xed, 0x00 }; + NAMES["cornsilk"] = new int[] { 0xff, 0xf8, 0xdc, 0x00 }; + NAMES["crimson"] = new int[] { 0xdc, 0x14, 0x3c, 0x00 }; + NAMES["cyan"] = new int[] { 0x00, 0xff, 0xff, 0x00 }; + NAMES["darkblue"] = new int[] { 0x00, 0x00, 0x8b, 0x00 }; + NAMES["darkcyan"] = new int[] { 0x00, 0x8b, 0x8b, 0x00 }; + NAMES["darkgoldenrod"] = new int[] { 0xb8, 0x86, 0x0b, 0x00 }; + NAMES["darkgray"] = new int[] { 0xa9, 0xa9, 0xa9, 0x00 }; + NAMES["darkgreen"] = new int[] { 0x00, 0x64, 0x00, 0x00 }; + NAMES["darkkhaki"] = new int[] { 0xbd, 0xb7, 0x6b, 0x00 }; + NAMES["darkmagenta"] = new int[] { 0x8b, 0x00, 0x8b, 0x00 }; + NAMES["darkolivegreen"] = new int[] { 0x55, 0x6b, 0x2f, 0x00 }; + NAMES["darkorange"] = new int[] { 0xff, 0x8c, 0x00, 0x00 }; + NAMES["darkorchid"] = new int[] { 0x99, 0x32, 0xcc, 0x00 }; + NAMES["darkred"] = new int[] { 0x8b, 0x00, 0x00, 0x00 }; + NAMES["darksalmon"] = new int[] { 0xe9, 0x96, 0x7a, 0x00 }; + NAMES["darkseagreen"] = new int[] { 0x8f, 0xbc, 0x8f, 0x00 }; + NAMES["darkslateblue"] = new int[] { 0x48, 0x3d, 0x8b, 0x00 }; + NAMES["darkslategray"] = new int[] { 0x2f, 0x4f, 0x4f, 0x00 }; + NAMES["darkturquoise"] = new int[] { 0x00, 0xce, 0xd1, 0x00 }; + NAMES["darkviolet"] = new int[] { 0x94, 0x00, 0xd3, 0x00 }; + NAMES["deeppink"] = new int[] { 0xff, 0x14, 0x93, 0x00 }; + NAMES["deepskyblue"] = new int[] { 0x00, 0xbf, 0xff, 0x00 }; + NAMES["dimgray"] = new int[] { 0x69, 0x69, 0x69, 0x00 }; + NAMES["dodgerblue"] = new int[] { 0x1e, 0x90, 0xff, 0x00 }; + NAMES["firebrick"] = new int[] { 0xb2, 0x22, 0x22, 0x00 }; + NAMES["floralwhite"] = new int[] { 0xff, 0xfa, 0xf0, 0x00 }; + NAMES["forestgreen"] = new int[] { 0x22, 0x8b, 0x22, 0x00 }; + NAMES["fuchsia"] = new int[] { 0xff, 0x00, 0xff, 0x00 }; + NAMES["gainsboro"] = new int[] { 0xdc, 0xdc, 0xdc, 0x00 }; + NAMES["ghostwhite"] = new int[] { 0xf8, 0xf8, 0xff, 0x00 }; + NAMES["gold"] = new int[] { 0xff, 0xd7, 0x00, 0x00 }; + NAMES["goldenrod"] = new int[] { 0xda, 0xa5, 0x20, 0x00 }; + NAMES["gray"] = new int[] { 0x80, 0x80, 0x80, 0x00 }; + NAMES["green"] = new int[] { 0x00, 0x80, 0x00, 0x00 }; + NAMES["greenyellow"] = new int[] { 0xad, 0xff, 0x2f, 0x00 }; + NAMES["honeydew"] = new int[] { 0xf0, 0xff, 0xf0, 0x00 }; + NAMES["hotpink"] = new int[] { 0xff, 0x69, 0xb4, 0x00 }; + NAMES["indianred"] = new int[] { 0xcd, 0x5c, 0x5c, 0x00 }; + NAMES["indigo"] = new int[] { 0x4b, 0x00, 0x82, 0x00 }; + NAMES["ivory"] = new int[] { 0xff, 0xff, 0xf0, 0x00 }; + NAMES["khaki"] = new int[] { 0xf0, 0xe6, 0x8c, 0x00 }; + NAMES["lavender"] = new int[] { 0xe6, 0xe6, 0xfa, 0x00 }; + NAMES["lavenderblush"] = new int[] { 0xff, 0xf0, 0xf5, 0x00 }; + NAMES["lawngreen"] = new int[] { 0x7c, 0xfc, 0x00, 0x00 }; + NAMES["lemonchiffon"] = new int[] { 0xff, 0xfa, 0xcd, 0x00 }; + NAMES["lightblue"] = new int[] { 0xad, 0xd8, 0xe6, 0x00 }; + NAMES["lightcoral"] = new int[] { 0xf0, 0x80, 0x80, 0x00 }; + NAMES["lightcyan"] = new int[] { 0xe0, 0xff, 0xff, 0x00 }; + NAMES["lightgoldenrodyellow"] = new int[] { 0xfa, 0xfa, 0xd2, 0x00 }; + NAMES["lightgreen"] = new int[] { 0x90, 0xee, 0x90, 0x00 }; + NAMES["lightgrey"] = new int[] { 0xd3, 0xd3, 0xd3, 0x00 }; + NAMES["lightpink"] = new int[] { 0xff, 0xb6, 0xc1, 0x00 }; + NAMES["lightsalmon"] = new int[] { 0xff, 0xa0, 0x7a, 0x00 }; + NAMES["lightseagreen"] = new int[] { 0x20, 0xb2, 0xaa, 0x00 }; + NAMES["lightskyblue"] = new int[] { 0x87, 0xce, 0xfa, 0x00 }; + NAMES["lightslategray"] = new int[] { 0x77, 0x88, 0x99, 0x00 }; + NAMES["lightsteelblue"] = new int[] { 0xb0, 0xc4, 0xde, 0x00 }; + NAMES["lightyellow"] = new int[] { 0xff, 0xff, 0xe0, 0x00 }; + NAMES["lime"] = new int[] { 0x00, 0xff, 0x00, 0x00 }; + NAMES["limegreen"] = new int[] { 0x32, 0xcd, 0x32, 0x00 }; + NAMES["linen"] = new int[] { 0xfa, 0xf0, 0xe6, 0x00 }; + NAMES["magenta"] = new int[] { 0xff, 0x00, 0xff, 0x00 }; + NAMES["maroon"] = new int[] { 0x80, 0x00, 0x00, 0x00 }; + NAMES["mediumaquamarine"] = new int[] { 0x66, 0xcd, 0xaa, 0x00 }; + NAMES["mediumblue"] = new int[] { 0x00, 0x00, 0xcd, 0x00 }; + NAMES["mediumorchid"] = new int[] { 0xba, 0x55, 0xd3, 0x00 }; + NAMES["mediumpurple"] = new int[] { 0x93, 0x70, 0xdb, 0x00 }; + NAMES["mediumseagreen"] = new int[] { 0x3c, 0xb3, 0x71, 0x00 }; + NAMES["mediumslateblue"] = new int[] { 0x7b, 0x68, 0xee, 0x00 }; + NAMES["mediumspringgreen"] = new int[] { 0x00, 0xfa, 0x9a, 0x00 }; + NAMES["mediumturquoise"] = new int[] { 0x48, 0xd1, 0xcc, 0x00 }; + NAMES["mediumvioletred"] = new int[] { 0xc7, 0x15, 0x85, 0x00 }; + NAMES["midnightblue"] = new int[] { 0x19, 0x19, 0x70, 0x00 }; + NAMES["mintcream"] = new int[] { 0xf5, 0xff, 0xfa, 0x00 }; + NAMES["mistyrose"] = new int[] { 0xff, 0xe4, 0xe1, 0x00 }; + NAMES["moccasin"] = new int[] { 0xff, 0xe4, 0xb5, 0x00 }; + NAMES["navajowhite"] = new int[] { 0xff, 0xde, 0xad, 0x00 }; + NAMES["navy"] = new int[] { 0x00, 0x00, 0x80, 0x00 }; + NAMES["oldlace"] = new int[] { 0xfd, 0xf5, 0xe6, 0x00 }; + NAMES["olive"] = new int[] { 0x80, 0x80, 0x00, 0x00 }; + NAMES["olivedrab"] = new int[] { 0x6b, 0x8e, 0x23, 0x00 }; + NAMES["orange"] = new int[] { 0xff, 0xa5, 0x00, 0x00 }; + NAMES["orangered"] = new int[] { 0xff, 0x45, 0x00, 0x00 }; + NAMES["orchid"] = new int[] { 0xda, 0x70, 0xd6, 0x00 }; + NAMES["palegoldenrod"] = new int[] { 0xee, 0xe8, 0xaa, 0x00 }; + NAMES["palegreen"] = new int[] { 0x98, 0xfb, 0x98, 0x00 }; + NAMES["paleturquoise"] = new int[] { 0xaf, 0xee, 0xee, 0x00 }; + NAMES["palevioletred"] = new int[] { 0xdb, 0x70, 0x93, 0x00 }; + NAMES["papayawhip"] = new int[] { 0xff, 0xef, 0xd5, 0x00 }; + NAMES["peachpuff"] = new int[] { 0xff, 0xda, 0xb9, 0x00 }; + NAMES["peru"] = new int[] { 0xcd, 0x85, 0x3f, 0x00 }; + NAMES["pink"] = new int[] { 0xff, 0xc0, 0xcb, 0x00 }; + NAMES["plum"] = new int[] { 0xdd, 0xa0, 0xdd, 0x00 }; + NAMES["powderblue"] = new int[] { 0xb0, 0xe0, 0xe6, 0x00 }; + NAMES["purple"] = new int[] { 0x80, 0x00, 0x80, 0x00 }; + NAMES["red"] = new int[] { 0xff, 0x00, 0x00, 0x00 }; + NAMES["rosybrown"] = new int[] { 0xbc, 0x8f, 0x8f, 0x00 }; + NAMES["royalblue"] = new int[] { 0x41, 0x69, 0xe1, 0x00 }; + NAMES["saddlebrown"] = new int[] { 0x8b, 0x45, 0x13, 0x00 }; + NAMES["salmon"] = new int[] { 0xfa, 0x80, 0x72, 0x00 }; + NAMES["sandybrown"] = new int[] { 0xf4, 0xa4, 0x60, 0x00 }; + NAMES["seagreen"] = new int[] { 0x2e, 0x8b, 0x57, 0x00 }; + NAMES["seashell"] = new int[] { 0xff, 0xf5, 0xee, 0x00 }; + NAMES["sienna"] = new int[] { 0xa0, 0x52, 0x2d, 0x00 }; + NAMES["silver"] = new int[] { 0xc0, 0xc0, 0xc0, 0x00 }; + NAMES["skyblue"] = new int[] { 0x87, 0xce, 0xeb, 0x00 }; + NAMES["slateblue"] = new int[] { 0x6a, 0x5a, 0xcd, 0x00 }; + NAMES["slategray"] = new int[] { 0x70, 0x80, 0x90, 0x00 }; + NAMES["snow"] = new int[] { 0xff, 0xfa, 0xfa, 0x00 }; + NAMES["springgreen"] = new int[] { 0x00, 0xff, 0x7f, 0x00 }; + NAMES["steelblue"] = new int[] { 0x46, 0x82, 0xb4, 0x00 }; + NAMES["tan"] = new int[] { 0xd2, 0xb4, 0x8c, 0x00 }; + NAMES["transparent"] = new int[] { 0x00, 0x00, 0x00, 0xff }; + NAMES["teal"] = new int[] { 0x00, 0x80, 0x80, 0x00 }; + NAMES["thistle"] = new int[] { 0xd8, 0xbf, 0xd8, 0x00 }; + NAMES["tomato"] = new int[] { 0xff, 0x63, 0x47, 0x00 }; + NAMES["turquoise"] = new int[] { 0x40, 0xe0, 0xd0, 0x00 }; + NAMES["violet"] = new int[] { 0xee, 0x82, 0xee, 0x00 }; + NAMES["wheat"] = new int[] { 0xf5, 0xde, 0xb3, 0x00 }; + NAMES["white"] = new int[] { 0xff, 0xff, 0xff, 0x00 }; + NAMES["whitesmoke"] = new int[] { 0xf5, 0xf5, 0xf5, 0x00 }; + NAMES["yellow"] = new int[] { 0xff, 0xff, 0x00, 0x00 }; + NAMES["yellowgreen"] = new int[] { 0x9, 0xacd, 0x32, 0x00 }; + } + + /** + * Gives you a Color based on a name. + * + * @param name + * a name such as black, violet, cornflowerblue or #RGB or #RRGGBB + * or rgb(R,G,B) + * @return the corresponding Color object + * @throws IllegalArgumentException + * if the String isn't a know representation of a color. + */ + public static Color GetRGBColor(String name) { + int[] c = { 0, 0, 0, 0 }; + if (name.StartsWith("#")) { + if (name.Length == 4) { + c[0] = int.Parse(name.Substring(1, 1), NumberStyles.HexNumber) * 16; + c[1] = int.Parse(name.Substring(2, 1), NumberStyles.HexNumber) * 16; + c[2] = int.Parse(name.Substring(3), NumberStyles.HexNumber) * 16; + return new Color(c[0], c[1], c[2], c[3]); + } + if (name.Length == 7) { + c[0] = int.Parse(name.Substring(1, 2), NumberStyles.HexNumber); + c[1] = int.Parse(name.Substring(3, 2), NumberStyles.HexNumber); + c[2] = int.Parse(name.Substring(5), NumberStyles.HexNumber); + return new Color(c[0], c[1], c[2], c[3]); + } + throw new ArgumentException( + "Unknown color format. Must be #RGB or #RRGGBB"); + } + else if (name.StartsWith("rgb(")) { + StringTokenizer tok = new StringTokenizer(name, "rgb(), \t\r\n\f"); + for (int k = 0; k < 3; ++k) { + String v = tok.NextToken(); + if (v.EndsWith("%")) + c[k] = int.Parse(v.Substring(0, v.Length - 1)) * 255 / 100; + else + c[k] = int.Parse(v); + if (c[k] < 0) + c[k] = 0; + else if (c[k] > 255) + c[k] = 255; + } + return new Color(c[0], c[1], c[2], c[3]); + } + name = name.ToLower(CultureInfo.InvariantCulture); + if (!NAMES.ContainsKey(name)) + throw new ArgumentException("Color '" + name + + "' not found."); + c = (int[]) NAMES[name]; + return new Color(c[0], c[1], c[2], c[3]); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs b/iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs new file mode 100644 index 0000000..c9a8c05 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + +public class ChainedProperties { + + public static int[] fontSizes = {8, 10, 12, 14, 18, 24, 36}; + public ArrayList chain = new ArrayList(); + + /** Creates a new instance of ChainedProperties */ + public ChainedProperties() { + } + + public String this[String key] { + get { + for (int k = chain.Count - 1; k >= 0; --k) { + Object[] obj = (Object[])chain[k]; + Hashtable prop = (Hashtable)obj[1]; + String ret = (String)prop[key]; + if (ret != null) + return ret; + } + return null; + } + } + + public bool HasProperty(String key) { + for (int k = chain.Count - 1; k >= 0; --k) { + Object[] obj = (Object[])chain[k]; + Hashtable prop = (Hashtable)obj[1]; + if (prop.ContainsKey(key)) + return true; + } + return false; + } + + public void AddToChain(String key, Hashtable prop) { + // adjust the font size + String value = (String)prop["size"]; + if (value != null) { + if (value.EndsWith("px")) { + prop["size"] = value.Substring(0, value.Length - 2); + } + else { + int s = 0; + if (value.StartsWith("+") || value.StartsWith("-")) { + String old = this["basefontsize"]; + if (old == null) + old = "12"; + float f = float.Parse(old, System.Globalization.NumberFormatInfo.InvariantInfo); + int c = (int)f; + for (int k = fontSizes.Length - 1; k >= 0; --k) { + if (c >= fontSizes[k]) { + s = k; + break; + } + } + int inc = int.Parse(value.StartsWith("+") ? value.Substring(1) : value); + s += inc; + } + else { + try { + s = int.Parse(value) - 1; + } + catch { + s = 0; + } + } + if (s < 0) + s = 0; + else if (s >= fontSizes.Length) + s = fontSizes.Length - 1; + prop["size"] = fontSizes[s].ToString(); + } + } + chain.Add(new Object[]{key, prop}); + } + + public void RemoveChain(String key) { + for (int k = chain.Count - 1; k >= 0; --k) { + if (key.Equals(((Object[])chain[k])[0])) { + chain.RemoveAt(k); + return; + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs b/iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs new file mode 100644 index 0000000..290876c --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs @@ -0,0 +1,338 @@ +using System; +using System.Collections; +using System.Globalization; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.html; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + /** + * + * @author psoares + */ + public class FactoryProperties { + + private FontFactoryImp fontImp = FontFactory.FontImp; + + /** Creates a new instance of FactoryProperties */ + public FactoryProperties() { + } + + public Chunk CreateChunk(String text, ChainedProperties props) { + Font font = GetFont(props); + float size = font.Size; + size /= 2; + Chunk ck = new Chunk(text, font); + if (props.HasProperty("sub")) + ck.SetTextRise(-size); + else if (props.HasProperty("sup")) + ck.SetTextRise(size); + ck.SetHyphenation(GetHyphenation(props)); + return ck; + } + + private static void SetParagraphLeading(Paragraph p, String leading) { + if (leading == null) { + p.SetLeading(0, 1.5f); + return; + } + try { + StringTokenizer tk = new StringTokenizer(leading, " ,"); + String v = tk.NextToken(); + float v1 = float.Parse(v, System.Globalization.NumberFormatInfo.InvariantInfo); + if (!tk.HasMoreTokens()) { + p.SetLeading(v1, 0); + return; + } + v = tk.NextToken(); + float v2 = float.Parse(v, System.Globalization.NumberFormatInfo.InvariantInfo); + p.SetLeading(v1, v2); + } + catch { + p.SetLeading(0, 1.5f); + } + + } + + public static Paragraph CreateParagraph(Hashtable props) { + Paragraph p = new Paragraph(); + String value = (String)props["align"]; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "center")) + p.Alignment = Element.ALIGN_CENTER; + else if (Util.EqualsIgnoreCase(value, "right")) + p.Alignment = Element.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(value, "justify")) + p.Alignment = Element.ALIGN_JUSTIFIED; + } + SetParagraphLeading(p, (String)props["leading"]); + p.Hyphenation = GetHyphenation(props); + return p; + } + + public static void CreateParagraph(Paragraph p, ChainedProperties props) { + String value = props["align"]; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "center")) + p.Alignment = Element.ALIGN_CENTER; + else if (Util.EqualsIgnoreCase(value, "right")) + p.Alignment = Element.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(value, "justify")) + p.Alignment = Element.ALIGN_JUSTIFIED; + } + p.Hyphenation = GetHyphenation(props); + SetParagraphLeading(p, props["leading"]); + value = props["before"]; + if (value != null) { + try { + p.SpacingBefore = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + catch {} + } + value = props["after"]; + if (value != null) { + try { + p.SpacingAfter = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + catch {} + } + value = props["extraparaspace"]; + if (value != null) { + try { + p.ExtraParagraphSpace = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + catch {} + } + } + + public static Paragraph CreateParagraph(ChainedProperties props) { + Paragraph p = new Paragraph(); + CreateParagraph(p, props); + return p; + } + + public static ListItem CreateListItem(ChainedProperties props) { + ListItem p = new ListItem(); + CreateParagraph(p, props); + return p; + } + + public Font GetFont(ChainedProperties props) { + String face = props["face"]; + if (face != null) { + StringTokenizer tok = new StringTokenizer(face, ","); + while (tok.HasMoreTokens()) { + face = tok.NextToken().Trim(); + if (face.StartsWith("\"")) + face = face.Substring(1); + if (face.EndsWith("\"")) + face = face.Substring(0, face.Length - 1); + if (fontImp.IsRegistered(face)) + break; + } + } + int style = 0; + if (props.HasProperty("i")) + style |= Font.ITALIC; + if (props.HasProperty("b")) + style |= Font.BOLD; + if (props.HasProperty("u")) + style |= Font.UNDERLINE; + if (props.HasProperty("s")) + style |= Font.STRIKETHRU ; + + String value = props["size"]; + float size = 12; + if (value != null) + size = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + Color color = Markup.DecodeColor(props["color"]); + String encoding = props["encoding"]; + if (encoding == null) + encoding = BaseFont.WINANSI; + return fontImp.GetFont(face, encoding, true, size, style, color); + } + + /** + * Gets a HyphenationEvent based on the hyphenation entry in ChainedProperties. + * @param props ChainedProperties + * @return a HyphenationEvent + * @since 2.1.2 + */ + public static IHyphenationEvent GetHyphenation(ChainedProperties props) { + return GetHyphenation(props["hyphenation"]); + } + + /** + * Gets a HyphenationEvent based on the hyphenation entry in a HashMap. + * @param props a HashMap with properties + * @return a HyphenationEvent + * @since 2.1.2 + */ + public static IHyphenationEvent GetHyphenation(Hashtable props) { + return GetHyphenation((String)props["hyphenation"]); + } + + /** + * Gets a HyphenationEvent based on a String. + * For instance "en_UK,3,2" returns new HyphenationAuto("en", "UK", 3, 2); + * @param a String, for instance "en_UK,2,2" + * @return a HyphenationEvent + * @since 2.1.2 + */ + public static IHyphenationEvent GetHyphenation(String s) { + if (s == null || s.Length == 0) { + return null; + } + String lang = s; + String country = null; + int leftMin = 2; + int rightMin = 2; + + int pos = s.IndexOf('_'); + if (pos == -1) { + return new HyphenationAuto(lang, country, leftMin, rightMin); + } + lang = s.Substring(0, pos); + country = s.Substring(pos + 1); + pos = country.IndexOf(','); + if (pos == -1) { + return new HyphenationAuto(lang, country, leftMin, rightMin); + } + s = country.Substring(pos + 1); + country = country.Substring(0, pos); + pos = s.IndexOf(','); + if (pos == -1) { + leftMin = int.Parse(s); + } + else { + leftMin = int.Parse(s.Substring(0, pos)); + rightMin = int.Parse(s.Substring(pos + 1)); + } + return new HyphenationAuto(lang, country, leftMin, rightMin); + } + + public static void InsertStyle(Hashtable h) { + String style = (String)h["style"]; + if (style == null) + return; + Properties prop = Markup.ParseAttributes(style); + foreach (String key in prop.Keys) { + if (key.Equals(Markup.CSS_KEY_FONTFAMILY)) { + h["face"] = prop[key]; + } + else if (key.Equals(Markup.CSS_KEY_FONTSIZE)) { + h["size"] = Markup.ParseLength(prop[key]).ToString(NumberFormatInfo.InvariantInfo) + "px"; + } + else if (key.Equals(Markup.CSS_KEY_FONTSTYLE)) { + String ss = prop[key].Trim().ToLower(CultureInfo.InvariantCulture); + if (ss.Equals("italic") || ss.Equals("oblique")) + h["i"] = null; + } + else if (key.Equals(Markup.CSS_KEY_FONTWEIGHT)) { + String ss = prop[key].Trim().ToLower(CultureInfo.InvariantCulture); + if (ss.Equals("bold") || ss.Equals("700") || ss.Equals("800") || ss.Equals("900")) + h["b"] = null; + } + else if (key.Equals(Markup.CSS_KEY_FONTWEIGHT)) { + String ss = prop[key].Trim().ToLower(CultureInfo.InvariantCulture); + if (ss.Equals("underline")) + h["u"] = null; + } + else if (key.Equals(Markup.CSS_KEY_COLOR)) { + Color c = Markup.DecodeColor(prop[key]); + if (c != null) { + int hh = c.ToArgb() & 0xffffff; + String hs = "#" + hh.ToString("X06", NumberFormatInfo.InvariantInfo); + h["color"] = hs; + } + } + else if (key.Equals(Markup.CSS_KEY_LINEHEIGHT)) { + String ss = prop[key].Trim(); + float v = Markup.ParseLength(prop[key]); + if (ss.EndsWith("%")) { + v /= 100; + h["leading"] = "0," + v.ToString(NumberFormatInfo.InvariantInfo); + } + else { + h["leading"] = v.ToString(NumberFormatInfo.InvariantInfo) + ",0"; + } + } + else if (key.Equals(Markup.CSS_KEY_TEXTALIGN)) { + String ss = prop[key].Trim().ToLower(System.Globalization.CultureInfo.InvariantCulture); + h["align"] = ss; + } + } + } + + public FontFactoryImp FontImp { + get { + return fontImp; + } + set { + fontImp = value; + } + } + + public static Hashtable followTags = new Hashtable(); + + static FactoryProperties() { + followTags["i"] = "i"; + followTags["b"] = "b"; + followTags["u"] = "u"; + followTags["sub"] = "sub"; + followTags["sup"] = "sup"; + followTags["em"] = "i"; + followTags["strong"] = "b"; + followTags["s"] = "s"; + followTags["strike"] = "s"; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs b/iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs new file mode 100644 index 0000000..3a7bd57 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs @@ -0,0 +1,624 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.xml.simpleparser; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + public class HTMLWorker : ISimpleXMLDocHandler, IDocListener { + + protected ArrayList objectList; + protected IDocListener document; + private Paragraph currentParagraph; + private ChainedProperties cprops = new ChainedProperties(); + private Stack stack = new Stack(); + private bool pendingTR = false; + private bool pendingTD = false; + private bool pendingLI = false; + private StyleSheet style = new StyleSheet(); + private bool isPRE = false; + private Stack tableState = new Stack(); + private bool skipText = false; + private Hashtable interfaceProps; + private FactoryProperties factoryProperties = new FactoryProperties(); + + /** Creates a new instance of HTMLWorker */ + public HTMLWorker(IDocListener document) { + this.document = document; + } + + public StyleSheet Style { + set { + style = value; + } + get { + return style; + } + } + + public Hashtable InterfaceProps { + set { + interfaceProps = value; + FontFactoryImp ff = null; + if (interfaceProps != null) + ff = (FontFactoryImp)interfaceProps["font_factory"]; + if (ff != null) + factoryProperties.FontImp = ff; + } + get { + return interfaceProps; + } + } + + public void Parse(TextReader reader) { + SimpleXMLParser.Parse(this, null, reader, true); + } + + public static ArrayList ParseToList(TextReader reader, StyleSheet style) { + return ParseToList(reader, style, null); + } + + public static ArrayList ParseToList(TextReader reader, StyleSheet style, Hashtable interfaceProps) { + HTMLWorker worker = new HTMLWorker(null); + if (style != null) + worker.Style = style; + worker.document = worker; + worker.InterfaceProps = interfaceProps; + worker.objectList = new ArrayList(); + worker.Parse(reader); + return worker.objectList; + } + + public virtual void EndDocument() { + foreach (IElement e in stack) + document.Add(e); + if (currentParagraph != null) + document.Add(currentParagraph); + currentParagraph = null; + } + + public virtual void StartDocument() { + Hashtable h = new Hashtable(); + style.ApplyStyle("body", h); + cprops.AddToChain("body", h); + } + + public virtual void StartElement(String tag, Hashtable h) { + if (!tagsSupported.ContainsKey(tag)) + return; + style.ApplyStyle(tag, h); + String follow = (String)FactoryProperties.followTags[tag]; + if (follow != null) { + Hashtable prop = new Hashtable(); + prop[follow] = null; + cprops.AddToChain(follow, prop); + return; + } + FactoryProperties.InsertStyle(h); + if (tag.Equals("a")) { + cprops.AddToChain(tag, h); + if (currentParagraph == null) + currentParagraph = new Paragraph(); + stack.Push(currentParagraph); + currentParagraph = new Paragraph(); + return; + } + if (tag.Equals("br")) { + if (currentParagraph == null) + currentParagraph = new Paragraph(); + currentParagraph.Add(factoryProperties.CreateChunk("\n", cprops)); + return; + } + if (tag.Equals("font") || tag.Equals("span")) { + cprops.AddToChain(tag, h); + return; + } + if (tag.Equals("img")) { + String src = (String)h["src"]; + if (src == null) + return; + cprops.AddToChain(tag, h); + Image img = null; + if (interfaceProps != null) { + IImageProvider ip = (IImageProvider)interfaceProps["img_provider"]; + if (ip != null) + img = ip.GetImage(src, h, cprops, document); + if (img == null) { + Hashtable images = (Hashtable)interfaceProps["img_static"]; + if (images != null) { + Image tim = (Image)images[src]; + if (tim != null) + img = Image.GetInstance(tim); + } else { + if (!src.StartsWith("http")) { // relative src references only + String baseurl = (String)interfaceProps["img_baseurl"]; + if (baseurl != null) { + src = baseurl + src; + img = Image.GetInstance(src); + } + } + } + } + } + if (img == null) { + if (!src.StartsWith("http")) { + String path = cprops["image_path"]; + if (path == null) + path = ""; + src = Path.Combine(path, src); + } + img = Image.GetInstance(src); + } + String align = (String)h["align"]; + String width = (String)h["width"]; + String height = (String)h["height"]; + String before = cprops["before"]; + String after = cprops["after"]; + if (before != null) + img.SpacingBefore = float.Parse(before, System.Globalization.NumberFormatInfo.InvariantInfo); + if (after != null) + img.SpacingAfter = float.Parse(after, System.Globalization.NumberFormatInfo.InvariantInfo); + float wp = LengthParse(width, (int)img.Width); + float lp = LengthParse(height, (int)img.Height); + if (wp > 0 && lp > 0) + img.ScalePercent(wp > lp ? lp : wp); + else if (wp > 0) + img.ScalePercent(wp); + else if (lp > 0) + img.ScalePercent(lp); + img.WidthPercentage = 0; + if (align != null) { + EndElement("p"); + int ralign = Image.MIDDLE_ALIGN; + if (Util.EqualsIgnoreCase(align, "left")) + ralign = Image.LEFT_ALIGN; + else if (Util.EqualsIgnoreCase(align, "right")) + ralign = Image.RIGHT_ALIGN; + img.Alignment = ralign; + IImg i = null; + bool skip = false; + if (interfaceProps != null) { + i = (IImg)interfaceProps["img_interface"]; + if (i != null) + skip = i.Process(img, h, cprops, document); + } + if (!skip) + document.Add(img); + cprops.RemoveChain(tag); + } + else { + cprops.RemoveChain(tag); + if (currentParagraph == null) + currentParagraph = FactoryProperties.CreateParagraph(cprops); + currentParagraph.Add(new Chunk(img, 0, 0)); + } + return; + } + + EndElement("p"); + if (tag.Equals("h1") || tag.Equals("h2") || tag.Equals("h3") || tag.Equals("h4") || tag.Equals("h5") || tag.Equals("h6")) { + if (!h.ContainsKey("size")) { + int v = 7 - int.Parse(tag.Substring(1)); + h["size"] = v.ToString(); + } + cprops.AddToChain(tag, h); + return; + } + if (tag.Equals("ul")) { + if (pendingLI) + EndElement("li"); + skipText = true; + cprops.AddToChain(tag, h); + List list = new List(false, 10); + list.SetListSymbol("\u2022"); + stack.Push(list); + return; + } + if (tag.Equals("ol")) { + if (pendingLI) + EndElement("li"); + skipText = true; + cprops.AddToChain(tag, h); + List list = new List(true, 10); + stack.Push(list); + return; + } + if (tag.Equals("li")) { + if (pendingLI) + EndElement("li"); + skipText = false; + pendingLI = true; + cprops.AddToChain(tag, h); + stack.Push(FactoryProperties.CreateListItem(cprops)); + return; + } + if (tag.Equals("div") || tag.Equals("body")) { + cprops.AddToChain(tag, h); + return; + } + if (tag.Equals("pre")) { + if (!h.ContainsKey("face")) { + h["face"] = "Courier"; + } + cprops.AddToChain(tag, h); + isPRE = true; + return; + } + if (tag.Equals("p")) { + cprops.AddToChain(tag, h); + currentParagraph = FactoryProperties.CreateParagraph(h); + return; + } + if (tag.Equals("tr")) { + if (pendingTR) + EndElement("tr"); + skipText = true; + pendingTR = true; + cprops.AddToChain("tr", h); + return; + } + if (tag.Equals("td") || tag.Equals("th")) { + if (pendingTD) + EndElement(tag); + skipText = false; + pendingTD = true; + cprops.AddToChain("td", h); + stack.Push(new IncCell(tag, cprops)); + return; + } + if (tag.Equals("table")) { + cprops.AddToChain("table", h); + IncTable table = new IncTable(h); + stack.Push(table); + tableState.Push(new bool[]{pendingTR, pendingTD}); + pendingTR = pendingTD = false; + skipText = true; + return; + } + } + + public virtual void EndElement(String tag) { + if (!tagsSupported.ContainsKey(tag)) + return; + String follow = (String)FactoryProperties.followTags[tag]; + if (follow != null) { + cprops.RemoveChain(follow); + return; + } + if (tag.Equals("font") || tag.Equals("span")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("a")) { + if (currentParagraph == null) + currentParagraph = new Paragraph(); + IALink i = null; + bool skip = false; + if (interfaceProps != null) { + i = (IALink)interfaceProps["alink_interface"]; + if (i != null) + skip = i.Process(currentParagraph, cprops); + } + if (!skip) { + String href = cprops["href"]; + if (href != null) { + ArrayList chunks = currentParagraph.Chunks; + for (int k = 0; k < chunks.Count; ++k) { + Chunk ck = (Chunk)chunks[k]; + ck.SetAnchor(href); + } + } + } + Paragraph tmp = (Paragraph)stack.Pop(); + Phrase tmp2 = new Phrase(); + tmp2.Add(currentParagraph); + tmp.Add(tmp2); + currentParagraph = tmp; + cprops.RemoveChain("a"); + return; + } + if (tag.Equals("br")) { + return; + } + if (currentParagraph != null) { + if (stack.Count == 0) + document.Add(currentParagraph); + else { + Object obj = stack.Pop(); + if (obj is ITextElementArray) { + ITextElementArray current = (ITextElementArray)obj; + current.Add(currentParagraph); + } + stack.Push(obj); + } + } + currentParagraph = null; + if (tag.Equals("ul") || tag.Equals("ol")) { + if (pendingLI) + EndElement("li"); + skipText = false; + cprops.RemoveChain(tag); + if (stack.Count == 0) + return; + Object obj = stack.Pop(); + if (!(obj is List)) { + stack.Push(obj); + return; + } + if (stack.Count == 0) + document.Add((IElement)obj); + else + ((ITextElementArray)stack.Peek()).Add(obj); + return; + } + if (tag.Equals("li")) { + pendingLI = false; + skipText = true; + cprops.RemoveChain(tag); + if (stack.Count == 0) + return; + Object obj = stack.Pop(); + if (!(obj is ListItem)) { + stack.Push(obj); + return; + } + if (stack.Count == 0) { + document.Add((IElement)obj); + return; + } + Object list = stack.Pop(); + if (!(list is List)) { + stack.Push(list); + return; + } + ListItem item = (ListItem)obj; + ((List)list).Add(item); + ArrayList cks = item.Chunks; + if (cks.Count > 0) + item.ListSymbol.Font = ((Chunk)cks[0]).Font; + stack.Push(list); + return; + } + if (tag.Equals("div") || tag.Equals("body")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("pre")) { + cprops.RemoveChain(tag); + isPRE = false; + return; + } + if (tag.Equals("p")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("h1") || tag.Equals("h2") || tag.Equals("h3") || tag.Equals("h4") || tag.Equals("h5") || tag.Equals("h6")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("table")) { + if (pendingTR) + EndElement("tr"); + cprops.RemoveChain("table"); + IncTable table = (IncTable) stack.Pop(); + PdfPTable tb = table.BuildTable(); + tb.SplitRows = true; + if (stack.Count == 0) + document.Add(tb); + else + ((ITextElementArray)stack.Peek()).Add(tb); + bool[] state = (bool[])tableState.Pop(); + pendingTR = state[0]; + pendingTD = state[1]; + skipText = false; + return; + } + if (tag.Equals("tr")) { + if (pendingTD) + EndElement("td"); + pendingTR = false; + cprops.RemoveChain("tr"); + ArrayList cells = new ArrayList(); + IncTable table = null; + while (true) { + Object obj = stack.Pop(); + if (obj is IncCell) { + cells.Add(((IncCell)obj).Cell); + } + if (obj is IncTable) { + table = (IncTable)obj; + break; + } + } + table.AddCols(cells); + table.EndRow(); + stack.Push(table); + skipText = true; + return; + } + if (tag.Equals("td") || tag.Equals("th")) { + pendingTD = false; + cprops.RemoveChain("td"); + skipText = true; + return; + } + } + + public virtual void Text(String str) { + if (skipText) + return; + String content = str; + if (isPRE) { + if (currentParagraph == null) + currentParagraph = FactoryProperties.CreateParagraph(cprops); + currentParagraph.Add(factoryProperties.CreateChunk(content, cprops)); + return; + } + if (content.Trim().Length == 0 && content.IndexOf(' ') < 0) { + return; + } + + StringBuilder buf = new StringBuilder(); + int len = content.Length; + char character; + bool newline = false; + for (int i = 0; i < len; i++) { + switch (character = content[i]) { + case ' ': + if (!newline) { + buf.Append(character); + } + break; + case '\n': + if (i > 0) { + newline = true; + buf.Append(' '); + } + break; + case '\r': + break; + case '\t': + break; + default: + newline = false; + buf.Append(character); + break; + } + } + if (currentParagraph == null) + currentParagraph = FactoryProperties.CreateParagraph(cprops); + currentParagraph.Add(factoryProperties.CreateChunk(buf.ToString(), cprops)); + } + + public bool Add(IElement element) { + objectList.Add(element); + return true; + } + + public void ClearTextWrap() { + } + + public void Close() { + } + + public bool NewPage() { + return true; + } + + public void Open() { + } + + public void ResetFooter() { + } + + public void ResetHeader() { + } + + public void ResetPageCount() { + } + + public bool SetMarginMirroring(bool marginMirroring) { + return true; + } + + public bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) { + return true; + } + + public bool SetPageSize(Rectangle pageSize) { + return true; + } + + public const String tagsSupportedString = "ol ul li a pre font span br p div body table td th tr i b u sub sup em strong s strike" + + " h1 h2 h3 h4 h5 h6 img"; + + public static Hashtable tagsSupported = new Hashtable(); + + static HTMLWorker() { + StringTokenizer tok = new StringTokenizer(tagsSupportedString); + while (tok.HasMoreTokens()) + tagsSupported[tok.NextToken()] = null; + } + + public HeaderFooter Footer { + set { + } + } + + public HeaderFooter Header { + set { + } + } + + public int PageCount { + set { + } + } + + private static float LengthParse(String txt, int c) { + if (txt == null) + return -1; + if (txt.EndsWith("%")) { + float vf = float.Parse(txt.Substring(0, txt.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + return vf; + } + if (txt.EndsWith("px")) { + float vf = float.Parse(txt.Substring(0, txt.Length - 2), System.Globalization.NumberFormatInfo.InvariantInfo); + return vf; + } + int v = int.Parse(txt); + return (float)v / c * 100f; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs new file mode 100644 index 0000000..ee2d897 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs @@ -0,0 +1,54 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2005 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + public interface IALink { + bool Process(Paragraph current, ChainedProperties cprops); + } +} diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs new file mode 100644 index 0000000..820933b --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; +using iTextSharp.text; +/* + * Copyright 2007 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + public interface IImageProvider { + Image GetImage(String src, Hashtable h, ChainedProperties cprops, IDocListener doc); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs new file mode 100644 index 0000000..6eeb6f4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; +using iTextSharp.text; + +/* + * Copyright 2005 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.html.simpleparser { + public interface IImg { + bool Process(Image img, Hashtable h, ChainedProperties cprops, IDocListener doc); + } +} diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs new file mode 100644 index 0000000..acd3387 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.html; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + /** + * + * @author psoares + */ + public class IncCell : ITextElementArray { + + private ArrayList chunks = new ArrayList(); + private PdfPCell cell; + + /** Creates a new instance of IncCell */ + public IncCell(String tag, ChainedProperties props) { + cell = new PdfPCell(); + String value = props["colspan"]; + if (value != null) + cell.Colspan = int.Parse(value); + value = props["align"]; + if (tag.Equals("th")) + cell.HorizontalAlignment = Element.ALIGN_CENTER; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "center")) + cell.HorizontalAlignment = Element.ALIGN_CENTER; + else if (Util.EqualsIgnoreCase(value, "right")) + cell.HorizontalAlignment = Element.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(value, "left")) + cell.HorizontalAlignment = Element.ALIGN_LEFT; + else if (Util.EqualsIgnoreCase(value, "justify")) + cell.HorizontalAlignment = Element.ALIGN_JUSTIFIED; + } + value = props["valign"]; + cell.VerticalAlignment = Element.ALIGN_MIDDLE; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "top")) + cell.VerticalAlignment = Element.ALIGN_TOP; + else if (Util.EqualsIgnoreCase(value, "bottom")) + cell.VerticalAlignment = Element.ALIGN_BOTTOM; + } + value = props["border"]; + float border = 0; + if (value != null) + border = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + cell.BorderWidth = border; + value = props["cellpadding"]; + if (value != null) + cell.Padding = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + cell.UseDescender = true; + value = props["bgcolor"]; + cell.BackgroundColor = Markup.DecodeColor(value); + } + + public bool Add(Object o) { + if (!(o is IElement)) + return false; + cell.AddElement((IElement)o); + return true; + } + + public ArrayList Chunks { + get { + return chunks; + } + } + + public bool Process(IElementListener listener) { + return true; + } + + public int Type { + get { + return Element.RECTANGLE; + } + } + + public PdfPCell Cell { + get { + return cell; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + public override string ToString() { + return base.ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs new file mode 100644 index 0000000..d71c9bd --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + /** + * + * @author psoares + */ + public class IncTable { + private Hashtable props = new Hashtable(); + private ArrayList rows = new ArrayList(); + private ArrayList cols; + /** Creates a new instance of IncTable */ + public IncTable(Hashtable props) { + foreach (DictionaryEntry dc in props) + this.props[dc.Key] = dc.Value; + } + + public void AddCol(PdfPCell cell) { + if (cols == null) + cols = new ArrayList(); + cols.Add(cell); + } + + public void AddCols(ArrayList ncols) { + if (cols == null) + cols = new ArrayList(ncols); + else + cols.AddRange(ncols); + } + + public void EndRow() { + if (cols != null) { + cols.Reverse(); + rows.Add(cols); + cols = null; + } + } + + public ArrayList Rows { + get { + return rows; + } + } + + public PdfPTable BuildTable() { + if (rows.Count == 0) + return new PdfPTable(1); + int ncol = 0; + ArrayList c0 = (ArrayList)rows[0]; + for (int k = 0; k < c0.Count; ++k) { + ncol += ((PdfPCell)c0[k]).Colspan; + } + PdfPTable table = new PdfPTable(ncol); + String width = (String)props["width"]; + if (width == null) + table.WidthPercentage = 100; + else { + if (width.EndsWith("%")) + table.WidthPercentage = float.Parse(width.Substring(0, width.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + else { + table.TotalWidth = float.Parse(width, System.Globalization.NumberFormatInfo.InvariantInfo); + table.LockedWidth = true; + } + } + for (int row = 0; row < rows.Count; ++row) { + ArrayList col = (ArrayList)rows[row]; + for (int k = 0; k < col.Count; ++k) { + table.AddCell((PdfPCell)col[k]); + } + } + return table; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs b/iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs new file mode 100644 index 0000000..707e53f --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + public class StyleSheet { + + public Hashtable classMap = new Hashtable(); + public Hashtable tagMap = new Hashtable(); + + /** Creates a new instance of StyleSheet */ + public StyleSheet() { + } + + public void ApplyStyle(String tag, Hashtable props) { + Hashtable map = (Hashtable)tagMap[tag.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + Hashtable temp; + if (map != null) { + temp = new Hashtable(map); + foreach (DictionaryEntry dc in props) + temp[dc.Key] = dc.Value; + foreach (DictionaryEntry dc in temp) + props[dc.Key] = dc.Value; + } + String cm = (String)props["class"]; + if (cm == null) + return; + map = (Hashtable)classMap[cm.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (map == null) + return; + props.Remove("class"); + temp = new Hashtable(map); + foreach (DictionaryEntry dc in props) + temp[dc.Key] = dc.Value; + foreach (DictionaryEntry dc in temp) + props[dc.Key] = dc.Value; + } + + private void ApplyMap(Hashtable map, Hashtable props) { + + } + + public void LoadStyle(String style, Hashtable props) { + classMap[style.ToLower(System.Globalization.CultureInfo.InvariantCulture)] = props; + } + + public void LoadStyle(String style, String key, String value) { + style = style.ToLower(System.Globalization.CultureInfo.InvariantCulture); + Hashtable props = (Hashtable)classMap[style]; + if (props == null) { + props = new Hashtable(); + classMap[style] = props; + } + props[key] = value; + } + + public void LoadTagStyle(String tag, Hashtable props) { + tagMap[tag.ToLower(System.Globalization.CultureInfo.InvariantCulture)] = props; + } + + public void LoadTagStyle(String tag, String key, String value) { + tag = tag.ToLower(System.Globalization.CultureInfo.InvariantCulture); + Hashtable props = (Hashtable)tagMap[tag]; + if (props == null) { + props = new Hashtable(); + tagMap[tag] = props; + } + props[key] = value; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/AcroFields.cs b/iTechSharp/iTextSharp/text/pdf/AcroFields.cs new file mode 100644 index 0000000..7508c8f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/AcroFields.cs @@ -0,0 +1,2126 @@ +using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.util; +/* + * Copyright 2003-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Query and change fields in existing documents either by method + * calls or by FDF merging. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class AcroFields { + + internal PdfReader reader; + internal PdfWriter writer; + internal Hashtable fields; + private int topFirst; + private Hashtable sigNames; + private bool append; + public const int DA_FONT = 0; + public const int DA_SIZE = 1; + public const int DA_COLOR = 2; + private Hashtable extensionFonts = new Hashtable(); + private XfaForm xfa; + /** + * A field type invalid or not found. + */ + public const int FIELD_TYPE_NONE = 0; + /** + * A field type. + */ + public const int FIELD_TYPE_PUSHBUTTON = 1; + /** + * A field type. + */ + public const int FIELD_TYPE_CHECKBOX = 2; + /** + * A field type. + */ + public const int FIELD_TYPE_RADIOBUTTON = 3; + /** + * A field type. + */ + public const int FIELD_TYPE_TEXT = 4; + /** + * A field type. + */ + public const int FIELD_TYPE_LIST = 5; + /** + * A field type. + */ + public const int FIELD_TYPE_COMBO = 6; + /** + * A field type. + */ + public const int FIELD_TYPE_SIGNATURE = 7; + + private bool lastWasString; + + /** Holds value of property generateAppearances. */ + private bool generateAppearances = true; + + private Hashtable localFonts = new Hashtable(); + + private float extraMarginLeft; + private float extraMarginTop; + private ArrayList substitutionFonts; + + internal AcroFields(PdfReader reader, PdfWriter writer) { + this.reader = reader; + this.writer = writer; + xfa = new XfaForm(reader); + if (writer is PdfStamperImp) { + append = ((PdfStamperImp)writer).append; + } + Fill(); + } + + internal void Fill() { + fields = new Hashtable(); + PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObjectRelease(reader.Catalog.Get(PdfName.ACROFORM)); + if (top == null) + return; + PdfArray arrfds = (PdfArray)PdfReader.GetPdfObjectRelease(top.Get(PdfName.FIELDS)); + if (arrfds == null || arrfds.Size == 0) + return; + arrfds = null; + for (int k = 1; k <= reader.NumberOfPages; ++k) { + PdfDictionary page = reader.GetPageNRelease(k); + PdfArray annots = (PdfArray)PdfReader.GetPdfObjectRelease(page.Get(PdfName.ANNOTS), page); + if (annots == null) + continue; + ArrayList arr = annots.ArrayList; + for (int j = 0; j < arr.Count; ++j) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)arr[j], annots); + if (!(annoto is PdfDictionary)) { + PdfReader.ReleaseLastXrefPartial((PdfObject)arr[j]); + continue; + } + PdfDictionary annot = (PdfDictionary)annoto; + if (!PdfName.WIDGET.Equals(annot.Get(PdfName.SUBTYPE))) { + PdfReader.ReleaseLastXrefPartial((PdfObject)arr[j]); + continue; + } + PdfDictionary widget = annot; + PdfDictionary dic = new PdfDictionary(); + dic.Merge(annot); + String name = ""; + PdfDictionary value = null; + PdfObject lastV = null; + while (annot != null) { + dic.MergeDifferent(annot); + PdfString t = (PdfString)PdfReader.GetPdfObject(annot.Get(PdfName.T)); + if (t != null) + name = t.ToUnicodeString() + "." + name; + if (lastV == null && annot.Get(PdfName.V) != null) + lastV = PdfReader.GetPdfObjectRelease(annot.Get(PdfName.V)); + if (value == null && t != null) { + value = annot; + if (annot.Get(PdfName.V) == null && lastV != null) + value.Put(PdfName.V, lastV); + } + annot = (PdfDictionary)PdfReader.GetPdfObject(annot.Get(PdfName.PARENT), annot); + } + if (name.Length > 0) + name = name.Substring(0, name.Length - 1); + Item item = (Item)fields[name]; + if (item == null) { + item = new Item(); + fields[name] = item; + } + if (value == null) + item.values.Add(widget); + else + item.values.Add(value); + item.widgets.Add(widget); + item.widget_refs.Add(arr[j]); // must be a reference + if (top != null) + dic.MergeDifferent(top); + item.merged.Add(dic); + item.page.Add(k); + item.tabOrder.Add(j); + } + } + } + + /** Gets the list of appearance names. Use it to get the names allowed + * with radio and checkbox fields. If the /Opt key exists the values will + * also be included. The name 'Off' may also be valid + * even if not returned in the list. + * @param fieldName the fully qualified field name + * @return the list of names or null if the field does not exist + */ + public String[] GetAppearanceStates(String fieldName) { + Item fd = (Item)fields[fieldName]; + if (fd == null) + return null; + Hashtable names = new Hashtable(); + PdfDictionary vals = (PdfDictionary)fd.values[0]; + PdfObject opts = PdfReader.GetPdfObject(vals.Get(PdfName.OPT)); + if (opts != null) { + if (opts.IsString()) + names[((PdfString)opts).ToUnicodeString()] = null; + else if (opts.IsArray()) { + ArrayList list = ((PdfArray)opts).ArrayList; + for (int k = 0; k < list.Count; ++k) { + PdfObject v = PdfReader.GetPdfObject((PdfObject)list[k]); + if (v != null && v.IsString()) + names[((PdfString)v).ToUnicodeString()] = null; + } + } + } + ArrayList wd = fd.widgets; + for (int k = 0; k < wd.Count; ++k) { + PdfDictionary dic = (PdfDictionary)wd[k]; + dic = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.AP)); + if (dic == null) + continue; + PdfObject ob = PdfReader.GetPdfObject(dic.Get(PdfName.N)); + if (ob == null || !ob.IsDictionary()) + continue; + dic = (PdfDictionary)ob; + foreach (PdfName pname in dic.Keys) { + String name = PdfName.DecodeName(pname.ToString()); + names[name] = null; + } + } + string[] outs = new string[names.Count]; + names.Keys.CopyTo(outs, 0); + return outs; + } + + private String[] GetListOption(String fieldName, int idx) { + Item fd = GetFieldItem(fieldName); + if (fd == null) + return null; + PdfObject obj = PdfReader.GetPdfObject(((PdfDictionary)fd.merged[0]).Get(PdfName.OPT)); + if (obj == null || !obj.IsArray()) + return null; + PdfArray ar = (PdfArray)obj; + String[] ret = new String[ar.Size]; + ArrayList a = ar.ArrayList; + for (int k = 0; k < a.Count; ++k) { + obj = PdfReader.GetPdfObject((PdfObject)a[k]); + try { + if (obj.IsArray()) { + obj = (PdfObject)((PdfArray)obj).ArrayList[idx]; + } + if (obj.IsString()) + ret[k] = ((PdfString)obj).ToUnicodeString(); + else + ret[k] = obj.ToString(); + } + catch { + ret[k] = ""; + } + } + return ret; + } + + /** + * Gets the list of export option values from fields of type list or combo. + * If the field doesn't exist or the field type is not list or combo it will return + * null. + * @param fieldName the field name + * @return the list of export option values from fields of type list or combo + */ + public String[] GetListOptionExport(String fieldName) { + return GetListOption(fieldName, 0); + } + + /** + * Gets the list of display option values from fields of type list or combo. + * If the field doesn't exist or the field type is not list or combo it will return + * null. + * @param fieldName the field name + * @return the list of export option values from fields of type list or combo + */ + public String[] GetListOptionDisplay(String fieldName) { + return GetListOption(fieldName, 1); + } + + /** + * Sets the option list for fields of type list or combo. One of exportValues + * or displayValues may be null but not both. This method will only + * set the list but will not set the value or appearance. For that, calling setField() + * is required. + *

+ * An example: + *

+ *

+        * PdfReader pdf = new PdfReader("input.pdf");
+        * PdfStamper stp = new PdfStamper(pdf, new FileOutputStream("output.pdf"));
+        * AcroFields af = stp.GetAcroFields();
+        * af.SetListOption("ComboBox", new String[]{"a", "b", "c"}, new String[]{"first", "second", "third"});
+        * af.SetField("ComboBox", "b");
+        * stp.Close();
+        * 
+ * @param fieldName the field name + * @param exportValues the export values + * @param displayValues the display values + * @return true if the operation succeeded, false otherwise + */ + public bool SetListOption(String fieldName, String[] exportValues, String[] displayValues) { + if (exportValues == null && displayValues == null) + return false; + if (exportValues != null && displayValues != null && exportValues.Length != displayValues.Length) + throw new ArgumentException("The export and the display array must have the same size."); + int ftype = GetFieldType(fieldName); + if (ftype != FIELD_TYPE_COMBO && ftype != FIELD_TYPE_LIST) + return false; + Item fd = (Item)fields[fieldName]; + String[] sing = null; + if (exportValues == null && displayValues != null) + sing = displayValues; + else if (exportValues != null && displayValues == null) + sing = exportValues; + PdfArray opt = new PdfArray(); + if (sing != null) { + for (int k = 0; k < sing.Length; ++k) + opt.Add(new PdfString(sing[k], PdfObject.TEXT_UNICODE)); + } + else { + for (int k = 0; k < exportValues.Length; ++k) { + PdfArray a = new PdfArray(); + a.Add(new PdfString(exportValues[k], PdfObject.TEXT_UNICODE)); + a.Add(new PdfString(displayValues[k], PdfObject.TEXT_UNICODE)); + opt.Add(a); + } + } + ((PdfDictionary)fd.values[0]).Put(PdfName.OPT, opt); + for (int j = 0; j < fd.merged.Count; ++j) + ((PdfDictionary)fd.merged[j]).Put(PdfName.OPT, opt); + return true; + } + + /** + * Gets the field type. The type can be one of: FIELD_TYPE_PUSHBUTTON, + * FIELD_TYPE_CHECKBOX, FIELD_TYPE_RADIOBUTTON, + * FIELD_TYPE_TEXT, FIELD_TYPE_LIST, + * FIELD_TYPE_COMBO or FIELD_TYPE_SIGNATURE. + *

+ * If the field does not exist or is invalid it returns + * FIELD_TYPE_NONE. + * @param fieldName the field name + * @return the field type + */ + public int GetFieldType(String fieldName) { + Item fd = GetFieldItem(fieldName); + if (fd == null) + return FIELD_TYPE_NONE; + PdfObject type = PdfReader.GetPdfObject(((PdfDictionary)fd.merged[0]).Get(PdfName.FT)); + if (type == null) + return FIELD_TYPE_NONE; + int ff = 0; + PdfObject ffo = PdfReader.GetPdfObject(((PdfDictionary)fd.merged[0]).Get(PdfName.FF)); + if (ffo != null && ffo.Type == PdfObject.NUMBER) + ff = ((PdfNumber)ffo).IntValue; + if (PdfName.BTN.Equals(type)) { + if ((ff & PdfFormField.FF_PUSHBUTTON) != 0) + return FIELD_TYPE_PUSHBUTTON; + if ((ff & PdfFormField.FF_RADIO) != 0) + return FIELD_TYPE_RADIOBUTTON; + else + return FIELD_TYPE_CHECKBOX; + } + else if (PdfName.TX.Equals(type)) { + return FIELD_TYPE_TEXT; + } + else if (PdfName.CH.Equals(type)) { + if ((ff & PdfFormField.FF_COMBO) != 0) + return FIELD_TYPE_COMBO; + else + return FIELD_TYPE_LIST; + } + else if (PdfName.SIG.Equals(type)) { + return FIELD_TYPE_SIGNATURE; + } + return FIELD_TYPE_NONE; + } + + /** + * Export the fields as a FDF. + * @param writer the FDF writer + */ + public void ExportAsFdf(FdfWriter writer) { + foreach (DictionaryEntry entry in fields) { + Item item = (Item)entry.Value; + string name = (String)entry.Key; + PdfObject v = PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.V)); + if (v == null) + continue; + string value = GetField(name); + if (lastWasString) + writer.SetFieldAsString(name, value); + else + writer.SetFieldAsName(name, value); + } + } + + /** + * Renames a field. Only the last part of the name can be renamed. For example, + * if the original field is "ab.cd.ef" only the "ef" part can be renamed. + * @param oldName the old field name + * @param newName the new field name + * @return true if the renaming was successful, false + * otherwise + */ + public bool RenameField(String oldName, String newName) { + int idx1 = oldName.LastIndexOf('.') + 1; + int idx2 = newName.LastIndexOf('.') + 1; + if (idx1 != idx2) + return false; + if (!oldName.Substring(0, idx1).Equals(newName.Substring(0, idx2))) + return false; + if (fields.ContainsKey(newName)) + return false; + Item item = (Item)fields[oldName]; + if (item == null) + return false; + newName = newName.Substring(idx2); + PdfString ss = new PdfString(newName, PdfObject.TEXT_UNICODE); + for (int k = 0; k < item.merged.Count; ++k) { + PdfDictionary dic = (PdfDictionary)item.values[k]; + dic.Put(PdfName.T, ss); + MarkUsed(dic); + dic = (PdfDictionary)item.merged[k]; + dic.Put(PdfName.T, ss); + } + fields.Remove(oldName); + fields[newName] = item; + return true; + } + + public static Object[] SplitDAelements(String da) { + PRTokeniser tk = new PRTokeniser(PdfEncodings.ConvertToBytes(da, null)); + ArrayList stack = new ArrayList(); + Object[] ret = new Object[3]; + while (tk.NextToken()) { + if (tk.TokenType == PRTokeniser.TK_COMMENT) + continue; + if (tk.TokenType == PRTokeniser.TK_OTHER) { + String oper = tk.StringValue; + if (oper.Equals("Tf")) { + if (stack.Count >= 2) { + ret[DA_FONT] = stack[stack.Count - 2]; + ret[DA_SIZE] = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + else if (oper.Equals("g")) { + if (stack.Count >= 1) { + float gray = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + if (gray != 0) + ret[DA_COLOR] = new GrayColor(gray); + } + } + else if (oper.Equals("rg")) { + if (stack.Count >= 3) { + float red = float.Parse((String)stack[stack.Count - 3], System.Globalization.NumberFormatInfo.InvariantInfo); + float green = float.Parse((String)stack[stack.Count - 2], System.Globalization.NumberFormatInfo.InvariantInfo); + float blue = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + ret[DA_COLOR] = new Color(red, green, blue); + } + } + else if (oper.Equals("k")) { + if (stack.Count >= 4) { + float cyan = float.Parse((String)stack[stack.Count - 4], System.Globalization.NumberFormatInfo.InvariantInfo); + float magenta = float.Parse((String)stack[stack.Count - 3], System.Globalization.NumberFormatInfo.InvariantInfo); + float yellow = float.Parse((String)stack[stack.Count - 2], System.Globalization.NumberFormatInfo.InvariantInfo); + float black = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + ret[DA_COLOR] = new CMYKColor(cyan, magenta, yellow, black); + } + } + stack.Clear(); + } + else + stack.Add(tk.StringValue); + } + return ret; + } + + public void DecodeGenericDictionary(PdfDictionary merged, BaseField tx) { + int flags = 0; + // the text size and color + PdfString da = (PdfString)PdfReader.GetPdfObject(merged.Get(PdfName.DA)); + if (da != null) { + Object[] dab = SplitDAelements(da.ToUnicodeString()); + if (dab[DA_SIZE] != null) + tx.FontSize = (float)dab[DA_SIZE]; + if (dab[DA_COLOR] != null) + tx.TextColor = (Color)dab[DA_COLOR]; + if (dab[DA_FONT] != null) { + PdfDictionary font = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.DR)); + if (font != null) { + font = (PdfDictionary)PdfReader.GetPdfObject(font.Get(PdfName.FONT)); + if (font != null) { + PdfObject po = font.Get(new PdfName((String)dab[DA_FONT])); + if (po != null && po.Type == PdfObject.INDIRECT) { + PRIndirectReference por = (PRIndirectReference)po; + BaseFont bp = new DocumentFont((PRIndirectReference)po); + tx.Font = bp; + int porkey = por.Number; + BaseFont porf = (BaseFont)extensionFonts[porkey]; + if (porf == null) { + if (!extensionFonts.ContainsKey(porkey)) { + PdfDictionary fo = (PdfDictionary)PdfReader.GetPdfObject(po); + PdfDictionary fd = (PdfDictionary)PdfReader.GetPdfObject(fo.Get(PdfName.FONTDESCRIPTOR)); + if (fd != null) { + PRStream prs = (PRStream)PdfReader.GetPdfObject(fd.Get(PdfName.FONTFILE2)); + if (prs == null) + prs = (PRStream)PdfReader.GetPdfObject(fd.Get(PdfName.FONTFILE3)); + if (prs == null) { + extensionFonts[porkey] = null; + } + else { + try { + porf = BaseFont.CreateFont("font.ttf", BaseFont.IDENTITY_H, true, false, PdfReader.GetStreamBytes(prs), null); + } + catch { + } + extensionFonts[porkey] = porf; + } + } + } + } + if (tx is TextField) + ((TextField)tx).ExtensionFont = porf; + } + else { + BaseFont bf = (BaseFont)localFonts[dab[DA_FONT]]; + if (bf == null) { + String[] fn = (String[])stdFieldFontNames[dab[DA_FONT]]; + if (fn != null) { + try { + String enc = "winansi"; + if (fn.Length > 1) + enc = fn[1]; + bf = BaseFont.CreateFont(fn[0], enc, false); + tx.Font = bf; + } + catch { + // empty + } + } + } + else + tx.Font = bf; + } + } + } + } + } + //rotation, border and backgound color + PdfDictionary mk = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.MK)); + if (mk != null) { + PdfArray ar = (PdfArray)PdfReader.GetPdfObject(mk.Get(PdfName.BC)); + Color border = GetMKColor(ar); + tx.BorderColor = border; + if (border != null) + tx.BorderWidth = 1; + ar = (PdfArray)PdfReader.GetPdfObject(mk.Get(PdfName.BG)); + tx.BackgroundColor = GetMKColor(ar); + PdfNumber rotation = (PdfNumber)PdfReader.GetPdfObject(mk.Get(PdfName.R)); + if (rotation != null) + tx.Rotation = rotation.IntValue; + } + //flags + PdfNumber nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.F)); + flags = 0; + tx.Visibility = BaseField.VISIBLE_BUT_DOES_NOT_PRINT; + if (nfl != null) { + flags = nfl.IntValue; + if ((flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) != 0) + tx.Visibility = BaseField.HIDDEN; + else if ((flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_NOVIEW) != 0) + tx.Visibility = BaseField.HIDDEN_BUT_PRINTABLE; + else if ((flags & PdfFormField.FLAGS_PRINT) != 0) + tx.Visibility = BaseField.VISIBLE; + } + //multiline + nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.FF)); + flags = 0; + if (nfl != null) + flags = nfl.IntValue; + tx.Options = flags; + if ((flags & PdfFormField.FF_COMB) != 0) { + PdfNumber maxLen = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.MAXLEN)); + int len = 0; + if (maxLen != null) + len = maxLen.IntValue; + tx.MaxCharacterLength = len; + } + //alignment + nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.Q)); + if (nfl != null) { + if (nfl.IntValue == PdfFormField.Q_CENTER) + tx.Alignment = Element.ALIGN_CENTER; + else if (nfl.IntValue == PdfFormField.Q_RIGHT) + tx.Alignment = Element.ALIGN_RIGHT; + } + //border styles + PdfDictionary bs = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.BS)); + if (bs != null) { + PdfNumber w = (PdfNumber)PdfReader.GetPdfObject(bs.Get(PdfName.W)); + if (w != null) + tx.BorderWidth = w.FloatValue; + PdfName s = (PdfName)PdfReader.GetPdfObject(bs.Get(PdfName.S)); + if (PdfName.D.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_DASHED; + else if (PdfName.B.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_BEVELED; + else if (PdfName.I.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_INSET; + else if (PdfName.U.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_UNDERLINE; + } + else { + PdfArray bd = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.BORDER)); + if (bd != null) { + ArrayList ar = bd.ArrayList; + if (ar.Count >= 3) + tx.BorderWidth = ((PdfNumber)ar[2]).FloatValue; + if (ar.Count >= 4) + tx.BorderStyle = PdfBorderDictionary.STYLE_DASHED; + } + } + } + + internal PdfAppearance GetAppearance(PdfDictionary merged, String text, String fieldName) { + topFirst = 0; + TextField tx = null; + if (fieldCache == null || !fieldCache.ContainsKey(fieldName)) { + tx = new TextField(writer, null, null); + tx.SetExtraMargin(extraMarginLeft, extraMarginTop); + tx.BorderWidth = 0; + tx.SubstitutionFonts = substitutionFonts; + DecodeGenericDictionary(merged, tx); + //rect + PdfArray rect = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT)); + Rectangle box = PdfReader.GetNormalizedRectangle(rect); + if (tx.Rotation == 90 || tx.Rotation == 270) + box = box.Rotate(); + tx.Box = box; + if (fieldCache != null) + fieldCache[fieldName] = tx; + } + else { + tx = (TextField)fieldCache[fieldName]; + tx.Writer = writer; + } + PdfName fieldType = (PdfName)PdfReader.GetPdfObject(merged.Get(PdfName.FT)); + if (PdfName.TX.Equals(fieldType)) { + tx.Text = text; + return tx.GetAppearance(); + } + if (!PdfName.CH.Equals(fieldType)) + throw new DocumentException("An appearance was requested without a variable text field."); + PdfArray opt = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.OPT)); + int flags = 0; + PdfNumber nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.FF)); + if (nfl != null) + flags = nfl.IntValue; + if ((flags & PdfFormField.FF_COMBO) != 0 && opt == null) { + tx.Text = text; + return tx.GetAppearance(); + } + if (opt != null) { + ArrayList op = opt.ArrayList; + String[] choices = new String[op.Count]; + String[] choicesExp = new String[op.Count]; + for (int k = 0; k < op.Count; ++k) { + PdfObject obj = (PdfObject)op[k]; + if (obj.IsString()) { + choices[k] = choicesExp[k] = ((PdfString)obj).ToUnicodeString(); + } + else { + ArrayList opar = ((PdfArray)obj).ArrayList; + choicesExp[k] = ((PdfString)opar[0]).ToUnicodeString(); + choices[k] = ((PdfString)opar[1]).ToUnicodeString(); + } + } + if ((flags & PdfFormField.FF_COMBO) != 0) { + for (int k = 0; k < choices.Length; ++k) { + if (text.Equals(choicesExp[k])) { + text = choices[k]; + break; + } + } + tx.Text = text; + return tx.GetAppearance(); + } + int idx = 0; + for (int k = 0; k < choicesExp.Length; ++k) { + if (text.Equals(choicesExp[k])) { + idx = k; + break; + } + } + tx.Choices = choices; + tx.ChoiceExports = choicesExp; + tx.ChoiceSelection = idx; + } + PdfAppearance app = tx.GetListAppearance(); + topFirst = tx.TopFirst; + return app; + } + + internal Color GetMKColor(PdfArray ar) { + if (ar == null) + return null; + ArrayList cc = ar.ArrayList; + switch (cc.Count) { + case 1: + return new GrayColor(((PdfNumber)cc[0]).FloatValue); + case 3: + return new Color(ExtendedColor.Normalize(((PdfNumber)cc[0]).FloatValue), ExtendedColor.Normalize(((PdfNumber)cc[1]).FloatValue), ExtendedColor.Normalize(((PdfNumber)cc[2]).FloatValue)); + case 4: + return new CMYKColor(((PdfNumber)cc[0]).FloatValue, ((PdfNumber)cc[1]).FloatValue, ((PdfNumber)cc[2]).FloatValue, ((PdfNumber)cc[3]).FloatValue); + default: + return null; + } + } + + /** Gets the field value. + * @param name the fully qualified field name + * @return the field value + */ + public String GetField(String name) { + if (xfa.XfaPresent) { + name = xfa.FindFieldName(name, this); + if (name == null) + return null; + name = XfaForm.Xml2Som.GetShortName(name); + return XfaForm.GetNodeText(xfa.FindDatasetsNode(name)); + } + Item item = (Item)fields[name]; + if (item == null) + return null; + lastWasString = false; + PdfObject v = PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.V)); + if (v == null) + return ""; + PdfName type = (PdfName)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FT)); + if (PdfName.BTN.Equals(type)) { + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FF)); + int flags = 0; + if (ff != null) + flags = ff.IntValue; + if ((flags & PdfFormField.FF_PUSHBUTTON) != 0) + return ""; + String value = ""; + if (v.IsName()) + value = PdfName.DecodeName(v.ToString()); + else if (v.IsString()) + value = ((PdfString)v).ToUnicodeString(); + PdfObject opts = PdfReader.GetPdfObject(((PdfDictionary)item.values[0]).Get(PdfName.OPT)); + if (opts != null && opts.IsArray()) { + ArrayList list = ((PdfArray)opts).ArrayList; + int idx = 0; + try { + idx = int.Parse(value); + PdfString ps = (PdfString)list[idx]; + value = ps.ToUnicodeString(); + lastWasString = true; + } + catch { + } + } + return value; + } + if (v.IsString()) { + lastWasString = true; + return ((PdfString)v).ToUnicodeString(); + } + return PdfName.DecodeName(v.ToString()); + } + + /** + * Sets a field property. Valid property names are: + *

+ *

    + *
  • textfont - sets the text font. The value for this entry is a BaseFont.
    + *
  • textcolor - sets the text color. The value for this entry is a java.awt.Color.
    + *
  • textsize - sets the text size. The value for this entry is a Float. + *
  • bgcolor - sets the background color. The value for this entry is a java.awt.Color. + * If null removes the background.
    + *
  • bordercolor - sets the border color. The value for this entry is a java.awt.Color. + * If null removes the border.
    + *
+ * @param field the field name + * @param name the property name + * @param value the property value + * @param inst an array of int indexing into AcroField.Item.merged elements to process. + * Set to null to process all + * @return true if the property exists, false otherwise + */ + public bool SetFieldProperty(String field, String name, Object value, int[] inst) { + if (writer == null) + throw new Exception("This AcroFields instance is read-only."); + Item item = (Item)fields[field]; + if (item == null) + return false; + InstHit hit = new InstHit(inst); + if (Util.EqualsIgnoreCase(name, "textfont")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfString da = (PdfString)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DA)); + PdfDictionary dr = (PdfDictionary)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DR)); + if (da != null && dr != null) { + Object[] dao = SplitDAelements(da.ToUnicodeString()); + PdfAppearance cb = new PdfAppearance(); + if (dao[DA_FONT] != null) { + BaseFont bf = (BaseFont)value; + PdfName psn = (PdfName)PdfAppearance.stdFieldFontNames[bf.PostscriptFontName]; + if (psn == null) { + psn = new PdfName(bf.PostscriptFontName); + } + PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fonts == null) { + fonts = new PdfDictionary(); + dr.Put(PdfName.FONT, fonts); + } + PdfIndirectReference fref = (PdfIndirectReference)fonts.Get(psn); + PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); + MarkUsed(top); + dr = (PdfDictionary)PdfReader.GetPdfObject(top.Get(PdfName.DR)); + if (dr == null) { + dr = new PdfDictionary(); + top.Put(PdfName.DR, dr); + } + MarkUsed(dr); + PdfDictionary fontsTop = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fontsTop == null) { + fontsTop = new PdfDictionary(); + dr.Put(PdfName.FONT, fontsTop); + } + MarkUsed(fontsTop); + PdfIndirectReference frefTop = (PdfIndirectReference)fontsTop.Get(psn); + if (frefTop != null) { + if (fref == null) + fonts.Put(psn, frefTop); + } + else if (fref == null) { + FontDetails fd; + if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { + fd = new FontDetails(null, ((DocumentFont)bf).IndirectReference, bf); + } + else { + bf.Subset = false; + fd = writer.AddSimple(bf); + localFonts[psn.ToString().Substring(1)] = bf; + } + fontsTop.Put(psn, fd.IndirectReference); + fonts.Put(psn, fd.IndirectReference); + } + ByteBuffer buf = cb.InternalBuffer; + buf.Append(psn.GetBytes()).Append(' ').Append((float)dao[DA_SIZE]).Append(" Tf "); + if (dao[DA_COLOR] != null) + cb.SetColorFill((Color)dao[DA_COLOR]); + PdfString s = new PdfString(cb.ToString()); + ((PdfDictionary)item.merged[k]).Put(PdfName.DA, s); + ((PdfDictionary)item.widgets[k]).Put(PdfName.DA, s); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + } + } + else if (Util.EqualsIgnoreCase(name, "textcolor")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfString da = (PdfString)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DA)); + if (da != null) { + Object[] dao = SplitDAelements(da.ToUnicodeString()); + PdfAppearance cb = new PdfAppearance(); + if (dao[DA_FONT] != null) { + ByteBuffer buf = cb.InternalBuffer; + buf.Append(new PdfName((String)dao[DA_FONT]).GetBytes()).Append(' ').Append((float)dao[DA_SIZE]).Append(" Tf "); + cb.SetColorFill((Color)value); + PdfString s = new PdfString(cb.ToString()); + ((PdfDictionary)item.merged[k]).Put(PdfName.DA, s); + ((PdfDictionary)item.widgets[k]).Put(PdfName.DA, s); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + } + } + else if (Util.EqualsIgnoreCase(name, "textsize")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfString da = (PdfString)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DA)); + if (da != null) { + Object[] dao = SplitDAelements(da.ToUnicodeString()); + PdfAppearance cb = new PdfAppearance(); + if (dao[DA_FONT] != null) { + ByteBuffer buf = cb.InternalBuffer; + buf.Append(new PdfName((String)dao[DA_FONT]).GetBytes()).Append(' ').Append((float)value).Append(" Tf "); + if (dao[DA_COLOR] != null) + cb.SetColorFill((Color)dao[DA_COLOR]); + PdfString s = new PdfString(cb.ToString()); + ((PdfDictionary)item.merged[k]).Put(PdfName.DA, s); + ((PdfDictionary)item.widgets[k]).Put(PdfName.DA, s); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + } + } + else if (Util.EqualsIgnoreCase(name, "bgcolor") || Util.EqualsIgnoreCase(name, "bordercolor")) { + PdfName dname = (Util.EqualsIgnoreCase(name, "bgcolor") ? PdfName.BG : PdfName.BC); + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfObject obj = PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.MK)); + MarkUsed(obj); + PdfDictionary mk = (PdfDictionary)obj; + if (mk == null) { + if (value == null) + return true; + mk = new PdfDictionary(); + ((PdfDictionary)item.merged[k]).Put(PdfName.MK, mk); + ((PdfDictionary)item.widgets[k]).Put(PdfName.MK, mk); + MarkUsed((PdfDictionary)item.widgets[k]); + } + if (value == null) + mk.Remove(dname); + else + mk.Put(dname, PdfFormField.GetMKColor((Color)value)); + } + } + } + else + return false; + return true; + } + + /** + * Sets a field property. Valid property names are: + *

+ *

    + *
  • flags - a set of flags specifying various characteristics of the field’s widget annotation. + * The value of this entry replaces that of the F entry in the form’s corresponding annotation dictionary.
    + *
  • setflags - a set of flags to be set (turned on) in the F entry of the form’s corresponding + * widget annotation dictionary. Bits equal to 1 cause the corresponding bits in F to be set to 1.
    + *
  • clrflags - a set of flags to be cleared (turned off) in the F entry of the form’s corresponding + * widget annotation dictionary. Bits equal to 1 cause the corresponding + * bits in F to be set to 0.
    + *
  • fflags - a set of flags specifying various characteristics of the field. The value + * of this entry replaces that of the Ff entry in the form’s corresponding field dictionary.
    + *
  • setfflags - a set of flags to be set (turned on) in the Ff entry of the form’s corresponding + * field dictionary. Bits equal to 1 cause the corresponding bits in Ff to be set to 1.
    + *
  • clrfflags - a set of flags to be cleared (turned off) in the Ff entry of the form’s corresponding + * field dictionary. Bits equal to 1 cause the corresponding bits in Ff + * to be set to 0.
    + *
+ * @param field the field name + * @param name the property name + * @param value the property value + * @param inst an array of int indexing into AcroField.Item.merged elements to process. + * Set to null to process all + * @return true if the property exists, false otherwise + */ + public bool SetFieldProperty(String field, String name, int value, int[] inst) { + if (writer == null) + throw new Exception("This AcroFields instance is read-only."); + Item item = (Item)fields[field]; + if (item == null) + return false; + InstHit hit = new InstHit(inst); + if (Util.EqualsIgnoreCase(name, "flags")) { + PdfNumber num = new PdfNumber(value); + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + ((PdfDictionary)item.merged[k]).Put(PdfName.F, num); + ((PdfDictionary)item.widgets[k]).Put(PdfName.F, num); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "setflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.widgets[k]).Get(PdfName.F)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val | value); + ((PdfDictionary)item.merged[k]).Put(PdfName.F, num); + ((PdfDictionary)item.widgets[k]).Put(PdfName.F, num); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "clrflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.widgets[k]).Get(PdfName.F)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val & (~value)); + ((PdfDictionary)item.merged[k]).Put(PdfName.F, num); + ((PdfDictionary)item.widgets[k]).Put(PdfName.F, num); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "fflags")) { + PdfNumber num = new PdfNumber(value); + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + ((PdfDictionary)item.merged[k]).Put(PdfName.FF, num); + ((PdfDictionary)item.values[k]).Put(PdfName.FF, num); + MarkUsed((PdfDictionary)item.values[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "setfflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.values[k]).Get(PdfName.FF)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val | value); + ((PdfDictionary)item.merged[k]).Put(PdfName.FF, num); + ((PdfDictionary)item.values[k]).Put(PdfName.FF, num); + MarkUsed((PdfDictionary)item.values[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "clrfflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.values[k]).Get(PdfName.FF)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val & (~value)); + ((PdfDictionary)item.merged[k]).Put(PdfName.FF, num); + ((PdfDictionary)item.values[k]).Put(PdfName.FF, num); + MarkUsed((PdfDictionary)item.values[k]); + } + } + } + else + return false; + return true; + } + + /** + * Merges an XML data structure into this form. + * @param n the top node of the data structure + * @throws java.io.IOException on error + * @throws com.lowagie.text.DocumentException o error + */ + public void MergeXfaData(XmlNode n) { + XfaForm.Xml2SomDatasets data = new XfaForm.Xml2SomDatasets(n); + foreach (String name in data.Order) { + String text = XfaForm.GetNodeText((XmlNode)data.Name2Node[name]); + SetField(name, text); + } + } + + /** Sets the fields by FDF merging. + * @param fdf the FDF form + * @throws IOException on error + * @throws DocumentException on error + */ + public void SetFields(FdfReader fdf) { + Hashtable fd = fdf.Fields; + foreach (string f in fd.Keys) { + String v = fdf.GetFieldValue(f); + if (v != null) + SetField(f, v); + } + } + + /** Sets the fields by XFDF merging. + * @param xfdf the XFDF form + * @throws IOException on error + * @throws DocumentException on error + */ + + public void SetFields(XfdfReader xfdf) { + Hashtable fd = xfdf.Fields; + foreach (string f in fd.Keys) { + String v = xfdf.GetFieldValue(f); + if (v != null) + SetField(f, v); + } + } + + /** + * Regenerates the field appearance. + * This is usefull when you change a field property, but not its value, + * for instance form.SetFieldProperty("f", "bgcolor", Color.BLUE, null); + * This won't have any effect, unless you use RegenerateField("f") after changing + * the property. + * + * @param name the fully qualified field name or the partial name in the case of XFA forms + * @throws IOException on error + * @throws DocumentException on error + * @return true if the field was found and changed, + * false otherwise + */ + public bool RegenerateField(String name) { + String value = GetField(name); + return SetField(name, value, value); + } + + /** Sets the field value. + * @param name the fully qualified field name or the partial name in the case of XFA forms + * @param value the field value + * @throws IOException on error + * @throws DocumentException on error + * @return true if the field was found and changed, + * false otherwise + */ + public bool SetField(String name, String value) { + return SetField(name, value, null); + } + + /** Sets the field value and the display string. The display string + * is used to build the appearance in the cases where the value + * is modified by Acrobat with JavaScript and the algorithm is + * known. + * @param name the fully qualified field name or the partial name in the case of XFA forms + * @param value the field value + * @param display the string that is used for the appearance. If null + * the value parameter will be used + * @return true if the field was found and changed, + * false otherwise + * @throws IOException on error + * @throws DocumentException on error + */ + public bool SetField(String name, String value, String display) { + if (writer == null) + throw new DocumentException("This AcroFields instance is read-only."); + if (xfa.XfaPresent) { + name = xfa.FindFieldName(name, this); + if (name == null) + return false; + String shortName = XfaForm.Xml2Som.GetShortName(name); + XmlNode xn = xfa.FindDatasetsNode(shortName); + if (xn == null) { + xn = xfa.DatasetsSom.InsertNode(xfa.DatasetsNode, shortName); + } + xfa.SetNodeText(xn, value); + } + Item item = (Item)fields[name]; + if (item == null) + return false; + PdfName type = (PdfName)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FT)); + if (PdfName.TX.Equals(type)) { + PdfNumber maxLen = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.MAXLEN)); + int len = 0; + if (maxLen != null) + len = maxLen.IntValue; + if (len > 0) + value = value.Substring(0, Math.Min(len, value.Length)); + } + if (display == null) + display = value; + if (PdfName.TX.Equals(type) || PdfName.CH.Equals(type)) { + PdfString v = new PdfString(value, PdfObject.TEXT_UNICODE); + for (int idx = 0; idx < item.values.Count; ++idx) { + PdfDictionary valueDic = (PdfDictionary)item.values[idx]; + valueDic.Put(PdfName.V, v); + valueDic.Remove(PdfName.I); + MarkUsed(valueDic); + PdfDictionary merged = (PdfDictionary)item.merged[idx]; + merged.Remove(PdfName.I); + merged.Put(PdfName.V, v); + PdfDictionary widget = (PdfDictionary)item.widgets[idx]; + if (generateAppearances) { + PdfAppearance app = GetAppearance(merged, display, name); + if (PdfName.CH.Equals(type)) { + PdfNumber n = new PdfNumber(topFirst); + widget.Put(PdfName.TI, n); + merged.Put(PdfName.TI, n); + } + PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(widget.Get(PdfName.AP)); + if (appDic == null) { + appDic = new PdfDictionary(); + widget.Put(PdfName.AP, appDic); + merged.Put(PdfName.AP, appDic); + } + appDic.Put(PdfName.N, app.IndirectReference); + writer.ReleaseTemplate(app); + } + else { + widget.Remove(PdfName.AP); + merged.Remove(PdfName.AP); + } + MarkUsed(widget); + } + return true; + } + else if (PdfName.BTN.Equals(type)) { + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FF)); + int flags = 0; + if (ff != null) + flags = ff.IntValue; + if ((flags & PdfFormField.FF_PUSHBUTTON) != 0) { + //we'll assume that the value is an image in base64 + Image img; + try { + img = Image.GetInstance(Convert.FromBase64String(value)); + } + catch { + return false; + } + PushbuttonField pb = GetNewPushbuttonFromField(name); + pb.Image = img; + ReplacePushbuttonField(name, pb.Field); + return true; + } + PdfName v = new PdfName(value); + ArrayList lopt = new ArrayList(); + PdfObject opts = PdfReader.GetPdfObject(((PdfDictionary)item.values[0]).Get(PdfName.OPT)); + if (opts != null && opts.IsArray()) { + ArrayList list = ((PdfArray)opts).ArrayList; + for (int k = 0; k < list.Count; ++k) { + PdfObject vv = PdfReader.GetPdfObject((PdfObject)list[k]); + if (vv != null && vv.IsString()) + lopt.Add(((PdfString)vv).ToUnicodeString()); + else + lopt.Add(null); + } + } + int vidx = lopt.IndexOf(value); + PdfName valt = null; + PdfName vt; + if (vidx >= 0) { + vt = valt = new PdfName(vidx.ToString()); + } + else + vt = v; + for (int idx = 0; idx < item.values.Count; ++idx) { + PdfDictionary merged = (PdfDictionary)item.merged[idx]; + PdfDictionary widget = (PdfDictionary)item.widgets[idx]; + MarkUsed((PdfDictionary)item.values[idx]); + if (valt != null) { + PdfString ps = new PdfString(value, PdfObject.TEXT_UNICODE); + ((PdfDictionary)item.values[idx]).Put(PdfName.V, ps); + merged.Put(PdfName.V, ps); + } + else { + ((PdfDictionary)item.values[idx]).Put(PdfName.V, v); + merged.Put(PdfName.V, v); + } + MarkUsed(widget); + if (IsInAP(widget, vt)) { + merged.Put(PdfName.AS, vt); + widget.Put(PdfName.AS, vt); + } + else { + merged.Put(PdfName.AS, PdfName.Off_); + widget.Put(PdfName.AS, PdfName.Off_); + } + } + return true; + } + return false; + } + + internal bool IsInAP(PdfDictionary dic, PdfName check) { + PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.AP)); + if (appDic == null) + return false; + PdfDictionary NDic = (PdfDictionary)PdfReader.GetPdfObject(appDic.Get(PdfName.N)); + return (NDic != null && NDic.Get(check) != null); + } + + /** Gets all the fields. The fields are keyed by the fully qualified field name and + * the value is an instance of AcroFields.Item. + * @return all the fields + */ + public Hashtable Fields { + get { + return fields; + } + } + + /** + * Gets the field structure. + * @param name the name of the field + * @return the field structure or null if the field + * does not exist + */ + public Item GetFieldItem(String name) { + if (xfa.XfaPresent) { + name = xfa.FindFieldName(name, this); + if (name == null) + return null; + } + return (Item)fields[name]; + } + + /** + * Gets the long XFA translated name. + * @param name the name of the field + * @return the long field name + */ + public String GetTranslatedFieldName(String name) { + if (xfa.XfaPresent) { + String namex = xfa.FindFieldName(name, this); + if (namex != null) + name = namex; + } + return name; + } + + /** + * Gets the field box positions in the document. The return is an array of float + * multiple of 5. For each of this groups the values are: [page, llx, lly, urx, + * ury]. The coordinates have the page rotation in consideration. + * @param name the field name + * @return the positions or null if field does not exist + */ + public float[] GetFieldPositions(String name) { + Item item = GetFieldItem(name); + if (item == null) + return null; + float[] ret = new float[item.page.Count * 5]; + int ptr = 0; + for (int k = 0; k < item.page.Count; ++k) { + try { + PdfDictionary wd = (PdfDictionary)item.widgets[k]; + PdfArray rect = (PdfArray)wd.Get(PdfName.RECT); + if (rect == null) + continue; + Rectangle r = PdfReader.GetNormalizedRectangle(rect); + int page = (int)item.page[k]; + int rotation = reader.GetPageRotation(page); + ret[ptr++] = page; + if (rotation != 0) { + Rectangle pageSize = reader.GetPageSize(page); + switch (rotation) { + case 270: + r = new Rectangle( + pageSize.Top - r.Bottom, + r.Left, + pageSize.Top - r.Top, + r.Right); + break; + case 180: + r = new Rectangle( + pageSize.Right - r.Left, + pageSize.Top - r.Bottom, + pageSize.Right - r.Right, + pageSize.Top - r.Top); + break; + case 90: + r = new Rectangle( + r.Bottom, + pageSize.Right - r.Left, + r.Top, + pageSize.Right - r.Right); + break; + } + r.Normalize(); + } + ret[ptr++] = r.Left; + ret[ptr++] = r.Bottom; + ret[ptr++] = r.Right; + ret[ptr++] = r.Top; + } + catch { + // empty on purpose + } + } + if (ptr < ret.Length) { + float[] ret2 = new float[ptr]; + System.Array.Copy(ret, 0, ret2, 0, ptr); + return ret2; + } + return ret; + } + + private int RemoveRefFromArray(PdfArray array, PdfObject refo) { + ArrayList ar = array.ArrayList; + if (refo == null || !refo.IsIndirect()) + return ar.Count; + PdfIndirectReference refi = (PdfIndirectReference)refo; + for (int j = 0; j < ar.Count; ++j) { + PdfObject obj = (PdfObject)ar[j]; + if (!obj.IsIndirect()) + continue; + if (((PdfIndirectReference)obj).Number == refi.Number) + ar.RemoveAt(j--); + } + return ar.Count; + } + + /** + * Removes all the fields from page. + * @param page the page to remove the fields from + * @return true if any field was removed, false otherwise + */ + public bool RemoveFieldsFromPage(int page) { + if (page < 1) + return false; + String[] names = new String[fields.Count]; + fields.Keys.CopyTo(names, 0); + bool found = false; + for (int k = 0; k < names.Length; ++k) { + bool fr = RemoveField(names[k], page); + found = (found || fr); + } + return found; + } + + /** + * Removes a field from the document. If page equals -1 all the fields with this + * name are removed from the document otherwise only the fields in + * that particular page are removed. + * @param name the field name + * @param page the page to remove the field from or -1 to remove it from all the pages + * @return true if the field exists, false otherwise + */ + public bool RemoveField(String name, int page) { + Item item = GetFieldItem(name); + if (item == null) + return false; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM), reader.Catalog); + + if (acroForm == null) + return false; + PdfArray arrayf = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); + if (arrayf == null) + return false; + for (int k = 0; k < item.widget_refs.Count; ++k) { + int pageV = (int)item.page[k]; + if (page != -1 && page != pageV) + continue; + PdfIndirectReference refi = (PdfIndirectReference)item.widget_refs[k]; + PdfDictionary wd = (PdfDictionary)PdfReader.GetPdfObject(refi); + PdfDictionary pageDic = reader.GetPageN(pageV); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS), pageDic); + if (annots != null) { + if (RemoveRefFromArray(annots, refi) == 0) { + pageDic.Remove(PdfName.ANNOTS); + MarkUsed(pageDic); + } + else + MarkUsed(annots); + } + PdfReader.KillIndirect(refi); + PdfIndirectReference kid = refi; + while ((refi = (PdfIndirectReference)wd.Get(PdfName.PARENT)) != null) { + wd = (PdfDictionary)PdfReader.GetPdfObject(refi); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(wd.Get(PdfName.KIDS)); + if (RemoveRefFromArray(kids, kid) != 0) + break; + kid = refi; + PdfReader.KillIndirect(refi); + } + if (refi == null) { + RemoveRefFromArray(arrayf, kid); + MarkUsed(arrayf); + } + if (page != -1) { + item.merged.RemoveAt(k); + item.page.RemoveAt(k); + item.values.RemoveAt(k); + item.widget_refs.RemoveAt(k); + item.widgets.RemoveAt(k); + --k; + } + } + if (page == -1 || item.merged.Count == 0) + fields.Remove(name); + return true; + } + + /** + * Removes a field from the document. + * @param name the field name + * @return true if the field exists, false otherwise + */ + public bool RemoveField(String name) { + return RemoveField(name, -1); + } + + /** Sets the option to generate appearances. Not generating apperances + * will speed-up form filling but the results can be + * unexpected in Acrobat. Don't use it unless your environment is well + * controlled. The default is true. + * @param generateAppearances the option to generate appearances + */ + public bool GenerateAppearances { + set { + generateAppearances = value; + PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); + if (generateAppearances) + top.Remove(PdfName.NEEDAPPEARANCES); + else + top.Put(PdfName.NEEDAPPEARANCES, PdfBoolean.PDFTRUE); + } + get { + return generateAppearances; + } + } + + /** The field representations for retrieval and modification. */ + public class Item { + /** An array of PdfDictionary where the value tag /V + * is present. + */ + public ArrayList values = new ArrayList(); + /** An array of PdfDictionary with the widgets. + */ + public ArrayList widgets = new ArrayList(); + /** An array of PdfDictionary with the widget references. + */ + public ArrayList widget_refs = new ArrayList(); + /** An array of PdfDictionary with all the field + * and widget tags merged. + */ + public ArrayList merged = new ArrayList(); + /** An array of Integer with the page numbers where + * the widgets are displayed. + */ + public ArrayList page = new ArrayList(); + /** An array of Integer with the tab order of the field in the page. + */ + public ArrayList tabOrder = new ArrayList(); + } + + private class InstHit { + IntHashtable hits; + public InstHit(int[] inst) { + if (inst == null) + return; + hits = new IntHashtable(); + for (int k = 0; k < inst.Length; ++k) + hits[inst[k]] = 1; + } + + public bool IsHit(int n) { + if (hits == null) + return true; + return hits.ContainsKey(n); + } + } + + private void FindSignatureNames() { + if (sigNames != null) + return; + sigNames = new Hashtable(); + ArrayList sorter = new ArrayList(); + foreach (DictionaryEntry entry in fields) { + Item item = (Item)entry.Value; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (!PdfName.SIG.Equals(merged.Get(PdfName.FT))) + continue; + PdfObject vo = PdfReader.GetPdfObject(merged.Get(PdfName.V)); + if (vo == null || vo.Type != PdfObject.DICTIONARY) + continue; + PdfDictionary v = (PdfDictionary)vo; + PdfObject contents = v.Get(PdfName.CONTENTS); + if (contents == null || contents.Type != PdfObject.STRING) + continue; + PdfObject ro = v.Get(PdfName.BYTERANGE); + if (ro == null || ro.Type != PdfObject.ARRAY) + continue; + ArrayList ra = ((PdfArray)ro).ArrayList; + if (ra.Count < 2) + continue; + int length = ((PdfNumber)ra[ra.Count - 1]).IntValue + ((PdfNumber)ra[ra.Count - 2]).IntValue; + sorter.Add(new Object[]{entry.Key, new int[]{length, 0}}); + } + sorter.Sort(new AcroFields.ISorterComparator()); + if (sorter.Count > 0) { + if (((int[])((Object[])sorter[sorter.Count - 1])[1])[0] == reader.FileLength) + totalRevisions = sorter.Count; + else + totalRevisions = sorter.Count + 1; + for (int k = 0; k < sorter.Count; ++k) { + Object[] objs = (Object[])sorter[k]; + String name = (String)objs[0]; + int[] p = (int[])objs[1]; + p[1] = k + 1; + sigNames[name] = p; + } + } + } + + /** + * Gets the field names that have signatures and are signed. + * @return the field names that have signatures and are signed + */ + public ArrayList GetSignatureNames() { + FindSignatureNames(); + return new ArrayList(sigNames.Keys); + } + + /** + * Gets the field names that have blank signatures. + * @return the field names that have blank signatures + */ + public ArrayList GetBlankSignatureNames() { + FindSignatureNames(); + ArrayList sigs = new ArrayList(); + foreach (DictionaryEntry entry in fields) { + Item item = (Item)entry.Value; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (!PdfName.SIG.Equals(merged.Get(PdfName.FT))) + continue; + if (sigNames.ContainsKey(entry.Key)) + continue; + sigs.Add(entry.Key); + } + return sigs; + } + + /** + * Gets the signature dictionary, the one keyed by /V. + * @param name the field name + * @return the signature dictionary keyed by /V or null if the field is not + * a signature + */ + public PdfDictionary GetSignatureDictionary(String name) { + FindSignatureNames(); + name = GetTranslatedFieldName(name); + if (!sigNames.ContainsKey(name)) + return null; + Item item = (Item)fields[name]; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + return (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.V)); + } + + /** + * Checks is the signature covers the entire document or just part of it. + * @param name the signature field name + * @return true if the signature covers the entire document, + * false otherwise + */ + public bool SignatureCoversWholeDocument(String name) { + FindSignatureNames(); + name = GetTranslatedFieldName(name); + if (!sigNames.ContainsKey(name)) + return false; + return ((int[])sigNames[name])[0] == reader.FileLength; + } + + /** + * Verifies a signature. An example usage is: + *

+ *

+        * KeyStore kall = PdfPKCS7.LoadCacertsKeyStore();
+        * PdfReader reader = new PdfReader("my_signed_doc.pdf");
+        * AcroFields af = reader.GetAcroFields();
+        * ArrayList names = af.GetSignatureNames();
+        * for (int k = 0; k < names.Size(); ++k) {
+        *    String name = (String)names.Get(k);
+        *    System.out.Println("Signature name: " + name);
+        *    System.out.Println("Signature covers whole document: " + af.SignatureCoversWholeDocument(name));
+        *    PdfPKCS7 pk = af.VerifySignature(name);
+        *    Calendar cal = pk.GetSignDate();
+        *    Certificate pkc[] = pk.GetCertificates();
+        *    System.out.Println("Subject: " + PdfPKCS7.GetSubjectFields(pk.GetSigningCertificate()));
+        *    System.out.Println("Document modified: " + !pk.Verify());
+        *    Object fails[] = PdfPKCS7.VerifyCertificates(pkc, kall, null, cal);
+        *    if (fails == null)
+        *        System.out.Println("Certificates verified against the KeyStore");
+        *    else
+        *        System.out.Println("Certificate failed: " + fails[1]);
+        * }
+        * 
+ * @param name the signature field name + * @return a PdfPKCS7 class to continue the verification + */ + public PdfPKCS7 VerifySignature(String name) { + PdfDictionary v = GetSignatureDictionary(name); + if (v == null) + return null; + PdfName sub = (PdfName)PdfReader.GetPdfObject(v.Get(PdfName.SUBFILTER)); + PdfString contents = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.CONTENTS)); + PdfPKCS7 pk = null; + if (sub.Equals(PdfName.ADBE_X509_RSA_SHA1)) { + PdfString cert = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.CERT)); + pk = new PdfPKCS7(contents.GetOriginalBytes(), cert.GetBytes()); + } + else + pk = new PdfPKCS7(contents.GetOriginalBytes()); + UpdateByteRange(pk, v); + PdfString str = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.M)); + if (str != null) + pk.SignDate = PdfDate.Decode(str.ToString()); + PdfObject obj = PdfReader.GetPdfObject(v.Get(PdfName.NAME)); + if (obj != null) { + if (obj.IsString()) + pk.SignName = ((PdfString)obj).ToUnicodeString(); + else if(obj.IsName()) + pk.SignName = PdfName.DecodeName(obj.ToString()); + } + str = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.REASON)); + if (str != null) + pk.Reason = str.ToUnicodeString(); + str = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.LOCATION)); + if (str != null) + pk.Location = str.ToUnicodeString(); + return pk; + } + + private void UpdateByteRange(PdfPKCS7 pkcs7, PdfDictionary v) { + PdfArray b = (PdfArray)PdfReader.GetPdfObject(v.Get(PdfName.BYTERANGE)); + RandomAccessFileOrArray rf = reader.SafeFile; + try { + rf.ReOpen(); + byte[] buf = new byte[8192]; + ArrayList ar = b.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + int start = ((PdfNumber)ar[k]).IntValue; + int length = ((PdfNumber)ar[++k]).IntValue; + rf.Seek(start); + while (length > 0) { + int rd = rf.Read(buf, 0, Math.Min(length, buf.Length)); + if (rd <= 0) + break; + length -= rd; + pkcs7.Update(buf, 0, rd); + } + } + } + finally { + try{rf.Close();}catch{} + } + } + + /** + * Gets the total number of revisions this document has. + * @return the total number of revisions + */ + public int TotalRevisions { + get { + FindSignatureNames(); + return this.totalRevisions; + } + } + + /** + * Gets this field revision. + * @param field the signature field name + * @return the revision or zero if it's not a signature field + */ + public int GetRevision(String field) { + FindSignatureNames(); + field = GetTranslatedFieldName(field); + if (!sigNames.ContainsKey(field)) + return 0; + return ((int[])sigNames[field])[1]; + } + + /** + * Extracts a revision from the document. + * @param field the signature field name + * @return an Stream covering the revision. Returns null if + * it's not a signature field + * @throws IOException on error + */ + public Stream ExtractRevision(String field) { + FindSignatureNames(); + field = GetTranslatedFieldName(field); + if (!sigNames.ContainsKey(field)) + return null; + int length = ((int[])sigNames[field])[0]; + RandomAccessFileOrArray raf = reader.SafeFile; + raf.ReOpen(); + raf.Seek(0); + return new RevisionStream(raf, length); + } + + /** + * Sets a cache for field appearances. Parsing the existing PDF to + * create a new TextField is time expensive. For those tasks that repeatedly + * fill the same PDF with different field values the use of the cache has dramatic + * speed advantages. An example usage: + *

+ *

+        * String pdfFile = ...;// the pdf file used as template
+        * ArrayList xfdfFiles = ...;// the xfdf file names
+        * ArrayList pdfOutFiles = ...;// the output file names, one for each element in xpdfFiles
+        * Hashtable cache = new Hashtable();// the appearances cache
+        * PdfReader originalReader = new PdfReader(pdfFile);
+        * for (int k = 0; k < xfdfFiles.Size(); ++k) {
+        *    PdfReader reader = new PdfReader(originalReader);
+        *    XfdfReader xfdf = new XfdfReader((String)xfdfFiles.Get(k));
+        *    PdfStamper stp = new PdfStamper(reader, new FileOutputStream((String)pdfOutFiles.Get(k)));
+        *    AcroFields af = stp.GetAcroFields();
+        *    af.SetFieldCache(cache);
+        *    af.SetFields(xfdf);
+        *    stp.Close();
+        * }
+        * 
+ * @param fieldCache an HasMap that will carry the cached appearances + */ + public Hashtable FieldCache { + set { + fieldCache = value; + } + get { + return fieldCache; + } + } + + private void MarkUsed(PdfObject obj) { + if (!append) + return; + ((PdfStamperImp)writer).MarkUsed(obj); + } + + /** + * Sets extra margins in text fields to better mimic the Acrobat layout. + * @param extraMarginLeft the extra marging left + * @param extraMarginTop the extra margin top + */ + public void SetExtraMargin(float extraMarginLeft, float extraMarginTop) { + this.extraMarginLeft = extraMarginLeft; + this.extraMarginTop = extraMarginTop; + } + + /** + * Adds a substitution font to the list. The fonts in this list will be used if the original + * font doesn't contain the needed glyphs. + * @param font the font + */ + public void AddSubstitutionFont(BaseFont font) { + if (substitutionFonts == null) + substitutionFonts = new ArrayList(); + substitutionFonts.Add(font); + } + + private static Hashtable stdFieldFontNames = new Hashtable(); + + /** + * Holds value of property fieldCache. + */ + private Hashtable fieldCache; + + private int totalRevisions; + + static AcroFields() { + stdFieldFontNames["CoBO"] = new String[]{"Courier-BoldOblique"}; + stdFieldFontNames["CoBo"] = new String[]{"Courier-Bold"}; + stdFieldFontNames["CoOb"] = new String[]{"Courier-Oblique"}; + stdFieldFontNames["Cour"] = new String[]{"Courier"}; + stdFieldFontNames["HeBO"] = new String[]{"Helvetica-BoldOblique"}; + stdFieldFontNames["HeBo"] = new String[]{"Helvetica-Bold"}; + stdFieldFontNames["HeOb"] = new String[]{"Helvetica-Oblique"}; + stdFieldFontNames["Helv"] = new String[]{"Helvetica"}; + stdFieldFontNames["Symb"] = new String[]{"Symbol"}; + stdFieldFontNames["TiBI"] = new String[]{"Times-BoldItalic"}; + stdFieldFontNames["TiBo"] = new String[]{"Times-Bold"}; + stdFieldFontNames["TiIt"] = new String[]{"Times-Italic"}; + stdFieldFontNames["TiRo"] = new String[]{"Times-Roman"}; + stdFieldFontNames["ZaDb"] = new String[]{"ZapfDingbats"}; + stdFieldFontNames["HySm"] = new String[]{"HYSMyeongJo-Medium", "UniKS-UCS2-H"}; + stdFieldFontNames["HyGo"] = new String[]{"HYGoThic-Medium", "UniKS-UCS2-H"}; + stdFieldFontNames["KaGo"] = new String[]{"HeiseiKakuGo-W5", "UniKS-UCS2-H"}; + stdFieldFontNames["KaMi"] = new String[]{"HeiseiMin-W3", "UniJIS-UCS2-H"}; + stdFieldFontNames["MHei"] = new String[]{"MHei-Medium", "UniCNS-UCS2-H"}; + stdFieldFontNames["MSun"] = new String[]{"MSung-Light", "UniCNS-UCS2-H"}; + stdFieldFontNames["STSo"] = new String[]{"STSong-Light", "UniGB-UCS2-H"}; + } + + public class RevisionStream : Stream { + private byte[] b = new byte[1]; + private RandomAccessFileOrArray raf; + private int length; + private int rangePosition = 0; + private bool closed; + + internal RevisionStream(RandomAccessFileOrArray raf, int length) { + this.raf = raf; + this.length = length; + } + + public override int ReadByte() { + int n = Read(b, 0, 1); + if (n != 1) + return -1; + return b[0] & 0xff; + } + + public override int Read(byte[] b, int off, int len) { + if (b == null) { + throw new ArgumentNullException(); + } else if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0)) { + throw new ArgumentOutOfRangeException(); + } else if (len == 0) { + return 0; + } + if (rangePosition >= length) { + Close(); + return -1; + } + int elen = Math.Min(len, length - rangePosition); + raf.ReadFully(b, off, elen); + rangePosition += elen; + return elen; + } + + public override void Close() { + if (!closed) { + raf.Close(); + closed = true; + } + } + + public override bool CanRead { + get { + return true; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return false; + } + } + + public override long Length { + get { + return 0; + } + } + + public override long Position { + get { + return 0; + } + set { + } + } + + public override void Flush() { + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + } + } + + private class ISorterComparator : IComparer { + public int Compare(Object o1, Object o2) { + int n1 = ((int[])((Object[])o1)[1])[0]; + int n2 = ((int[])((Object[])o2)[1])[0]; + return n1 - n2; + } + } + + /** + * Sets a list of substitution fonts. The list is composed of BaseFont and can also be null. The fonts in this list will be used if the original + * font doesn't contain the needed glyphs. + * @param substitutionFonts the list + */ + public ArrayList SubstitutionFonts { + set { + substitutionFonts = value; + } + get { + return substitutionFonts; + } + } + + /** + * Gets the XFA form processor. + * @return the XFA form processor + */ + public XfaForm Xfa { + get { + return xfa; + } + } + + private static readonly PdfName[] buttonRemove = {PdfName.MK, PdfName.F , PdfName.FF , PdfName.Q , PdfName.BS , PdfName.BORDER}; + + /** + * Creates a new pushbutton from an existing field. If there are several pushbuttons with the same name + * only the first one is used. This pushbutton can be changed and be used to replace + * an existing one, with the same name or other name, as long is it is in the same document. To replace an existing pushbutton + * call {@link #replacePushbuttonField(String,PdfFormField)}. + * @param field the field name that should be a pushbutton + * @return a new pushbutton or null if the field is not a pushbutton + */ + public PushbuttonField GetNewPushbuttonFromField(String field) { + return GetNewPushbuttonFromField(field, 0); + } + + /** + * Creates a new pushbutton from an existing field. This pushbutton can be changed and be used to replace + * an existing one, with the same name or other name, as long is it is in the same document. To replace an existing pushbutton + * call {@link #replacePushbuttonField(String,PdfFormField,int)}. + * @param field the field name that should be a pushbutton + * @param order the field order in fields with same name + * @return a new pushbutton or null if the field is not a pushbutton + */ + public PushbuttonField GetNewPushbuttonFromField(String field, int order) { + if (GetFieldType(field) != FIELD_TYPE_PUSHBUTTON) + return null; + Item item = GetFieldItem(field); + if (order >= item.merged.Count) + return null; + int posi = order * 5; + float[] pos = GetFieldPositions(field); + Rectangle box = new Rectangle(pos[posi + 1], pos[posi + 2], pos[posi + 3], pos[posi + 4]); + PushbuttonField newButton = new PushbuttonField(writer, box, null); + PdfDictionary dic = (PdfDictionary)item.merged[order]; + DecodeGenericDictionary(dic, newButton); + PdfDictionary mk = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.MK)); + if (mk != null) { + PdfString text = (PdfString)PdfReader.GetPdfObject(mk.Get(PdfName.CA)); + if (text != null) + newButton.Text = text.ToUnicodeString(); + PdfNumber tp = (PdfNumber)PdfReader.GetPdfObject(mk.Get(PdfName.TP)); + if (tp != null) + newButton.Layout = tp.IntValue + 1; + PdfDictionary ifit = (PdfDictionary)PdfReader.GetPdfObject(mk.Get(PdfName.IF)); + if (ifit != null) { + PdfName sw = (PdfName)PdfReader.GetPdfObject(ifit.Get(PdfName.SW)); + if (sw != null) { + int scale = PushbuttonField.SCALE_ICON_ALWAYS; + if (sw.Equals(PdfName.B)) + scale = PushbuttonField.SCALE_ICON_IS_TOO_BIG; + else if (sw.Equals(PdfName.S)) + scale = PushbuttonField.SCALE_ICON_IS_TOO_SMALL; + else if (sw.Equals(PdfName.N)) + scale = PushbuttonField.SCALE_ICON_NEVER; + newButton.ScaleIcon = scale; + } + sw = (PdfName)PdfReader.GetPdfObject(ifit.Get(PdfName.S)); + if (sw != null) { + if (sw.Equals(PdfName.A)) + newButton.ProportionalIcon = false; + } + PdfArray aj = (PdfArray)PdfReader.GetPdfObject(ifit.Get(PdfName.A)); + if (aj != null && aj.Size == 2) { + float left = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)aj.ArrayList[0])).FloatValue; + float bottom = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)aj.ArrayList[1])).FloatValue; + newButton.IconHorizontalAdjustment = left; + newButton.IconVerticalAdjustment = bottom; + } + PdfObject fb = PdfReader.GetPdfObject(ifit.Get(PdfName.FB)); + if (fb != null && fb.ToString().Equals("true")) + newButton.IconFitToBounds = true; + } + PdfObject i = mk.Get(PdfName.I); + if (i != null && i.IsIndirect()) + newButton.IconReference = (PRIndirectReference)i; + } + return newButton; + } + + /** + * Replaces the first field with a new pushbutton. The pushbutton can be created with + * {@link #getNewPushbuttonFromField(String)} from the same document or it can be a + * generic PdfFormField of the type pushbutton. + * @param field the field name + * @param button the PdfFormField representing the pushbutton + * @return true if the field was replaced, false if the field + * was not a pushbutton + */ + public bool ReplacePushbuttonField(String field, PdfFormField button) { + return ReplacePushbuttonField(field, button, 0); + } + + /** + * Replaces the designated field with a new pushbutton. The pushbutton can be created with + * {@link #getNewPushbuttonFromField(String,int)} from the same document or it can be a + * generic PdfFormField of the type pushbutton. + * @param field the field name + * @param button the PdfFormField representing the pushbutton + * @param order the field order in fields with same name + * @return true if the field was replaced, false if the field + * was not a pushbutton + */ + public bool ReplacePushbuttonField(String field, PdfFormField button, int order) { + if (GetFieldType(field) != FIELD_TYPE_PUSHBUTTON) + return false; + Item item = GetFieldItem(field); + if (order >= item.merged.Count) + return false; + PdfDictionary merged = (PdfDictionary)item.merged[order]; + PdfDictionary values = (PdfDictionary)item.values[order]; + PdfDictionary widgets = (PdfDictionary)item.widgets[order]; + for (int k = 0; k < buttonRemove.Length; ++k) { + merged.Remove(buttonRemove[k]); + values.Remove(buttonRemove[k]); + widgets.Remove(buttonRemove[k]); + } + foreach (PdfName key in button.Keys) { + if (key.Equals(PdfName.T) || key.Equals(PdfName.RECT)) + continue; + if (key.Equals(PdfName.FF)) + values.Put(key, button.Get(key)); + else + widgets.Put(key, button.Get(key)); + merged.Put(key, button.Get(key)); + } + return true; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs b/iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs new file mode 100644 index 0000000..684515e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs @@ -0,0 +1,772 @@ +using System; +using System.Text; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Shape arabic characters. This code was inspired by an LGPL'ed C library: + * Pango ( see http://www.pango.com/ ). Note that the code of this is the + * original work of Paulo Soares. Hence it is perfectly justifiable to distribute + * it under the MPL. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class ArabicLigaturizer { + + static bool IsVowel(char s) { + return ((s >= '\u064B') && (s <= '\u0655')) || (s == '\u0670'); + } + + static char Charshape(char s, int which) + /* which 0=isolated 1=final 2=initial 3=medial */ + { + int l, r, m; + if ((s >= '\u0621') && (s <= '\u06D3')) { + l = 0; + r = chartable.Length - 1; + while (l <= r) { + m = (l + r) / 2; + if (s == chartable[m][0]) { + return chartable[m][which + 1]; + } + else if (s < chartable[m][0]) { + r = m - 1; + } + else { + l = m + 1; + } + } + } + else if (s >= '\ufef5' && s <= '\ufefb') + return (char)(s + which); + return s; + } + + static int Shapecount(char s) { + int l, r, m; + if ((s >= '\u0621') && (s <= '\u06D3') && !IsVowel(s)) { + l = 0; + r = chartable.Length - 1; + while (l <= r) { + m = (l + r) / 2; + if (s == chartable[m][0]) { + return chartable[m].Length - 1; + } + else if (s < chartable[m][0]) { + r = m - 1; + } + else { + l = m + 1; + } + } + } + else if (s == ZWJ) { + return 4; + } + return 1; + } + + static int Ligature(char newchar, Charstruct oldchar) { + /* 0 == no ligature possible; 1 == vowel; 2 == two chars; 3 == Lam+Alef */ + int retval = 0; + + if (oldchar.basechar == 0) + return 0; + if (IsVowel(newchar)) { + retval = 1; + if ((oldchar.vowel != 0) && (newchar != SHADDA)) { + retval = 2; /* we eliminate the old vowel .. */ + } + switch (newchar) { + case SHADDA: + if (oldchar.mark1 == 0) { + oldchar.mark1 = SHADDA; + } + else { + return 0; /* no ligature possible */ + } + break; + case HAMZABELOW: + switch (oldchar.basechar) { + case ALEF: + oldchar.basechar = ALEFHAMZABELOW; + retval = 2; + break; + case LAM_ALEF: + oldchar.basechar = LAM_ALEFHAMZABELOW; + retval = 2; + break; + default: + oldchar.mark1 = HAMZABELOW; + break; + } + break; + case HAMZAABOVE: + switch (oldchar.basechar) { + case ALEF: + oldchar.basechar = ALEFHAMZA; + retval = 2; + break; + case LAM_ALEF: + oldchar.basechar = LAM_ALEFHAMZA; + retval = 2; + break; + case WAW: + oldchar.basechar = WAWHAMZA; + retval = 2; + break; + case YEH: + case ALEFMAKSURA: + case FARSIYEH: + oldchar.basechar = YEHHAMZA; + retval = 2; + break; + default: /* whatever sense this may make .. */ + oldchar.mark1 = HAMZAABOVE; + break; + } + break; + case MADDA: + switch (oldchar.basechar) { + case ALEF: + oldchar.basechar = ALEFMADDA; + retval = 2; + break; + } + break; + default: + oldchar.vowel = newchar; + break; + } + if (retval == 1) { + oldchar.lignum++; + } + return retval; + } + if (oldchar.vowel != 0) { /* if we already joined a vowel, we can't join a Hamza */ + return 0; + } + + switch (oldchar.basechar) { + case LAM: + switch (newchar) { + case ALEF: + oldchar.basechar = LAM_ALEF; + oldchar.numshapes = 2; + retval = 3; + break; + case ALEFHAMZA: + oldchar.basechar = LAM_ALEFHAMZA; + oldchar.numshapes = 2; + retval = 3; + break; + case ALEFHAMZABELOW: + oldchar.basechar = LAM_ALEFHAMZABELOW; + oldchar.numshapes = 2; + retval = 3; + break; + case ALEFMADDA: + oldchar.basechar = LAM_ALEFMADDA; + oldchar.numshapes = 2; + retval = 3; + break; + } + break; + case (char)0: + oldchar.basechar = newchar; + oldchar.numshapes = Shapecount(newchar); + retval = 1; + break; + } + return retval; + } + + static void Copycstostring(StringBuilder str, Charstruct s, int level) { + /* s is a shaped charstruct; i is the index into the string */ + if (s.basechar == 0) + return; + + str.Append(s.basechar); + s.lignum--; + if (s.mark1 != 0) { + if ((level & ar_novowel) == 0) { + str.Append(s.mark1); + s.lignum--; + } + else { + s.lignum--; + } + } + if (s.vowel != 0) { + if ((level & ar_novowel) == 0) { + str.Append(s.vowel); + s.lignum--; + } + else { /* vowel elimination */ + s.lignum--; + } + } + } + + // return len + internal static void Doublelig(StringBuilder str, int level) + /* Ok. We have presentation ligatures in our font. */ + { + int len; + int olen = len = str.Length; + int j = 0, si = 1; + char lapresult; + + while (si < olen) { + lapresult = (char)0; + if ((level & ar_composedtashkeel) != 0) { + switch (str[j]) { + case SHADDA: + switch (str[si]) { + case KASRA: + lapresult = '\uFC62'; + break; + case FATHA: + lapresult = '\uFC60'; + break; + case DAMMA: + lapresult = '\uFC61'; + break; + case '\u064C': + lapresult = '\uFC5E'; + break; + case '\u064D': + lapresult = '\uFC5F'; + break; + } + break; + case KASRA: + if (str[si] == SHADDA) + lapresult = '\uFC62'; + break; + case FATHA: + if (str[si] == SHADDA) + lapresult = '\uFC60'; + break; + case DAMMA: + if (str[si] == SHADDA) + lapresult = '\uFC61'; + break; + } + } + + if ((level & ar_lig) != 0) { + switch (str[j]) { + case '\uFEDF': /* LAM initial */ + switch (str[si]) { + case '\uFE9E': + lapresult = '\uFC3F'; + break; /* JEEM final */ + case '\uFEA0': + lapresult = '\uFCC9'; + break; /* JEEM medial */ + case '\uFEA2': + lapresult = '\uFC40'; + break; /* HAH final */ + case '\uFEA4': + lapresult = '\uFCCA'; + break; /* HAH medial */ + case '\uFEA6': + lapresult = '\uFC41'; + break; /* KHAH final */ + case '\uFEA8': + lapresult = '\uFCCB'; + break; /* KHAH medial */ + case '\uFEE2': + lapresult = '\uFC42'; + break; /* MEEM final */ + case '\uFEE4': + lapresult = '\uFCCC'; + break; /* MEEM medial */ + } + break; + case '\uFE97': /* TEH inital */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFCA1'; + break; /* JEEM medial */ + case '\uFEA4': + lapresult = '\uFCA2'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFCA3'; + break; /* KHAH medial */ + } + break; + case '\uFE91': /* BEH inital */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFC9C'; + break; /* JEEM medial */ + case '\uFEA4': + lapresult = '\uFC9D'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFC9E'; + break; /* KHAH medial */ + } + break; + case '\uFEE7': /* NOON inital */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFCD2'; + break; /* JEEM initial */ + case '\uFEA4': + lapresult = '\uFCD3'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFCD4'; + break; /* KHAH medial */ + } + break; + + case '\uFEE8': /* NOON medial */ + switch (str[si]) { + case '\uFEAE': + lapresult = '\uFC8A'; + break; /* REH final */ + case '\uFEB0': + lapresult = '\uFC8B'; + break; /* ZAIN final */ + } + break; + case '\uFEE3': /* MEEM initial */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFCCE'; + break; /* JEEM medial */ + case '\uFEA4': + lapresult = '\uFCCF'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFCD0'; + break; /* KHAH medial */ + case '\uFEE4': + lapresult = '\uFCD1'; + break; /* MEEM medial */ + } + break; + + case '\uFED3': /* FEH initial */ + switch (str[si]) { + case '\uFEF2': + lapresult = '\uFC32'; + break; /* YEH final */ + } + break; + + default: + break; + } /* end switch string[si] */ + } + if (lapresult != 0) { + str[j] = lapresult; + len--; + si++; /* jump over one character */ + /* we'll have to change this, too. */ + } + else { + j++; + str[j] = str[si]; + si++; + } + } + str.Length = len; + } + + static bool Connects_to_left(Charstruct a) { + return a.numshapes > 2; + } + + internal static void Shape(char[] text, StringBuilder str, int level) { + /* string is assumed to be empty and big enough. + * text is the original text. + * This routine does the basic arabic reshaping. + * *len the number of non-null characters. + * + * Note: We have to unshape each character first! + */ + int join; + int which; + char nextletter; + + int p = 0; /* initialize for output */ + Charstruct oldchar = new Charstruct(); + Charstruct curchar = new Charstruct(); + while (p < text.Length) { + nextletter = text[p++]; + //nextletter = unshape (nextletter); + + join = Ligature(nextletter, curchar); + if (join == 0) { /* shape curchar */ + int nc = Shapecount(nextletter); + //(*len)++; + if (nc == 1) { + which = 0; /* final or isolated */ + } + else { + which = 2; /* medial or initial */ + } + if (Connects_to_left(oldchar)) { + which++; + } + + which = which % (curchar.numshapes); + curchar.basechar = Charshape(curchar.basechar, which); + + /* get rid of oldchar */ + Copycstostring(str, oldchar, level); + oldchar = curchar; /* new values in oldchar */ + + /* init new curchar */ + curchar = new Charstruct(); + curchar.basechar = nextletter; + curchar.numshapes = nc; + curchar.lignum++; + // (*len) += unligature (&curchar, level); + } + else if (join == 1) { + } + // else + // { + // (*len) += unligature (&curchar, level); + // } + // p = g_utf8_next_char (p); + } + + /* Handle last char */ + if (Connects_to_left(oldchar)) + which = 1; + else + which = 0; + which = which % (curchar.numshapes); + curchar.basechar = Charshape(curchar.basechar, which); + + /* get rid of oldchar */ + Copycstostring(str, oldchar, level); + Copycstostring(str, curchar, level); + } + + internal static int Arabic_shape(char[] src, int srcoffset, int srclength, char[] dest, int destoffset, int destlength, int level) { + char[] str = new char[srclength]; + for (int k = srclength + srcoffset - 1; k >= srcoffset; --k) + str[k - srcoffset] = src[k]; + StringBuilder str2 = new StringBuilder(srclength); + Shape(str, str2, level); + if ((level & (ar_composedtashkeel | ar_lig)) != 0) + Doublelig(str2, level); + // string.Reverse(); + System.Array.Copy(str2.ToString().ToCharArray(), 0, dest, destoffset, str2.Length); + return str2.Length; + } + + internal static void ProcessNumbers(char[] text, int offset, int length, int options) { + int limit = offset + length; + if ((options & DIGITS_MASK) != 0) { + char digitBase = '\u0030'; // European digits + switch (options & DIGIT_TYPE_MASK) { + case DIGIT_TYPE_AN: + digitBase = '\u0660'; // Arabic-Indic digits + break; + + case DIGIT_TYPE_AN_EXTENDED: + digitBase = '\u06f0'; // Eastern Arabic-Indic digits (Persian and Urdu) + break; + + default: + break; + } + + switch (options & DIGITS_MASK) { + case DIGITS_EN2AN: { + int digitDelta = digitBase - '\u0030'; + for (int i = offset; i < limit; ++i) { + char ch = text[i]; + if (ch <= '\u0039' && ch >= '\u0030') { + text[i] += (char)digitDelta; + } + } + } + break; + + case DIGITS_AN2EN: { + char digitTop = (char)(digitBase + 9); + int digitDelta = '\u0030' - digitBase; + for (int i = offset; i < limit; ++i) { + char ch = text[i]; + if (ch <= digitTop && ch >= digitBase) { + text[i] += (char)digitDelta; + } + } + } + break; + + case DIGITS_EN2AN_INIT_LR: + ShapeToArabicDigitsWithContext(text, 0, length, digitBase, false); + break; + + case DIGITS_EN2AN_INIT_AL: + ShapeToArabicDigitsWithContext(text, 0, length, digitBase, true); + break; + + default: + break; + } + } + } + + internal static void ShapeToArabicDigitsWithContext(char[] dest, int start, int length, char digitBase, bool lastStrongWasAL) { + digitBase -= '0'; // move common adjustment out of loop + + int limit = start + length; + for (int i = start; i < limit; ++i) { + char ch = dest[i]; + switch (BidiOrder.GetDirection(ch)) { + case BidiOrder.L: + case BidiOrder.R: + lastStrongWasAL = false; + break; + case BidiOrder.AL: + lastStrongWasAL = true; + break; + case BidiOrder.EN: + if (lastStrongWasAL && ch <= '\u0039') { + dest[i] = (char)(ch + digitBase); + } + break; + default: + break; + } + } + } + + private const char ALEF = '\u0627'; + private const char ALEFHAMZA = '\u0623'; + private const char ALEFHAMZABELOW = '\u0625'; + private const char ALEFMADDA = '\u0622'; + private const char LAM = '\u0644'; + private const char HAMZA = '\u0621'; + private const char TATWEEL = '\u0640'; + private const char ZWJ = '\u200D'; + + private const char HAMZAABOVE = '\u0654'; + private const char HAMZABELOW = '\u0655'; + + private const char WAWHAMZA = '\u0624'; + private const char YEHHAMZA = '\u0626'; + private const char WAW = '\u0648'; + private const char ALEFMAKSURA = '\u0649'; + private const char YEH = '\u064A'; + private const char FARSIYEH = '\u06CC'; + + private const char SHADDA = '\u0651'; + private const char KASRA = '\u0650'; + private const char FATHA = '\u064E'; + private const char DAMMA = '\u064F'; + private const char MADDA = '\u0653'; + + private const char LAM_ALEF = '\uFEFB'; + private const char LAM_ALEFHAMZA = '\uFEF7'; + private const char LAM_ALEFHAMZABELOW = '\uFEF9'; + private const char LAM_ALEFMADDA = '\uFEF5'; + + private static char[][] chartable = { + new char[]{'\u0621', '\uFE80'}, /* HAMZA */ + new char[]{'\u0622', '\uFE81', '\uFE82'}, /* ALEF WITH MADDA ABOVE */ + new char[]{'\u0623', '\uFE83', '\uFE84'}, /* ALEF WITH HAMZA ABOVE */ + new char[]{'\u0624', '\uFE85', '\uFE86'}, /* WAW WITH HAMZA ABOVE */ + new char[]{'\u0625', '\uFE87', '\uFE88'}, /* ALEF WITH HAMZA BELOW */ + new char[]{'\u0626', '\uFE89', '\uFE8A', '\uFE8B', '\uFE8C'}, /* YEH WITH HAMZA ABOVE */ + new char[]{'\u0627', '\uFE8D', '\uFE8E'}, /* ALEF */ + new char[]{'\u0628', '\uFE8F', '\uFE90', '\uFE91', '\uFE92'}, /* BEH */ + new char[]{'\u0629', '\uFE93', '\uFE94'}, /* TEH MARBUTA */ + new char[]{'\u062A', '\uFE95', '\uFE96', '\uFE97', '\uFE98'}, /* TEH */ + new char[]{'\u062B', '\uFE99', '\uFE9A', '\uFE9B', '\uFE9C'}, /* THEH */ + new char[]{'\u062C', '\uFE9D', '\uFE9E', '\uFE9F', '\uFEA0'}, /* JEEM */ + new char[]{'\u062D', '\uFEA1', '\uFEA2', '\uFEA3', '\uFEA4'}, /* HAH */ + new char[]{'\u062E', '\uFEA5', '\uFEA6', '\uFEA7', '\uFEA8'}, /* KHAH */ + new char[]{'\u062F', '\uFEA9', '\uFEAA'}, /* DAL */ + new char[]{'\u0630', '\uFEAB', '\uFEAC'}, /* THAL */ + new char[]{'\u0631', '\uFEAD', '\uFEAE'}, /* REH */ + new char[]{'\u0632', '\uFEAF', '\uFEB0'}, /* ZAIN */ + new char[]{'\u0633', '\uFEB1', '\uFEB2', '\uFEB3', '\uFEB4'}, /* SEEN */ + new char[]{'\u0634', '\uFEB5', '\uFEB6', '\uFEB7', '\uFEB8'}, /* SHEEN */ + new char[]{'\u0635', '\uFEB9', '\uFEBA', '\uFEBB', '\uFEBC'}, /* SAD */ + new char[]{'\u0636', '\uFEBD', '\uFEBE', '\uFEBF', '\uFEC0'}, /* DAD */ + new char[]{'\u0637', '\uFEC1', '\uFEC2', '\uFEC3', '\uFEC4'}, /* TAH */ + new char[]{'\u0638', '\uFEC5', '\uFEC6', '\uFEC7', '\uFEC8'}, /* ZAH */ + new char[]{'\u0639', '\uFEC9', '\uFECA', '\uFECB', '\uFECC'}, /* AIN */ + new char[]{'\u063A', '\uFECD', '\uFECE', '\uFECF', '\uFED0'}, /* GHAIN */ + new char[]{'\u0640', '\u0640', '\u0640', '\u0640', '\u0640'}, /* TATWEEL */ + new char[]{'\u0641', '\uFED1', '\uFED2', '\uFED3', '\uFED4'}, /* FEH */ + new char[]{'\u0642', '\uFED5', '\uFED6', '\uFED7', '\uFED8'}, /* QAF */ + new char[]{'\u0643', '\uFED9', '\uFEDA', '\uFEDB', '\uFEDC'}, /* KAF */ + new char[]{'\u0644', '\uFEDD', '\uFEDE', '\uFEDF', '\uFEE0'}, /* LAM */ + new char[]{'\u0645', '\uFEE1', '\uFEE2', '\uFEE3', '\uFEE4'}, /* MEEM */ + new char[]{'\u0646', '\uFEE5', '\uFEE6', '\uFEE7', '\uFEE8'}, /* NOON */ + new char[]{'\u0647', '\uFEE9', '\uFEEA', '\uFEEB', '\uFEEC'}, /* HEH */ + new char[]{'\u0648', '\uFEED', '\uFEEE'}, /* WAW */ + new char[]{'\u0649', '\uFEEF', '\uFEF0', '\uFBE8', '\uFBE9'}, /* ALEF MAKSURA */ + new char[]{'\u064A', '\uFEF1', '\uFEF2', '\uFEF3', '\uFEF4'}, /* YEH */ + new char[]{'\u0671', '\uFB50', '\uFB51'}, /* ALEF WASLA */ + new char[]{'\u0679', '\uFB66', '\uFB67', '\uFB68', '\uFB69'}, /* TTEH */ + new char[]{'\u067A', '\uFB5E', '\uFB5F', '\uFB60', '\uFB61'}, /* TTEHEH */ + new char[]{'\u067B', '\uFB52', '\uFB53', '\uFB54', '\uFB55'}, /* BEEH */ + new char[]{'\u067E', '\uFB56', '\uFB57', '\uFB58', '\uFB59'}, /* PEH */ + new char[]{'\u067F', '\uFB62', '\uFB63', '\uFB64', '\uFB65'}, /* TEHEH */ + new char[]{'\u0680', '\uFB5A', '\uFB5B', '\uFB5C', '\uFB5D'}, /* BEHEH */ + new char[]{'\u0683', '\uFB76', '\uFB77', '\uFB78', '\uFB79'}, /* NYEH */ + new char[]{'\u0684', '\uFB72', '\uFB73', '\uFB74', '\uFB75'}, /* DYEH */ + new char[]{'\u0686', '\uFB7A', '\uFB7B', '\uFB7C', '\uFB7D'}, /* TCHEH */ + new char[]{'\u0687', '\uFB7E', '\uFB7F', '\uFB80', '\uFB81'}, /* TCHEHEH */ + new char[]{'\u0688', '\uFB88', '\uFB89'}, /* DDAL */ + new char[]{'\u068C', '\uFB84', '\uFB85'}, /* DAHAL */ + new char[]{'\u068D', '\uFB82', '\uFB83'}, /* DDAHAL */ + new char[]{'\u068E', '\uFB86', '\uFB87'}, /* DUL */ + new char[]{'\u0691', '\uFB8C', '\uFB8D'}, /* RREH */ + new char[]{'\u0698', '\uFB8A', '\uFB8B'}, /* JEH */ + new char[]{'\u06A4', '\uFB6A', '\uFB6B', '\uFB6C', '\uFB6D'}, /* VEH */ + new char[]{'\u06A6', '\uFB6E', '\uFB6F', '\uFB70', '\uFB71'}, /* PEHEH */ + new char[]{'\u06A9', '\uFB8E', '\uFB8F', '\uFB90', '\uFB91'}, /* KEHEH */ + new char[]{'\u06AD', '\uFBD3', '\uFBD4', '\uFBD5', '\uFBD6'}, /* NG */ + new char[]{'\u06AF', '\uFB92', '\uFB93', '\uFB94', '\uFB95'}, /* GAF */ + new char[]{'\u06B1', '\uFB9A', '\uFB9B', '\uFB9C', '\uFB9D'}, /* NGOEH */ + new char[]{'\u06B3', '\uFB96', '\uFB97', '\uFB98', '\uFB99'}, /* GUEH */ + new char[]{'\u06BA', '\uFB9E', '\uFB9F'}, /* NOON GHUNNA */ + new char[]{'\u06BB', '\uFBA0', '\uFBA1', '\uFBA2', '\uFBA3'}, /* RNOON */ + new char[]{'\u06BE', '\uFBAA', '\uFBAB', '\uFBAC', '\uFBAD'}, /* HEH DOACHASHMEE */ + new char[]{'\u06C0', '\uFBA4', '\uFBA5'}, /* HEH WITH YEH ABOVE */ + new char[]{'\u06C1', '\uFBA6', '\uFBA7', '\uFBA8', '\uFBA9'}, /* HEH GOAL */ + new char[]{'\u06C5', '\uFBE0', '\uFBE1'}, /* KIRGHIZ OE */ + new char[]{'\u06C6', '\uFBD9', '\uFBDA'}, /* OE */ + new char[]{'\u06C7', '\uFBD7', '\uFBD8'}, /* U */ + new char[]{'\u06C8', '\uFBDB', '\uFBDC'}, /* YU */ + new char[]{'\u06C9', '\uFBE2', '\uFBE3'}, /* KIRGHIZ YU */ + new char[]{'\u06CB', '\uFBDE', '\uFBDF'}, /* VE */ + new char[]{'\u06CC', '\uFBFC', '\uFBFD', '\uFBFE', '\uFBFF'}, /* FARSI YEH */ + new char[]{'\u06D0', '\uFBE4', '\uFBE5', '\uFBE6', '\uFBE7'}, /* E */ + new char[]{'\u06D2', '\uFBAE', '\uFBAF'}, /* YEH BARREE */ + new char[]{'\u06D3', '\uFBB0', '\uFBB1'} /* YEH BARREE WITH HAMZA ABOVE */ + }; + + public const int ar_nothing = 0x0; + public const int ar_novowel = 0x1; + public const int ar_composedtashkeel = 0x4; + public const int ar_lig = 0x8; + /** + * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits. + */ + public const int DIGITS_EN2AN = 0x20; + + /** + * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039). + */ + public const int DIGITS_AN2EN = 0x40; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be not an Arabic, + * letter, so European digits at the start of the text will not change. + * Compare to DIGITS_ALEN2AN_INIT_AL. + */ + public const int DIGITS_EN2AN_INIT_LR = 0x60; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be an Arabic, + * letter, so European digits at the start of the text will change. + * Compare to DIGITS_ALEN2AN_INT_LR. + */ + public const int DIGITS_EN2AN_INIT_AL = 0x80; + + /** Not a valid option value. */ + private const int DIGITS_RESERVED = 0xa0; + + /** + * Bit mask for digit shaping options. + */ + public const int DIGITS_MASK = 0xe0; + + /** + * Digit type option: Use Arabic-Indic digits (U+0660...U+0669). + */ + public const int DIGIT_TYPE_AN = 0; + + /** + * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9). + */ + public const int DIGIT_TYPE_AN_EXTENDED = 0x100; + + /** + * Bit mask for digit type options. + */ + public const int DIGIT_TYPE_MASK = '\u0100'; // '\u3f00'? + + private class Charstruct { + internal char basechar; + internal char mark1; /* has to be initialized to zero */ + internal char vowel; + internal int lignum; /* is a ligature with lignum aditional characters */ + internal int numshapes = 1; + }; + + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs b/iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs new file mode 100644 index 0000000..65ead6c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; + +/* + * $Id: BadPasswordException.cs,v 1.1 2008/01/10 15:49:39 psoares33 Exp $ + * + * Copyright 2008 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class BadPasswordException : IOException { + public BadPasswordException() : base("Bad user Password") { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs b/iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs new file mode 100644 index 0000000..db72d7c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs @@ -0,0 +1,72 @@ +using System; + +/* + * $Id: BadPdfFormatException.cs,v 1.3 2008/05/13 11:25:16 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + /** + * Signals that a bad PDF format has been used to construct a PdfObject. + * + * @see PdfException + * @see PdfBoolean + * @see PdfNumber + * @see PdfString + * @see PdfName + * @see PdfDictionary + * @see PdfFont + */ + + public class BadPdfFormatException : Exception + { + public BadPdfFormatException() : base() {} + public BadPdfFormatException(string message) : base(message) {} + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Barcode.cs b/iTechSharp/iTextSharp/text/pdf/Barcode.cs new file mode 100644 index 0000000..22ef490 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Barcode.cs @@ -0,0 +1,430 @@ +using System; +using iTextSharp.text; +/* + * $Id: Barcode.cs,v 1.4 2006/07/31 13:51:38 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Base class containing properties and methods commom to all + * barcode types. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public abstract class Barcode { + /** A type of barcode */ + public const int EAN13 = 1; + /** A type of barcode */ + public const int EAN8 = 2; + /** A type of barcode */ + public const int UPCA = 3; + /** A type of barcode */ + public const int UPCE = 4; + /** A type of barcode */ + public const int SUPP2 = 5; + /** A type of barcode */ + public const int SUPP5 = 6; + /** A type of barcode */ + public const int POSTNET = 7; + /** A type of barcode */ + public const int PLANET = 8; + /** A type of barcode */ + public const int CODE128 = 9; + /** A type of barcode */ + public const int CODE128_UCC = 10; + /** A type of barcode */ + public const int CODE128_RAW = 11; + /** A type of barcode */ + public const int CODABAR = 12; + + /** The minimum bar width. + */ + protected float x; + + /** The bar multiplier for wide bars or the distance between + * bars for Postnet and Planet. + */ + protected float n; + + /** The text font. null if no text. + */ + protected BaseFont font; + + /** The size of the text or the height of the shorter bar + * in Postnet. + */ + protected float size; + + /** If positive, the text distance under the bars. If zero or negative, + * the text distance above the bars. + */ + protected float baseline; + + /** The height of the bars. + */ + protected float barHeight; + + /** The text Element. Can be Element.ALIGN_LEFT, + * Element.ALIGN_CENTER or Element.ALIGN_RIGHT. + */ + protected int textAlignment; + + /** The optional checksum generation. + */ + protected bool generateChecksum; + + /** Shows the generated checksum in the the text. + */ + protected bool checksumText; + + /** Show the start and stop character '*' in the text for + * the barcode 39 or 'ABCD' for codabar. + */ + protected bool startStopText; + + /** Generates extended barcode 39. + */ + protected bool extended; + + /** The code to generate. + */ + protected string code = ""; + + /** Show the guard bars for barcode EAN. + */ + protected bool guardBars; + + /** The code type. + */ + protected int codeType; + + /** The ink spreading. */ + protected float inkSpreading = 0; + + /** Gets the minimum bar width. + * @return the minimum bar width + */ + public float X { + get { + return x; + } + + set { + this.x = value; + } + } + + /** Gets the bar multiplier for wide bars. + * @return the bar multiplier for wide bars + */ + public float N { + get { + return n; + } + + set { + this.n = value; + } + } + + /** Gets the text font. null if no text. + * @return the text font. null if no text + */ + public BaseFont Font { + get { + return font; + } + + set { + this.font = value; + } + } + + /** Gets the size of the text. + * @return the size of the text + */ + public float Size { + get { + return size; + } + + set { + this.size = value; + } + } + + /** Gets the text baseline. + * If positive, the text distance under the bars. If zero or negative, + * the text distance above the bars. + * @return the baseline. + */ + public float Baseline { + get { + return baseline; + } + + set { + this.baseline = value; + } + } + + /** Gets the height of the bars. + * @return the height of the bars + */ + public float BarHeight { + get { + return barHeight; + } + + set { + this.barHeight = value; + } + } + + /** Gets the text Element. Can be Element.ALIGN_LEFT, + * Element.ALIGN_CENTER or Element.ALIGN_RIGHT. + * @return the text alignment + */ + public int TextAlignment{ + get { + return textAlignment; + } + + set { + this.textAlignment = value; + } + } + + /** The property for the optional checksum generation. + */ + public bool GenerateChecksum { + set { + this.generateChecksum = value; + } + get { + return generateChecksum; + } + } + + /** Sets the property to show the generated checksum in the the text. + * @param checksumText new value of property checksumText + */ + public bool ChecksumText { + set { + this.checksumText = value; + } + get { + return checksumText; + } + } + + /** Gets the property to show the start and stop character '*' in the text for + * the barcode 39. + * @param startStopText new value of property startStopText + */ + public bool StartStopText { + set { + this.startStopText = value; + } + get { + return startStopText; + } + } + + /** Sets the property to generate extended barcode 39. + * @param extended new value of property extended + */ + public bool Extended { + set { + this.extended = value; + } + get { + return extended; + } + } + + /** Gets the code to generate. + * @return the code to generate + */ + public virtual string Code { + get { + return code; + } + + set { + this.code = value; + } + } + + /** Sets the property to show the guard bars for barcode EAN. + * @param guardBars new value of property guardBars + */ + public bool GuardBars { + set { + this.guardBars = value; + } + get { + return guardBars; + } + } + + /** Gets the code type. + * @return the code type + */ + public int CodeType { + get { + return codeType; + } + + set { + this.codeType = value; + } + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public abstract Rectangle BarcodeSize { + get; + } + + public float InkSpreading { + set { + inkSpreading = value; + } + get { + return inkSpreading; + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public abstract Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor); + + /** Creates a template with the barcode. + * @param cb the PdfContentByte to create the template. It + * serves no other use + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the template + * @see #placeBarcode(PdfContentByte cb, Color barColor, Color textColor) + */ + public PdfTemplate CreateTemplateWithBarcode(PdfContentByte cb, Color barColor, Color textColor) { + PdfTemplate tp = cb.CreateTemplate(0, 0); + Rectangle rect = PlaceBarcode(tp, barColor, textColor); + tp.BoundingBox = rect; + return tp; + } + + /** Creates an Image with the barcode. + * @param cb the PdfContentByte to create the Image. It + * serves no other use + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the Image + * @see #placeBarcode(PdfContentByte cb, Color barColor, Color textColor) + */ + public Image CreateImageWithBarcode(PdfContentByte cb, Color barColor, Color textColor) { + return Image.GetInstance(CreateTemplateWithBarcode(cb, barColor, textColor)); + } + + /** + * The alternate text to be used, if present. + */ + protected String altText; + + /** + * Sets the alternate text. If present, this text will be used instead of the + * text derived from the supplied code. + * @param altText the alternate text + */ + public String AltText { + set { + altText = value; + } + get { + return altText; + } + } + + public abstract System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Barcode128.cs b/iTechSharp/iTextSharp/text/pdf/Barcode128.cs new file mode 100644 index 0000000..96c4807 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Barcode128.cs @@ -0,0 +1,809 @@ +using System; +using System.Text; +using iTextSharp.text; +/* + * $Id: Barcode128.cs,v 1.6 2007/10/24 16:31:54 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Implements the code 128 and UCC/EAN-128. Other symbologies are allowed in raw mode.

+ * The code types allowed are:
+ *

    + *
  • CODE128 - plain barcode 128. + *
  • CODE128_UCC - support for UCC/EAN-128 with a full list of AI. + *
  • CODE128_RAW - raw mode. The code attribute has the actual codes from 0 + * to 105 followed by '\uffff' and the human readable text. + *
+ * The default parameters are: + *
+     * x = 0.8f;
+     * font = BaseFont.CreateFont("Helvetica", "winansi", false);
+     * size = 8;
+     * baseline = size;
+     * barHeight = size * 3;
+     * textint= Element.ALIGN_CENTER;
+     * codeType = CODE128;
+     * 
+ * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class Barcode128 : Barcode { + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = + { + new byte[] {2, 1, 2, 2, 2, 2}, + new byte[] {2, 2, 2, 1, 2, 2}, + new byte[] {2, 2, 2, 2, 2, 1}, + new byte[] {1, 2, 1, 2, 2, 3}, + new byte[] {1, 2, 1, 3, 2, 2}, + new byte[] {1, 3, 1, 2, 2, 2}, + new byte[] {1, 2, 2, 2, 1, 3}, + new byte[] {1, 2, 2, 3, 1, 2}, + new byte[] {1, 3, 2, 2, 1, 2}, + new byte[] {2, 2, 1, 2, 1, 3}, + new byte[] {2, 2, 1, 3, 1, 2}, + new byte[] {2, 3, 1, 2, 1, 2}, + new byte[] {1, 1, 2, 2, 3, 2}, + new byte[] {1, 2, 2, 1, 3, 2}, + new byte[] {1, 2, 2, 2, 3, 1}, + new byte[] {1, 1, 3, 2, 2, 2}, + new byte[] {1, 2, 3, 1, 2, 2}, + new byte[] {1, 2, 3, 2, 2, 1}, + new byte[] {2, 2, 3, 2, 1, 1}, + new byte[] {2, 2, 1, 1, 3, 2}, + new byte[] {2, 2, 1, 2, 3, 1}, + new byte[] {2, 1, 3, 2, 1, 2}, + new byte[] {2, 2, 3, 1, 1, 2}, + new byte[] {3, 1, 2, 1, 3, 1}, + new byte[] {3, 1, 1, 2, 2, 2}, + new byte[] {3, 2, 1, 1, 2, 2}, + new byte[] {3, 2, 1, 2, 2, 1}, + new byte[] {3, 1, 2, 2, 1, 2}, + new byte[] {3, 2, 2, 1, 1, 2}, + new byte[] {3, 2, 2, 2, 1, 1}, + new byte[] {2, 1, 2, 1, 2, 3}, + new byte[] {2, 1, 2, 3, 2, 1}, + new byte[] {2, 3, 2, 1, 2, 1}, + new byte[] {1, 1, 1, 3, 2, 3}, + new byte[] {1, 3, 1, 1, 2, 3}, + new byte[] {1, 3, 1, 3, 2, 1}, + new byte[] {1, 1, 2, 3, 1, 3}, + new byte[] {1, 3, 2, 1, 1, 3}, + new byte[] {1, 3, 2, 3, 1, 1}, + new byte[] {2, 1, 1, 3, 1, 3}, + new byte[] {2, 3, 1, 1, 1, 3}, + new byte[] {2, 3, 1, 3, 1, 1}, + new byte[] {1, 1, 2, 1, 3, 3}, + new byte[] {1, 1, 2, 3, 3, 1}, + new byte[] {1, 3, 2, 1, 3, 1}, + new byte[] {1, 1, 3, 1, 2, 3}, + new byte[] {1, 1, 3, 3, 2, 1}, + new byte[] {1, 3, 3, 1, 2, 1}, + new byte[] {3, 1, 3, 1, 2, 1}, + new byte[] {2, 1, 1, 3, 3, 1}, + new byte[] {2, 3, 1, 1, 3, 1}, + new byte[] {2, 1, 3, 1, 1, 3}, + new byte[] {2, 1, 3, 3, 1, 1}, + new byte[] {2, 1, 3, 1, 3, 1}, + new byte[] {3, 1, 1, 1, 2, 3}, + new byte[] {3, 1, 1, 3, 2, 1}, + new byte[] {3, 3, 1, 1, 2, 1}, + new byte[] {3, 1, 2, 1, 1, 3}, + new byte[] {3, 1, 2, 3, 1, 1}, + new byte[] {3, 3, 2, 1, 1, 1}, + new byte[] {3, 1, 4, 1, 1, 1}, + new byte[] {2, 2, 1, 4, 1, 1}, + new byte[] {4, 3, 1, 1, 1, 1}, + new byte[] {1, 1, 1, 2, 2, 4}, + new byte[] {1, 1, 1, 4, 2, 2}, + new byte[] {1, 2, 1, 1, 2, 4}, + new byte[] {1, 2, 1, 4, 2, 1}, + new byte[] {1, 4, 1, 1, 2, 2}, + new byte[] {1, 4, 1, 2, 2, 1}, + new byte[] {1, 1, 2, 2, 1, 4}, + new byte[] {1, 1, 2, 4, 1, 2}, + new byte[] {1, 2, 2, 1, 1, 4}, + new byte[] {1, 2, 2, 4, 1, 1}, + new byte[] {1, 4, 2, 1, 1, 2}, + new byte[] {1, 4, 2, 2, 1, 1}, + new byte[] {2, 4, 1, 2, 1, 1}, + new byte[] {2, 2, 1, 1, 1, 4}, + new byte[] {4, 1, 3, 1, 1, 1}, + new byte[] {2, 4, 1, 1, 1, 2}, + new byte[] {1, 3, 4, 1, 1, 1}, + new byte[] {1, 1, 1, 2, 4, 2}, + new byte[] {1, 2, 1, 1, 4, 2}, + new byte[] {1, 2, 1, 2, 4, 1}, + new byte[] {1, 1, 4, 2, 1, 2}, + new byte[] {1, 2, 4, 1, 1, 2}, + new byte[] {1, 2, 4, 2, 1, 1}, + new byte[] {4, 1, 1, 2, 1, 2}, + new byte[] {4, 2, 1, 1, 1, 2}, + new byte[] {4, 2, 1, 2, 1, 1}, + new byte[] {2, 1, 2, 1, 4, 1}, + new byte[] {2, 1, 4, 1, 2, 1}, + new byte[] {4, 1, 2, 1, 2, 1}, + new byte[] {1, 1, 1, 1, 4, 3}, + new byte[] {1, 1, 1, 3, 4, 1}, + new byte[] {1, 3, 1, 1, 4, 1}, + new byte[] {1, 1, 4, 1, 1, 3}, + new byte[] {1, 1, 4, 3, 1, 1}, + new byte[] {4, 1, 1, 1, 1, 3}, + new byte[] {4, 1, 1, 3, 1, 1}, + new byte[] {1, 1, 3, 1, 4, 1}, + new byte[] {1, 1, 4, 1, 3, 1}, + new byte[] {3, 1, 1, 1, 4, 1}, + new byte[] {4, 1, 1, 1, 3, 1}, + new byte[] {2, 1, 1, 4, 1, 2}, + new byte[] {2, 1, 1, 2, 1, 4}, + new byte[] {2, 1, 1, 2, 3, 2} + }; + + /** The stop bars. + */ + private static readonly byte[] BARS_STOP = {2, 3, 3, 1, 1, 1, 2}; + /** The charset code change. + */ + public const char CODE_AB_TO_C = (char)99; + /** The charset code change. + */ + public const char CODE_AC_TO_B = (char)100; + /** The charset code change. + */ + public const char CODE_BC_TO_A = (char)101; + /** The code for UCC/EAN-128. + */ + public const char FNC1_INDEX = (char)102; + /** The start code. + */ + public const char START_A = (char)103; + /** The start code. + */ + public const char START_B = (char)104; + /** The start code. + */ + public const char START_C = (char)105; + + public const char FNC1 = '\u00ca'; + public const char DEL = '\u00c3'; + public const char FNC3 = '\u00c4'; + public const char FNC2 = '\u00c5'; + public const char SHIFT = '\u00c6'; + public const char CODE_C = '\u00c7'; + public const char CODE_A = '\u00c8'; + public const char FNC4 = '\u00c8'; + public const char STARTA = '\u00cb'; + public const char STARTB = '\u00cc'; + public const char STARTC = '\u00cd'; + + private static IntHashtable ais = new IntHashtable(); + + /** Creates new Barcode128 */ + public Barcode128() { + x = 0.8f; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + codeType = CODE128; + } + + /** + * Removes the FNC1 codes in the text. + * @param code the text to clean + * @return the cleaned text + */ + public static String RemoveFNC1(String code) { + int len = code.Length; + StringBuilder buf = new StringBuilder(len); + for (int k = 0; k < len; ++k) { + char c = code[k]; + if (c >= 32 && c <= 126) + buf.Append(c); + } + return buf.ToString(); + } + + /** + * Gets the human readable text of a sequence of AI. + * @param code the text + * @return the human readable text + */ + public static String GetHumanReadableUCCEAN(String code) { + StringBuilder buf = new StringBuilder(); + String fnc1 = FNC1.ToString(); + try { + while (true) { + if (code.StartsWith(fnc1)) { + code = code.Substring(1); + continue; + } + int n = 0; + int idlen = 0; + for (int k = 2; k < 5; ++k) { + if (code.Length < k) + break; + if ((n = ais[int.Parse(code.Substring(0, k))]) != 0) { + idlen = k; + break; + } + } + if (idlen == 0) + break; + buf.Append('(').Append(code.Substring(0, idlen)).Append(')'); + code = code.Substring(idlen); + if (n > 0) { + n -= idlen; + if (code.Length <= n) + break; + buf.Append(RemoveFNC1(code.Substring(0, n))); + code = code.Substring(n); + } + else { + int idx = code.IndexOf(FNC1); + if (idx < 0) + break; + buf.Append(code.Substring(0,idx)); + code = code.Substring(idx + 1); + } + } + } + catch { + //empty + } + buf.Append(RemoveFNC1(code)); + return buf.ToString(); + } + + /** Returns true if the next numDigits + * starting from index textIndex are numeric skipping any FNC1. + * @param text the text to check + * @param textIndex where to check from + * @param numDigits the number of digits to check + * @return the check result + */ + internal static bool IsNextDigits(string text, int textIndex, int numDigits) { + int len = text.Length; + while (textIndex < len && numDigits > 0) { + if (text[textIndex] == FNC1) { + ++textIndex; + continue; + } + int n = Math.Min(2, numDigits); + if (textIndex + n > len) + return false; + while (n-- > 0) { + char c = text[textIndex++]; + if (c < '0' || c > '9') + return false; + --numDigits; + } + } + return numDigits == 0; + } + + /** Packs the digits for charset C also considering FNC1. It assumes that all the parameters + * are valid. + * @param text the text to pack + * @param textIndex where to pack from + * @param numDigits the number of digits to pack. It is always an even number + * @return the packed digits, two digits per character + */ + internal static String GetPackedRawDigits(String text, int textIndex, int numDigits) { + String outs = ""; + int start = textIndex; + while (numDigits > 0) { + if (text[textIndex] == FNC1) { + outs += FNC1_INDEX; + ++textIndex; + continue; + } + numDigits -= 2; + int c1 = text[textIndex++] - '0'; + int c2 = text[textIndex++] - '0'; + outs += (char)(c1 * 10 + c2); + } + return (char)(textIndex - start) + outs; + } + + /** Converts the human readable text to the characters needed to + * create a barcode. Some optimization is done to get the shortest code. + * @param text the text to convert + * @param ucc true if it is an UCC/EAN-128. In this case + * the character FNC1 is added + * @return the code ready to be fed to GetBarsCode128Raw() + */ + public static string GetRawText(string text, bool ucc) { + String outs = ""; + int tLen = text.Length; + if (tLen == 0) { + outs += START_B; + if (ucc) + outs += FNC1_INDEX; + return outs; + } + int c = 0; + for (int k = 0; k < tLen; ++k) { + c = text[k]; + if (c > 127 && c != FNC1) + throw new ArgumentException("There are illegal characters for barcode 128 in '" + text + "'."); + } + c = text[0]; + char currentCode = START_B; + int index = 0; + if (IsNextDigits(text, index, 2)) { + currentCode = START_C; + outs += currentCode; + if (ucc) + outs += FNC1_INDEX; + String out2 = GetPackedRawDigits(text, index, 2); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else if (c < ' ') { + currentCode = START_A; + outs += currentCode; + if (ucc) + outs += FNC1_INDEX; + outs += (char)(c + 64); + ++index; + } + else { + outs += currentCode; + if (ucc) + outs += FNC1_INDEX; + if (c == FNC1) + outs += FNC1_INDEX; + else + outs += (char)(c - ' '); + ++index; + } + while (index < tLen) { + switch (currentCode) { + case START_A: + { + if (IsNextDigits(text, index, 4)) { + currentCode = START_C; + outs += CODE_AB_TO_C; + String out2 = GetPackedRawDigits(text, index, 4); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else { + c = text[index++]; + if (c == FNC1) + outs += FNC1_INDEX; + else if (c > '_') { + currentCode = START_B; + outs += CODE_AC_TO_B; + outs += (char)(c - ' '); + } + else if (c < ' ') + outs += (char)(c + 64); + else + outs += (char)(c - ' '); + } + } + break; + case START_B: + { + if (IsNextDigits(text, index, 4)) { + currentCode = START_C; + outs += CODE_AB_TO_C; + String out2 = GetPackedRawDigits(text, index, 4); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else { + c = text[index++]; + if (c == FNC1) + outs += FNC1_INDEX; + else if (c < ' ') { + currentCode = START_A; + outs += CODE_BC_TO_A; + outs += (char)(c + 64); + } + else { + outs += (char)(c - ' '); + } + } + } + break; + case START_C: + { + if (IsNextDigits(text, index, 2)) { + String out2 = GetPackedRawDigits(text, index, 2); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else { + c = text[index++]; + if (c == FNC1) + outs += FNC1_INDEX; + else if (c < ' ') { + currentCode = START_A; + outs += CODE_BC_TO_A; + outs += (char)(c + 64); + } + else { + currentCode = START_B; + outs += CODE_AC_TO_B; + outs += (char)(c - ' '); + } + } + } + break; + } + } + return outs; + } + + /** Generates the bars. The input has the actual barcodes, not + * the human readable text. + * @param text the barcode + * @return the bars + */ + public static byte[] GetBarsCode128Raw(string text) { + int k; + int idx = text.IndexOf('\uffff'); + if (idx >= 0) + text = text.Substring(0, idx); + int chk = text[0]; + for (k = 1; k < text.Length; ++k) + chk += k * text[k]; + chk = chk % 103; + text += (char)chk; + byte[] bars = new byte[(text.Length + 1) * 6 + 7]; + for (k = 0; k < text.Length; ++k) + Array.Copy(BARS[text[k]], 0, bars, k * 6, 6); + Array.Copy(BARS_STOP, 0, bars, k * 6, 7); + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + string fullCode; + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx < 0) + fullCode = ""; + else + fullCode = code.Substring(idx + 1); + } + else if (codeType == CODE128_UCC) + fullCode = GetHumanReadableUCCEAN(code); + else + fullCode = RemoveFNC1(code); + fontX = font.GetWidthPoint(altText != null ? altText : fullCode, size); + } + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx >= 0) + fullCode = code.Substring(0, idx); + else + fullCode = code; + } + else { + fullCode = GetRawText(code, codeType == CODE128_UCC); + } + int len = fullCode.Length; + float fullWidth = (len + 2) * 11 * x + 2 * x; + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + string fullCode; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx < 0) + fullCode = ""; + else + fullCode = code.Substring(idx + 1); + } + else if (codeType == CODE128_UCC) + fullCode = GetHumanReadableUCCEAN(code); + else + fullCode = RemoveFNC1(code); + float fontX = 0; + if (font != null) { + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + string bCode; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx >= 0) + bCode = code.Substring(0, idx); + else + bCode = code; + } + else { + bCode = GetRawText(code, codeType == CODE128_UCC); + } + int len = bCode.Length; + float fullWidth = (len + 2) * 11 * x + 2 * x; + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + byte[] bars = GetBarsCode128Raw(bCode); + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = bars[k] * x; + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String bCode; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx >= 0) + bCode = code.Substring(0, idx); + else + bCode = code; + } + else { + bCode = GetRawText(code, codeType == CODE128_UCC); + } + int len = bCode.Length; + int fullWidth = (len + 2) * 11 + 2; + byte[] bars = GetBarsCode128Raw(bCode); + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = bars[k]; + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + + /** + * Sets the code to generate. If it's an UCC code and starts with '(' it will + * be split by the AI. This code in UCC mode is valid: + *

+ * (01)00000090311314(10)ABC123(15)060916 + * @param code the code to generate + */ + public override string Code { + set { + string code = value; + if (CodeType == Barcode128.CODE128_UCC && code.StartsWith("(")) { + int idx = 0; + String ret = ""; + while (idx >= 0) { + int end = code.IndexOf(')', idx); + if (end < 0) + throw new ArgumentException("Badly formed UCC string: " + code); + String sai = code.Substring(idx + 1, end - (idx + 1)); + if (sai.Length < 2) + throw new ArgumentException("AI too short: (" + sai + ")"); + int ai = int.Parse(sai); + int len = ais[ai]; + if (len == 0) + throw new ArgumentException("AI not found: (" + sai + ")"); + sai = ai.ToString(); + if (sai.Length == 1) + sai = "0" + sai; + idx = code.IndexOf('(', end); + int next = (idx < 0 ? code.Length : idx); + ret += sai + code.Substring(end + 1, next - (end + 1)); + if (len < 0) { + if (idx >= 0) + ret += FNC1; + } + else if (next - end - 1 + sai.Length != len) + throw new ArgumentException("Invalid AI length: (" + sai + ")"); + } + base.Code = ret; + } + else + base.Code = code; + } + } + + static Barcode128 () { + ais[0] = 20; + ais[1] = 16; + ais[2] = 16; + ais[10] = -1; + ais[11] = 9; + ais[12] = 8; + ais[13] = 8; + ais[15] = 8; + ais[17] = 8; + ais[20] = 4; + ais[21] = -1; + ais[22] = -1; + ais[23] = -1; + ais[240] = -1; + ais[241] = -1; + ais[250] = -1; + ais[251] = -1; + ais[252] = -1; + ais[30] = -1; + for (int k = 3100; k < 3700; ++k) + ais[k] = 10; + ais[37] = -1; + for (int k = 3900; k < 3940; ++k) + ais[k] = -1; + ais[400] = -1; + ais[401] = -1; + ais[402] = 20; + ais[403] = -1; + for (int k = 410; k < 416; ++k) + ais[k] = 16; + ais[420] = -1; + ais[421] = -1; + ais[422] = 6; + ais[423] = -1; + ais[424] = 6; + ais[425] = 6; + ais[426] = 6; + ais[7001] = 17; + ais[7002] = -1; + for (int k = 7030; k < 7040; ++k) + ais[k] = -1; + ais[8001] = 18; + ais[8002] = -1; + ais[8003] = -1; + ais[8004] = -1; + ais[8005] = 10; + ais[8006] = 22; + ais[8007] = -1; + ais[8008] = -1; + ais[8018] = 22; + ais[8020] = -1; + ais[8100] = 10; + ais[8101] = 14; + ais[8102] = 6; + for (int k = 90; k < 100; ++k) + ais[k] = -1; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Barcode39.cs b/iTechSharp/iTextSharp/text/pdf/Barcode39.cs new file mode 100644 index 0000000..f93dea7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Barcode39.cs @@ -0,0 +1,370 @@ +using System; +using iTextSharp.text; +/* + * $Id: Barcode39.cs,v 1.6 2007/05/03 19:36:07 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Implements the code 39 and code 39 extended. The default parameters are: + *

+     *x = 0.8f;
+     *n = 2;
+     *font = BaseFont.CreateFont("Helvetica", "winansi", false);
+     *size = 8;
+     *baseline = size;
+     *barHeight = size * 3;
+     *textint= Element.ALIGN_CENTER;
+     *generateChecksum = false;
+     *checksumText = false;
+     *startStopText = true;
+     *extended = false;
+     * 
+ * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class Barcode39 : Barcode { + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = + { + new byte[] {0,0,0,1,1,0,1,0,0}, + new byte[] {1,0,0,1,0,0,0,0,1}, + new byte[] {0,0,1,1,0,0,0,0,1}, + new byte[] {1,0,1,1,0,0,0,0,0}, + new byte[] {0,0,0,1,1,0,0,0,1}, + new byte[] {1,0,0,1,1,0,0,0,0}, + new byte[] {0,0,1,1,1,0,0,0,0}, + new byte[] {0,0,0,1,0,0,1,0,1}, + new byte[] {1,0,0,1,0,0,1,0,0}, + new byte[] {0,0,1,1,0,0,1,0,0}, + new byte[] {1,0,0,0,0,1,0,0,1}, + new byte[] {0,0,1,0,0,1,0,0,1}, + new byte[] {1,0,1,0,0,1,0,0,0}, + new byte[] {0,0,0,0,1,1,0,0,1}, + new byte[] {1,0,0,0,1,1,0,0,0}, + new byte[] {0,0,1,0,1,1,0,0,0}, + new byte[] {0,0,0,0,0,1,1,0,1}, + new byte[] {1,0,0,0,0,1,1,0,0}, + new byte[] {0,0,1,0,0,1,1,0,0}, + new byte[] {0,0,0,0,1,1,1,0,0}, + new byte[] {1,0,0,0,0,0,0,1,1}, + new byte[] {0,0,1,0,0,0,0,1,1}, + new byte[] {1,0,1,0,0,0,0,1,0}, + new byte[] {0,0,0,0,1,0,0,1,1}, + new byte[] {1,0,0,0,1,0,0,1,0}, + new byte[] {0,0,1,0,1,0,0,1,0}, + new byte[] {0,0,0,0,0,0,1,1,1}, + new byte[] {1,0,0,0,0,0,1,1,0}, + new byte[] {0,0,1,0,0,0,1,1,0}, + new byte[] {0,0,0,0,1,0,1,1,0}, + new byte[] {1,1,0,0,0,0,0,0,1}, + new byte[] {0,1,1,0,0,0,0,0,1}, + new byte[] {1,1,1,0,0,0,0,0,0}, + new byte[] {0,1,0,0,1,0,0,0,1}, + new byte[] {1,1,0,0,1,0,0,0,0}, + new byte[] {0,1,1,0,1,0,0,0,0}, + new byte[] {0,1,0,0,0,0,1,0,1}, + new byte[] {1,1,0,0,0,0,1,0,0}, + new byte[] {0,1,1,0,0,0,1,0,0}, + new byte[] {0,1,0,1,0,1,0,0,0}, + new byte[] {0,1,0,1,0,0,0,1,0}, + new byte[] {0,1,0,0,0,1,0,1,0}, + new byte[] {0,0,0,1,0,1,0,1,0}, + new byte[] {0,1,0,0,1,0,1,0,0} + }; + + /** The index chars to BARS. + */ + private const string CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*"; + + /** The character combinations to make the code 39 extended. + */ + private const string EXTENDED = "%U" + + "$A$B$C$D$E$F$G$H$I$J$K$L$M$N$O$P$Q$R$S$T$U$V$W$X$Y$Z" + + "%A%B%C%D%E /A/B/C/D/E/F/G/H/I/J/K/L - ./O" + + " 0 1 2 3 4 5 6 7 8 9/Z%F%G%H%I%J%V" + + " A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" + + "%K%L%M%N%O%W" + + "+A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z" + + "%P%Q%R%S%T"; + + /** Creates a new Barcode39. + */ + public Barcode39() { + x = 0.8f; + n = 2; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + generateChecksum = false; + checksumText = false; + startStopText = true; + extended = false; + } + + /** Creates the bars. + * @param text the text to create the bars. This text does not include the start and + * stop characters + * @return the bars + */ + public static byte[] GetBarsCode39(string text) { + text = "*" + text + "*"; + byte[] bars = new byte[text.Length * 10 - 1]; + for (int k = 0; k < text.Length; ++k) { + int idx = CHARS.IndexOf(text[k]); + if (idx < 0) + throw new ArgumentException("The character '" + text[k] + "' is illegal in code 39."); + Array.Copy(BARS[idx], 0, bars, k * 10, 9); + } + return bars; + } + + /** Converts the extended text into a normal, escaped text, + * ready to generate bars. + * @param text the extended text + * @return the escaped text + */ + public static string GetCode39Ex(string text) { + string ret = ""; + for (int k = 0; k < text.Length; ++k) { + char c = text[k]; + if (c > 127) + throw new ArgumentException("The character '" + c + "' is illegal in code 39 extended."); + char c1 = EXTENDED[c * 2]; + char c2 = EXTENDED[c * 2 + 1]; + if (c1 != ' ') + ret += c1; + ret += c2; + } + return ret; + } + + /** Calculates the checksum. + * @param text the text + * @return the checksum + */ + internal static char GetChecksum(string text) { + int chk = 0; + for (int k = 0; k < text.Length; ++k) { + int idx = CHARS.IndexOf(text[k]); + if (idx < 0) + throw new ArgumentException("The character '" + text[k] + "' is illegal in code 39."); + chk += idx; + } + return CHARS[chk % 43]; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + string fCode = code; + if (extended) + fCode = GetCode39Ex(code); + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + string fullCode = code; + if (generateChecksum && checksumText) + fullCode += GetChecksum(fCode); + if (startStopText) + fullCode = "*" + fullCode + "*"; + fontX = font.GetWidthPoint(altText != null ? altText : fullCode, size); + } + int len = fCode.Length + 2; + if (generateChecksum) + ++len; + float fullWidth = len * (6 * x + 3 * x * n) + (len - 1) * x; + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + string fullCode = code; + float fontX = 0; + string bCode = code; + if (extended) + bCode = GetCode39Ex(code); + if (font != null) { + if (generateChecksum && checksumText) + fullCode += GetChecksum(bCode); + if (startStopText) + fullCode = "*" + fullCode + "*"; + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length + 2; + float fullWidth = len * (6 * x + 3 * x * n) + (len - 1) * x; + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + byte[] bars = GetBarsCode39(bCode); + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = (bars[k] == 0 ? x : x * n); + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String bCode = code; + if (extended) + bCode = GetCode39Ex(code); + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length + 2; + int nn = (int)n; + int fullWidth = len * (6 + 3 * nn) + (len - 1); + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + byte[] bars = GetBarsCode39(bCode); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = (bars[k] == 0 ? 1 : nn); + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs new file mode 100644 index 0000000..d80ab49 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs @@ -0,0 +1,324 @@ +using System; +using iTextSharp.text; +/* + * $Id: BarcodeCodabar.cs,v 1.7 2007/02/22 20:48:38 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + /** Implements the code codabar. The default parameters are: + *

+    *x = 0.8f;
+    *n = 2;
+    *font = BaseFont.CreateFont("Helvetica", "winansi", false);
+    *size = 8;
+    *baseline = size;
+    *barHeight = size * 3;
+    *textAlignment = Element.ALIGN_CENTER;
+    *generateChecksum = false;
+    *checksumText = false;
+    *startStopText = false;
+    * 
+ * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeCodabar : Barcode{ + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = new byte[][] { + new byte[]{0,0,0,0,0,1,1}, // 0 + new byte[]{0,0,0,0,1,1,0}, // 1 + new byte[]{0,0,0,1,0,0,1}, // 2 + new byte[]{1,1,0,0,0,0,0}, // 3 + new byte[]{0,0,1,0,0,1,0}, // 4 + new byte[]{1,0,0,0,0,1,0}, // 5 + new byte[]{0,1,0,0,0,0,1}, // 6 + new byte[]{0,1,0,0,1,0,0}, // 7 + new byte[]{0,1,1,0,0,0,0}, // 8 + new byte[]{1,0,0,1,0,0,0}, // 9 + new byte[]{0,0,0,1,1,0,0}, // - + new byte[]{0,0,1,1,0,0,0}, // $ + new byte[]{1,0,0,0,1,0,1}, // : + new byte[]{1,0,1,0,0,0,1}, // / + new byte[]{1,0,1,0,1,0,0}, // . + new byte[]{0,0,1,0,1,0,1}, // + + new byte[]{0,0,1,1,0,1,0}, // a + new byte[]{0,1,0,1,0,0,1}, // b + new byte[]{0,0,0,1,0,1,1}, // c + new byte[]{0,0,0,1,1,1,0} // d + }; + + /** The index chars to BARS. + */ + private const string CHARS = "0123456789-$:/.+ABCD"; + + private const int START_STOP_IDX = 16; + /** Creates a new BarcodeCodabar. + */ + public BarcodeCodabar() { + x = 0.8f; + n = 2; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + generateChecksum = false; + checksumText = false; + startStopText = false; + codeType = CODABAR; + } + + /** Creates the bars. + * @param text the text to create the bars + * @return the bars + */ + public static byte[] GetBarsCodabar(String text) { + text = text.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + int len = text.Length; + if (len < 2) + throw new ArgumentException("Codabar must have at least a start and stop character."); + if (CHARS.IndexOf(text[0]) < START_STOP_IDX || CHARS.IndexOf(text[len - 1]) < START_STOP_IDX) + throw new ArgumentException("Codabar must have one of 'ABCD' as start/stop character."); + byte[] bars = new byte[text.Length * 8 - 1]; + for (int k = 0; k < len; ++k) { + int idx = CHARS.IndexOf(text[k]); + if (idx >= START_STOP_IDX && k > 0 && k < len - 1) + throw new ArgumentException("In codabar, start/stop characters are only allowed at the extremes."); + if (idx < 0) + throw new ArgumentException("The character '" + text[k] + "' is illegal in codabar."); + Array.Copy(BARS[idx], 0, bars, k * 8, 7); + } + return bars; + } + + public static String CalculateChecksum(String code) { + if (code.Length < 2) + return code; + String text = code.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + int sum = 0; + int len = text.Length; + for (int k = 0; k < len; ++k) + sum += CHARS.IndexOf(text[k]); + sum = (sum + 15) / 16 * 16 - sum; + return code.Substring(0, len - 1) + CHARS[sum] + code.Substring(len - 1); + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + String text = code; + if (generateChecksum && checksumText) + text = CalculateChecksum(code); + if (!startStopText) + text = text.Substring(1, text.Length - 2); + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + fontX = font.GetWidthPoint(altText != null ? altText : text, size); + } + text = code; + if (generateChecksum) + text = CalculateChecksum(code); + byte[] bars = GetBarsCodabar(text); + int wide = 0; + for (int k = 0; k < bars.Length; ++k) { + wide += (int)bars[k]; + } + int narrow = bars.Length - wide; + float fullWidth = x * (narrow + wide * n); + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + String fullCode = code; + if (generateChecksum && checksumText) + fullCode = CalculateChecksum(code); + if (!startStopText) + fullCode = fullCode.Substring(1, fullCode.Length - 2); + float fontX = 0; + if (font != null) { + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + byte[] bars = GetBarsCodabar(generateChecksum ? CalculateChecksum(code) : code); + int wide = 0; + for (int k = 0; k < bars.Length; ++k) { + wide += (int)bars[k]; + } + int narrow = bars.Length - wide; + float fullWidth = x * (narrow + wide * n); + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = (bars[k] == 0 ? x : x * n); + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String fullCode = code; + if (generateChecksum && checksumText) + fullCode = CalculateChecksum(code); + if (!startStopText) + fullCode = fullCode.Substring(1, fullCode.Length - 2); + byte[] bars = GetBarsCodabar(generateChecksum ? CalculateChecksum(code) : code); + int wide = 0; + for (int k = 0; k < bars.Length; ++k) { + wide += (int)bars[k]; + } + int narrow = bars.Length - wide; + int fullWidth = narrow + wide * (int)n; + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = (bars[k] == 0 ? 1 : (int)n); + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs new file mode 100644 index 0000000..48e5e1d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs @@ -0,0 +1,1265 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf.codec; +using System.Collections; +/* + * $Id: BarcodeDatamatrix.cs,v 1.3 2007/05/21 10:56:38 psoares33 Exp $ + * + * Copyright 2007 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class BarcodeDatamatrix { + /** + * No error. + */ + public const int DM_NO_ERROR = 0; + /** + * The text is too big for the symbology capabilities. + */ + public const int DM_ERROR_TEXT_TOO_BIG = 1; + /** + * The dimensions given for the symbol are illegal. + */ + public const int DM_ERROR_INVALID_SQUARE = 3; + /** + * An error while parsing an extension. + */ + public const int DM_ERROR_EXTENSION = 5; + + /** + * The best encodation will be used. + */ + public const int DM_AUTO = 0; + /** + * ASCII encodation. + */ + public const int DM_ASCII = 1; + /** + * C40 encodation. + */ + public const int DM_C40 = 2; + /** + * TEXT encodation. + */ + public const int DM_TEXT = 3; + /** + * Binary encodation. + */ + public const int DM_B256 = 4; + /** + * X21 encodation. + */ + public const int DM_X21 = 5; + /** + * EDIFACT encodation. + */ + public const int DM_EDIFACT = 6; + /** + * No encodation needed. The bytes provided are already encoded. + */ + public const int DM_RAW = 7; + + /** + * Allows extensions to be embedded at the start of the text. + */ + public const int DM_EXTENSION = 32; + /** + * Doesn't generate the image but returns all the other information. + */ + public const int DM_TEST = 64; + + private static readonly DmParams[] dmSizes = { + new DmParams(10, 10, 10, 10, 3, 3, 5), + new DmParams(12, 12, 12, 12, 5, 5, 7), + new DmParams(8, 18, 8, 18, 5, 5, 7), + new DmParams(14, 14, 14, 14, 8, 8, 10), + new DmParams(8, 32, 8, 16, 10, 10, 11), + new DmParams(16, 16, 16, 16, 12, 12, 12), + new DmParams(12, 26, 12, 26, 16, 16, 14), + new DmParams(18, 18, 18, 18, 18, 18, 14), + new DmParams(20, 20, 20, 20, 22, 22, 18), + new DmParams(12, 36, 12, 18, 22, 22, 18), + new DmParams(22, 22, 22, 22, 30, 30, 20), + new DmParams(16, 36, 16, 18, 32, 32, 24), + new DmParams(24, 24, 24, 24, 36, 36, 24), + new DmParams(26, 26, 26, 26, 44, 44, 28), + new DmParams(16, 48, 16, 24, 49, 49, 28), + new DmParams(32, 32, 16, 16, 62, 62, 36), + new DmParams(36, 36, 18, 18, 86, 86, 42), + new DmParams(40, 40, 20, 20, 114, 114, 48), + new DmParams(44, 44, 22, 22, 144, 144, 56), + new DmParams(48, 48, 24, 24, 174, 174, 68), + new DmParams(52, 52, 26, 26, 204, 102, 42), + new DmParams(64, 64, 16, 16, 280, 140, 56), + new DmParams(72, 72, 18, 18, 368, 92, 36), + new DmParams(80, 80, 20, 20, 456, 114, 48), + new DmParams(88, 88, 22, 22, 576, 144, 56), + new DmParams(96, 96, 24, 24, 696, 174, 68), + new DmParams(104, 104, 26, 26, 816, 136, 56), + new DmParams(120, 120, 20, 20, 1050, 175, 68), + new DmParams(132, 132, 22, 22, 1304, 163, 62), + new DmParams(144, 144, 24, 24, 1558, 156, 62)}; + + private const String x12 = "\r*> 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private int extOut; + private short[] place; + private byte[] image; + private int height; + private int width; + private int ws; + private int options; + + /** + * Creates an instance of this class. + */ + public BarcodeDatamatrix() { + } + + private void SetBit(int x, int y, int xByte) { + image[y * xByte + x / 8] |= (byte)(128 >> (x & 7)); + } + + private void Draw(byte[] data, int dataSize, DmParams dm) { + int i, j, p, x, y, xs, ys, z; + int xByte = (dm.width + ws * 2 + 7) / 8; + for (int k = 0; k < image.Length; ++k) + image[k] = 0; + //alignment patterns + //dotted horizontal line + for (i = ws; i < dm.height + ws; i += dm.heightSection) { + for (j = ws; j < dm.width + ws; j += 2) { + SetBit(j, i, xByte); + } + } + //solid horizontal line + for (i = dm.heightSection - 1 + ws; i < dm.height + ws; i += dm.heightSection) { + for (j = ws; j < dm.width + ws; ++j) { + SetBit(j, i, xByte); + } + } + //solid vertical line + for (i = ws; i < dm.width + ws; i += dm.widthSection) { + for (j = ws; j < dm.height + ws; ++j) { + SetBit(i, j, xByte); + } + } + //dotted vertical line + for (i = dm.widthSection - 1 + ws; i < dm.width + ws; i += dm.widthSection) { + for (j = 1 + ws; j < dm.height + ws; j += 2) { + SetBit(i, j, xByte); + } + } + p = 0; + for (ys = 0; ys < dm.height; ys += dm.heightSection) { + for (y = 1; y < dm.heightSection - 1; ++y) { + for (xs = 0; xs < dm.width; xs += dm.widthSection) { + for (x = 1; x < dm.widthSection - 1; ++x) { + z = place[p++]; + if (z == 1 || (z > 1 && ((data[z/8-1] & 0xff) & (128 >> (z%8))) != 0)) + SetBit(x + xs + ws, y + ys + ws, xByte); + } + } + } + } + } + + private static void MakePadding(byte[] data, int position, int count) { + //already in ascii mode + if (count <= 0) + return; + data[position++] = (byte)129; + while (--count > 0) { + int t = 129 + (((position + 1) * 149) % 253) + 1; + if (t > 254) + t -= 254; + data[position++] = (byte)t; + } + } + + private static bool IsDigit(int c) { + return c >= '0' && c <= '9'; + } + + private static int AsciiEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int ptrIn, ptrOut, c; + ptrIn = textOffset; + ptrOut = dataOffset; + textLength += textOffset; + dataLength += dataOffset; + while (ptrIn < textLength) { + if (ptrOut >= dataLength) + return -1; + c = text[ptrIn++] & 0xff; + if (IsDigit(c) && ptrIn < textLength && IsDigit(text[ptrIn] & 0xff)) { + data[ptrOut++] = (byte)((c - '0') * 10 + (text[ptrIn++] & 0xff) - '0' + 130); + } + else if (c > 127) { + if (ptrOut + 1 >= dataLength) + return -1; + data[ptrOut++] = (byte)235; + data[ptrOut++] = (byte)(c - 128 + 1); + } + else { + data[ptrOut++] = (byte)(c + 1); + } + } + return ptrOut - dataOffset; + } + + private static int B256Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int k, j, prn, tv, c; + if (textLength == 0) + return 0; + if (textLength < 250 && textLength + 2 > dataLength) + return -1; + if (textLength >= 250 && textLength + 3 > dataLength) + return -1; + data[dataOffset] = (byte)231; + if (textLength < 250) { + data[dataOffset + 1] = (byte)textLength; + k = 2; + } + else { + data[dataOffset + 1] = (byte)(textLength / 250 + 249); + data[dataOffset + 2] = (byte)(textLength % 250); + k = 3; + } + System.Array.Copy(text, textOffset, data, k + dataOffset, textLength); + k += textLength + dataOffset; + for (j = dataOffset + 1; j < k; ++j) { + c = data[j] & 0xff; + prn = ((149 * (j + 1)) % 255) + 1; + tv = c + prn; + if (tv > 255) + tv -= 256; + data[j] = (byte)tv; + + } + return k - dataOffset; + } + + private static int X12Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int ptrIn, ptrOut, count, k, n, ci; + byte c; + if (textLength == 0) + return 0; + ptrIn = 0; + ptrOut = 0; + byte[] x = new byte[textLength]; + count = 0; + for (; ptrIn < textLength; ++ptrIn) { + int i = x12.IndexOf((char)text[ptrIn + textOffset]); + if (i >= 0) { + x[ptrIn] = (byte)i; + ++count; + } + else { + x[ptrIn] = 100; + if (count >= 6) + count -= (count / 3) * 3; + for (k = 0; k < count; ++k) + x[ptrIn - k - 1] = 100; + count = 0; + } + } + if (count >= 6) + count -= (count / 3) * 3; + for (k = 0; k < count; ++k) + x[ptrIn - k - 1] = 100; + ptrIn = 0; + c = 0; + for (; ptrIn < textLength; ++ptrIn) { + c = x[ptrIn]; + if (ptrOut >= dataLength) + break; + if (c < 40) { + if (ptrIn == 0 || (ptrIn > 0 && x[ptrIn - 1] > 40)) + data[dataOffset + ptrOut++] = (byte)238; + if (ptrOut + 2 > dataLength) + break; + n = 1600 * x[ptrIn] + 40 * x[ptrIn + 1] + x[ptrIn + 2] + 1; + data[dataOffset + ptrOut++] = (byte)(n / 256); + data[dataOffset + ptrOut++] = (byte)n; + ptrIn += 2; + } + else { + if (ptrIn > 0 && x[ptrIn - 1] < 40) + data[dataOffset + ptrOut++] = (byte)254; + ci = text[ptrIn + textOffset] & 0xff; + if (ci > 127) { + data[dataOffset + ptrOut++] = (byte)235; + ci -= 128; + } + if (ptrOut >= dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(ci + 1); + } + } + c = 100; + if (textLength > 0) + c = x[textLength - 1]; + if (ptrIn != textLength || (c < 40 && ptrOut >= dataLength)) + return -1; + if (c < 40) + data[dataOffset + ptrOut++] = (byte)(254); + return ptrOut; + } + + private static int EdifactEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int ptrIn, ptrOut, edi, pedi, c; + if (textLength == 0) + return 0; + ptrIn = 0; + ptrOut = 0; + edi = 0; + pedi = 18; + bool ascii = true; + for (; ptrIn < textLength; ++ptrIn) { + c = text[ptrIn + textOffset] & 0xff; + if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_') { + if (ascii) { + if (ptrOut + 1 > dataLength) + break; + data[dataOffset + ptrOut++] = (byte)240; + ascii = false; + } + c &= 0x3f; + edi |= c << pedi; + if (pedi == 0) { + if (ptrOut + 3 > dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(edi >> 16); + data[dataOffset + ptrOut++] = (byte)(edi >> 8); + data[dataOffset + ptrOut++] = (byte)edi; + edi = 0; + pedi = 18; + } + else + pedi -= 6; + } + else { + if (!ascii) { + edi |= ('_' & 0x3f) << pedi; + if (ptrOut + (3 - pedi / 8) > dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(edi >> 16); + if (pedi <= 12) + data[dataOffset + ptrOut++] = (byte)(edi >> 8); + if (pedi <= 6) + data[dataOffset + ptrOut++] = (byte)edi; + ascii = true; + pedi = 18; + edi = 0; + } + if (c > 127) { + if (ptrOut >= dataLength) + break; + data[dataOffset + ptrOut++] = (byte)235; + c -= 128; + } + if (ptrOut >= dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(c + 1); + } + } + if (ptrIn != textLength) + return -1; + if (!ascii) { + edi |= ('_' & 0x3f) << pedi; + if (ptrOut + (3 - pedi / 8) > dataLength) + return -1; + data[dataOffset + ptrOut++] = (byte)(edi >> 16); + if (pedi <= 12) + data[dataOffset + ptrOut++] = (byte)(edi >> 8); + if (pedi <= 6) + data[dataOffset + ptrOut++] = (byte)edi; + } + return ptrOut; + } + + private static int C40OrTextEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, bool c40) { + int ptrIn, ptrOut, encPtr, last0, last1, i, a, c; + String basic, shift2, shift3; + if (textLength == 0) + return 0; + ptrIn = 0; + ptrOut = 0; + if (c40) + data[dataOffset + ptrOut++] = (byte)230; + else + data[dataOffset + ptrOut++] = (byte)239; + shift2 = "!\"#$%&'()*+,-./:;<=>?@[\\]^_"; + if (c40) { + basic = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + shift3 = "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"; + } + else { + basic = " 0123456789abcdefghijklmnopqrstuvwxyz"; + shift3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\u007f"; + } + int[] enc = new int[textLength * 4 + 10]; + encPtr = 0; + last0 = 0; + last1 = 0; + while (ptrIn < textLength) { + if ((encPtr % 3) == 0) { + last0 = ptrIn; + last1 = encPtr; + } + c = text[textOffset + ptrIn++] & 0xff; + if (c > 127) { + c -= 128; + enc[encPtr++] = 1; + enc[encPtr++] = 30; + } + int idx = basic.IndexOf((char)c); + if (idx >= 0) { + enc[encPtr++] = idx + 3; + } + else if (c < 32) { + enc[encPtr++] = 0; + enc[encPtr++] = c; + } + else if ((idx = shift2.IndexOf((char)c)) >= 0) { + enc[encPtr++] = 1; + enc[encPtr++] = idx; + } + else if ((idx = shift3.IndexOf((char)c)) >= 0) { + enc[encPtr++] = 2; + enc[encPtr++] = idx; + } + } + if ((encPtr % 3) != 0) { + ptrIn = last0; + encPtr = last1; + } + if (encPtr / 3 * 2 > dataLength - 2) { + return -1; + } + i = 0; + for (; i < encPtr; i += 3) { + a = 1600 * enc[i] + 40 * enc[i + 1] + enc[i + 2] + 1; + data[dataOffset + ptrOut++] = (byte)(a / 256); + data[dataOffset + ptrOut++] = (byte)a; + } + data[ptrOut++] = (byte)254; + i = AsciiEncodation(text, ptrIn, textLength - ptrIn, data, ptrOut, dataLength - ptrOut); + if (i < 0) + return i; + return ptrOut + i; + } + + private static int GetEncodation(byte[] text, int textOffset, int textSize, byte[] data, int dataOffset, int dataSize, int options, bool firstMatch) { + int e, j, k; + int[] e1 = new int[6]; + if (dataSize < 0) + return -1; + e = -1; + options &= 7; + if (options == 0) { + e1[0] = AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[0] >= 0) + return e1[0]; + e1[1] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); + if (firstMatch && e1[1] >= 0) + return e1[1]; + e1[2] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); + if (firstMatch && e1[2] >= 0) + return e1[2]; + e1[3] = B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[3] >= 0) + return e1[3]; + e1[4] = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[4] >= 0) + return e1[4]; + e1[5] = EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[5] >= 0) + return e1[5]; + if (e1[0] < 0 && e1[1] < 0 && e1[2] < 0 && e1[3] < 0 && e1[4] < 0 && e1[5] < 0) { + return -1; + } + j = 0; + e = 99999; + for (k = 0; k < 6; ++k) { + if (e1[k] >= 0 && e1[k] < e) { + e = e1[k]; + j = k; + } + } + if (j == 0) + e = AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + else if (j == 1) + e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); + else if (j == 2) + e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); + else if (j == 3) + e = B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + else if (j == 4) + e = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + return e; + } + switch (options) { + case DM_ASCII: + return AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_C40: + return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); + case DM_TEXT: + return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); + case DM_B256: + return B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_X21: + return X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_EDIFACT: + return EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_RAW: + if (textSize > dataSize) + return -1; + System.Array.Copy(text, textOffset, data, dataOffset, textSize); + return textSize; + } + return -1; + } + + private static int GetNumber(byte[] text, int ptrIn, int n) { + int v, j, c; + v = 0; + for (j = 0; j < n; ++j) { + c = text[ptrIn++] &0xff; + if (c < '0' || c > '9') + return -1; + v = v * 10 + c - '0'; + } + return v; + } + + private int ProcessExtensions(byte[] text, int textOffset, int textSize, byte[] data) { + int order, ptrIn, ptrOut, eci, fn, ft, fi, c; + if ((options & DM_EXTENSION) == 0) + return 0; + order = 0; + ptrIn = 0; + ptrOut = 0; + while (ptrIn < textSize) { + if (order > 20) + return -1; + c = text[textOffset + ptrIn++] &0xff; + ++order; + switch (c) { + case '.': + extOut = ptrIn; + return ptrOut; + case 'e': + if (ptrIn + 6 > textSize) + return -1; + eci = GetNumber(text, textOffset + ptrIn, 6); + if (eci < 0) + return -1; + ptrIn += 6; + data[ptrOut++] = (byte)241; + if (eci < 127) + data[ptrOut++] = (byte)(eci + 1); + else if (eci < 16383) { + data[ptrOut++] = (byte)((eci - 127) / 254 + 128); + data[ptrOut++] = (byte)(((eci - 127) % 254) + 1); + } + else { + data[ptrOut++] = (byte)((eci - 16383) / 64516 + 192); + data[ptrOut++] = (byte)((((eci - 16383) / 254) % 254) + 1); + data[ptrOut++] = (byte)(((eci - 16383) % 254) + 1); + } + break; + case 's': + if (order != 1) + return -1; + if (ptrIn + 9 > textSize) + return -1; + fn = GetNumber(text, textOffset + ptrIn, 2); + if (fn <= 0 || fn > 16) + return -1; + ptrIn += 2; + ft = GetNumber(text, textOffset + ptrIn, 2); + if (ft <= 1 || ft > 16) + return -1; + ptrIn += 2; + fi = GetNumber(text, textOffset + ptrIn, 5); + if (fi < 0 || fn >= 64516) + return -1; + ptrIn += 5; + data[ptrOut++] = (byte)(233); + data[ptrOut++] = (byte)(((fn - 1) << 4) | (17 - ft)); + data[ptrOut++] = (byte)(fi / 254 + 1); + data[ptrOut++] = (byte)((fi % 254) + 1); + break; + case 'p': + if (order != 1) + return -1; + data[ptrOut++] = (byte)(234); + break; + case 'm': + if (order != 1) + return -1; + if (ptrIn + 1 > textSize) + return -1; + c = text[textOffset + ptrIn++] &0xff; + if (c != '5' && c != '5') + return -1; + data[ptrOut++] = (byte)(234); + data[ptrOut++] = (byte)(c == '5' ? 236 : 237); + break; + case 'f': + if (order != 1 && (order != 2 || (text[textOffset] != 's' && text[textOffset] != 'm'))) + return -1; + data[ptrOut++] = (byte)(232); + break; + } + } + return -1; + } + + /** + * Creates a barcode. The String is interpreted with the ISO-8859-1 encoding + * @param text the text + * @return the status of the generation. It can be one of this values: + *

+ * DM_NO_ERROR - no error.
+ * DM_ERROR_TEXT_TOO_BIG - the text is too big for the symbology capabilities.
+ * DM_ERROR_INVALID_SQUARE - the dimensions given for the symbol are illegal.
+ * DM_ERROR_EXTENSION - an error was while parsing an extension. + * @throws java.io.UnsupportedEncodingException on error + */ + public int Generate(String text) { + byte[] t = System.Text.Encoding.GetEncoding(1252).GetBytes(text); + return Generate(t, 0, t.Length); + } + + /** + * Creates a barcode. + * @param text the text + * @param textOffset the offset to the start of the text + * @param textSize the text size + * @return the status of the generation. It can be one of this values: + *

+ * DM_NO_ERROR - no error.
+ * DM_ERROR_TEXT_TOO_BIG - the text is too big for the symbology capabilities.
+ * DM_ERROR_INVALID_SQUARE - the dimensions given for the symbol are illegal.
+ * DM_ERROR_EXTENSION - an error was while parsing an extension. + */ + public int Generate(byte[] text, int textOffset, int textSize) { + int extCount, e, k, full; + DmParams dm, last; + byte[] data = new byte[2500]; + extOut = 0; + extCount = ProcessExtensions(text, textOffset, textSize, data); + if (extCount < 0) { + return DM_ERROR_EXTENSION; + } + e = -1; + if (height == 0 || width == 0) { + last = dmSizes[dmSizes.Length - 1]; + e = GetEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, last.dataSize - extCount, options, false); + if (e < 0) { + return DM_ERROR_TEXT_TOO_BIG; + } + e += extCount; + for (k = 0; k < dmSizes.Length; ++k) { + if (dmSizes[k].dataSize >= e) + break; + } + dm = dmSizes[k]; + height = dm.height; + width = dm.width; + } + else { + for (k = 0; k < dmSizes.Length; ++k) { + if (height == dmSizes[k].height && width == dmSizes[k].width) + break; + } + if (k == dmSizes.Length) { + return DM_ERROR_INVALID_SQUARE; + } + dm = dmSizes[k]; + e = GetEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, dm.dataSize - extCount, options, true); + if (e < 0) { + return DM_ERROR_TEXT_TOO_BIG; + } + e += extCount; + } + if ((options & DM_TEST) != 0) { + return DM_NO_ERROR; + } + image = new byte[(((dm.width + 2 * ws) + 7) / 8) * (dm.height + 2 * ws)]; + MakePadding(data, e, dm.dataSize - e); + place = Placement.DoPlacement(dm.height - (dm.height / dm.heightSection * 2), dm.width - (dm.width / dm.widthSection * 2)); + full = dm.dataSize + ((dm.dataSize + 2) / dm.dataBlock) * dm.errorBlock; + ReedSolomon.GenerateECC(data, dm.dataSize, dm.dataBlock, dm.errorBlock); + Draw(data, full, dm); + return DM_NO_ERROR; + } + + /** Gets an Image with the barcode. A successful call to the method generate() + * before calling this method is required. + * @return the barcode Image + * @throws BadElementException on error + */ + public Image CreateImage() { + if (image == null) + return null; + byte[] g4 = CCITTG4Encoder.Compress(image, width + 2 * ws, height + 2 * ws); + return Image.GetInstance(width + 2 * ws, height + 2 * ws, false, Image.CCITTG4, 0, g4, null); + } + + /** + * Creates a java.awt.Image. A successful call to the method generate() + * before calling this method is required. + * @param foreground the color of the bars + * @param background the color of the background + * @return the image + */ + public virtual System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + if (image == null) + return null; + int h = height + 2 * ws; + int w = width + 2 * ws; + int stride = (w + 7) / 8; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(w, h); + for (int k = 0; k < h; ++k) { + int p = k * stride; + for (int j = 0; j < w; ++j) { + int b = image[p + (j / 8)] & 0xff; + b <<= j % 8; + bmp.SetPixel(j, k, (b & 0x80) == 0 ? background : foreground); + } + } + return bmp; + } + + private class DmParams { + internal DmParams(int height, int width, int heightSection, int widthSection, int dataSize, int dataBlock, int errorBlock) { + this.height = height; + this.width = width; + this.heightSection = heightSection; + this.widthSection = widthSection; + this.dataSize = dataSize; + this.dataBlock = dataBlock; + this.errorBlock = errorBlock; + } + + internal int height; + internal int width; + internal int heightSection; + internal int widthSection; + internal int dataSize; + internal int dataBlock; + internal int errorBlock; + }; + + /** + * Gets the generated image. The image is represented as a stream of bytes, each byte representing + * 8 pixels, 0 for white and 1 for black, with the high-order bit of each byte first. Each row + * is aligned at byte boundaries. The dimensions of the image are defined by height and width + * plus 2 * ws. + * @return the generated image + */ + public byte[] BitImage { + get { + return image; + } + } + + /** + * Gets/sets the height of the barcode. If the height is zero it will be calculated. This height doesn't include the whitespace border, if any. + *

+ * The allowed dimensions are (height, width):

+ * 10, 10
+ * 12, 12
+ * 8, 18
+ * 14, 14
+ * 8, 32
+ * 16, 16
+ * 12, 26
+ * 18, 18
+ * 20, 20
+ * 12, 36
+ * 22, 22
+ * 16, 36
+ * 24, 24
+ * 26, 26
+ * 16, 48
+ * 32, 32
+ * 36, 36
+ * 40, 40
+ * 44, 44
+ * 48, 48
+ * 52, 52
+ * 64, 64
+ * 72, 72
+ * 80, 80
+ * 88, 88
+ * 96, 96
+ * 104, 104
+ * 120, 120
+ * 132, 132
+ * 144, 144
+ * @param height the height of the barcode + */ + public int Height { + get { + return height; + } + set { + height = value; + } + } + + /** + * Gets/sets the width of the barcode. If the width is zero it will be calculated. This width doesn't include the whitespace border, if any. + *

+ * The allowed dimensions are (height, width):

+ * 10, 10
+ * 12, 12
+ * 8, 18
+ * 14, 14
+ * 8, 32
+ * 16, 16
+ * 12, 26
+ * 18, 18
+ * 20, 20
+ * 12, 36
+ * 22, 22
+ * 16, 36
+ * 24, 24
+ * 26, 26
+ * 16, 48
+ * 32, 32
+ * 36, 36
+ * 40, 40
+ * 44, 44
+ * 48, 48
+ * 52, 52
+ * 64, 64
+ * 72, 72
+ * 80, 80
+ * 88, 88
+ * 96, 96
+ * 104, 104
+ * 120, 120
+ * 132, 132
+ * 144, 144
+ * @param width the width of the barcode + */ + public int Width { + get { + return width; + } + set { + width = value; + } + } + + /** + * Gets/sets the whitespace border around the barcode. + * @param ws the whitespace border around the barcode + */ + public int Ws { + get { + return ws; + } + set { + ws = value; + } + } + + /** + * Gets/sets the options for the barcode generation. The options can be:

+ * One of:
+ * DM_AUTO - the best encodation will be used
+ * DM_ASCII - ASCII encodation
+ * DM_C40 - C40 encodation
+ * DM_TEXT - TEXT encodation
+ * DM_B256 - binary encodation
+ * DM_X21 - X21 encodation
+ * DM_EDIFACT - EDIFACT encodation
+ * DM_RAW - no encodation. The bytes provided are already encoded and will be added directly to the barcode, using padding if needed. It assumes that the encodation state is left at ASCII after the last byte.
+ *

+ * One of:
+ * DM_EXTENSION - allows extensions to be embedded at the start of the text:

+ * exxxxxx - ECI number xxxxxx
+ * m5 - macro 5
+ * m6 - macro 6
+ * f - FNC1
+ * saabbccccc - Structured Append, aa symbol position (1-16), bb total number of symbols (2-16), ccccc file identification (0-64515)
+ * p - Reader programming
+ * . - extension terminator

+ * Example for a structured append, symbol 2 of 6, with FNC1 and ECI 000005. The actual text is "Hello".

+ * s020600075fe000005.Hello

+ * One of:
+ * DM_TEST - doesn't generate the image but returns all the other information. + * @param options the barcode options + */ + public int Options { + get { + return options; + } + set { + options = value; + } + } + + internal class Placement { + private int nrow; + private int ncol; + private short[] array; + private static Hashtable cache = Hashtable.Synchronized(new Hashtable()); + + private Placement() { + } + + internal static short[] DoPlacement(int nrow, int ncol) { + int key = nrow * 1000 + ncol; + short[] pc = (short[])cache[key]; + if (pc != null) + return pc; + Placement p = new Placement(); + p.nrow = nrow; + p.ncol = ncol; + p.array = new short[nrow * ncol]; + p.Ecc200(); + cache[key] = p.array; + return p.array; + } + + /* "module" places "chr+bit" with appropriate wrapping within array[] */ + private void Module(int row, int col, int chr, int bit) { + if (row < 0) { row += nrow; col += 4 - ((nrow+4)%8); } + if (col < 0) { col += ncol; row += 4 - ((ncol+4)%8); } + array[row*ncol+col] = (short)(8*chr + bit); + } + /* "utah" places the 8 bits of a utah-shaped symbol character in ECC200 */ + private void Utah(int row, int col, int chr) { + Module(row-2,col-2,chr,0); + Module(row-2,col-1,chr,1); + Module(row-1,col-2,chr,2); + Module(row-1,col-1,chr,3); + Module(row-1,col,chr,4); + Module(row,col-2,chr,5); + Module(row,col-1,chr,6); + Module(row,col,chr,7); + } + /* "cornerN" places 8 bits of the four special corner cases in ECC200 */ + private void Corner1(int chr) { + Module(nrow-1,0,chr,0); + Module(nrow-1,1,chr,1); + Module(nrow-1,2,chr,2); + Module(0,ncol-2,chr,3); + Module(0,ncol-1,chr,4); + Module(1,ncol-1,chr,5); + Module(2,ncol-1,chr,6); + Module(3,ncol-1,chr,7); + } + private void Corner2(int chr){ + Module(nrow-3,0,chr,0); + Module(nrow-2,0,chr,1); + Module(nrow-1,0,chr,2); + Module(0,ncol-4,chr,3); + Module(0,ncol-3,chr,4); + Module(0,ncol-2,chr,5); + Module(0,ncol-1,chr,6); + Module(1,ncol-1,chr,7); + } + private void Corner3(int chr){ + Module(nrow-3,0,chr,0); + Module(nrow-2,0,chr,1); + Module(nrow-1,0,chr,2); + Module(0,ncol-2,chr,3); + Module(0,ncol-1,chr,4); + Module(1,ncol-1,chr,5); + Module(2,ncol-1,chr,6); + Module(3,ncol-1,chr,7); + } + private void Corner4(int chr){ + Module(nrow-1,0,chr,0); + Module(nrow-1,ncol-1,chr,1); + Module(0,ncol-3,chr,2); + Module(0,ncol-2,chr,3); + Module(0,ncol-1,chr,4); + Module(1,ncol-3,chr,5); + Module(1,ncol-2,chr,6); + Module(1,ncol-1,chr,7); + } + /* "ECC200" fills an nrow x ncol array with appropriate values for ECC200 */ + private void Ecc200(){ + int row, col, chr; + /* First, fill the array[] with invalid entries */ + for (int k = 0; k < array.Length; ++k) + array[k] = (short)0; + /* Starting in the correct location for character #1, bit 8,... */ + chr = 1; row = 4; col = 0; + do { + /* repeatedly first check for one of the special corner cases, then... */ + if ((row == nrow) && (col == 0)) Corner1(chr++); + if ((row == nrow-2) && (col == 0) && (ncol%4 != 0)) Corner2(chr++); + if ((row == nrow-2) && (col == 0) && (ncol%8 == 4)) Corner3(chr++); + if ((row == nrow+4) && (col == 2) && (ncol%8 == 0)) Corner4(chr++); + /* sweep upward diagonally, inserting successive characters,... */ + do { + if ((row < nrow) && (col >= 0) && array[row*ncol+col] == 0) + Utah(row,col,chr++); + row -= 2; col += 2; + } while ((row >= 0) && (col < ncol)); + row += 1; col += 3; + /* & then sweep downward diagonally, inserting successive characters,... */ + + do { + if ((row >= 0) && (col < ncol) && array[row*ncol+col] == 0) + Utah(row,col,chr++); + row += 2; col -= 2; + } while ((row < nrow) && (col >= 0)); + row += 3; col += 1; + /* ... until the entire array is scanned */ + } while ((row < nrow) || (col < ncol)); + /* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */ + if (array[nrow*ncol-1] == 0) { + array[nrow*ncol-1] = array[nrow*ncol-ncol-2] = 1; + } + } + } + + internal class ReedSolomon { + + private static readonly int[] log = { + 0, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210, + 4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234, + 5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162, + 244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91, + 6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193, + 229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, + 245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, + 57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176, + 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179, + 42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113, + 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66, + 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170, + 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251, + 47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131, + 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70, + 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150 + }; + + private static readonly int[] alog = { + 1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228, + 229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184, + 93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208, + 141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123, + 246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82, + 164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135, + 35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, + 217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172, + 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200, + 189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, + 214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169, + 127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206, + 177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111, + 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74, + 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151, + 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1 + }; + + private static readonly int[] poly5 = { + 228, 48, 15, 111, 62 + }; + + private static readonly int[] poly7 = { + 23, 68, 144, 134, 240, 92, 254 + }; + + private static readonly int[] poly10 = { + 28, 24, 185, 166, 223, 248, 116, 255, 110, 61 + }; + + private static readonly int[] poly11 = { + 175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120 + }; + + private static readonly int[] poly12 = { + 41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242 + }; + + private static readonly int[] poly14 = { + 156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185 + }; + + private static readonly int[] poly18 = { + 83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, + 90, 188 + }; + + private static readonly int[] poly20 = { + 15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, + 27, 174, 186, 172 + }; + + private static readonly int[] poly24 = { + 52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, + 254, 124, 12, 181, 184, 96, 50, 193 + }; + + private static readonly int[] poly28 = { + 211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, + 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255 + }; + + private static readonly int[] poly36 = { + 245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182, + 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, + 225, 98, 81, 112 + }; + + private static readonly int[] poly42 = { + 77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, + 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, + 248, 202, 69, 50, 150, 177, 226, 5, 9, 5 + }; + + private static readonly int[] poly48 = { + 245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, + 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, + 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19 + }; + + private static readonly int[] poly56 = { + 175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, + 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, + 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, + 155, 43, 203, 107, 233, 53, 143, 46 + }; + + private static readonly int[] poly62 = { + 242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, + 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, + 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, + 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204 + }; + + private static readonly int[] poly68 = { + 220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, + 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, + 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, + 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, + 96, 103, 82, 186 + }; + + private static int[] GetPoly(int nc) { + switch (nc) { + case 5: + return poly5; + case 7: + return poly7; + case 10: + return poly10; + case 11: + return poly11; + case 12: + return poly12; + case 14: + return poly14; + case 18: + return poly18; + case 20: + return poly20; + case 24: + return poly24; + case 28: + return poly28; + case 36: + return poly36; + case 42: + return poly42; + case 48: + return poly48; + case 56: + return poly56; + case 62: + return poly62; + case 68: + return poly68; + } + return null; + } + + private static void ReedSolomonBlock(byte[] wd, int nd, byte[] ncout, int nc, int[] c) { + int i, j, k; + + for (i=0; i<=nc; i++) ncout[i] = 0; + for (i=0; i + *x = 0.8f; + *font = BaseFont.CreateFont("Helvetica", "winansi", false); + *size = 8; + *baseline = size; + *barHeight = size * 3; + *guardBars = true; + *codeType = EAN13; + *code = ""; + * + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeEAN : Barcode { + + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_EMPTY = {}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_UPCA = {0, 2, 4, 6, 28, 30, 52, 54, 56, 58}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_EAN13 = {0, 2, 28, 30, 56, 58}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_EAN8 = {0, 2, 20, 22, 40, 42}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_UPCE = {0, 2, 28, 30, 32}; + /** The x coordinates to place the text.*/ + private static readonly float[] TEXTPOS_EAN13 = {6.5f, 13.5f, 20.5f, 27.5f, 34.5f, 41.5f, 53.5f, 60.5f, 67.5f, 74.5f, 81.5f, 88.5f}; + /** The x coordinates to place the text.*/ + private static readonly float[] TEXTPOS_EAN8 = {6.5f, 13.5f, 20.5f, 27.5f, 39.5f, 46.5f, 53.5f, 60.5f}; + /** The basic bar widths.*/ + private static readonly byte[][] BARS = + { + new byte[] {3, 2, 1, 1}, // 0 + new byte[] {2, 2, 2, 1}, // 1 + new byte[] {2, 1, 2, 2}, // 2 + new byte[] {1, 4, 1, 1}, // 3 + new byte[] {1, 1, 3, 2}, // 4 + new byte[] {1, 2, 3, 1}, // 5 + new byte[] {1, 1, 1, 4}, // 6 + new byte[] {1, 3, 1, 2}, // 7 + new byte[] {1, 2, 1, 3}, // 8 + new byte[] {3, 1, 1, 2} // 9 + }; + + /** The total number of bars for EAN13.*/ + private const int TOTALBARS_EAN13 = 11 + 12 * 4; + /** The total number of bars for EAN8.*/ + private const int TOTALBARS_EAN8 = 11 + 8 * 4; + /** The total number of bars for UPCE.*/ + private const int TOTALBARS_UPCE = 9 + 6 * 4; + /** The total number of bars for supplemental 2.*/ + private const int TOTALBARS_SUPP2 = 13; + /** The total number of bars for supplemental 5.*/ + private const int TOTALBARS_SUPP5 = 31; + /** Marker for odd parity.*/ + private const byte ODD = 0; + /** Marker for even parity.*/ + private const byte EVEN = 1; + + /** Sequence of parities to be used with EAN13.*/ + private static readonly byte[][] PARITY13 = + { + new byte[] {ODD, ODD, ODD, ODD, ODD, ODD}, // 0 + new byte[] {ODD, ODD, EVEN, ODD, EVEN, EVEN}, // 1 + new byte[] {ODD, ODD, EVEN, EVEN, ODD, EVEN}, // 2 + new byte[] {ODD, ODD, EVEN, EVEN, EVEN, ODD}, // 3 + new byte[] {ODD, EVEN, ODD, ODD, EVEN, EVEN}, // 4 + new byte[] {ODD, EVEN, EVEN, ODD, ODD, EVEN}, // 5 + new byte[] {ODD, EVEN, EVEN, EVEN, ODD, ODD}, // 6 + new byte[] {ODD, EVEN, ODD, EVEN, ODD, EVEN}, // 7 + new byte[] {ODD, EVEN, ODD, EVEN, EVEN, ODD}, // 8 + new byte[] {ODD, EVEN, EVEN, ODD, EVEN, ODD} // 9 + }; + + /** Sequence of parities to be used with supplemental 2.*/ + private static readonly byte[][] PARITY2 = + { + new byte[] {ODD, ODD}, // 0 + new byte[] {ODD, EVEN}, // 1 + new byte[] {EVEN, ODD}, // 2 + new byte[] {EVEN, EVEN} // 3 + }; + + /** Sequence of parities to be used with supplemental 2.*/ + private static readonly byte[][] PARITY5 = + { + new byte[] {EVEN, EVEN, ODD, ODD, ODD}, // 0 + new byte[] {EVEN, ODD, EVEN, ODD, ODD}, // 1 + new byte[] {EVEN, ODD, ODD, EVEN, ODD}, // 2 + new byte[] {EVEN, ODD, ODD, ODD, EVEN}, // 3 + new byte[] {ODD, EVEN, EVEN, ODD, ODD}, // 4 + new byte[] {ODD, ODD, EVEN, EVEN, ODD}, // 5 + new byte[] {ODD, ODD, ODD, EVEN, EVEN}, // 6 + new byte[] {ODD, EVEN, ODD, EVEN, ODD}, // 7 + new byte[] {ODD, EVEN, ODD, ODD, EVEN}, // 8 + new byte[] {ODD, ODD, EVEN, ODD, EVEN} // 9 + }; + + /** Sequence of parities to be used with UPCE.*/ + private static readonly byte[][] PARITYE = + { + new byte[] {EVEN, EVEN, EVEN, ODD, ODD, ODD}, // 0 + new byte[] {EVEN, EVEN, ODD, EVEN, ODD, ODD}, // 1 + new byte[] {EVEN, EVEN, ODD, ODD, EVEN, ODD}, // 2 + new byte[] {EVEN, EVEN, ODD, ODD, ODD, EVEN}, // 3 + new byte[] {EVEN, ODD, EVEN, EVEN, ODD, ODD}, // 4 + new byte[] {EVEN, ODD, ODD, EVEN, EVEN, ODD}, // 5 + new byte[] {EVEN, ODD, ODD, ODD, EVEN, EVEN}, // 6 + new byte[] {EVEN, ODD, EVEN, ODD, EVEN, ODD}, // 7 + new byte[] {EVEN, ODD, EVEN, ODD, ODD, EVEN}, // 8 + new byte[] {EVEN, ODD, ODD, EVEN, ODD, EVEN} // 9 + }; + + /** Creates new BarcodeEAN */ + public BarcodeEAN() { + x = 0.8f; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + guardBars = true; + codeType = EAN13; + code = ""; + } + + /** Calculates the EAN parity character. + * @param code the code + * @return the parity character + */ + public static int CalculateEANParity(string code) { + int mul = 3; + int total = 0; + for (int k = code.Length - 1; k >= 0; --k) { + int n = code[k] - '0'; + total += mul * n; + mul ^= 2; + } + return (10 - (total % 10)) % 10; + } + + /** Converts an UPCA code into an UPCE code. If the code can not + * be converted a null is returned. + * @param text the code to convert. It must have 12 numeric characters + * @return the 8 converted digits or null if the + * code could not be converted + */ + static public string ConvertUPCAtoUPCE(string text) { + if (text.Length != 12 || !(text.StartsWith("0") || text.StartsWith("1"))) + return null; + if (text.Substring(3, 3).Equals("000") || text.Substring(3, 3).Equals("100") + || text.Substring(3, 3).Equals("200")) { + if (text.Substring(6, 2).Equals("00")) + return text.Substring(0, 1) + text.Substring(1, 2) + text.Substring(8, 3) + text.Substring(3, 1) + text.Substring(11); + } + else if (text.Substring(4, 2).Equals("00")) { + if (text.Substring(6, 3).Equals("000")) + return text.Substring(0, 1) + text.Substring(1, 3) + text.Substring(9, 2) + "3" + text.Substring(11); + } + else if (text.Substring(5, 1).Equals("0")) { + if (text.Substring(6, 4).Equals("0000")) + return text.Substring(0, 1) + text.Substring(1, 4) + text.Substring(10, 1) + "4" + text.Substring(11); + } + else if (text[10] >= '5') { + if (text.Substring(6, 4).Equals("0000")) + return text.Substring(0, 1) + text.Substring(1, 5) + text.Substring(10, 1) + text.Substring(11); + } + return null; + } + + /** Creates the bars for the barcode EAN13 and UPCA. + * @param _code the text with 13 digits + * @return the barcode + */ + public static byte[] GetBarsEAN13(string _code) { + int[] code = new int[_code.Length]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_EAN13]; + int pb = 0; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + byte[] sequence = PARITY13[code[0]]; + for (int k = 0; k < sequence.Length; ++k) { + int c = code[k + 1]; + byte[] stripes = BARS[c]; + if (sequence[k] == ODD) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + for (int k = 7; k < 13; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + return bars; + } + + /** Creates the bars for the barcode EAN8. + * @param _code the text with 8 digits + * @return the barcode + */ + public static byte[] GetBarsEAN8(string _code) { + int[] code = new int[_code.Length]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_EAN8]; + int pb = 0; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + for (int k = 0; k < 4; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + for (int k = 4; k < 8; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + return bars; + } + + /** Creates the bars for the barcode UPCE. + * @param _code the text with 8 digits + * @return the barcode + */ + public static byte[] GetBarsUPCE(string _code) { + int[] code = new int[_code.Length]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_UPCE]; + bool flip = (code[0] != 0); + int pb = 0; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + byte[] sequence = PARITYE[code[code.Length - 1]]; + for (int k = 1; k < code.Length - 1; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + if (sequence[k - 1] == (flip ? EVEN : ODD)) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + return bars; + } + + /** Creates the bars for the barcode supplemental 2. + * @param _code the text with 2 digits + * @return the barcode + */ + public static byte[] GetBarsSupplemental2(string _code) { + int[] code = new int[2]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_SUPP2]; + int pb = 0; + int parity = (code[0] * 10 + code[1]) % 4; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 2; + byte[] sequence = PARITY2[parity]; + for (int k = 0; k < sequence.Length; ++k) { + if (k == 1) { + bars[pb++] = 1; + bars[pb++] = 1; + } + int c = code[k]; + byte[] stripes = BARS[c]; + if (sequence[k] == ODD) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + return bars; + } + + /** Creates the bars for the barcode supplemental 5. + * @param _code the text with 5 digits + * @return the barcode + */ + public static byte[] GetBarsSupplemental5(string _code) { + int[] code = new int[5]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_SUPP5]; + int pb = 0; + int parity = (((code[0] + code[2] + code[4]) * 3) + ((code[1] + code[3]) * 9)) % 10; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 2; + byte[] sequence = PARITY5[parity]; + for (int k = 0; k < sequence.Length; ++k) { + if (k != 0) { + bars[pb++] = 1; + bars[pb++] = 1; + } + int c = code[k]; + byte[] stripes = BARS[c]; + if (sequence[k] == ODD) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float width = 0; + float height = barHeight; + if (font != null) { + if (baseline <= 0) + height += -baseline + size; + else + height += baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + } + switch (codeType) { + case BarcodeEAN.EAN13: + width = x * (11 + 12 * 7); + if (font != null) { + width += font.GetWidthPoint(code[0], size); + } + break; + case EAN8: + width = x * (11 + 8 * 7); + break; + case UPCA: + width = x * (11 + 12 * 7); + if (font != null) { + width += font.GetWidthPoint(code[0], size) + font.GetWidthPoint(code[11], size); + } + break; + case UPCE: + width = x * (9 + 6 * 7); + if (font != null) { + width += font.GetWidthPoint(code[0], size) + font.GetWidthPoint(code[7], size); + } + break; + case SUPP2: + width = x * (6 + 2 * 7); + break; + case SUPP5: + width = x * (4 + 5 * 7 + 4 * 2); + break; + default: + throw new ArgumentException("Invalid code type."); + } + return new Rectangle(width, height); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + Rectangle rect = this.BarcodeSize; + float barStartX = 0; + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + switch (codeType) { + case EAN13: + case UPCA: + case UPCE: + if (font != null) + barStartX += font.GetWidthPoint(code[0], size); + break; + } + byte[] bars = null; + int[] guard = GUARD_EMPTY; + switch (codeType) { + case EAN13: + bars = GetBarsEAN13(code); + guard = GUARD_EAN13; + break; + case EAN8: + bars = GetBarsEAN8(code); + guard = GUARD_EAN8; + break; + case UPCA: + bars = GetBarsEAN13("0" + code); + guard = GUARD_UPCA; + break; + case UPCE: + bars = GetBarsUPCE(code); + guard = GUARD_UPCE; + break; + case SUPP2: + bars = GetBarsSupplemental2(code); + break; + case SUPP5: + bars = GetBarsSupplemental5(code); + break; + } + float keepBarX = barStartX; + bool print = true; + float gd = 0; + if (font != null && baseline > 0 && guardBars) { + gd = baseline / 2; + } + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = bars[k] * x; + if (print) { + if (Array.BinarySearch(guard, k) >= 0) + cb.Rectangle(barStartX, barStartY - gd, w - inkSpreading, barHeight + gd); + else + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + } + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + switch (codeType) { + case EAN13: + cb.SetTextMatrix(0, textStartY); + cb.ShowText(code.Substring(0, 1)); + for (int k = 1; k < 13; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + break; + case EAN8: + for (int k = 0; k < 8; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = TEXTPOS_EAN8[k] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + break; + case UPCA: + cb.SetTextMatrix(0, textStartY); + cb.ShowText(code.Substring(0, 1)); + for (int k = 1; k < 11; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = keepBarX + TEXTPOS_EAN13[k] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + cb.SetTextMatrix(keepBarX + x * (11 + 12 * 7), textStartY); + cb.ShowText(code.Substring(11, 1)); + break; + case UPCE: + cb.SetTextMatrix(0, textStartY); + cb.ShowText(code.Substring(0, 1)); + for (int k = 1; k < 7; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + cb.SetTextMatrix(keepBarX + x * (9 + 6 * 7), textStartY); + cb.ShowText(code.Substring(7, 1)); + break; + case SUPP2: + case SUPP5: + for (int k = 0; k < code.Length; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = (7.5f + (9 * k)) * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + break; + } + cb.EndText(); + } + return rect; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + int width = 0; + byte[] bars = null; + switch (codeType) { + case EAN13: + bars = GetBarsEAN13(code); + width = 11 + 12 * 7; + break; + case EAN8: + bars = GetBarsEAN8(code); + width = 11 + 8 * 7; + break; + case UPCA: + bars = GetBarsEAN13("0" + code); + width = 11 + 12 * 7; + break; + case UPCE: + bars = GetBarsUPCE(code); + width = 9 + 6 * 7; + break; + case SUPP2: + bars = GetBarsSupplemental2(code); + width = 6 + 2 * 7; + break; + case SUPP5: + bars = GetBarsSupplemental5(code); + width = 4 + 5 * 7 + 4 * 2; + break; + default: + throw new InvalidOperationException("Invalid code type."); + } + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = bars[k]; + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs new file mode 100644 index 0000000..0f15fb0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs @@ -0,0 +1,150 @@ +using System; +using iTextSharp.text; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** This class takes 2 barcodes, an EAN/UPC and a supplemental + * and creates a single barcode with both combined in the + * expected layout. The UPC/EAN should have a positive text + * baseline and the supplemental a negative one (in the supplemental + * the text is on the top of the barcode.

+ * The default parameters are: + *

+     *n = 8; // horizontal distance between the two barcodes
+     * 
+ * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeEANSUPP : Barcode { + + /** The barcode with the EAN/UPC. + */ + protected Barcode ean; + /** The barcode with the supplemental. + */ + protected Barcode supp; + + /** Creates new combined barcode. + * @param ean the EAN/UPC barcode + * @param supp the supplemental barcode + */ + public BarcodeEANSUPP(Barcode ean, Barcode supp) { + n = 8; // horizontal distance between the two barcodes + this.ean = ean; + this.supp = supp; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + Rectangle rect = ean.BarcodeSize; + rect.Right = rect.Width + supp.BarcodeSize.Width + n; + return rect; + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + if (supp.Font != null) + supp.BarHeight = ean.BarHeight + supp.Baseline - supp.Font.GetFontDescriptor(BaseFont.CAPHEIGHT, supp.Size); + else + supp.BarHeight = ean.BarHeight; + Rectangle eanR = ean.BarcodeSize; + cb.SaveState(); + ean.PlaceBarcode(cb, barColor, textColor); + cb.RestoreState(); + cb.SaveState(); + cb.ConcatCTM(1, 0, 0, 1, eanR.Width + n, eanR.Height - ean.BarHeight); + supp.PlaceBarcode(cb, barColor, textColor); + cb.RestoreState(); + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + throw new InvalidOperationException("The two barcodes must be composed externally."); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs new file mode 100644 index 0000000..cc1479b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs @@ -0,0 +1,317 @@ +using System; +using System.Text; +using iTextSharp.text; + +/* + * $Id: BarcodeInter25.cs,v 1.5 2006/09/17 15:58:51 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Implements the code interleaved 2 of 5. The text can include + * non numeric characters that are printed but do not generate bars. + * The default parameters are: + *

+     *x = 0.8f;
+     *n = 2;
+     *font = BaseFont.CreateFont("Helvetica", "winansi", false);
+     *size = 8;
+     *baseline = size;
+     *barHeight = size * 3;
+     *textint= Element.ALIGN_CENTER;
+     *generateChecksum = false;
+     *checksumText = false;
+     * 
+ * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeInter25 : Barcode { + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = { + new byte[] {0,0,1,1,0}, + new byte[] {1,0,0,0,1}, + new byte[] {0,1,0,0,1}, + new byte[] {1,1,0,0,0}, + new byte[] {0,0,1,0,1}, + new byte[] {1,0,1,0,0}, + new byte[] {0,1,1,0,0}, + new byte[] {0,0,0,1,1}, + new byte[] {1,0,0,1,0}, + new byte[] {0,1,0,1,0} + }; + + /** Creates new BarcodeInter25 */ + public BarcodeInter25() { + x = 0.8f; + n = 2; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + generateChecksum = false; + checksumText = false; + } + + /** Deletes all the non numeric characters from text. + * @param text the text + * @return a string with only numeric characters + */ + public static string KeepNumbers(string text) { + StringBuilder sb = new StringBuilder(); + for (int k = 0; k < text.Length; ++k) { + char c = text[k]; + if (c >= '0' && c <= '9') + sb.Append(c); + } + return sb.ToString(); + } + + /** Calculates the checksum. + * @param text the numeric text + * @return the checksum + */ + public static char GetChecksum(string text) { + int mul = 3; + int total = 0; + for (int k = text.Length - 1; k >= 0; --k) { + int n = text[k] - '0'; + total += mul * n; + mul ^= 2; + } + return (char)(((10 - (total % 10)) % 10) + '0'); + } + + /** Creates the bars for the barcode. + * @param text the text. It can contain non numeric characters + * @return the barcode + */ + public static byte[] GetBarsInter25(string text) { + text = KeepNumbers(text); + if ((text.Length & 1) != 0) + throw new ArgumentException("The text length must be even."); + byte[] bars = new byte[text.Length * 5 + 7]; + int pb = 0; + bars[pb++] = 0; + bars[pb++] = 0; + bars[pb++] = 0; + bars[pb++] = 0; + int len = text.Length / 2; + for (int k = 0; k < len; ++k) { + int c1 = text[k * 2] - '0'; + int c2 = text[k * 2 + 1] - '0'; + byte[] b1 = BARS[c1]; + byte[] b2 = BARS[c2]; + for (int j = 0; j < 5; ++j) { + bars[pb++] = b1[j]; + bars[pb++] = b2[j]; + } + } + bars[pb++] = 1; + bars[pb++] = 0; + bars[pb++] = 0; + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + string fullCode = code; + if (generateChecksum && checksumText) + fullCode += GetChecksum(fullCode); + fontX = font.GetWidthPoint(altText != null ? altText : fullCode, size); + } + string fCode = KeepNumbers(code); + int len = fCode.Length; + if (generateChecksum) + ++len; + float fullWidth = len * (3 * x + 2 * x * n) + (6 + n ) * x; + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + string fullCode = code; + float fontX = 0; + if (font != null) { + if (generateChecksum && checksumText) + fullCode += GetChecksum(fullCode); + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + string bCode = KeepNumbers(code); + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length; + float fullWidth = len * (3 * x + 2 * x * n) + (6 + n ) * x; + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + byte[] bars = GetBarsInter25(bCode); + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = (bars[k] == 0 ? x : x * n); + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String bCode = KeepNumbers(code); + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length; + int nn = (int)n; + int fullWidth = len * (3 + 2 * nn) + (6 + nn ); + byte[] bars = GetBarsInter25(bCode); + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = (bars[k] == 0 ? 1 : nn); + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs b/iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs new file mode 100644 index 0000000..94cf499 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs @@ -0,0 +1,1551 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf.codec; +using System.Collections; +using System.Text; + +namespace iTextSharp.text.pdf { + /** Generates the 2D barcode PDF417. Supports dimensioning auto-sizing, fixed + * and variable sizes, automatic and manual error levels, raw codeword input, + * codeword size optimization and bitmap inversion. The output can + * be a CCITT G4 Image or a raw bitmap. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodePDF417 { + + /** Auto-size is made based on aspectRatio and yHeight. */ + public const int PDF417_USE_ASPECT_RATIO = 0; + /** The size of the barcode will be at least codeColumns*codeRows. */ + public const int PDF417_FIXED_RECTANGLE = 1; + /** The size will be at least codeColumns + * with a variable number of codeRows. + */ + public const int PDF417_FIXED_COLUMNS = 2; + /** The size will be at least codeRows + * with a variable number of codeColumns. + */ + public const int PDF417_FIXED_ROWS = 4; + /** The error level correction is set automatically according + * to ISO 15438 recomendations. + */ + public const int PDF417_AUTO_ERROR_LEVEL = 0; + /** The error level correction is set by the user. It can be 0 to 8. */ + public const int PDF417_USE_ERROR_LEVEL = 16; + /** + * One single binary segment is used + */ + public const int PDF417_FORCE_BINARY = 32; + /** No text interpretation is done and the content of codewords + * is used directly. + */ + public const int PDF417_USE_RAW_CODEWORDS = 64; + /** Inverts the output bits of the raw bitmap that is normally + * bit one for black. It has only effect for the raw bitmap. + */ + public const int PDF417_INVERT_BITMAP = 128; + /** Use Macro PDF417 Encoding + * @see #setMacroFileId(String) + * @see #setMacroSegmentId(int) + * @see #setMacroSegmentCount(int) + */ + public const int PDF417_USE_MACRO = 256; + + + private int macroSegmentCount=0; + private int macroSegmentId=-1; + private String macroFileId; + private int macroIndex; + + protected int bitPtr; + protected int cwPtr; + protected SegmentList segmentList; + + /** Creates a new BarcodePDF417 with the default settings. */ + public BarcodePDF417() { + SetDefaultParameters(); + } + + /** + * Sets the segment id for macro PDF417 encoding + * @param id the id (starting at 0) + * @see #setMacroSegmentCount(int) + */ + public int MacroSegmentId { + set { + this.macroSegmentId = value; + } + } + + /** + * Sets the segment count for macro PDF417 encoding + * @param cnt the number of macro segments + * @see #setMacroSegmentId(int) + */ + public int MacroSegmentCount { + set { + this.macroSegmentCount = value; + } + } + + /** + * Sets the File ID for macro PDF417 encoding + * @param id the file id + */ + public String MacroFileId { + set { + this.macroFileId = value; + } + } + + protected bool CheckSegmentType(Segment segment, char type) { + if (segment == null) + return false; + return segment.type == type; + } + + protected int GetSegmentLength(Segment segment) { + if (segment == null) + return 0; + return segment.end - segment.start; + } + + /** Set the default settings that correspond to PDF417_USE_ASPECT_RATIO + * and PDF417_AUTO_ERROR_LEVEL. + */ + public void SetDefaultParameters() { + options = 0; + outBits = null; + text = new byte[0]; + yHeight = 3; + aspectRatio = 0.5f; + } + + protected void OutCodeword17(int codeword) { + int bytePtr = bitPtr / 8; + int bit = bitPtr - bytePtr * 8; + outBits[bytePtr++] |= (byte)(codeword >> (9 + bit)); + outBits[bytePtr++] |= (byte)(codeword >> (1 + bit)); + codeword <<= 8; + outBits[bytePtr] |= (byte)(codeword >> (1 + bit)); + bitPtr += 17; + } + + protected void OutCodeword18(int codeword) { + int bytePtr = bitPtr / 8; + int bit = bitPtr - bytePtr * 8; + outBits[bytePtr++] |= (byte)(codeword >> (10 + bit)); + outBits[bytePtr++] |= (byte)(codeword >> (2 + bit)); + codeword <<= 8; + outBits[bytePtr] |= (byte)(codeword >> (2 + bit)); + if (bit == 7) + outBits[++bytePtr] |= 0x80; + bitPtr += 18; + } + + protected void OutCodeword(int codeword) { + OutCodeword17(codeword); + } + + protected void OutStopPattern() { + OutCodeword18(STOP_PATTERN); + } + + protected void OutStartPattern() { + OutCodeword17(START_PATTERN); + } + + protected void OutPaintCode() { + int codePtr = 0; + bitColumns = START_CODE_SIZE * (codeColumns + 3) + STOP_SIZE; + int lenBits = ((bitColumns - 1) / 8 + 1) * codeRows; + outBits = new byte[lenBits]; + for (int row = 0; row < codeRows; ++row) { + bitPtr = ((bitColumns - 1) / 8 + 1) * 8 * row; + int rowMod = row % 3; + int[] cluster = CLUSTERS[rowMod]; + OutStartPattern(); + int edge = 0; + switch (rowMod) { + case 0: + edge = 30 * (row / 3) + ((codeRows - 1) / 3); + break; + case 1: + edge = 30 * (row / 3) + errorLevel * 3 + ((codeRows - 1) % 3); + break; + default: + edge = 30 * (row / 3) + codeColumns - 1; + break; + } + OutCodeword(cluster[edge]); + + for (int column = 0; column < codeColumns; ++column) { + OutCodeword(cluster[codewords[codePtr++]]); + } + + switch (rowMod) { + case 0: + edge = 30 * (row / 3) + codeColumns - 1; + break; + case 1: + edge = 30 * (row / 3) + ((codeRows - 1) / 3); + break; + default: + edge = 30 * (row / 3) + errorLevel * 3 + ((codeRows - 1) % 3); + break; + } + OutCodeword(cluster[edge]); + OutStopPattern(); + } + if ((options & PDF417_INVERT_BITMAP) != 0) { + for (int k = 0; k < outBits.Length; ++k) + outBits[k] ^= 0xff; + } + } + + protected void CalculateErrorCorrection(int dest) { + if (errorLevel < 0 || errorLevel > 8) + errorLevel = 0; + int[] A = ERROR_LEVEL[errorLevel]; + int Alength = 2 << errorLevel; + for (int k = 0; k < Alength; ++k) + codewords[dest + k] = 0; + int lastE = Alength - 1; + for (int k = 0; k < lenCodewords; ++k) { + int t1 = codewords[k] + codewords[dest]; + for (int e = 0; e <= lastE; ++e) { + int t2 = (t1 * A[lastE - e]) % MOD; + int t3 = MOD - t2; + codewords[dest + e] = ((e == lastE ? 0 : codewords[dest + e + 1]) + t3) % MOD; + } + } + for (int k = 0; k < Alength; ++k) + codewords[dest + k] = (MOD - codewords[dest + k]) % MOD; + } + + private static int GetTextTypeAndValue(byte[] input, int maxLength, int idx) { + if (idx >= maxLength) + return 0; + char c = (char)(input[idx] & 0xff); + if (c >= 'A' && c <= 'Z') + return (ALPHA + c - 'A'); + if (c >= 'a' && c <= 'z') + return (LOWER + c - 'a'); + if (c == ' ') + return (ALPHA + LOWER + MIXED + SPACE); + int ms = MIXED_SET.IndexOf(c); + int ps = PUNCTUATION_SET.IndexOf(c); + if (ms < 0 && ps < 0) + return (ISBYTE + c); + if (ms == ps) + return (MIXED + PUNCTUATION + ms); + if (ms >= 0) + return (MIXED + ms); + return (PUNCTUATION + ps); + } + + protected int GetTextTypeAndValue(int maxLength, int idx) { + return GetTextTypeAndValue(text, maxLength,idx); + } + + private void TextCompaction(byte[] input, int start, int length) { + int[] dest = new int[ABSOLUTE_MAX_TEXT_SIZE * 2]; + int mode = ALPHA; + int ptr = 0; + int fullBytes = 0; + int v = 0; + int k; + int size; + length += start; + for (k = start; k < length; ++k) { + v = GetTextTypeAndValue(input, length, k); + if ((v & mode) != 0) { + dest[ptr++] = v & 0xff; + continue; + } + if ((v & ISBYTE) != 0) { + if ((ptr & 1) != 0) { + //add a padding word + dest[ptr++] = PAL; + mode = (mode & PUNCTUATION) != 0 ? ALPHA : mode; + } + dest[ptr++] = BYTESHIFT; + dest[ptr++] = v & 0xff; + fullBytes += 2; + continue; + } + switch (mode) { + case ALPHA: + if ((v & LOWER) != 0) { + dest[ptr++] = LL; + dest[ptr++] = v & 0xff; + mode = LOWER; + } + else if ((v & MIXED) != 0) { + dest[ptr++] = ML; + dest[ptr++] = v & 0xff; + mode = MIXED; + } + else if ((GetTextTypeAndValue(input, length, k + 1) & GetTextTypeAndValue(input, length, k + 2) & PUNCTUATION) != 0) { + dest[ptr++] = ML; + dest[ptr++] = PL; + dest[ptr++] = v & 0xff; + mode = PUNCTUATION; + } + else { + dest[ptr++] = PS; + dest[ptr++] = v & 0xff; + } + break; + case LOWER: + if ((v & ALPHA) != 0) { + if ((GetTextTypeAndValue(length, k + 1) & GetTextTypeAndValue(length, k + 2) & ALPHA) != 0) { + dest[ptr++] = ML; + dest[ptr++] = AL; + mode = ALPHA; + } + else { + dest[ptr++] = AS; + } + dest[ptr++] = v & 0xff; + } + else if ((v & MIXED) != 0) { + dest[ptr++] = ML; + dest[ptr++] = v & 0xff; + mode = MIXED; + } + else if ((GetTextTypeAndValue(input, length, k + 1) & GetTextTypeAndValue(input, length, k + 2) & PUNCTUATION) != 0) { + dest[ptr++] = ML; + dest[ptr++] = PL; + dest[ptr++] = v & 0xff; + mode = PUNCTUATION; + } + else { + dest[ptr++] = PS; + dest[ptr++] = v & 0xff; + } + break; + case MIXED: + if ((v & LOWER) != 0) { + dest[ptr++] = LL; + dest[ptr++] = v & 0xff; + mode = LOWER; + } + else if ((v & ALPHA) != 0) { + dest[ptr++] = AL; + dest[ptr++] = v & 0xff; + mode = ALPHA; + } + else if ((GetTextTypeAndValue(input, length, k + 1) & GetTextTypeAndValue(input, length, k + 2) & PUNCTUATION) != 0) { + dest[ptr++] = PL; + dest[ptr++] = v & 0xff; + mode = PUNCTUATION; + } + else { + dest[ptr++] = PS; + dest[ptr++] = v & 0xff; + } + break; + case PUNCTUATION: + dest[ptr++] = PAL; + mode = ALPHA; + --k; + break; + } + } + if ((ptr & 1) != 0) + dest[ptr++] = PS; + size = (ptr + fullBytes) / 2; + if (size + cwPtr > MAX_DATA_CODEWORDS) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + length = ptr; + ptr = 0; + while (ptr < length) { + v = dest[ptr++]; + if (v >= 30) { + codewords[cwPtr++] = v; + codewords[cwPtr++] = dest[ptr++]; + } + else + codewords[cwPtr++] = v * 30 + dest[ptr++]; + } + } + + protected void TextCompaction(int start, int length) { + TextCompaction(text, start, length); + } + + protected void BasicNumberCompaction(int start, int length) { + BasicNumberCompaction(text, start, length); + } + + private void BasicNumberCompaction(byte[] input, int start, int length) { + int ret = cwPtr; + int retLast = length / 3; + int ni, k; + cwPtr += retLast + 1; + for (k = 0; k <= retLast; ++k) + codewords[ret + k] = 0; + codewords[ret + retLast] = 1; + length += start; + for (ni = start; ni < length; ++ni) { + // multiply by 10 + for (k = retLast; k >= 0; --k) + codewords[ret + k] *= 10; + // add the digit + codewords[ret + retLast] += input[ni] - '0'; + // propagate carry + for (k = retLast; k > 0; --k) { + codewords[ret + k - 1] += codewords[ret + k] / 900; + codewords[ret + k] %= 900; + } + } + } + + private void NumberCompaction(byte[] input, int start, int length) { + int full = (length / 44) * 15; + int size = length % 44; + int k; + if (size == 0) + size = full; + else + size = full + size / 3 + 1; + if (size + cwPtr > MAX_DATA_CODEWORDS) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + length += start; + for (k = start; k < length; k += 44) { + size = length - k < 44 ? length - k : 44; + BasicNumberCompaction(input, k, size); + } + } + + protected void NumberCompaction(int start, int length) { + NumberCompaction(text, start, length); + } + + protected void ByteCompaction6(int start) { + int length = 6; + int ret = cwPtr; + int retLast = 4; + int ni, k; + cwPtr += retLast + 1; + for (k = 0; k <= retLast ; ++k) + codewords[ret + k] = 0; + length += start; + for (ni = start; ni < length; ++ni) { + // multiply by 256 + for (k = retLast; k >= 0; --k) + codewords[ret + k] *= 256; + // add the digit + codewords[ret + retLast] += (int)text[ni] & 0xff; + // propagate carry + for (k = retLast; k > 0; --k) { + codewords[ret + k - 1] += codewords[ret + k] / 900; + codewords[ret + k] %= 900; + } + } + } + + internal void ByteCompaction(int start, int length) { + int k, j; + int size = (length / 6) * 5 + (length % 6); + if (size + cwPtr > MAX_DATA_CODEWORDS) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + length += start; + for (k = start; k < length; k += 6) { + size = length - k < 44 ? length - k : 6; + if (size < 6) { + for (j = 0; j < size; ++j) + codewords[cwPtr++] = (int)text[k + j] & 0xff; + } + else { + ByteCompaction6(k); + } + } + } + + internal void BreakString() { + int textLength = text.Length; + int lastP = 0; + int startN = 0; + int nd = 0; + char c = (char)0; + int k, j; + bool lastTxt, txt; + Segment v; + Segment vp; + Segment vn; + + if ((options & PDF417_FORCE_BINARY) != 0) { + segmentList.Add('B', 0, textLength); + return; + } + for (k = 0; k < textLength; ++k) { + c = (char)(text[k] & 0xff); + if (c >= '0' && c <= '9') { + if (nd == 0) + startN = k; + ++nd; + continue; + } + if (nd >= 13) { + if (lastP != startN) { + c = (char)(text[lastP] & 0xff); + lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + for (j = lastP; j < startN; ++j) { + c = (char)(text[j] & 0xff); + txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + if (txt != lastTxt) { + segmentList.Add(lastTxt ? 'T' : 'B', lastP, j); + lastP = j; + lastTxt = txt; + } + } + segmentList.Add(lastTxt ? 'T' : 'B', lastP, startN); + } + segmentList.Add('N', startN, k); + lastP = k; + } + nd = 0; + } + if (nd < 13) + startN = textLength; + if (lastP != startN) { + c = (char)(text[lastP] & 0xff); + lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + for (j = lastP; j < startN; ++j) { + c = (char)(text[j] & 0xff); + txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + if (txt != lastTxt) { + segmentList.Add(lastTxt ? 'T' : 'B', lastP, j); + lastP = j; + lastTxt = txt; + } + } + segmentList.Add(lastTxt ? 'T' : 'B', lastP, startN); + } + if (nd >= 13) + segmentList.Add('N', startN, textLength); + //optimize + //merge short binary + for (k = 0; k < segmentList.Size; ++k) { + v = segmentList.Get(k); + vp = segmentList.Get(k - 1); + vn = segmentList.Get(k + 1); + if (CheckSegmentType(v, 'B') && GetSegmentLength(v) == 1) { + if (CheckSegmentType(vp, 'T') && CheckSegmentType(vn, 'T') + && GetSegmentLength(vp) + GetSegmentLength(vn) >= 3) { + vp.end = vn.end; + segmentList.Remove(k); + segmentList.Remove(k); + k = -1; + continue; + } + } + } + //merge text sections + for (k = 0; k < segmentList.Size; ++k) { + v = segmentList.Get(k); + vp = segmentList.Get(k - 1); + vn = segmentList.Get(k + 1); + if (CheckSegmentType(v, 'T') && GetSegmentLength(v) >= 5) { + bool redo = false; + if ((CheckSegmentType(vp, 'B') && GetSegmentLength(vp) == 1) || CheckSegmentType(vp, 'T')) { + redo = true; + v.start = vp.start; + segmentList.Remove(k - 1); + --k; + } + if ((CheckSegmentType(vn, 'B') && GetSegmentLength(vn) == 1) || CheckSegmentType(vn, 'T')) { + redo = true; + v.end = vn.end; + segmentList.Remove(k + 1); + } + if (redo) { + k = -1; + continue; + } + } + } + //merge binary sections + for (k = 0; k < segmentList.Size; ++k) { + v = segmentList.Get(k); + vp = segmentList.Get(k - 1); + vn = segmentList.Get(k + 1); + if (CheckSegmentType(v, 'B')) { + bool redo = false; + if ((CheckSegmentType(vp, 'T') && GetSegmentLength(vp) < 5) || CheckSegmentType(vp, 'B')) { + redo = true; + v.start = vp.start; + segmentList.Remove(k - 1); + --k; + } + if ((CheckSegmentType(vn, 'T') && GetSegmentLength(vn) < 5) || CheckSegmentType(vn, 'B')) { + redo = true; + v.end = vn.end; + segmentList.Remove(k + 1); + } + if (redo) { + k = -1; + continue; + } + } + } + // check if all numbers + if (segmentList.Size == 1 && (v = segmentList.Get(0)).type == 'T' && GetSegmentLength(v) >= 8) { + for (k = v.start; k < v.end; ++k) { + c = (char)(text[k] & 0xff); + if (c < '0' || c > '9') + break; + } + if (k == v.end) + v.type = 'N'; + } + } + + protected void Assemble() { + int k; + if (segmentList.Size == 0) + return; + cwPtr = 1; + for (k = 0; k < segmentList.Size; ++k) { + Segment v = segmentList.Get(k); + switch (v.type) { + case 'T': + if (k != 0) + codewords[cwPtr++] = TEXT_MODE; + TextCompaction(v.start, GetSegmentLength(v)); + break; + case 'N': + codewords[cwPtr++] = NUMERIC_MODE; + NumberCompaction(v.start, GetSegmentLength(v)); + break; + case 'B': + codewords[cwPtr++] = (GetSegmentLength(v) % 6) != 0 ? BYTE_MODE : BYTE_MODE_6; + ByteCompaction(v.start, GetSegmentLength(v)); + break; + } + } + if ((options & PDF417_USE_MACRO) != 0) { + MacroCodes(); + } + + } + + private void MacroCodes() { + if (macroSegmentId < 0) { + throw new InvalidOperationException("macroSegmentId must be >=0"); + } + if (macroSegmentId >= macroSegmentCount) { + throw new InvalidOperationException("macroSegmentId must be < macroSemgentCount"); + } + if (macroSegmentCount < 1) { + throw new InvalidOperationException("macroSemgentCount must be > 0"); + } + + macroIndex = cwPtr; + codewords[cwPtr++] = MACRO_SEGMENT_ID; + Append(macroSegmentId, 5); + + if (macroFileId != null) { + Append(macroFileId); + } + + if (macroSegmentId >= macroSegmentCount-1) { + codewords[cwPtr++] = MACRO_LAST_SEGMENT; + } + + } + + private void Append(int inp, int len) { + StringBuilder sb = new StringBuilder(len+1); + sb.Append(inp); + for(int i = sb.Length; i < len; i++) { + sb.Insert(0, "0"); + } + + byte[] bytes = PdfEncodings.ConvertToBytes(sb.ToString(), "cp437"); + NumberCompaction(bytes, 0, bytes.Length); + } + + private void Append(String s) { + byte[] bytes = PdfEncodings.ConvertToBytes(s, "cp437"); + TextCompaction(bytes, 0, bytes.Length); + } + + protected static int MaxPossibleErrorLevel(int remain) { + int level = 8; + int size = 512; + while (level > 0) { + if (remain >= size) + return level; + --level; + size >>= 1; + } + return 0; + } + + protected void DumpList() { + if (segmentList.Size == 0) + return; + for (int k = 0; k < segmentList.Size; ++k) { + Segment v = segmentList.Get(k); + int len = GetSegmentLength(v); + char[] c = new char[len]; + for (int j = 0; j < len; ++j) { + c[j] = (char)(text[v.start + j] & 0xff); + if (c[j] == '\r') + c[j] = '\n'; + } + Console.WriteLine("" + v.type + new String(c)); + } + } + + protected int GetMaxSquare() { + if (codeColumns > 21) { + codeColumns = 29; + codeRows = 32; + } + else { + codeColumns = 16; + codeRows = 58; + } + return MAX_DATA_CODEWORDS + 2; + } + + /** Paints the barcode. If no exception was thrown a valid barcode is available. */ + public void PaintCode() { + int maxErr, lenErr, tot, pad; + if ((options & PDF417_USE_RAW_CODEWORDS) != 0) { + if (lenCodewords > MAX_DATA_CODEWORDS || lenCodewords < 1 || lenCodewords != codewords[0]) { + throw new ArgumentException("Invalid codeword size."); + } + } + else { + if (text == null) + throw new ArgumentNullException("Text cannot be null."); + if (text.Length > ABSOLUTE_MAX_TEXT_SIZE) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + segmentList = new SegmentList(); + BreakString(); + //dumpList(); + Assemble(); + segmentList = null; + codewords[0] = lenCodewords = cwPtr; + } + maxErr = MaxPossibleErrorLevel(MAX_DATA_CODEWORDS + 2 - lenCodewords); + if ((options & PDF417_USE_ERROR_LEVEL) == 0) { + if (lenCodewords < 41) + errorLevel = 2; + else if (lenCodewords < 161) + errorLevel = 3; + else if (lenCodewords < 321) + errorLevel = 4; + else + errorLevel = 5; + } + if (errorLevel < 0) + errorLevel = 0; + else if (errorLevel > maxErr) + errorLevel = maxErr; + if (codeColumns < 1) + codeColumns = 1; + else if (codeColumns > 30) + codeColumns = 30; + if (codeRows < 3) + codeRows = 3; + else if (codeRows > 90) + codeRows = 90; + lenErr = 2 << errorLevel; + bool fixedColumn = (options & PDF417_FIXED_ROWS) == 0; + bool skipRowColAdjust = false; + tot = lenCodewords + lenErr; + if ((options & PDF417_FIXED_RECTANGLE) != 0) { + tot = codeColumns * codeRows; + if (tot > MAX_DATA_CODEWORDS + 2) { + tot = GetMaxSquare(); + } + if (tot < lenCodewords + lenErr) + tot = lenCodewords + lenErr; + else + skipRowColAdjust = true; + } + else if ((options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS)) == 0) { + double c, b; + fixedColumn = true; + if (aspectRatio < 0.001) + aspectRatio = 0.001f; + else if (aspectRatio > 1000) + aspectRatio = 1000; + b = 73 * aspectRatio - 4; + c = (-b + Math.Sqrt(b * b + 4 * 17 * aspectRatio * (lenCodewords + lenErr) * yHeight)) / (2 * 17 * aspectRatio); + codeColumns = (int)(c + 0.5); + if (codeColumns < 1) + codeColumns = 1; + else if (codeColumns > 30) + codeColumns = 30; + } + if (!skipRowColAdjust) { + if (fixedColumn) { + codeRows = (tot - 1) / codeColumns + 1; + if (codeRows < 3) + codeRows = 3; + else if (codeRows > 90) { + codeRows = 90; + codeColumns = (tot - 1) / 90 + 1; + } + } + else { + codeColumns = (tot - 1) / codeRows + 1; + if (codeColumns > 30) { + codeColumns = 30; + codeRows = (tot - 1) / 30 + 1; + } + } + tot = codeRows * codeColumns; + } + if (tot > MAX_DATA_CODEWORDS + 2) { + tot = GetMaxSquare(); + } + errorLevel = MaxPossibleErrorLevel(tot - lenCodewords); + lenErr = 2 << errorLevel; + pad = tot - lenErr - lenCodewords; + if ((options & PDF417_USE_MACRO) != 0) { + // the padding comes before the control block + System.Array.Copy(codewords, macroIndex, codewords, macroIndex + pad, pad); + cwPtr = lenCodewords + pad; + while (pad-- != 0) + codewords[macroIndex++] = TEXT_MODE; + } + else { + cwPtr = lenCodewords; + while (pad-- != 0) + codewords[cwPtr++] = TEXT_MODE; + } + codewords[0] = lenCodewords = cwPtr; + CalculateErrorCorrection(lenCodewords); + lenCodewords = tot; + OutPaintCode(); + } + + /** Gets an Image with the barcode. The image will have to be + * scaled in the Y direction by yHeightfor the barcode + * to have the right printing aspect. + * @return the barcode Image + * @throws BadElementException on error + */ + public Image GetImage() { + PaintCode(); + byte[] g4 = CCITTG4Encoder.Compress(outBits, bitColumns, codeRows); + return Image.GetInstance(bitColumns, codeRows, false, Element.CCITTG4, (options & PDF417_INVERT_BITMAP) == 0 ? 0 : Element.CCITT_BLACKIS1, g4, null); + } + + public virtual System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + PaintCode(); + int h = (int)yHeight; + int stride = (bitColumns + 7) / 8; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(bitColumns, codeRows * h); + int y = 0; + for (int k = 0; k < codeRows; ++k) { + for (int hh = 0; hh < h; ++hh) { + int p = k * stride; + for (int j = 0; j < bitColumns; ++j) { + int b = outBits[p + (j / 8)] & 0xff; + b <<= j % 8; + bmp.SetPixel(j, y, (b & 0x80) == 0 ? background : foreground); + } + ++y; + } + } + return bmp; + } + + /** Gets the raw image bits of the barcode. The image will have to + * be scaled in the Y direction by yHeight. + * @return The raw barcode image + */ + public byte[] OutBits { + get { + return this.outBits; + } + } + + /** Gets the number of X pixels of outBits. + * @return the number of X pixels of outBits + */ + public int BitColumns { + get { + return this.bitColumns; + } + } + + /** Gets the number of Y pixels of outBits. + * It is also the number of rows in the barcode. + * @return the number of Y pixels of outBits + */ + /** Sets the number of barcode rows. This number may be changed + * to keep the barcode valid. + * @param codeRows the number of barcode rows + */ + public int CodeRows { + set { + this.codeRows = value; + } + get { + return codeRows; + } + } + + /** Sets the number of barcode data columns. + * This number may be changed to keep the barcode valid. + * @param codeColumns the number of barcode data columns + */ + public int CodeColumns { + set { + this.codeColumns = value; + } + get { + return codeColumns; + } + } + + /** Gets the codeword array. This array is always 928 elements long. + * It can be writen to if the option PDF417_USE_RAW_CODEWORDS + * is set. + * @return the codeword array + */ + public int[] Codewords { + get { + return this.codewords; + } + } + + /** Sets the length of the codewords. + * @param lenCodewords the length of the codewords + */ + public int LenCodewords { + set { + this.lenCodewords = value; + } + get { + return lenCodewords; + } + } + + /** Gets the error level correction used for the barcode. It may different + * from the previously set value. + * @return the error level correction used for the barcode + */ + /** Sets the error level correction for the barcode. + * @param errorLevel the error level correction for the barcode + */ + public int ErrorLevel { + set { + this.errorLevel = value; + } + get { + return errorLevel; + } + } + + /** Sets the bytes that form the barcode. This bytes should + * be interpreted in the codepage Cp437. + * @param text the bytes that form the barcode + */ + public byte[] Text { + set { + this.text = value; + } + get { + return text; + } + } + + /** Sets the text that will form the barcode. This text is converted + * to bytes using the encoding Cp437. + * @param s the text that will form the barcode + * @throws UnsupportedEncodingException if the encoding Cp437 is not supported + */ + public void SetText(String s) { + this.text = PdfEncodings.ConvertToBytes(s, "cp437"); + } + + /** Sets the options to generate the barcode. This can be all + * the PDF417_* constants. + * @param options the options to generate the barcode + */ + public int Options { + set { + this.options = value; + } + get { + return options; + } + } + + /** Sets the barcode aspect ratio. A ratio or 0.5 will make the + * barcode width twice as large as the height. + * @param aspectRatio the barcode aspect ratio + */ + public float AspectRatio { + set { + this.aspectRatio = value; + } + get { + return aspectRatio; + } + } + + /** Sets the Y pixel height relative to X. It is usually 3. + * @param yHeight the Y pixel height relative to X + */ + public float YHeight { + set { + this.yHeight = value; + } + get { + return yHeight; + } + } + + protected const int START_PATTERN = 0x1fea8; + protected const int STOP_PATTERN = 0x3fa29; + protected const int START_CODE_SIZE = 17; + protected const int STOP_SIZE = 18; + protected const int MOD = 929; + protected const int ALPHA = 0x10000; + protected const int LOWER = 0x20000; + protected const int MIXED = 0x40000; + protected const int PUNCTUATION = 0x80000; + protected const int ISBYTE = 0x100000; + protected const int BYTESHIFT = 913; + protected const int PL = 25; + protected const int LL = 27; + protected const int AS = 27; + protected const int ML = 28; + protected const int AL = 28; + protected const int PS = 29; + protected const int PAL = 29; + protected const int SPACE = 26; + protected const int TEXT_MODE = 900; + protected const int BYTE_MODE_6 = 924; + protected const int BYTE_MODE = 901; + protected const int NUMERIC_MODE = 902; + protected const int ABSOLUTE_MAX_TEXT_SIZE = 5420; + protected const int MAX_DATA_CODEWORDS = 926; + protected const int MACRO_SEGMENT_ID=928; + protected const int MACRO_LAST_SEGMENT=922; + + private const string MIXED_SET = "0123456789&\r\t,:#-.$/+%*=^"; + private const string PUNCTUATION_SET = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'"; + + private static readonly int[][] CLUSTERS = new int[][] + {new int[]{ + 0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e, 0x1a8c0, 0x1d470, + 0x1a860, 0x15040, 0x1a830, 0x15020, 0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, + 0x1d678, 0x1eb3e, 0x158c0, 0x1ac70, 0x15860, 0x15dc0, 0x1aef0, 0x1d77c, + 0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0, 0x1af7c, 0x15e78, + 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0, 0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, + 0x1e93c, 0x1a460, 0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418, + 0x14810, 0x1a6e0, 0x1d378, 0x1e9be, 0x14cc0, 0x1a670, 0x1d33c, 0x14c60, + 0x1a638, 0x1d31e, 0x14c30, 0x1a61c, 0x14ee0, 0x1a778, 0x1d3be, 0x14e70, + 0x1a73c, 0x14e38, 0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, 0x14f1e, 0x1a2c0, + 0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440, 0x1a230, 0x1d11c, + 0x14420, 0x1a218, 0x14410, 0x14408, 0x146c0, 0x1a370, 0x1d1bc, 0x14660, + 0x1a338, 0x1d19e, 0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc, + 0x14738, 0x1a39e, 0x1471c, 0x147bc, 0x1a160, 0x1d0b8, 0x1e85e, 0x14240, + 0x1a130, 0x1d09c, 0x14220, 0x1a118, 0x1d08e, 0x14210, 0x1a10c, 0x14208, + 0x1a106, 0x14360, 0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e, + 0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0, 0x1d05c, 0x14120, + 0x1a098, 0x1d04e, 0x14110, 0x1a08c, 0x14108, 0x1a086, 0x14104, 0x141b0, + 0x14198, 0x1418c, 0x140a0, 0x1d02e, 0x1a04c, 0x1a046, 0x14082, 0x1cae0, + 0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460, 0x1ca38, 0x1e51e, + 0x12840, 0x19430, 0x12820, 0x196e0, 0x1cb78, 0x1e5be, 0x12cc0, 0x19670, + 0x1cb3c, 0x12c60, 0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe, + 0x12e70, 0x1973c, 0x12e38, 0x12e1c, 0x12f78, 0x197be, 0x12f3c, 0x12fbe, + 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60, 0x1ed38, 0x1f69e, 0x1b440, 0x1da30, + 0x1ed1c, 0x1b420, 0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, 0x192c0, 0x1c970, + 0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660, 0x1db38, 0x1ed9e, + 0x16c40, 0x12420, 0x19218, 0x1c90e, 0x16c20, 0x1b618, 0x16c10, 0x126c0, + 0x19370, 0x1c9bc, 0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738, + 0x1db9e, 0x16e30, 0x12618, 0x16e18, 0x12770, 0x193bc, 0x16f70, 0x12738, + 0x1939e, 0x16f38, 0x1b79e, 0x16f1c, 0x127bc, 0x16fbc, 0x1279e, 0x16f9e, + 0x1d960, 0x1ecb8, 0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918, + 0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160, 0x1c8b8, 0x1e45e, + 0x1b360, 0x19130, 0x1c89c, 0x16640, 0x12220, 0x1d99c, 0x1c88e, 0x16620, + 0x12210, 0x1910c, 0x16610, 0x1b30c, 0x19106, 0x12204, 0x12360, 0x191b8, + 0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c, 0x1918e, 0x16718, + 0x1230c, 0x12306, 0x123b8, 0x191de, 0x167b8, 0x1239c, 0x1679c, 0x1238e, + 0x1678e, 0x167de, 0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e, + 0x1b110, 0x1d88c, 0x1b108, 0x1d886, 0x1b104, 0x1b102, 0x12140, 0x190b0, + 0x1c85c, 0x16340, 0x12120, 0x19098, 0x1c84e, 0x16320, 0x1b198, 0x1d8ce, + 0x16310, 0x12108, 0x19086, 0x16308, 0x1b186, 0x16304, 0x121b0, 0x190dc, + 0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c, 0x12186, 0x16386, + 0x163dc, 0x163ce, 0x1b0a0, 0x1d858, 0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, + 0x1d846, 0x1b084, 0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090, + 0x1904c, 0x16190, 0x1b0cc, 0x19046, 0x16188, 0x12084, 0x16184, 0x12082, + 0x120d8, 0x161d8, 0x161cc, 0x161c6, 0x1d82c, 0x1d826, 0x1b042, 0x1902c, + 0x12048, 0x160c8, 0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60, + 0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18, 0x11410, 0x11408, + 0x116c0, 0x18b70, 0x1c5bc, 0x11660, 0x18b38, 0x1c59e, 0x11630, 0x18b1c, + 0x11618, 0x1160c, 0x11770, 0x18bbc, 0x11738, 0x18b9e, 0x1171c, 0x117bc, + 0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30, 0x1e69c, 0x19a20, + 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c, 0x19a08, 0x1cd06, 0x18960, 0x1c4b8, + 0x1e25e, 0x19b60, 0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e, + 0x13620, 0x19b18, 0x1890c, 0x13610, 0x11208, 0x13608, 0x11360, 0x189b8, + 0x1c4de, 0x13760, 0x11330, 0x1cdde, 0x13730, 0x19b9c, 0x1898e, 0x13718, + 0x1130c, 0x1370c, 0x113b8, 0x189de, 0x137b8, 0x1139c, 0x1379c, 0x1138e, + 0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20, 0x1ee98, 0x1f74e, + 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86, 0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, + 0x1bb40, 0x19920, 0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10, + 0x19908, 0x1cc86, 0x1bb08, 0x1dd86, 0x19902, 0x11140, 0x188b0, 0x1c45c, + 0x13340, 0x11120, 0x18898, 0x1c44e, 0x17740, 0x13320, 0x19998, 0x1ccce, + 0x17720, 0x1bb98, 0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708, + 0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce, 0x177b0, 0x13398, + 0x199ce, 0x17798, 0x1bbce, 0x11186, 0x13386, 0x111dc, 0x133dc, 0x111ce, + 0x177dc, 0x133ce, 0x1dca0, 0x1ee58, 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88, + 0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e, 0x1b9a0, 0x19890, + 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46, 0x1b988, 0x19884, 0x1b984, 0x19882, + 0x1b982, 0x110a0, 0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0, + 0x13190, 0x198cc, 0x18846, 0x17390, 0x1b9cc, 0x11084, 0x17388, 0x13184, + 0x11082, 0x13182, 0x110d8, 0x1886e, 0x131d8, 0x110cc, 0x173d8, 0x131cc, + 0x110c6, 0x173cc, 0x131c6, 0x110ee, 0x173ee, 0x1dc50, 0x1ee2c, 0x1dc48, + 0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0, 0x19848, 0x1cc26, + 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842, 0x1b8c2, 0x11050, 0x1882c, 0x130d0, + 0x11048, 0x18826, 0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042, + 0x171c4, 0x130c2, 0x171c2, 0x130ec, 0x171ec, 0x171e6, 0x1ee16, 0x1dc22, + 0x1cc16, 0x19824, 0x19822, 0x11028, 0x13068, 0x170e8, 0x11022, 0x13062, + 0x18560, 0x10a40, 0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c, + 0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30, 0x1859c, 0x10b18, + 0x1858e, 0x10b0c, 0x10b06, 0x10bb8, 0x185de, 0x10b9c, 0x10b8e, 0x10bde, + 0x18d40, 0x1c6b0, 0x1e35c, 0x18d20, 0x1c698, 0x18d10, 0x1c68c, 0x18d08, + 0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40, 0x10920, 0x1c6dc, + 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce, 0x11b10, 0x10908, 0x18486, 0x11b08, + 0x18d86, 0x10902, 0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98, + 0x18dce, 0x11b8c, 0x10986, 0x109dc, 0x11bdc, 0x109ce, 0x11bce, 0x1cea0, + 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c, 0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, + 0x18ca0, 0x1c658, 0x19da0, 0x18c90, 0x1c64c, 0x19d90, 0x1cecc, 0x1c646, + 0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0, 0x18458, 0x119a0, + 0x10890, 0x1c66e, 0x13ba0, 0x11990, 0x18ccc, 0x18446, 0x13b90, 0x19dcc, + 0x10884, 0x13b88, 0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8, + 0x108cc, 0x13bd8, 0x119cc, 0x108c6, 0x13bcc, 0x119c6, 0x108ee, 0x119ee, + 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48, 0x1f7a6, 0x1ef44, 0x1ef42, 0x1ce50, + 0x1e72c, 0x1ded0, 0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42, + 0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626, 0x1bdd0, 0x19cc8, + 0x1ce66, 0x1bdc8, 0x1dee6, 0x18c42, 0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, + 0x1842c, 0x118d0, 0x10848, 0x18426, 0x139d0, 0x118c8, 0x18c66, 0x17bd0, + 0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2, 0x17bc4, 0x1086c, + 0x118ec, 0x10866, 0x139ec, 0x118e6, 0x17bec, 0x139e6, 0x17be6, 0x1ef28, + 0x1f796, 0x1ef24, 0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64, + 0x1ce22, 0x1de62, 0x18c28, 0x1c616, 0x19c68, 0x18c24, 0x1bce8, 0x19c64, + 0x18c22, 0x1bce4, 0x19c62, 0x1bce2, 0x10828, 0x18416, 0x11868, 0x18c36, + 0x138e8, 0x11864, 0x10822, 0x179e8, 0x138e4, 0x11862, 0x179e4, 0x138e2, + 0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32, 0x19c34, 0x1bc74, + 0x1bc72, 0x11834, 0x13874, 0x178f4, 0x178f2, 0x10540, 0x10520, 0x18298, + 0x10510, 0x10508, 0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc, + 0x105ce, 0x186a0, 0x18690, 0x1c34c, 0x18688, 0x1c346, 0x18684, 0x18682, + 0x104a0, 0x18258, 0x10da0, 0x186d8, 0x1824c, 0x10d90, 0x186cc, 0x10d88, + 0x186c6, 0x10d84, 0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee, + 0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750, 0x1c748, 0x1c744, + 0x1c742, 0x18650, 0x18ed0, 0x1c76c, 0x1c326, 0x18ec8, 0x1c766, 0x18ec4, + 0x18642, 0x18ec2, 0x10450, 0x10cd0, 0x10448, 0x18226, 0x11dd0, 0x10cc8, + 0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2, 0x1046c, 0x10cec, + 0x10466, 0x11dec, 0x10ce6, 0x11de6, 0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, + 0x1cf68, 0x1e7b6, 0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68, + 0x1c736, 0x19ee8, 0x18e64, 0x18622, 0x19ee4, 0x18e62, 0x19ee2, 0x10428, + 0x18216, 0x10c68, 0x18636, 0x11ce8, 0x10c64, 0x10422, 0x13de8, 0x11ce4, + 0x10c62, 0x13de4, 0x11ce2, 0x10436, 0x10c76, 0x11cf6, 0x13df6, 0x1f7d4, + 0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714, 0x1cf34, 0x1c712, + 0x1df74, 0x1cf32, 0x1df72, 0x18614, 0x18e34, 0x18612, 0x19e74, 0x18e32, + 0x1bef4 + }, new int[]{ + 0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20, 0x1f518, 0x1fa8e, + 0x1ea10, 0x1f50c, 0x1ea08, 0x1f506, 0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, + 0x1d640, 0x1eb30, 0x1f59c, 0x1d620, 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c, + 0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de, 0x1ae40, 0x1d730, + 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e, 0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, + 0x1ae04, 0x1af60, 0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20, + 0x1af18, 0x1d78e, 0x15e10, 0x1af0c, 0x15e08, 0x1af06, 0x15f60, 0x1afb8, + 0x1d7de, 0x15f30, 0x1af9c, 0x15f18, 0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, + 0x15f9c, 0x15f8e, 0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, 0x1f498, 0x1fa4e, + 0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902, 0x1d340, 0x1e9b0, + 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce, 0x1d310, 0x1e98c, 0x1d308, 0x1e986, + 0x1d304, 0x1d302, 0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce, + 0x1a710, 0x1d38c, 0x1a708, 0x1d386, 0x1a704, 0x1a702, 0x14f40, 0x1a7b0, + 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce, 0x14f10, 0x1a78c, 0x14f08, 0x1a786, + 0x14f04, 0x14fb0, 0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc, + 0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c, 0x1e888, 0x1f446, + 0x1e884, 0x1e882, 0x1d1a0, 0x1e8d8, 0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, + 0x1e8c6, 0x1d184, 0x1d182, 0x1a3a0, 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc, + 0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8, 0x1d1ee, 0x14790, + 0x1a3cc, 0x14788, 0x1a3c6, 0x14784, 0x14782, 0x147d8, 0x1a3ee, 0x147cc, + 0x147c6, 0x147ee, 0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842, + 0x1d0d0, 0x1e86c, 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2, 0x1a1d0, 0x1d0ec, + 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2, 0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, + 0x143c4, 0x143c2, 0x143ec, 0x143e6, 0x1e828, 0x1f416, 0x1e824, 0x1e822, + 0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076, 0x1a0e4, 0x1a0e2, + 0x141e8, 0x1a0f6, 0x141e4, 0x141e2, 0x1e814, 0x1e812, 0x1d034, 0x1d032, + 0x1a074, 0x1a072, 0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e, + 0x1e510, 0x1f28c, 0x1e508, 0x1f286, 0x1e504, 0x1e502, 0x1cb40, 0x1e5b0, + 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce, 0x1cb10, 0x1e58c, 0x1cb08, 0x1e586, + 0x1cb04, 0x1cb02, 0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce, + 0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702, 0x12f40, 0x197b0, + 0x1cbdc, 0x12f20, 0x19798, 0x1cbce, 0x12f10, 0x1978c, 0x12f08, 0x19786, + 0x12f04, 0x12fb0, 0x197dc, 0x12f98, 0x197ce, 0x12f8c, 0x12f86, 0x12fdc, + 0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c, 0x169f8, 0x1f688, + 0x1fb46, 0x168fc, 0x1f684, 0x1f682, 0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, + 0x1e490, 0x1fb6e, 0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84, + 0x1e482, 0x1ed82, 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0, 0x1c990, 0x1e4cc, + 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88, 0x1c984, 0x1db84, 0x1c982, 0x1db82, + 0x193a0, 0x1c9d8, 0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, 0x1b790, 0x1dbcc, + 0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782, 0x127a0, 0x193d8, + 0x1c9ee, 0x16fa0, 0x12790, 0x193cc, 0x16f90, 0x1b7cc, 0x193c6, 0x16f88, + 0x12784, 0x16f84, 0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc, + 0x127c6, 0x16fc6, 0x127ee, 0x1f650, 0x1fb2c, 0x165f8, 0x1f648, 0x1fb26, + 0x164fc, 0x1f644, 0x1647e, 0x1f642, 0x1e450, 0x1f22c, 0x1ecd0, 0x1e448, + 0x1f226, 0x1ecc8, 0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c, + 0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4, 0x1c8c2, 0x1d9c2, + 0x191d0, 0x1c8ec, 0x1b3d0, 0x191c8, 0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, + 0x191c2, 0x1b3c2, 0x123d0, 0x191ec, 0x167d0, 0x123c8, 0x191e6, 0x167c8, + 0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec, 0x123e6, 0x167e6, + 0x1f628, 0x1fb16, 0x162fc, 0x1f624, 0x1627e, 0x1f622, 0x1e428, 0x1f216, + 0x1ec68, 0x1f636, 0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8, + 0x1c864, 0x1d8e4, 0x1c862, 0x1d8e2, 0x190e8, 0x1c876, 0x1b1e8, 0x1d8f6, + 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8, 0x190f6, 0x163e8, 0x121e4, 0x163e4, + 0x121e2, 0x163e2, 0x121f6, 0x163f6, 0x1f614, 0x1617e, 0x1f612, 0x1e414, + 0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832, 0x1d872, 0x19074, + 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4, 0x161f4, 0x120f2, 0x161f2, 0x1f60a, + 0x1e40a, 0x1ec1a, 0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158, + 0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, 0x1f146, 0x1e284, 0x1e282, 0x1c5a0, + 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc, 0x1c588, 0x1e2c6, 0x1c584, 0x1c582, + 0x18ba0, 0x1c5d8, 0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84, + 0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc, 0x11788, 0x18bc6, + 0x11784, 0x11782, 0x117d8, 0x18bee, 0x117cc, 0x117c6, 0x117ee, 0x1f350, + 0x1f9ac, 0x135f8, 0x1f348, 0x1f9a6, 0x134fc, 0x1f344, 0x1347e, 0x1f342, + 0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8, 0x1f366, 0x1e6c4, + 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c, 0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, + 0x1e6e6, 0x1cdc4, 0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8, + 0x1c4e6, 0x19bc8, 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2, 0x113d0, 0x189ec, + 0x137d0, 0x113c8, 0x189e6, 0x137c8, 0x19be6, 0x137c4, 0x113c2, 0x137c2, + 0x113ec, 0x137ec, 0x113e6, 0x137e6, 0x1fba8, 0x175f0, 0x1bafc, 0x1fba4, + 0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328, 0x1f996, 0x132fc, + 0x1f768, 0x1fbb6, 0x176fc, 0x1327e, 0x1f764, 0x1f322, 0x1767e, 0x1f762, + 0x1e228, 0x1f116, 0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4, + 0x1e662, 0x1eee2, 0x1c468, 0x1e236, 0x1cce8, 0x1c464, 0x1dde8, 0x1cce4, + 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2, 0x188e8, 0x1c476, 0x199e8, 0x188e4, + 0x1bbe8, 0x199e4, 0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6, + 0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4, 0x133e2, 0x177e2, + 0x111f6, 0x133f6, 0x1fb94, 0x172f8, 0x1b97e, 0x1fb92, 0x1727c, 0x1723e, + 0x1f314, 0x1317e, 0x1f734, 0x1f312, 0x1737e, 0x1f732, 0x1e214, 0x1e634, + 0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74, 0x1c432, 0x1dcf4, + 0x1cc72, 0x1dcf2, 0x18874, 0x198f4, 0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, + 0x110f4, 0x131f4, 0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c, + 0x1713e, 0x1f30a, 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a, 0x1c41a, 0x1cc3a, + 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa, 0x1107a, 0x130fa, 0x171fa, 0x170be, + 0x1e150, 0x1f0ac, 0x1e148, 0x1f0a6, 0x1e144, 0x1e142, 0x1c2d0, 0x1e16c, + 0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec, 0x185c8, 0x1c2e6, + 0x185c4, 0x185c2, 0x10bd0, 0x185ec, 0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, + 0x10bec, 0x10be6, 0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2, + 0x1e128, 0x1f096, 0x1e368, 0x1e124, 0x1e364, 0x1e122, 0x1e362, 0x1c268, + 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4, 0x1c262, 0x1c6e2, 0x184e8, 0x1c276, + 0x18de8, 0x184e4, 0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8, + 0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6, 0x1f9d4, 0x13af8, + 0x19d7e, 0x1f9d2, 0x13a7c, 0x13a3e, 0x1f194, 0x1197e, 0x1f3b4, 0x1f192, + 0x13b7e, 0x1f3b2, 0x1e114, 0x1e334, 0x1e112, 0x1e774, 0x1e332, 0x1e772, + 0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2, 0x18474, 0x18cf4, + 0x18472, 0x19df4, 0x18cf2, 0x19df2, 0x108f4, 0x119f4, 0x108f2, 0x13bf4, + 0x119f2, 0x13bf2, 0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e, + 0x1f9ca, 0x1397c, 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e, 0x1f18a, 0x1f39a, + 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a, 0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, + 0x1defa, 0x1843a, 0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, 0x118fa, 0x139fa, + 0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be, 0x178bc, 0x1789e, + 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2, 0x1c168, 0x1e0b6, 0x1c164, 0x1c162, + 0x182e8, 0x1c176, 0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2, + 0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, 0x1e094, 0x1e1b4, 0x1e092, 0x1e1b2, + 0x1c134, 0x1c374, 0x1c132, 0x1c372, 0x18274, 0x186f4, 0x18272, 0x186f2, + 0x104f4, 0x10df4, 0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca, + 0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a, 0x1c77a, 0x1823a, + 0x1867a, 0x18efa, 0x1047a, 0x10cfa, 0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, + 0x13d1e, 0x11cbe, 0x13dbe, 0x17d70, 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c, + 0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8, 0x1be5e, 0x17c9c, + 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c, 0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, + 0x18174, 0x18172, 0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a, + 0x1837a, 0x1027a, 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e, 0x13eb8, 0x19f5e, + 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede, 0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, + 0x17e8c, 0x17e86, 0x13e5c, 0x17edc, 0x13e4e, 0x17ece, 0x17e58, 0x1bf2e, + 0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26, 0x10f5e, 0x11f5c, + 0x11f4e, 0x13f58, 0x19fae, 0x13f4c, 0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, + 0x13f26 + }, new int[]{ + 0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0, 0x1a8f8, 0x1d47e, + 0x150f0, 0x1a87c, 0x15078, 0x1fad0, 0x15be0, 0x1adf8, 0x1fac8, 0x159f0, + 0x1acfc, 0x1fac4, 0x158f8, 0x1ac7e, 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec, + 0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e, 0x1f5c2, 0x1ebd0, + 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4, 0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, + 0x1ebe6, 0x1d7c4, 0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4, + 0x14bc0, 0x1a5f0, 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e, 0x148f0, 0x1a47c, + 0x14878, 0x1a43e, 0x1483c, 0x1fa68, 0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, + 0x1a67e, 0x1fa62, 0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, 0x14efc, 0x1f4e4, + 0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2, 0x1d3e8, 0x1e9f6, + 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6, 0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, + 0x1d17e, 0x144f0, 0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34, + 0x146f8, 0x1a37e, 0x1fa32, 0x1467c, 0x1463e, 0x1f474, 0x1477e, 0x1f472, + 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2, 0x1a3f4, 0x1a3f2, 0x142f0, 0x1a17c, + 0x14278, 0x1a13e, 0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a, + 0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e, 0x141be, 0x140bc, + 0x1409e, 0x12bc0, 0x195f0, 0x1cafc, 0x129e0, 0x194f8, 0x1ca7e, 0x128f0, + 0x1947c, 0x12878, 0x1943e, 0x1283c, 0x1f968, 0x12df0, 0x196fc, 0x1f964, + 0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8, 0x1f976, 0x12efc, + 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8, 0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, + 0x1e5f6, 0x1cbe4, 0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0, + 0x1daf8, 0x1ed7e, 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0, 0x1b478, 0x1da3e, + 0x16870, 0x1b43c, 0x16838, 0x1b41e, 0x1681c, 0x125e0, 0x192f8, 0x1c97e, + 0x16de0, 0x124f0, 0x1927c, 0x16cf0, 0x1b67c, 0x1923e, 0x16c78, 0x1243c, + 0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e, 0x1fb74, 0x1f932, + 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c, 0x1263e, 0x16e3e, 0x1f274, 0x1277e, + 0x1f6f4, 0x1f272, 0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2, + 0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, 0x193f4, 0x193f2, 0x165c0, 0x1b2f0, + 0x1d97c, 0x164e0, 0x1b278, 0x1d93e, 0x16470, 0x1b23c, 0x16438, 0x1b21e, + 0x1641c, 0x1640e, 0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678, + 0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c, 0x1fb3a, 0x1677c, + 0x1233e, 0x1673e, 0x1f23a, 0x1f67a, 0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, + 0x191fa, 0x162e0, 0x1b178, 0x1d8be, 0x16270, 0x1b13c, 0x16238, 0x1b11e, + 0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c, 0x1633c, 0x1211e, + 0x1631e, 0x121be, 0x163be, 0x16170, 0x1b0bc, 0x16138, 0x1b09e, 0x1611c, + 0x1610e, 0x120bc, 0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c, + 0x1608e, 0x1205e, 0x160de, 0x1605c, 0x1604e, 0x115e0, 0x18af8, 0x1c57e, + 0x114f0, 0x18a7c, 0x11478, 0x18a3e, 0x1143c, 0x1141e, 0x1f8b4, 0x116f8, + 0x18b7e, 0x1f8b2, 0x1167c, 0x1163e, 0x1f174, 0x1177e, 0x1f172, 0x1e2f4, + 0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0, 0x19af0, 0x1cd7c, + 0x134e0, 0x19a78, 0x1cd3e, 0x13470, 0x19a3c, 0x13438, 0x19a1e, 0x1341c, + 0x1340e, 0x112f0, 0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e, + 0x1363c, 0x1121e, 0x1361e, 0x1f89a, 0x1137c, 0x1f9ba, 0x1377c, 0x1133e, + 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a, 0x1e6fa, 0x1c4fa, 0x1cdfa, 0x189fa, + 0x1bae0, 0x1dd78, 0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38, + 0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c, 0x132e0, 0x19978, + 0x1ccbe, 0x176e0, 0x13270, 0x1993c, 0x17670, 0x1bb3c, 0x1991e, 0x17638, + 0x1321c, 0x1761c, 0x1320e, 0x1760e, 0x11178, 0x188be, 0x13378, 0x1113c, + 0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e, 0x111be, 0x133be, + 0x177be, 0x172c0, 0x1b970, 0x1dcbc, 0x17260, 0x1b938, 0x1dc9e, 0x17230, + 0x1b91c, 0x17218, 0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370, + 0x13138, 0x1989e, 0x17338, 0x1b99e, 0x1731c, 0x1310e, 0x1730e, 0x110bc, + 0x131bc, 0x1109e, 0x173bc, 0x1319e, 0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, + 0x17130, 0x1b89c, 0x17118, 0x1b88e, 0x1710c, 0x17106, 0x130b8, 0x1985e, + 0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e, 0x130de, 0x171de, + 0x170b0, 0x1b85c, 0x17098, 0x1b84e, 0x1708c, 0x17086, 0x1305c, 0x170dc, + 0x1304e, 0x170ce, 0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e, + 0x1702c, 0x17026, 0x10af0, 0x1857c, 0x10a78, 0x1853e, 0x10a3c, 0x10a1e, + 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a, 0x1c2fa, 0x185fa, 0x11ae0, 0x18d78, + 0x1c6be, 0x11a70, 0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978, + 0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e, 0x109be, 0x11bbe, + 0x13ac0, 0x19d70, 0x1cebc, 0x13a60, 0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, + 0x13a18, 0x19d0e, 0x13a0c, 0x13a06, 0x11970, 0x18cbc, 0x13b70, 0x11938, + 0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e, 0x108bc, 0x119bc, + 0x1089e, 0x13bbc, 0x1199e, 0x13b9e, 0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, + 0x1bd30, 0x1de9c, 0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08, + 0x1bd06, 0x17a04, 0x13960, 0x19cb8, 0x1ce5e, 0x17b60, 0x13930, 0x19c9c, + 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18, 0x1390c, 0x17b0c, 0x13906, 0x17b06, + 0x118b8, 0x18c5e, 0x139b8, 0x1189c, 0x17bb8, 0x1399c, 0x1188e, 0x17b9c, + 0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde, 0x17940, 0x1bcb0, + 0x1de5c, 0x17920, 0x1bc98, 0x1de4e, 0x17910, 0x1bc8c, 0x17908, 0x1bc86, + 0x17904, 0x17902, 0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998, + 0x1bcce, 0x1798c, 0x13886, 0x17986, 0x1185c, 0x138dc, 0x1184e, 0x179dc, + 0x138ce, 0x179ce, 0x178a0, 0x1bc58, 0x1de2e, 0x17890, 0x1bc4c, 0x17888, + 0x1bc46, 0x17884, 0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc, + 0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850, 0x1bc2c, 0x17848, + 0x1bc26, 0x17844, 0x17842, 0x1382c, 0x1786c, 0x13826, 0x17866, 0x17828, + 0x1bc16, 0x17824, 0x17822, 0x13816, 0x17836, 0x10578, 0x182be, 0x1053c, + 0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e, 0x10d1c, 0x10d0e, + 0x104bc, 0x10dbc, 0x1049e, 0x10d9e, 0x11d60, 0x18eb8, 0x1c75e, 0x11d30, + 0x18e9c, 0x11d18, 0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8, + 0x10c9c, 0x11d9c, 0x10c8e, 0x11d8e, 0x1045e, 0x10cde, 0x11dde, 0x13d40, + 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98, 0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, + 0x19e86, 0x13d04, 0x13d02, 0x11cb0, 0x18e5c, 0x13db0, 0x11c98, 0x18e4e, + 0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c, 0x11cdc, 0x10c4e, + 0x13ddc, 0x11cce, 0x13dce, 0x1bea0, 0x1df58, 0x1efae, 0x1be90, 0x1df4c, + 0x1be88, 0x1df46, 0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0, + 0x13c90, 0x19e4c, 0x17d90, 0x1becc, 0x19e46, 0x17d88, 0x13c84, 0x17d84, + 0x13c82, 0x17d82, 0x11c58, 0x18e2e, 0x13cd8, 0x11c4c, 0x17dd8, 0x13ccc, + 0x11c46, 0x17dcc, 0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee, + 0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42, 0x13c50, 0x19e2c, + 0x17cd0, 0x13c48, 0x19e26, 0x17cc8, 0x1be66, 0x17cc4, 0x13c42, 0x17cc2, + 0x11c2c, 0x13c6c, 0x11c26, 0x17cec, 0x13c66, 0x17ce6, 0x1be28, 0x1df16, + 0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24, 0x17c64, 0x13c22, + 0x17c62, 0x11c16, 0x13c36, 0x17c76, 0x1be14, 0x1be12, 0x13c14, 0x17c34, + 0x13c12, 0x17c32, 0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e, + 0x1025e, 0x106de, 0x10eb0, 0x1875c, 0x10e98, 0x1874e, 0x10e8c, 0x10e86, + 0x1065c, 0x10edc, 0x1064e, 0x10ece, 0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, + 0x18f4c, 0x11e88, 0x18f46, 0x11e84, 0x11e82, 0x10e58, 0x1872e, 0x11ed8, + 0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e, 0x11eee, 0x19f50, + 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44, 0x19f42, 0x11e50, 0x18f2c, 0x13ed0, + 0x19f6c, 0x18f26, 0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c, + 0x11e6c, 0x10e26, 0x13eec, 0x11e66, 0x13ee6, 0x1dfa8, 0x1efd6, 0x1dfa4, + 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68, 0x19f24, 0x1bf64, 0x19f22, 0x1bf62, + 0x11e28, 0x18f16, 0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4, + 0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6, 0x1df94, 0x1df92, + 0x19f14, 0x1bf34, 0x19f12, 0x1bf32, 0x11e14, 0x13e34, 0x11e12, 0x17e74, + 0x13e32, 0x17e72, 0x1df8a, 0x19f0a, 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a, + 0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746, 0x1032e, 0x1076e, + 0x10f50, 0x187ac, 0x10f48, 0x187a6, 0x10f44, 0x10f42, 0x1072c, 0x10f6c, + 0x10726, 0x10f66, 0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796, + 0x11f68, 0x18fb6, 0x11f64, 0x10f22, 0x11f62, 0x10716, 0x10f36, 0x11f76, + 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4, 0x18f92, 0x19fb2, 0x10f14, 0x11f34, + 0x10f12, 0x13f74, 0x11f32, 0x13f72, 0x1cfca, 0x18f8a, 0x19f9a, 0x10f0a, + 0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6, 0x107a4, 0x107a2, + 0x10396, 0x107b6, 0x187d4, 0x187d2, 0x10794, 0x10fb4, 0x10792, 0x10fb2, + 0x1c7ea + }}; + + private static readonly int[][] ERROR_LEVEL = new int[][] + {new int[]{ + 27, 917 + }, new int[]{ + 522, 568, 723, 809 + }, new int[]{ + 237, 308, 436, 284, 646, 653, 428, 379 + }, new int[]{ + 274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65 + }, new int[]{ + 361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517, + 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410 + }, new int[]{ + 539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 381, 612, + 723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 400, 672, 762, 283, 184, + 440, 35, 519, 31, 460, 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, + 648, 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, 623, 264, 543 + }, new int[]{ + 521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 749, 415, + 822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 292, 908, 490, 704, + 516, 258, 457, 907, 594, 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, + 193, 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, 463, 646, 776, + 171, 491, 297, 763, 156, 732, 95, 270, 447, 90, 507, 48, 228, 821, 808, 898, + 784, 663, 627, 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, + 157, 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 804, 34, + 211, 330, 539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 801, 4, 108, 539 + }, new int[]{ + 524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 138, 720, + 858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 280, 201, 280, 828, 757, + 710, 814, 919, 89, 68, 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, + 439, 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, 549, 209, 884, + 315, 70, 329, 793, 490, 274, 877, 162, 749, 812, 684, 461, 334, 376, 849, 521, + 307, 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, + 637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 538, 906, 90, + 2, 290, 743, 199, 655, 903, 329, 49, 802, 580, 355, 588, 188, 462, 10, 134, + 628, 320, 479, 130, 739, 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, + 722, 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, 60, 732, 621, + 895, 544, 261, 852, 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528, + 503, 118, 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, + 73, 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 893, 754, + 605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 922, 191, 910, 532, + 609, 829, 189, 20, 167, 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, + 404, 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, 55, 497, 10 + }, new int[]{ + 352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 350, 492, + 197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 87, 193, 352, 781, + 846, 75, 327, 520, 435, 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, + 539, 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, 916, 552, 41, + 542, 289, 122, 272, 383, 800, 485, 98, 752, 472, 761, 107, 784, 860, 658, 741, + 290, 204, 681, 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, + 808, 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 258, + 240, 518, 794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 596, 786, 303, + 570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, + 40, 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, 92, 358, 785, + 288, 357, 850, 836, 827, 736, 707, 94, 8, 494, 114, 521, 2, 499, 851, 543, + 152, 729, 771, 95, 248, 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, + 669, 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578, + 37, 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 911, + 283, 711, 472, 420, 245, 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, + 842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, 159, 672, 729, + 624, 59, 193, 417, 158, 209, 563, 564, 343, 693, 109, 608, 563, 365, 181, 772, + 677, 310, 248, 353, 708, 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, + 618, 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45, + 787, 680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 905, + 789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, + 242, 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, 665, 397, 808, + 851, 309, 473, 795, 378, 31, 647, 915, 459, 806, 590, 731, 425, 216, 548, 249, + 321, 881, 699, 535, 673, 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, + 660, 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437, + 375, 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 842, + 37, 357, 720, 742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, + 342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, 610, 46, 656, + 447, 171, 616, 464, 190, 531, 297, 321, 762, 752, 533, 175, 134, 14, 381, 433, + 717, 45, 111, 20, 596, 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, + 407, 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, 223, 849, 647, + 63, 310, 863, 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263 + }}; + + /** Holds value of property outBits. */ + private byte[] outBits; + + /** Holds value of property bitColumns. */ + private int bitColumns; + + /** Holds value of property codeRows. */ + private int codeRows; + + /** Holds value of property codeColumns. */ + private int codeColumns; + + /** Holds value of property codewords. */ + private int[] codewords = new int[MAX_DATA_CODEWORDS + 2]; + + /** Holds value of property lenCodewords. */ + private int lenCodewords; + + /** Holds value of property errorLevel. */ + private int errorLevel; + + /** Holds value of property text. */ + private byte[] text; + + /** Holds value of property options. */ + private int options; + + /** Holds value of property aspectRatio. */ + private float aspectRatio; + + /** Holds value of property yHeight. */ + private float yHeight; + + protected class Segment { + public char type; + public int start; + public int end; + + public Segment(char type, int start, int end) { + this.type = type; + this.start = start; + this.end = end; + } + } + + protected class SegmentList { + protected ArrayList list = new ArrayList(); + + public void Add(char type, int start, int end) { + list.Add(new Segment(type, start, end)); + } + + public Segment Get(int idx) { + if (idx < 0 || idx >= list.Count) + return null; + return (Segment)list[idx]; + } + + public void Remove(int idx) { + if (idx < 0 || idx >= list.Count) + return; + list.RemoveAt(idx); + } + + public int Size { + get { + return list.Count; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs b/iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs new file mode 100644 index 0000000..0aa745f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs @@ -0,0 +1,219 @@ +using System; +using iTextSharp.text; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements the Postnet and Planet barcodes. The default parameters are: + *

+     *n = 72f / 22f; // distance between bars
+     *x = 0.02f * 72f; // bar width
+     *barHeight = 0.125f * 72f; // height of the tall bars
+     *size = 0.05f * 72f; // height of the short bars
+     *codeType = POSTNET; // type of code
+     * 
+ * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodePostnet : Barcode{ + + /** The bars for each character. + */ + private static readonly byte[][] BARS = { + new byte[] {1,1,0,0,0}, + new byte[] {0,0,0,1,1}, + new byte[] {0,0,1,0,1}, + new byte[] {0,0,1,1,0}, + new byte[] {0,1,0,0,1}, + new byte[] {0,1,0,1,0}, + new byte[] {0,1,1,0,0}, + new byte[] {1,0,0,0,1}, + new byte[] {1,0,0,1,0}, + new byte[] {1,0,1,0,0} + }; + + /** Creates new BarcodePostnet */ + public BarcodePostnet() { + n = 72f / 22f; // distance between bars + x = 0.02f * 72f; // bar width + barHeight = 0.125f * 72f; // height of the tall bars + size = 0.05f * 72f; // height of the short bars + codeType = POSTNET; // type of code + } + + /** Creates the bars for Postnet. + * @param text the code to be created without checksum + * @return the bars + */ + public static byte[] GetBarsPostnet(string text) { + int total = 0; + for (int k = text.Length - 1; k >= 0; --k) { + int n = text[k] - '0'; + total += n; + } + text += (char)(((10 - (total % 10)) % 10) + '0'); + byte[] bars = new byte[text.Length * 5 + 2]; + bars[0] = 1; + bars[bars.Length - 1] = 1; + for (int k = 0; k < text.Length; ++k) { + int c = text[k] - '0'; + Array.Copy(BARS[c], 0, bars, k * 5 + 1, 5); + } + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float width = ((code.Length + 1) * 5 + 1) * n + x; + return new Rectangle(width, barHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

+ * The bars and text are written in the following colors:

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

barColor

textColor

Result

null

null

bars and text painted with current fill color

barColor

null

bars and text painted with barColor

null

textColor

bars painted with current color
text painted with textColor

barColor

textColor

bars painted with barColor
text painted with textColor

+ * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + if (barColor != null) + cb.SetColorFill(barColor); + byte[] bars = GetBarsPostnet(code); + byte flip = 1; + if (codeType == PLANET) { + flip = 0; + bars[0] = 0; + bars[bars.Length - 1] = 0; + } + float startX = 0; + for (int k = 0; k < bars.Length; ++k) { + cb.Rectangle(startX, 0, x - inkSpreading, bars[k] == flip ? barHeight : size); + startX += n; + } + cb.Fill(); + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + int barWidth = (int)x; + if (barWidth <= 0) + barWidth = 1; + int barDistance = (int)n; + if (barDistance <= barWidth) + barDistance = barWidth + 1; + int barShort = (int)size; + if (barShort <= 0) + barShort = 1; + int barTall = (int)barHeight; + if (barTall <= barShort) + barTall = barShort + 1; + byte[] bars = GetBarsPostnet(code); + int width = bars.Length * barDistance; + byte flip = 1; + if (codeType == PLANET) { + flip = 0; + bars[0] = 0; + bars[bars.Length - 1] = 0; + } + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, barTall); + int seg1 = barTall - barShort; + for (int i = 0; i < seg1; ++i) { + int idx = 0; + for (int k = 0; k < bars.Length; ++k) { + bool dot = (bars[k] == flip); + for (int j = 0; j < barDistance; ++j) { + bmp.SetPixel(idx++, i, (dot && j < barWidth) ? foreground : background); + } + } + } + for (int i = seg1; i < barTall; ++i) { + int idx = 0; + for (int k = 0; k < bars.Length; ++k) { + for (int j = 0; j < barDistance; ++j) { + bmp.SetPixel(idx++, i, (j < barWidth) ? foreground : background); + } + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BaseField.cs b/iTechSharp/iTextSharp/text/pdf/BaseField.cs new file mode 100644 index 0000000..9d73757 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BaseField.cs @@ -0,0 +1,630 @@ +using System; +using System.Collections; +using System.Text; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + public abstract class BaseField { + + /** A thin border with 1 point width. */ + public const float BORDER_WIDTH_THIN = 1; + /** A medium border with 2 point width. */ + public const float BORDER_WIDTH_MEDIUM = 2; + /** A thick border with 3 point width. */ + public const float BORDER_WIDTH_THICK = 3; + /** The field is visible. */ + public const int VISIBLE = 0; + /** The field is hidden. */ + public const int HIDDEN = 1; + /** The field is visible but does not print. */ + public const int VISIBLE_BUT_DOES_NOT_PRINT = 2; + /** The field is hidden but is printable. */ + public const int HIDDEN_BUT_PRINTABLE = 3; + /** The user may not change the value of the field. */ + public const int READ_ONLY = PdfFormField.FF_READ_ONLY; + /** The field must have a value at the time it is exported by a submit-form + * action. + */ + public const int REQUIRED = PdfFormField.FF_REQUIRED; + /** The field may contain multiple lines of text. + * This flag is only meaningful with text fields. + */ + public const int MULTILINE = PdfFormField.FF_MULTILINE; + /** The field will not scroll (horizontally for single-line + * fields, vertically for multiple-line fields) to accommodate more text + * than will fit within its annotation rectangle. Once the field is full, no + * further text will be accepted. + */ + public const int DO_NOT_SCROLL = PdfFormField.FF_DONOTSCROLL; + /** The field is intended for entering a secure password that should + * not be echoed visibly to the screen. + */ + public const int PASSWORD = PdfFormField.FF_PASSWORD; + /** The text entered in the field represents the pathname of + * a file whose contents are to be submitted as the value of the field. + */ + public const int FILE_SELECTION = PdfFormField.FF_FILESELECT; + /** The text entered in the field will not be spell-checked. + * This flag is meaningful only in text fields and in combo + * fields with the EDIT flag set. + */ + public const int DO_NOT_SPELL_CHECK = PdfFormField.FF_DONOTSPELLCHECK; + /** If set the combo box includes an editable text box as well as a drop list; if + * clear, it includes only a drop list. + * This flag is only meaningful with combo fields. + */ + public const int EDIT = PdfFormField.FF_EDIT; + + /** + * combo box flag. + */ + public const int COMB = PdfFormField.FF_COMB; + + protected float borderWidth = BORDER_WIDTH_THIN; + protected int borderStyle = PdfBorderDictionary.STYLE_SOLID; + protected Color borderColor; + protected Color backgroundColor; + protected Color textColor; + protected BaseFont font; + protected float fontSize = 0; + protected int alignment = Element.ALIGN_LEFT; + protected PdfWriter writer; + protected String text; + protected Rectangle box; + + /** Holds value of property rotation. */ + protected int rotation = 0; + + /** Holds value of property visibility. */ + protected int visibility; + + /** Holds value of property fieldName. */ + protected String fieldName; + + /** Holds value of property options. */ + protected int options; + + /** Holds value of property maxCharacterLength. */ + protected int maxCharacterLength; + + private static Hashtable fieldKeys = new Hashtable(); + + static BaseField() { + foreach (DictionaryEntry entry in PdfCopyFieldsImp.fieldKeys) + fieldKeys[entry.Key] = entry.Value; + fieldKeys[PdfName.T] = 1; + } + /** Creates a new TextField. + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public BaseField(PdfWriter writer, Rectangle box, String fieldName) { + this.writer = writer; + Box = box; + this.fieldName = fieldName; + } + + protected BaseFont RealFont { + get { + if (font == null) + return BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, false); + else + return font; + } + } + + protected PdfAppearance GetBorderAppearance() { + PdfAppearance app = PdfAppearance.CreateAppearance(writer, box.Width, box.Height); + switch (rotation) { + case 90: + app.SetMatrix(0, 1, -1, 0, box.Height, 0); + break; + case 180: + app.SetMatrix(-1, 0, 0, -1, box.Width, box.Height); + break; + case 270: + app.SetMatrix(0, -1, 1, 0, 0, box.Width); + break; + } + app.SaveState(); + // background + if (backgroundColor != null) { + app.SetColorFill(backgroundColor); + app.Rectangle(0, 0, box.Width, box.Height); + app.Fill(); + } + // border + if (borderStyle == PdfBorderDictionary.STYLE_UNDERLINE) { + if (borderWidth != 0 && borderColor != null) { + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.MoveTo(0, borderWidth / 2); + app.LineTo(box.Width, borderWidth / 2); + app.Stroke(); + } + } + else if (borderStyle == PdfBorderDictionary.STYLE_BEVELED) { + if (borderWidth != 0 && borderColor != null) { + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.Rectangle(borderWidth / 2, borderWidth / 2, box.Width - borderWidth, box.Height - borderWidth); + app.Stroke(); + } + // beveled + Color actual = backgroundColor; + if (actual == null) + actual = Color.WHITE; + app.SetGrayFill(1); + DrawTopFrame(app); + app.SetColorFill(actual.Darker()); + DrawBottomFrame(app); + } + else if (borderStyle == PdfBorderDictionary.STYLE_INSET) { + if (borderWidth != 0 && borderColor != null) { + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.Rectangle(borderWidth / 2, borderWidth / 2, box.Width - borderWidth, box.Height - borderWidth); + app.Stroke(); + } + // inset + app.SetGrayFill(0.5f); + DrawTopFrame(app); + app.SetGrayFill(0.75f); + DrawBottomFrame(app); + } + else { + if (borderWidth != 0 && borderColor != null) { + if (borderStyle == PdfBorderDictionary.STYLE_DASHED) + app.SetLineDash(3, 0); + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.Rectangle(borderWidth / 2, borderWidth / 2, box.Width - borderWidth, box.Height - borderWidth); + app.Stroke(); + if ((options & COMB) != 0 && maxCharacterLength > 1) { + float step = box.Width / maxCharacterLength; + float yb = borderWidth / 2; + float yt = box.Height - borderWidth / 2; + for (int k = 1; k < maxCharacterLength; ++k) { + float x = step * k; + app.MoveTo(x, yb); + app.LineTo(x, yt); + } + app.Stroke(); + } + } + } + app.RestoreState(); + return app; + } + + protected static ArrayList GetHardBreaks(String text) { + ArrayList arr = new ArrayList(); + char[] cs = text.ToCharArray(); + int len = cs.Length; + StringBuilder buf = new StringBuilder(); + for (int k = 0; k < len; ++k) { + char c = cs[k]; + if (c == '\r') { + if (k + 1 < len && cs[k + 1] == '\n') + ++k; + arr.Add(buf.ToString()); + buf = new StringBuilder(); + } + else if (c == '\n') { + arr.Add(buf.ToString()); + buf = new StringBuilder(); + } + else + buf.Append(c); + } + arr.Add(buf.ToString()); + return arr; + } + + protected static void TrimRight(StringBuilder buf) { + int len = buf.Length; + while (true) { + if (len == 0) + return; + if (buf[--len] != ' ') + return; + buf.Length = len; + } + } + + protected static ArrayList BreakLines(ArrayList breaks, BaseFont font, float fontSize, float width) { + ArrayList lines = new ArrayList(); + StringBuilder buf = new StringBuilder(); + for (int ck = 0; ck < breaks.Count; ++ck) { + buf.Length = 0; + float w = 0; + char[] cs = ((String)breaks[ck]).ToCharArray(); + int len = cs.Length; + // 0 inline first, 1 inline, 2 spaces + int state = 0; + int lastspace = -1; + char c = (char)0; + int refk = 0; + for (int k = 0; k < len; ++k) { + c = cs[k]; + switch (state) { + case 0: + w += font.GetWidthPoint(c, fontSize); + buf.Append(c); + if (w > width) { + w = 0; + if (buf.Length > 1) { + --k; + buf.Length = buf.Length - 1; + } + lines.Add(buf.ToString()); + buf.Length = 0; + refk = k; + if (c == ' ') + state = 2; + else + state = 1; + } + else { + if (c != ' ') + state = 1; + } + break; + case 1: + w += font.GetWidthPoint(c, fontSize); + buf.Append(c); + if (c == ' ') + lastspace = k; + if (w > width) { + w = 0; + if (lastspace >= 0) { + k = lastspace; + buf.Length = lastspace - refk; + TrimRight(buf); + lines.Add(buf.ToString()); + buf.Length = 0; + refk = k; + lastspace = -1; + state = 2; + } + else { + if (buf.Length > 1) { + --k; + buf.Length = buf.Length - 1; + } + lines.Add(buf.ToString()); + buf.Length = 0; + refk = k; + if (c == ' ') + state = 2; + } + } + break; + case 2: + if (c != ' ') { + w = 0; + --k; + state = 1; + } + break; + } + } + TrimRight(buf); + lines.Add(buf.ToString()); + } + return lines; + } + + private void DrawTopFrame(PdfAppearance app) { + app.MoveTo(borderWidth, borderWidth); + app.LineTo(borderWidth, box.Height - borderWidth); + app.LineTo(box.Width - borderWidth, box.Height - borderWidth); + app.LineTo(box.Width - 2 * borderWidth, box.Height - 2 * borderWidth); + app.LineTo(2 * borderWidth, box.Height - 2 * borderWidth); + app.LineTo(2 * borderWidth, 2 * borderWidth); + app.LineTo(borderWidth, borderWidth); + app.Fill(); + } + + private void DrawBottomFrame(PdfAppearance app) { + app.MoveTo(borderWidth, borderWidth); + app.LineTo(box.Width - borderWidth, borderWidth); + app.LineTo(box.Width - borderWidth, box.Height - borderWidth); + app.LineTo(box.Width - 2 * borderWidth, box.Height - 2 * borderWidth); + app.LineTo(box.Width - 2 * borderWidth, 2 * borderWidth); + app.LineTo(2 * borderWidth, 2 * borderWidth); + app.LineTo(borderWidth, borderWidth); + app.Fill(); + } + + /** Sets the border width in points. To eliminate the border + * set the border color to null. + * @param borderWidth the border width in points + */ + public float BorderWidth { + set { + this.borderWidth = value; + } + get { + return borderWidth; + } + } + + /** Sets the border style. The styles are found in PdfBorderDictionary + * and can be STYLE_SOLID, STYLE_DASHED, + * STYLE_BEVELED, STYLE_INSET and + * STYLE_UNDERLINE. + * @param borderStyle the border style + */ + public int BorderStyle { + set { + this.borderStyle = value; + } + get { + return borderStyle; + } + } + + /** Sets the border color. Set to null to remove + * the border. + * @param borderColor the border color + */ + public Color BorderColor { + set { + this.borderColor = value; + } + get { + return borderColor; + } + } + + /** Sets the background color. Set to null for + * transparent background. + * @param backgroundColor the background color + */ + public Color BackgroundColor { + set { + this.backgroundColor = value; + } + get { + return backgroundColor; + } + } + + /** Sets the text color. If null the color used + * will be black. + * @param textColor the text color + */ + public Color TextColor { + set { + this.textColor = value; + } + get { + return textColor; + } + } + + /** Sets the text font. If null then Helvetica + * will be used. + * @param font the text font + */ + public BaseFont Font { + set { + this.font = value; + } + get { + return font; + } + } + + /** Sets the font size. If 0 then auto-sizing will be used but + * only for text fields. + * @param fontSize the font size + */ + public float FontSize { + set { + this.fontSize = value; + } + get { + return fontSize; + } + } + + /** Sets the text horizontal alignment. It can be Element.ALIGN_LEFT, + * Element.ALIGN_CENTER and Element.ALIGN_RIGHT. + * @param alignment the text horizontal alignment + */ + public int Alignment { + set { + this.alignment = value; + } + get { + return alignment; + } + } + + /** Sets the text for text fields. + * @param text the text + */ + public string Text { + set { + this.text = value; + } + get { + return text; + } + } + + /** Sets the field dimension and position. + * @param box the field dimension and position + */ + public Rectangle Box { + set { + if (value == null) + box = null; + else { + box = new Rectangle(value); + box.Normalize(); + } + } + get { + return box; + } + } + + /** Sets the field rotation. This value should be the same as + * the page rotation where the field will be shown. + * @param rotation the field rotation + */ + public int Rotation { + set { + if (value % 90 != 0) + throw new ArgumentException("Rotation must be a multiple of 90."); + rotation = (value % 360); + if (rotation < 0) + rotation += 360; + } + get { + return rotation; + } + } + + /** Convenience method to set the field rotation the same as the + * page rotation. + * @param page the page + */ + public void SetRotationFromPage(Rectangle page) { + Rotation = page.Rotation; + } + + /** Sets the field visibility flag. This flags can be one of + * VISIBLE, HIDDEN, VISIBLE_BUT_DOES_NOT_PRINT + * and HIDDEN_BUT_PRINTABLE. + * @param visibility field visibility flag + */ + public int Visibility { + set { + this.visibility = value; + } + get { + return visibility; + } + } + + /** Sets the field name. + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public string FieldName { + set { + this.fieldName = value; + } + get { + return fieldName; + } + } + + /** Sets the option flags. The option flags can be a combination by oring of + * READ_ONLY, REQUIRED, + * MULTILINE, DO_NOT_SCROLL, + * PASSWORD, FILE_SELECTION, + * DO_NOT_SPELL_CHECK and EDIT. + * @param options the option flags + */ + public int Options { + set { + this.options = value; + } + get { + return options; + } + } + + /** Sets the maximum length of the field’s text, in characters. + * It is only meaningful for text fields. + * @param maxCharacterLength the maximum length of the field’s text, in characters + */ + public int MaxCharacterLength { + set { + this.maxCharacterLength = value; + } + get { + return maxCharacterLength; + } + } + + public PdfWriter Writer { + get { + return writer; + } + set { + writer = value; + } + } + + /** + * Moves the field keys from from to to. The moved keys + * are removed from from. + * @param from the source + * @param to the destination. It may be null + */ + public static void MoveFields(PdfDictionary from, PdfDictionary to) { + PdfName[] keys = new PdfName[from.Size]; + foreach (PdfName key in keys) { + if (fieldKeys.ContainsKey(key)) { + if (to != null) + to.Put(key, from.Get(key)); + from.Remove(key); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BaseFont.cs b/iTechSharp/iTextSharp/text/pdf/BaseFont.cs new file mode 100644 index 0000000..c2b27ca --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BaseFont.cs @@ -0,0 +1,1433 @@ +using System; +using System.Globalization; +using System.Reflection; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.xml.simpleparser; + +/* + * $Id: BaseFont.cs,v 1.17 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2000-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + ///

+ /// Summary description for BaseFont. + /// + public abstract class BaseFont { + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER = "Courier"; + + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER_BOLD = "Courier-Bold"; + + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER_OBLIQUE = "Courier-Oblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER_BOLDOBLIQUE = "Courier-BoldOblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA = "Helvetica"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA_BOLD = "Helvetica-Bold"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA_OBLIQUE = "Helvetica-Oblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA_BOLDOBLIQUE = "Helvetica-BoldOblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string SYMBOL = "Symbol"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_ROMAN = "Times-Roman"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_BOLD = "Times-Bold"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_ITALIC = "Times-Italic"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_BOLDITALIC = "Times-BoldItalic"; + + /** This is a possible value of a base 14 type 1 font */ + public const string ZAPFDINGBATS = "ZapfDingbats"; + + /** The maximum height above the baseline reached by glyphs in this + * font, excluding the height of glyphs for accented characters. + */ + public const int ASCENT = 1; + /** The y coordinate of the top of flat capital letters, measured from + * the baseline. + */ + public const int CAPHEIGHT = 2; + /** The maximum depth below the baseline reached by glyphs in this + * font. The value is a negative number. + */ + public const int DESCENT = 3; + /** The angle, expressed in degrees counterclockwise from the vertical, + * of the dominant vertical strokes of the font. The value is + * negative for fonts that slope to the right, as almost all italic fonts do. + */ + public const int ITALICANGLE = 4; + /** The lower left x glyph coordinate. + */ + public const int BBOXLLX = 5; + /** The lower left y glyph coordinate. + */ + public const int BBOXLLY = 6; + /** The upper right x glyph coordinate. + */ + public const int BBOXURX = 7; + /** The upper right y glyph coordinate. + */ + public const int BBOXURY = 8; + /** java.awt.Font property */ + public const int AWT_ASCENT = 9; + /** java.awt.Font property */ + public const int AWT_DESCENT = 10; + /** java.awt.Font property */ + public const int AWT_LEADING = 11; + /** java.awt.Font property */ + public const int AWT_MAXADVANCE = 12; + /** + * The undeline position. Usually a negative value. + */ + public const int UNDERLINE_POSITION = 13; + /** + * The underline thickness. + */ + public const int UNDERLINE_THICKNESS = 14; + /** + * The strikethrough position. + */ + public const int STRIKETHROUGH_POSITION = 15; + /** + * The strikethrough thickness. + */ + public const int STRIKETHROUGH_THICKNESS = 16; + /** + * The recommended vertical size for subscripts for this font. + */ + public const int SUBSCRIPT_SIZE = 17; + /** + * The recommended vertical offset from the baseline for subscripts for this font. Usually a negative value. + */ + public const int SUBSCRIPT_OFFSET = 18; + /** + * The recommended vertical size for superscripts for this font. + */ + public const int SUPERSCRIPT_SIZE = 19; + /** + * The recommended vertical offset from the baseline for superscripts for this font. + */ + public const int SUPERSCRIPT_OFFSET = 20; + + /** The font is Type 1. + */ + public const int FONT_TYPE_T1 = 0; + /** The font is True Type with a standard encoding. + */ + public const int FONT_TYPE_TT = 1; + /** The font is CJK. + */ + public const int FONT_TYPE_CJK = 2; + /** The font is True Type with a Unicode encoding. + */ + public const int FONT_TYPE_TTUNI = 3; + /** A font already inside the document. + */ + public const int FONT_TYPE_DOCUMENT = 4; + /** A Type3 font. + */ + public const int FONT_TYPE_T3 = 5; + + /** The Unicode encoding with horizontal writing. + */ + public const string IDENTITY_H = "Identity-H"; + /** The Unicode encoding with vertical writing. + */ + public const string IDENTITY_V = "Identity-V"; + + /** A possible encoding. */ + public const string CP1250 = "Cp1250"; + + /** A possible encoding. */ + public const string CP1252 = "Cp1252"; + + /** A possible encoding. */ + public const string CP1257 = "Cp1257"; + + /** A possible encoding. */ + public const string WINANSI = "Cp1252"; + + /** A possible encoding. */ + public const string MACROMAN = "MacRoman"; + + public static readonly int[] CHAR_RANGE_LATIN = {0, 0x17f, 0x2000, 0x206f, 0x20a0, 0x20cf, 0xfb00, 0xfb06}; + public static readonly int[] CHAR_RANGE_ARABIC = {0, 0x7f, 0x0600, 0x067f, 0x20a0, 0x20cf, 0xfb50, 0xfbff, 0xfe70, 0xfeff}; + public static readonly int[] CHAR_RANGE_HEBREW = {0, 0x7f, 0x0590, 0x05ff, 0x20a0, 0x20cf, 0xfb1d, 0xfb4f}; + public static readonly int[] CHAR_RANGE_CYRILLIC = {0, 0x7f, 0x0400, 0x052f, 0x2000, 0x206f, 0x20a0, 0x20cf}; + + /** if the font has to be embedded */ + public const bool EMBEDDED = true; + + /** if the font doesn't have to be embedded */ + public const bool NOT_EMBEDDED = false; + /** if the font has to be cached */ + public const bool CACHED = true; + /** if the font doesn't have to be cached */ + public const bool NOT_CACHED = false; + + /** The path to the font resources. */ + public const string RESOURCE_PATH = "iTextSharp.text.pdf.fonts."; + /** The fake CID code that represents a newline. */ + public const char CID_NEWLINE = '\u7fff'; + + protected ArrayList subsetRanges; + + /** The font type. + */ + internal int fontType; + /** a not defined character in a custom PDF encoding */ + public const string notdef = ".notdef"; + + /** table of characters widths for this encoding */ + protected int[] widths = new int[256]; + + /** encoding names */ + protected string[] differences = new string[256]; + /** same as differences but with the unicode codes */ + protected char[] unicodeDifferences = new char[256]; + protected int[][] charBBoxes = new int[256][]; + /** encoding used with this font */ + protected string encoding; + + /** true if the font is to be embedded in the PDF */ + protected bool embedded; + + /** + * true if the font must use it's built in encoding. In that case the + * encoding is only used to map a char to the position inside + * the font, not to the expected char name. + */ + protected bool fontSpecific = true; + + /** cache for the fonts already used. */ + protected static Hashtable fontCache = new Hashtable(); + + /** list of the 14 built in fonts. */ + protected static Hashtable BuiltinFonts14 = new Hashtable(); + + /** Forces the output of the width array. Only matters for the 14 + * built-in fonts. + */ + protected bool forceWidthsOutput = false; + + /** Converts char directly to byte + * by casting. + */ + protected bool directTextToByte = false; + + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. + */ + protected bool subset = true; + + protected bool fastWinansi = false; + + /** + * Custom encodings use this map to key the Unicode character + * to the single byte code. + */ + protected IntHashtable specialMap; + + protected static internal ArrayList resourceSearch = ArrayList.Synchronized(new ArrayList()); + + private static Random random = new Random(); + + static BaseFont() { + BuiltinFonts14.Add(COURIER, PdfName.COURIER); + BuiltinFonts14.Add(COURIER_BOLD, PdfName.COURIER_BOLD); + BuiltinFonts14.Add(COURIER_BOLDOBLIQUE, PdfName.COURIER_BOLDOBLIQUE); + BuiltinFonts14.Add(COURIER_OBLIQUE, PdfName.COURIER_OBLIQUE); + BuiltinFonts14.Add(HELVETICA, PdfName.HELVETICA); + BuiltinFonts14.Add(HELVETICA_BOLD, PdfName.HELVETICA_BOLD); + BuiltinFonts14.Add(HELVETICA_BOLDOBLIQUE, PdfName.HELVETICA_BOLDOBLIQUE); + BuiltinFonts14.Add(HELVETICA_OBLIQUE, PdfName.HELVETICA_OBLIQUE); + BuiltinFonts14.Add(SYMBOL, PdfName.SYMBOL); + BuiltinFonts14.Add(TIMES_ROMAN, PdfName.TIMES_ROMAN); + BuiltinFonts14.Add(TIMES_BOLD, PdfName.TIMES_BOLD); + BuiltinFonts14.Add(TIMES_BOLDITALIC, PdfName.TIMES_BOLDITALIC); + BuiltinFonts14.Add(TIMES_ITALIC, PdfName.TIMES_ITALIC); + BuiltinFonts14.Add(ZAPFDINGBATS, PdfName.ZAPFDINGBATS); + } + + /** Generates the PDF stream with the Type1 and Truetype fonts returning + * a PdfStream. + */ + internal class StreamFont : PdfStream { + + /** Generates the PDF stream with the Type1 and Truetype fonts returning + * a PdfStream. + * @param contents the content of the stream + * @param lengths an array of int that describes the several lengths of each part of the font + */ + internal StreamFont(byte[] contents, int[] lengths) { + bytes = contents; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + for (int k = 0; k < lengths.Length; ++k) { + Put(new PdfName("Length" + (k + 1)), new PdfNumber(lengths[k])); + } + FlateCompress(); + } + + internal StreamFont(byte[] contents, string subType) { + bytes = contents; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + if (subType != null) + Put(PdfName.SUBTYPE, new PdfName(subType)); + FlateCompress(); + } + } + + /** + *Creates new BaseFont + */ + protected BaseFont() { + } + + /** + * Creates a new font. This will always be the default Helvetica font (not embedded). + * This method is introduced because Helvetica is used in many examples. + * @return a BaseFont object (Helvetica, Winansi, not embedded) + * @throws IOException This shouldn't occur ever + * @throws DocumentException This shouldn't occur ever + * @since 2.1.1 + */ + public static BaseFont CreateFont() { + return CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED); + } + /** + * Creates a new font. This font can be one of the 14 built in types, + * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the + * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier + * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An + * example would be "STSong-Light,Bold". Note that this modifiers do not work if + * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1". + * This would get the second font (indexes start at 0), in this case "MS PGothic". + *

+ * The fonts are cached and if they already exist they are extracted from the cache, + * not parsed again. + *

+ * Besides the common encodings described by name, custom encodings + * can also be made. These encodings will only work for the single byte fonts + * Type1 and TrueType. The encoding string starts with a '#' + * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list + * of hex values representing the Unicode codes that compose that encoding.
+ * The "simple" encoding is recommended for TrueType fonts + * as the "full" encoding risks not matching the character with the right glyph + * if not done with care.
+ * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be + * described by non standard names like the Tex math fonts. Each group of three elements + * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character + * used to access the glyph. The space must be assigned to character position 32 otherwise + * text justification will not work. + *

+ * Example for a "simple" encoding that includes the Unicode + * character space, A, B and ecyrillic: + *

+        * "# simple 32 0020 0041 0042 0454"
+        * 
+ *

+ * Example for a "full" encoding for a Type1 Tex font: + *

+        * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
+        * 
+ *

+ * This method calls:
+ *

+        * createFont(name, encoding, embedded, true, null, null);
+        * 
+ * @param name the name of the font or it's location on file + * @param encoding the encoding to be applied to this font + * @param embedded true if the font is to be embedded in the PDF + * @return returns a new font. This font may come from the cache + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + public static BaseFont CreateFont(string name, string encoding, bool embedded) { + return CreateFont(name, encoding, embedded, true, null, null); + } + + /** Creates a new font. This font can be one of the 14 built in types, + * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the + * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier + * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An + * example would be "STSong-Light,Bold". Note that this modifiers do not work if + * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1". + * This would get the second font (indexes start at 0), in this case "MS PGothic". + *

+ * The fonts may or may not be cached depending on the flag cached. + * If the byte arrays are present the font will be + * read from them instead of the name. A name is still required to identify + * the font type. + *

+ * Besides the common encodings described by name, custom encodings + * can also be made. These encodings will only work for the single byte fonts + * Type1 and TrueType. The encoding string starts with a '#' + * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list + * of hex values representing the Unicode codes that compose that encoding.
+ * The "simple" encoding is recommended for TrueType fonts + * as the "full" encoding risks not matching the character with the right glyph + * if not done with care.
+ * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be + * described by non standard names like the Tex math fonts. Each group of three elements + * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character + * used to access the glyph. The space must be assigned to character position 32 otherwise + * text justification will not work. + *

+ * Example for a "simple" encoding that includes the Unicode + * character space, A, B and ecyrillic: + *

+        * "# simple 32 0020 0041 0042 0454"
+        * 
+ *

+ * Example for a "full" encoding for a Type1 Tex font: + *

+        * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
+        * 
+ * @param name the name of the font or it's location on file + * @param encoding the encoding to be applied to this font + * @param embedded true if the font is to be embedded in the PDF + * @param cached true if the font comes from the cache or is added to + * the cache if new, false if the font is always created new + * @param ttfAfm the true type font or the afm in a byte array + * @param pfb the pfb in a byte array + * @return returns a new font. This font may come from the cache but only if cached + * is true, otherwise it will always be created new + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + public static BaseFont CreateFont(string name, string encoding, bool embedded, bool cached, byte[] ttfAfm, byte[] pfb) { + return CreateFont(name, encoding, embedded, cached, ttfAfm, pfb, false); + } + + /** Creates a new font. This font can be one of the 14 built in types, + * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the + * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier + * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An + * example would be "STSong-Light,Bold". Note that this modifiers do not work if + * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1". + * This would get the second font (indexes start at 0), in this case "MS PGothic". + *

+ * The fonts may or may not be cached depending on the flag cached. + * If the byte arrays are present the font will be + * read from them instead of the name. A name is still required to identify + * the font type. + *

+ * Besides the common encodings described by name, custom encodings + * can also be made. These encodings will only work for the single byte fonts + * Type1 and TrueType. The encoding string starts with a '#' + * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list + * of hex values representing the Unicode codes that compose that encoding.
+ * The "simple" encoding is recommended for TrueType fonts + * as the "full" encoding risks not matching the character with the right glyph + * if not done with care.
+ * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be + * described by non standard names like the Tex math fonts. Each group of three elements + * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character + * used to access the glyph. The space must be assigned to character position 32 otherwise + * text justification will not work. + *

+ * Example for a "simple" encoding that includes the Unicode + * character space, A, B and ecyrillic: + *

+        * "# simple 32 0020 0041 0042 0454"
+        * 
+ *

+ * Example for a "full" encoding for a Type1 Tex font: + *

+        * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
+        * 
+ * @param name the name of the font or it's location on file + * @param encoding the encoding to be applied to this font + * @param embedded true if the font is to be embedded in the PDF + * @param cached true if the font comes from the cache or is added to + * the cache if new, false if the font is always created new + * @param ttfAfm the true type font or the afm in a byte array + * @param pfb the pfb in a byte array + * @param noThrow if true will not throw an exception if the font is not recognized and will return null, if false will throw + * an exception if the font is not recognized. Note that even if true an exception may be thrown in some circumstances. + * This parameter is useful for FontFactory that may have to check many invalid font names before finding the right one + * @return returns a new font. This font may come from the cache but only if cached + * is true, otherwise it will always be created new + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + public static BaseFont CreateFont(string name, string encoding, bool embedded, bool cached, byte[] ttfAfm, byte[] pfb, bool noThrow) { + string nameBase = GetBaseName(name); + encoding = NormalizeEncoding(encoding); + bool isBuiltinFonts14 = BuiltinFonts14.ContainsKey(name); + bool isCJKFont = isBuiltinFonts14 ? false : CJKFont.IsCJKFont(nameBase, encoding); + if (isBuiltinFonts14 || isCJKFont) + embedded = false; + else if (encoding.Equals(IDENTITY_H) || encoding.Equals(IDENTITY_V)) + embedded = true; + BaseFont fontFound = null; + BaseFont fontBuilt = null; + string key = name + "\n" + encoding + "\n" + embedded; + if (cached) { + lock (fontCache) { + fontFound = (BaseFont)fontCache[key]; + } + if (fontFound != null) + return fontFound; + } + if (isBuiltinFonts14 || name.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".afm") || name.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".pfm")) { + fontBuilt = new Type1Font(name, encoding, embedded, ttfAfm, pfb); + fontBuilt.fastWinansi = encoding.Equals(CP1252); + } + else if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) { + if (encoding.Equals(IDENTITY_H) || encoding.Equals(IDENTITY_V)) + fontBuilt = new TrueTypeFontUnicode(name, encoding, embedded, ttfAfm); + else { + fontBuilt = new TrueTypeFont(name, encoding, embedded, ttfAfm); + fontBuilt.fastWinansi = encoding.Equals(CP1252); + } + } + else if (isCJKFont) + fontBuilt = new CJKFont(name, encoding, embedded); + else if (noThrow) + return null; + else + throw new DocumentException("Font '" + name + "' with '" + encoding + "' is not recognized."); + if (cached) { + lock (fontCache) { + fontFound = (BaseFont)fontCache[key]; + if (fontFound != null) + return fontFound; + fontCache.Add(key, fontBuilt); + } + } + return fontBuilt; + } + + /** + * Creates a font based on an existing document font. The created font font may not + * behave as expected, depending on the encoding or subset. + * @param fontRef the reference to the document font + * @return the font + */ + public static BaseFont CreateFont(PRIndirectReference fontRef) { + return new DocumentFont(fontRef); + } + + /** + * Gets the name without the modifiers Bold, Italic or BoldItalic. + * @param name the full name of the font + * @return the name without the modifiers Bold, Italic or BoldItalic + */ + protected static string GetBaseName(string name) { + if (name.EndsWith(",Bold")) + return name.Substring(0, name.Length - 5); + else if (name.EndsWith(",Italic")) + return name.Substring(0, name.Length - 7); + else if (name.EndsWith(",BoldItalic")) + return name.Substring(0, name.Length - 11); + else + return name; + } + + /** + * Normalize the encoding names. "winansi" is changed to "Cp1252" and + * "macroman" is changed to "MacRoman". + * @param enc the encoding to be normalized + * @return the normalized encoding + */ + protected static string NormalizeEncoding(string enc) { + if (enc.Equals("winansi") || enc.Equals("")) + return CP1252; + else if (enc.Equals("macroman")) + return MACROMAN; + int n = IanaEncodings.GetEncodingNumber(enc); + if (n == 1252) + return CP1252; + if (n == 10000) + return MACROMAN; + return enc; + } + + /** + * Creates the widths and the differences arrays + * @throws UnsupportedEncodingException the encoding is not supported + */ + protected void CreateEncoding() { + if (encoding.StartsWith("#")) { + specialMap = new IntHashtable(); + StringTokenizer tok = new StringTokenizer(encoding.Substring(1), " ,\t\n\r\f"); + if (tok.NextToken().Equals("full")) { + while (tok.HasMoreTokens()) { + String order = tok.NextToken(); + String name = tok.NextToken(); + char uni = (char)int.Parse(tok.NextToken(), NumberStyles.HexNumber); + int orderK; + if (order.StartsWith("'")) + orderK = (int)order[1]; + else + orderK = int.Parse(order); + orderK %= 256; + specialMap[(int)uni] = orderK; + differences[orderK] = name; + unicodeDifferences[orderK] = uni; + widths[orderK] = GetRawWidth((int)uni, name); + charBBoxes[orderK] = GetRawCharBBox((int)uni, name); + } + } + else { + int k = 0; + if (tok.HasMoreTokens()) + k = int.Parse(tok.NextToken()); + while (tok.HasMoreTokens() && k < 256) { + String hex = tok.NextToken(); + int uni = int.Parse(hex, NumberStyles.HexNumber) % 0x10000; + String name = GlyphList.UnicodeToName(uni); + if (name != null) { + specialMap[uni] = k; + differences[k] = name; + unicodeDifferences[k] = (char)uni; + widths[k] = GetRawWidth(uni, name); + charBBoxes[k] = GetRawCharBBox(uni, name); + ++k; + } + } + } + for (int k = 0; k < 256; ++k) { + if (differences[k] == null) { + differences[k] = notdef; + } + } + } + else if (fontSpecific) { + for (int k = 0; k < 256; ++k) { + widths[k] = GetRawWidth(k, null); + charBBoxes[k] = GetRawCharBBox(k, null); + } + } + else { + string s; + string name; + char c; + byte[] b = new byte[1]; + for (int k = 0; k < 256; ++k) { + b[0] = (byte)k; + s = PdfEncodings.ConvertToString(b, encoding); + if (s.Length > 0) { + c = s[0]; + } + else { + c = '?'; + } + name = GlyphList.UnicodeToName((int)c); + if (name == null) + name = notdef; + differences[k] = name; + this.UnicodeDifferences[k] = c; + widths[k] = GetRawWidth((int)c, name); + charBBoxes[k] = GetRawCharBBox((int)c, name); + } + } + } + + /** + * Gets the width from the font according to the Unicode char c + * or the name. If the name is null it's a symbolic font. + * @param c the unicode char + * @param name the glyph name + * @return the width of the char + */ + internal abstract int GetRawWidth(int c, string name); + + /** + * Gets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @return the kerning to be applied + */ + public abstract int GetKerning(int char1, int char2); + + /** + * Sets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @param kern the kerning to apply in normalized 1000 units + * @return true if the kerning was applied, false otherwise + */ + public abstract bool SetKerning(int char1, int char2, int kern); + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public virtual int GetWidth(int char1) { + if (fastWinansi) { + if (char1 < 128 || (char1 >= 160 && char1 <= 255)) + return widths[char1]; + else + return widths[PdfEncodings.winansi[char1]]; + } + else { + int total = 0; + byte[] mbytes = ConvertToBytes((char)char1); + for (int k = 0; k < mbytes.Length; ++k) + total += widths[0xff & mbytes[k]]; + return total; + } + } + + /** + * Gets the width of a string in normalized 1000 units. + * @param text the string to get the witdth of + * @return the width in normalized 1000 units + */ + public virtual int GetWidth(string text) { + int total = 0; + if (fastWinansi) { + int len = text.Length; + for (int k = 0; k < len; ++k) { + char char1 = text[k]; + if (char1 < 128 || (char1 >= 160 && char1 <= 255)) + total += widths[char1]; + else + total += widths[PdfEncodings.winansi[char1]]; + } + return total; + } + else { + byte[] mbytes = ConvertToBytes(text); + for (int k = 0; k < mbytes.Length; ++k) + total += widths[0xff & mbytes[k]]; + } + return total; + } + + /** + * Gets the descent of a String in normalized 1000 units. The descent will always be + * less than or equal to zero even if all the characters have an higher descent. + * @param text the String to get the descent of + * @return the dexcent in normalized 1000 units + */ + public int GetDescent(String text) { + int min = 0; + char[] chars = text.ToCharArray(); + for (int k = 0; k < chars.Length; ++k) { + int[] bbox = GetCharBBox(chars[k]); + if (bbox != null && bbox[1] < min) + min = bbox[1]; + } + return min; + } + + /** + * Gets the ascent of a String in normalized 1000 units. The ascent will always be + * greater than or equal to zero even if all the characters have a lower ascent. + * @param text the String to get the ascent of + * @return the ascent in normalized 1000 units + */ + public int GetAscent(String text) { + int max = 0; + char[] chars = text.ToCharArray(); + for (int k = 0; k < chars.Length; ++k) { + int[] bbox = GetCharBBox(chars[k]); + if (bbox != null && bbox[3] > max) + max = bbox[3]; + } + return max; + } + + /** + * Gets the descent of a String in points. The descent will always be + * less than or equal to zero even if all the characters have an higher descent. + * @param text the String to get the descent of + * @param fontSize the size of the font + * @return the dexcent in points + */ + public float GetDescentPoint(String text, float fontSize) + { + return (float)GetDescent(text) * 0.001f * fontSize; + } + + /** + * Gets the ascent of a String in points. The ascent will always be + * greater than or equal to zero even if all the characters have a lower ascent. + * @param text the String to get the ascent of + * @param fontSize the size of the font + * @return the ascent in points + */ + public float GetAscentPoint(String text, float fontSize) + { + return (float)GetAscent(text) * 0.001f * fontSize; + } + + /** + * Gets the width of a String in points taking kerning + * into account. + * @param text the String to get the witdth of + * @param fontSize the font size + * @return the width in points + */ + public float GetWidthPointKerned(String text, float fontSize) { + float size = (float)GetWidth(text) * 0.001f * fontSize; + if (!HasKernPairs()) + return size; + int len = text.Length - 1; + int kern = 0; + char[] c = text.ToCharArray(); + for (int k = 0; k < len; ++k) { + kern += GetKerning(c[k], c[k + 1]); + } + return size + kern * 0.001f * fontSize; + } + + /** + * Gets the width of a string in points. + * @param text the string to get the witdth of + * @param fontSize the font size + * @return the width in points + */ + public float GetWidthPoint(string text, float fontSize) { + return (float)GetWidth(text) * 0.001f * fontSize; + } + + /** + * Gets the width of a char in points. + * @param char1 the char to get the witdth of + * @param fontSize the font size + * @return the width in points + */ + public float GetWidthPoint(int char1, float fontSize) { + return GetWidth(char1) * 0.001f * fontSize; + } + + /** + * Converts a string to a byte array according + * to the font's encoding. + * @param text the string to be converted + * @return an array of byte representing the conversion according to the font's encoding + */ + internal virtual byte[] ConvertToBytes(string text) { + if (directTextToByte) + return PdfEncodings.ConvertToBytes(text, null); + if (specialMap != null) { + byte[] b = new byte[text.Length]; + int ptr = 0; + int length = text.Length; + for (int k = 0; k < length; ++k) { + char c = text[k]; + if (specialMap.ContainsKey((int)c)) + b[ptr++] = (byte)specialMap[(int)c]; + } + if (ptr < length) { + byte[] b2 = new byte[ptr]; + System.Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + else + return b; + } + return PdfEncodings.ConvertToBytes(text, encoding); + } + + /** + * Converts a char to a byte array according + * to the font's encoding. + * @param text the String to be converted + * @return an array of byte representing the conversion according to the font's encoding + */ + internal virtual byte[] ConvertToBytes(int char1) { + if (directTextToByte) + return PdfEncodings.ConvertToBytes((char)char1, null); + if (specialMap != null) { + if (specialMap.ContainsKey(char1)) + return new byte[]{(byte)specialMap[(int)char1]}; + else + return new byte[0]; + } + return PdfEncodings.ConvertToBytes((char)char1, encoding); + } + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param params several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + */ + internal abstract void WriteFont(PdfWriter writer, PdfIndirectReference piRef, Object[] oParams); + + /** Gets the encoding used to convert string into byte[]. + * @return the encoding name + */ + public string Encoding { + get { + return encoding; + } + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT, + * ITALICANGLE, BBOXLLX, BBOXLLY, BBOXURX + * and BBOXURY. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + */ + public abstract float GetFontDescriptor(int key, float fontSize); + + /** Gets the font type. The font types can be: FONT_TYPE_T1, + * FONT_TYPE_TT, FONT_TYPE_CJK and FONT_TYPE_TTUNI. + * @return the font type + */ + public int FontType { + get { + return fontType; + } + + set { + fontType = value; + } + } + + /** Gets the embedded flag. + * @return true if the font is embedded. + */ + public bool IsEmbedded() { + return embedded; + } + + /** Gets the symbolic flag of the font. + * @return true if the font is symbolic + */ + public bool IsFontSpecific() { + return fontSpecific; + } + + /** Creates a unique subset prefix to be added to the font name when the font is embedded and subset. + * @return the subset prefix + */ + internal static string CreateSubsetPrefix() { + char[] s = new char[7]; + lock (random) { + for (int k = 0; k < 6; ++k) + s[k] = (char)(random.Next('A', 'Z' + 1)); + } + s[6] = '+'; + return new String(s); + } + + /** Gets the Unicode character corresponding to the byte output to the pdf stream. + * @param index the byte index + * @return the Unicode character + */ + internal char GetUnicodeDifferences(int index) { + return unicodeDifferences[index]; + } + + /** Gets the postscript font name. + * @return the postscript font name + */ + public abstract string PostscriptFontName { + get; + set; + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public abstract string[][] FullFontName { + get; + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public abstract string[][] AllNameEntries{ + get; + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @param name the name of the font + * @param encoding the encoding of the font + * @param ttfAfm the true type font or the afm in a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return the full name of the font + */ + public static string[][] GetFullFontName(string name, string encoding, byte[] ttfAfm) { + string nameBase = GetBaseName(name); + BaseFont fontBuilt = null; + if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) + fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true); + else + fontBuilt = CreateFont(name, encoding, false, false, ttfAfm, null); + return fontBuilt.FullFontName; + } + + /** Gets all the names from the font. Only the required tables are read. + * @param name the name of the font + * @param encoding the encoding of the font + * @param ttfAfm the true type font or the afm in a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return an array of Object[] built with {getPostscriptFontName(), GetFamilyFontName(), GetFullFontName()} + */ + public static Object[] GetAllFontNames(String name, String encoding, byte[] ttfAfm) { + String nameBase = GetBaseName(name); + BaseFont fontBuilt = null; + if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) + fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true); + else + fontBuilt = CreateFont(name, encoding, false, false, ttfAfm, null); + return new Object[]{fontBuilt.PostscriptFontName, fontBuilt.FamilyFontName, fontBuilt.FullFontName}; + } + + /** Gets all the entries of the namestable from the font. Only the required tables are read. + * @param name the name of the font + * @param encoding the encoding of the font + * @param ttfAfm the true type font or the afm in a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return an array of Object[] built with {getPostscriptFontName(), getFamilyFontName(), getFullFontName()} + */ + public static String[][] GetAllNameEntries(String name, String encoding, byte[] ttfAfm) { + String nameBase = GetBaseName(name); + BaseFont fontBuilt = null; + if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) + fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true); + else + fontBuilt = CreateFont(name, encoding, false, false, ttfAfm, null); + return fontBuilt.AllNameEntries; + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + */ + public abstract string[][] FamilyFontName { + get; + } + + /** Gets the code pages supported by the font. This has only meaning + * with True Type fonts. + * @return the code pages supported by the font + */ + public virtual string[] CodePagesSupported { + get { + return new string[0]; + } + } + + /** Enumerates the postscript font names present inside a + * True Type Collection. + * @param ttcFile the file name of the font + * @throws DocumentException on error + * @throws IOException on error + * @return the postscript font names + */ + public static string[] EnumerateTTCNames(string ttcFile) { + return new EnumerateTTC(ttcFile).Names; + } + + /** Enumerates the postscript font names present inside a + * True Type Collection. + * @param ttcArray the font as a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return the postscript font names + */ + public static string[] EnumerateTTCNames(byte[] ttcArray) { + return new EnumerateTTC(ttcArray).Names; + } + + /** Gets the font width array. + * @return the font width array + */ + public int[] Widths { + get { + return widths; + } + } + + /** Gets the array with the names of the characters. + * @return the array with the names of the characters + */ + public string[] Differences { + get { + return differences; + } + } + + /** Gets the array with the unicode characters. + * @return the array with the unicode characters + */ + public char[] UnicodeDifferences { + get { + return unicodeDifferences; + } + } + + /** Set to true to force the generation of the + * widths array. + * @param forceWidthsOutput true to force the generation of the + * widths array + */ + public bool ForceWidthsOutput { + set { + this.forceWidthsOutput = value; + } + get { + return forceWidthsOutput; + } + } + + /** Sets the conversion of char directly to byte + * by casting. This is a low level feature to put the bytes directly in + * the content stream without passing through string.GetBytes(). + * @param directTextToByte New value of property directTextToByte. + */ + public bool DirectTextToByte { + set { + this.directTextToByte = value; + } + get { + return directTextToByte; + } + } + + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. When set to true + * only the glyphs used will be included in the font. When set to false + * and {@link #addSubsetRange(int[])} was not called the full font will be included + * otherwise just the characters ranges will be included. + * @param subset new value of property subset + */ + public bool Subset { + set { + this.subset = value; + } + get { + return subset; + } + } + + public static void AddToResourceSearch (object obj) { + if (obj is Assembly) { + resourceSearch.Add(obj); + } + else if (obj is string) { + string f = (string)obj; + if (Directory.Exists(f) || File.Exists(f)) + resourceSearch.Add(obj); + } + } + + /** Gets the font resources. + * @param key the name of the resource + * @return the Stream to get the resource or + * null if not found + */ + public static Stream GetResourceStream(string key) { + Stream istr = null; + // Try to use resource loader to load the properties file. + try { + Assembly assm = Assembly.GetExecutingAssembly(); + istr = assm.GetManifestResourceStream(key); + } + catch { + } + if (istr != null) + return istr; + for (int k = 0; k < resourceSearch.Count; ++k) { + object obj = resourceSearch[k]; + try { + if (obj is Assembly) { + istr = ((Assembly)obj).GetManifestResourceStream(key); + if (istr != null) + return istr; + } + else if (obj is string) { + string dir = (string)obj; + try { + istr = Assembly.LoadFrom(dir).GetManifestResourceStream(key); + } + catch { + } + if (istr != null) + return istr; + string modkey = key.Replace('.', '/'); + string fullPath = Path.Combine(dir, modkey); + if (File.Exists(fullPath)) { + return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read); + } + int idx = modkey.LastIndexOf('/'); + if (idx >= 0) { + modkey = modkey.Substring(0, idx) + "." + modkey.Substring(idx + 1); + fullPath = Path.Combine(dir, modkey); + if (File.Exists(fullPath)) + return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read); + } + } + } + catch { + } + } + + return istr; + } + + /** Gets the Unicode equivalent to a CID. + * The (inexistent) CID is translated as '\n'. + * It has only meaning with CJK fonts with Identity encoding. + * @param c the CID code + * @return the Unicode equivalent + */ + public virtual int GetUnicodeEquivalent(int c) { + return c; + } + + /** Gets the CID code given an Unicode. + * It has only meaning with CJK fonts. + * @param c the Unicode + * @return the CID equivalent + */ + public virtual int GetCidCode(int c) { + return c; + } + + /** Checks if the font has any kerning pairs. + * @return true if the font has any kerning pairs + */ + public abstract bool HasKernPairs(); + + /** + * Checks if a character exists in this font. + * @param c the character to check + * @return true if the character has a glyph, + * false otherwise + */ + public virtual bool CharExists(int c) { + byte[] b = ConvertToBytes(c); + return b.Length > 0; + } + + /** + * Sets the character advance. + * @param c the character + * @param advance the character advance normalized to 1000 units + * @return true if the advance was set, + * false otherwise + */ + public virtual bool SetCharAdvance(int c, int advance) { + byte[] b = ConvertToBytes(c); + if (b.Length == 0) + return false; + widths[0xff & b[0]] = advance; + return true; + } + + private static void AddFont(PRIndirectReference fontRef, IntHashtable hits, ArrayList fonts) { + PdfObject obj = PdfReader.GetPdfObject(fontRef); + if (obj == null || !obj.IsDictionary()) + return; + PdfDictionary font = (PdfDictionary)obj; + PdfName subtype = (PdfName)PdfReader.GetPdfObject(font.Get(PdfName.SUBTYPE)); + if (!PdfName.TYPE1.Equals(subtype) && !PdfName.TRUETYPE.Equals(subtype)) + return; + PdfName name = (PdfName)PdfReader.GetPdfObject(font.Get(PdfName.BASEFONT)); + fonts.Add(new Object[]{PdfName.DecodeName(name.ToString()), fontRef}); + hits[fontRef.Number] = 1; + } + + private static void RecourseFonts(PdfDictionary page, IntHashtable hits, ArrayList fonts, int level) { + ++level; + if (level > 50) // in case we have an endless loop + return; + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(page.Get(PdfName.RESOURCES)); + if (resources == null) + return; + PdfDictionary font = (PdfDictionary)PdfReader.GetPdfObject(resources.Get(PdfName.FONT)); + if (font != null) { + foreach (PdfName key in font.Keys) { + PdfObject ft = font.Get(key); + if (ft == null || !ft.IsIndirect()) + continue; + int hit = ((PRIndirectReference)ft).Number; + if (hits.ContainsKey(hit)) + continue; + AddFont((PRIndirectReference)ft, hits, fonts); + } + } + PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(resources.Get(PdfName.XOBJECT)); + if (xobj != null) { + foreach (PdfName key in xobj.Keys) { + RecourseFonts((PdfDictionary)PdfReader.GetPdfObject(xobj.Get(key)), hits, fonts, level); + } + } + } + + /** + * Gets a list of all document fonts. Each element of the ArrayList + * contains a Object[]{String,PRIndirectReference} with the font name + * and the indirect reference to it. + * @param reader the document where the fonts are to be listed from + * @return the list of fonts and references + */ + public static ArrayList GetDocumentFonts(PdfReader reader) { + IntHashtable hits = new IntHashtable(); + ArrayList fonts = new ArrayList(); + int npages = reader.NumberOfPages; + for (int k = 1; k <= npages; ++k) + RecourseFonts(reader.GetPageN(k), hits, fonts, 1); + return fonts; + } + + /** + * Gets a list of the document fonts in a particular page. Each element of the ArrayList + * contains a Object[]{String,PRIndirectReference} with the font name + * and the indirect reference to it. + * @param reader the document where the fonts are to be listed from + * @param page the page to list the fonts from + * @return the list of fonts and references + */ + public static ArrayList GetDocumentFonts(PdfReader reader, int page) { + IntHashtable hits = new IntHashtable(); + ArrayList fonts = new ArrayList(); + RecourseFonts(reader.GetPageN(page), hits, fonts, 1); + return fonts; + } + + /** + * Gets the smallest box enclosing the character contours. It will return + * null if the font has not the information or the character has no + * contours, as in the case of the space, for example. Characters with no contours may + * also return [0,0,0,0]. + * @param c the character to get the contour bounding box from + * @return an array of four floats with the bounding box in the format [llx,lly,urx,ury] or + * null + */ + public virtual int[] GetCharBBox(int c) { + byte[] b = ConvertToBytes(c); + if (b.Length == 0) + return null; + else + return charBBoxes[b[0] & 0xff]; + } + + protected abstract int[] GetRawCharBBox(int c, String name); + + /** + * iText expects Arabic Diactrics (tashkeel) to have zero advance but some fonts, + * most notably those that come with Windows, like times.ttf, have non-zero + * advance for those characters. This method makes those character to have zero + * width advance and work correctly in the iText Arabic shaping and reordering + * context. + */ + public void CorrectArabicAdvance() { + for (char c = '\u064b'; c <= '\u0658'; ++c) + SetCharAdvance(c, 0); + SetCharAdvance('\u0670', 0); + for (char c = '\u06d6'; c <= '\u06dc'; ++c) + SetCharAdvance(c, 0); + for (char c = '\u06df'; c <= '\u06e4'; ++c) + SetCharAdvance(c, 0); + for (char c = '\u06e7'; c <= '\u06e8'; ++c) + SetCharAdvance(c, 0); + for (char c = '\u06ea'; c <= '\u06ed'; ++c) + SetCharAdvance(c, 0); + } + + /** + * Adds a character range when subsetting. The range is an int array + * where the first element is the start range inclusive and the second element is the + * end range inclusive. Several ranges are allowed in the same array. + * @param range the character range + */ + public void AddSubsetRange(int[] range) { + if (subsetRanges == null) + subsetRanges = new ArrayList(); + subsetRanges.Add(range); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/BidiLine.cs b/iTechSharp/iTextSharp/text/pdf/BidiLine.cs new file mode 100644 index 0000000..239e921 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BidiLine.cs @@ -0,0 +1,946 @@ +using System; +using System.Collections; +using System.Text; + +/* + * + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Does all the line bidirectional processing with PdfChunk assembly. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BidiLine { + private const int pieceSizeStart = 256; + + protected int runDirection; + protected int pieceSize = pieceSizeStart; + protected char[] text = new char[pieceSizeStart]; + protected PdfChunk[] detailChunks = new PdfChunk[pieceSizeStart]; + protected int totalTextLength = 0; + + protected byte[] orderLevels = new byte[pieceSizeStart]; + protected int[] indexChars = new int[pieceSizeStart]; + + protected ArrayList chunks = new ArrayList(); + protected int indexChunk = 0; + protected int indexChunkChar = 0; + protected int currentChar = 0; + + protected int storedRunDirection; + protected char[] storedText = new char[0]; + protected PdfChunk[] storedDetailChunks = new PdfChunk[0]; + protected int storedTotalTextLength = 0; + + protected byte[] storedOrderLevels = new byte[0]; + protected int[] storedIndexChars = new int[0]; + + protected int storedIndexChunk = 0; + protected int storedIndexChunkChar = 0; + protected int storedCurrentChar = 0; + + protected bool shortStore; + protected static IntHashtable mirrorChars = new IntHashtable(); + protected int arabicOptions; + + /** Creates new BidiLine */ + public BidiLine() { + } + + public BidiLine(BidiLine org) { + runDirection = org.runDirection; + pieceSize = org.pieceSize; + text = (char[])org.text.Clone(); + detailChunks = (PdfChunk[])org.detailChunks.Clone(); + totalTextLength = org.totalTextLength; + + orderLevels = (byte[])org.orderLevels.Clone(); + indexChars = (int[])org.indexChars.Clone(); + + chunks = new ArrayList(org.chunks); + indexChunk = org.indexChunk; + indexChunkChar = org.indexChunkChar; + currentChar = org.currentChar; + + storedRunDirection = org.storedRunDirection; + storedText = (char[])org.storedText.Clone(); + storedDetailChunks = (PdfChunk[])org.storedDetailChunks.Clone(); + storedTotalTextLength = org.storedTotalTextLength; + + storedOrderLevels = (byte[])org.storedOrderLevels.Clone(); + storedIndexChars = (int[])org.storedIndexChars.Clone(); + + storedIndexChunk = org.storedIndexChunk; + storedIndexChunkChar = org.storedIndexChunkChar; + storedCurrentChar = org.storedCurrentChar; + + shortStore = org.shortStore; + arabicOptions = org.arabicOptions; + } + + public bool IsEmpty() { + return (currentChar >= totalTextLength && indexChunk >= chunks.Count); + } + + public void ClearChunks() { + chunks.Clear(); + totalTextLength = 0; + currentChar = 0; + } + + public bool GetParagraph(int runDirection) { + this.runDirection = runDirection; + currentChar = 0; + totalTextLength = 0; + bool hasText = false; + char c; + char uniC; + BaseFont bf; + for (; indexChunk < chunks.Count; ++indexChunk) { + PdfChunk ck = (PdfChunk)chunks[indexChunk]; + bf = ck.Font.Font; + string s = ck.ToString(); + int len = s.Length; + for (; indexChunkChar < len; ++indexChunkChar) { + c = s[indexChunkChar]; + uniC = (char)bf.GetUnicodeEquivalent(c); + if (uniC == '\r' || uniC == '\n') { + // next condition is never true for CID + if (uniC == '\r' && indexChunkChar + 1 < len && s[indexChunkChar + 1] == '\n') + ++indexChunkChar; + ++indexChunkChar; + if (indexChunkChar >= len) { + indexChunkChar = 0; + ++indexChunk; + } + hasText = true; + if (totalTextLength == 0) + detailChunks[0] = ck; + break; + } + AddPiece(c, ck); + } + if (hasText) + break; + indexChunkChar = 0; + } + if (totalTextLength == 0) + return hasText; + + // remove trailing WS + totalTextLength = TrimRight(0, totalTextLength - 1) + 1; + if (totalTextLength == 0) + return true; + + if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { + if (orderLevels.Length < totalTextLength) { + orderLevels = new byte[pieceSize]; + indexChars = new int[pieceSize]; + } + + ArabicLigaturizer.ProcessNumbers(text, 0, totalTextLength, arabicOptions); + BidiOrder order = new BidiOrder(text, 0, totalTextLength, (sbyte)(runDirection == PdfWriter.RUN_DIRECTION_RTL ? 1 : 0)); + byte[] od = order.GetLevels(); + for (int k = 0; k < totalTextLength; ++k) { + orderLevels[k] = od[k]; + indexChars[k] = k; + } + DoArabicShapping(); + MirrorGlyphs(); + } + totalTextLength = TrimRightEx(0, totalTextLength - 1) + 1; + return true; + } + + public void AddChunk(PdfChunk chunk) { + chunks.Add(chunk); + } + + public void AddChunks(ArrayList chunks) { + this.chunks.AddRange(chunks); + } + + public void AddPiece(char c, PdfChunk chunk) { + if (totalTextLength >= pieceSize) { + char[] tempText = text; + PdfChunk[] tempDetailChunks = detailChunks; + pieceSize *= 2; + text = new char[pieceSize]; + detailChunks = new PdfChunk[pieceSize]; + Array.Copy(tempText, 0, text, 0, totalTextLength); + Array.Copy(tempDetailChunks, 0, detailChunks, 0, totalTextLength); + } + text[totalTextLength] = c; + detailChunks[totalTextLength++] = chunk; + } + + public void Save() { + if (indexChunk > 0) { + if (indexChunk >= chunks.Count) + chunks.Clear(); + else { + for (--indexChunk; indexChunk >= 0; --indexChunk) + chunks.RemoveAt(indexChunk); + } + indexChunk = 0; + } + storedRunDirection = runDirection; + storedTotalTextLength = totalTextLength; + storedIndexChunk = indexChunk; + storedIndexChunkChar = indexChunkChar; + storedCurrentChar = currentChar; + shortStore = (currentChar < totalTextLength); + if (!shortStore) { + // long save + if (storedText.Length < totalTextLength) { + storedText = new char[totalTextLength]; + storedDetailChunks = new PdfChunk[totalTextLength]; + } + Array.Copy(text, 0, storedText, 0, totalTextLength); + Array.Copy(detailChunks, 0, storedDetailChunks, 0, totalTextLength); + } + if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { + if (storedOrderLevels.Length < totalTextLength) { + storedOrderLevels = new byte[totalTextLength]; + storedIndexChars = new int[totalTextLength]; + } + Array.Copy(orderLevels, currentChar, storedOrderLevels, currentChar, totalTextLength - currentChar); + Array.Copy(indexChars, currentChar, storedIndexChars, currentChar, totalTextLength - currentChar); + } + } + + public void Restore() { + runDirection = storedRunDirection; + totalTextLength = storedTotalTextLength; + indexChunk = storedIndexChunk; + indexChunkChar = storedIndexChunkChar; + currentChar = storedCurrentChar; + if (!shortStore) { + // long restore + Array.Copy(storedText, 0, text, 0, totalTextLength); + Array.Copy(storedDetailChunks, 0, detailChunks, 0, totalTextLength); + } + if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { + Array.Copy(storedOrderLevels, currentChar, orderLevels, currentChar, totalTextLength - currentChar); + Array.Copy(storedIndexChars, currentChar, indexChars, currentChar, totalTextLength - currentChar); + } + } + + public void MirrorGlyphs() { + for (int k = 0; k < totalTextLength; ++k) { + if ((orderLevels[k] & 1) == 1) { + int mirror = mirrorChars[text[k]]; + if (mirror != 0) + text[k] = (char)mirror; + } + } + } + + public void DoArabicShapping() { + int src = 0; + int dest = 0; + for (;;) { + while (src < totalTextLength) { + char c = text[src]; + if (c >= 0x0600 && c <= 0x06ff) + break; + if (src != dest) { + text[dest] = text[src]; + detailChunks[dest] = detailChunks[src]; + orderLevels[dest] = orderLevels[src]; + } + ++src; + ++dest; + } + if (src >= totalTextLength) { + totalTextLength = dest; + return; + } + int startArabicIdx = src; + ++src; + while (src < totalTextLength) { + char c = text[src]; + if (c < 0x0600 || c > 0x06ff) + break; + ++src; + } + int arabicWordSize = src - startArabicIdx; + int size = ArabicLigaturizer.Arabic_shape(text, startArabicIdx, arabicWordSize, text, dest, arabicWordSize, arabicOptions); + if (startArabicIdx != dest) { + for (int k = 0; k < size; ++k) { + detailChunks[dest] = detailChunks[startArabicIdx]; + orderLevels[dest++] = orderLevels[startArabicIdx++]; + } + } + else + dest += size; + } + } + + public PdfLine ProcessLine(float leftX, float width, int alignment, int runDirection, int arabicOptions) { + this.arabicOptions = arabicOptions; + Save(); + bool isRTL = (runDirection == PdfWriter.RUN_DIRECTION_RTL); + if (currentChar >= totalTextLength) { + bool hasText = GetParagraph(runDirection); + if (!hasText) + return null; + if (totalTextLength == 0) { + ArrayList ar = new ArrayList(); + PdfChunk ckx = new PdfChunk("", detailChunks[0]); + ar.Add(ckx); + return new PdfLine(0, 0, 0, alignment, true, ar, isRTL); + } + } + float originalWidth = width; + int lastSplit = -1; + if (currentChar != 0) + currentChar = TrimLeftEx(currentChar, totalTextLength - 1); + int oldCurrentChar = currentChar; + int uniC = 0; + PdfChunk ck = null; + float charWidth = 0; + PdfChunk lastValidChunk = null; + bool splitChar = false; + bool surrogate = false; + for (; currentChar < totalTextLength; ++currentChar) { + ck = detailChunks[currentChar]; + surrogate = Utilities.IsSurrogatePair(text, currentChar); + if (surrogate) + uniC = ck.GetUnicodeEquivalent(Utilities.ConvertToUtf32(text, currentChar)); + else + uniC = ck.GetUnicodeEquivalent(text[currentChar]); + if (PdfChunk.NoPrint(uniC)) + continue; + if (surrogate) + charWidth = ck.GetCharWidth(uniC); + else + charWidth = ck.GetCharWidth(text[currentChar]); + splitChar = ck.IsExtSplitCharacter(oldCurrentChar, currentChar, totalTextLength, text, detailChunks); + if (splitChar && Char.IsWhiteSpace((char)uniC)) + lastSplit = currentChar; + if (width - charWidth < 0) + break; + if (splitChar) + lastSplit = currentChar; + width -= charWidth; + lastValidChunk = ck; + if (surrogate) + ++currentChar; + if (ck.IsTab()) { + Object[] tab = (Object[])ck.GetAttribute(Chunk.TAB); + float tabPosition = (float)tab[1]; + bool newLine = (bool)tab[2]; + if (newLine && tabPosition < originalWidth - width) { + return new PdfLine(0, originalWidth, width, alignment, true, CreateArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); + } + detailChunks[currentChar].AdjustLeft(leftX); + width = originalWidth - tabPosition; + } + } + if (lastValidChunk == null) { + // not even a single char fit; must output the first char + ++currentChar; + if (surrogate) + ++currentChar; + return new PdfLine(0, originalWidth, 0, alignment, false, CreateArrayOfPdfChunks(currentChar - 1, currentChar - 1), isRTL); + } + if (currentChar >= totalTextLength) { + // there was more line than text + return new PdfLine(0, originalWidth, width, alignment, true, CreateArrayOfPdfChunks(oldCurrentChar, totalTextLength - 1), isRTL); + } + int newCurrentChar = TrimRightEx(oldCurrentChar, currentChar - 1); + if (newCurrentChar < oldCurrentChar) { + // only WS + return new PdfLine(0, originalWidth, width, alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); + } + if (newCurrentChar == currentChar - 1) { // middle of word + IHyphenationEvent he = (IHyphenationEvent)lastValidChunk.GetAttribute(Chunk.HYPHENATION); + if (he != null) { + int[] word = GetWord(oldCurrentChar, newCurrentChar); + if (word != null) { + float testWidth = width + GetWidth(word[0], currentChar - 1); + String pre = he.GetHyphenatedWordPre(new String(text, word[0], word[1] - word[0]), lastValidChunk.Font.Font, lastValidChunk.Font.Size, testWidth); + String post = he.HyphenatedWordPost; + if (pre.Length > 0) { + PdfChunk extra = new PdfChunk(pre, lastValidChunk); + currentChar = word[1] - post.Length; + return new PdfLine(0, originalWidth, testWidth - lastValidChunk.Font.Width(pre), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, word[0] - 1, extra), isRTL); + } + } + } + } + if (lastSplit == -1 || lastSplit >= newCurrentChar) { + // no split point or split point ahead of end + return new PdfLine(0, originalWidth, width + GetWidth(newCurrentChar + 1, currentChar - 1), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); + } + // standard split + currentChar = lastSplit + 1; + newCurrentChar = TrimRightEx(oldCurrentChar, lastSplit); + if (newCurrentChar < oldCurrentChar) { + // only WS again + newCurrentChar = currentChar - 1; + } + return new PdfLine(0, originalWidth, originalWidth - GetWidth(oldCurrentChar, newCurrentChar), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); + } + + /** Gets the width of a range of characters. + * @param startIdx the first index to calculate + * @param lastIdx the last inclusive index to calculate + * @return the sum of all widths + */ + public float GetWidth(int startIdx, int lastIdx) { + char c = (char)0; + PdfChunk ck = null; + float width = 0; + for (; startIdx <= lastIdx; ++startIdx) { + bool surrogate = Utilities.IsSurrogatePair(text, startIdx); + if (surrogate) { + width += detailChunks[startIdx].GetCharWidth(Utilities.ConvertToUtf32(text, startIdx)); + ++startIdx; + } + else { + c = text[startIdx]; + ck = detailChunks[startIdx]; + if (PdfChunk.NoPrint(ck.GetUnicodeEquivalent(c))) + continue; + width += detailChunks[startIdx].GetCharWidth(c); + } + } + return width; + } + + public ArrayList CreateArrayOfPdfChunks(int startIdx, int endIdx) { + return CreateArrayOfPdfChunks(startIdx, endIdx, null); + } + + public ArrayList CreateArrayOfPdfChunks(int startIdx, int endIdx, PdfChunk extraPdfChunk) { + bool bidi = (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL); + if (bidi) + Reorder(startIdx, endIdx); + ArrayList ar = new ArrayList(); + PdfChunk refCk = detailChunks[startIdx]; + PdfChunk ck = null; + StringBuilder buf = new StringBuilder(); + char c; + int idx = 0; + for (; startIdx <= endIdx; ++startIdx) { + idx = bidi ? indexChars[startIdx] : startIdx; + c = text[idx]; + ck = detailChunks[idx]; + if (PdfChunk.NoPrint(ck.GetUnicodeEquivalent(c))) + continue; + if (ck.IsImage() || ck.IsSeparator() || ck.IsTab()) { + if (buf.Length > 0) { + ar.Add(new PdfChunk(buf.ToString(), refCk)); + buf = new StringBuilder(); + } + ar.Add(ck); + } + else if (ck == refCk) { + buf.Append(c); + } + else { + if (buf.Length > 0) { + ar.Add(new PdfChunk(buf.ToString(), refCk)); + buf = new StringBuilder(); + } + if (!ck.IsImage() && !ck.IsSeparator() && !ck.IsTab()) + buf.Append(c); + refCk = ck; + } + } + if (buf.Length > 0) { + ar.Add(new PdfChunk(buf.ToString(), refCk)); + } + if (extraPdfChunk != null) + ar.Add(extraPdfChunk); + return ar; + } + + public int[] GetWord(int startIdx, int idx) { + int last = idx; + int first = idx; + // forward + for (; last < totalTextLength; ++last) { + if (!char.IsLetter(text[last])) + break; + } + if (last == idx) + return null; + // backward + for (; first >= startIdx; --first) { + if (!char.IsLetter(text[first])) + break; + } + ++first; + return new int[]{first, last}; + } + + public int TrimRight(int startIdx, int endIdx) { + int idx = endIdx; + char c; + for (; idx >= startIdx; --idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c)) + break; + } + return idx; + } + + public int TrimLeft(int startIdx, int endIdx) { + int idx = startIdx; + char c; + for (; idx <= endIdx; ++idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c)) + break; + } + return idx; + } + + public int TrimRightEx(int startIdx, int endIdx) { + int idx = endIdx; + char c = (char)0; + for (; idx >= startIdx; --idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c) && !PdfChunk.NoPrint(c)) + break; + } + return idx; + } + + public int TrimLeftEx(int startIdx, int endIdx) { + int idx = startIdx; + char c = (char)0; + for (; idx <= endIdx; ++idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c) && !PdfChunk.NoPrint(c)) + break; + } + return idx; + } + + public void Reorder(int start, int end) { + byte maxLevel = orderLevels[start]; + byte minLevel = maxLevel; + byte onlyOddLevels = maxLevel; + byte onlyEvenLevels = maxLevel; + for (int k = start + 1; k <= end; ++k) { + byte b = orderLevels[k]; + if (b > maxLevel) + maxLevel = b; + else if (b < minLevel) + minLevel = b; + onlyOddLevels &= b; + onlyEvenLevels |= b; + } + if ((onlyEvenLevels & 1) == 0) // nothing to do + return; + if ((onlyOddLevels & 1) == 1) { // single inversion + Flip(start, end + 1); + return; + } + minLevel |= 1; + for (; maxLevel >= minLevel; --maxLevel) { + int pstart = start; + for (;;) { + for (;pstart <= end; ++pstart) { + if (orderLevels[pstart] >= maxLevel) + break; + } + if (pstart > end) + break; + int pend = pstart + 1; + for (; pend <= end; ++pend) { + if (orderLevels[pend] < maxLevel) + break; + } + Flip(pstart, pend); + pstart = pend + 1; + } + } + } + + public void Flip(int start, int end) { + int mid = (start + end) / 2; + --end; + for (; start < mid; ++start, --end) { + int temp = indexChars[start]; + indexChars[start] = indexChars[end]; + indexChars[end] = temp; + } + } + + public static bool IsWS(char c) { + return (c <= ' '); + } + + static BidiLine() { + mirrorChars[0x0028] = 0x0029; // LEFT PARENTHESIS + mirrorChars[0x0029] = 0x0028; // RIGHT PARENTHESIS + mirrorChars[0x003C] = 0x003E; // LESS-THAN SIGN + mirrorChars[0x003E] = 0x003C; // GREATER-THAN SIGN + mirrorChars[0x005B] = 0x005D; // LEFT SQUARE BRACKET + mirrorChars[0x005D] = 0x005B; // RIGHT SQUARE BRACKET + mirrorChars[0x007B] = 0x007D; // LEFT CURLY BRACKET + mirrorChars[0x007D] = 0x007B; // RIGHT CURLY BRACKET + mirrorChars[0x00AB] = 0x00BB; // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + mirrorChars[0x00BB] = 0x00AB; // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + mirrorChars[0x2039] = 0x203A; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + mirrorChars[0x203A] = 0x2039; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + mirrorChars[0x2045] = 0x2046; // LEFT SQUARE BRACKET WITH QUILL + mirrorChars[0x2046] = 0x2045; // RIGHT SQUARE BRACKET WITH QUILL + mirrorChars[0x207D] = 0x207E; // SUPERSCRIPT LEFT PARENTHESIS + mirrorChars[0x207E] = 0x207D; // SUPERSCRIPT RIGHT PARENTHESIS + mirrorChars[0x208D] = 0x208E; // SUBSCRIPT LEFT PARENTHESIS + mirrorChars[0x208E] = 0x208D; // SUBSCRIPT RIGHT PARENTHESIS + mirrorChars[0x2208] = 0x220B; // ELEMENT OF + mirrorChars[0x2209] = 0x220C; // NOT AN ELEMENT OF + mirrorChars[0x220A] = 0x220D; // SMALL ELEMENT OF + mirrorChars[0x220B] = 0x2208; // CONTAINS AS MEMBER + mirrorChars[0x220C] = 0x2209; // DOES NOT CONTAIN AS MEMBER + mirrorChars[0x220D] = 0x220A; // SMALL CONTAINS AS MEMBER + mirrorChars[0x2215] = 0x29F5; // DIVISION SLASH + mirrorChars[0x223C] = 0x223D; // TILDE OPERATOR + mirrorChars[0x223D] = 0x223C; // REVERSED TILDE + mirrorChars[0x2243] = 0x22CD; // ASYMPTOTICALLY EQUAL TO + mirrorChars[0x2252] = 0x2253; // APPROXIMATELY EQUAL TO OR THE IMAGE OF + mirrorChars[0x2253] = 0x2252; // IMAGE OF OR APPROXIMATELY EQUAL TO + mirrorChars[0x2254] = 0x2255; // COLON EQUALS + mirrorChars[0x2255] = 0x2254; // EQUALS COLON + mirrorChars[0x2264] = 0x2265; // LESS-THAN OR EQUAL TO + mirrorChars[0x2265] = 0x2264; // GREATER-THAN OR EQUAL TO + mirrorChars[0x2266] = 0x2267; // LESS-THAN OVER EQUAL TO + mirrorChars[0x2267] = 0x2266; // GREATER-THAN OVER EQUAL TO + mirrorChars[0x2268] = 0x2269; // [BEST FIT] LESS-THAN BUT NOT EQUAL TO + mirrorChars[0x2269] = 0x2268; // [BEST FIT] GREATER-THAN BUT NOT EQUAL TO + mirrorChars[0x226A] = 0x226B; // MUCH LESS-THAN + mirrorChars[0x226B] = 0x226A; // MUCH GREATER-THAN + mirrorChars[0x226E] = 0x226F; // [BEST FIT] NOT LESS-THAN + mirrorChars[0x226F] = 0x226E; // [BEST FIT] NOT GREATER-THAN + mirrorChars[0x2270] = 0x2271; // [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO + mirrorChars[0x2271] = 0x2270; // [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO + mirrorChars[0x2272] = 0x2273; // [BEST FIT] LESS-THAN OR EQUIVALENT TO + mirrorChars[0x2273] = 0x2272; // [BEST FIT] GREATER-THAN OR EQUIVALENT TO + mirrorChars[0x2274] = 0x2275; // [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO + mirrorChars[0x2275] = 0x2274; // [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO + mirrorChars[0x2276] = 0x2277; // LESS-THAN OR GREATER-THAN + mirrorChars[0x2277] = 0x2276; // GREATER-THAN OR LESS-THAN + mirrorChars[0x2278] = 0x2279; // NEITHER LESS-THAN NOR GREATER-THAN + mirrorChars[0x2279] = 0x2278; // NEITHER GREATER-THAN NOR LESS-THAN + mirrorChars[0x227A] = 0x227B; // PRECEDES + mirrorChars[0x227B] = 0x227A; // SUCCEEDS + mirrorChars[0x227C] = 0x227D; // PRECEDES OR EQUAL TO + mirrorChars[0x227D] = 0x227C; // SUCCEEDS OR EQUAL TO + mirrorChars[0x227E] = 0x227F; // [BEST FIT] PRECEDES OR EQUIVALENT TO + mirrorChars[0x227F] = 0x227E; // [BEST FIT] SUCCEEDS OR EQUIVALENT TO + mirrorChars[0x2280] = 0x2281; // [BEST FIT] DOES NOT PRECEDE + mirrorChars[0x2281] = 0x2280; // [BEST FIT] DOES NOT SUCCEED + mirrorChars[0x2282] = 0x2283; // SUBSET OF + mirrorChars[0x2283] = 0x2282; // SUPERSET OF + mirrorChars[0x2284] = 0x2285; // [BEST FIT] NOT A SUBSET OF + mirrorChars[0x2285] = 0x2284; // [BEST FIT] NOT A SUPERSET OF + mirrorChars[0x2286] = 0x2287; // SUBSET OF OR EQUAL TO + mirrorChars[0x2287] = 0x2286; // SUPERSET OF OR EQUAL TO + mirrorChars[0x2288] = 0x2289; // [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO + mirrorChars[0x2289] = 0x2288; // [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO + mirrorChars[0x228A] = 0x228B; // [BEST FIT] SUBSET OF WITH NOT EQUAL TO + mirrorChars[0x228B] = 0x228A; // [BEST FIT] SUPERSET OF WITH NOT EQUAL TO + mirrorChars[0x228F] = 0x2290; // SQUARE IMAGE OF + mirrorChars[0x2290] = 0x228F; // SQUARE ORIGINAL OF + mirrorChars[0x2291] = 0x2292; // SQUARE IMAGE OF OR EQUAL TO + mirrorChars[0x2292] = 0x2291; // SQUARE ORIGINAL OF OR EQUAL TO + mirrorChars[0x2298] = 0x29B8; // CIRCLED DIVISION SLASH + mirrorChars[0x22A2] = 0x22A3; // RIGHT TACK + mirrorChars[0x22A3] = 0x22A2; // LEFT TACK + mirrorChars[0x22A6] = 0x2ADE; // ASSERTION + mirrorChars[0x22A8] = 0x2AE4; // TRUE + mirrorChars[0x22A9] = 0x2AE3; // FORCES + mirrorChars[0x22AB] = 0x2AE5; // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + mirrorChars[0x22B0] = 0x22B1; // PRECEDES UNDER RELATION + mirrorChars[0x22B1] = 0x22B0; // SUCCEEDS UNDER RELATION + mirrorChars[0x22B2] = 0x22B3; // NORMAL SUBGROUP OF + mirrorChars[0x22B3] = 0x22B2; // CONTAINS AS NORMAL SUBGROUP + mirrorChars[0x22B4] = 0x22B5; // NORMAL SUBGROUP OF OR EQUAL TO + mirrorChars[0x22B5] = 0x22B4; // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + mirrorChars[0x22B6] = 0x22B7; // ORIGINAL OF + mirrorChars[0x22B7] = 0x22B6; // IMAGE OF + mirrorChars[0x22C9] = 0x22CA; // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + mirrorChars[0x22CA] = 0x22C9; // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + mirrorChars[0x22CB] = 0x22CC; // LEFT SEMIDIRECT PRODUCT + mirrorChars[0x22CC] = 0x22CB; // RIGHT SEMIDIRECT PRODUCT + mirrorChars[0x22CD] = 0x2243; // REVERSED TILDE EQUALS + mirrorChars[0x22D0] = 0x22D1; // DOUBLE SUBSET + mirrorChars[0x22D1] = 0x22D0; // DOUBLE SUPERSET + mirrorChars[0x22D6] = 0x22D7; // LESS-THAN WITH DOT + mirrorChars[0x22D7] = 0x22D6; // GREATER-THAN WITH DOT + mirrorChars[0x22D8] = 0x22D9; // VERY MUCH LESS-THAN + mirrorChars[0x22D9] = 0x22D8; // VERY MUCH GREATER-THAN + mirrorChars[0x22DA] = 0x22DB; // LESS-THAN EQUAL TO OR GREATER-THAN + mirrorChars[0x22DB] = 0x22DA; // GREATER-THAN EQUAL TO OR LESS-THAN + mirrorChars[0x22DC] = 0x22DD; // EQUAL TO OR LESS-THAN + mirrorChars[0x22DD] = 0x22DC; // EQUAL TO OR GREATER-THAN + mirrorChars[0x22DE] = 0x22DF; // EQUAL TO OR PRECEDES + mirrorChars[0x22DF] = 0x22DE; // EQUAL TO OR SUCCEEDS + mirrorChars[0x22E0] = 0x22E1; // [BEST FIT] DOES NOT PRECEDE OR EQUAL + mirrorChars[0x22E1] = 0x22E0; // [BEST FIT] DOES NOT SUCCEED OR EQUAL + mirrorChars[0x22E2] = 0x22E3; // [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO + mirrorChars[0x22E3] = 0x22E2; // [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO + mirrorChars[0x22E4] = 0x22E5; // [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO + mirrorChars[0x22E5] = 0x22E4; // [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO + mirrorChars[0x22E6] = 0x22E7; // [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO + mirrorChars[0x22E7] = 0x22E6; // [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO + mirrorChars[0x22E8] = 0x22E9; // [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO + mirrorChars[0x22E9] = 0x22E8; // [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO + mirrorChars[0x22EA] = 0x22EB; // [BEST FIT] NOT NORMAL SUBGROUP OF + mirrorChars[0x22EB] = 0x22EA; // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP + mirrorChars[0x22EC] = 0x22ED; // [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO + mirrorChars[0x22ED] = 0x22EC; // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + mirrorChars[0x22F0] = 0x22F1; // UP RIGHT DIAGONAL ELLIPSIS + mirrorChars[0x22F1] = 0x22F0; // DOWN RIGHT DIAGONAL ELLIPSIS + mirrorChars[0x22F2] = 0x22FA; // ELEMENT OF WITH LONG HORIZONTAL STROKE + mirrorChars[0x22F3] = 0x22FB; // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22F4] = 0x22FC; // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22F6] = 0x22FD; // ELEMENT OF WITH OVERBAR + mirrorChars[0x22F7] = 0x22FE; // SMALL ELEMENT OF WITH OVERBAR + mirrorChars[0x22FA] = 0x22F2; // CONTAINS WITH LONG HORIZONTAL STROKE + mirrorChars[0x22FB] = 0x22F3; // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22FC] = 0x22F4; // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22FD] = 0x22F6; // CONTAINS WITH OVERBAR + mirrorChars[0x22FE] = 0x22F7; // SMALL CONTAINS WITH OVERBAR + mirrorChars[0x2308] = 0x2309; // LEFT CEILING + mirrorChars[0x2309] = 0x2308; // RIGHT CEILING + mirrorChars[0x230A] = 0x230B; // LEFT FLOOR + mirrorChars[0x230B] = 0x230A; // RIGHT FLOOR + mirrorChars[0x2329] = 0x232A; // LEFT-POINTING ANGLE BRACKET + mirrorChars[0x232A] = 0x2329; // RIGHT-POINTING ANGLE BRACKET + mirrorChars[0x2768] = 0x2769; // MEDIUM LEFT PARENTHESIS ORNAMENT + mirrorChars[0x2769] = 0x2768; // MEDIUM RIGHT PARENTHESIS ORNAMENT + mirrorChars[0x276A] = 0x276B; // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + mirrorChars[0x276B] = 0x276A; // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + mirrorChars[0x276C] = 0x276D; // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x276D] = 0x276C; // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x276E] = 0x276F; // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + mirrorChars[0x276F] = 0x276E; // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + mirrorChars[0x2770] = 0x2771; // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x2771] = 0x2770; // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x2772] = 0x2773; // LIGHT LEFT TORTOISE SHELL BRACKET + mirrorChars[0x2773] = 0x2772; // LIGHT RIGHT TORTOISE SHELL BRACKET + mirrorChars[0x2774] = 0x2775; // MEDIUM LEFT CURLY BRACKET ORNAMENT + mirrorChars[0x2775] = 0x2774; // MEDIUM RIGHT CURLY BRACKET ORNAMENT + mirrorChars[0x27D5] = 0x27D6; // LEFT OUTER JOIN + mirrorChars[0x27D6] = 0x27D5; // RIGHT OUTER JOIN + mirrorChars[0x27DD] = 0x27DE; // LONG RIGHT TACK + mirrorChars[0x27DE] = 0x27DD; // LONG LEFT TACK + mirrorChars[0x27E2] = 0x27E3; // WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK + mirrorChars[0x27E3] = 0x27E2; // WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK + mirrorChars[0x27E4] = 0x27E5; // WHITE SQUARE WITH LEFTWARDS TICK + mirrorChars[0x27E5] = 0x27E4; // WHITE SQUARE WITH RIGHTWARDS TICK + mirrorChars[0x27E6] = 0x27E7; // MATHEMATICAL LEFT WHITE SQUARE BRACKET + mirrorChars[0x27E7] = 0x27E6; // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + mirrorChars[0x27E8] = 0x27E9; // MATHEMATICAL LEFT ANGLE BRACKET + mirrorChars[0x27E9] = 0x27E8; // MATHEMATICAL RIGHT ANGLE BRACKET + mirrorChars[0x27EA] = 0x27EB; // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + mirrorChars[0x27EB] = 0x27EA; // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + mirrorChars[0x2983] = 0x2984; // LEFT WHITE CURLY BRACKET + mirrorChars[0x2984] = 0x2983; // RIGHT WHITE CURLY BRACKET + mirrorChars[0x2985] = 0x2986; // LEFT WHITE PARENTHESIS + mirrorChars[0x2986] = 0x2985; // RIGHT WHITE PARENTHESIS + mirrorChars[0x2987] = 0x2988; // Z NOTATION LEFT IMAGE BRACKET + mirrorChars[0x2988] = 0x2987; // Z NOTATION RIGHT IMAGE BRACKET + mirrorChars[0x2989] = 0x298A; // Z NOTATION LEFT BINDING BRACKET + mirrorChars[0x298A] = 0x2989; // Z NOTATION RIGHT BINDING BRACKET + mirrorChars[0x298B] = 0x298C; // LEFT SQUARE BRACKET WITH UNDERBAR + mirrorChars[0x298C] = 0x298B; // RIGHT SQUARE BRACKET WITH UNDERBAR + mirrorChars[0x298D] = 0x2990; // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + mirrorChars[0x298E] = 0x298F; // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + mirrorChars[0x298F] = 0x298E; // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + mirrorChars[0x2990] = 0x298D; // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + mirrorChars[0x2991] = 0x2992; // LEFT ANGLE BRACKET WITH DOT + mirrorChars[0x2992] = 0x2991; // RIGHT ANGLE BRACKET WITH DOT + mirrorChars[0x2993] = 0x2994; // LEFT ARC LESS-THAN BRACKET + mirrorChars[0x2994] = 0x2993; // RIGHT ARC GREATER-THAN BRACKET + mirrorChars[0x2995] = 0x2996; // DOUBLE LEFT ARC GREATER-THAN BRACKET + mirrorChars[0x2996] = 0x2995; // DOUBLE RIGHT ARC LESS-THAN BRACKET + mirrorChars[0x2997] = 0x2998; // LEFT BLACK TORTOISE SHELL BRACKET + mirrorChars[0x2998] = 0x2997; // RIGHT BLACK TORTOISE SHELL BRACKET + mirrorChars[0x29B8] = 0x2298; // CIRCLED REVERSE SOLIDUS + mirrorChars[0x29C0] = 0x29C1; // CIRCLED LESS-THAN + mirrorChars[0x29C1] = 0x29C0; // CIRCLED GREATER-THAN + mirrorChars[0x29C4] = 0x29C5; // SQUARED RISING DIAGONAL SLASH + mirrorChars[0x29C5] = 0x29C4; // SQUARED FALLING DIAGONAL SLASH + mirrorChars[0x29CF] = 0x29D0; // LEFT TRIANGLE BESIDE VERTICAL BAR + mirrorChars[0x29D0] = 0x29CF; // VERTICAL BAR BESIDE RIGHT TRIANGLE + mirrorChars[0x29D1] = 0x29D2; // BOWTIE WITH LEFT HALF BLACK + mirrorChars[0x29D2] = 0x29D1; // BOWTIE WITH RIGHT HALF BLACK + mirrorChars[0x29D4] = 0x29D5; // TIMES WITH LEFT HALF BLACK + mirrorChars[0x29D5] = 0x29D4; // TIMES WITH RIGHT HALF BLACK + mirrorChars[0x29D8] = 0x29D9; // LEFT WIGGLY FENCE + mirrorChars[0x29D9] = 0x29D8; // RIGHT WIGGLY FENCE + mirrorChars[0x29DA] = 0x29DB; // LEFT DOUBLE WIGGLY FENCE + mirrorChars[0x29DB] = 0x29DA; // RIGHT DOUBLE WIGGLY FENCE + mirrorChars[0x29F5] = 0x2215; // REVERSE SOLIDUS OPERATOR + mirrorChars[0x29F8] = 0x29F9; // BIG SOLIDUS + mirrorChars[0x29F9] = 0x29F8; // BIG REVERSE SOLIDUS + mirrorChars[0x29FC] = 0x29FD; // LEFT-POINTING CURVED ANGLE BRACKET + mirrorChars[0x29FD] = 0x29FC; // RIGHT-POINTING CURVED ANGLE BRACKET + mirrorChars[0x2A2B] = 0x2A2C; // MINUS SIGN WITH FALLING DOTS + mirrorChars[0x2A2C] = 0x2A2B; // MINUS SIGN WITH RISING DOTS + mirrorChars[0x2A2D] = 0x2A2C; // PLUS SIGN IN LEFT HALF CIRCLE + mirrorChars[0x2A2E] = 0x2A2D; // PLUS SIGN IN RIGHT HALF CIRCLE + mirrorChars[0x2A34] = 0x2A35; // MULTIPLICATION SIGN IN LEFT HALF CIRCLE + mirrorChars[0x2A35] = 0x2A34; // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + mirrorChars[0x2A3C] = 0x2A3D; // INTERIOR PRODUCT + mirrorChars[0x2A3D] = 0x2A3C; // RIGHTHAND INTERIOR PRODUCT + mirrorChars[0x2A64] = 0x2A65; // Z NOTATION DOMAIN ANTIRESTRICTION + mirrorChars[0x2A65] = 0x2A64; // Z NOTATION RANGE ANTIRESTRICTION + mirrorChars[0x2A79] = 0x2A7A; // LESS-THAN WITH CIRCLE INSIDE + mirrorChars[0x2A7A] = 0x2A79; // GREATER-THAN WITH CIRCLE INSIDE + mirrorChars[0x2A7D] = 0x2A7E; // LESS-THAN OR SLANTED EQUAL TO + mirrorChars[0x2A7E] = 0x2A7D; // GREATER-THAN OR SLANTED EQUAL TO + mirrorChars[0x2A7F] = 0x2A80; // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + mirrorChars[0x2A80] = 0x2A7F; // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + mirrorChars[0x2A81] = 0x2A82; // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + mirrorChars[0x2A82] = 0x2A81; // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + mirrorChars[0x2A83] = 0x2A84; // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + mirrorChars[0x2A84] = 0x2A83; // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + mirrorChars[0x2A8B] = 0x2A8C; // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + mirrorChars[0x2A8C] = 0x2A8B; // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + mirrorChars[0x2A91] = 0x2A92; // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + mirrorChars[0x2A92] = 0x2A91; // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + mirrorChars[0x2A93] = 0x2A94; // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + mirrorChars[0x2A94] = 0x2A93; // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + mirrorChars[0x2A95] = 0x2A96; // SLANTED EQUAL TO OR LESS-THAN + mirrorChars[0x2A96] = 0x2A95; // SLANTED EQUAL TO OR GREATER-THAN + mirrorChars[0x2A97] = 0x2A98; // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + mirrorChars[0x2A98] = 0x2A97; // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + mirrorChars[0x2A99] = 0x2A9A; // DOUBLE-LINE EQUAL TO OR LESS-THAN + mirrorChars[0x2A9A] = 0x2A99; // DOUBLE-LINE EQUAL TO OR GREATER-THAN + mirrorChars[0x2A9B] = 0x2A9C; // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN + mirrorChars[0x2A9C] = 0x2A9B; // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN + mirrorChars[0x2AA1] = 0x2AA2; // DOUBLE NESTED LESS-THAN + mirrorChars[0x2AA2] = 0x2AA1; // DOUBLE NESTED GREATER-THAN + mirrorChars[0x2AA6] = 0x2AA7; // LESS-THAN CLOSED BY CURVE + mirrorChars[0x2AA7] = 0x2AA6; // GREATER-THAN CLOSED BY CURVE + mirrorChars[0x2AA8] = 0x2AA9; // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + mirrorChars[0x2AA9] = 0x2AA8; // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + mirrorChars[0x2AAA] = 0x2AAB; // SMALLER THAN + mirrorChars[0x2AAB] = 0x2AAA; // LARGER THAN + mirrorChars[0x2AAC] = 0x2AAD; // SMALLER THAN OR EQUAL TO + mirrorChars[0x2AAD] = 0x2AAC; // LARGER THAN OR EQUAL TO + mirrorChars[0x2AAF] = 0x2AB0; // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + mirrorChars[0x2AB0] = 0x2AAF; // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + mirrorChars[0x2AB3] = 0x2AB4; // PRECEDES ABOVE EQUALS SIGN + mirrorChars[0x2AB4] = 0x2AB3; // SUCCEEDS ABOVE EQUALS SIGN + mirrorChars[0x2ABB] = 0x2ABC; // DOUBLE PRECEDES + mirrorChars[0x2ABC] = 0x2ABB; // DOUBLE SUCCEEDS + mirrorChars[0x2ABD] = 0x2ABE; // SUBSET WITH DOT + mirrorChars[0x2ABE] = 0x2ABD; // SUPERSET WITH DOT + mirrorChars[0x2ABF] = 0x2AC0; // SUBSET WITH PLUS SIGN BELOW + mirrorChars[0x2AC0] = 0x2ABF; // SUPERSET WITH PLUS SIGN BELOW + mirrorChars[0x2AC1] = 0x2AC2; // SUBSET WITH MULTIPLICATION SIGN BELOW + mirrorChars[0x2AC2] = 0x2AC1; // SUPERSET WITH MULTIPLICATION SIGN BELOW + mirrorChars[0x2AC3] = 0x2AC4; // SUBSET OF OR EQUAL TO WITH DOT ABOVE + mirrorChars[0x2AC4] = 0x2AC3; // SUPERSET OF OR EQUAL TO WITH DOT ABOVE + mirrorChars[0x2AC5] = 0x2AC6; // SUBSET OF ABOVE EQUALS SIGN + mirrorChars[0x2AC6] = 0x2AC5; // SUPERSET OF ABOVE EQUALS SIGN + mirrorChars[0x2ACD] = 0x2ACE; // SQUARE LEFT OPEN BOX OPERATOR + mirrorChars[0x2ACE] = 0x2ACD; // SQUARE RIGHT OPEN BOX OPERATOR + mirrorChars[0x2ACF] = 0x2AD0; // CLOSED SUBSET + mirrorChars[0x2AD0] = 0x2ACF; // CLOSED SUPERSET + mirrorChars[0x2AD1] = 0x2AD2; // CLOSED SUBSET OR EQUAL TO + mirrorChars[0x2AD2] = 0x2AD1; // CLOSED SUPERSET OR EQUAL TO + mirrorChars[0x2AD3] = 0x2AD4; // SUBSET ABOVE SUPERSET + mirrorChars[0x2AD4] = 0x2AD3; // SUPERSET ABOVE SUBSET + mirrorChars[0x2AD5] = 0x2AD6; // SUBSET ABOVE SUBSET + mirrorChars[0x2AD6] = 0x2AD5; // SUPERSET ABOVE SUPERSET + mirrorChars[0x2ADE] = 0x22A6; // SHORT LEFT TACK + mirrorChars[0x2AE3] = 0x22A9; // DOUBLE VERTICAL BAR LEFT TURNSTILE + mirrorChars[0x2AE4] = 0x22A8; // VERTICAL BAR DOUBLE LEFT TURNSTILE + mirrorChars[0x2AE5] = 0x22AB; // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE + mirrorChars[0x2AEC] = 0x2AED; // DOUBLE STROKE NOT SIGN + mirrorChars[0x2AED] = 0x2AEC; // REVERSED DOUBLE STROKE NOT SIGN + mirrorChars[0x2AF7] = 0x2AF8; // TRIPLE NESTED LESS-THAN + mirrorChars[0x2AF8] = 0x2AF7; // TRIPLE NESTED GREATER-THAN + mirrorChars[0x2AF9] = 0x2AFA; // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO + mirrorChars[0x2AFA] = 0x2AF9; // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO + mirrorChars[0x3008] = 0x3009; // LEFT ANGLE BRACKET + mirrorChars[0x3009] = 0x3008; // RIGHT ANGLE BRACKET + mirrorChars[0x300A] = 0x300B; // LEFT DOUBLE ANGLE BRACKET + mirrorChars[0x300B] = 0x300A; // RIGHT DOUBLE ANGLE BRACKET + mirrorChars[0x300C] = 0x300D; // [BEST FIT] LEFT CORNER BRACKET + mirrorChars[0x300D] = 0x300C; // [BEST FIT] RIGHT CORNER BRACKET + mirrorChars[0x300E] = 0x300F; // [BEST FIT] LEFT WHITE CORNER BRACKET + mirrorChars[0x300F] = 0x300E; // [BEST FIT] RIGHT WHITE CORNER BRACKET + mirrorChars[0x3010] = 0x3011; // LEFT BLACK LENTICULAR BRACKET + mirrorChars[0x3011] = 0x3010; // RIGHT BLACK LENTICULAR BRACKET + mirrorChars[0x3014] = 0x3015; // LEFT TORTOISE SHELL BRACKET + mirrorChars[0x3015] = 0x3014; // RIGHT TORTOISE SHELL BRACKET + mirrorChars[0x3016] = 0x3017; // LEFT WHITE LENTICULAR BRACKET + mirrorChars[0x3017] = 0x3016; // RIGHT WHITE LENTICULAR BRACKET + mirrorChars[0x3018] = 0x3019; // LEFT WHITE TORTOISE SHELL BRACKET + mirrorChars[0x3019] = 0x3018; // RIGHT WHITE TORTOISE SHELL BRACKET + mirrorChars[0x301A] = 0x301B; // LEFT WHITE SQUARE BRACKET + mirrorChars[0x301B] = 0x301A; // RIGHT WHITE SQUARE BRACKET + mirrorChars[0xFF08] = 0xFF09; // FULLWIDTH LEFT PARENTHESIS + mirrorChars[0xFF09] = 0xFF08; // FULLWIDTH RIGHT PARENTHESIS + mirrorChars[0xFF1C] = 0xFF1E; // FULLWIDTH LESS-THAN SIGN + mirrorChars[0xFF1E] = 0xFF1C; // FULLWIDTH GREATER-THAN SIGN + mirrorChars[0xFF3B] = 0xFF3D; // FULLWIDTH LEFT SQUARE BRACKET + mirrorChars[0xFF3D] = 0xFF3B; // FULLWIDTH RIGHT SQUARE BRACKET + mirrorChars[0xFF5B] = 0xFF5D; // FULLWIDTH LEFT CURLY BRACKET + mirrorChars[0xFF5D] = 0xFF5B; // FULLWIDTH RIGHT CURLY BRACKET + mirrorChars[0xFF5F] = 0xFF60; // FULLWIDTH LEFT WHITE PARENTHESIS + mirrorChars[0xFF60] = 0xFF5F; // FULLWIDTH RIGHT WHITE PARENTHESIS + mirrorChars[0xFF62] = 0xFF63; // [BEST FIT] HALFWIDTH LEFT CORNER BRACKET + mirrorChars[0xFF63] = 0xFF62; // [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/BidiOrder.cs b/iTechSharp/iTextSharp/text/pdf/BidiOrder.cs new file mode 100644 index 0000000..08f4be6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BidiOrder.cs @@ -0,0 +1,1296 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +/* + * (C) Copyright IBM Corp. 1999, All Rights Reserved + * + * version 1.1 + */ + +/* + * As stated in the Javadoc comments below, materials from Unicode.org + * are used in this class. The following license applies to these materials: + * http://www.unicode.org/copyright.html#Exhibit1 + * + * EXHIBIT 1 + * UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + * + * Unicode Data Files include all data files under the directories + * http://www.unicode.org/Public/, http://www.unicode.org/reports/, + * and http://www.unicode.org/cldr/data/ . + * Unicode Software includes any source code published in the Unicode Standard + * or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, + * and http://www.unicode.org/cldr/data/. + * + * NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, + * INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), + * AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, + * ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT + * DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + * + * COPYRIGHT AND PERMISSION NOTICE + * Copyright © 1991-2007 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data Files") + * or Unicode software and any associated documentation (the "Software") to deal + * in the Data Files or Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or sell copies + * of the Data Files or Software, and to permit persons to whom the Data Files + * or Software are furnished to do so, provided that (a) the above copyright + * notice(s) and this permission notice appear with all copies of the Data Files + * or Software, (b) both the above copyright notice(s) and this permission notice + * appear in associated documentation, and (c) there is clear notice in each + * modified Data File or in the Software as well as in the documentation associated + * with the Data File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE + * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other dealings + * in these Data Files or Software without prior written authorization of the + * copyright holder. + */ + +/** + * Reference implementation of the Unicode 3.0 Bidi algorithm. + * + *

+ * This implementation is not optimized for performance. It is intended + * as a reference implementation that closely follows the specification + * of the Bidirectional Algorithm in The Unicode Standard version 3.0. + *

+ * Input:
+ * There are two levels of input to the algorithm, since clients may prefer + * to supply some information from out-of-band sources rather than relying on + * the default behavior. + *

    + *
  1. unicode type array + *
  2. unicode type array, with externally supplied base line direction + *
+ *

Output:
+ * Output is separated into several stages as well, to better enable clients + * to evaluate various aspects of implementation conformance. + *

    + *
  1. levels array over entire paragraph + *
  2. reordering array over entire paragraph + *
  3. levels array over line + *
  4. reordering array over line + *
+ * Note that for conformance, algorithms are only required to generate correct + * reordering and character directionality (odd or even levels) over a line. + * Generating identical level arrays over a line is not required. Bidi + * explicit format codes (LRE, RLE, LRO, RLO, PDF) and BN can be assigned + * arbitrary levels and positions as long as the other text matches. + *

+ * As the algorithm is defined to operate on a single paragraph at a time, + * this implementation is written to handle single paragraphs. Thus + * rule P1 is presumed by this implementation-- the data provided to the + * implementation is assumed to be a single paragraph, and either contains no + * 'B' codes, or a single 'B' code at the end of the input. 'B' is allowed + * as input to illustrate how the algorithm assigns it a level. + *

+ * Also note that rules L3 and L4 depend on the rendering engine that uses + * the result of the bidi algorithm. This implementation assumes that the + * rendering engine expects combining marks in visual order (e.g. to the + * left of their base character in RTL runs) and that it adjust the glyphs + * used to render mirrored characters that are in RTL runs so that they + * render appropriately. + * + * @author Doug Felt + */ + +namespace iTextSharp.text.pdf { + public sealed class BidiOrder { + private sbyte[] initialTypes; + private sbyte[] embeddings; // generated from processing format codes + private sbyte paragraphEmbeddingLevel = -1; // undefined + + private int textLength; // for convenience + private sbyte[] resultTypes; // for paragraph, not lines + private sbyte[] resultLevels; // for paragraph, not lines + + // The bidi types + + /** Left-to-right*/ + public const sbyte L = 0; + + /** Left-to-Right Embedding */ + public const sbyte LRE = 1; + + /** Left-to-Right Override */ + public const sbyte LRO = 2; + + /** Right-to-Left */ + public const sbyte R = 3; + + /** Right-to-Left Arabic */ + public const sbyte AL = 4; + + /** Right-to-Left Embedding */ + public const sbyte RLE = 5; + + /** Right-to-Left Override */ + public const sbyte RLO = 6; + + /** Pop Directional Format */ + public const sbyte PDF = 7; + + /** European Number */ + public const sbyte EN = 8; + + /** European Number Separator */ + public const sbyte ES = 9; + + /** European Number Terminator */ + public const sbyte ET = 10; + + /** Arabic Number */ + public const sbyte AN = 11; + + /** Common Number Separator */ + public const sbyte CS = 12; + + /** Non-Spacing Mark */ + public const sbyte NSM = 13; + + /** Boundary Neutral */ + public const sbyte BN = 14; + + /** Paragraph Separator */ + public const sbyte B = 15; + + /** Segment Separator */ + public const sbyte S = 16; + + /** Whitespace */ + public const sbyte WS = 17; + + /** Other Neutrals */ + public const sbyte ON = 18; + + /** Minimum bidi type value. */ + public const sbyte TYPE_MIN = 0; + + /** Maximum bidi type value. */ + public const sbyte TYPE_MAX = 18; + + // + // Input + // + + /** + * Initialize using an array of direction types. Types range from TYPE_MIN to TYPE_MAX inclusive + * and represent the direction codes of the characters in the text. + * + * @param types the types array + */ + public BidiOrder(sbyte[] types) { + ValidateTypes(types); + + this.initialTypes = (sbyte[])types.Clone(); // client type array remains unchanged + + RunAlgorithm(); + } + + /** + * Initialize using an array of direction types and an externally supplied paragraph embedding level. + * The embedding level may be -1, 0, or 1. -1 means to apply the default algorithm (rules P2 and P3), + * 0 is for LTR paragraphs, and 1 is for RTL paragraphs. + * + * @param types the types array + * @param paragraphEmbeddingLevel the externally supplied paragraph embedding level. + */ + public BidiOrder(sbyte[] types, sbyte paragraphEmbeddingLevel) { + ValidateTypes(types); + ValidateParagraphEmbeddingLevel(paragraphEmbeddingLevel); + + this.initialTypes = (sbyte[])types.Clone(); // client type array remains unchanged + this.paragraphEmbeddingLevel = paragraphEmbeddingLevel; + + RunAlgorithm(); + } + + public BidiOrder(char[] text, int offset, int length, sbyte paragraphEmbeddingLevel) { + initialTypes = new sbyte[length]; + for (int k = 0; k < length; ++k) { + initialTypes[k] = rtypes[text[offset + k]]; + } + ValidateParagraphEmbeddingLevel(paragraphEmbeddingLevel); + + this.paragraphEmbeddingLevel = paragraphEmbeddingLevel; + + RunAlgorithm(); + } + + public static sbyte GetDirection(char c) { + return rtypes[c]; + } + + /** + * The algorithm. + * Does not include line-based processing (Rules L1, L2). + * These are applied later in the line-based phase of the algorithm. + */ + private void RunAlgorithm() { + textLength = initialTypes.Length; + + // Initialize output types. + // Result types initialized to input types. + resultTypes = (sbyte[])initialTypes.Clone(); + + + // 1) determining the paragraph level + // Rule P1 is the requirement for entering this algorithm. + // Rules P2, P3. + // If no externally supplied paragraph embedding level, use default. + if (paragraphEmbeddingLevel == -1) { + DetermineParagraphEmbeddingLevel(); + } + + // Initialize result levels to paragraph embedding level. + resultLevels = new sbyte[textLength]; + SetLevels(0, textLength, paragraphEmbeddingLevel); + + // 2) Explicit levels and directions + // Rules X1-X8. + DetermineExplicitEmbeddingLevels(); + + // Rule X9. + textLength = RemoveExplicitCodes(); + + // Rule X10. + // Run remainder of algorithm one level run at a time + sbyte prevLevel = paragraphEmbeddingLevel; + int start = 0; + while (start < textLength) { + sbyte level = resultLevels[start]; + sbyte prevType = TypeForLevel(Math.Max(prevLevel, level)); + + int limit = start + 1; + while (limit < textLength && resultLevels[limit] == level) { + ++limit; + } + + sbyte succLevel = limit < textLength ? resultLevels[limit] : paragraphEmbeddingLevel; + sbyte succType = TypeForLevel(Math.Max(succLevel, level)); + + // 3) resolving weak types + // Rules W1-W7. + ResolveWeakTypes(start, limit, level, prevType, succType); + + // 4) resolving neutral types + // Rules N1-N3. + ResolveNeutralTypes(start, limit, level, prevType, succType); + + // 5) resolving implicit embedding levels + // Rules I1, I2. + ResolveImplicitLevels(start, limit, level, prevType, succType); + + prevLevel = level; + start = limit; + } + + // Reinsert explicit codes and assign appropriate levels to 'hide' them. + // This is for convenience, so the resulting level array maps 1-1 + // with the initial array. + // See the implementation suggestions section of TR#9 for guidelines on + // how to implement the algorithm without removing and reinserting the codes. + textLength = ReinsertExplicitCodes(textLength); + } + + /** + * 1) determining the paragraph level. + *

+ * Rules P2, P3. + *

+ * At the end of this function, the member variable paragraphEmbeddingLevel is set to either 0 or 1. + */ + private void DetermineParagraphEmbeddingLevel() { + sbyte strongType = -1; // unknown + + // Rule P2. + for (int i = 0; i < textLength; ++i) { + sbyte t = resultTypes[i]; + if (t == L || t == AL || t == R) { + strongType = t; + break; + } + } + + // Rule P3. + if (strongType == -1) { // none found + // default embedding level when no strong types found is 0. + paragraphEmbeddingLevel = 0; + } else if (strongType == L) { + paragraphEmbeddingLevel = 0; + } else { // AL, R + paragraphEmbeddingLevel = 1; + } + } + + /** + * Process embedding format codes. + *

+ * Calls processEmbeddings to generate an embedding array from the explicit format codes. The + * embedding overrides in the array are then applied to the result types, and the result levels are + * initialized. + * @see #processEmbeddings + */ + private void DetermineExplicitEmbeddingLevels() { + embeddings = ProcessEmbeddings(resultTypes, paragraphEmbeddingLevel); + + for (int i = 0; i < textLength; ++i) { + sbyte level = embeddings[i]; + if ((level & 0x80) != 0) { + level &= 0x7f; + resultTypes[i] = TypeForLevel(level); + } + resultLevels[i] = level; + } + } + + /** + * Rules X9. + * Remove explicit codes so that they may be ignored during the remainder + * of the main portion of the algorithm. The length of the resulting text + * is returned. + * @return the length of the data excluding explicit codes and BN. + */ + private int RemoveExplicitCodes() { + int w = 0; + for (int i = 0; i < textLength; ++i) { + sbyte t = initialTypes[i]; + if (!(t == LRE || t == RLE || t == LRO || t == RLO || t == PDF || t == BN)) { + embeddings[w] = embeddings[i]; + resultTypes[w] = resultTypes[i]; + resultLevels[w] = resultLevels[i]; + w++; + } + } + return w; // new textLength while explicit levels are removed + } + + /** + * Reinsert levels information for explicit codes. + * This is for ease of relating the level information + * to the original input data. Note that the levels + * assigned to these codes are arbitrary, they're + * chosen so as to avoid breaking level runs. + * @param textLength the length of the data after compression + * @return the length of the data (original length of + * types array supplied to constructor) + */ + private int ReinsertExplicitCodes(int textLength) { + for (int i = initialTypes.Length; --i >= 0;) { + sbyte t = initialTypes[i]; + if (t == LRE || t == RLE || t == LRO || t == RLO || t == PDF || t == BN) { + embeddings[i] = 0; + resultTypes[i] = t; + resultLevels[i] = -1; + } else { + --textLength; + embeddings[i] = embeddings[textLength]; + resultTypes[i] = resultTypes[textLength]; + resultLevels[i] = resultLevels[textLength]; + } + } + + // now propagate forward the levels information (could have + // propagated backward, the main thing is not to introduce a level + // break where one doesn't already exist). + + if (resultLevels[0] == -1) { + resultLevels[0] = paragraphEmbeddingLevel; + } + for (int i = 1; i < initialTypes.Length; ++i) { + if (resultLevels[i] == -1) { + resultLevels[i] = resultLevels[i-1]; + } + } + + // Embedding information is for informational purposes only + // so need not be adjusted. + + return initialTypes.Length; + } + + /** + * 2) determining explicit levels + * Rules X1 - X8 + * + * The interaction of these rules makes handling them a bit complex. + * This examines resultTypes but does not modify it. It returns embedding and + * override information in the result array. The low 7 bits are the level, the high + * bit is set if the level is an override, and clear if it is an embedding. + */ + private static sbyte[] ProcessEmbeddings(sbyte[] resultTypes, sbyte paragraphEmbeddingLevel) { + int EXPLICIT_LEVEL_LIMIT = 62; + + int textLength = resultTypes.Length; + sbyte[] embeddings = new sbyte[textLength]; + + // This stack will store the embedding levels and override status in a single sbyte + // as described above. + sbyte[] embeddingValueStack = new sbyte[EXPLICIT_LEVEL_LIMIT]; + int stackCounter = 0; + + // An LRE or LRO at level 60 is invalid, since the new level 62 is invalid. But + // an RLE at level 60 is valid, since the new level 61 is valid. The current wording + // of the rules requires that the RLE remain valid even if a previous LRE is invalid. + // This keeps track of ignored LRE or LRO codes at level 60, so that the matching PDFs + // will not try to pop the stack. + int overflowAlmostCounter = 0; + + // This keeps track of ignored pushes at level 61 or higher, so that matching PDFs will + // not try to pop the stack. + int overflowCounter = 0; + + // Rule X1. + + // Keep the level separate from the value (level | override status flag) for ease of access. + sbyte currentEmbeddingLevel = paragraphEmbeddingLevel; + sbyte currentEmbeddingValue = paragraphEmbeddingLevel; + + // Loop through types, handling all remaining rules + for (int i = 0; i < textLength; ++i) { + + embeddings[i] = currentEmbeddingValue; + + sbyte t = resultTypes[i]; + + // Rules X2, X3, X4, X5 + switch (t) { + case RLE: + case LRE: + case RLO: + case LRO: + // Only need to compute new level if current level is valid + if (overflowCounter == 0) { + sbyte newLevel; + if (t == RLE || t == RLO) { + newLevel = (sbyte)((currentEmbeddingLevel + 1) | 1); // least greater odd + } else { // t == LRE || t == LRO + newLevel = (sbyte)((currentEmbeddingLevel + 2) & ~1); // least greater even + } + + // If the new level is valid, push old embedding level and override status + // No check for valid stack counter, since the level check suffices. + if (newLevel < EXPLICIT_LEVEL_LIMIT) { + embeddingValueStack[stackCounter] = currentEmbeddingValue; + stackCounter++; + + currentEmbeddingLevel = newLevel; + if (t == LRO || t == RLO) { // override + currentEmbeddingValue = (sbyte)((byte)newLevel | 0x80); + } else { + currentEmbeddingValue = newLevel; + } + + // Adjust level of format mark (for expositional purposes only, this gets + // removed later). + embeddings[i] = currentEmbeddingValue; + break; + } + + // Otherwise new level is invalid, but a valid level can still be achieved if this + // level is 60 and we encounter an RLE or RLO further on. So record that we + // 'almost' overflowed. + if (currentEmbeddingLevel == 60) { + overflowAlmostCounter++; + break; + } + } + + // Otherwise old or new level is invalid. + overflowCounter++; + break; + + case PDF: + // The only case where this did not actually overflow but may have almost overflowed + // is when there was an RLE or RLO on level 60, which would result in level 61. So we + // only test the almost overflow condition in that case. + // + // Also note that there may be a PDF without any pushes at all. + + if (overflowCounter > 0) { + --overflowCounter; + } else if (overflowAlmostCounter > 0 && currentEmbeddingLevel != 61) { + --overflowAlmostCounter; + } else if (stackCounter > 0) { + --stackCounter; + currentEmbeddingValue = embeddingValueStack[stackCounter]; + currentEmbeddingLevel = (sbyte)(currentEmbeddingValue & 0x7f); + } + break; + + case B: + // Rule X8. + + // These values are reset for clarity, in this implementation B can only + // occur as the last code in the array. + stackCounter = 0; + overflowCounter = 0; + overflowAlmostCounter = 0; + currentEmbeddingLevel = paragraphEmbeddingLevel; + currentEmbeddingValue = paragraphEmbeddingLevel; + + embeddings[i] = paragraphEmbeddingLevel; + break; + + default: + break; + } + } + + return embeddings; + } + + + /** + * 3) resolving weak types + * Rules W1-W7. + * + * Note that some weak types (EN, AN) remain after this processing is complete. + */ + private void ResolveWeakTypes(int start, int limit, sbyte level, sbyte sor, sbyte eor) { + + // Rule W1. + // Changes all NSMs. + sbyte preceedingCharacterType = sor; + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + if (t == NSM) { + resultTypes[i] = preceedingCharacterType; + } else { + preceedingCharacterType = t; + } + } + + // Rule W2. + // EN does not change at the start of the run, because sor != AL. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == EN) { + for (int j = i - 1; j >= start; --j) { + sbyte t = resultTypes[j]; + if (t == L || t == R || t == AL) { + if (t == AL) { + resultTypes[i] = AN; + } + break; + } + } + } + } + + // Rule W3. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == AL) { + resultTypes[i] = R; + } + } + + // Rule W4. + // Since there must be values on both sides for this rule to have an + // effect, the scan skips the first and last value. + // + // Although the scan proceeds left to right, and changes the type values + // in a way that would appear to affect the computations later in the scan, + // there is actually no problem. A change in the current value can only + // affect the value to its immediate right, and only affect it if it is + // ES or CS. But the current value can only change if the value to its + // right is not ES or CS. Thus either the current value will not change, + // or its change will have no effect on the remainder of the analysis. + + for (int i = start + 1; i < limit - 1; ++i) { + if (resultTypes[i] == ES || resultTypes[i] == CS) { + sbyte prevSepType = resultTypes[i-1]; + sbyte succSepType = resultTypes[i+1]; + if (prevSepType == EN && succSepType == EN) { + resultTypes[i] = EN; + } else if (resultTypes[i] == CS && prevSepType == AN && succSepType == AN) { + resultTypes[i] = AN; + } + } + } + + // Rule W5. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == ET) { + // locate end of sequence + int runstart = i; + int runlimit = FindRunLimit(runstart, limit, new sbyte[] { ET }); + + // check values at ends of sequence + sbyte t = runstart == start ? sor : resultTypes[runstart - 1]; + + if (t != EN) { + t = runlimit == limit ? eor : resultTypes[runlimit]; + } + + if (t == EN) { + SetTypes(runstart, runlimit, EN); + } + + // continue at end of sequence + i = runlimit; + } + } + + // Rule W6. + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + if (t == ES || t == ET || t == CS) { + resultTypes[i] = ON; + } + } + + // Rule W7. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == EN) { + // set default if we reach start of run + sbyte prevStrongType = sor; + for (int j = i - 1; j >= start; --j) { + sbyte t = resultTypes[j]; + if (t == L || t == R) { // AL's have been removed + prevStrongType = t; + break; + } + } + if (prevStrongType == L) { + resultTypes[i] = L; + } + } + } + } + + /** + * 6) resolving neutral types + * Rules N1-N2. + */ + private void ResolveNeutralTypes(int start, int limit, sbyte level, sbyte sor, sbyte eor) { + + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + if (t == WS || t == ON || t == B || t == S) { + // find bounds of run of neutrals + int runstart = i; + int runlimit = FindRunLimit(runstart, limit, new sbyte[] {B, S, WS, ON}); + + // determine effective types at ends of run + sbyte leadingType; + sbyte trailingType; + + if (runstart == start) { + leadingType = sor; + } else { + leadingType = resultTypes[runstart - 1]; + if (leadingType == L || leadingType == R) { + // found the strong type + } else if (leadingType == AN) { + leadingType = R; + } else if (leadingType == EN) { + // Since EN's with previous strong L types have been changed + // to L in W7, the leadingType must be R. + leadingType = R; + } + } + + if (runlimit == limit) { + trailingType = eor; + } else { + trailingType = resultTypes[runlimit]; + if (trailingType == L || trailingType == R) { + // found the strong type + } else if (trailingType == AN) { + trailingType = R; + } else if (trailingType == EN) { + trailingType = R; + } + } + + sbyte resolvedType; + if (leadingType == trailingType) { + // Rule N1. + resolvedType = leadingType; + } else { + // Rule N2. + // Notice the embedding level of the run is used, not + // the paragraph embedding level. + resolvedType = TypeForLevel(level); + } + + SetTypes(runstart, runlimit, resolvedType); + + // skip over run of (former) neutrals + i = runlimit; + } + } + } + + /** + * 7) resolving implicit embedding levels + * Rules I1, I2. + */ + private void ResolveImplicitLevels(int start, int limit, sbyte level, sbyte sor, sbyte eor) { + if ((level & 1) == 0) { // even level + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + // Rule I1. + if (t == L ) { + // no change + } else if (t == R) { + resultLevels[i] += 1; + } else { // t == AN || t == EN + resultLevels[i] += 2; + } + } + } else { // odd level + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + // Rule I2. + if (t == R) { + // no change + } else { // t == L || t == AN || t == EN + resultLevels[i] += 1; + } + } + } + } + + // + // Output + // + + public byte[] GetLevels() { + return GetLevels(new int[]{textLength}); + } + + /** + * Return levels array breaking lines at offsets in linebreaks.
+ * Rule L1. + *

+ * The returned levels array contains the resolved level for each + * bidi code passed to the constructor. + *

+ * The linebreaks array must include at least one value. + * The values must be in strictly increasing order (no duplicates) + * between 1 and the length of the text, inclusive. The last value + * must be the length of the text. + * + * @param linebreaks the offsets at which to break the paragraph + * @return the resolved levels of the text + */ + public byte[] GetLevels(int[] linebreaks) { + + // Note that since the previous processing has removed all + // P, S, and WS values from resultTypes, the values referred to + // in these rules are the initial types, before any processing + // has been applied (including processing of overrides). + // + // This example implementation has reinserted explicit format codes + // and BN, in order that the levels array correspond to the + // initial text. Their final placement is not normative. + // These codes are treated like WS in this implementation, + // so they don't interrupt sequences of WS. + + ValidateLineBreaks(linebreaks, textLength); + + byte[] result = new byte[resultLevels.Length]; + for (int k = 0; k < resultLevels.Length; ++k) + result[k] = (byte)resultLevels[k]; + + // don't worry about linebreaks since if there is a break within + // a series of WS values preceeding S, the linebreak itself + // causes the reset. + for (int i = 0; i < result.Length; ++i) { + sbyte t = initialTypes[i]; + if (t == B || t == S) { + // Rule L1, clauses one and two. + result[i] = (byte)paragraphEmbeddingLevel; + + // Rule L1, clause three. + for (int j = i - 1; j >= 0; --j) { + if (IsWhitespace(initialTypes[j])) { // including format codes + result[j] = (byte)paragraphEmbeddingLevel; + } else { + break; + } + } + } + } + + // Rule L1, clause four. + int start = 0; + for (int i = 0; i < linebreaks.Length; ++i) { + int limit = linebreaks[i]; + for (int j = limit - 1; j >= start; --j) { + if (IsWhitespace(initialTypes[j])) { // including format codes + result[j] = (byte)paragraphEmbeddingLevel; + } else { + break; + } + } + + start = limit; + } + + return result; + } + + /** + * Return reordering array breaking lines at offsets in linebreaks. + *

+ * The reordering array maps from a visual index to a logical index. + * Lines are concatenated from left to right. So for example, the + * fifth character from the left on the third line is + *

 GetReordering(linebreaks)[linebreaks[1] + 4]
+ * (linebreaks[1] is the position after the last character of the + * second line, which is also the index of the first character on the + * third line, and adding four gets the fifth character from the left). + *

+ * The linebreaks array must include at least one value. + * The values must be in strictly increasing order (no duplicates) + * between 1 and the length of the text, inclusive. The last value + * must be the length of the text. + * + * @param linebreaks the offsets at which to break the paragraph. + */ +/* public int[] GetReordering(int[] linebreaks) { + ValidateLineBreaks(linebreaks, textLength); + + sbyte[] levels = GetLevels(linebreaks); + + return ComputeMultilineReordering(levels, linebreaks); + }*/ + + /** + * Return multiline reordering array for a given level array. + * Reordering does not occur across a line break. + */ + private static int[] ComputeMultilineReordering(sbyte[] levels, int[] linebreaks) { + int[] result = new int[levels.Length]; + + int start = 0; + for (int i = 0; i < linebreaks.Length; ++i) { + int limit = linebreaks[i]; + + sbyte[] templevels = new sbyte[limit - start]; + Array.Copy(levels, start, templevels, 0, templevels.Length); + + int[] temporder = ComputeReordering(templevels); + for (int j = 0; j < temporder.Length; ++j) { + result[start + j] = temporder[j] + start; + } + + start = limit; + } + + return result; + } + + /** + * Return reordering array for a given level array. This reorders a single line. + * The reordering is a visual to logical map. For example, + * the leftmost char is string.CharAt(order[0]). + * Rule L2. + */ + private static int[] ComputeReordering(sbyte[] levels) { + int lineLength = levels.Length; + + int[] result = new int[lineLength]; + + // initialize order + for (int i = 0; i < lineLength; ++i) { + result[i] = i; + } + + // locate highest level found on line. + // Note the rules say text, but no reordering across line bounds is performed, + // so this is sufficient. + sbyte highestLevel = 0; + sbyte lowestOddLevel = 63; + for (int i = 0; i < lineLength; ++i) { + sbyte level = levels[i]; + if (level > highestLevel) { + highestLevel = level; + } + if (((level & 1) != 0) && level < lowestOddLevel) { + lowestOddLevel = level; + } + } + + for (int level = highestLevel; level >= lowestOddLevel; --level) { + for (int i = 0; i < lineLength; ++i) { + if (levels[i] >= level) { + // find range of text at or above this level + int start = i; + int limit = i + 1; + while (limit < lineLength && levels[limit] >= level) { + ++limit; + } + + // reverse run + for (int j = start, k = limit - 1; j < k; ++j, --k) { + int temp = result[j]; + result[j] = result[k]; + result[k] = temp; + } + + // skip to end of level run + i = limit; + } + } + } + + return result; + } + + /** + * Return the base level of the paragraph. + */ + public sbyte GetBaseLevel() { + return paragraphEmbeddingLevel; + } + + // --- internal utilities ------------------------------------------------- + + /** + * Return true if the type is considered a whitespace type for the line break rules. + */ + private static bool IsWhitespace(sbyte biditype) { + switch (biditype) { + case LRE: + case RLE: + case LRO: + case RLO: + case PDF: + case BN: + case WS: + return true; + default: + return false; + } + } + + /** + * Return the strong type (L or R) corresponding to the level. + */ + private static sbyte TypeForLevel(int level) { + return ((level & 0x1) == 0) ? L : R; + } + + /** + * Return the limit of the run starting at index that includes only resultTypes in validSet. + * This checks the value at index, and will return index if that value is not in validSet. + */ + private int FindRunLimit(int index, int limit, sbyte[] validSet) { + --index; + loop: + while (++index < limit) { + sbyte t = resultTypes[index]; + for (int i = 0; i < validSet.Length; ++i) { + if (t == validSet[i]) { + goto loop; + } + } + // didn't find a match in validSet + return index; + } + return limit; + } + + /** + * Return the start of the run including index that includes only resultTypes in validSet. + * This assumes the value at index is valid, and does not check it. + */ + private int FindRunStart(int index, sbyte[] validSet) { + loop: + while (--index >= 0) { + sbyte t = resultTypes[index]; + for (int i = 0; i < validSet.Length; ++i) { + if (t == validSet[i]) { + goto loop; + } + } + return index + 1; + } + return 0; + } + + /** + * Set resultTypes from start up to (but not including) limit to newType. + */ + private void SetTypes(int start, int limit, sbyte newType) { + for (int i = start; i < limit; ++i) { + resultTypes[i] = newType; + } + } + + /** + * Set resultLevels from start up to (but not including) limit to newLevel. + */ + private void SetLevels(int start, int limit, sbyte newLevel) { + for (int i = start; i < limit; ++i) { + resultLevels[i] = newLevel; + } + } + + // --- input validation --------------------------------------------------- + + /** + * Throw exception if type array is invalid. + */ + private static void ValidateTypes(sbyte[] types) { + if (types == null) { + throw new ArgumentException("types is null"); + } + for (int i = 0; i < types.Length; ++i) { + if (types[i] < TYPE_MIN || types[i] > TYPE_MAX) { + throw new ArgumentException("illegal type value at " + i + ": " + types[i]); + } + } + for (int i = 0; i < types.Length - 1; ++i) { + if (types[i] == B) { + throw new ArgumentException("B type before end of paragraph at index: " + i); + } + } + } + + /** + * Throw exception if paragraph embedding level is invalid. Special allowance for -1 so that + * default processing can still be performed when using this API. + */ + private static void ValidateParagraphEmbeddingLevel(sbyte paragraphEmbeddingLevel) { + if (paragraphEmbeddingLevel != -1 && + paragraphEmbeddingLevel != 0 && + paragraphEmbeddingLevel != 1) { + throw new ArgumentException("illegal paragraph embedding level: " + paragraphEmbeddingLevel); + } + } + + /** + * Throw exception if line breaks array is invalid. + */ + private static void ValidateLineBreaks(int[] linebreaks, int textLength) { + int prev = 0; + for (int i = 0; i < linebreaks.Length; ++i) { + int next = linebreaks[i]; + if (next <= prev) { + throw new ArgumentException("bad linebreak: " + next + " at index: " + i); + } + prev = next; + } + if (prev != textLength) { + throw new ArgumentException("last linebreak must be at " + textLength); + } + } + + private static sbyte[] rtypes = new sbyte[0x10000]; + + private static char[] baseTypes = { + (char)0, (char)8, (char)BN, (char)9, (char)9, (char)S, (char)10, (char)10, (char)B, (char)11, (char)11, (char)S, (char)12, (char)12, (char)WS, (char)13, (char)13, (char)B, + (char)14, (char)27, (char)BN, (char)28, (char)30, (char)B, (char)31, (char)31, (char)S, (char)32, (char)32, (char)WS, (char)33, (char)34, (char)ON, (char)35, (char)37, (char)ET, + (char)38, (char)42, (char)ON, (char)43, (char)43, (char)ET, (char)44, (char)44, (char)CS, (char)45, (char)45, (char)ET, (char)46, (char)46, (char)CS, (char)47, (char)47, (char)ES, + (char)48, (char)57, (char)EN, (char)58, (char)58, (char)CS, (char)59, (char)64, (char)ON, (char)65, (char)90, (char)L, (char)91, (char)96, (char)ON, (char)97, (char)122, (char)L, + (char)123, (char)126, (char)ON, (char)127, (char)132, (char)BN, (char)133, (char)133, (char)B, (char)134, (char)159, (char)BN, (char)160, (char)160, (char)CS, + (char)161, (char)161, (char)ON, (char)162, (char)165, (char)ET, (char)166, (char)169, (char)ON, (char)170, (char)170, (char)L, (char)171, (char)175, (char)ON, + (char)176, (char)177, (char)ET, (char)178, (char)179, (char)EN, (char)180, (char)180, (char)ON, (char)181, (char)181, (char)L, (char)182, (char)184, (char)ON, + (char)185, (char)185, (char)EN, (char)186, (char)186, (char)L, (char)187, (char)191, (char)ON, (char)192, (char)214, (char)L, (char)215, (char)215, (char)ON, + (char)216, (char)246, (char)L, (char)247, (char)247, (char)ON, (char)248, (char)696, (char)L, (char)697, (char)698, (char)ON, (char)699, (char)705, (char)L, + (char)706, (char)719, (char)ON, (char)720, (char)721, (char)L, (char)722, (char)735, (char)ON, (char)736, (char)740, (char)L, (char)741, (char)749, (char)ON, + (char)750, (char)750, (char)L, (char)751, (char)767, (char)ON, (char)768, (char)855, (char)NSM, (char)856, (char)860, (char)L, (char)861, (char)879, (char)NSM, + (char)880, (char)883, (char)L, (char)884, (char)885, (char)ON, (char)886, (char)893, (char)L, (char)894, (char)894, (char)ON, (char)895, (char)899, (char)L, + (char)900, (char)901, (char)ON, (char)902, (char)902, (char)L, (char)903, (char)903, (char)ON, (char)904, (char)1013, (char)L, (char)1014, (char)1014, (char)ON, + (char)1015, (char)1154, (char)L, (char)1155, (char)1158, (char)NSM, (char)1159, (char)1159, (char)L, (char)1160, (char)1161, (char)NSM, + (char)1162, (char)1417, (char)L, (char)1418, (char)1418, (char)ON, (char)1419, (char)1424, (char)L, (char)1425, (char)1441, (char)NSM, + (char)1442, (char)1442, (char)L, (char)1443, (char)1465, (char)NSM, (char)1466, (char)1466, (char)L, (char)1467, (char)1469, (char)NSM, + (char)1470, (char)1470, (char)R, (char)1471, (char)1471, (char)NSM, (char)1472, (char)1472, (char)R, (char)1473, (char)1474, (char)NSM, + (char)1475, (char)1475, (char)R, (char)1476, (char)1476, (char)NSM, (char)1477, (char)1487, (char)L, (char)1488, (char)1514, (char)R, + (char)1515, (char)1519, (char)L, (char)1520, (char)1524, (char)R, (char)1525, (char)1535, (char)L, (char)1536, (char)1539, (char)AL, + (char)1540, (char)1547, (char)L, (char)1548, (char)1548, (char)CS, (char)1549, (char)1549, (char)AL, (char)1550, (char)1551, (char)ON, + (char)1552, (char)1557, (char)NSM, (char)1558, (char)1562, (char)L, (char)1563, (char)1563, (char)AL, (char)1564, (char)1566, (char)L, + (char)1567, (char)1567, (char)AL, (char)1568, (char)1568, (char)L, (char)1569, (char)1594, (char)AL, (char)1595, (char)1599, (char)L, + (char)1600, (char)1610, (char)AL, (char)1611, (char)1624, (char)NSM, (char)1625, (char)1631, (char)L, (char)1632, (char)1641, (char)AN, + (char)1642, (char)1642, (char)ET, (char)1643, (char)1644, (char)AN, (char)1645, (char)1647, (char)AL, (char)1648, (char)1648, (char)NSM, + (char)1649, (char)1749, (char)AL, (char)1750, (char)1756, (char)NSM, (char)1757, (char)1757, (char)AL, (char)1758, (char)1764, (char)NSM, + (char)1765, (char)1766, (char)AL, (char)1767, (char)1768, (char)NSM, (char)1769, (char)1769, (char)ON, (char)1770, (char)1773, (char)NSM, + (char)1774, (char)1775, (char)AL, (char)1776, (char)1785, (char)EN, (char)1786, (char)1805, (char)AL, (char)1806, (char)1806, (char)L, + (char)1807, (char)1807, (char)BN, (char)1808, (char)1808, (char)AL, (char)1809, (char)1809, (char)NSM, (char)1810, (char)1839, (char)AL, + (char)1840, (char)1866, (char)NSM, (char)1867, (char)1868, (char)L, (char)1869, (char)1871, (char)AL, (char)1872, (char)1919, (char)L, + (char)1920, (char)1957, (char)AL, (char)1958, (char)1968, (char)NSM, (char)1969, (char)1969, (char)AL, (char)1970, (char)2304, (char)L, + (char)2305, (char)2306, (char)NSM, (char)2307, (char)2363, (char)L, (char)2364, (char)2364, (char)NSM, (char)2365, (char)2368, (char)L, + (char)2369, (char)2376, (char)NSM, (char)2377, (char)2380, (char)L, (char)2381, (char)2381, (char)NSM, (char)2382, (char)2384, (char)L, + (char)2385, (char)2388, (char)NSM, (char)2389, (char)2401, (char)L, (char)2402, (char)2403, (char)NSM, (char)2404, (char)2432, (char)L, + (char)2433, (char)2433, (char)NSM, (char)2434, (char)2491, (char)L, (char)2492, (char)2492, (char)NSM, (char)2493, (char)2496, (char)L, + (char)2497, (char)2500, (char)NSM, (char)2501, (char)2508, (char)L, (char)2509, (char)2509, (char)NSM, (char)2510, (char)2529, (char)L, + (char)2530, (char)2531, (char)NSM, (char)2532, (char)2545, (char)L, (char)2546, (char)2547, (char)ET, (char)2548, (char)2560, (char)L, + (char)2561, (char)2562, (char)NSM, (char)2563, (char)2619, (char)L, (char)2620, (char)2620, (char)NSM, (char)2621, (char)2624, (char)L, + (char)2625, (char)2626, (char)NSM, (char)2627, (char)2630, (char)L, (char)2631, (char)2632, (char)NSM, (char)2633, (char)2634, (char)L, + (char)2635, (char)2637, (char)NSM, (char)2638, (char)2671, (char)L, (char)2672, (char)2673, (char)NSM, (char)2674, (char)2688, (char)L, + (char)2689, (char)2690, (char)NSM, (char)2691, (char)2747, (char)L, (char)2748, (char)2748, (char)NSM, (char)2749, (char)2752, (char)L, + (char)2753, (char)2757, (char)NSM, (char)2758, (char)2758, (char)L, (char)2759, (char)2760, (char)NSM, (char)2761, (char)2764, (char)L, + (char)2765, (char)2765, (char)NSM, (char)2766, (char)2785, (char)L, (char)2786, (char)2787, (char)NSM, (char)2788, (char)2800, (char)L, + (char)2801, (char)2801, (char)ET, (char)2802, (char)2816, (char)L, (char)2817, (char)2817, (char)NSM, (char)2818, (char)2875, (char)L, + (char)2876, (char)2876, (char)NSM, (char)2877, (char)2878, (char)L, (char)2879, (char)2879, (char)NSM, (char)2880, (char)2880, (char)L, + (char)2881, (char)2883, (char)NSM, (char)2884, (char)2892, (char)L, (char)2893, (char)2893, (char)NSM, (char)2894, (char)2901, (char)L, + (char)2902, (char)2902, (char)NSM, (char)2903, (char)2945, (char)L, (char)2946, (char)2946, (char)NSM, (char)2947, (char)3007, (char)L, + (char)3008, (char)3008, (char)NSM, (char)3009, (char)3020, (char)L, (char)3021, (char)3021, (char)NSM, (char)3022, (char)3058, (char)L, + (char)3059, (char)3064, (char)ON, (char)3065, (char)3065, (char)ET, (char)3066, (char)3066, (char)ON, (char)3067, (char)3133, (char)L, + (char)3134, (char)3136, (char)NSM, (char)3137, (char)3141, (char)L, (char)3142, (char)3144, (char)NSM, (char)3145, (char)3145, (char)L, + (char)3146, (char)3149, (char)NSM, (char)3150, (char)3156, (char)L, (char)3157, (char)3158, (char)NSM, (char)3159, (char)3259, (char)L, + (char)3260, (char)3260, (char)NSM, (char)3261, (char)3275, (char)L, (char)3276, (char)3277, (char)NSM, (char)3278, (char)3392, (char)L, + (char)3393, (char)3395, (char)NSM, (char)3396, (char)3404, (char)L, (char)3405, (char)3405, (char)NSM, (char)3406, (char)3529, (char)L, + (char)3530, (char)3530, (char)NSM, (char)3531, (char)3537, (char)L, (char)3538, (char)3540, (char)NSM, (char)3541, (char)3541, (char)L, + (char)3542, (char)3542, (char)NSM, (char)3543, (char)3632, (char)L, (char)3633, (char)3633, (char)NSM, (char)3634, (char)3635, (char)L, + (char)3636, (char)3642, (char)NSM, (char)3643, (char)3646, (char)L, (char)3647, (char)3647, (char)ET, (char)3648, (char)3654, (char)L, + (char)3655, (char)3662, (char)NSM, (char)3663, (char)3760, (char)L, (char)3761, (char)3761, (char)NSM, (char)3762, (char)3763, (char)L, + (char)3764, (char)3769, (char)NSM, (char)3770, (char)3770, (char)L, (char)3771, (char)3772, (char)NSM, (char)3773, (char)3783, (char)L, + (char)3784, (char)3789, (char)NSM, (char)3790, (char)3863, (char)L, (char)3864, (char)3865, (char)NSM, (char)3866, (char)3892, (char)L, + (char)3893, (char)3893, (char)NSM, (char)3894, (char)3894, (char)L, (char)3895, (char)3895, (char)NSM, (char)3896, (char)3896, (char)L, + (char)3897, (char)3897, (char)NSM, (char)3898, (char)3901, (char)ON, (char)3902, (char)3952, (char)L, (char)3953, (char)3966, (char)NSM, + (char)3967, (char)3967, (char)L, (char)3968, (char)3972, (char)NSM, (char)3973, (char)3973, (char)L, (char)3974, (char)3975, (char)NSM, + (char)3976, (char)3983, (char)L, (char)3984, (char)3991, (char)NSM, (char)3992, (char)3992, (char)L, (char)3993, (char)4028, (char)NSM, + (char)4029, (char)4037, (char)L, (char)4038, (char)4038, (char)NSM, (char)4039, (char)4140, (char)L, (char)4141, (char)4144, (char)NSM, + (char)4145, (char)4145, (char)L, (char)4146, (char)4146, (char)NSM, (char)4147, (char)4149, (char)L, (char)4150, (char)4151, (char)NSM, + (char)4152, (char)4152, (char)L, (char)4153, (char)4153, (char)NSM, (char)4154, (char)4183, (char)L, (char)4184, (char)4185, (char)NSM, + (char)4186, (char)5759, (char)L, (char)5760, (char)5760, (char)WS, (char)5761, (char)5786, (char)L, (char)5787, (char)5788, (char)ON, + (char)5789, (char)5905, (char)L, (char)5906, (char)5908, (char)NSM, (char)5909, (char)5937, (char)L, (char)5938, (char)5940, (char)NSM, + (char)5941, (char)5969, (char)L, (char)5970, (char)5971, (char)NSM, (char)5972, (char)6001, (char)L, (char)6002, (char)6003, (char)NSM, + (char)6004, (char)6070, (char)L, (char)6071, (char)6077, (char)NSM, (char)6078, (char)6085, (char)L, (char)6086, (char)6086, (char)NSM, + (char)6087, (char)6088, (char)L, (char)6089, (char)6099, (char)NSM, (char)6100, (char)6106, (char)L, (char)6107, (char)6107, (char)ET, + (char)6108, (char)6108, (char)L, (char)6109, (char)6109, (char)NSM, (char)6110, (char)6127, (char)L, (char)6128, (char)6137, (char)ON, + (char)6138, (char)6143, (char)L, (char)6144, (char)6154, (char)ON, (char)6155, (char)6157, (char)NSM, (char)6158, (char)6158, (char)WS, + (char)6159, (char)6312, (char)L, (char)6313, (char)6313, (char)NSM, (char)6314, (char)6431, (char)L, (char)6432, (char)6434, (char)NSM, + (char)6435, (char)6438, (char)L, (char)6439, (char)6443, (char)NSM, (char)6444, (char)6449, (char)L, (char)6450, (char)6450, (char)NSM, + (char)6451, (char)6456, (char)L, (char)6457, (char)6459, (char)NSM, (char)6460, (char)6463, (char)L, (char)6464, (char)6464, (char)ON, + (char)6465, (char)6467, (char)L, (char)6468, (char)6469, (char)ON, (char)6470, (char)6623, (char)L, (char)6624, (char)6655, (char)ON, + (char)6656, (char)8124, (char)L, (char)8125, (char)8125, (char)ON, (char)8126, (char)8126, (char)L, (char)8127, (char)8129, (char)ON, + (char)8130, (char)8140, (char)L, (char)8141, (char)8143, (char)ON, (char)8144, (char)8156, (char)L, (char)8157, (char)8159, (char)ON, + (char)8160, (char)8172, (char)L, (char)8173, (char)8175, (char)ON, (char)8176, (char)8188, (char)L, (char)8189, (char)8190, (char)ON, + (char)8191, (char)8191, (char)L, (char)8192, (char)8202, (char)WS, (char)8203, (char)8205, (char)BN, (char)8206, (char)8206, (char)L, + (char)8207, (char)8207, (char)R, (char)8208, (char)8231, (char)ON, (char)8232, (char)8232, (char)WS, (char)8233, (char)8233, (char)B, + (char)8234, (char)8234, (char)LRE, (char)8235, (char)8235, (char)RLE, (char)8236, (char)8236, (char)PDF, (char)8237, (char)8237, (char)LRO, + (char)8238, (char)8238, (char)RLO, (char)8239, (char)8239, (char)WS, (char)8240, (char)8244, (char)ET, (char)8245, (char)8276, (char)ON, + (char)8277, (char)8278, (char)L, (char)8279, (char)8279, (char)ON, (char)8280, (char)8286, (char)L, (char)8287, (char)8287, (char)WS, + (char)8288, (char)8291, (char)BN, (char)8292, (char)8297, (char)L, (char)8298, (char)8303, (char)BN, (char)8304, (char)8304, (char)EN, + (char)8305, (char)8307, (char)L, (char)8308, (char)8313, (char)EN, (char)8314, (char)8315, (char)ET, (char)8316, (char)8318, (char)ON, + (char)8319, (char)8319, (char)L, (char)8320, (char)8329, (char)EN, (char)8330, (char)8331, (char)ET, (char)8332, (char)8334, (char)ON, + (char)8335, (char)8351, (char)L, (char)8352, (char)8369, (char)ET, (char)8370, (char)8399, (char)L, (char)8400, (char)8426, (char)NSM, + (char)8427, (char)8447, (char)L, (char)8448, (char)8449, (char)ON, (char)8450, (char)8450, (char)L, (char)8451, (char)8454, (char)ON, + (char)8455, (char)8455, (char)L, (char)8456, (char)8457, (char)ON, (char)8458, (char)8467, (char)L, (char)8468, (char)8468, (char)ON, + (char)8469, (char)8469, (char)L, (char)8470, (char)8472, (char)ON, (char)8473, (char)8477, (char)L, (char)8478, (char)8483, (char)ON, + (char)8484, (char)8484, (char)L, (char)8485, (char)8485, (char)ON, (char)8486, (char)8486, (char)L, (char)8487, (char)8487, (char)ON, + (char)8488, (char)8488, (char)L, (char)8489, (char)8489, (char)ON, (char)8490, (char)8493, (char)L, (char)8494, (char)8494, (char)ET, + (char)8495, (char)8497, (char)L, (char)8498, (char)8498, (char)ON, (char)8499, (char)8505, (char)L, (char)8506, (char)8507, (char)ON, + (char)8508, (char)8511, (char)L, (char)8512, (char)8516, (char)ON, (char)8517, (char)8521, (char)L, (char)8522, (char)8523, (char)ON, + (char)8524, (char)8530, (char)L, (char)8531, (char)8543, (char)ON, (char)8544, (char)8591, (char)L, (char)8592, (char)8721, (char)ON, + (char)8722, (char)8723, (char)ET, (char)8724, (char)9013, (char)ON, (char)9014, (char)9082, (char)L, (char)9083, (char)9108, (char)ON, + (char)9109, (char)9109, (char)L, (char)9110, (char)9168, (char)ON, (char)9169, (char)9215, (char)L, (char)9216, (char)9254, (char)ON, + (char)9255, (char)9279, (char)L, (char)9280, (char)9290, (char)ON, (char)9291, (char)9311, (char)L, (char)9312, (char)9371, (char)EN, + (char)9372, (char)9449, (char)L, (char)9450, (char)9450, (char)EN, (char)9451, (char)9751, (char)ON, (char)9752, (char)9752, (char)L, + (char)9753, (char)9853, (char)ON, (char)9854, (char)9855, (char)L, (char)9856, (char)9873, (char)ON, (char)9874, (char)9887, (char)L, + (char)9888, (char)9889, (char)ON, (char)9890, (char)9984, (char)L, (char)9985, (char)9988, (char)ON, (char)9989, (char)9989, (char)L, + (char)9990, (char)9993, (char)ON, (char)9994, (char)9995, (char)L, (char)9996, (char)10023, (char)ON, (char)10024, (char)10024, (char)L, + (char)10025, (char)10059, (char)ON, (char)10060, (char)10060, (char)L, (char)10061, (char)10061, (char)ON, (char)10062, (char)10062, (char)L, + (char)10063, (char)10066, (char)ON, (char)10067, (char)10069, (char)L, (char)10070, (char)10070, (char)ON, (char)10071, (char)10071, (char)L, + (char)10072, (char)10078, (char)ON, (char)10079, (char)10080, (char)L, (char)10081, (char)10132, (char)ON, (char)10133, (char)10135, (char)L, + (char)10136, (char)10159, (char)ON, (char)10160, (char)10160, (char)L, (char)10161, (char)10174, (char)ON, (char)10175, (char)10191, (char)L, + (char)10192, (char)10219, (char)ON, (char)10220, (char)10223, (char)L, (char)10224, (char)11021, (char)ON, (char)11022, (char)11903, (char)L, + (char)11904, (char)11929, (char)ON, (char)11930, (char)11930, (char)L, (char)11931, (char)12019, (char)ON, (char)12020, (char)12031, (char)L, + (char)12032, (char)12245, (char)ON, (char)12246, (char)12271, (char)L, (char)12272, (char)12283, (char)ON, (char)12284, (char)12287, (char)L, + (char)12288, (char)12288, (char)WS, (char)12289, (char)12292, (char)ON, (char)12293, (char)12295, (char)L, (char)12296, (char)12320, (char)ON, + (char)12321, (char)12329, (char)L, (char)12330, (char)12335, (char)NSM, (char)12336, (char)12336, (char)ON, (char)12337, (char)12341, (char)L, + (char)12342, (char)12343, (char)ON, (char)12344, (char)12348, (char)L, (char)12349, (char)12351, (char)ON, (char)12352, (char)12440, (char)L, + (char)12441, (char)12442, (char)NSM, (char)12443, (char)12444, (char)ON, (char)12445, (char)12447, (char)L, (char)12448, (char)12448, (char)ON, + (char)12449, (char)12538, (char)L, (char)12539, (char)12539, (char)ON, (char)12540, (char)12828, (char)L, (char)12829, (char)12830, (char)ON, + (char)12831, (char)12879, (char)L, (char)12880, (char)12895, (char)ON, (char)12896, (char)12923, (char)L, (char)12924, (char)12925, (char)ON, + (char)12926, (char)12976, (char)L, (char)12977, (char)12991, (char)ON, (char)12992, (char)13003, (char)L, (char)13004, (char)13007, (char)ON, + (char)13008, (char)13174, (char)L, (char)13175, (char)13178, (char)ON, (char)13179, (char)13277, (char)L, (char)13278, (char)13279, (char)ON, + (char)13280, (char)13310, (char)L, (char)13311, (char)13311, (char)ON, (char)13312, (char)19903, (char)L, (char)19904, (char)19967, (char)ON, + (char)19968, (char)42127, (char)L, (char)42128, (char)42182, (char)ON, (char)42183, (char)64284, (char)L, (char)64285, (char)64285, (char)R, + (char)64286, (char)64286, (char)NSM, (char)64287, (char)64296, (char)R, (char)64297, (char)64297, (char)ET, (char)64298, (char)64310, (char)R, + (char)64311, (char)64311, (char)L, (char)64312, (char)64316, (char)R, (char)64317, (char)64317, (char)L, (char)64318, (char)64318, (char)R, + (char)64319, (char)64319, (char)L, (char)64320, (char)64321, (char)R, (char)64322, (char)64322, (char)L, (char)64323, (char)64324, (char)R, + (char)64325, (char)64325, (char)L, (char)64326, (char)64335, (char)R, (char)64336, (char)64433, (char)AL, (char)64434, (char)64466, (char)L, + (char)64467, (char)64829, (char)AL, (char)64830, (char)64831, (char)ON, (char)64832, (char)64847, (char)L, (char)64848, (char)64911, (char)AL, + (char)64912, (char)64913, (char)L, (char)64914, (char)64967, (char)AL, (char)64968, (char)65007, (char)L, (char)65008, (char)65020, (char)AL, + (char)65021, (char)65021, (char)ON, (char)65022, (char)65023, (char)L, (char)65024, (char)65039, (char)NSM, (char)65040, (char)65055, (char)L, + (char)65056, (char)65059, (char)NSM, (char)65060, (char)65071, (char)L, (char)65072, (char)65103, (char)ON, (char)65104, (char)65104, (char)CS, + (char)65105, (char)65105, (char)ON, (char)65106, (char)65106, (char)CS, (char)65107, (char)65107, (char)L, (char)65108, (char)65108, (char)ON, + (char)65109, (char)65109, (char)CS, (char)65110, (char)65118, (char)ON, (char)65119, (char)65119, (char)ET, (char)65120, (char)65121, (char)ON, + (char)65122, (char)65123, (char)ET, (char)65124, (char)65126, (char)ON, (char)65127, (char)65127, (char)L, (char)65128, (char)65128, (char)ON, + (char)65129, (char)65130, (char)ET, (char)65131, (char)65131, (char)ON, (char)65132, (char)65135, (char)L, (char)65136, (char)65140, (char)AL, + (char)65141, (char)65141, (char)L, (char)65142, (char)65276, (char)AL, (char)65277, (char)65278, (char)L, (char)65279, (char)65279, (char)BN, + (char)65280, (char)65280, (char)L, (char)65281, (char)65282, (char)ON, (char)65283, (char)65285, (char)ET, (char)65286, (char)65290, (char)ON, + (char)65291, (char)65291, (char)ET, (char)65292, (char)65292, (char)CS, (char)65293, (char)65293, (char)ET, (char)65294, (char)65294, (char)CS, + (char)65295, (char)65295, (char)ES, (char)65296, (char)65305, (char)EN, (char)65306, (char)65306, (char)CS, (char)65307, (char)65312, (char)ON, + (char)65313, (char)65338, (char)L, (char)65339, (char)65344, (char)ON, (char)65345, (char)65370, (char)L, (char)65371, (char)65381, (char)ON, + (char)65382, (char)65503, (char)L, (char)65504, (char)65505, (char)ET, (char)65506, (char)65508, (char)ON, (char)65509, (char)65510, (char)ET, + (char)65511, (char)65511, (char)L, (char)65512, (char)65518, (char)ON, (char)65519, (char)65528, (char)L, (char)65529, (char)65531, (char)BN, + (char)65532, (char)65533, (char)ON, (char)65534, (char)65535, (char)L}; + + static BidiOrder() { + for (int k = 0; k < baseTypes.Length; ++k) { + int start = baseTypes[k]; + int end = baseTypes[++k]; + sbyte b = (sbyte)baseTypes[++k]; + while (start <= end) + rtypes[start++] = b; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs b/iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs new file mode 100644 index 0000000..8c7d617 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs @@ -0,0 +1,673 @@ +using System; +using System.IO; +using System.Text; +using System.Globalization; + +/* + * $Id: ByteBuffer.cs,v 1.7 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Acts like a StringBuilder but works with byte arrays. + * floating point is converted to a format suitable to the PDF. + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class ByteBuffer : Stream { + /** The count of bytes in the buffer. */ + protected int count; + + /** The buffer where the bytes are stored. */ + protected byte[] buf; + + private static int byteCacheSize = 0; + + private static byte[][] byteCache = new byte[byteCacheSize][]; + public const byte ZERO = (byte)'0'; + private static char[] chars = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + private static byte[] bytes = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102}; + /** + * If true always output floating point numbers with 6 decimal digits. + * If false uses the faster, although less precise, representation. + */ + public static bool HIGH_PRECISION = false; + + /** Creates new ByteBuffer with capacity 128 */ + public ByteBuffer() : this(128) {} + + /** + * Creates a byte buffer with a certain capacity. + * @param size the initial capacity + */ + public ByteBuffer(int size) { + if (size < 1) + size = 128; + buf = new byte[size]; + } + + /** + * Sets the cache size. + *

+ * This can only be used to increment the size. + * If the size that is passed through is smaller than the current size, nothing happens. + * + * @param size the size of the cache + */ + + public static void SetCacheSize(int size) { + if (size > 3276700) size = 3276700; + if (size <= byteCacheSize) return; + byte[][] tmpCache = new byte[size][]; + System.Array.Copy(byteCache, 0, tmpCache, 0, byteCacheSize); + byteCache = tmpCache; + byteCacheSize = size; + } + + /** + * You can fill the cache in advance if you want to. + * + * @param decimals + */ + + public static void FillCache(int decimals) { + int step = 1; + switch (decimals) { + case 0: + step = 100; + break; + case 1: + step = 10; + break; + } + for (int i = 1; i < byteCacheSize; i += step) { + if (byteCache[i] != null) continue; + byteCache[i] = ConvertToBytes(i); + } + } + + /** + * Converts an double (multiplied by 100 and cast to an int) into an array of bytes. + * + * @param i the int + * @return a bytearray + */ + + private static byte[] ConvertToBytes(int i) { + int size = (int)Math.Floor(Math.Log(i) / Math.Log(10)); + if (i % 100 != 0) { + size += 2; + } + if (i % 10 != 0) { + size++; + } + if (i < 100) { + size++; + if (i < 10) { + size++; + } + } + size--; + byte[] cache = new byte[size]; + size --; + if (i < 100) { + cache[0] = (byte)'0'; + } + if (i % 10 != 0) { + cache[size--] = bytes[i % 10]; + } + if (i % 100 != 0) { + cache[size--] = bytes[(i / 10) % 10]; + cache[size--] = (byte)'.'; + } + size = (int)Math.Floor(Math.Log(i) / Math.Log(10)) - 1; + int add = 0; + while (add < size) { + cache[add] = bytes[(i / (int)Math.Pow(10, size - add + 1)) % 10]; + add++; + } + return cache; + } + + /** + * Appends an int. The size of the array will grow by one. + * @param b the int to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append_i(int b) { + int newcount = count + 1; + if (newcount > buf.Length) { + byte[] newbuf = new byte[Math.Max(buf.Length << 1, newcount)]; + Array.Copy(buf, 0, newbuf, 0, count); + buf = newbuf; + } + buf[count] = (byte)b; + count = newcount; + return this; + } + + /** + * Appends the subarray of the byte array. The buffer will grow by + * len bytes. + * @param b the array to be appended + * @param off the offset to the start of the array + * @param len the length of bytes to Append + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(byte[] b, int off, int len) { + if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0) || len == 0) + return this; + int newcount = count + len; + if (newcount > buf.Length) { + byte[] newbuf = new byte[Math.Max(buf.Length << 1, newcount)]; + Array.Copy(buf, 0, newbuf, 0, count); + buf = newbuf; + } + Array.Copy(b, off, buf, count, len); + count = newcount; + return this; + } + + /** + * Appends an array of bytes. + * @param b the array to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(byte[] b) { + return Append(b, 0, b.Length); + } + + /** + * Appends a string to the buffer. The string is + * converted according to the encoding ISO-8859-1. + * @param str the string to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(string str) { + if (str != null) + return Append(DocWriter.GetISOBytes(str)); + return this; + } + + /** + * Appends a char to the buffer. The char is + * converted according to the encoding ISO-8859-1. + * @param c the char to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(char c) { + return Append_i(c); + } + + /** + * Appends another ByteBuffer to this buffer. + * @param buf the ByteBuffer to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(ByteBuffer buf) { + return Append(buf.buf, 0, buf.count); + } + + /** + * Appends the string representation of an int. + * @param i the int to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(int i) { + return Append((double)i); + } + + public ByteBuffer Append(byte b) { + return Append_i(b); + } + + public ByteBuffer AppendHex(byte b) { + Append(bytes[(b >> 4) & 0x0f]); + return Append(bytes[b & 0x0f]); + } + + /** + * Appends a string representation of a float according + * to the Pdf conventions. + * @param i the float to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(float i) { + return Append((double)i); + } + + /** + * Appends a string representation of a double according + * to the Pdf conventions. + * @param d the double to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(double d) { + Append(FormatDouble(d, this)); + return this; + } + + /** + * Outputs a double into a format suitable for the PDF. + * @param d a double + * @return the string representation of the double + */ + public static string FormatDouble(double d) { + return FormatDouble(d, null); + } + + /** + * Outputs a double into a format suitable for the PDF. + * @param d a double + * @param buf a ByteBuffer + * @return the String representation of the double if + * buf is null. If buf is not null, + * then the double is appended directly to the buffer and this methods returns null. + */ + public static string FormatDouble(double d, ByteBuffer buf) { + if (HIGH_PRECISION) { + String sform = d.ToString("0.######", CultureInfo.InvariantCulture); + if (buf == null) + return sform; + else { + buf.Append(sform); + return null; + } + } + bool negative = false; + if (Math.Abs(d) < 0.000015) { + if (buf != null) { + buf.Append(ZERO); + return null; + } else { + return "0"; + } + } + if (d < 0) { + negative = true; + d = -d; + } + if (d < 1.0) { + d += 0.000005; + if (d >= 1) { + if (negative) { + if (buf != null) { + buf.Append((byte)'-'); + buf.Append((byte)'1'); + return null; + } else { + return "-1"; + } + } else { + if (buf != null) { + buf.Append((byte)'1'); + return null; + } else { + return "1"; + } + } + } + if (buf != null) { + int v = (int) (d * 100000); + + if (negative) buf.Append((byte)'-'); + buf.Append((byte)'0'); + buf.Append((byte)'.'); + + buf.Append( (byte)(v / 10000 + ZERO) ); + if (v % 10000 != 0) { + buf.Append( (byte)((v / 1000) % 10 + ZERO) ); + if (v % 1000 != 0) { + buf.Append( (byte)((v / 100) % 10 + ZERO) ); + if (v % 100 != 0) { + buf.Append((byte)((v / 10) % 10 + ZERO) ); + if (v % 10 != 0) { + buf.Append((byte)((v) % 10 + ZERO) ); + } + } + } + } + return null; + } else { + int x = 100000; + int v = (int) (d * x); + + StringBuilder res = new StringBuilder(); + if (negative) res.Append('-'); + res.Append("0."); + + while ( v < x/10 ) { + res.Append('0'); + x /= 10; + } + res.Append(v); + int cut = res.Length - 1; + while (res[cut] == '0') { + --cut; + } + res.Length = cut + 1; + return res.ToString(); + } + } else if (d <= 32767) { + d += 0.005; + int v = (int) (d * 100); + + if (v < byteCacheSize && byteCache[v] != null) { + if (buf != null) { + if (negative) buf.Append((byte)'-'); + buf.Append(byteCache[v]); + return null; + } else { + string tmp = PdfEncodings.ConvertToString(byteCache[v], null); + if (negative) tmp = "-" + tmp; + return tmp; + } + } + if (buf != null) { + if (v < byteCacheSize) { + //create the cachebyte[] + byte[] cache; + int size = 0; + if (v >= 1000000) { + //the original number is >=10000, we need 5 more bytes + size += 5; + } else if (v >= 100000) { + //the original number is >=1000, we need 4 more bytes + size += 4; + } else if (v >= 10000) { + //the original number is >=100, we need 3 more bytes + size += 3; + } else if (v >= 1000) { + //the original number is >=10, we need 2 more bytes + size += 2; + } else if (v >= 100) { + //the original number is >=1, we need 1 more bytes + size += 1; + } + + //now we must check if we have a decimal number + if (v % 100 != 0) { + //yes, do not forget the "." + size += 2; + } + if (v % 10 != 0) { + size++; + } + cache = new byte[size]; + int add = 0; + if (v >= 1000000) { + cache[add++] = bytes[(v / 1000000)]; + } + if (v >= 100000) { + cache[add++] = bytes[(v / 100000) % 10]; + } + if (v >= 10000) { + cache[add++] = bytes[(v / 10000) % 10]; + } + if (v >= 1000) { + cache[add++] = bytes[(v / 1000) % 10]; + } + if (v >= 100) { + cache[add++] = bytes[(v / 100) % 10]; + } + + if (v % 100 != 0) { + cache[add++] = (byte)'.'; + cache[add++] = bytes[(v / 10) % 10]; + if (v % 10 != 0) { + cache[add++] = bytes[v % 10]; + } + } + byteCache[v] = cache; + } + + if (negative) buf.Append((byte)'-'); + if (v >= 1000000) { + buf.Append( bytes[(v / 1000000)] ); + } + if (v >= 100000) { + buf.Append( bytes[(v / 100000) % 10] ); + } + if (v >= 10000) { + buf.Append( bytes[(v / 10000) % 10] ); + } + if (v >= 1000) { + buf.Append( bytes[(v / 1000) % 10] ); + } + if (v >= 100) { + buf.Append( bytes[(v / 100) % 10] ); + } + + if (v % 100 != 0) { + buf.Append((byte)'.'); + buf.Append( bytes[(v / 10) % 10] ); + if (v % 10 != 0) { + buf.Append( bytes[v % 10] ); + } + } + return null; + } else { + StringBuilder res = new StringBuilder(); + if (negative) res.Append('-'); + if (v >= 1000000) { + res.Append( chars[(v / 1000000)] ); + } + if (v >= 100000) { + res.Append( chars[(v / 100000) % 10] ); + } + if (v >= 10000) { + res.Append( chars[(v / 10000) % 10] ); + } + if (v >= 1000) { + res.Append( chars[(v / 1000) % 10] ); + } + if (v >= 100) { + res.Append( chars[(v / 100) % 10] ); + } + + if (v % 100 != 0) { + res.Append('.'); + res.Append( chars[(v / 10) % 10] ); + if (v % 10 != 0) { + res.Append( chars[v % 10] ); + } + } + return res.ToString(); + } + } else { + StringBuilder res = new StringBuilder(); + if (negative) res.Append('-'); + d += 0.5; + long v = (long) d; + return res.Append(v).ToString(); + } + } + + /** + * Sets the size to zero. + */ + public void Reset() { + count = 0; + } + + /** + * Creates a newly allocated byte array. Its size is the current + * size of this output stream and the valid contents of the buffer + * have been copied into it. + * + * @return the current contents of this output stream, as a byte array. + */ + public byte[] ToByteArray() { + byte[] newbuf = new byte[count]; + Array.Copy(buf, 0, newbuf, 0, count); + return newbuf; + } + + /** + * Returns the current size of the buffer. + * + * @return the value of the count field, which is the number of valid bytes in this byte buffer. + */ + public int Size { + get { + return count; + } + set { + if (value > count || value < 0) + throw new ArgumentOutOfRangeException("The new size must be positive and <= of the current size"); + count = value; + } + } + + /** + * Converts the buffer's contents into a string, translating bytes into + * characters according to the platform's default character encoding. + * + * @return string translated from the buffer's contents. + */ + public override string ToString() { + char[] tmp = this.ConvertToChar(buf); + return new String(tmp, 0, count); + } + + /** + * Converts the buffer's contents into a string, translating bytes into + * characters according to the specified character encoding. + * + * @param enc a character-encoding name. + * @return string translated from the buffer's contents. + * @throws UnsupportedEncodingException + * If the named encoding is not supported. + */ +// public string ToString(System.Text.Encoding enc) { +// return new String(ref buf, 0, count, enc); +// } + + /** + * Writes the complete contents of this byte buffer output to + * the specified output stream argument, as if by calling the output + * stream's write method using out.Write(buf, 0, count). + * + * @param out the output stream to which to write the data. + * @exception IOException if an I/O error occurs. + */ + public void WriteTo(Stream str) { + str.Write(buf, 0, count); + } + + private char[] ConvertToChar(byte[] buf) { + char[] retVal = new char[count + 1]; + for (int i = 0; i <= count; i++) { + retVal[i] = (char)buf[i]; + } + return retVal; + } + + public byte[] Buffer { + get { + return buf; + } + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + return count; + } + } + + public override long Position { + get { + return count; + } + set { + } + } + + public override void Flush() { + } + + public override int Read(byte[] buffer, int offset, int count) { + return 0; + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + Append(buffer, offset, count); + } + + public override void WriteByte(byte value) { + Append(value); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CFFFont.cs b/iTechSharp/iTextSharp/text/pdf/CFFFont.cs new file mode 100644 index 0000000..4062617 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/CFFFont.cs @@ -0,0 +1,1111 @@ +using System; +using System.Text; +using System.Collections; +/* + * + * Copyright 2003 Sivan Toledo + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + */ + +namespace iTextSharp.text.pdf { + public class CFFFont { + + internal static String[] operatorNames = { + "version", "Notice", "FullName", "FamilyName", + "Weight", "FontBBox", "BlueValues", "OtherBlues", + "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", + "UNKNOWN_12", "UniqueID", "XUID", "charset", + "Encoding", "CharStrings", "Private", "Subrs", + "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23", + "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27", + "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31", + "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", + "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", + "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz", + "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15", + "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed", + "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", + "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27", + "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion", + "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", + "FDArray", "FDSelect", "FontName" + }; + + internal static String[] standardStrings = { + // Automatically generated from Appendix A of the CFF specification; do + // not edit. Size should be 391. + ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quoteright", "parenleft", "parenright", + "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", + "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", + "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", + "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", + "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", + "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", + "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", + "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", + "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", + "florin", "section", "currency", "quotesingle", "quotedblleft", + "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", + "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", + "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", + "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", + "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", + "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", + "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", + "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", + "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", + "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", + "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", + "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", + "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", + "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", + "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", + "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", + "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", + "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", + "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", + "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", + "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", + "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", + "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", + "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", + "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", + "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", + "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", + "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", + "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", + "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", + "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", + "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", + "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", + "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", + "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", + "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", + "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", + "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", + "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", + "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", + "threeinferior", "fourinferior", "fiveinferior", "sixinferior", + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", "periodinferior", "commainferior", "Agravesmall", + "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", + "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", + "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", + "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", + "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", + "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", + "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" + }; + + //private String[] strings; + public String GetString(char sid) { + if (sid < standardStrings.Length) return standardStrings[sid]; + if (sid >= standardStrings.Length+(stringOffsets.Length-1)) return null; + int j = sid - standardStrings.Length; + int p = GetPosition(); + Seek(stringOffsets[j]); + StringBuilder s = new StringBuilder(); + for (int k=stringOffsets[j]; k count in the index header. 1->offset size in index header + + 2+1 + //offset array size * offset size + + (count+1)*indexOffSize + //???zero <-> one base + - 1 + // read object offset relative to object array base + + GetOffset(indexOffSize); + } + //nextIndexOffset = offsets[count]; + return offsets; + } + + protected String key; + protected Object[] args = new Object[48]; + protected int arg_count = 0; + + protected void GetDictItem() { + for (int i=0; i= 32 && b0 <= 246) { + sbyte item = (sbyte) ((int)b0-139); + args[arg_count] = (int)item; + arg_count++; + //System.err.Println(item+" "); + continue; + } + if (b0 >= 247 && b0 <= 250) { + char b1 = GetCard8(); + short item = (short) (((int)b0-247)*256+(int)b1+108); + args[arg_count] = (int)item; + arg_count++; + //System.err.Println(item+" "); + continue; + } + if (b0 >= 251 && b0 <= 254) { + char b1 = GetCard8(); + short item = (short) (-((int)b0-251)*256-(int)b1-108); + args[arg_count] = (int)item; + arg_count++; + //System.err.Println(item+" "); + continue; + } + if (b0 == 30) { + String item = ""; + bool done = false; + char buffer = (char)0; + byte avail = 0; + int nibble = 0; + while (!done) { + // get a nibble + if (avail==0) { buffer = GetCard8(); avail=2; } + if (avail==1) { nibble = (buffer / 16); avail--; } + if (avail==2) { nibble = (buffer % 16); avail--; } + switch (nibble) { + case 0xa: item += "." ; break; + case 0xb: item += "E" ; break; + case 0xc: item += "E-"; break; + case 0xe: item += "-" ; break; + case 0xf: done=true ; break; + default: + if (nibble >= 0 && nibble <= 9) + item += nibble.ToString(); + else { + item += ""; + done = true; + } + break; + } + } + args[arg_count] = item; + arg_count++; + //System.err.Println(" real=["+item+"]"); + continue; + } + if (b0 <= 21) { + gotKey=true; + if (b0 != 12) key = operatorNames[b0]; + else key = operatorNames[32 + GetCard8()]; + //for (int i=0; i> 24) & 0xff); + i++; + goto case 3; + case 3: + buffer[myOffset+i] = (byte) ((value >> 16) & 0xff); + i++; + goto case 2; + case 2: + buffer[myOffset+i] = (byte) ((value >> 8) & 0xff); + i++; + goto case 1; + case 1: + buffer[myOffset+i] = (byte) ((value >> 0) & 0xff); + i++; + break; + } + /* + int mask = 0xff; + for (int i=size-1; i>=0; i--) { + buffer[myOffset+i] = (byte) (value & mask); + mask <<= 8; + } + */ + } + } + + protected internal class IndexBaseItem : Item { + public IndexBaseItem() {} + } + + protected internal class IndexMarkerItem : Item { + private OffsetItem offItem; + private IndexBaseItem indexBase; + public IndexMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { + this.offItem = offItem; + this.indexBase = indexBase; + } + public override void Xref() { + //System.err.Println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); + offItem.Set(this.myOffset-indexBase.myOffset+1); + } + } + /** + * + * @author orly manor + * + * TODO To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ + protected internal class SubrMarkerItem : Item { + private OffsetItem offItem; + private IndexBaseItem indexBase; + public SubrMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { + this.offItem = offItem; + this.indexBase = indexBase; + } + public override void Xref() { + //System.err.Println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); + offItem.Set(this.myOffset-indexBase.myOffset); + } + } + + + /** an unknown offset in a dictionary for the list. + * We will fix up the offset later; for now, assume it's large. + */ + protected internal class DictOffsetItem : OffsetItem { + public int size; + public DictOffsetItem() {this.size=5; } + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += size; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + if (size==5) { + buffer[myOffset] = 29; + buffer[myOffset+1] = (byte) ((value >> 24) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+3] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+4] = (byte) ((value >> 0) & 0xff); + } + } + } + + /** Card24 item. + */ + + protected internal class UInt24Item : Item { + public int value; + public UInt24Item(int value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 3; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+1] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 0) & 0xff); + } + } + + /** Card32 item. + */ + + protected internal class UInt32Item : Item { + public int value; + public UInt32Item(int value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 4; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 24) & 0xff); + buffer[myOffset+1] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+3] = (byte) ((value >> 0) & 0xff); + } + } + + /** A SID or Card16 item. + */ + + protected internal class UInt16Item : Item { + public char value; + public UInt16Item(char value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 2; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+1] = (byte) ((value >> 0) & 0xff); + } + } + + /** A Card8 item. + */ + + protected internal class UInt8Item : Item { + public char value; + public UInt8Item(char value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 1; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 0) & 0xff); + } + } + + protected internal class StringItem : Item { + public String s; + public StringItem(String s) {this.s=s;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += s.Length; + } + public override void Emit(byte[] buffer) { + for (int i=0; i> 24) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+3] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+4] = (byte) ((value >> 0) & 0xff); + } + } + } + + /** An offset-marker item for the list. + * It is used to mark an offset and to set the offset list item. + */ + + protected internal class MarkerItem : Item { + OffsetItem p; + public MarkerItem(OffsetItem pointerToMarker) {p=pointerToMarker;} + public override void Xref() { + p.Set(this.myOffset); + } + } + + /** a utility that creates a range item for an entire index + * + * @param indexOffset where the index is + * @return a range item representing the entire index + */ + + protected virtual RangeItem GetEntireIndexRange(int indexOffset) { + Seek(indexOffset); + int count = GetCard16(); + if (count==0) { + return new RangeItem(buf,indexOffset,2); + } else { + int indexOffSize = GetCard8(); + Seek(indexOffset+2+1+count*indexOffSize); + int size = GetOffset(indexOffSize)-1; + return new RangeItem(buf,indexOffset, + 2+1+(count+1)*indexOffSize+size); + } + } + + + /** get a single CID font. The PDF architecture (1.4) + * supports 16-bit strings only with CID CFF fonts, not + * in Type-1 CFF fonts, so we convert the font to CID if + * it is in the Type-1 format. + * Two other tasks that we need to do are to select + * only a single font from the CFF package (this again is + * a PDF restriction) and to subset the CharStrings glyph + * description. + */ + + + public byte[] GetCID(String fontName) + //throws java.io.FileNotFoundException + { + int j; + for (j=0; j 127) + fdFontName = fdFontName.Substring(0,127); + String extraStrings = "Adobe"+"Identity"+fdFontName; + + int origStringsLen = stringOffsets[stringOffsets.Length-1] + - stringOffsets[0]; + int stringsBaseOffset = stringOffsets[0]-1; + + byte stringsIndexOffSize; + if (origStringsLen+extraStrings.Length <= 0xff) stringsIndexOffSize = 1; + else if (origStringsLen+extraStrings.Length <= 0xffff) stringsIndexOffSize = 2; + else if (origStringsLen+extraStrings.Length <= 0xffffff) stringsIndexOffSize = 3; + else stringsIndexOffSize = 4; + + l.Add(new UInt16Item((char)((stringOffsets.Length-1)+3))); // count + l.Add(new UInt8Item((char)stringsIndexOffSize)); // offSize + for (int i=0; i= 0) { + //System.err.Println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength); + l.Add(GetEntireIndexRange(fonts[j].privateSubrs)); + } + } + + // copy the charstring index + + l.Add(new MarkerItem(charstringsRef)); + l.Add(GetEntireIndexRange(fonts[j].charstringsOffset)); + + // now create the new CFF font + + int[] currentOffset = new int[1]; + currentOffset[0] = 0; + + foreach (Item item in l) { + item.Increment(currentOffset); + } + + foreach (Item item in l) { + item.Xref(); + } + + int size = currentOffset[0]; + byte[] b = new byte[size]; + + foreach (Item item in l) { + item.Emit(b); + } + + return b; + } + + + public bool IsCID(String fontName) { + int j; + for (j=0; j"); + } + + // string index + + //strings = new String[stringOffsets.length-1]; + /* + System.err.Println("std strings = "+standardStrings.length); + System.err.Println("fnt strings = "+(stringOffsets.length-1)); + for (char j=0; j"); + } + */ + + // top dict + + for (int j=0; j= 0) { + //System.err.Println("PRIVATE::"); + Seek(fonts[j].privateOffset); + while (GetPosition() < fonts[j].privateOffset+fonts[j].privateLength) { + GetDictItem(); + if (key=="Subrs") + //Add the private offset to the lsubrs since the offset is + // relative to the begining of the PrivateDict + fonts[j].privateSubrs = (int)args[0]+fonts[j].privateOffset; + } + } + + // fdarray index + if (fonts[j].fdarrayOffset >= 0) { + int[] fdarrayOffsets = GetIndex(fonts[j].fdarrayOffset); + + fonts[j].fdprivateOffsets = new int[fdarrayOffsets.Length-1]; + fonts[j].fdprivateLengths = new int[fdarrayOffsets.Length-1]; + + //System.err.Println("FD Font::"); + + for (int k=0; k + * @author Oren Manor & Ygal Blum + */ + public class CFFFontSubset : CFFFont { + + /** + * The Strings in this array represent Type1/Type2 operator names + */ + internal static String[] SubrsFunctions = { + "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto", + "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13", + "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask", + "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto", + "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto" + }; + /** + * The Strings in this array represent Type1/Type2 escape operator names + */ + internal static String[] SubrsEscapeFuncs = { + "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6", + "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg", + "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse", + "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31", + "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST" + }; + + /** + * A HashMap containing the glyphs used in the text after being converted + * to glyph number by the CMap + */ + internal Hashtable GlyphsUsed; + /** + * The GlyphsUsed keys as an ArrayList + */ + internal ArrayList glyphsInList; + /** + * A HashMap for keeping the FDArrays being used by the font + */ + internal Hashtable FDArrayUsed = new Hashtable(); + /** + * A HashMaps array for keeping the subroutines used in each FontDict + */ + internal Hashtable[] hSubrsUsed; + /** + * The SubroutinesUsed HashMaps as ArrayLists + */ + internal ArrayList[] lSubrsUsed; + /** + * A HashMap for keeping the Global subroutines used in the font + */ + internal Hashtable hGSubrsUsed = new Hashtable(); + /** + * The Global SubroutinesUsed HashMaps as ArrayLists + */ + internal ArrayList lGSubrsUsed = new ArrayList(); + /** + * A HashMap for keeping the subroutines used in a non-cid font + */ + internal Hashtable hSubrsUsedNonCID = new Hashtable(); + /** + * The SubroutinesUsed HashMap as ArrayList + */ + internal ArrayList lSubrsUsedNonCID = new ArrayList(); + /** + * An array of the new Indexs for the local Subr. One index for each FontDict + */ + internal byte[][] NewLSubrsIndex; + /** + * The new subroutines index for a non-cid font + */ + internal byte[] NewSubrsIndexNonCID; + /** + * The new global subroutines index of the font + */ + internal byte[] NewGSubrsIndex; + /** + * The new CharString of the font + */ + internal byte[] NewCharStringsIndex; + + /** + * The bias for the global subroutines + */ + internal int GBias = 0; + + /** + * The linked list for generating the new font stream + */ + internal ArrayList OutputList; + + /** + * Number of arguments to the stem operators in a subroutine calculated recursivly + */ + internal int NumOfHints=0; + + + /** + * C'tor for CFFFontSubset + * @param rf - The font file + * @param GlyphsUsed - a HashMap that contains the glyph used in the subset + */ + public CFFFontSubset(RandomAccessFileOrArray rf,Hashtable GlyphsUsed) : base(rf) { + // Use CFFFont c'tor in order to parse the font file. + this.GlyphsUsed = GlyphsUsed; + //Put the glyphs into a list + glyphsInList = new ArrayList(GlyphsUsed.Keys); + + + for (int i=0;i=0) + { + // Proces the FDSelect + ReadFDSelect(i); + // Build the FDArrayUsed hashmap + BuildFDArrayUsed(i); + } + if (fonts[i].isCID) + // Build the FD Array used Hash Map + ReadFDArray(i); + // compute the charset length + fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs); + } + } + + /** + * Calculates the length of the charset according to its format + * @param Offset The Charset Offset + * @param NumofGlyphs Number of glyphs in the font + * @return the length of the Charset + */ + internal int CountCharset(int Offset,int NumofGlyphs){ + int format; + int Length=0; + Seek(Offset); + // Read the format + format = GetCard8(); + // Calc according to format + switch (format){ + case 0: + Length = 1+2*NumofGlyphs; + break; + case 1: + Length = 1+3*CountRange(NumofGlyphs,1); + break; + case 2: + Length = 1+4*CountRange(NumofGlyphs,2); + break; + default: + break; + } + return Length; + } + + /** + * Function calculates the number of ranges in the Charset + * @param NumofGlyphs The number of glyphs in the font + * @param Type The format of the Charset + * @return The number of ranges in the Charset data structure + */ + int CountRange(int NumofGlyphs,int Type){ + int num=0; + char Sid; + int i=1,nLeft; + while (i= 0) + GBias = CalcBias(gsubrIndexOffset,j); + + // Prepare the new CharStrings Index + BuildNewCharString(j); + // Prepare the new Global and Local Subrs Indices + BuildNewLGSubrs(j); + // Build the new file + byte[] Ret = BuildNewFile(j); + return Ret; + } + finally { + try { + buf.Close(); + } + catch { + // empty on purpose + } + } + } + + /** + * Function calcs bias according to the CharString type and the count + * of the subrs + * @param Offset The offset to the relevent subrs index + * @param Font the font + * @return The calculated Bias + */ + protected int CalcBias(int Offset,int Font) + { + Seek(Offset); + int nSubrs = GetCard16(); + // If type==1 -> bias=0 + if (fonts[Font].CharstringType == 1) + return 0; + // else calc according to the count + else if (nSubrs < 1240) + return 107; + else if (nSubrs < 33900) + return 1131; + else + return 32768; + } + + /** + *Function uses BuildNewIndex to create the new index of the subset charstrings + * @param FontIndex the font + * @throws IOException + */ + protected void BuildNewCharString(int FontIndex) + { + NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed); + } + + /** + * Function builds the new local & global subsrs indices. IF CID then All of + * the FD Array lsubrs will be subsetted. + * @param Font the font + * @throws IOException + */ + protected void BuildNewLGSubrs(int Font) + { + // If the font is CID then the lsubrs are divided into FontDicts. + // for each FD array the lsubrs will be subsetted. + if (fonts[Font].isCID) + { + // Init the hasmap-array and the arraylist-array to hold the subrs used + // in each private dict. + hSubrsUsed = new Hashtable[fonts[Font].fdprivateOffsets.Length]; + lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.Length]; + // A [][] which will store the byte array for each new FD Array lsubs index + NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.Length][]; + // An array to hold the offset for each Lsubr index + fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.Length]; + // A [][] which will store the offset array for each lsubr index + fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.Length][]; + + // Put the FDarrayUsed into a list + ArrayList FDInList = new ArrayList(FDArrayUsed.Keys); + // For each FD array which is used subset the lsubr + for (int j=0;j=0) + { + //Scans the Charsting data storing the used Local and Global subroutines + // by the glyphs. Scans the Subrs recursivley. + BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]); + // Builds the New Local Subrs index + NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD]); + } + } + } + // If the font is not CID && the Private Subr exists then subset: + else if (fonts[Font].privateSubrs>=0) + { + // Build the subrs offsets; + fonts[Font].SubrsOffsets = GetIndex(fonts[Font].privateSubrs); + //Scans the Charsting data storing the used Local and Global subroutines + // by the glyphs. Scans the Subrs recursivley. + BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID); + } + // For all fonts susbset the Global Subroutines + // Scan the Global Subr Hashmap recursivly on the Gsubrs + BuildGSubrsUsed(Font); + if (fonts[Font].privateSubrs>=0) + // Builds the New Local Subrs index + NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID); + //Builds the New Global Subrs index + NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed); + } + + /** + * The function finds for the FD array processed the local subr offset and its + * offset array. + * @param Font the font + * @param FD The FDARRAY processed + */ + protected void BuildFDSubrsOffsets(int Font,int FD) + { + // Initiate to -1 to indicate lsubr operator present + fonts[Font].PrivateSubrsOffset[FD] = -1; + // Goto begining of objects + Seek(fonts[Font].fdprivateOffsets[FD]); + // While in the same object: + while (GetPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD]) + { + GetDictItem(); + // If the dictItem is the "Subrs" then find and store offset, + if (key=="Subrs") + fonts[Font].PrivateSubrsOffset[FD] = (int)args[0]+fonts[Font].fdprivateOffsets[FD]; + } + //Read the lsub index if the lsubr was found + if (fonts[Font].PrivateSubrsOffset[FD] >= 0) + fonts[Font].PrivateSubrsOffsetsArray[FD] = GetIndex(fonts[Font].PrivateSubrsOffset[FD]); + } + + /** + * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap. + * The HashMap (of the lsub only) is then scaned recursivly for Lsubr & Gsubrs + * calls. + * @param Font the font + * @param FD FD array processed. 0 indicates function was called by non CID font + * @param SubrOffset the offset to the subr index to calc the bias + * @param SubrsOffsets the offset array of the subr index + * @param hSubr HashMap of the subrs used + * @param lSubr ArrayList of the subrs used + */ + protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,Hashtable hSubr,ArrayList lSubr) + { + + // Calc the Bias for the subr index + int LBias = CalcBias(SubrOffset,Font); + + // For each glyph used find its GID, start & end pos + for (int i=0;i= 0) + { + EmptyStack(); + NumOfHints=0; + // Using FDSELECT find the FD Array the glyph belongs to. + int GlyphFD = fonts[Font].FDSelect[glyph]; + // If the Glyph is part of the FD being processed + if (GlyphFD == FD) + // Find the Subrs called by the glyph and insert to hash: + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + else + // If the font is not CID + //Find the Subrs called by the glyph and insert to hash: + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used + for (int i=0;i=0) + { + // Read and process the subr + int Start = SubrsOffsets[Subr]; + int End = SubrsOffsets[Subr+1]; + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + } + } + + /** + * Function scans the Glsubr used ArrayList to find recursive calls + * to Gsubrs and adds to Hashmap & ArrayList + * @param Font the font + */ + protected void BuildGSubrsUsed(int Font) + { + int LBias = 0; + int SizeOfNonCIDSubrsUsed = 0; + if (fonts[Font].privateSubrs>=0) + { + LBias = CalcBias(fonts[Font].privateSubrs,Font); + SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.Count; + } + + // For each global subr used + for (int i=0;i=0) + { + // Read the subr and process + int Start = gsubrOffsets[Subr]; + int End = gsubrOffsets[Subr+1]; + + if (fonts[Font].isCID) + ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null); + else + { + ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); + if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.Count) + { + for (int j=SizeOfNonCIDSubrsUsed;j=0) + { + // Read the subr and process + int LStart = fonts[Font].SubrsOffsets[LSubr]; + int LEnd = fonts[Font].SubrsOffsets[LSubr+1]; + ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); + } + } + SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.Count; + } + } + } + } + } + + /** + * The function reads a subrs (glyph info) between begin and end. + * Adds calls to a Lsubr to the hSubr and lSubrs. + * Adds calls to a Gsubr to the hGSubr and lGSubrs. + * @param begin the start point of the subr + * @param end the end point of the subr + * @param GBias the bias of the Global Subrs + * @param LBias the bias of the Local Subrs + * @param hSubr the HashMap for the lSubrs + * @param lSubr the ArrayList for the lSubrs + */ + protected void ReadASubr(int begin,int end,int GBias,int LBias,Hashtable hSubr,ArrayList lSubr,int[] LSubrsOffsets) + { + // Clear the stack for the subrs + EmptyStack(); + NumOfHints = 0; + // Goto begining of the subr + Seek(begin); + while (GetPosition() < end) + { + // Read the next command + ReadCommand(); + int pos = GetPosition(); + Object TopElement=null; + if (arg_count > 0) + TopElement = args[arg_count-1]; + int NumOfArgs = arg_count; + // Check the modification needed on the Argument Stack according to key; + HandelStack(); + // a call to a Lsubr + if (key=="callsubr") + { + // Verify that arguments are passed + if (NumOfArgs > 0) + { + // Calc the index of the Subrs + int Subr = (int)TopElement + LBias; + // If the subr isn't in the HashMap -> Put in + if (!hSubr.ContainsKey(Subr)) + { + hSubr[Subr] = null; + lSubr.Add(Subr); + } + CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // a call to a Gsubr + else if (key=="callgsubr") + { + // Verify that arguments are passed + if (NumOfArgs > 0) + { + // Calc the index of the Subrs + int Subr = (int)TopElement + GBias; + // If the subr isn't in the HashMap -> Put in + if (!hGSubrsUsed.ContainsKey(Subr)) + { + hGSubrsUsed[Subr] = null; + lGSubrsUsed.Add(Subr); + } + CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // A call to "stem" + else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") + // Increment the NumOfHints by the number couples of of arguments + NumOfHints += NumOfArgs/2; + // A call to "mask" + else if (key == "hintmask" || key == "cntrmask") + { + // Compute the size of the mask + int SizeOfMask = NumOfHints/8; + if (NumOfHints%8 != 0 || SizeOfMask == 0) + SizeOfMask++; + // Continue the pointer in SizeOfMask steps + for (int i=0;i flush the stack + */ + protected int StackOpp() + { + if (key == "ifelse") + return -3; + if (key == "roll" || key == "put") + return -2; + if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" || + key == "div" || key == "mul" || key == "drop" || key == "and" || + key == "or" || key == "eq") + return -1; + if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" || + key == "index" || key == "get" || key == "not" || key == "return") + return 0; + if (key == "random" || key == "dup") + return 1; + return 2; + } + + /** + * Empty the Type2 Stack + * + */ + protected void EmptyStack() + { + // Null the arguments + for (int i=0; i0) + { + args[arg_count-1]=null; + arg_count--; + } + } + + /** + * Add an item to the stack + * + */ + protected void PushStack() + { + arg_count++; + } + + /** + * The function reads the next command after the file pointer is set + */ + protected void ReadCommand() + { + key = null; + bool gotKey = false; + // Until a key is found + while (!gotKey) { + // Read the first Char + char b0 = GetCard8(); + // decode according to the type1/type2 format + if (b0 == 28) // the two next bytes represent a short int; + { + int first = GetCard8(); + int second = GetCard8(); + args[arg_count] = first<<8 | second; + arg_count++; + continue; + } + if (b0 >= 32 && b0 <= 246) // The byte read is the byte; + { + args[arg_count] = (int)b0 - 139; + arg_count++; + continue; + } + if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constetute a short int + { + int w = GetCard8(); + args[arg_count] = ((int)b0-247)*256 + w + 108; + arg_count++; + continue; + } + if (b0 >= 251 && b0 <= 254)// Same as above except negative + { + int w = GetCard8(); + args[arg_count] = -((int)b0-251)*256 - w - 108; + arg_count++; + continue; + } + if (b0 == 255)// The next for bytes represent a double. + { + int first = GetCard8(); + int second = GetCard8(); + int third = GetCard8(); + int fourth = GetCard8(); + args[arg_count] = first<<24 | second<<16 | third<<8 | fourth; + arg_count++; + continue; + } + if (b0<=31 && b0 != 28) // An operator was found.. Set Key. + { + gotKey=true; + // 12 is an escape command therefor the next byte is a part + // of this command + if (b0 == 12) + { + int b1 = GetCard8(); + if (b1>SubrsEscapeFuncs.Length-1) + b1 = SubrsEscapeFuncs.Length-1; + key = SubrsEscapeFuncs[b1]; + } + else + key = SubrsFunctions[b0]; + continue; + } + } + } + + /** + * The function reads the subroutine and returns the number of the hint in it. + * If a call to another subroutine is found the function calls recursively. + * @param begin the start point of the subr + * @param end the end point of the subr + * @param LBias the bias of the Local Subrs + * @param GBias the bias of the Global Subrs + * @param LSubrsOffsets The Offsets array of the subroutines + * @return The number of hints in the subroutine read. + */ + protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets) + { + // Goto begining of the subr + Seek(begin); + while (GetPosition() < end) + { + // Read the next command + ReadCommand(); + int pos = GetPosition(); + Object TopElement = null; + if (arg_count>0) + TopElement = args[arg_count-1]; + int NumOfArgs = arg_count; + //Check the modification needed on the Argument Stack according to key; + HandelStack(); + // a call to a Lsubr + if (key=="callsubr") + { + if (NumOfArgs>0) + { + int Subr = (int)TopElement + LBias; + CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // a call to a Gsubr + else if (key=="callgsubr") + { + if (NumOfArgs>0) + { + int Subr = (int)TopElement + GBias; + CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // A call to "stem" + else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") + // Increment the NumOfHints by the number couples of of arguments + NumOfHints += NumOfArgs/2; + // A call to "mask" + else if (key == "hintmask" || key == "cntrmask") + { + // Compute the size of the mask + int SizeOfMask = NumOfHints/8; + if (NumOfHints%8 != 0 || SizeOfMask == 0) + SizeOfMask++; + // Continue the pointer in SizeOfMask steps + for (int i=0;i> 8) & 0xff); + NewIndex[Place++] = (byte) ((Count >> 0) & 0xff); + // Write the offsize field + NewIndex[Place++] = Offsize; + // Write the offset array according to the offsize + for (int i=0;i> 24) & 0xff); + goto case 3; + case 3: + NewIndex[Place++] = (byte) ((Num >> 16) & 0xff); + goto case 2; + case 2: + NewIndex[Place++] = (byte) ((Num >> 8) & 0xff); + goto case 1; + case 1: + NewIndex[Place++] = (byte) ((Num >> 0) & 0xff); + break; + } + } + // Write the new object array one by one + for (int i=0;i=0) + OutputList.Add(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength)); + // Else create a new one + else + CreateFDSelect(fdselectRef,fonts[Font].nglyphs); + + // Copy the Charset + // Mark the beginning and copy entirly + OutputList.Add(new MarkerItem(charsetRef)); + OutputList.Add(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength)); + + // Copy the FDArray + // If an FDArray exists + if (fonts[Font].fdarrayOffset>=0) + { + // Mark the beginning + OutputList.Add(new MarkerItem(fdarrayRef)); + // Build a new FDArray with its private dicts and their LSubrs + Reconstruct(Font); + } + else + // Else create a new one + CreateFDArray(fdarrayRef,privateRef,Font); + + } + // If the font is not CID + else + { + // create FDSelect + CreateFDSelect(fdselectRef,fonts[Font].nglyphs); + // recreate a new charset + CreateCharset(charsetRef,fonts[Font].nglyphs); + // create a font dict index (fdarray) + CreateFDArray(fdarrayRef,privateRef,Font); + } + + // if a private dict exists insert its subsetted version + if (fonts[Font].privateOffset>=0) + { + // Mark the beginning of the private dict + IndexBaseItem PrivateBase = new IndexBaseItem(); + OutputList.Add(PrivateBase); + OutputList.Add(new MarkerItem(privateRef)); + + OffsetItem Subr = new DictOffsetItem(); + // Build and copy the new private dict + CreateNonCIDPrivate(Font,Subr); + // Copy the new LSubrs index + CreateNonCIDSubrs(Font,PrivateBase,Subr); + } + + // copy the charstring index + OutputList.Add(new MarkerItem(charstringsRef)); + + // Add the subsetted charstring + OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.Length)); + + // now create the new CFF font + int[] currentOffset = new int[1]; + currentOffset[0] = 0; + // Count and save the offset for each item + foreach (Item item in OutputList) { + item.Increment(currentOffset); + } + // Compute the Xref for each of the offset items + foreach (Item item in OutputList) { + item.Xref(); + } + + int size = currentOffset[0]; + byte[] b = new byte[size]; + + // Emit all the items into the new byte array + foreach (Item item in OutputList) { + item.Emit(b); + } + // Return the new stream + return b; + } + + /** + * Function Copies the header from the original fileto the output list + */ + protected void CopyHeader() + { + Seek(0); + int major = GetCard8(); + int minor = GetCard8(); + int hdrSize = GetCard8(); + int offSize = GetCard8(); + nextIndexOffset = hdrSize; + OutputList.Add(new RangeItem(buf,0,hdrSize)); + } + + /** + * Function Build the header of an index + * @param Count the count field of the index + * @param Offsize the offsize field of the index + * @param First the first offset of the index + */ + protected void BuildIndexHeader(int Count,int Offsize,int First) + { + // Add the count field + OutputList.Add(new UInt16Item((char)Count)); // count + // Add the offsize field + OutputList.Add(new UInt8Item((char)Offsize)); // offSize + // Add the first offset according to the offsize + switch (Offsize){ + case 1: + OutputList.Add(new UInt8Item((char)First)); // first offset + break; + case 2: + OutputList.Add(new UInt16Item((char)First)); // first offset + break; + case 3: + OutputList.Add(new UInt24Item((char)First)); // first offset + break; + case 4: + OutputList.Add(new UInt32Item((char)First)); // first offset + break; + default: + break; + } + } + + /** + * Function adds the keys into the TopDict + * @param fdarrayRef OffsetItem for the FDArray + * @param fdselectRef OffsetItem for the FDSelect + * @param charsetRef OffsetItem for the CharSet + * @param charstringsRef OffsetItem for the CharString + */ + protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef) + { + // create an FDArray key + OutputList.Add(fdarrayRef); + OutputList.Add(new UInt8Item((char)12)); + OutputList.Add(new UInt8Item((char)36)); + // create an FDSelect key + OutputList.Add(fdselectRef); + OutputList.Add(new UInt8Item((char)12)); + OutputList.Add(new UInt8Item((char)37)); + // create an charset key + OutputList.Add(charsetRef); + OutputList.Add(new UInt8Item((char)15)); + // create a CharStrings key + OutputList.Add(charstringsRef); + OutputList.Add(new UInt8Item((char)17)); + } + + /** + * Function takes the original string item and adds the new strings + * to accomodate the CID rules + * @param Font the font + */ + protected void CreateNewStringIndex(int Font) + { + String fdFontName = fonts[Font].name+"-OneRange"; + if (fdFontName.Length > 127) + fdFontName = fdFontName.Substring(0,127); + String extraStrings = "Adobe"+"Identity"+fdFontName; + + int origStringsLen = stringOffsets[stringOffsets.Length-1] + - stringOffsets[0]; + int stringsBaseOffset = stringOffsets[0]-1; + + byte stringsIndexOffSize; + if (origStringsLen+extraStrings.Length <= 0xff) stringsIndexOffSize = 1; + else if (origStringsLen+extraStrings.Length <= 0xffff) stringsIndexOffSize = 2; + else if (origStringsLen+extraStrings.Length <= 0xffffff) stringsIndexOffSize = 3; + else stringsIndexOffSize = 4; + + OutputList.Add(new UInt16Item((char)((stringOffsets.Length-1)+3))); // count + OutputList.Add(new UInt8Item((char)stringsIndexOffSize)); // offSize + for (int i=0; i= 0) + { + OutputList.Add(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i])); + OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].Length)); + } + } + } + + /** + * Calculates how many byte it took to write the offset for the subrs in a specific + * private dict. + * @param Offset The Offset for the private dict + * @param Size The size of the private dict + * @return The size of the offset of the subrs in the private dict + */ + internal int CalcSubrOffsetSize(int Offset,int Size) + { + // Set the size to 0 + int OffsetSize = 0; + // Go to the beginning of the private dict + Seek(Offset); + // Go until the end of the private dict + while (GetPosition() < Offset+Size) + { + int p1 = GetPosition(); + GetDictItem(); + int p2 = GetPosition(); + // When reached to the subrs offset + if (key=="Subrs") { + // The Offsize (minus the subrs key) + OffsetSize = p2-p1-1; + } + // All other keys are ignored + } + // return the size + return OffsetSize; + } + + /** + * Function computes the size of an index + * @param indexOffset The offset for the computed index + * @return The size of the index + */ + protected int CountEntireIndexRange(int indexOffset) + { + // Go to the beginning of the index + Seek(indexOffset); + // Read the count field + int count = GetCard16(); + // If count==0 -> size=2 + if (count==0) + return 2; + else + { + // Read the offsize field + int indexOffSize = GetCard8(); + // Go to the last element of the offset array + Seek(indexOffset+2+1+count*indexOffSize); + // The size of the object array is the value of the last element-1 + int size = GetOffset(indexOffSize)-1; + // Return the size of the entire index + return 2+1+(count+1)*indexOffSize+size; + } + } + + /** + * The function creates a private dict for a font that was not CID + * All the keys are copied as is except for the subrs key + * @param Font the font + * @param Subr The OffsetItem for the subrs of the private + */ + internal void CreateNonCIDPrivate(int Font,OffsetItem Subr) + { + // Go to the beginning of the private dict and read untill the end + Seek(fonts[Font].privateOffset); + while (GetPosition() < fonts[Font].privateOffset+fonts[Font].privateLength) + { + int p1 = GetPosition(); + GetDictItem(); + int p2 = GetPosition(); + // If the dictItem is the "Subrs" then, + // use marker for offset and write operator number + if (key=="Subrs") { + OutputList.Add(Subr); + OutputList.Add(new UInt8Item((char)19)); // Subrs + } + // Else copy the entire range + else + OutputList.Add(new RangeItem(buf,p1,p2-p1)); + } + } + + /** + * the function marks the beginning of the subrs index and adds the subsetted subrs + * index to the output list. + * @param Font the font + * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs + * @param Subrs OffsetItem for the subrs + * @throws IOException + */ + internal void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs) + { + // Mark the beginning of the Subrs index + OutputList.Add(new SubrMarkerItem(Subrs,PrivateBase)); + // Put the subsetted new subrs index + OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.Length)); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CJKFont.cs b/iTechSharp/iTextSharp/text/pdf/CJKFont.cs new file mode 100644 index 0000000..1e978a2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/CJKFont.cs @@ -0,0 +1,646 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.util; + +/* + * $Id: CJKFont.cs,v 1.9 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * Creates a CJK font compatible with the fonts in the Adobe Asian font Pack. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + +internal class CJKFont : BaseFont { + /** The encoding used in the PDF document for CJK fonts + */ + internal const string CJK_ENCODING = "UNICODEBIGUNMARKED"; + private const int FIRST = 0; + private const int BRACKET = 1; + private const int SERIAL = 2; + private const int V1Y = 880; + + internal static Properties cjkFonts = new Properties(); + internal static Properties cjkEncodings = new Properties(); + internal static Hashtable allCMaps = Hashtable.Synchronized(new Hashtable()); + internal static Hashtable allFonts = Hashtable.Synchronized(new Hashtable()); + private static bool propertiesLoaded = false; + + /** The font name */ + private string fontName; + /** The style modifier */ + private string style = ""; + /** The CMap name associated with this font */ + private string CMap; + + private bool cidDirect = false; + + private char[] translationMap; + private IntHashtable vMetrics; + private IntHashtable hMetrics; + private Hashtable fontDesc; + private bool vertical = false; + + private static void LoadProperties() { + if (propertiesLoaded) + return; + lock (allFonts) { + if (propertiesLoaded) + return; + try { + Stream isp = GetResourceStream(RESOURCE_PATH + "cjkfonts.properties"); + cjkFonts.Load(isp); + isp.Close(); + isp = GetResourceStream(RESOURCE_PATH + "cjkencodings.properties"); + cjkEncodings.Load(isp); + isp.Close(); + } + catch { + cjkFonts = new Properties(); + cjkEncodings = new Properties(); + } + propertiesLoaded = true; + } + } + + /** Creates a CJK font. + * @param fontName the name of the font + * @param enc the encoding of the font + * @param emb always false. CJK font and not embedded + * @throws DocumentException on error + * @throws IOException on error + */ + internal CJKFont(string fontName, string enc, bool emb) { + LoadProperties(); + this.FontType = FONT_TYPE_CJK; + string nameBase = GetBaseName(fontName); + if (!IsCJKFont(nameBase, enc)) + throw new DocumentException("Font '" + fontName + "' with '" + enc + "' encoding is not a CJK font."); + if (nameBase.Length < fontName.Length) { + style = fontName.Substring(nameBase.Length); + fontName = nameBase; + } + this.fontName = fontName; + encoding = CJK_ENCODING; + vertical = enc.EndsWith("V"); + CMap = enc; + if (enc.StartsWith("Identity-")) { + cidDirect = true; + string s = cjkFonts[fontName]; + s = s.Substring(0, s.IndexOf('_')); + char[] c = (char[])allCMaps[s]; + if (c == null) { + c = ReadCMap(s); + if (c == null) + throw new DocumentException("The cmap " + s + " does not exist as a resource."); + c[CID_NEWLINE] = '\n'; + allCMaps.Add(s, c); + } + translationMap = c; + } + else { + char[] c = (char[])allCMaps[enc]; + if (c == null) { + string s = cjkEncodings[enc]; + if (s == null) + throw new DocumentException("The resource cjkencodings.properties does not contain the encoding " + enc); + StringTokenizer tk = new StringTokenizer(s); + string nt = tk.NextToken(); + c = (char[])allCMaps[nt]; + if (c == null) { + c = ReadCMap(nt); + allCMaps.Add(nt, c); + } + if (tk.HasMoreTokens()) { + string nt2 = tk.NextToken(); + char[] m2 = ReadCMap(nt2); + for (int k = 0; k < 0x10000; ++k) { + if (m2[k] == 0) + m2[k] = c[k]; + } + allCMaps.Add(enc, m2); + c = m2; + } + } + translationMap = c; + } + fontDesc = (Hashtable)allFonts[fontName]; + if (fontDesc == null) { + fontDesc = ReadFontProperties(fontName); + allFonts.Add(fontName, fontDesc); + } + hMetrics = (IntHashtable)fontDesc["W"]; + vMetrics = (IntHashtable)fontDesc["W2"]; + } + + /** Checks if its a valid CJK font. + * @param fontName the font name + * @param enc the encoding + * @return true if it is CJK font + */ + public static bool IsCJKFont(string fontName, string enc) { + LoadProperties(); + string encodings = cjkFonts[fontName]; + return (encodings != null && (enc.Equals("Identity-H") || enc.Equals("Identity-V") || encodings.IndexOf("_" + enc + "_") >= 0)); + } + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public override int GetWidth(int char1) { + int c = (int)char1; + if (!cidDirect) + c = translationMap[c]; + int v; + if (vertical) + v = vMetrics[c]; + else + v = hMetrics[c]; + if (v > 0) + return v; + else + return 1000; + } + + public override int GetWidth(string text) { + int total = 0; + for (int k = 0; k < text.Length; ++k) { + int c = text[k]; + if (!cidDirect) + c = translationMap[c]; + int v; + if (vertical) + v = vMetrics[c]; + else + v = hMetrics[c]; + if (v > 0) + total += v; + else + total += 1000; + } + return total; + } + + internal override int GetRawWidth(int c, string name) { + return 0; + } + public override int GetKerning(int char1, int char2) { + return 0; + } + + private PdfDictionary GetFontDescriptor() { + PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR); + dic.Put(PdfName.ASCENT, new PdfLiteral((String)fontDesc["Ascent"])); + dic.Put(PdfName.CAPHEIGHT, new PdfLiteral((String)fontDesc["CapHeight"])); + dic.Put(PdfName.DESCENT, new PdfLiteral((String)fontDesc["Descent"])); + dic.Put(PdfName.FLAGS, new PdfLiteral((String)fontDesc["Flags"])); + dic.Put(PdfName.FONTBBOX, new PdfLiteral((String)fontDesc["FontBBox"])); + dic.Put(PdfName.FONTNAME, new PdfName(fontName + style)); + dic.Put(PdfName.ITALICANGLE, new PdfLiteral((String)fontDesc["ItalicAngle"])); + dic.Put(PdfName.STEMV, new PdfLiteral((String)fontDesc["StemV"])); + PdfDictionary pdic = new PdfDictionary(); + pdic.Put(PdfName.PANOSE, new PdfString((String)fontDesc["Panose"], null)); + dic.Put(PdfName.STYLE, pdic); + return dic; + } + + private PdfDictionary GetCIDFont(PdfIndirectReference fontDescriptor, IntHashtable cjkTag) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.SUBTYPE, PdfName.CIDFONTTYPE0); + dic.Put(PdfName.BASEFONT, new PdfName(fontName + style)); + dic.Put(PdfName.FONTDESCRIPTOR, fontDescriptor); + int[] keys = cjkTag.ToOrderedKeys(); + string w = ConvertToHCIDMetrics(keys, hMetrics); + if (w != null) + dic.Put(PdfName.W, new PdfLiteral(w)); + if (vertical) { + w = ConvertToVCIDMetrics(keys, vMetrics, hMetrics); + if (w != null) + dic.Put(PdfName.W2, new PdfLiteral(w)); + } + else + dic.Put(PdfName.DW, new PdfNumber(1000)); + PdfDictionary cdic = new PdfDictionary(); + cdic.Put(PdfName.REGISTRY, new PdfString((string)fontDesc["Registry"], null)); + cdic.Put(PdfName.ORDERING, new PdfString((string)fontDesc["Ordering"], null)); + cdic.Put(PdfName.SUPPLEMENT, new PdfLiteral((string)fontDesc["Supplement"])); + dic.Put(PdfName.CIDSYSTEMINFO, cdic); + return dic; + } + + private PdfDictionary GetFontBaseType(PdfIndirectReference CIDFont) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE0); + string name = fontName; + if (style.Length > 0) + name += "-" + style.Substring(1); + name += "-" + CMap; + dic.Put(PdfName.BASEFONT, new PdfName(name)); + dic.Put(PdfName.ENCODING, new PdfName(CMap)); + dic.Put(PdfName.DESCENDANTFONTS, new PdfArray(CIDFont)); + return dic; + } + + internal override void WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) { + IntHashtable cjkTag = (IntHashtable)parms[0]; + PdfIndirectReference ind_font = null; + PdfObject pobj = null; + PdfIndirectObject obj = null; + pobj = GetFontDescriptor(); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetCIDFont(ind_font, cjkTag); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetFontBaseType(ind_font); + writer.AddToBody(pobj, piref); + } + + private float GetDescNumber(string name) { + return int.Parse((string)fontDesc[name]); + } + + private float GetBBox(int idx) { + string s = (string)fontDesc["FontBBox"]; + StringTokenizer tk = new StringTokenizer(s, " []\r\n\t\f"); + string ret = tk.NextToken(); + for (int k = 0; k < idx; ++k) + ret = tk.NextToken(); + return int.Parse(ret); + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT + * and ITALICANGLE. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + */ + public override float GetFontDescriptor(int key, float fontSize) { + switch (key) { + case AWT_ASCENT: + case ASCENT: + return GetDescNumber("Ascent") * fontSize / 1000; + case CAPHEIGHT: + return GetDescNumber("CapHeight") * fontSize / 1000; + case AWT_DESCENT: + case DESCENT: + return GetDescNumber("Descent") * fontSize / 1000; + case ITALICANGLE: + return GetDescNumber("ItalicAngle"); + case BBOXLLX: + return fontSize * GetBBox(0) / 1000; + case BBOXLLY: + return fontSize * GetBBox(1) / 1000; + case BBOXURX: + return fontSize * GetBBox(2) / 1000; + case BBOXURY: + return fontSize * GetBBox(3) / 1000; + case AWT_LEADING: + return 0; + case AWT_MAXADVANCE: + return fontSize * (GetBBox(2) - GetBBox(0)) / 1000; + } + return 0; + } + + public override string PostscriptFontName { + get { + return fontName; + } + set { + fontName = value; + } + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] FullFontName { + get { + return new string[][]{new string[] {"", "", "", fontName}}; + } + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] AllNameEntries { + get { + return new string[][]{new string[]{"4", "", "", "", fontName}}; + } + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + */ + public override string[][] FamilyFontName { + get { + return this.FullFontName; + } + } + + internal static char[] ReadCMap(string name) { + Stream istr = null; + try { + name = name + ".cmap"; + istr = GetResourceStream(RESOURCE_PATH + name); + char[] c = new char[0x10000]; + for (int k = 0; k < 0x10000; ++k) + c[k] = (char)((istr.ReadByte() << 8) + istr.ReadByte()); + return c; + } + catch { + // empty on purpose + } + finally { + try{istr.Close();}catch{} + } + + return null; + } + + internal static IntHashtable CreateMetric(string s) { + IntHashtable h = new IntHashtable(); + StringTokenizer tk = new StringTokenizer(s); + while (tk.HasMoreTokens()) { + int n1 = int.Parse(tk.NextToken()); + h[n1] = int.Parse(tk.NextToken()); + } + return h; + } + + internal static string ConvertToHCIDMetrics(int[] keys, IntHashtable h) { + if (keys.Length == 0) + return null; + int lastCid = 0; + int lastValue = 0; + int start; + for (start = 0; start < keys.Length; ++start) { + lastCid = keys[start]; + lastValue = h[lastCid]; + if (lastValue != 0) { + ++start; + break; + } + } + if (lastValue == 0) + return null; + StringBuilder buf = new StringBuilder(); + buf.Append('['); + buf.Append(lastCid); + int state = FIRST; + for (int k = start; k < keys.Length; ++k) { + int cid = keys[k]; + int value = h[cid]; + if (value == 0) + continue; + switch (state) { + case FIRST: { + if (cid == lastCid + 1 && value == lastValue) { + state = SERIAL; + } + else if (cid == lastCid + 1) { + state = BRACKET; + buf.Append('[').Append(lastValue); + } + else { + buf.Append('[').Append(lastValue).Append(']').Append(cid); + } + break; + } + case BRACKET: { + if (cid == lastCid + 1 && value == lastValue) { + state = SERIAL; + buf.Append(']').Append(lastCid); + } + else if (cid == lastCid + 1) { + buf.Append(' ').Append(lastValue); + } + else { + state = FIRST; + buf.Append(' ').Append(lastValue).Append(']').Append(cid); + } + break; + } + case SERIAL: { + if (cid != lastCid + 1 || value != lastValue) { + buf.Append(' ').Append(lastCid).Append(' ').Append(lastValue).Append(' ').Append(cid); + state = FIRST; + } + break; + } + } + lastValue = value; + lastCid = cid; + } + switch (state) { + case FIRST: { + buf.Append('[').Append(lastValue).Append("]]"); + break; + } + case BRACKET: { + buf.Append(' ').Append(lastValue).Append("]]"); + break; + } + case SERIAL: { + buf.Append(' ').Append(lastCid).Append(' ').Append(lastValue).Append(']'); + break; + } + } + return buf.ToString(); + } + + internal static string ConvertToVCIDMetrics(int[] keys, IntHashtable v, IntHashtable h) { + if (keys.Length == 0) + return null; + int lastCid = 0; + int lastValue = 0; + int lastHValue = 0; + int start; + for (start = 0; start < keys.Length; ++start) { + lastCid = keys[start]; + lastValue = v[lastCid]; + if (lastValue != 0) { + ++start; + break; + } + else + lastHValue = h[lastCid]; + } + if (lastValue == 0) + return null; + if (lastHValue == 0) + lastHValue = 1000; + StringBuilder buf = new StringBuilder(); + buf.Append('['); + buf.Append(lastCid); + int state = FIRST; + for (int k = start; k < keys.Length; ++k) { + int cid = keys[k]; + int value = v[cid]; + if (value == 0) + continue; + int hValue = h[lastCid]; + if (hValue == 0) + hValue = 1000; + switch (state) { + case FIRST: { + if (cid == lastCid + 1 && value == lastValue && hValue == lastHValue) { + state = SERIAL; + } + else { + buf.Append(' ').Append(lastCid).Append(' ').Append(-lastValue).Append(' ').Append(lastHValue / 2).Append(' ').Append(V1Y).Append(' ').Append(cid); + } + break; + } + case SERIAL: { + if (cid != lastCid + 1 || value != lastValue || hValue != lastHValue) { + buf.Append(' ').Append(lastCid).Append(' ').Append(-lastValue).Append(' ').Append(lastHValue / 2).Append(' ').Append(V1Y).Append(' ').Append(cid); + state = FIRST; + } + break; + } + } + lastValue = value; + lastCid = cid; + lastHValue = hValue; + } + buf.Append(' ').Append(lastCid).Append(' ').Append(-lastValue).Append(' ').Append(lastHValue / 2).Append(' ').Append(V1Y).Append(" ]"); + return buf.ToString(); + } + + internal static Hashtable ReadFontProperties(String name) { + try { + name += ".properties"; + Stream isp = GetResourceStream(RESOURCE_PATH + name); + Properties p = new Properties(); + p.Load(isp); + isp.Close(); + IntHashtable W = CreateMetric(p["W"]); + p.Remove("W"); + IntHashtable W2 = CreateMetric(p["W2"]); + p.Remove("W2"); + Hashtable map = new Hashtable(); + foreach (string key in p.Keys) { + map[key] = p[key]; + } + map["W"] = W; + map["W2"] = W2; + return map; + } + catch { + // empty on purpose + } + return null; + } + + public override int GetUnicodeEquivalent(int c) { + if (cidDirect) + return translationMap[c]; + return c; + } + + public override int GetCidCode(int c) { + if (cidDirect) + return c; + return translationMap[c]; + } + + public override bool HasKernPairs() { + return false; + } + + public override bool CharExists(int c) { + return translationMap[c] != 0; + } + + public override bool SetCharAdvance(int c, int advance) { + return false; + } + + public override bool SetKerning(int char1, int char2, int kern) { + return false; + } + + public override int[] GetCharBBox(int c) { + return null; + } + + protected override int[] GetRawCharBBox(int c, String name) { + return null; + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CMYKColor.cs b/iTechSharp/iTextSharp/text/pdf/CMYKColor.cs new file mode 100644 index 0000000..ba718d2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/CMYKColor.cs @@ -0,0 +1,112 @@ +using System; + +/* + * $Id: CMYKColor.cs,v 1.4 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class CMYKColor : ExtendedColor { + + float ccyan; + float cmagenta; + float cyellow; + float cblack; + + public CMYKColor(int intCyan, int intMagenta, int intYellow, int intBlack) : + this((float)intCyan / 255f, (float)intMagenta / 255f, (float)intYellow / 255f, (float)intBlack / 255f) {} + + public CMYKColor(float floatCyan, float floatMagenta, float floatYellow, float floatBlack) : + base(TYPE_CMYK, 1f - floatCyan - floatBlack, 1f - floatMagenta - floatBlack, 1f - floatYellow - floatBlack) { + ccyan = Normalize(floatCyan); + cmagenta = Normalize(floatMagenta); + cyellow = Normalize(floatYellow); + cblack = Normalize(floatBlack); + } + + public float Cyan { + get { + return ccyan; + } + } + + public float Magenta { + get { + return cmagenta; + } + } + + public float Yellow { + get { + return cyellow; + } + } + + public float Black { + get { + return cblack; + } + } + + public override bool Equals(Object obj) { + if (!(obj is CMYKColor)) + return false; + CMYKColor c2 = (CMYKColor)obj; + return (ccyan == c2.ccyan && cmagenta == c2.cmagenta && cyellow == c2.cyellow && cblack == c2.cblack); + } + + public override int GetHashCode() { + return ccyan.GetHashCode() ^ cmagenta.GetHashCode() ^ cyellow.GetHashCode() ^ cblack.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CodeFile1.cs b/iTechSharp/iTextSharp/text/pdf/CodeFile1.cs new file mode 100644 index 0000000..e69de29 diff --git a/iTechSharp/iTextSharp/text/pdf/ColorDetails.cs b/iTechSharp/iTextSharp/text/pdf/ColorDetails.cs new file mode 100644 index 0000000..86d0636 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ColorDetails.cs @@ -0,0 +1,107 @@ +using System; + +/* + * $Id: ColorDetails.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Each spotcolor in the document will have an instance of this class + * + * @author Phillip Pan (phillip@formstar.com) + */ + public class ColorDetails { + + /** The indirect reference to this color + */ + PdfIndirectReference indirectReference; + /** The color name that appears in the document body stream + */ + PdfName colorName; + /** The color + */ + PdfSpotColor spotcolor; + + /** Each spot color used in a document has an instance of this class. + * @param colorName the color name + * @param indirectReference the indirect reference to the font + * @param scolor the PDfSpotColor + */ + internal ColorDetails(PdfName colorName, PdfIndirectReference indirectReference, PdfSpotColor scolor) { + this.colorName = colorName; + this.indirectReference = indirectReference; + this.spotcolor = scolor; + } + + /** Gets the indirect reference to this color. + * @return the indirect reference to this color + */ + internal PdfIndirectReference IndirectReference { + get { + return indirectReference; + } + } + + /** Gets the color name as it appears in the document body. + * @return the color name + */ + internal PdfName ColorName { + get { + return colorName; + } + } + + /** Gets the SpotColor object. + * @return the PdfSpotColor + */ + internal PdfObject GetSpotColor(PdfWriter writer) { + return spotcolor.GetSpotObject(writer); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/ColumnText.cs b/iTechSharp/iTextSharp/text/pdf/ColumnText.cs new file mode 100644 index 0000000..6e72376 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ColumnText.cs @@ -0,0 +1,1534 @@ +using System; +using System.Collections; +using System.util.collections; +using iTextSharp.text.pdf.draw; + +/* + * Copyright 2001-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * Formats text in a columnwise form. The text is bound + * on the left and on the right by a sequence of lines. This allows the column + * to have any shape, not only rectangular. + *

+ * Several parameters can be set like the first paragraph line indent and + * extra space between paragraphs. + *

+ * A call to the method go will return one of the following + * situations: the column ended or the text ended. + *

+ * I the column ended, a new column definition can be loaded with the method + * setColumns and the method go can be called again. + *

+ * If the text ended, more text can be loaded with addText + * and the method go can be called again.
+ * The only limitation is that one or more complete paragraphs must be loaded + * each time. + *

+ * Full bidirectional reordering is supported. If the run direction is + * PdfWriter.RUN_DIRECTION_RTL the meaning of the horizontal + * alignments and margins is mirrored. + * @author Paulo Soares (psoares@consiste.pt) + */ + +public class ColumnText { + /** Eliminate the arabic vowels */ + public int AR_NOVOWEL = ArabicLigaturizer.ar_novowel; + /** Compose the tashkeel in the ligatures. */ + public const int AR_COMPOSEDTASHKEEL = ArabicLigaturizer.ar_composedtashkeel; + /** Do some extra double ligatures. */ + public const int AR_LIG = ArabicLigaturizer.ar_lig; + /** + * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits. + */ + public const int DIGITS_EN2AN = ArabicLigaturizer.DIGITS_EN2AN; + + /** + * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039). + */ + public const int DIGITS_AN2EN = ArabicLigaturizer.DIGITS_AN2EN; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be not an Arabic, + * letter, so European digits at the start of the text will not change. + * Compare to DIGITS_ALEN2AN_INIT_AL. + */ + public const int DIGITS_EN2AN_INIT_LR = ArabicLigaturizer.DIGITS_EN2AN_INIT_LR; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be an Arabic, + * letter, so European digits at the start of the text will change. + * Compare to DIGITS_ALEN2AN_INT_LR. + */ + public const int DIGITS_EN2AN_INIT_AL = ArabicLigaturizer.DIGITS_EN2AN_INIT_AL; + + /** + * Digit type option: Use Arabic-Indic digits (U+0660...U+0669). + */ + public const int DIGIT_TYPE_AN = ArabicLigaturizer.DIGIT_TYPE_AN; + + /** + * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9). + */ + public const int DIGIT_TYPE_AN_EXTENDED = ArabicLigaturizer.DIGIT_TYPE_AN_EXTENDED; + + protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT; + public static float GLOBAL_SPACE_CHAR_RATIO = 0; + + /** Signals that there is no more text available. */ + public const int NO_MORE_TEXT = 1; + + /** Signals that there is no more column. */ + public const int NO_MORE_COLUMN = 2; + + /** The column is valid. */ + protected const int LINE_STATUS_OK = 0; + + /** The line is out the column limits. */ + protected const int LINE_STATUS_OFFLIMITS = 1; + + /** The line cannot fit this column position. */ + protected const int LINE_STATUS_NOLINE = 2; + + /** Upper bound of the column. */ + protected float maxY; + + /** Lower bound of the column. */ + protected float minY; + + protected float leftX; + + protected float rightX; + + /** The column Element. Default is left Element. */ + protected int alignment = Element.ALIGN_LEFT; + + /** The left column bound. */ + protected ArrayList leftWall; + + /** The right column bound. */ + protected ArrayList rightWall; + + /** The chunks that form the text. */ +// protected ArrayList chunks = new ArrayList(); + protected BidiLine bidiLine; + + /** The current y line location. Text will be written at this line minus the leading. */ + protected float yLine; + + /** The leading for the current line. */ + protected float currentLeading = 16; + + /** The fixed text leading. */ + protected float fixedLeading = 16; + + /** The text leading that is multiplied by the biggest font size in the line. */ + protected float multipliedLeading = 0; + + /** The PdfContent where the text will be written to. */ + protected PdfContentByte canvas; + + protected PdfContentByte[] canvases; + + /** The line status when trying to fit a line to a column. */ + protected int lineStatus; + + /** The first paragraph line indent. */ + protected float indent = 0; + + /** The following paragraph lines indent. */ + protected float followingIndent = 0; + + /** The right paragraph lines indent. */ + protected float rightIndent = 0; + + /** The extra space between paragraphs. */ + protected float extraParagraphSpace = 0; + + /** The width of the line when the column is defined as a simple rectangle. */ + protected float rectangularWidth = -1; + + protected bool rectangularMode = false; + + /** Holds value of property spaceCharRatio. */ + private float spaceCharRatio = GLOBAL_SPACE_CHAR_RATIO; + + private bool lastWasNewline = true; + + /** Holds value of property linesWritten. */ + private int linesWritten; + + private float firstLineY; + + private bool firstLineYDone = false; + + /** Holds value of property arabicOptions. */ + private int arabicOptions = 0; + + protected float descender; + + protected bool composite = false; + + protected ColumnText compositeColumn; + + protected internal ArrayList compositeElements; + + protected int listIdx = 0; + + private bool splittedRow; + + protected Phrase waitPhrase; + + /** if true, first line height is adjusted so that the max ascender touches the top */ + private bool useAscender = false; + + /** + * Creates a ColumnText. + * @param text the place where the text will be written to. Can + * be a template. + */ + public ColumnText(PdfContentByte canvas) { + this.canvas = canvas; + } + + /** Creates an independent duplicated of the instance org. + * @param org the original ColumnText + * @return the duplicated + */ + public static ColumnText Duplicate(ColumnText org) { + ColumnText ct = new ColumnText(null); + ct.SetACopy(org); + return ct; + } + + /** Makes this instance an independent copy of org. + * @param org the original ColumnText + * @return itself + */ + public ColumnText SetACopy(ColumnText org) { + SetSimpleVars(org); + if (org.bidiLine != null) + bidiLine = new BidiLine(org.bidiLine); + return this; + } + + protected internal void SetSimpleVars(ColumnText org) { + maxY = org.maxY; + minY = org.minY; + alignment = org.alignment; + leftWall = null; + if (org.leftWall != null) + leftWall = new ArrayList(org.leftWall); + rightWall = null; + if (org.rightWall != null) + rightWall = new ArrayList(org.rightWall); + yLine = org.yLine; + currentLeading = org.currentLeading; + fixedLeading = org.fixedLeading; + multipliedLeading = org.multipliedLeading; + canvas = org.canvas; + canvases = org.canvases; + lineStatus = org.lineStatus; + indent = org.indent; + followingIndent = org.followingIndent; + rightIndent = org.rightIndent; + extraParagraphSpace = org.extraParagraphSpace; + rectangularWidth = org.rectangularWidth; + rectangularMode = org.rectangularMode; + spaceCharRatio = org.spaceCharRatio; + lastWasNewline = org.lastWasNewline; + linesWritten = org.linesWritten; + arabicOptions = org.arabicOptions; + runDirection = org.runDirection; + descender = org.descender; + composite = org.composite; + splittedRow = org.splittedRow; + if (org.composite) { + compositeElements = new ArrayList(org.compositeElements); + if (splittedRow) { + PdfPTable table = (PdfPTable)compositeElements[0]; + compositeElements[0] = new PdfPTable(table); + } + if (org.compositeColumn != null) + compositeColumn = Duplicate(org.compositeColumn); + } + listIdx = org.listIdx; + firstLineY = org.firstLineY; + leftX = org.leftX; + rightX = org.rightX; + firstLineYDone = org.firstLineYDone; + waitPhrase = org.waitPhrase; + useAscender = org.useAscender; + filledWidth = org.filledWidth; + adjustFirstLine = org.adjustFirstLine; + } + + private void AddWaitingPhrase() { + if (bidiLine == null && waitPhrase != null) { + bidiLine = new BidiLine(); + foreach (Chunk ck in waitPhrase.Chunks) { + bidiLine.AddChunk(new PdfChunk(ck, null)); + } + waitPhrase = null; + } + } + + /** + * Adds a Phrase to the current text array. + * @param phrase the text + */ + public void AddText(Phrase phrase) { + if (phrase == null || composite) + return; + AddWaitingPhrase(); + if (bidiLine == null) { + waitPhrase = phrase; + return; + } + foreach (Chunk c in phrase.Chunks) { + bidiLine.AddChunk(new PdfChunk(c, null)); + } + } + + /** + * Replaces the current text array with this Phrase. + * Anything added previously with AddElement() is lost. + * @param phrase the text + */ + public void SetText(Phrase phrase) { + bidiLine = null; + composite = false; + compositeColumn = null; + compositeElements = null; + listIdx = 0; + splittedRow = false; + waitPhrase = phrase; + } + + /** + * Adds a Chunk to the current text array. + * Will not have any effect if AddElement() was called before. + * @param chunk the text + */ + public void AddText(Chunk chunk) { + if (chunk == null || composite) + return; + AddText(new Phrase(chunk)); + } + + /** + * Adds an element. Elements supported are Paragraph, + * List, PdfPTable, Image and + * Graphic. + *

+ * It removes all the text placed with addText(). + * @param element the Element + */ + public void AddElement(IElement element) { + if (element == null) + return; + if (element is Image) { + Image img = (Image)element; + PdfPTable t = new PdfPTable(1); + float w = img.WidthPercentage; + if (w == 0) { + t.TotalWidth = img.ScaledWidth; + t.LockedWidth = true; + } + else + t.WidthPercentage = w; + t.SpacingAfter = img.SpacingAfter; + t.SpacingBefore = img.SpacingBefore; + switch (img.Alignment) { + case Image.LEFT_ALIGN: + t.HorizontalAlignment = Element.ALIGN_LEFT; + break; + case Image.RIGHT_ALIGN: + t.HorizontalAlignment = Element.ALIGN_RIGHT; + break; + default: + t.HorizontalAlignment = Element.ALIGN_CENTER; + break; + } + PdfPCell c = new PdfPCell(img, true); + c.Padding = 0; + c.Border = img.Border; + c.BorderColor = img.BorderColor; + c.BorderWidth = img.BorderWidth; + c.BackgroundColor = img.BackgroundColor; + t.AddCell(c); + element = t; + } + if (element.Type == Element.CHUNK) { + element = new Paragraph((Chunk)element); + } + else if (element.Type == Element.PHRASE) { + element = new Paragraph((Phrase)element); + } + if (element is SimpleTable) { + try { + element = ((SimpleTable)element).CreatePdfPTable(); + } catch (DocumentException) { + throw new ArgumentException("Element not allowed."); + } + } + else if (element.Type != Element.PARAGRAPH && element.Type != Element.LIST && element.Type != Element.PTABLE && element.Type != Element.YMARK) + throw new ArgumentException("Element not allowed."); + if (!composite) { + composite = true; + compositeElements = new ArrayList(); + bidiLine = null; + waitPhrase = null; + } + compositeElements.Add(element); + } + + /** + * Converts a sequence of lines representing one of the column bounds into + * an internal format. + *

+ * Each array element will contain a float[4] representing + * the line x = ax + b. + * @param cLine the column array + * @return the converted array + */ + protected ArrayList ConvertColumn(float[] cLine) { + if (cLine.Length < 4) + throw new Exception("No valid column line found."); + ArrayList cc = new ArrayList(); + for (int k = 0; k < cLine.Length - 2; k += 2) { + float x1 = cLine[k]; + float y1 = cLine[k + 1]; + float x2 = cLine[k + 2]; + float y2 = cLine[k + 3]; + if (y1 == y2) + continue; + // x = ay + b + float a = (x1 - x2) / (y1 - y2); + float b = x1 - a * y1; + float[] r = new float[4]; + r[0] = Math.Min(y1, y2); + r[1] = Math.Max(y1, y2); + r[2] = a; + r[3] = b; + cc.Add(r); + maxY = Math.Max(maxY, r[1]); + minY = Math.Min(minY, r[0]); + } + if (cc.Count == 0) + throw new Exception("No valid column line found."); + return cc; + } + + /** + * Finds the intersection between the yLine and the column. It will + * set the lineStatus apropriatly. + * @param wall the column to intersect + * @return the x coordinate of the intersection + */ + protected float FindLimitsPoint(ArrayList wall) { + lineStatus = LINE_STATUS_OK; + if (yLine < minY || yLine > maxY) { + lineStatus = LINE_STATUS_OFFLIMITS; + return 0; + } + for (int k = 0; k < wall.Count; ++k) { + float[] r = (float[])wall[k]; + if (yLine < r[0] || yLine > r[1]) + continue; + return r[2] * yLine + r[3]; + } + lineStatus = LINE_STATUS_NOLINE; + return 0; + } + + /** + * Finds the intersection between the yLine and the two + * column bounds. It will set the lineStatus apropriatly. + * @return a float[2]with the x coordinates of the intersection + */ + protected float[] FindLimitsOneLine() { + float x1 = FindLimitsPoint(leftWall); + if (lineStatus == LINE_STATUS_OFFLIMITS || lineStatus == LINE_STATUS_NOLINE) + return null; + float x2 = FindLimitsPoint(rightWall); + if (lineStatus == LINE_STATUS_NOLINE) + return null; + return new float[]{x1, x2}; + } + + /** + * Finds the intersection between the yLine, + * the yLine-leadingand the two + * column bounds. It will set the lineStatus apropriatly. + * @return a float[4]with the x coordinates of the intersection + */ + protected float[] FindLimitsTwoLines() { + bool repeat = false; + for (;;) { + if (repeat && currentLeading == 0) + return null; + repeat = true; + float[] x1 = FindLimitsOneLine(); + if (lineStatus == LINE_STATUS_OFFLIMITS) + return null; + yLine -= currentLeading; + if (lineStatus == LINE_STATUS_NOLINE) { + continue; + } + float[] x2 = FindLimitsOneLine(); + if (lineStatus == LINE_STATUS_OFFLIMITS) + return null; + if (lineStatus == LINE_STATUS_NOLINE) { + yLine -= currentLeading; + continue; + } + if (x1[0] >= x2[1] || x2[0] >= x1[1]) + continue; + return new float[]{x1[0], x1[1], x2[0], x2[1]}; + } + } + + /** + * Sets the columns bounds. Each column bound is described by a + * float[] with the line points [x1,y1,x2,y2,...]. + * The array must have at least 4 elements. + * @param leftLine the left column bound + * @param rightLine the right column bound + */ + public void SetColumns(float[] leftLine, float[] rightLine) { + maxY = -10e20f; + minY = 10e20f; + rightWall = ConvertColumn(rightLine); + leftWall = ConvertColumn(leftLine); + rectangularWidth = -1; + rectangularMode = false; + } + + /** + * Simplified method for rectangular columns. + * @param phrase a Phrase + * @param llx the lower left x corner + * @param lly the lower left y corner + * @param urx the upper right x corner + * @param ury the upper right y corner + * @param leading the leading + * @param alignment the column alignment + */ + public void SetSimpleColumn(Phrase phrase, float llx, float lly, float urx, float ury, float leading, int alignment) { + AddText(phrase); + SetSimpleColumn(llx, lly, urx, ury, leading, alignment); + } + + /** + * Simplified method for rectangular columns. + * @param llx the lower left x corner + * @param lly the lower left y corner + * @param urx the upper right x corner + * @param ury the upper right y corner + * @param leading the leading + * @param alignment the column alignment + */ + public void SetSimpleColumn(float llx, float lly, float urx, float ury, float leading, int alignment) { + Leading = leading; + this.alignment = alignment; + SetSimpleColumn(llx, lly, urx, ury); + } + + /** + * Simplified method for rectangular columns. + * @param llx + * @param lly + * @param urx + * @param ury + */ + public void SetSimpleColumn(float llx, float lly, float urx, float ury) { + leftX = Math.Min(llx, urx); + maxY = Math.Max(lly, ury); + minY = Math.Min(lly, ury); + rightX = Math.Max(llx, urx); + yLine = maxY; + rectangularWidth = rightX - leftX; + if (rectangularWidth < 0) + rectangularWidth = 0; + rectangularMode = true; + } + + /** + * Sets the leading fixed and variable. The resultant leading will be + * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param fixedLeading the fixed leading + * @param multipliedLeading the variable leading + */ + public void SetLeading(float fixedLeading, float multipliedLeading) { + this.fixedLeading = fixedLeading; + this.multipliedLeading = multipliedLeading; + } + + /** + * Gets the fixed leading + * @return the leading + */ + public float Leading { + get { + return fixedLeading; + } + + set { + this.fixedLeading = value; + this.multipliedLeading = 0; + } + } + + /** + * Gets the variable leading + * @return the leading + */ + public float MultipliedLeading { + get { + return multipliedLeading; + } + } + + /** + * Gets the yLine. + * @return the yLine + */ + public float YLine { + get { + return yLine; + } + + set { + this.yLine = value; + } + } + + /** + * Gets the Element. + * @return the alignment + */ + public int Alignment{ + get { + return alignment; + } + + set { + this.alignment = value; + } + } + + /** + * Gets the first paragraph line indent. + * @return the indent + */ + public float Indent { + get { + return indent; + } + + set { + this.indent = value; + lastWasNewline = true; + } + } + + /** + * Gets the following paragraph lines indent. + * @return the indent + */ + public float FollowingIndent { + get { + return followingIndent; + } + + set { + this.followingIndent = value; + lastWasNewline = true; + } + } + + /** + * Gets the right paragraph lines indent. + * @return the indent + */ + public float RightIndent { + get { + return rightIndent; + } + + set { + this.rightIndent = value; + lastWasNewline = true; + } + } + + /** + * Outputs the lines to the document. It is equivalent to go(false). + * @return returns the result of the operation. It can be NO_MORE_TEXT + * and/or NO_MORE_COLUMN + * @throws DocumentException on error + */ + public int Go() { + return Go(false); + } + + /** + * Outputs the lines to the document. The output can be simulated. + * @param simulate true to simulate the writting to the document + * @return returns the result of the operation. It can be NO_MORE_TEXT + * and/or NO_MORE_COLUMN + * @throws DocumentException on error + */ + public int Go(bool simulate) { + if (composite) + return GoComposite(simulate); + AddWaitingPhrase(); + if (bidiLine == null) + return NO_MORE_TEXT; + descender = 0; + linesWritten = 0; + bool dirty = false; + float ratio = spaceCharRatio; + Object[] currentValues = new Object[2]; + PdfFont currentFont = null; + float lastBaseFactor = 0F; + currentValues[1] = lastBaseFactor; + PdfDocument pdf = null; + PdfContentByte graphics = null; + PdfContentByte text = null; + firstLineY = float.NaN; + int localRunDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; + if (runDirection != PdfWriter.RUN_DIRECTION_DEFAULT) + localRunDirection = runDirection; + if (canvas != null) { + graphics = canvas; + pdf = canvas.PdfDocument; + text = canvas.Duplicate; + } + else if (!simulate) + throw new Exception("ColumnText.go with simulate==false and text==null."); + if (!simulate) { + if (ratio == GLOBAL_SPACE_CHAR_RATIO) + ratio = text.PdfWriter.SpaceCharRatio; + else if (ratio < 0.001f) + ratio = 0.001f; + } + float firstIndent = 0; + + int status = 0; + if (rectangularMode) { + for (;;) { + firstIndent = (lastWasNewline ? indent : followingIndent); + if (rectangularWidth <= firstIndent + rightIndent) { + status = NO_MORE_COLUMN; + if (bidiLine.IsEmpty()) + status |= NO_MORE_TEXT; + break; + } + if (bidiLine.IsEmpty()) { + status = NO_MORE_TEXT; + break; + } + PdfLine line = bidiLine.ProcessLine(leftX, rectangularWidth - firstIndent - rightIndent, alignment, localRunDirection, arabicOptions); + if (line == null) { + status = NO_MORE_TEXT; + break; + } + float maxSize = line.MaxSizeSimple; + if (UseAscender && float.IsNaN(firstLineY)) { + currentLeading = line.Ascender; + } + else { + currentLeading = fixedLeading + maxSize * multipliedLeading; + } + if (yLine > maxY || yLine - currentLeading < minY ) { + status = NO_MORE_COLUMN; + bidiLine.Restore(); + break; + } + yLine -= currentLeading; + if (!simulate && !dirty) { + text.BeginText(); + dirty = true; + } + if (float.IsNaN(firstLineY)) { + firstLineY = yLine; + } + UpdateFilledWidth(rectangularWidth - line.WidthLeft); + if (!simulate) { + currentValues[0] = currentFont; + text.SetTextMatrix(leftX + (line.RTL ? rightIndent : firstIndent) + line.IndentLeft, yLine); + pdf.WriteLineToContent(line, text, graphics, currentValues, ratio); + currentFont = (PdfFont)currentValues[0]; + } + lastWasNewline = line.NewlineSplit; + yLine -= line.NewlineSplit ? extraParagraphSpace : 0; + ++linesWritten; + descender = line.Descender; + } + } + else { + currentLeading = fixedLeading; + for (;;) { + firstIndent = (lastWasNewline ? indent : followingIndent); + float yTemp = yLine; + float[] xx = FindLimitsTwoLines(); + if (xx == null) { + status = NO_MORE_COLUMN; + if (bidiLine.IsEmpty()) + status |= NO_MORE_TEXT; + yLine = yTemp; + break; + } + if (bidiLine.IsEmpty()) { + status = NO_MORE_TEXT; + yLine = yTemp; + break; + } + float x1 = Math.Max(xx[0], xx[2]); + float x2 = Math.Min(xx[1], xx[3]); + if (x2 - x1 <= firstIndent + rightIndent) + continue; + if (!simulate && !dirty) { + text.BeginText(); + dirty = true; + } + PdfLine line = bidiLine.ProcessLine(x1, x2 - x1 - firstIndent - rightIndent, alignment, localRunDirection, arabicOptions); + if (line == null) { + status = NO_MORE_TEXT; + yLine = yTemp; + break; + } + if (!simulate) { + currentValues[0] = currentFont; + text.SetTextMatrix(x1 + (line.RTL ? rightIndent : firstIndent) + line.IndentLeft, yLine); + pdf.WriteLineToContent(line, text, graphics, currentValues, ratio); + currentFont = (PdfFont)currentValues[0]; + } + lastWasNewline = line.NewlineSplit; + yLine -= line.NewlineSplit ? extraParagraphSpace : 0; + ++linesWritten; + descender = line.Descender; + } + } + if (dirty) { + text.EndText(); + canvas.Add(text); + } + return status; + } + + /** + * Sets the extra space between paragraphs. + * @return the extra space between paragraphs + */ + public float ExtraParagraphSpace { + get { + return extraParagraphSpace; + } + + set { + this.extraParagraphSpace = value; + } + } + + /** + * Clears the chunk array. A call to go() will always return + * NO_MORE_TEXT. + */ + public void ClearChunks() { + if (bidiLine != null) + bidiLine.ClearChunks(); + } + + /** Gets the space/character extra spacing ratio for + * fully justified text. + * @return the space/character extra spacing ratio + */ + public float SpaceCharRatio { + get { + return spaceCharRatio; + } + + set { + this.spaceCharRatio = value; + } + } + + /** Gets the run direction. + * @return the run direction + */ + public int RunDirection { + get { + return runDirection; + } + + set { + if (value < PdfWriter.RUN_DIRECTION_DEFAULT || value > PdfWriter.RUN_DIRECTION_RTL) + throw new Exception("Invalid run direction: " + value); + this.runDirection = value; + } + } + + /** Gets the number of lines written. + * @return the number of lines written + */ + public int LinesWritten { + get { + return this.linesWritten; + } + } + + /** Sets the arabic shaping options. The option can be AR_NOVOWEL, + * AR_COMPOSEDTASHKEEL and AR_LIG. + * @param arabicOptions the arabic shaping options + */ + public int ArabicOptions { + set { + this.arabicOptions = value; + } + get { + return arabicOptions; + } + } + + /** Gets the biggest descender value of the last line written. + * @return the biggest descender value of the last line written + */ + public float Descender { + get { + return descender; + } + } + + /** Gets the width that the line will occupy after writing. + * Only the width of the first line is returned. + * @param phrase the Phrase containing the line + * @param runDirection the run direction + * @param arabicOptions the options for the arabic shaping + * @return the width of the line + */ + public static float GetWidth(Phrase phrase, int runDirection, int arabicOptions) { + ColumnText ct = new ColumnText(null); + ct.AddText(phrase); + ct.AddWaitingPhrase(); + PdfLine line = ct.bidiLine.ProcessLine(0, 20000, Element.ALIGN_LEFT, runDirection, arabicOptions); + if (line == null) + return 0; + else + return 20000 - line.WidthLeft; + } + + /** Gets the width that the line will occupy after writing. + * Only the width of the first line is returned. + * @param phrase the Phrase containing the line + * @return the width of the line + */ + public static float GetWidth(Phrase phrase) { + return GetWidth(phrase, PdfWriter.RUN_DIRECTION_NO_BIDI, 0); + } + + /** Shows a line of text. Only the first line is written. + * @param canvas where the text is to be written to + * @param alignment the alignment. It is not influenced by the run direction + * @param phrase the Phrase with the text + * @param x the x reference position + * @param y the y reference position + * @param rotation the rotation to be applied in degrees counterclockwise + * @param runDirection the run direction + * @param arabicOptions the options for the arabic shaping + */ + public static void ShowTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation, int runDirection, int arabicOptions) { + if (alignment != Element.ALIGN_LEFT && alignment != Element.ALIGN_CENTER + && alignment != Element.ALIGN_RIGHT) + alignment = Element.ALIGN_LEFT; + canvas.SaveState(); + ColumnText ct = new ColumnText(canvas); + if (rotation == 0) { + if (alignment == Element.ALIGN_LEFT) + ct.SetSimpleColumn(phrase, x, y - 1, 20000 + x, y + 2, 2, alignment); + else if (alignment == Element.ALIGN_RIGHT) + ct.SetSimpleColumn(phrase, x-20000, y-1, x, y+2, 2, alignment); + else + ct.SetSimpleColumn(phrase, x-20000, y-1, x+20000, y+2, 2, alignment); + } + else { + double alpha = rotation * Math.PI / 180.0; + float cos = (float)Math.Cos(alpha); + float sin = (float)Math.Sin(alpha); + canvas.ConcatCTM(cos, sin, -sin, cos, x, y); + if (alignment == Element.ALIGN_LEFT) + ct.SetSimpleColumn(phrase, 0, -1, 20000, 2, 2, alignment); + else if (alignment == Element.ALIGN_RIGHT) + ct.SetSimpleColumn(phrase, -20000, -1, 0, 2, 2, alignment); + else + ct.SetSimpleColumn(phrase, -20000, -1, 20000, 2, 2, alignment); + } + if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { + if (alignment == Element.ALIGN_LEFT) + alignment = Element.ALIGN_RIGHT; + else if (alignment == Element.ALIGN_RIGHT) + alignment = Element.ALIGN_LEFT; + } + ct.Alignment = alignment; + ct.ArabicOptions = arabicOptions; + ct.RunDirection = runDirection; + ct.Go(); + canvas.RestoreState(); + } + + /** Shows a line of text. Only the first line is written. + * @param canvas where the text is to be written to + * @param alignment the alignment + * @param phrase the Phrase with the text + * @param x the x reference position + * @param y the y reference position + * @param rotation the rotation to be applied in degrees counterclockwise + */ + public static void ShowTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation) { + ShowTextAligned(canvas, alignment, phrase, x, y, rotation, PdfWriter.RUN_DIRECTION_NO_BIDI, 0); + } + + protected int GoComposite(bool simulate) { + if (!rectangularMode) + throw new DocumentException("Irregular columns are not supported in composite mode."); + linesWritten = 0; + descender = 0; + bool firstPass = adjustFirstLine; + main_loop: + while (true) { + if (compositeElements.Count == 0) + return NO_MORE_TEXT; + IElement element = (IElement)compositeElements[0]; + if (element.Type == Element.PARAGRAPH) { + Paragraph para = (Paragraph)element; + int status = 0; + for (int keep = 0; keep < 2; ++keep) { + float lastY = yLine; + bool createHere = false; + if (compositeColumn == null) { + compositeColumn = new ColumnText(canvas); + compositeColumn.UseAscender = (firstPass ? useAscender : false); + compositeColumn.Alignment = para.Alignment; + compositeColumn.Indent = para.IndentationLeft + para.FirstLineIndent; + compositeColumn.ExtraParagraphSpace = para.ExtraParagraphSpace; + compositeColumn.FollowingIndent = para.IndentationLeft; + compositeColumn.RightIndent = para.IndentationRight; + compositeColumn.SetLeading(para.Leading, para.MultipliedLeading); + compositeColumn.RunDirection = runDirection; + compositeColumn.ArabicOptions = arabicOptions; + compositeColumn.SpaceCharRatio = spaceCharRatio; + compositeColumn.AddText(para); + if (!firstPass) { + yLine -= para.SpacingBefore; + } + createHere = true; + } + compositeColumn.leftX = leftX; + compositeColumn.rightX = rightX; + compositeColumn.yLine = yLine; + compositeColumn.rectangularWidth = rectangularWidth; + compositeColumn.rectangularMode = rectangularMode; + compositeColumn.minY = minY; + compositeColumn.maxY = maxY; + bool keepCandidate = (para.KeepTogether && createHere && !firstPass); + status = compositeColumn.Go(simulate || (keepCandidate && keep == 0)); + UpdateFilledWidth(compositeColumn.filledWidth); + if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { + compositeColumn = null; + yLine = lastY; + return NO_MORE_COLUMN; + } + if (simulate || !keepCandidate) + break; + if (keep == 0) { + compositeColumn = null; + yLine = lastY; + } + } + firstPass = false; + yLine = compositeColumn.yLine; + linesWritten += compositeColumn.linesWritten; + descender = compositeColumn.descender; + if ((status & NO_MORE_TEXT) != 0) { + compositeColumn = null; + compositeElements.RemoveAt(0); + yLine -= para.SpacingAfter; + } + if ((status & NO_MORE_COLUMN) != 0) { + return NO_MORE_COLUMN; + } + } + else if (element.Type == Element.LIST) { + List list = (List)element; + ArrayList items = list.Items; + ListItem item = null; + float listIndentation = list.IndentationLeft; + int count = 0; + Stack stack = new Stack(); + for (int k = 0; k < items.Count; ++k) { + Object obj = items[k]; + if (obj is ListItem) { + if (count == listIdx) { + item = (ListItem)obj; + break; + } + else ++count; + } + else if (obj is List) { + stack.Push(new Object[]{list, k, listIndentation}); + list = (List)obj; + items = list.Items; + listIndentation += list.IndentationLeft; + k = -1; + continue; + } + if (k == items.Count - 1) { + if (stack.Count > 0) { + Object[] objs = (Object[])stack.Pop(); + list = (List)objs[0]; + items = list.Items; + k = (int)objs[1]; + listIndentation = (float)objs[2]; + } + } + } + int status = 0; + for (int keep = 0; keep < 2; ++keep) { + float lastY = yLine; + bool createHere = false; + if (compositeColumn == null) { + if (item == null) { + listIdx = 0; + compositeElements.RemoveAt(0); + goto main_loop; + } + compositeColumn = new ColumnText(canvas); + + compositeColumn.UseAscender = (firstPass ? useAscender : false); + compositeColumn.Alignment = item.Alignment; + compositeColumn.Indent = item.IndentationLeft + listIndentation + item.FirstLineIndent; + compositeColumn.ExtraParagraphSpace = item.ExtraParagraphSpace; + compositeColumn.FollowingIndent = compositeColumn.Indent; + compositeColumn.RightIndent = item.IndentationRight + list.IndentationRight; + compositeColumn.SetLeading(item.Leading, item.MultipliedLeading); + compositeColumn.RunDirection = runDirection; + compositeColumn.ArabicOptions = arabicOptions; + compositeColumn.SpaceCharRatio = spaceCharRatio; + compositeColumn.AddText(item); + if (!firstPass) { + yLine -= item.SpacingBefore; + } + createHere = true; + } + compositeColumn.leftX = leftX; + compositeColumn.rightX = rightX; + compositeColumn.yLine = yLine; + compositeColumn.rectangularWidth = rectangularWidth; + compositeColumn.rectangularMode = rectangularMode; + compositeColumn.minY = minY; + compositeColumn.maxY = maxY; + bool keepCandidate = (item.KeepTogether && createHere && !firstPass); + status = compositeColumn.Go(simulate || (keepCandidate && keep == 0)); + UpdateFilledWidth(compositeColumn.filledWidth); + if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { + compositeColumn = null; + yLine = lastY; + return NO_MORE_COLUMN; + } + if (simulate || !keepCandidate) + break; + if (keep == 0) { + compositeColumn = null; + yLine = lastY; + } + } + firstPass = false; + yLine = compositeColumn.yLine; + linesWritten += compositeColumn.linesWritten; + descender = compositeColumn.descender; + if (!float.IsNaN(compositeColumn.firstLineY) && !compositeColumn.firstLineYDone) { + if (!simulate) + ShowTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(item.ListSymbol), compositeColumn.leftX + listIndentation, compositeColumn.firstLineY, 0); + compositeColumn.firstLineYDone = true; + } + if ((status & NO_MORE_TEXT) != 0) { + compositeColumn = null; + ++listIdx; + yLine -= item.SpacingAfter; + } + if ((status & NO_MORE_COLUMN) != 0) { + return NO_MORE_COLUMN; + } + } + else if (element.Type == Element.PTABLE) { + // don't write anything in the current column if there's no more space available + if (yLine < minY || yLine > maxY) + return NO_MORE_COLUMN; + + // get the PdfPTable element + PdfPTable table = (PdfPTable)element; + + // we ignore tables without a body + if (table.Size <= table.HeaderRows) { + compositeElements.RemoveAt(0); + continue; + } + + // offsets + float yTemp = yLine; + if (!firstPass && listIdx == 0) { + yTemp -= table.SpacingBefore; + } + float yLineWrite = yTemp; + + // don't write anything in the current column if there's no more space available + if (yTemp < minY || yTemp > maxY) { + return NO_MORE_COLUMN; + } + + // coordinates + currentLeading = 0; + float x1 = leftX; + float tableWidth; + if (table.LockedWidth) { + tableWidth = table.TotalWidth; + UpdateFilledWidth(tableWidth); + } + else { + tableWidth = rectangularWidth * table.WidthPercentage / 100f; + table.TotalWidth = tableWidth; + } + + // how many header rows are real header rows; how many are footer rows? + int headerRows = table.HeaderRows; + int footerRows = table.FooterRows; + if (footerRows > headerRows) + footerRows = headerRows; + int realHeaderRows = headerRows - footerRows; + float headerHeight = table.HeaderHeight; + float footerHeight = table.FooterHeight; + + // make sure the header and footer fit on the page + bool skipHeader = (!firstPass && table.SkipFirstHeader && listIdx <= headerRows); + if (!skipHeader) { + yTemp -= headerHeight; + if (yTemp < minY || yTemp > maxY) { + if (firstPass) { + compositeElements.RemoveAt(0); + continue; + } + return NO_MORE_COLUMN; + } + } + + // how many real rows (not header or footer rows) fit on a page? + int k; + if (listIdx < headerRows) { + listIdx = headerRows; + } + if (!table.ElementComplete) { + yTemp -= footerHeight; + } + for (k = listIdx; k < table.Size; ++k) { + float rowHeight = table.GetRowHeight(k); + if (yTemp - rowHeight < minY) + break; + yTemp -= rowHeight; + } + if (!table.ElementComplete) { + yTemp += footerHeight; + } + // either k is the first row that doesn't fit on the page (break); + if (k < table.Size) { + if (table.SplitRows && (!table.SplitLate || (k == listIdx && firstPass))) { + if (!splittedRow) { + splittedRow = true; + table = new PdfPTable(table); + compositeElements[0] = table; + ArrayList rows = table.Rows; + for (int i = headerRows; i < listIdx; ++i) + rows[i] = null; + } + float h = yTemp - minY; + PdfPRow newRow = table.GetRow(k).SplitRow(h); + if (newRow == null) { + if (k == listIdx) { + return NO_MORE_COLUMN; + } + } + else { + yTemp = minY; + table.Rows.Insert(++k, newRow); + } + } + else if (!table.SplitRows && k == listIdx && firstPass) { + compositeElements.RemoveAt(0); + splittedRow = false; + continue; + } + else if (k == listIdx && !firstPass && (!table.SplitRows || table.SplitLate) && (table.FooterRows == 0 || table.ElementComplete)) { + return NO_MORE_COLUMN; + } + } + // or k is the number of rows in the table (for loop was done). + firstPass = false; + // we draw the table (for real now) + if (!simulate) { + // set the alignment + switch (table.HorizontalAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + x1 += rectangularWidth - tableWidth; + break; + default: + x1 += (rectangularWidth - tableWidth) / 2f; + break; + } + // copy the rows that fit on the page in a new table nt + PdfPTable nt = PdfPTable.ShallowCopy(table); + ArrayList rows = table.Rows; + ArrayList sub = nt.Rows; + + // first we add the real header rows (if necessary) + if (!skipHeader) { + for (int j = 0; j < realHeaderRows; ++j) { + PdfPRow headerRow = (PdfPRow)rows[j]; + sub.Add(headerRow); + } + } + else { + nt.HeaderRows = footerRows; + } + // then we add the real content + for (int j = listIdx; j < k; ++j) { + sub.Add(rows[j]); + } + // if k < table.size(), we must indicate that the new table is complete; + // otherwise no footers will be added (because iText thinks the table continues on the same page) + if (k < table.Size) { + nt.ElementComplete = true; + } + // we add the footer rows if necessary (not for incomplete tables) + for (int j = 0; j < footerRows && nt.ElementComplete; ++j) { + sub.Add(rows[j + realHeaderRows]); + } + + // we need a correction if the last row needs to be extended + float rowHeight = 0; + if (table.ExtendLastRow) { + PdfPRow last = (PdfPRow)sub[sub.Count - 1 - footerRows]; + rowHeight = last.MaxHeights; + last.MaxHeights = yTemp - minY + rowHeight; + yTemp = minY; + } + + // now we render the rows of the new table + if (canvases != null) + nt.WriteSelectedRows(0, -1, x1, yLineWrite, canvases); + else + nt.WriteSelectedRows(0, -1, x1, yLineWrite, canvas); + if (table.ExtendLastRow) { + PdfPRow last = (PdfPRow)sub[sub.Count - 1 - footerRows]; + last.MaxHeights = rowHeight; + } + } + else if (table.ExtendLastRow && minY > PdfPRow.BOTTOM_LIMIT) { + yTemp = minY; + } + yLine = yTemp; + if (!(skipHeader || table.ElementComplete)) { + yLine += footerHeight; + } + if (k >= table.Size) { + yLine -= table.SpacingAfter; + compositeElements.RemoveAt(0); + splittedRow = false; + listIdx = 0; + } + else { + if (splittedRow) { + ArrayList rows = table.Rows; + for (int i = listIdx; i < k; ++i) + rows[i] = null; + } + listIdx = k; + return NO_MORE_COLUMN; + } + } + else if (element.Type == Element.YMARK) { + if (!simulate) { + IDrawInterface zh = (IDrawInterface)element; + zh.Draw(canvas, leftX, minY, rightX, maxY, yLine); + } + compositeElements.RemoveAt(0); + } + else + compositeElements.RemoveAt(0); + } + } + + /** + * Sets the canvas. + * @param canvas + */ + public PdfContentByte Canvas { + set { + canvas = value; + canvases = null; + if (compositeColumn != null) + compositeColumn.Canvas = value; + } + get { + return canvas; + } + } + + /** + * Sets the canvases. + * @param canvas + */ + public PdfContentByte[] Canvases { + set { + canvases = value; + canvas = canvases[PdfPTable.TEXTCANVAS]; + if (compositeColumn != null) + compositeColumn.Canvases = canvases; + } + get { + return canvases; + } + } + + /** + * Checks if the element has a height of 0. + * @return true or false + * @since 2.1.2 + */ + public bool ZeroHeightElement() { + return composite && compositeElements.Count != 0 && ((IElement)compositeElements[0]).Type == Element.YMARK; + } + + /** + * Enables/Disables adjustment of first line height based on max ascender. + * @param use enable adjustment if true + */ + public bool UseAscender { + set { + useAscender = value; + } + get { + return useAscender; + } + } + + /** + * Checks the status variable and looks if there's still some text. + */ + public static bool HasMoreText(int status) { + return (status & ColumnText.NO_MORE_TEXT) == 0; + } + /** + * Holds value of property filledWidth. + */ + private float filledWidth; + + /** + * Sets the real width used by the largest line. Only used to set it + * to zero to start another measurement. + * @param filledWidth the real width used by the largest line + */ + public float FilledWidth { + set { + filledWidth = value; + } + get { + return filledWidth; + } + } + + /** + * Replaces the filledWidth if greater than the existing one. + * @param w the new filledWidth if greater than the existing one + */ + public void UpdateFilledWidth(float w) { + if (w > filledWidth) + filledWidth = w; + } + + private bool adjustFirstLine = true; + + /** + * Sets the first line adjustment. Some objects have properties, like spacing before, that + * behave differently if the object is the first to be written after go() or not. The first line adjustment is + * true by default but can be changed if several objects are to be placed one + * after the other in the same column calling go() several times. + * @param adjustFirstLine true to adjust the first line, false otherwise + */ + public bool AdjustFirstLine { + set { + adjustFirstLine = value; + } + get { + return adjustFirstLine; + } + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs b/iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs new file mode 100644 index 0000000..d2d8645 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs @@ -0,0 +1,109 @@ +using System; +using iTextSharp.text; + +/* + * $Id: DefaultSplitCharacter.cs,v 1.1 2008/05/22 22:11:09 psoares33 Exp $ + * + * Copyright 2008 Bruno Lowagie and Xavier Le Vourch + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * The default class that is used to determine whether or not a character + * is a split character. You can subclass this class to define your own + * split characters. + * @since 2.1.2 + */ + public class DefaultSplitCharacter : ISplitCharacter { + + /** + * An instance of the default SplitCharacter. + */ + public static readonly ISplitCharacter DEFAULT = new DefaultSplitCharacter(); + + /** + * Checks if a character can be used to split a PdfString. + *

+ * for the moment every character less than or equal to SPACE, the character '-' + * and some specific unicode ranges are 'splitCharacters'. + * + * @param start start position in the array + * @param current current position in the array + * @param end end position in the array + * @param cc the character array that has to be checked + * @param ck chunk array + * @return true if the character can be used to split a string, false otherwise + */ + public bool IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { + char c = GetCurrentCharacter(current, cc, ck); + if (c <= ' ' || c == '-' || c == '\u2010') { + return true; + } + if (c < 0x2002) + return false; + return ((c >= 0x2002 && c <= 0x200b) + || (c >= 0x2e80 && c < 0xd7a0) + || (c >= 0xf900 && c < 0xfb00) + || (c >= 0xfe30 && c < 0xfe50) + || (c >= 0xff61 && c < 0xffa0)); + } + + /** + * Returns the current character + * @param current current position in the array + * @param cc the character array that has to be checked + * @param ck chunk array + * @return the current character + */ + protected char GetCurrentCharacter(int current, char[] cc, PdfChunk[] ck) { + if (ck == null) { + return (char)cc[current]; + } + return (char)ck[Math.Min(current, ck.Length - 1)].GetUnicodeEquivalent(cc[current]); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/DocumentFont.cs b/iTechSharp/iTextSharp/text/pdf/DocumentFont.cs new file mode 100644 index 0000000..d2dd905 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/DocumentFont.cs @@ -0,0 +1,633 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class DocumentFont : BaseFont { + + // code, [glyph, width] + private Hashtable metrics = new Hashtable(); + private String fontName; + private PRIndirectReference refFont; + private PdfDictionary font; + private IntHashtable uni2byte = new IntHashtable(); + private IntHashtable byte2uni = new IntHashtable(); + private float Ascender = 800; + private float CapHeight = 700; + private float Descender = -200; + private float ItalicAngle = 0; + private float llx = -50; + private float lly = -200; + private float urx = 100; + private float ury = 900; + private bool isType0 = false; + + private BaseFont cjkMirror; + + private static String[] cjkNames = {"HeiseiMin-W3", "HeiseiKakuGo-W5", "STSong-Light", "MHei-Medium", + "MSung-Light", "HYGoThic-Medium", "HYSMyeongJo-Medium", "MSungStd-Light", "STSongStd-Light", + "HYSMyeongJoStd-Medium", "KozMinPro-Regular"}; + + private static String[] cjkEncs = {"UniJIS-UCS2-H", "UniJIS-UCS2-H", "UniGB-UCS2-H", "UniCNS-UCS2-H", + "UniCNS-UCS2-H", "UniKS-UCS2-H", "UniKS-UCS2-H", "UniCNS-UCS2-H", "UniGB-UCS2-H", + "UniKS-UCS2-H", "UniJIS-UCS2-H"}; + + private static String[] cjkNames2 = {"MSungStd-Light", "STSongStd-Light", "HYSMyeongJoStd-Medium", "KozMinPro-Regular"}; + + private static String[] cjkEncs2 = {"UniCNS-UCS2-H", "UniGB-UCS2-H", "UniKS-UCS2-H", "UniJIS-UCS2-H", + "UniCNS-UTF16-H", "UniGB-UTF16-H", "UniKS-UTF16-H", "UniJIS-UTF16-H"}; + + private static int[] stdEnc = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 32,33,34,35,36,37,38,8217,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 8216,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,161,162,163,8260,165,402,167,164,39,8220,171,8249,8250,64257,64258, + 0,8211,8224,8225,183,0,182,8226,8218,8222,8221,187,8230,8240,0,191, + 0,96,180,710,732,175,728,729,168,0,730,184,0,733,731,711, + 8212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,198,0,170,0,0,0,0,321,216,338,186,0,0,0,0, + 0,230,0,0,0,305,0,0,322,248,339,223,0,0,0,0}; + + /** Creates a new instance of DocumentFont */ + internal DocumentFont(PRIndirectReference refFont) { + encoding = ""; + fontSpecific = false; + this.refFont = refFont; + fontType = FONT_TYPE_DOCUMENT; + font = (PdfDictionary)PdfReader.GetPdfObject(refFont); + fontName = PdfName.DecodeName(((PdfName)PdfReader.GetPdfObject(font.Get(PdfName.BASEFONT))).ToString()); + PdfName subType = (PdfName)PdfReader.GetPdfObject(font.Get(PdfName.SUBTYPE)); + if (PdfName.TYPE1.Equals(subType) || PdfName.TRUETYPE.Equals(subType)) + DoType1TT(); + else { + for (int k = 0; k < cjkNames.Length; ++k) { + if (fontName.StartsWith(cjkNames[k])) { + fontName = cjkNames[k]; + cjkMirror = BaseFont.CreateFont(fontName, cjkEncs[k], false); + return; + } + } + String enc = PdfName.DecodeName(((PdfName)PdfReader.GetPdfObject(font.Get(PdfName.ENCODING))).ToString()); + for (int k = 0; k < cjkEncs2.Length; ++k) { + if (enc.StartsWith(cjkEncs2[k])) { + if (k > 3) + k -= 4; + cjkMirror = BaseFont.CreateFont(cjkNames2[k], cjkEncs2[k], false); + return; + } + } + if (PdfName.TYPE0.Equals(subType) && enc.Equals("Identity-H")) { + ProcessType0(font); + isType0 = true; + } + } + } + + private void ProcessType0(PdfDictionary font) { + byte[] touni = PdfReader.GetStreamBytes((PRStream)PdfReader.GetPdfObjectRelease(font.Get(PdfName.TOUNICODE))); + PdfArray df = (PdfArray)PdfReader.GetPdfObjectRelease(font.Get(PdfName.DESCENDANTFONTS)); + PdfDictionary cidft = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)df.ArrayList[0]); + PdfNumber dwo = (PdfNumber)PdfReader.GetPdfObjectRelease(cidft.Get(PdfName.DW)); + int dw = 1000; + if (dwo != null) + dw = dwo.IntValue; + IntHashtable widths = ReadWidths((PdfArray)PdfReader.GetPdfObjectRelease(cidft.Get(PdfName.W))); + PdfDictionary fontDesc = (PdfDictionary)PdfReader.GetPdfObjectRelease(cidft.Get(PdfName.FONTDESCRIPTOR)); + FillFontDesc(fontDesc); + FillMetrics(touni, widths, dw); + } + + private IntHashtable ReadWidths(PdfArray ws) { + IntHashtable hh = new IntHashtable(); + if (ws == null) + return hh; + ArrayList ar = ws.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + int c1 = ((PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)ar[k])).IntValue; + PdfObject obj = PdfReader.GetPdfObjectRelease((PdfObject)ar[++k]); + if (obj.IsArray()) { + ArrayList ar2 = ((PdfArray)obj).ArrayList; + for (int j = 0; j < ar2.Count; ++j) { + int c2 = ((PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)ar2[j])).IntValue; + hh[c1++] = c2; + } + } + else { + int c2 = ((PdfNumber)obj).IntValue; + int w = ((PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)ar[++k])).IntValue; + for (; c1 <= c2; ++c1) + hh[c1] = w; + } + } + return hh; + } + + private String DecodeString(PdfString ps) { + if (ps.IsHexWriting()) + return PdfEncodings.ConvertToString(ps.GetBytes(), "UnicodeBigUnmarked"); + else + return ps.ToUnicodeString(); + } + + private void FillMetrics(byte[] touni, IntHashtable widths, int dw) { + PdfContentParser ps = new PdfContentParser(new PRTokeniser(touni)); + PdfObject ob = null; + PdfObject last = null; + while ((ob = ps.ReadPRObject()) != null) { + if (ob.Type == PdfContentParser.COMMAND_TYPE) { + if (ob.ToString().Equals("beginbfchar")) { + int n = ((PdfNumber)last).IntValue; + for (int k = 0; k < n; ++k) { + String cid = DecodeString((PdfString)ps.ReadPRObject()); + String uni = DecodeString((PdfString)ps.ReadPRObject()); + if (uni.Length == 1) { + int cidc = (int)cid[0]; + int unic = (int)uni[uni.Length - 1]; + int w = dw; + if (widths.ContainsKey(cidc)) + w = widths[cidc]; + metrics[unic] = new int[]{cidc, w}; + } + } + } + else if (ob.ToString().Equals("beginbfrange")) { + int n = ((PdfNumber)last).IntValue; + for (int k = 0; k < n; ++k) { + String cid1 = DecodeString((PdfString)ps.ReadPRObject()); + String cid2 = DecodeString((PdfString)ps.ReadPRObject()); + int cid1c = (int)cid1[0]; + int cid2c = (int)cid2[0]; + PdfObject ob2 = ps.ReadPRObject(); + if (ob2.IsString()) { + String uni = DecodeString((PdfString)ob2); + if (uni.Length == 1) { + int unic = (int)uni[uni.Length - 1]; + for (; cid1c <= cid2c; cid1c++, unic++) { + int w = dw; + if (widths.ContainsKey(cid1c)) + w = widths[cid1c]; + metrics[unic] = new int[]{cid1c, w}; + } + } + } + else { + ArrayList ar = ((PdfArray)ob2).ArrayList; + for (int j = 0; j < ar.Count; ++j, ++cid1c) { + String uni = DecodeString((PdfString)ar[j]); + if (uni.Length == 1) { + int unic = (int)uni[uni.Length - 1]; + int w = dw; + if (widths.ContainsKey(cid1c)) + w = widths[cid1c]; + metrics[unic] = new int[]{cid1c, w}; + } + } + } + } + } + } + else + last = ob; + } + } + + private void DoType1TT() { + PdfObject enc = PdfReader.GetPdfObject(font.Get(PdfName.ENCODING)); + if (enc == null) + FillEncoding(null); + else { + if (enc.IsName()) + FillEncoding((PdfName)enc); + else { + PdfDictionary encDic = (PdfDictionary)enc; + enc = PdfReader.GetPdfObject(encDic.Get(PdfName.BASEENCODING)); + if (enc == null) + FillEncoding(null); + else + FillEncoding((PdfName)enc); + PdfArray diffs = (PdfArray)PdfReader.GetPdfObject(encDic.Get(PdfName.DIFFERENCES)); + if (diffs != null) { + ArrayList dif = diffs.ArrayList; + int currentNumber = 0; + for (int k = 0; k < dif.Count; ++k) { + PdfObject obj = (PdfObject)dif[k]; + if (obj.IsNumber()) + currentNumber = ((PdfNumber)obj).IntValue; + else { + int[] c = GlyphList.NameToUnicode(PdfName.DecodeName(((PdfName)obj).ToString())); + if (c != null && c.Length > 0) { + if (byte2uni.ContainsKey(currentNumber)) { + uni2byte.Remove(byte2uni[currentNumber]); + } + uni2byte[c[0]] = currentNumber; + byte2uni[currentNumber] = c[0]; + } + ++currentNumber; + } + } + } + } + } + PdfArray newWidths = (PdfArray)PdfReader.GetPdfObject(font.Get(PdfName.WIDTHS)); + PdfNumber first = (PdfNumber)PdfReader.GetPdfObject(font.Get(PdfName.FIRSTCHAR)); + PdfNumber last = (PdfNumber)PdfReader.GetPdfObject(font.Get(PdfName.LASTCHAR)); + if (BuiltinFonts14.ContainsKey(fontName)) { + BaseFont bf; + bf = BaseFont.CreateFont(fontName, WINANSI, false); + int[] e = uni2byte.ToOrderedKeys(); + for (int k = 0; k < e.Length; ++k) { + int n = uni2byte[e[k]]; + widths[n] = bf.GetRawWidth(n, GlyphList.UnicodeToName(e[k])); + } + Ascender = bf.GetFontDescriptor(ASCENT, 1000); + CapHeight = bf.GetFontDescriptor(CAPHEIGHT, 1000); + Descender = bf.GetFontDescriptor(DESCENT, 1000); + ItalicAngle = bf.GetFontDescriptor(ITALICANGLE, 1000); + llx = bf.GetFontDescriptor(BBOXLLX, 1000); + lly = bf.GetFontDescriptor(BBOXLLY, 1000); + urx = bf.GetFontDescriptor(BBOXURX, 1000); + ury = bf.GetFontDescriptor(BBOXURY, 1000); + } + if (first != null && last != null && newWidths != null) { + int f = first.IntValue; + ArrayList ar = newWidths.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + widths[f + k] = ((PdfNumber)ar[k]).IntValue; + } + } + FillFontDesc((PdfDictionary)PdfReader.GetPdfObject(font.Get(PdfName.FONTDESCRIPTOR))); + } + + private void FillFontDesc(PdfDictionary fontDesc) { + if (fontDesc == null) + return; + PdfNumber v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.ASCENT)); + if (v != null) + Ascender = v.FloatValue; + v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.CAPHEIGHT)); + if (v != null) + CapHeight = v.FloatValue; + v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.DESCENT)); + if (v != null) + Descender = v.FloatValue; + v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.ITALICANGLE)); + if (v != null) + ItalicAngle = v.FloatValue; + PdfArray bbox = (PdfArray)PdfReader.GetPdfObject(fontDesc.Get(PdfName.FONTBBOX)); + if (bbox != null) { + ArrayList ar = bbox.ArrayList; + llx = ((PdfNumber)ar[0]).FloatValue; + lly = ((PdfNumber)ar[1]).FloatValue; + urx = ((PdfNumber)ar[2]).FloatValue; + ury = ((PdfNumber)ar[3]).FloatValue; + if (llx > urx) { + float t = llx; + llx = urx; + urx = t; + } + if (lly > ury) { + float t = lly; + lly = ury; + ury = t; + } + } + } + + private void FillEncoding(PdfName encoding) { + if (PdfName.MAC_ROMAN_ENCODING.Equals(encoding) || PdfName.WIN_ANSI_ENCODING.Equals(encoding)) { + byte[] b = new byte[256]; + for (int k = 0; k < 256; ++k) + b[k] = (byte)k; + String enc = WINANSI; + if (PdfName.MAC_ROMAN_ENCODING.Equals(encoding)) + enc = MACROMAN; + String cv = PdfEncodings.ConvertToString(b, enc); + char[] arr = cv.ToCharArray(); + for (int k = 0; k < 256; ++k) { + uni2byte[arr[k]] = k; + byte2uni[k] = arr[k]; + } + } + else { + for (int k = 0; k < 256; ++k) { + uni2byte[stdEnc[k]] = k; + byte2uni[k] = stdEnc[k]; + } + } + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + * + */ + public override string[][] FamilyFontName { + get { + return FullFontName; + } + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT, + * ITALICANGLE, BBOXLLX, BBOXLLY, BBOXURX + * and BBOXURY. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + * + */ + public override float GetFontDescriptor(int key, float fontSize) { + if (cjkMirror != null) + return cjkMirror.GetFontDescriptor(key, fontSize); + switch (key) { + case AWT_ASCENT: + case ASCENT: + return Ascender * fontSize / 1000; + case CAPHEIGHT: + return CapHeight * fontSize / 1000; + case AWT_DESCENT: + case DESCENT: + return Descender * fontSize / 1000; + case ITALICANGLE: + return ItalicAngle; + case BBOXLLX: + return llx * fontSize / 1000; + case BBOXLLY: + return lly * fontSize / 1000; + case BBOXURX: + return urx * fontSize / 1000; + case BBOXURY: + return ury * fontSize / 1000; + case AWT_LEADING: + return 0; + case AWT_MAXADVANCE: + return (urx - llx) * fontSize / 1000; + } + return 0; + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + * + */ + public override string[][] FullFontName { + get { + return new string[][]{new string[]{"", "", "", fontName}}; + } + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
+ * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] AllNameEntries { + get { + return new string[][]{new string[]{"4", "", "", "", fontName}}; + } + } + + /** Gets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @return the kerning to be applied + * + */ + public override int GetKerning(int char1, int char2) { + return 0; + } + + /** Gets the postscript font name. + * @return the postscript font name + * + */ + public override string PostscriptFontName { + get { + return fontName; + } + set { + } + } + + /** Gets the width from the font according to the Unicode char c + * or the name. If the name is null it's a symbolic font. + * @param c the unicode char + * @param name the glyph name + * @return the width of the char + * + */ + internal override int GetRawWidth(int c, String name) { + return 0; + } + + /** Checks if the font has any kerning pairs. + * @return true if the font has any kerning pairs + * + */ + public override bool HasKernPairs() { + return false; + } + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param params several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + * + */ + internal override void WriteFont(PdfWriter writer, PdfIndirectReference refi, Object[] param) { + } + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public override int GetWidth(int char1) { + if (cjkMirror != null) + return cjkMirror.GetWidth(char1); + else if (isType0) { + int[] ws = (int[])metrics[(int)char1]; + if (ws != null) + return ws[1]; + else + return 0; + } + else + return base.GetWidth(char1); + } + + public override int GetWidth(String text) { + if (cjkMirror != null) + return cjkMirror.GetWidth(text); + else if (isType0) { + char[] chars = text.ToCharArray(); + int len = chars.Length; + int total = 0; + for (int k = 0; k < len; ++k) { + int[] ws = (int[])metrics[(int)chars[k]]; + if (ws != null) + total += ws[1]; + } + return total; + } + else + return base.GetWidth(text); + } + + internal override byte[] ConvertToBytes(String text) { + if (cjkMirror != null) + return PdfEncodings.ConvertToBytes(text, CJKFont.CJK_ENCODING); + else if (isType0) { + char[] chars = text.ToCharArray(); + int len = chars.Length; + byte[] b = new byte[len * 2]; + int bptr = 0; + for (int k = 0; k < len; ++k) { + int[] ws = (int[])metrics[(int)chars[k]]; + if (ws != null) { + int g = ws[0]; + b[bptr++] = (byte)(g / 256); + b[bptr++] = (byte)(g); + } + } + if (bptr == b.Length) + return b; + else { + byte[] nb = new byte[bptr]; + System.Array.Copy(b, 0, nb, 0, bptr); + return nb; + } + } + else { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + for (int k = 0; k < cc.Length; ++k) { + if (uni2byte.ContainsKey(cc[k])) + b[ptr++] = (byte)uni2byte[cc[k]]; + } + if (ptr == b.Length) + return b; + else { + byte[] b2 = new byte[ptr]; + System.Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + } + } + + internal override byte[] ConvertToBytes(int char1) { + if (cjkMirror != null) + return PdfEncodings.ConvertToBytes((char)char1, CJKFont.CJK_ENCODING); + else if (isType0) { + int[] ws = (int[])metrics[(int)char1]; + if (ws != null) { + int g = ws[0]; + return new byte[]{(byte)(g / 256), (byte)(g)}; + } + else + return new byte[0]; + } + else { + if (uni2byte.ContainsKey(char1)) + return new byte[]{(byte)uni2byte[char1]}; + else + return new byte[0]; + } + } + + internal PdfIndirectReference IndirectReference { + get { + return refFont; + } + } + + public override bool CharExists(int c) { + if (cjkMirror != null) + return cjkMirror.CharExists(c); + else if (isType0) { + return metrics.ContainsKey((int)c); + } + else + return base.CharExists(c); + } + + public override bool SetKerning(int char1, int char2, int kern) { + return false; + } + + public override int[] GetCharBBox(int c) { + return null; + } + + protected override int[] GetRawCharBBox(int c, String name) { + return null; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs b/iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs new file mode 100644 index 0000000..88398fe --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: EnumerateTTC.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Enumerates all the fonts inside a True Type Collection. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class EnumerateTTC : TrueTypeFont { + + protected String[] names; + + internal EnumerateTTC(String ttcFile) { + fileName = ttcFile; + rf = new RandomAccessFileOrArray(ttcFile); + FindNames(); + } + + internal EnumerateTTC(byte[] ttcArray) { + fileName = "Byte array TTC"; + rf = new RandomAccessFileOrArray(ttcArray); + FindNames(); + } + + internal void FindNames() { + tables = new Hashtable(); + + try { + String mainTag = ReadStandardString(4); + if (!mainTag.Equals("ttcf")) + throw new DocumentException(fileName + " is not a valid TTC file."); + rf.SkipBytes(4); + int dirCount = rf.ReadInt(); + names = new String[dirCount]; + int dirPos = rf.FilePointer; + for (int dirIdx = 0; dirIdx < dirCount; ++dirIdx) { + tables.Clear(); + rf.Seek(dirPos); + rf.SkipBytes(dirIdx * 4); + directoryOffset = rf.ReadInt(); + rf.Seek(directoryOffset); + if (rf.ReadInt() != 0x00010000) + throw new DocumentException(fileName + " is not a valid TTF file."); + int num_tables = rf.ReadUnsignedShort(); + rf.SkipBytes(6); + for (int k = 0; k < num_tables; ++k) { + String tag = ReadStandardString(4); + rf.SkipBytes(4); + int[] table_location = new int[2]; + table_location[0] = rf.ReadInt(); + table_location[1] = rf.ReadInt(); + tables[tag] = table_location; + } + names[dirIdx] = this.BaseFont; + } + } + finally { + if (rf != null) + rf.Close(); + } + } + + internal String[] Names { + get { + return names; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs b/iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs new file mode 100644 index 0000000..b12e3c9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs @@ -0,0 +1,101 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: ExtendedColor.cs,v 1.4 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + //public class ExtendedColor : Color { + public abstract class ExtendedColor : Color { + + internal const int TYPE_RGB = 0; + internal const int TYPE_GRAY = 1; + internal const int TYPE_CMYK = 2; + internal const int TYPE_SEPARATION = 3; + internal const int TYPE_PATTERN = 4; + internal const int TYPE_SHADING = 5; + + protected int type; + + public ExtendedColor(int type) : base(0, 0, 0) { + this.type = type; + } + + public ExtendedColor(int type, float red, float green, float blue) : base(Normalize(red), Normalize(green), Normalize(blue)) { + this.type = type; + } + + public int Type { + get { + return type; + } + } + + public static int GetType(object color) { + if (color is ExtendedColor) + return ((ExtendedColor)color).Type; + return TYPE_RGB; + } + + internal static float Normalize(float value) { + if (value < 0) + return 0; + if (value > 1) + return 1; + return (float)value; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FdfReader.cs b/iTechSharp/iTextSharp/text/pdf/FdfReader.cs new file mode 100644 index 0000000..cb7e23b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FdfReader.cs @@ -0,0 +1,218 @@ +using System; +using System.Text; +using System.Collections; +using System.Net; +using System.IO; + +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Reads an FDF form and makes the fields available + * @author Paulo Soares (psoares@consiste.pt) + */ + public class FdfReader : PdfReader { + + internal Hashtable fields; + internal String fileSpec; + internal PdfName encoding; + + /** Reads an FDF form. + * @param filename the file name of the form + * @throws IOException on error + */ + public FdfReader(String filename) : base(filename) { + } + + /** Reads an FDF form. + * @param pdfIn the byte array with the form + * @throws IOException on error + */ + public FdfReader(byte[] pdfIn) : base(pdfIn) { + } + + /** Reads an FDF form. + * @param url the URL of the document + * @throws IOException on error + */ + public FdfReader(Uri url) : base(url) { + } + + /** Reads an FDF form. + * @param is the InputStream containing the document. The stream is read to the + * end but is not closed + * @throws IOException on error + */ + public FdfReader(Stream isp) : base(isp) { + } + + protected internal override void ReadPdf() { + fields = new Hashtable(); + try { + tokens.CheckFdfHeader(); + RebuildXref(); + ReadDocObj(); + } + finally { + try { + tokens.Close(); + } + catch { + // empty on purpose + } + } + ReadFields(); + } + + protected virtual void KidNode(PdfDictionary merged, String name) { + PdfArray kids = (PdfArray)GetPdfObject(merged.Get(PdfName.KIDS)); + if (kids == null || kids.ArrayList.Count == 0) { + if (name.Length > 0) + name = name.Substring(1); + fields[name] = merged; + } + else { + merged.Remove(PdfName.KIDS); + ArrayList ar = kids.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + PdfDictionary dic = new PdfDictionary(); + dic.Merge(merged); + PdfDictionary newDic = (PdfDictionary)GetPdfObject((PdfObject)ar[k]); + PdfString t = (PdfString)GetPdfObject(newDic.Get(PdfName.T)); + String newName = name; + if (t != null) + newName += "." + t.ToUnicodeString(); + dic.Merge(newDic); + dic.Remove(PdfName.T); + KidNode(dic, newName); + } + } + } + + protected virtual void ReadFields() { + catalog = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.ROOT)); + PdfDictionary fdf = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.FDF)); + if (fdf == null) + return; + PdfString fs = (PdfString)GetPdfObject(fdf.Get(PdfName.F)); + if (fs != null) + fileSpec = fs.ToUnicodeString(); + PdfArray fld = (PdfArray)GetPdfObject(fdf.Get(PdfName.FIELDS)); + if (fld == null) + return; + encoding = (PdfName)GetPdfObject(fdf.Get(PdfName.ENCODING)); + PdfDictionary merged = new PdfDictionary(); + merged.Put(PdfName.KIDS, fld); + KidNode(merged, ""); + } + + /** Gets all the fields. The map is keyed by the fully qualified + * field name and the value is a merged PdfDictionary + * with the field content. + * @return all the fields + */ + public Hashtable Fields { + get { + return fields; + } + } + + /** Gets the field dictionary. + * @param name the fully qualified field name + * @return the field dictionary + */ + public PdfDictionary GetField(String name) { + return (PdfDictionary)fields[name]; + } + + /** Gets the field value or null if the field does not + * exist or has no value defined. + * @param name the fully qualified field name + * @return the field value or null + */ + public String GetFieldValue(String name) { + PdfDictionary field = (PdfDictionary)fields[name]; + if (field == null) + return null; + PdfObject v = GetPdfObject(field.Get(PdfName.V)); + if (v == null) + return null; + if (v.IsName()) + return PdfName.DecodeName(((PdfName)v).ToString()); + else if (v.IsString()) { + PdfString vs = (PdfString)v; + if (encoding == null || vs.Encoding != null) + return vs.ToUnicodeString(); + byte[] b = vs.GetBytes(); + if (b.Length >= 2 && b[0] == (byte)254 && b[1] == (byte)255) + return vs.ToUnicodeString(); + try { + if (encoding.Equals(PdfName.SHIFT_JIS)) + return Encoding.GetEncoding(932).GetString(b); + else if (encoding.Equals(PdfName.UHC)) + return Encoding.GetEncoding(949).GetString(b); + else if (encoding.Equals(PdfName.GBK)) + return Encoding.GetEncoding(936).GetString(b); + else if (encoding.Equals(PdfName.BIGFIVE)) + return Encoding.GetEncoding(950).GetString(b); + } + catch { + } + return vs.ToUnicodeString(); + } + return null; + } + + /** Gets the PDF file specification contained in the FDF. + * @return the PDF file specification contained in the FDF + */ + public String FileSpec { + get { + return fileSpec; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FdfWriter.cs b/iTechSharp/iTextSharp/text/pdf/FdfWriter.cs new file mode 100644 index 0000000..864a217 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FdfWriter.cs @@ -0,0 +1,324 @@ +using System; +using System.util; +using System.IO; +using System.Collections; + +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Writes an FDF form. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class FdfWriter { + private static readonly byte[] HEADER_FDF = DocWriter.GetISOBytes("%FDF-1.2\n%\u00e2\u00e3\u00cf\u00d3\n"); + Hashtable fields = new Hashtable(); + + /** The PDF file associated with the FDF. */ + private String file; + + /** Creates a new FdfWriter. */ + public FdfWriter() { + } + + /** Writes the content to a stream. + * @param os the stream + * @throws DocumentException on error + * @throws IOException on error + */ + public void WriteTo(Stream os) { + Wrt wrt = new Wrt(os, this); + wrt.WriteTo(); + } + + internal bool SetField(String field, PdfObject value) { + Hashtable map = fields; + StringTokenizer tk = new StringTokenizer(field, "."); + if (!tk.HasMoreTokens()) + return false; + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (tk.HasMoreTokens()) { + if (obj == null) { + obj = new Hashtable(); + map[s] = obj; + map = (Hashtable)obj; + continue; + } + else if (obj is Hashtable) + map = (Hashtable)obj; + else + return false; + } + else { + if (!(obj is Hashtable)) { + map[s] = value; + return true; + } + else + return false; + } + } + } + + internal void IterateFields(Hashtable values, Hashtable map, String name) { + foreach (DictionaryEntry entry in map) { + String s = (String)entry.Key; + Object obj = entry.Value; + if (obj is Hashtable) + IterateFields(values, (Hashtable)obj, name + "." + s); + else + values[(name + "." + s).Substring(1)] = obj; + } + } + + /** Removes the field value. + * @param field the field name + * @return true if the field was found and removed, + * false otherwise + */ + public bool RemoveField(String field) { + Hashtable map = fields; + StringTokenizer tk = new StringTokenizer(field, "."); + if (!tk.HasMoreTokens()) + return false; + ArrayList hist = new ArrayList(); + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (obj == null) + return false; + hist.Add(map); + hist.Add(s); + if (tk.HasMoreTokens()) { + if (obj is Hashtable) + map = (Hashtable)obj; + else + return false; + } + else { + if (obj is Hashtable) + return false; + else + break; + } + } + for (int k = hist.Count - 2; k >= 0; k -= 2) { + map = (Hashtable)hist[k]; + String s = (String)hist[k + 1]; + map.Remove(s); + if (map.Count > 0) + break; + } + return true; + } + + /** Gets all the fields. The map is keyed by the fully qualified + * field name and the values are PdfObject. + * @return a map with all the fields + */ + public Hashtable GetFields() { + Hashtable values = new Hashtable(); + IterateFields(values, fields, ""); + return values; + } + + /** Gets the field value. + * @param field the field name + * @return the field value or null if not found + */ + public String GetField(String field) { + Hashtable map = fields; + StringTokenizer tk = new StringTokenizer(field, "."); + if (!tk.HasMoreTokens()) + return null; + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (obj == null) + return null; + if (tk.HasMoreTokens()) { + if (obj is Hashtable) + map = (Hashtable)obj; + else + return null; + } + else { + if (obj is Hashtable) + return null; + else { + if (((PdfObject)obj).IsString()) + return ((PdfString)obj).ToUnicodeString(); + else + return PdfName.DecodeName(obj.ToString()); + } + } + } + } + + /** Sets the field value as a name. + * @param field the fully qualified field name + * @param value the value + * @return true if the value was inserted, + * false if the name is incompatible with + * an existing field + */ + public bool SetFieldAsName(String field, String value) { + return SetField(field, new PdfName(value)); + } + + /** Sets the field value as a string. + * @param field the fully qualified field name + * @param value the value + * @return true if the value was inserted, + * false if the name is incompatible with + * an existing field + */ + public bool SetFieldAsString(String field, String value) { + return SetField(field, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + + /** Sets all the fields from this FdfReader + * @param fdf the FdfReader + */ + public void SetFields(FdfReader fdf) { + Hashtable map = fdf.Fields; + foreach (DictionaryEntry entry in map) { + String key = (String)entry.Key; + PdfDictionary dic = (PdfDictionary)entry.Value; + PdfObject v = dic.Get(PdfName.V); + if (v != null) { + SetField(key, v); + } + } + } + + /** Sets all the fields from this PdfReader + * @param pdf the PdfReader + */ + public void SetFields(PdfReader pdf) { + SetFields(pdf.AcroFields); + } + + /** Sets all the fields from this AcroFields + * @param acro the AcroFields + */ + public void SetFields(AcroFields af) { + foreach (DictionaryEntry entry in af.Fields) { + String fn = (String)entry.Key; + AcroFields.Item item = (AcroFields.Item)entry.Value; + PdfDictionary dic = (PdfDictionary)item.merged[0]; + PdfObject v = PdfReader.GetPdfObjectRelease(dic.Get(PdfName.V)); + if (v == null) + continue; + PdfObject ft = PdfReader.GetPdfObjectRelease(dic.Get(PdfName.FT)); + if (ft == null || PdfName.SIG.Equals(ft)) + continue; + SetField(fn, v); + } + } + + /** Gets the PDF file name associated with the FDF. + * @return the PDF file name associated with the FDF + */ + public String File { + get { + return this.file; + } + set { + file = value; + } + } + + internal class Wrt : PdfWriter { + private FdfWriter fdf; + + internal Wrt(Stream os, FdfWriter fdf) : base(new PdfDocument(), os) { + this.fdf = fdf; + this.os.Write(HEADER_FDF, 0, HEADER_FDF.Length); + body = new PdfBody(this); + } + + internal void WriteTo() { + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.FIELDS, Calculate(fdf.fields)); + if (fdf.file != null) + dic.Put(PdfName.F, new PdfString(fdf.file, PdfObject.TEXT_UNICODE)); + PdfDictionary fd = new PdfDictionary(); + fd.Put(PdfName.FDF, dic); + PdfIndirectReference refi = AddToBody(fd).IndirectReference; + byte[] b = GetISOBytes("trailer\n"); + os.Write(b, 0, b.Length); + PdfDictionary trailer = new PdfDictionary(); + trailer.Put(PdfName.ROOT, refi); + trailer.ToPdf(null, os); + b = GetISOBytes("\n%%EOF\n"); + os.Write(b, 0, b.Length); + os.Close(); + } + + + internal PdfArray Calculate(Hashtable map) { + PdfArray ar = new PdfArray(); + foreach (DictionaryEntry entry in map) { + String key = (String)entry.Key; + Object v = entry.Value; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.T, new PdfString(key, PdfObject.TEXT_UNICODE)); + if (v is Hashtable) { + dic.Put(PdfName.KIDS, Calculate((Hashtable)v)); + } + else { + dic.Put(PdfName.V, (PdfObject)v); + } + ar.Add(dic); + } + return ar; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FontDetails.cs b/iTechSharp/iTextSharp/text/pdf/FontDetails.cs new file mode 100644 index 0000000..8e56bb1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FontDetails.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; + +/* + * $Id: FontDetails.cs,v 1.7 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Each font in the document will have an instance of this class + * where the characters used will be represented. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class FontDetails { + + /** The indirect reference to this font + */ + PdfIndirectReference indirectReference; + /** The font name that appears in the document body stream + */ + PdfName fontName; + /** The font + */ + BaseFont baseFont; + /** The font if its an instance of TrueTypeFontUnicode + */ + TrueTypeFontUnicode ttu; + + CJKFont cjkFont; + /** The array used with single byte encodings + */ + byte[] shortTag; + /** The map used with double byte encodings. The key is Int(glyph) and the + * value is int[]{glyph, width, Unicode code} + */ + Hashtable longTag; + + IntHashtable cjkTag; + /** The font type + */ + int fontType; + /** true if the font is symbolic + */ + bool symbolic; + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. + */ + protected bool subset = true; + /** Each font used in a document has an instance of this class. + * This class stores the characters used in the document and other + * specifics unique to the current working document. + * @param fontName the font name + * @param indirectReference the indirect reference to the font + * @param baseFont the BaseFont + */ + internal FontDetails(PdfName fontName, PdfIndirectReference indirectReference, BaseFont baseFont) { + this.fontName = fontName; + this.indirectReference = indirectReference; + this.baseFont = baseFont; + fontType = baseFont.FontType; + switch (fontType) { + case BaseFont.FONT_TYPE_T1: + case BaseFont.FONT_TYPE_TT: + shortTag = new byte[256]; + break; + case BaseFont.FONT_TYPE_CJK: + cjkTag = new IntHashtable(); + cjkFont = (CJKFont)baseFont; + break; + case BaseFont.FONT_TYPE_TTUNI: + longTag = new Hashtable(); + ttu = (TrueTypeFontUnicode)baseFont; + symbolic = baseFont.IsFontSpecific(); + break; + } + } + + /** Gets the indirect reference to this font. + * @return the indirect reference to this font + */ + internal PdfIndirectReference IndirectReference { + get { + return indirectReference; + } + } + + /** Gets the font name as it appears in the document body. + * @return the font name + */ + internal PdfName FontName { + get { + return fontName; + } + } + + /** Gets the BaseFont of this font. + * @return the BaseFont of this font + */ + internal BaseFont BaseFont { + get { + return baseFont; + } + } + + /** Converts the text into bytes to be placed in the document. + * The conversion is done according to the font and the encoding and the characters + * used are stored. + * @param text the text to convert + * @return the conversion + */ + internal byte[] ConvertToBytes(string text) { + byte[] b = null; + switch (fontType) { + case BaseFont.FONT_TYPE_T3: + return baseFont.ConvertToBytes(text); + case BaseFont.FONT_TYPE_T1: + case BaseFont.FONT_TYPE_TT: { + b = baseFont.ConvertToBytes(text); + int len = b.Length; + for (int k = 0; k < len; ++k) + shortTag[((int)b[k]) & 0xff] = 1; + break; + } + case BaseFont.FONT_TYPE_CJK: { + int len = text.Length; + for (int k = 0; k < len; ++k) + cjkTag[cjkFont.GetCidCode(text[k])] = 0; + b = baseFont.ConvertToBytes(text); + break; + } + case BaseFont.FONT_TYPE_DOCUMENT: { + b = baseFont.ConvertToBytes(text); + break; + } + case BaseFont.FONT_TYPE_TTUNI: { + int len = text.Length; + int[] metrics = null; + char[] glyph = new char[len]; + int i = 0; + if (symbolic) { + b = PdfEncodings.ConvertToBytes(text, "symboltt"); + len = b.Length; + for (int k = 0; k < len; ++k) { + metrics = ttu.GetMetricsTT(b[k] & 0xff); + if (metrics == null) + continue; + longTag[metrics[0]] = new int[]{metrics[0], metrics[1], ttu.GetUnicodeDifferences(b[k] & 0xff)}; + glyph[i++] = (char)metrics[0]; + } + } + else { + for (int k = 0; k < len; ++k) { + int val; + if (Utilities.IsSurrogatePair(text, k)) { + val = Utilities.ConvertToUtf32(text, k); + k++; + } + else { + val = (int)text[k]; + } + metrics = ttu.GetMetricsTT(val); + if (metrics == null) + continue; + int m0 = metrics[0]; + int gl = m0; + if (!longTag.ContainsKey(gl)) + longTag[gl] = new int[]{m0, metrics[1], val}; + glyph[i++] = (char)m0; + } + } + string s = new String(glyph, 0, i); + b = PdfEncodings.ConvertToBytes(s, CJKFont.CJK_ENCODING); + break; + } + } + return b; + } + + /** Writes the font definition to the document. + * @param writer the PdfWriter of this document + */ + internal void WriteFont(PdfWriter writer) { + switch (fontType) { + case BaseFont.FONT_TYPE_T3: + baseFont.WriteFont(writer, indirectReference, null); + break; + case BaseFont.FONT_TYPE_T1: + case BaseFont.FONT_TYPE_TT: { + int firstChar; + int lastChar; + for (firstChar = 0; firstChar < 256; ++firstChar) { + if (shortTag[firstChar] != 0) + break; + } + for (lastChar = 255; lastChar >= firstChar; --lastChar) { + if (shortTag[lastChar] != 0) + break; + } + if (firstChar > 255) { + firstChar = 255; + lastChar = 255; + } + baseFont.WriteFont(writer, indirectReference, new Object[]{firstChar, lastChar, shortTag, subset}); + break; + } + case BaseFont.FONT_TYPE_CJK: + baseFont.WriteFont(writer, indirectReference, new Object[]{cjkTag}); + break; + case BaseFont.FONT_TYPE_TTUNI: + baseFont.WriteFont(writer, indirectReference, new Object[]{longTag, subset}); + break; + } + } + + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. Set to false + * to include all. + * @param subset new value of property subset + */ + public bool Subset { + set { + this.subset = value; + } + get { + return subset; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FontSelector.cs b/iTechSharp/iTextSharp/text/pdf/FontSelector.cs new file mode 100644 index 0000000..41cb9f3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FontSelector.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Selects the appropriate fonts that contain the glyphs needed to + * render text correctly. The fonts are checked in order until the + * character is found. + *

+ * The built in fonts "Symbol" and "ZapfDingbats", if used, have a special encoding + * to allow the characters to be referred by Unicode. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class FontSelector { + + protected ArrayList fonts = new ArrayList(); + + /** + * Adds a Font to be searched for valid characters. + * @param font the Font + */ + public void AddFont(Font font) { + if (font.BaseFont != null) { + fonts.Add(font); + return; + } + BaseFont bf = font.GetCalculatedBaseFont(true); + Font f2 = new Font(bf, font.Size, font.CalculatedStyle, font.Color); + fonts.Add(f2); + } + + /** + * Process the text so that it will render with a combination of fonts + * if needed. + * @param text the text + * @return a Phrase with one or more chunks + */ + public Phrase Process(String text) { + int fsize = fonts.Count; + if (fsize == 0) + throw new ArgumentException("No font is defined."); + char[] cc = text.ToCharArray(); + int len = cc.Length; + StringBuilder sb = new StringBuilder(); + Font font = null; + int lastidx = -1; + Phrase ret = new Phrase(); + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c == '\n' || c == '\r') { + sb.Append(c); + continue; + } + if (Utilities.IsSurrogatePair(cc, k)) { + int u = Utilities.ConvertToUtf32(cc, k); + for (int f = 0; f < fsize; ++f) { + font = (Font)fonts[f]; + if (font.BaseFont.CharExists(u)) { + if (lastidx != f) { + if (sb.Length > 0 && lastidx != -1) { + Chunk ck = new Chunk(sb.ToString(), (Font)fonts[lastidx]); + ret.Add(ck); + sb.Length = 0; + } + lastidx = f; + } + sb.Append(c); + sb.Append(cc[++k]); + break; + } + } + } + else { + for (int f = 0; f < fsize; ++f) { + font = (Font)fonts[f]; + if (font.BaseFont.CharExists(c)) { + if (lastidx != f) { + if (sb.Length > 0 && lastidx != -1) { + Chunk ck = new Chunk(sb.ToString(), (Font)fonts[lastidx]); + ret.Add(ck); + sb.Length = 0; + } + lastidx = f; + } + sb.Append(c); + break; + } + } + } + } + if (sb.Length > 0) { + Chunk ck = new Chunk(sb.ToString(), (Font)fonts[lastidx == -1 ? 0 : lastidx]); + ret.Add(ck); + } + return ret; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/GlyphList.cs b/iTechSharp/iTextSharp/text/pdf/GlyphList.cs new file mode 100644 index 0000000..9ba1c7a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/GlyphList.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; +using System.IO; +using System.Globalization; +using System.util; + +/* + * $Id: GlyphList.cs,v 1.7 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class GlyphList { + private static Hashtable unicode2names = new Hashtable(); + private static Hashtable names2unicode = new Hashtable(); + + static GlyphList() { + Stream istr = null; + try { + istr = BaseFont.GetResourceStream(BaseFont.RESOURCE_PATH + "glyphlist.txt"); + if (istr == null) { + String msg = "glyphlist.txt not found as resource."; + throw new Exception(msg); + } + byte[] buf = new byte[1024]; + MemoryStream outp = new MemoryStream(); + while (true) { + int size = istr.Read(buf, 0, buf.Length); + if (size == 0) + break; + outp.Write(buf, 0, size); + } + istr.Close(); + istr = null; + String s = PdfEncodings.ConvertToString(outp.ToArray(), null); + StringTokenizer tk = new StringTokenizer(s, "\r\n"); + while (tk.HasMoreTokens()) { + String line = tk.NextToken(); + if (line.StartsWith("#")) + continue; + StringTokenizer t2 = new StringTokenizer(line, " ;\r\n\t\f"); + String name = null; + String hex = null; + if (!t2.HasMoreTokens()) + continue; + name = t2.NextToken(); + if (!t2.HasMoreTokens()) + continue; + hex = t2.NextToken(); + int num = int.Parse(hex, NumberStyles.HexNumber); + unicode2names[num] = name; + names2unicode[name] = new int[]{num}; + } + } + catch (Exception e) { + Console.Error.WriteLine("glyphlist.txt loading error: " + e.Message); + } + finally { + if (istr != null) { + try { + istr.Close(); + } + catch { + // empty on purpose + } + } + } + } + + public static int[] NameToUnicode(string name) { + return (int[])names2unicode[name]; + } + + public static string UnicodeToName(int num) { + return (string)unicode2names[num]; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/GrayColor.cs b/iTechSharp/iTextSharp/text/pdf/GrayColor.cs new file mode 100644 index 0000000..ea3c9c8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/GrayColor.cs @@ -0,0 +1,86 @@ +using System; + +/* + * $Id: GrayColor.cs,v 1.5 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class GrayColor : ExtendedColor { + + private float cgray; + + public static readonly GrayColor GRAYBLACK = new GrayColor(0f); + public static readonly GrayColor GRAYWHITE = new GrayColor(1f); + + public GrayColor(int intGray) : this((float)intGray / 255f) {} + + public GrayColor(float floatGray) : base(TYPE_GRAY, floatGray, floatGray, floatGray) { + cgray = Normalize(floatGray); + } + + public float Gray { + get { + return cgray; + } + } + + public override bool Equals(Object obj) { + return (obj is GrayColor) && ((GrayColor)obj).cgray == this.cgray; + } + + public override int GetHashCode() { + return cgray.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs b/iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs new file mode 100644 index 0000000..1d665c3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs @@ -0,0 +1,130 @@ +using System; + +using iTextSharp.text.pdf.hyphenation; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Hyphenates words automatically accordingly to the language and country. + * The hyphenator engine was taken from FOP and uses the TEX patterns. If a language + * is not provided and a TEX pattern for it exists, it can be easily adapted. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class HyphenationAuto : IHyphenationEvent { + + /** The hyphenator engine. + */ + protected Hyphenator hyphenator; + /** The second part of the hyphenated word. + */ + protected string post; + + /** Creates a new hyphenation instance usable in Chunk. + * @param lang the language ("en" for english, for example) + * @param country the country ("GB" for Great-Britain or "none" for no country, for example) + * @param leftMin the minimun number of letters before the hyphen + * @param rightMin the minimun number of letters after the hyphen + */ + public HyphenationAuto(string lang, string country, int leftMin, int rightMin) { + hyphenator = new Hyphenator(lang, country, leftMin, rightMin); + } + + /** Gets the hyphen symbol. + * @return the hyphen symbol + */ + public string HyphenSymbol { + get { + return "-"; + } + } + + /** Hyphenates a word and returns the first part of it. To get + * the second part of the hyphenated word call getHyphenatedWordPost(). + * @param word the word to hyphenate + * @param font the font used by this word + * @param fontSize the font size used by this word + * @param remainingWidth the width available to fit this word in + * @return the first part of the hyphenated word including + * the hyphen symbol, if any + */ + public string GetHyphenatedWordPre(string word, BaseFont font, float fontSize, float remainingWidth) { + post = word; + string hyphen = this.HyphenSymbol; + float hyphenWidth = font.GetWidthPoint(hyphen, fontSize); + if (hyphenWidth > remainingWidth) + return ""; + Hyphenation hyphenation = hyphenator.Hyphenate(word); + if (hyphenation == null) { + return ""; + } + int len = hyphenation.Length; + int k; + for (k = 0; k < len; ++k) { + if (font.GetWidthPoint(hyphenation.GetPreHyphenText(k), fontSize) + hyphenWidth > remainingWidth) + break; + } + --k; + if (k < 0) + return ""; + post = hyphenation.GetPostHyphenText(k); + return hyphenation.GetPreHyphenText(k) + hyphen; + } + + /** Gets the second part of the hyphenated word. Must be called + * after getHyphenatedWordPre(). + * @return the second part of the hyphenated word + */ + public string HyphenatedWordPost { + get { + return post; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs b/iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs new file mode 100644 index 0000000..d2337e8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs @@ -0,0 +1,108 @@ +using System; +using System.Text; +using System.Collections; +using System.IO; + +namespace iTextSharp.text.pdf +{ + ///

+ /// Summary description for ICC_Profile. + /// + public class ICC_Profile + { + protected byte[] data; + protected int numComponents; + private static Hashtable cstags = new Hashtable(); + + protected ICC_Profile() { + } + + public static ICC_Profile GetInstance(byte[] data) { + if (data.Length < 128 | data[36] != 0x61 || data[37] != 0x63 + || data[38] != 0x73 || data[39] != 0x70) + throw new ArgumentException("Invalid ICC profile"); + ICC_Profile icc = new ICC_Profile(); + icc.data = data; + object cs = cstags[Encoding.ASCII.GetString(data, 16, 4)]; + icc.numComponents = (cs == null ? 0 : (int)cs); + return icc; + } + + public static ICC_Profile GetInstance(Stream file) { + byte[] head = new byte[128]; + int remain = head.Length; + int ptr = 0; + while (remain > 0) { + int n = file.Read(head, ptr, remain); + if (n <= 0) + throw new ArgumentException("Invalid ICC profile"); + remain -= n; + ptr += n; + } + if (head[36] != 0x61 || head[37] != 0x63 + || head[38] != 0x73 || head[39] != 0x70) + throw new ArgumentException("Invalid ICC profile"); + remain = ((head[0] & 0xff) << 24) | ((head[1] & 0xff) << 16) + | ((head[2] & 0xff) << 8) | (head[3] & 0xff); + byte[] icc = new byte[remain]; + System.Array.Copy(head, 0, icc, 0, head.Length); + remain -= head.Length; + ptr = head.Length; + while (remain > 0) { + int n = file.Read(icc, ptr, remain); + if (n <= 0) + throw new ArgumentException("Invalid ICC profile"); + remain -= n; + ptr += n; + } + return GetInstance(icc); + } + + public static ICC_Profile GetInstance(String fname) { + FileStream fs = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.Read); + ICC_Profile icc = GetInstance(fs); + fs.Close(); + return icc; + } + + public byte[] Data { + get { + return data; + } + } + + public int NumComponents { + get { + return numComponents; + } + } + + static ICC_Profile() { + cstags["XYZ "] = 3; + cstags["Lab "] = 3; + cstags["Luv "] = 3; + cstags["YCbr"] = 3; + cstags["Yxy "] = 3; + cstags["RGB "] = 3; + cstags["GRAY"] = 1; + cstags["HSV "] = 3; + cstags["HLS "] = 3; + cstags["CMYK"] = 4; + cstags["CMY "] = 3; + cstags["2CLR"] = 2; + cstags["3CLR"] = 3; + cstags["4CLR"] = 4; + cstags["5CLR"] = 5; + cstags["6CLR"] = 6; + cstags["7CLR"] = 7; + cstags["8CLR"] = 8; + cstags["9CLR"] = 9; + cstags["ACLR"] = 10; + cstags["BCLR"] = 11; + cstags["CCLR"] = 12; + cstags["DCLR"] = 13; + cstags["ECLR"] = 14; + cstags["FCLR"] = 15; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs b/iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs new file mode 100644 index 0000000..4c7d34b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs @@ -0,0 +1,84 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Classes implementing this interface can create custom encodings or + * replace existing ones. It is used in the context of PdfEncoding. + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IExtraEncoding { + + /** + * Converts an Unicode string to a byte array according to some encoding. + * @param text the Unicode string + * @param encoding the requested encoding. It's mainly of use if the same class + * supports more than one encoding. + * @return the conversion or null if no conversion is supported + */ + byte[] CharToByte(String text, String encoding); + + /** + * Converts an Unicode char to a byte array according to some encoding. + * @param char1 the Unicode char + * @param encoding the requested encoding. It's mainly of use if the same class + * supports more than one encoding. + * @return the conversion or null if no conversion is supported + */ + byte[] CharToByte(char char1, String encoding); + + /** + * Converts a byte array to an Unicode string according to some encoding. + * @param b the input byte array + * @param encoding the requested encoding. It's mainly of use if the same class + * supports more than one encoding. + * @return the conversion or null if no conversion is supported + */ + String ByteToChar(byte[] b, String encoding); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs b/iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs new file mode 100644 index 0000000..5369ab8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs @@ -0,0 +1,83 @@ +using System; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Called by Chunk to hyphenate a word. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IHyphenationEvent { + + /** Gets the hyphen symbol. + * @return the hyphen symbol + */ + string HyphenSymbol { + get; + } + + /** Hyphenates a word and returns the first part of it. To get + * the second part of the hyphenated word call getHyphenatedWordPost(). + * @param word the word to hyphenate + * @param font the font used by this word + * @param fontSize the font size used by this word + * @param remainingWidth the width available to fit this word in + * @return the first part of the hyphenated word including + * the hyphen symbol, if any + */ + string GetHyphenatedWordPre(string word, BaseFont font, float fontSize, float remainingWidth); + + /** Gets the second part of the hyphenated word. Must be called + * after getHyphenatedWordPre(). + * @return the second part of the hyphenated word + */ + string HyphenatedWordPost { + get; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs b/iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs new file mode 100644 index 0000000..1a6d4bf --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs @@ -0,0 +1,73 @@ +using System; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * The interface common to all layer types. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IPdfOCG { + + /** + * Gets the PdfIndirectReference that represents this layer. + * @return the PdfIndirectReference that represents this layer + */ + PdfIndirectReference Ref { + get; + } + + /** + * Gets the object representing the layer. + * @return the object representing the layer + */ + PdfObject PdfObject { + get; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs b/iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs new file mode 100644 index 0000000..bf4e680 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs @@ -0,0 +1,29 @@ +using System; + +namespace iTextSharp.text.pdf +{ + /// + /// Summary description for IPdfPCellEvent. + /// + public interface IPdfPCellEvent { + /** This method is called at the end of the cell rendering. The text or graphics are added to + * one of the 4 PdfContentByte contained in + * canvases.
+ * The indexes to canvases are:

+ *

    + *
  • PdfPTable.BASECANVAS - the original PdfContentByte. Anything placed here + * will be under the cell. + *
  • PdfPTable.BACKGROUNDCANVAS - the layer where the background goes to. + *
  • PdfPTable.LINECANVAS - the layer where the lines go to. + *
  • PdfPTable.TEXTCANVAS - the layer where the text go to. Anything placed here + * will be over the cell. + *
+ * The layers are placed in sequence on top of each other. + *

+ * @param cell the cell + * @param position the coordinates of the cell + * @param canvases an array of PdfContentByte + */ + void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs b/iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs new file mode 100644 index 0000000..0762633 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs @@ -0,0 +1,96 @@ +using System; + +/* + * $Id: IPdfPTableEvent.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** An interface that can be used to retrieve the position of cells in PdfPTable. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IPdfPTableEvent { + + /** This method is called at the end of the table rendering. The text or graphics are added to + * one of the 4 PdfContentByte contained in + * canvases.
+ * The indexes to canvases are:

+ *

    + *
  • PdfPTable.BASECANVAS - the original PdfContentByte. Anything placed here + * will be under the table. + *
  • PdfPTable.BACKGROUNDCANVAS - the layer where the background goes to. + *
  • PdfPTable.LINECANVAS - the layer where the lines go to. + *
  • PdfPTable.TEXTCANVAS - the layer where the text go to. Anything placed here + * will be over the table. + *
+ * The layers are placed in sequence on top of each other. + *

+ * The widths and heights have the coordinates of the cells.
+ * The size of the widths array is the number of rows. + * Each sub-array in widths corresponds to the x column border positions where + * the first element is the x coordinate of the left table border and the last + * element is the x coordinate of the right table border. + * If colspan is not used all the sub-arrays in widths + * are the same.
+ * For the heights the first element is the y coordinate of the top table border and the last + * element is the y coordinate of the bottom table border. + * @param table the PdfPTable in use + * @param widths an array of arrays with the cells' x positions. It has the length of the number + * of rows + * @param heights an array with the cells' y positions. It has a length of the number + * of rows + 1 + * @param headerRows the number of rows defined for the header. + * @param rowStart the first row number after the header + * @param canvases an array of PdfContentByte + */ + void TableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases); + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs b/iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs new file mode 100644 index 0000000..b441107 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs @@ -0,0 +1,189 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: IPdfPageEvent.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Allows a class to catch several document events. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + + public interface IPdfPageEvent { + + /** + * Called when the document is opened. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnOpenDocument(PdfWriter writer, Document document); + + /** + * Called when a page is initialized. + *

+ * Note that if even if a page is not written this method is still + * called. It is preferable to use onEndPage to avoid + * infinite loops. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnStartPage(PdfWriter writer, Document document); + + /** + * Called when a page is finished, just before being written to the document. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnEndPage(PdfWriter writer, Document document); + + /** + * Called when the document is closed. + *

+ * Note that this method is called with the page number equal + * to the last page plus one. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnCloseDocument(PdfWriter writer, Document document); + + /** + * Called when a Paragraph is written. + *

+ * paragraphPosition will hold the height at which the + * paragraph will be written to. This is useful to insert bookmarks with + * more control. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the paragraph will be written to + */ + void OnParagraph(PdfWriter writer, Document document, float paragraphPosition); + + /** + * Called when a Paragraph is written. + *

+ * paragraphPosition will hold the height of the end of the paragraph. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position of the end of the paragraph + */ + void OnParagraphEnd(PdfWriter writer,Document document,float paragraphPosition); + + /** + * Called when a Chapter is written. + *

+ * position will hold the height at which the + * chapter will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + void OnChapter(PdfWriter writer,Document document,float paragraphPosition, Paragraph title); + + /** + * Called when the end of a Chapter is reached. + *

+ * position will hold the height of the end of the chapter. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + */ + void OnChapterEnd(PdfWriter writer,Document document,float paragraphPosition); + + /** + * Called when a Section is written. + *

+ * position will hold the height at which the + * section will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + void OnSection(PdfWriter writer,Document document,float paragraphPosition, int depth, Paragraph title); + + /** + * Called when the end of a Section is reached. + *

+ * position will hold the height of the section end. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + */ + void OnSectionEnd(PdfWriter writer,Document document,float paragraphPosition); + + /** + * Called when a Chunk with a generic tag is written. + *

+ * It is usefull to pinpoint the Chunk location to generate + * bookmarks, for example. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param rect the Rectangle containing the Chunk + * @param text the text of the tag + */ + void OnGenericTag(PdfWriter writer, Document document, Rectangle rect, string text); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/IntHashtable.cs b/iTechSharp/iTextSharp/text/pdf/IntHashtable.cs new file mode 100644 index 0000000..57aae9e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IntHashtable.cs @@ -0,0 +1,312 @@ +using System; + +// IntHashtable - a Hashtable that uses ints as the keys +// +// This is 90% based on JavaSoft's java.util.Hashtable. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ + +namespace iTextSharp.text.pdf { + + /// A Hashtable that uses ints as the keys. + //

+ // Use just like java.util.Hashtable, except that the keys must be ints. + // This is much faster than creating a new int for each access. + //

+ // Fetch the software.
+ // Fetch the entire Acme package. + //

+ // @see java.util.Hashtable + + public class IntHashtable { + /// The hash table data. + private IntHashtableEntry[] table; + + /// The total number of entries in the hash table. + private int count; + + /// Rehashes the table when count exceeds this threshold. + private int threshold; + + /// The load factor for the hashtable. + private float loadFactor; + + /// Constructs a new, empty hashtable with the specified initial + // capacity and the specified load factor. + // @param initialCapacity the initial number of buckets + // @param loadFactor a number between 0.0 and 1.0, it defines + // the threshold for rehashing the hashtable into + // a bigger one. + // @exception IllegalArgumentException If the initial capacity + // is less than or equal to zero. + // @exception IllegalArgumentException If the load factor is + // less than or equal to zero. + public IntHashtable( int initialCapacity, float loadFactor ) { + if ( initialCapacity <= 0 || loadFactor <= 0.0 ) + throw new ArgumentException(); + this.loadFactor = loadFactor; + table = new IntHashtableEntry[initialCapacity]; + threshold = (int) ( initialCapacity * loadFactor ); + } + + /// Constructs a new, empty hashtable with the specified initial + // capacity. + // @param initialCapacity the initial number of buckets + public IntHashtable( int initialCapacity ) : this( initialCapacity, 0.75f ) {} + + /// Constructs a new, empty hashtable. A default capacity and load factor + // is used. Note that the hashtable will automatically grow when it gets + // full. + public IntHashtable() : this( 101, 0.75f ) {} + + /// Returns the number of elements contained in the hashtable. + public int Size { + get { + return count; + } + } + + /// Returns true if the hashtable contains no elements. + public bool IsEmpty() { + return count == 0; + } + + /// Returns true if the specified object is an element of the hashtable. + // This operation is more expensive than the ContainsKey() method. + // @param value the value that we are looking for + // @exception NullPointerException If the value being searched + // for is equal to null. + // @see IntHashtable#containsKey + public bool Contains( int value ) { + IntHashtableEntry[] tab = table; + for ( int i = tab.Length ; i-- > 0 ; ) { + for ( IntHashtableEntry e = tab[i] ; e != null ; e = e.next ) { + if ( e.value == value ) + return true; + } + } + return false; + } + + /// Returns true if the collection contains an element for the key. + // @param key the key that we are looking for + // @see IntHashtable#contains + public bool ContainsKey( int key ) { + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) { + if ( e.hash == hash && e.key == key ) + return true; + } + return false; + } + + /// Gets the object associated with the specified key in the + // hashtable. + // @param key the specified key + // @returns the element for the key or null if the key + // is not defined in the hash table. + // @see IntHashtable#put + public int this[int key] { + get { + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) { + if ( e.hash == hash && e.key == key ) + return e.value; + } + return 0; + } + + set { + // Makes sure the key is not already in the hashtable. + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) { + if ( e.hash == hash && e.key == key ) { + e.value = value; + return; + } + } + + if ( count >= threshold ) { + // Rehash the table if the threshold is exceeded. + Rehash(); + this[key] = value; + return; + } + + // Creates the new entry. + IntHashtableEntry en = new IntHashtableEntry(); + en.hash = hash; + en.key = key; + en.value = value; + en.next = tab[index]; + tab[index] = en; + ++count; + } + } + + /// Rehashes the content of the table into a bigger table. + // This method is called automatically when the hashtable's + // size exceeds the threshold. + protected void Rehash() { + int oldCapacity = table.Length; + IntHashtableEntry[] oldTable = table; + + int newCapacity = oldCapacity * 2 + 1; + IntHashtableEntry[] newTable = new IntHashtableEntry[newCapacity]; + + threshold = (int) ( newCapacity * loadFactor ); + table = newTable; + + for ( int i = oldCapacity ; i-- > 0 ; ) { + for ( IntHashtableEntry old = oldTable[i] ; old != null ; ) { + IntHashtableEntry e = old; + old = old.next; + + int index = ( e.hash & 0x7FFFFFFF ) % newCapacity; + e.next = newTable[index]; + newTable[index] = e; + } + } + } + + /// Removes the element corresponding to the key. Does nothing if the + // key is not present. + // @param key the key that needs to be removed + // @return the value of key, or null if the key was not found. + public int Remove( int key ) { + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index], prev = null ; e != null ; prev = e, e = e.next ) { + if ( e.hash == hash && e.key == key ) { + if ( prev != null ) + prev.next = e.next; + else + tab[index] = e.next; + --count; + return e.value; + } + } + return 0; + } + + /// Clears the hash table so that it has no more elements in it. + public void Clear() { + IntHashtableEntry[] tab = table; + for ( int index = tab.Length; --index >= 0; ) + tab[index] = null; + count = 0; + } + + public IntHashtable Clone() { + IntHashtable t = new IntHashtable(); + t.count = count; + t.loadFactor = loadFactor; + t.threshold = threshold; + t.table = new IntHashtableEntry[table.Length]; + for (int i = table.Length ; i-- > 0 ; ) { + t.table[i] = (table[i] != null) + ? (IntHashtableEntry)table[i].Clone() : null; + } + return t; + } + + public int[] ToOrderedKeys() { + int[] res = GetKeys(); + Array.Sort(res); + return res; + } + + public int[] GetKeys() { + int[] res = new int[count]; + int ptr = 0; + int index = table.Length; + IntHashtableEntry entry = null; + while (true) { + if (entry == null) + while ((index-- > 0) && ((entry = table[index]) == null)); + if (entry == null) + break; + IntHashtableEntry e = entry; + entry = e.next; + res[ptr++] = e.key; + } + return res; + } + + public class IntHashtableEntry { + internal int hash; + internal int key; + internal int value; + internal IntHashtableEntry next; + + public int Key { + get { + return key; + } + } + + public int Value { + get { + return value; + } + } + + protected internal IntHashtableEntry Clone() { + IntHashtableEntry entry = new IntHashtableEntry(); + entry.hash = hash; + entry.key = key; + entry.value = value; + entry.next = (next != null) ? next.Clone() : null; + return entry; + } + } + + public IntHashtableIterator GetEntryIterator() { + return new IntHashtableIterator(table); + } + + public class IntHashtableIterator { + // boolean keys; + int index; + IntHashtableEntry[] table; + IntHashtableEntry entry; + + internal IntHashtableIterator(IntHashtableEntry[] table) { + this.table = table; + this.index = table.Length; + } + + public bool HasNext() { + if (entry != null) { + return true; + } + while (index-- > 0) { + if ((entry = table[index]) != null) { + return true; + } + } + return false; + } + + public IntHashtableEntry Next() { + if (entry == null) { + while ((index-- > 0) && ((entry = table[index]) == null)); + } + if (entry != null) { + IntHashtableEntry e = entry; + entry = e.next; + return e; + } + throw new InvalidOperationException("IntHashtableIterator"); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs b/iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs new file mode 100644 index 0000000..cad5aff --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs @@ -0,0 +1,240 @@ +using System; +using System.IO; +using System.Collections; + +/* + * Copyright 2002-2008 by Paulo Soares. + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageioimpl.plugins.tiff.TIFFLZWDecompressor.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ +namespace iTextSharp.text.pdf { + /** + * A class for performing LZW decoding. + * + * + */ + public class LZWDecoder { + + byte[][] stringTable; + byte[] data = null; + Stream uncompData; + int tableIndex, bitsToGet = 9; + int bytePointer; + int nextData = 0; + int nextBits = 0; + + internal int[] andTable = { + 511, + 1023, + 2047, + 4095 + }; + + public LZWDecoder() { + } + + /** + * Method to decode LZW compressed data. + * + * @param data The compressed data. + * @param uncompData Array to return the uncompressed data in. + */ + public void Decode(byte[] data, Stream uncompData) { + + if (data[0] == (byte)0x00 && data[1] == (byte)0x01) { + throw new Exception("LZW flavour not supported."); + } + + InitializeStringTable(); + + this.data = data; + this.uncompData = uncompData; + + // Initialize pointers + bytePointer = 0; + + nextData = 0; + nextBits = 0; + + int code, oldCode = 0; + byte[] str; + + while ((code = this.NextCode) != 257) { + + if (code == 256) { + + InitializeStringTable(); + code = NextCode; + + if (code == 257) { + break; + } + + WriteString(stringTable[code]); + oldCode = code; + + } else { + + if (code < tableIndex) { + + str = stringTable[code]; + + WriteString(str); + AddStringToTable(stringTable[oldCode], str[0]); + oldCode = code; + + } else { + + str = stringTable[oldCode]; + str = ComposeString(str, str[0]); + WriteString(str); + AddStringToTable(str); + oldCode = code; + } + } + } + } + + + /** + * Initialize the string table. + */ + public void InitializeStringTable() { + + stringTable = new byte[8192][]; + + for (int i=0; i<256; i++) { + stringTable[i] = new byte[1]; + stringTable[i][0] = (byte)i; + } + + tableIndex = 258; + bitsToGet = 9; + } + + /** + * Write out the string just uncompressed. + */ + public void WriteString(byte[] str) { + uncompData.Write(str, 0, str.Length); + } + + /** + * Add a new string to the string table. + */ + public void AddStringToTable(byte[] oldstring, byte newstring) { + int length = oldstring.Length; + byte[] str = new byte[length + 1]; + Array.Copy(oldstring, 0, str, 0, length); + str[length] = newstring; + + // Add this new string to the table + stringTable[tableIndex++] = str; + + if (tableIndex == 511) { + bitsToGet = 10; + } else if (tableIndex == 1023) { + bitsToGet = 11; + } else if (tableIndex == 2047) { + bitsToGet = 12; + } + } + + /** + * Add a new string to the string table. + */ + public void AddStringToTable(byte[] str) { + + // Add this new string to the table + stringTable[tableIndex++] = str; + + if (tableIndex == 511) { + bitsToGet = 10; + } else if (tableIndex == 1023) { + bitsToGet = 11; + } else if (tableIndex == 2047) { + bitsToGet = 12; + } + } + + /** + * Append newstring to the end of oldstring. + */ + public byte[] ComposeString(byte[] oldstring, byte newstring) { + int length = oldstring.Length; + byte[] str = new byte[length + 1]; + Array.Copy(oldstring, 0, str, 0, length); + str[length] = newstring; + + return str; + } + + // Returns the next 9, 10, 11 or 12 bits + public int NextCode { + get { + // Attempt to get the next code. The exception is caught to make + // this robust to cases wherein the EndOfInformation code has been + // omitted from a strip. Examples of such cases have been observed + // in practice. + try { + nextData = (nextData << 8) | (data[bytePointer++] & 0xff); + nextBits += 8; + + if (nextBits < bitsToGet) { + nextData = (nextData << 8) | (data[bytePointer++] & 0xff); + nextBits += 8; + } + + int code = + (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet-9]; + nextBits -= bitsToGet; + + return code; + } catch { + // Strip not terminated as expected: return EndOfInformation code. + return 257; + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs b/iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs new file mode 100644 index 0000000..3551982 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs @@ -0,0 +1,605 @@ +using System; +using System.Collections; +using iTextSharp.text; +/* + * $Id: MultiColumnText.cs,v 1.13 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 2004 Steve Appling + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Formats content into one or more columns bounded by a + * rectangle. The columns may be simple rectangles or + * more complicated shapes. Add all of the columns before + * adding content. Column continuation is supported. A MultiColumnText object may be added to + * a document using Document.add. + * @author Steve Appling + */ + public class MultiColumnText : IElement { + + /** special constant for automatic calculation of height */ + public const float AUTOMATIC = -1f; + + /** + * total desiredHeight of columns. If AUTOMATIC, this means fill pages until done. + * This may be larger than one page + */ + private float desiredHeight; + + /** + * total height of element written out so far + */ + private float totalHeight; + + /** + * true if all the text could not be written out due to height restriction + */ + private bool overflow; + + /** + * Top of the columns - y position on starting page. + * If AUTOMATIC, it means current y position when added to document + */ + private float top; + + /** + * used to store the y position of the bottom of the page + */ + private float pageBottom; + + /** + * ColumnText object used to do all the real work. This same object is used for all columns + */ + private ColumnText columnText; + + /** + * Array of ColumnDef objects used to define the columns + */ + private ArrayList columnDefs; + + /** + * true if all columns are simple (rectangular) + */ + private bool simple = true; + + private int currentColumn = 0; + + private float nextY = AUTOMATIC; + + private bool columnsRightToLeft = false; + + private PdfDocument document; + /** + * Default constructor. Sets height to AUTOMATIC. + * Columns will repeat on each page as necessary to accomodate content length. + */ + public MultiColumnText() : this(AUTOMATIC) { + } + + /** + * Construct a MultiColumnText container of the specified height. + * If height is AUTOMATIC, fill complete pages until done. + * If a specific height is used, it may span one or more pages. + * + * @param height + */ + public MultiColumnText(float height) { + columnDefs = new ArrayList(); + desiredHeight = height; + top = AUTOMATIC; + // canvas will be set later + columnText = new ColumnText(null); + totalHeight = 0f; + } + + /** + * Construct a MultiColumnText container of the specified height + * starting at the specified Y position. + * + * @param height + * @param top + */ + public MultiColumnText(float top, float height) { + columnDefs = new ArrayList(); + desiredHeight = height; + this.top = top; + nextY = top; + // canvas will be set later + columnText = new ColumnText(null); + totalHeight = 0f; + } + + /** + * Indicates that all of the text did not fit in the + * specified height. Note that isOverflow will return + * false before the MultiColumnText object has been + * added to the document. It will always be false if + * the height is AUTOMATIC. + * + * @return true if there is still space left in the column + */ + public bool IsOverflow() { + return overflow; + } + + /** + * Copy the parameters from the specified ColumnText to use + * when rendering. Parameters like setArabicOptions + * must be set in this way. + * + * @param sourceColumn + */ + public void UseColumnParams(ColumnText sourceColumn) { + // note that canvas will be overwritten later + columnText.SetSimpleVars(sourceColumn); + } + + /** + * Add a new column. The parameters are limits for each column + * wall in the format of a sequence of points (x1,y1,x2,y2,...). + * + * @param left limits for left column + * @param right limits for right column + */ + public void AddColumn(float[] left, float[] right) { + ColumnDef nextDef = new ColumnDef(left, right, this); + simple = nextDef.IsSimple(); + columnDefs.Add(nextDef); + } + + /** + * Add a simple rectangular column with specified left + * and right x position boundaries. + * + * @param left left boundary + * @param right right boundary + */ + public void AddSimpleColumn(float left, float right) { + ColumnDef newCol = new ColumnDef(left, right, this); + columnDefs.Add(newCol); + } + + /** + * Add the specified number of evenly spaced rectangular columns. + * Columns will be seperated by the specified gutterWidth. + * + * @param left left boundary of first column + * @param right right boundary of last column + * @param gutterWidth width of gutter spacing between columns + * @param numColumns number of columns to add + */ + public void AddRegularColumns(float left, float right, float gutterWidth, int numColumns) { + float currX = left; + float width = right - left; + float colWidth = (width - (gutterWidth * (numColumns - 1))) / numColumns; + for (int i = 0; i < numColumns; i++) { + AddSimpleColumn(currX, currX + colWidth); + currX += colWidth + gutterWidth; + } + } + + /** + * Add an element to be rendered in a column. + * Note that you can only add a Phrase + * or a Chunk if the columns are + * not all simple. This is an underlying restriction in + * {@link com.lowagie.text.pdf.ColumnText} + * + * @param element element to add + * @throws DocumentException if element can't be added + */ + public void AddElement(IElement element) { + if (simple) { + columnText.AddElement(element); + } else if (element is Phrase) { + columnText.AddText((Phrase) element); + } else if (element is Chunk) { + columnText.AddText((Chunk) element); + } else { + throw new DocumentException("Can't add " + element.GetType().ToString() + " to MultiColumnText with complex columns"); + } + } + + + /** + * Write out the columns. After writing, use + * {@link #isOverflow()} to see if all text was written. + * @param canvas PdfContentByte to write with + * @param document document to write to (only used to get page limit info) + * @param documentY starting y position to begin writing at + * @return the current height (y position) after writing the columns + * @throws DocumentException on error + */ + public float Write(PdfContentByte canvas, PdfDocument document, float documentY) { + this.document = document; + columnText.Canvas = canvas; + if (columnDefs.Count == 0) { + throw new DocumentException("MultiColumnText has no columns"); + } + overflow = false; + pageBottom = document.Bottom; + float currentHeight = 0; + bool done = false; + while (!done) { + if (top == AUTOMATIC) { + top = document.GetVerticalPosition(true); + } + else if (nextY == AUTOMATIC) { + nextY = document.GetVerticalPosition(true); // RS - 07/07/2005 - - Get current doc writing position for top of columns on new page. + } + + ColumnDef currentDef = (ColumnDef) columnDefs[CurrentColumn]; + columnText.YLine = top; + + float[] left = currentDef.ResolvePositions(Rectangle.LEFT_BORDER); + float[] right = currentDef.ResolvePositions(Rectangle.RIGHT_BORDER); + if (document.IsMarginMirroring() && document.PageNumber % 2 == 0){ + float delta = document.RightMargin - document.Left; + left = (float[])left.Clone(); + right = (float[])right.Clone(); + for (int i = 0; i < left.Length; i += 2) { + left[i] -= delta; + } + for (int i = 0; i < right.Length; i += 2) { + right[i] -= delta; + } + } + currentHeight = Math.Max(currentHeight, GetHeight(left, right)); + + if (currentDef.IsSimple()) { + columnText.SetSimpleColumn(left[2], left[3], right[0], right[1]); + } else { + columnText.SetColumns(left, right); + } + + int result = columnText.Go(); + if ((result & ColumnText.NO_MORE_TEXT) != 0) { + done = true; + top = columnText.YLine; + } else if (ShiftCurrentColumn()) { + top = nextY; + } else { // check if we are done because of height + totalHeight += currentHeight; + + if ((desiredHeight != AUTOMATIC) && (totalHeight >= desiredHeight)) { + overflow = true; + break; + } else { // need to start new page and reset the columns + documentY = nextY; + NewPage(); + currentHeight = 0; + } + } + } + if (desiredHeight == AUTOMATIC && columnDefs.Count == 1) { + currentHeight = documentY - columnText.YLine; + } + return currentHeight; + } + + private void NewPage() { + ResetCurrentColumn(); + if (desiredHeight == AUTOMATIC) { + top = nextY = AUTOMATIC; + } + else { + top = nextY; + } + totalHeight = 0; + if (document != null) { + document.NewPage(); + } + } + + /** + * Figure out the height of a column from the border extents + * + * @param left left border + * @param right right border + * @return height + */ + private float GetHeight(float[] left, float[] right) { + float max = float.MinValue; + float min = float.MaxValue; + for (int i = 0; i < left.Length; i += 2) { + min = Math.Min(min, left[i + 1]); + max = Math.Max(max, left[i + 1]); + } + for (int i = 0; i < right.Length; i += 2) { + min = Math.Min(min, right[i + 1]); + max = Math.Max(max, right[i + 1]); + } + return max - min; + } + + + /** + * Processes the element by adding it to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } catch (DocumentException) { + return false; + } + } + + /** + * Gets the type of the text element. + * + * @return a type + */ + + public int Type { + get { + return Element.MULTI_COLUMN_TEXT; + } + } + + /** + * Returns null - not used + * + * @return null + */ + + public ArrayList Chunks { + get { + return null; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return false; + } + + /** + * Calculates the appropriate y position for the bottom + * of the columns on this page. + * + * @return the y position of the bottom of the columns + */ + private float GetColumnBottom() { + if (desiredHeight == AUTOMATIC) { + return pageBottom; + } else { + return Math.Max(top - (desiredHeight - totalHeight), pageBottom); + } + } + + /** + * Moves the text insertion point to the beginning of the next column, issuing a page break if + * needed. + * @throws DocumentException on error + */ + public void NextColumn() { + currentColumn = (currentColumn + 1) % columnDefs.Count; + top = nextY; + if (currentColumn == 0) { + NewPage(); + } + } + + /** + * Gets the current column. + * @return the current column + */ + public int CurrentColumn { + get { + if (columnsRightToLeft) { + return (columnDefs.Count - currentColumn - 1); + } + return currentColumn; + } + } + + /** + * Resets the current column. + */ + public void ResetCurrentColumn() { + currentColumn = 0; + } + + /** + * Shifts the current column. + * @return true if the currentcolumn has changed + */ + public bool ShiftCurrentColumn() { + if (currentColumn + 1 < columnDefs.Count) { + currentColumn++; + return true; + } + return false; + } + + /** + * Sets the direction of the columns. + * @param direction true = right2left; false = left2right + */ + public void SetColumnsRightToLeft(bool direction) { + columnsRightToLeft = direction; + } + + /** Sets the ratio between the extra word spacing and the extra character spacing + * when the text is fully justified. + * Extra word spacing will grow spaceCharRatio times more than extra character spacing. + * If the ratio is PdfWriter.NO_SPACE_CHAR_RATIO then the extra character spacing + * will be zero. + * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing + */ + public float SpaceCharRatio { + set { + columnText.SpaceCharRatio = value; + } + } + + /** Sets the run direction. + * @param runDirection the run direction + */ + public int RunDirection { + set { + columnText.RunDirection = value; + } + } + + /** Sets the arabic shaping options. The option can be AR_NOVOWEL, + * AR_COMPOSEDTASHKEEL and AR_LIG. + * @param arabicOptions the arabic shaping options + */ + public int ArabicOptions { + set { + columnText.ArabicOptions = value; + } + } + + /** Sets the default alignment + * @param alignment the default alignment + */ + public int Alignment { + set { + columnText.Alignment = value; + } + } + + public override string ToString() { + return base.ToString(); + } + + /** + * Inner class used to define a column + */ + internal class ColumnDef { + private float[] left; + private float[] right; + private MultiColumnText mc; + + internal ColumnDef(float[] newLeft, float[] newRight, MultiColumnText mc) { + this.mc = mc; + left = newLeft; + right = newRight; + } + + internal ColumnDef(float leftPosition, float rightPosition, MultiColumnText mc) { + this.mc = mc; + left = new float[4]; + left[0] = leftPosition; // x1 + left[1] = mc.top; // y1 + left[2] = leftPosition; // x2 + if (mc.desiredHeight == AUTOMATIC || mc.top == AUTOMATIC) { + left[3] = AUTOMATIC; + } else { + left[3] = mc.top - mc.desiredHeight; + } + + right = new float[4]; + right[0] = rightPosition; // x1 + right[1] = mc.top; // y1 + right[2] = rightPosition; // x2 + if (mc.desiredHeight == AUTOMATIC || mc.top == AUTOMATIC) { + right[3] = AUTOMATIC; + } else { + right[3] = mc.top - mc.desiredHeight; + } + } + + /** + * Resolves the positions for the specified side of the column + * into real numbers once the top of the column is known. + * + * @param side either Rectangle.LEFT_BORDER + * or Rectangle.RIGHT_BORDER + * @return the array of floats for the side + */ + internal float[] ResolvePositions(int side) { + if (side == Rectangle.LEFT_BORDER) { + return ResolvePositions(left); + } else { + return ResolvePositions(right); + } + } + + internal float[] ResolvePositions(float[] positions) { + if (!IsSimple()) { + return positions; + } + if (mc.top == AUTOMATIC) { + // this is bad - must be programmer error + throw new Exception("resolvePositions called with top=AUTOMATIC (-1). " + + "Top position must be set befure lines can be resolved"); + } + positions[1] = mc.top; + positions[3] = mc.GetColumnBottom(); + return positions; + } + + /** + * Checks if column definition is a simple rectangle + * @return true if it is a simple column + */ + internal bool IsSimple() { + return (left.Length == 4 && right.Length == 4) && (left[0] == left[2] && right[0] == right[2]); + } + + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs b/iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs new file mode 100644 index 0000000..0058116 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs @@ -0,0 +1,81 @@ +using System; +using System.IO; + +namespace iTextSharp.text.pdf { + public class OutputStreamCounter : Stream { + protected Stream outc; + protected int counter = 0; + + public OutputStreamCounter(Stream _outc) { + outc = _outc; + } + + public int Counter { + get { + return counter; + } + } + + public void ResetCounter() { + counter = 0; + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override void Flush() { + outc.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) { + counter += count; + outc.Write(buffer, offset, count); + } + + public override void Close() { + outc.Close (); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs b/iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs new file mode 100644 index 0000000..a6295c9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using iTextSharp.text.pdf.crypto; +/* + * $Id: OutputStreamEncryption.cs,v 1.3 2007/04/29 13:57:07 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class OutputStreamEncryption : Stream { + protected Stream outc; + protected ARCFOUREncryption arcfour; + protected AESCipher cipher; + private byte[] buf = new byte[1]; + private const int AES_128 = 4; + private bool aes; + private bool finished; + + public OutputStreamEncryption(Stream outc, byte[] key, int off, int len, int revision) { + this.outc = outc; + aes = revision == AES_128; + if (aes) { + byte[] iv = IVGenerator.GetIV(); + byte[] nkey = new byte[len]; + System.Array.Copy(key, off, nkey, 0, len); + cipher = new AESCipher(true, nkey, iv); + Write(iv, 0, iv.Length); + } + else { + arcfour = new ARCFOUREncryption(); + arcfour.PrepareARCFOURKey(key, off, len); + } + } + + public OutputStreamEncryption(Stream outc, byte[] key, int revision) : this(outc, key, 0, key.Length, revision) { + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override void Flush() { + outc.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] b, int off, int len) { + if (aes) { + byte[] b2 = cipher.Update(b, off, len); + if (b2 == null || b2.Length == 0) + return; + outc.Write(b2, 0, b2.Length); + } + else { + byte[] b2 = new byte[Math.Min(len, 4192)]; + while (len > 0) { + int sz = Math.Min(len, b2.Length); + arcfour.EncryptARCFOUR(b, off, sz, b2, 0); + outc.Write(b2, 0, sz); + len -= sz; + off += sz; + } + } + } + + public override void Close() { + Finish(); + outc.Close(); + } + + public override void WriteByte(byte value) { + buf[0] = value; + Write(buf, 0, 1); + } + + public void Finish() { + if (!finished) { + finished = true; + if (aes) { + byte[] b = cipher.DoFinal(); + outc.Write(b, 0, b.Length); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs b/iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs new file mode 100644 index 0000000..f3c66f3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections; +/* + * $Id: PRAcroForm.cs,v 1.5 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * This class written by Mark Thompson, Copyright (C) 2002 by Mark Thompson. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * This class captures an AcroForm on input. Basically, it extends Dictionary + * by indexing the fields of an AcroForm + * @author Mark Thompson + */ + + public class PRAcroForm : PdfDictionary { + + /** + * This class holds the information for a single field + */ + public class FieldInformation { + internal String name; + internal PdfDictionary info; + internal PRIndirectReference refi; + + internal FieldInformation(String name, PdfDictionary info, PRIndirectReference refi) { + this.name = name; this.info = info; this.refi = refi; + } + public String Name { + get { + return name; + } + } + public PdfDictionary Info { + get { + return info; + } + } + public PRIndirectReference Ref { + get { + return refi; + } + } + } + + internal ArrayList fields; + internal ArrayList stack; + internal Hashtable fieldByName; + internal PdfReader reader; + + /** + * Constructor + * @param reader reader of the input file + */ + public PRAcroForm(PdfReader reader) { + this.reader = reader; + fields = new ArrayList(); + fieldByName = new Hashtable(); + stack = new ArrayList(); + } + /** + * Number of fields found + * @return size + */ + public new int Size { + get { + return fields.Count; + } + } + + public ArrayList Fields { + get { + return fields; + } + } + + public FieldInformation GetField(String name) { + return (FieldInformation)fieldByName[name]; + } + + /** + * Given the title (/T) of a reference, return the associated reference + * @param name a string containing the path + * @return a reference to the field, or null + */ + public PRIndirectReference GetRefByName(String name) { + FieldInformation fi = (FieldInformation)fieldByName[name]; + if (fi == null) return null; + return fi.Ref; + } + /** + * Read, and comprehend the acroform + * @param root the docment root + */ + public void ReadAcroForm(PdfDictionary root) { + if (root == null) + return; + hashMap = root.hashMap; + PushAttrib(root); + PdfArray fieldlist = (PdfArray)PdfReader.GetPdfObjectRelease(root.Get(PdfName.FIELDS)); + IterateFields(fieldlist, null, null); + } + + /** + * After reading, we index all of the fields. Recursive. + * @param fieldlist An array of fields + * @param fieldDict the last field dictionary we encountered (recursively) + * @param title the pathname of the field, up to this point or null + */ + protected void IterateFields(PdfArray fieldlist, PRIndirectReference fieldDict, String title) { + foreach (PRIndirectReference refi in fieldlist.ArrayList) { + PdfDictionary dict = (PdfDictionary) PdfReader.GetPdfObjectRelease(refi); + + // if we are not a field dictionary, pass our parent's values + PRIndirectReference myFieldDict = fieldDict; + String myTitle = title; + PdfString tField = (PdfString)dict.Get(PdfName.T); + bool isFieldDict = tField != null; + + if (isFieldDict) { + myFieldDict = refi; + if (title == null) myTitle = tField.ToString(); + else myTitle = title + '.' + tField.ToString(); + } + + PdfArray kids = (PdfArray)dict.Get(PdfName.KIDS); + if (kids != null) { + PushAttrib(dict); + IterateFields(kids, myFieldDict, myTitle); + stack.RemoveAt(stack.Count - 1); // pop + } + else { // leaf node + if (myFieldDict != null) { + PdfDictionary mergedDict = (PdfDictionary)stack[stack.Count - 1]; + if (isFieldDict) + mergedDict = MergeAttrib(mergedDict, dict); + + mergedDict.Put(PdfName.T, new PdfString(myTitle)); + FieldInformation fi = new FieldInformation(myTitle, mergedDict, myFieldDict); + fields.Add(fi); + fieldByName[myTitle] = fi; + } + } + } + } + /** + * merge field attributes from two dictionaries + * @param parent one dictionary + * @param child the other dictionary + * @return a merged dictionary + */ + protected PdfDictionary MergeAttrib(PdfDictionary parent, PdfDictionary child) { + PdfDictionary targ = new PdfDictionary(); + if (parent != null) targ.Merge(parent); + + foreach (PdfName key in child.Keys) { + if (key.Equals(PdfName.DR) || key.Equals(PdfName.DA) || + key.Equals(PdfName.Q) || key.Equals(PdfName.FF) || + key.Equals(PdfName.DV) || key.Equals(PdfName.V) + || key.Equals(PdfName.FT) + || key.Equals(PdfName.F)) { + targ.Put(key,child.Get(key)); + } + } + return targ; + } + /** + * stack a level of dictionary. Merge in a dictionary from this level + */ + protected void PushAttrib(PdfDictionary dict) { + PdfDictionary dic = null; + if (stack.Count != 0) { + dic = (PdfDictionary)stack[stack.Count - 1]; + } + dic = MergeAttrib(dic, dict); + stack.Add(dic); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs b/iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs new file mode 100644 index 0000000..3800c9e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs @@ -0,0 +1,107 @@ +using System; +using System.Text; +using System.IO; + +/* + * $Id: PRIndirectReference.cs,v 1.3 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class PRIndirectReference : PdfIndirectReference { + + protected PdfReader reader; + // membervariables + + // constructors + + /** + * Constructs a PdfIndirectReference. + * + * @param reader a PdfReader + * @param number the object number. + * @param generation the generation number. + */ + + internal PRIndirectReference(PdfReader reader, int number, int generation) { + type = INDIRECT; + this.number = number; + this.generation = generation; + this.reader = reader; + } + + /** + * Constructs a PdfIndirectReference. + * + * @param reader a PdfReader + * @param number the object number. + */ + + internal PRIndirectReference(PdfReader reader, int number) : this(reader, number, 0) {} + + // methods + + public override void ToPdf(PdfWriter writer, Stream os) { + int n = writer.GetNewObjectNumber(reader, number, generation); + byte[] b = PdfEncodings.ConvertToBytes(new StringBuilder().Append(n).Append(" 0 R").ToString(), null); + os.Write(b, 0, b.Length); + } + + public PdfReader Reader { + get { + return reader; + } + } + + public void SetNumber(int number, int generation) { + this.number = number; + this.generation = generation; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PRStream.cs b/iTechSharp/iTextSharp/text/pdf/PRStream.cs new file mode 100644 index 0000000..d381d03 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRStream.cs @@ -0,0 +1,205 @@ +using System; +using System.IO; + +using System.util.zlib; + +/* + * $Id: PRStream.cs,v 1.6 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +public class PRStream : PdfStream { + + protected PdfReader reader; + protected int offset; + protected int length; + + //added by ujihara for decryption + protected int objNum = 0; + protected int objGen = 0; + + public PRStream(PRStream stream, PdfDictionary newDic) { + reader = stream.reader; + offset = stream.offset; + length = stream.Length; + compressed = stream.compressed; + streamBytes = stream.streamBytes; + bytes = stream.bytes; + objNum = stream.objNum; + objGen = stream.objGen; + if (newDic != null) + Merge(newDic); + else + Merge(stream); + } + + public PRStream(PRStream stream, PdfDictionary newDic, PdfReader reader) : this(stream, newDic) { + this.reader = reader; + } + + public PRStream(PdfReader reader, int offset) { + this.reader = reader; + this.offset = offset; + } + + public PRStream(PdfReader reader, byte[] conts) { + this.reader = reader; + this.offset = -1; + if (Document.Compress) { + MemoryStream stream = new MemoryStream(); + ZDeflaterOutputStream zip = new ZDeflaterOutputStream(stream); + zip.Write(conts, 0, conts.Length); + zip.Close(); + bytes = stream.ToArray(); + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + else + bytes = conts; + Length = bytes.Length; + } + + /** + * Sets the data associated with the stream, either compressed or + * uncompressed. Note that the data will never be compressed if + * Document.compress is set to false. + * + * @param data raw data, decrypted and uncompressed. + * @param compress true if you want the stream to be compresssed. + * @since iText 2.1.1 + */ + public void SetData(byte[] data, bool compress) { + Remove(PdfName.FILTER); + this.offset = -1; + if (Document.Compress && compress) { + MemoryStream stream = new MemoryStream(); + ZDeflaterOutputStream zip = new ZDeflaterOutputStream(stream); + zip.Write(data, 0, data.Length); + zip.Close(); + bytes = stream.ToArray(); + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + else + bytes = data; + Length = bytes.Length; + } + + /**Sets the data associated with the stream + * @param data raw data, decrypted and uncompressed. + */ + public void SetData(byte[] data) { + SetData(data, true); + } + + public new int Length { + set { + length = value; + Put(PdfName.LENGTH, new PdfNumber(length)); + } + get { + return length; + } + } + + public int Offset { + get { + return offset; + } + } + + public PdfReader Reader { + get { + return reader; + } + } + + public new byte[] GetBytes() { + return bytes; + } + + public int ObjNum { + get { + return objNum; + } + set { + objNum = value; + } + } + + public int ObjGen { + get { + return objGen; + } + set { + objGen = value; + } + } + + public override void ToPdf(PdfWriter writer, Stream os) { + byte[] b = PdfReader.GetStreamBytesRaw(this); + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + PdfObject objLen = Get(PdfName.LENGTH); + int nn = b.Length; + if (crypto != null) + nn = crypto.CalculateStreamSize(nn); + Put(PdfName.LENGTH, new PdfNumber(nn)); + SuperToPdf(writer, os); + Put(PdfName.LENGTH, objLen); + os.Write(STARTSTREAM, 0, STARTSTREAM.Length); + if (length > 0) { + if (crypto != null) + b = crypto.EncryptByteArray(b); + os.Write(b, 0, b.Length); + } + os.Write(ENDSTREAM, 0, ENDSTREAM.Length); + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs b/iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs new file mode 100644 index 0000000..d8c7235 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs @@ -0,0 +1,565 @@ +using System; +using System.IO; +using System.Text; + +/* + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PRTokeniser { + + public const int TK_NUMBER = 1; + public const int TK_STRING = 2; + public const int TK_NAME = 3; + public const int TK_COMMENT = 4; + public const int TK_START_ARRAY = 5; + public const int TK_END_ARRAY = 6; + public const int TK_START_DIC = 7; + public const int TK_END_DIC = 8; + public const int TK_REF = 9; + public const int TK_OTHER = 10; + + internal const string EMPTY = ""; + + + protected RandomAccessFileOrArray file; + protected int type; + protected string stringValue; + protected int reference; + protected int generation; + protected bool hexString; + + public PRTokeniser(string filename) { + file = new RandomAccessFileOrArray(filename); + } + + public PRTokeniser(byte[] pdfIn) { + file = new RandomAccessFileOrArray(pdfIn); + } + + public PRTokeniser(RandomAccessFileOrArray file) { + this.file = file; + } + + public void Seek(int pos) { + file.Seek(pos); + } + + public int FilePointer { + get { + return file.FilePointer; + } + } + + public void Close() { + file.Close(); + } + + public int Length { + get { + return file.Length; + } + } + + public int Read() { + return file.Read(); + } + + public RandomAccessFileOrArray SafeFile { + get { + return new RandomAccessFileOrArray(file); + } + } + + public RandomAccessFileOrArray File { + get { + return file; + } + } + + public string ReadString(int size) { + StringBuilder buf = new StringBuilder(); + int ch; + while ((size--) > 0) { + ch = file.Read(); + if (ch == -1) + break; + buf.Append((char)ch); + } + return buf.ToString(); + } + + public static bool IsWhitespace(int ch) { + return (ch == 0 || ch == 9 || ch == 10 || ch == 12 || ch == 13 || ch == 32); + } + + public static bool IsDelimiter(int ch) { + return (ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '/' || ch == '%'); + } + + public int TokenType { + get { + return type; + } + } + + public string StringValue { + get { + return stringValue; + } + } + + public int Reference { + get { + return reference; + } + } + + public int Generation { + get { + return generation; + } + } + + public void BackOnePosition(int ch) { + if (ch != -1) + file.PushBack((byte)ch); + } + + public void ThrowError(string error) { + throw new IOException(error + " at file pointer " + file.FilePointer); + } + + public char CheckPdfHeader() { + file.StartOffset = 0; + String str = ReadString(1024); + int idx = str.IndexOf("%PDF-"); + if (idx < 0) + throw new IOException("PDF header signature not found."); + file.StartOffset = idx; + return str[idx + 7]; + } + + public void CheckFdfHeader() { + file.StartOffset = 0; + String str = ReadString(1024); + int idx = str.IndexOf("%FDF-1.2"); + if (idx < 0) + throw new IOException("FDF header signature not found."); + file.StartOffset = idx; + } + + public int Startxref { + get { + int size = Math.Min(1024, file.Length); + int pos = file.Length - size; + file.Seek(pos); + string str = ReadString(1024); + int idx = str.LastIndexOf("startxref"); + if (idx < 0) + throw new IOException("PDF startxref not found."); + return pos + idx; + } + } + + public static int GetHex(int v) { + if (v >= '0' && v <= '9') + return v - '0'; + if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + return -1; + } + + public void NextValidToken() { + int level = 0; + string n1 = null; + string n2 = null; + int ptr = 0; + while (NextToken()) { + if (type == TK_COMMENT) + continue; + switch (level) { + case 0: { + if (type != TK_NUMBER) + return; + ptr = file.FilePointer; + n1 = stringValue; + ++level; + break; + } + case 1: { + if (type != TK_NUMBER) { + file.Seek(ptr); + type = TK_NUMBER; + stringValue = n1; + return; + } + n2 = stringValue; + ++level; + break; + } + default: { + if (type != TK_OTHER || !stringValue.Equals("R")) { + file.Seek(ptr); + type = TK_NUMBER; + stringValue = n1; + return; + } + type = TK_REF; + reference = int.Parse(n1); + generation = int.Parse(n2); + return; + } + } + } + ThrowError("Unexpected end of file"); + } + + public bool NextToken() { + StringBuilder outBuf = null; + stringValue = EMPTY; + int ch = 0; + do { + ch = file.Read(); + } while (ch != -1 && IsWhitespace(ch)); + if (ch == -1) + return false; + switch (ch) { + case '[': + type = TK_START_ARRAY; + break; + case ']': + type = TK_END_ARRAY; + break; + case '/': { + outBuf = new StringBuilder(); + type = TK_NAME; + while (true) { + ch = file.Read(); + if (ch == -1 || IsDelimiter(ch) || IsWhitespace(ch)) + break; + if (ch == '#') { + ch = (GetHex(file.Read()) << 4) + GetHex(file.Read()); + } + outBuf.Append((char)ch); + } + BackOnePosition(ch); + break; + } + case '>': + ch = file.Read(); + if (ch != '>') + ThrowError("'>' not expected"); + type = TK_END_DIC; + break; + case '<': { + int v1 = file.Read(); + if (v1 == '<') { + type = TK_START_DIC; + break; + } + outBuf = new StringBuilder(); + type = TK_STRING; + hexString = true; + int v2 = 0; + while (true) { + while (IsWhitespace(v1)) + v1 = file.Read(); + if (v1 == '>') + break; + v1 = GetHex(v1); + if (v1 < 0) + break; + v2 = file.Read(); + while (IsWhitespace(v2)) + v2 = file.Read(); + if (v2 == '>') { + ch = v1 << 4; + outBuf.Append((char)ch); + break; + } + v2 = GetHex(v2); + if (v2 < 0) + break; + ch = (v1 << 4) + v2; + outBuf.Append((char)ch); + v1 = file.Read(); + } + if (v1 < 0 || v2 < 0) + ThrowError("Error reading string"); + break; + } + case '%': + type = TK_COMMENT; + do { + ch = file.Read(); + } while (ch != -1 && ch != '\r' && ch != '\n'); + break; + case '(': { + outBuf = new StringBuilder(); + type = TK_STRING; + hexString = false; + int nesting = 0; + while (true) { + ch = file.Read(); + if (ch == -1) + break; + if (ch == '(') { + ++nesting; + } + else if (ch == ')') { + --nesting; + } + else if (ch == '\\') { + bool lineBreak = false; + ch = file.Read(); + switch (ch) { + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case '(': + case ')': + case '\\': + break; + case '\r': + lineBreak = true; + ch = file.Read(); + if (ch != '\n') + BackOnePosition(ch); + break; + case '\n': + lineBreak = true; + break; + default: { + if (ch < '0' || ch > '7') { + break; + } + int octal = ch - '0'; + ch = file.Read(); + if (ch < '0' || ch > '7') { + BackOnePosition(ch); + ch = octal; + break; + } + octal = (octal << 3) + ch - '0'; + ch = file.Read(); + if (ch < '0' || ch > '7') { + BackOnePosition(ch); + ch = octal; + break; + } + octal = (octal << 3) + ch - '0'; + ch = octal & 0xff; + break; + } + } + if (lineBreak) + continue; + if (ch < 0) + break; + } + else if (ch == '\r') { + ch = file.Read(); + if (ch < 0) + break; + if (ch != '\n') { + BackOnePosition(ch); + ch = '\n'; + } + } + if (nesting == -1) + break; + outBuf.Append((char)ch); + } + if (ch == -1) + ThrowError("Error reading string"); + break; + } + default: { + outBuf = new StringBuilder(); + if (ch == '-' || ch == '+' || ch == '.' || (ch >= '0' && ch <= '9')) { + type = TK_NUMBER; + do { + outBuf.Append((char)ch); + ch = file.Read(); + } while (ch != -1 && ((ch >= '0' && ch <= '9') || ch == '.')); + } + else { + type = TK_OTHER; + do { + outBuf.Append((char)ch); + ch = file.Read(); + } while (ch != -1 && !IsDelimiter(ch) && !IsWhitespace(ch)); + } + BackOnePosition(ch); + break; + } + } + if (outBuf != null) + stringValue = outBuf.ToString(); + return true; + } + + public int IntValue { + get { + return int.Parse(stringValue); + } + } + + public bool ReadLineSegment(byte[] input) { + int c = -1; + bool eol = false; + int ptr = 0; + int len = input.Length; + // ssteward, pdftk-1.10, 040922: + // skip initial whitespace; added this because PdfReader.RebuildXref() + // assumes that line provided by readLineSegment does not have init. whitespace; + if ( ptr < len ) { + while ( IsWhitespace( (c = Read()) ) ); + } + while ( !eol && ptr < len ) { + switch (c) { + case -1: + case '\n': + eol = true; + break; + case '\r': + eol = true; + int cur = FilePointer; + if ((Read()) != '\n') { + Seek(cur); + } + break; + default: + input[ptr++] = (byte)c; + break; + } + + // break loop? do it before we Read() again + if ( eol || len <= ptr ) { + break; + } + else { + c = Read(); + } + } + if (ptr >= len) { + eol = false; + while (!eol) { + switch (c = Read()) { + case -1: + case '\n': + eol = true; + break; + case '\r': + eol = true; + int cur = FilePointer; + if ((Read()) != '\n') { + Seek(cur); + } + break; + } + } + } + + if ((c == -1) && (ptr == 0)) { + return false; + } + if (ptr + 2 <= len) { + input[ptr++] = (byte)' '; + input[ptr] = (byte)'X'; + } + return true; + } + + public static int[] CheckObjectStart(byte[] line) { + try { + PRTokeniser tk = new PRTokeniser(line); + int num = 0; + int gen = 0; + if (!tk.NextToken() || tk.TokenType != TK_NUMBER) + return null; + num = tk.IntValue; + if (!tk.NextToken() || tk.TokenType != TK_NUMBER) + return null; + gen = tk.IntValue; + if (!tk.NextToken()) + return null; + if (!tk.StringValue.Equals("obj")) + return null; + return new int[]{num, gen}; + } + catch { + } + return null; + } + + public bool IsHexString() { + return this.hexString; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PageResources.cs b/iTechSharp/iTextSharp/text/pdf/PageResources.cs new file mode 100644 index 0000000..81d44a8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PageResources.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections; + +/* + * $Id: PageResources.cs,v 1.6 2006/09/24 15:48:24 psoares33 Exp $ + * + * Copyright 2003-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PageResources { + + protected PdfDictionary fontDictionary = new PdfDictionary(); + protected PdfDictionary xObjectDictionary = new PdfDictionary(); + protected PdfDictionary colorDictionary = new PdfDictionary(); + protected PdfDictionary patternDictionary = new PdfDictionary(); + protected PdfDictionary shadingDictionary = new PdfDictionary(); + protected PdfDictionary extGStateDictionary = new PdfDictionary(); + protected PdfDictionary propertyDictionary = new PdfDictionary(); + protected Hashtable forbiddenNames; + protected PdfDictionary originalResources; + protected int[] namePtr = {0}; + protected Hashtable usedNames; + + internal PageResources() { + } + + internal void SetOriginalResources(PdfDictionary resources, int[] newNamePtr) { + if (newNamePtr != null) + namePtr = newNamePtr; + forbiddenNames = new Hashtable(); + usedNames = new Hashtable(); + if (resources == null) + return; + originalResources = new PdfDictionary(); + originalResources.Merge(resources); + foreach (PdfName key in resources.Keys) { + PdfObject sub = PdfReader.GetPdfObject(resources.Get(key)); + if (sub != null && sub.IsDictionary()) { + PdfDictionary dic = (PdfDictionary)sub; + foreach (PdfName name in dic.Keys) { + forbiddenNames[name] = null; + } + PdfDictionary dic2 = new PdfDictionary(); + dic2.Merge(dic); + originalResources.Put(key, dic2); + } + } + } + + internal PdfName TranslateName(PdfName name) { + PdfName translated = name; + if (forbiddenNames != null) { + translated = (PdfName)usedNames[name]; + if (translated == null) { + while (true) { + translated = new PdfName("Xi" + (namePtr[0]++)); + if (!forbiddenNames.ContainsKey(translated)) + break; + } + usedNames[name] = translated; + } + } + return translated; + } + + internal PdfName AddFont(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + fontDictionary.Put(name, reference); + return name; + } + + internal PdfName AddXObject(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + xObjectDictionary.Put(name, reference); + return name; + } + + internal PdfName AddColor(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + colorDictionary.Put(name, reference); + return name; + } + + internal void AddDefaultColor(PdfName name, PdfObject obj) { + if (obj == null || obj.IsNull()) + colorDictionary.Remove(name); + else + colorDictionary.Put(name, obj); + } + + internal void AddDefaultColor(PdfDictionary dic) { + colorDictionary.Merge(dic); + } + + internal void AddDefaultColorDiff(PdfDictionary dic) { + colorDictionary.MergeDifferent(dic); + } + + internal PdfName AddShading(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + shadingDictionary.Put(name, reference); + return name; + } + + internal PdfName AddPattern(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + patternDictionary.Put(name, reference); + return name; + } + + internal PdfName AddExtGState(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + extGStateDictionary.Put(name, reference); + return name; + } + + internal PdfName AddProperty(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + propertyDictionary.Put(name, reference); + return name; + } + + internal PdfDictionary Resources { + get { + PdfResources resources = new PdfResources(); + if (originalResources != null) + resources.Merge(originalResources); + resources.Put(PdfName.PROCSET, new PdfLiteral("[/PDF /Text /ImageB /ImageC /ImageI]")); + resources.Add(PdfName.FONT, fontDictionary); + resources.Add(PdfName.XOBJECT, xObjectDictionary); + resources.Add(PdfName.COLORSPACE, colorDictionary); + resources.Add(PdfName.PATTERN, patternDictionary); + resources.Add(PdfName.SHADING, shadingDictionary); + resources.Add(PdfName.EXTGSTATE, extGStateDictionary); + resources.Add(PdfName.PROPERTIES, propertyDictionary); + return resources; + } + } + + internal bool HasResources() { + return (fontDictionary.Size > 0 + || xObjectDictionary.Size > 0 + || colorDictionary.Size > 0 + || patternDictionary.Size > 0 + || shadingDictionary.Size > 0 + || extGStateDictionary.Size > 0 + || propertyDictionary.Size > 0); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PatternColor.cs b/iTechSharp/iTextSharp/text/pdf/PatternColor.cs new file mode 100644 index 0000000..b2d693a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PatternColor.cs @@ -0,0 +1,82 @@ +using System; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Represents a pattern. Can be used in high-level constructs (Paragraph, Cell, etc.). + */ + public class PatternColor : ExtendedColor { + /** The actual pattern. + */ + PdfPatternPainter painter; + + /** Creates a color representing a pattern. + * @param painter the actual pattern + */ + public PatternColor(PdfPatternPainter painter) : base(TYPE_PATTERN, .5f, .5f, .5f) { + this.painter = painter; + } + + /** Gets the pattern. + * @return the pattern + */ + public PdfPatternPainter Painter { + get { + return this.painter; + } + } + + public override bool Equals(Object obj) { + return this == obj; + } + + public override int GetHashCode() { + return painter.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs b/iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs new file mode 100644 index 0000000..a82f2d3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs @@ -0,0 +1,490 @@ +using System; +using System.Text; +using System.Collections; +using System.util; + +/* + * $Id: PdfAcroForm.cs,v 1.9 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * Each PDF document can contain maximum 1 AcroForm. + */ + +public class PdfAcroForm : PdfDictionary { + + private PdfWriter writer; + + + /** This is a map containing FieldTemplates. */ + private Hashtable fieldTemplates = new Hashtable(); + + /** This is an array containing DocumentFields. */ + private PdfArray documentFields = new PdfArray(); + + /** This is an array containing the calculationorder of the fields. */ + private PdfArray calculationOrder = new PdfArray(); + + /** Contains the signature flags. */ + private int sigFlags = 0; + + /** Creates new PdfAcroForm */ + public PdfAcroForm(PdfWriter writer) : base() { + this.writer = writer; + } + + public bool NeedAppearances { + set { + Put(PdfName.NEEDAPPEARANCES, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + + /** + * Adds fieldTemplates. + */ + + public void AddFieldTemplates(Hashtable ft) { + foreach (object key in ft.Keys) { + fieldTemplates[key] = ft[key]; + } + } + + /** + * Adds documentFields. + */ + + public void AddDocumentField(PdfIndirectReference piref) { + documentFields.Add(piref); + } + + /** + * Closes the AcroForm. + */ + + public bool IsValid() { + if (documentFields.Size == 0) return false; + Put(PdfName.FIELDS, documentFields); + if (sigFlags != 0) + Put(PdfName.SIGFLAGS, new PdfNumber(sigFlags)); + if (calculationOrder.Size > 0) + Put(PdfName.CO, calculationOrder); + if (fieldTemplates.Count == 0) return true; + PdfDictionary dic = new PdfDictionary(); + foreach (PdfTemplate template in fieldTemplates.Keys) { + PdfFormField.MergeResources(dic, (PdfDictionary)template.Resources); + } + Put(PdfName.DR, dic); + Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + PdfDictionary fonts = (PdfDictionary)dic.Get(PdfName.FONT); + if (fonts != null) { + writer.EliminateFontSubset(fonts); + } + return true; + } + + /** + * Adds an object to the calculationOrder. + */ + + public void AddCalculationOrder(PdfFormField formField) { + calculationOrder.Add(formField.IndirectReference); + } + + /** + * Sets the signature flags. + */ + + public int SigFlags { + set { + sigFlags |= value; + } + } + + /** + * Adds a formfield to the AcroForm. + */ + + public void AddFormField(PdfFormField formField) { + writer.AddAnnotation(formField); + } + + public PdfFormField AddHtmlPostButton(string name, string caption, string value, string url, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAction action = PdfAction.CreateSubmitForm(url, null, PdfAction.SUBMIT_HTML_FORMAT); + PdfFormField button = new PdfFormField(writer, llx, lly, urx, ury, action); + SetButtonParams(button, PdfFormField.FF_PUSHBUTTON, name, value); + DrawButton(button, caption, font, fontSize, llx, lly, urx, ury); + AddFormField(button); + return button; + } + + public PdfFormField AddResetButton(string name, string caption, string value, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAction action = PdfAction.CreateResetForm(null, 0); + PdfFormField button = new PdfFormField(writer, llx, lly, urx, ury, action); + SetButtonParams(button, PdfFormField.FF_PUSHBUTTON, name, value); + DrawButton(button, caption, font, fontSize, llx, lly, urx, ury); + AddFormField(button); + return button; + } + + public PdfFormField AddMap(string name, string value, string url, PdfContentByte appearance, float llx, float lly, float urx, float ury) { + PdfAction action = PdfAction.CreateSubmitForm(url, null, PdfAction.SUBMIT_HTML_FORMAT | PdfAction.SUBMIT_COORDINATES); + PdfFormField button = new PdfFormField(writer, llx, lly, urx, ury, action); + SetButtonParams(button, PdfFormField.FF_PUSHBUTTON, name, null); + PdfAppearance pa = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + pa.Add(appearance); + button.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, pa); + AddFormField(button); + return button; + } + + public void SetButtonParams(PdfFormField button, int characteristics, string name, string value) { + button.Button = characteristics; + button.Flags = PdfAnnotation.FLAGS_PRINT; + button.SetPage(); + button.FieldName = name; + if (value != null) button.ValueAsString = value; + } + + public void DrawButton(PdfFormField button, string caption, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAppearance pa = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + pa.DrawButton(0f, 0f, urx - llx, ury - lly, caption, font, fontSize); + button.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, pa); + } + + public PdfFormField AddHiddenField(string name, string value) { + PdfFormField hidden = PdfFormField.CreateEmpty(writer); + hidden.FieldName = name; + hidden.ValueAsName = value; + AddFormField(hidden); + return hidden; + } + + public PdfFormField AddSingleLineTextField(string name, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateTextField(writer, PdfFormField.SINGLELINE, PdfFormField.PLAINTEXT, 0); + SetTextFieldParams(field, text, name, llx, lly, urx, ury); + DrawSingleLineOfText(field, text, font, fontSize, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public PdfFormField AddMultiLineTextField(string name, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateTextField(writer, PdfFormField.MULTILINE, PdfFormField.PLAINTEXT, 0); + SetTextFieldParams(field, text, name, llx, lly, urx, ury); + DrawMultiLineOfText(field, text, font, fontSize, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public PdfFormField AddSingleLinePasswordField(string name, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateTextField(writer, PdfFormField.SINGLELINE, PdfFormField.PASSWORD, 0); + SetTextFieldParams(field, text, name, llx, lly, urx, ury); + DrawSingleLineOfText(field, text, font, fontSize, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public void SetTextFieldParams(PdfFormField field, string text, string name, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_INVERT); + field.ValueAsString = text; + field.DefaultValueAsString = text; + field.FieldName = name; + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + } + + public void DrawSingleLineOfText(PdfFormField field, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAppearance tp = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + PdfAppearance tp2 = (PdfAppearance)tp.Duplicate; + tp2.SetFontAndSize(font, fontSize); + tp2.ResetRGBColorFill(); + field.DefaultAppearanceString = tp2; + tp.DrawTextField(0f, 0f, urx - llx, ury - lly); + tp.BeginVariableText(); + tp.SaveState(); + tp.Rectangle(3f, 3f, urx - llx - 6f, ury - lly - 6f); + tp.Clip(); + tp.NewPath(); + tp.BeginText(); + tp.SetFontAndSize(font, fontSize); + tp.ResetRGBColorFill(); + tp.SetTextMatrix(4, (ury - lly) / 2 - (fontSize * 0.3f)); + tp.ShowText(text); + tp.EndText(); + tp.RestoreState(); + tp.EndVariableText(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + } + + public void DrawMultiLineOfText(PdfFormField field, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAppearance tp = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + PdfAppearance tp2 = (PdfAppearance)tp.Duplicate; + tp2.SetFontAndSize(font, fontSize); + tp2.ResetRGBColorFill(); + field.DefaultAppearanceString = tp2; + tp.DrawTextField(0f, 0f, urx - llx, ury - lly); + tp.BeginVariableText(); + tp.SaveState(); + tp.Rectangle(3f, 3f, urx - llx - 6f, ury - lly - 6f); + tp.Clip(); + tp.NewPath(); + tp.BeginText(); + tp.SetFontAndSize(font, fontSize); + tp.ResetRGBColorFill(); + tp.SetTextMatrix(4, 5); + System.util.StringTokenizer tokenizer = new System.util.StringTokenizer(text, "\n"); + float yPos = ury - lly; + while (tokenizer.HasMoreTokens()) { + yPos -= fontSize * 1.2f; + tp.ShowTextAligned(PdfContentByte.ALIGN_LEFT, tokenizer.NextToken(), 3, yPos, 0); + } + tp.EndText(); + tp.RestoreState(); + tp.EndVariableText(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + } + + public PdfFormField AddCheckBox(string name, string value, bool status, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateCheckBox(writer); + SetCheckBoxParams(field, name, value, status, llx, lly, urx, ury); + DrawCheckBoxAppearences(field, value, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public void SetCheckBoxParams(PdfFormField field, string name, string value, bool status, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_TOGGLE); + field.FieldName = name; + if (status) { + field.ValueAsName = value; + field.AppearanceState = value; + } + else { + field.ValueAsName = "Off"; + field.AppearanceState = "Off"; + } + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + field.BorderStyle = new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID); + } + + public void DrawCheckBoxAppearences(PdfFormField field, string value, float llx, float lly, float urx, float ury) { + BaseFont font = BaseFont.CreateFont(BaseFont.ZAPFDINGBATS, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED); + float size = (ury - lly); + PdfAppearance tpOn = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + PdfAppearance tp2 = (PdfAppearance)tpOn.Duplicate; + tp2.SetFontAndSize(font, size); + tp2.ResetRGBColorFill(); + field.DefaultAppearanceString = tp2; + tpOn.DrawTextField(0f, 0f, urx - llx, ury - lly); + tpOn.SaveState(); + tpOn.ResetRGBColorFill(); + tpOn.BeginText(); + tpOn.SetFontAndSize(font, size); + tpOn.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "4", (urx - llx) / 2, (ury - lly) / 2 - (size * 0.3f), 0); + tpOn.EndText(); + tpOn.RestoreState(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, value, tpOn); + PdfAppearance tpOff = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tpOff.DrawTextField(0f, 0f, urx - llx, ury - lly); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", tpOff); + } + + public PdfFormField GetRadioGroup(string name, string defaultValue, bool noToggleToOff) { + PdfFormField radio = PdfFormField.CreateRadioButton(writer, noToggleToOff); + radio.FieldName = name; + radio.ValueAsName = defaultValue; + return radio; + } + + public void AddRadioGroup(PdfFormField radiogroup) { + AddFormField(radiogroup); + } + + public PdfFormField AddRadioButton(PdfFormField radiogroup, string value, float llx, float lly, float urx, float ury) { + PdfFormField radio = PdfFormField.CreateEmpty(writer); + radio.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_TOGGLE); + string name = ((PdfName)radiogroup.Get(PdfName.V)).ToString().Substring(1); + if (name.Equals(value)) { + radio.AppearanceState = value; + } + else { + radio.AppearanceState = "Off"; + } + DrawRadioAppearences(radio, value, llx, lly, urx, ury); + radiogroup.AddKid(radio); + return radio; + } + + public void DrawRadioAppearences(PdfFormField field, string value, float llx, float lly, float urx, float ury) { + PdfAppearance tpOn = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tpOn.DrawRadioField(0f, 0f, urx - llx, ury - lly, true); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, value, tpOn); + PdfAppearance tpOff = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tpOff.DrawRadioField(0f, 0f, urx - llx, ury - lly, false); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", tpOff); + } + + public PdfFormField AddSelectList(string name, string[] options, string defaultValue, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateList(writer, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + StringBuilder text = new StringBuilder(); + for (int i = 0; i < options.Length; i++) { + text.Append(options[i]).Append('\n'); + } + DrawMultiLineOfText(choice, text.ToString(), font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public PdfFormField AddSelectList(string name, string[,] options, string defaultValue, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateList(writer, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + StringBuilder text = new StringBuilder(); + for (int i = 0; i < options.GetLength(0); i++) { + text.Append(options[i, 1]).Append('\n'); + } + DrawMultiLineOfText(choice, text.ToString(), font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public PdfFormField AddComboBox(string name, string[] options, string defaultValue, bool editable, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateCombo(writer, editable, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + if (defaultValue == null) { + defaultValue = options[0]; + } + DrawSingleLineOfText(choice, defaultValue, font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public PdfFormField AddComboBox(string name, string[,] options, string defaultValue, bool editable, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateCombo(writer, editable, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + string value = null; + for (int i = 0; i < options.GetLength(0); i++) { + if (options[i, 0].Equals(defaultValue)) { + value = options[i, 1]; + break; + } + } + if (value == null) { + value = options[0, 1]; + } + DrawSingleLineOfText(choice, value, font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public void SetChoiceParams(PdfFormField field, string name, string defaultValue, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_INVERT); + if (defaultValue != null) { + field.ValueAsString = defaultValue; + field.DefaultValueAsString = defaultValue; + } + field.FieldName = name; + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + field.BorderStyle = new PdfBorderDictionary(2, PdfBorderDictionary.STYLE_SOLID); + } + + public PdfFormField AddSignature(String name, float llx, float lly, float urx, float ury) { + PdfFormField signature = PdfFormField.CreateSignature(writer); + SetSignatureParams(signature, name, llx, lly, urx, ury); + DrawSignatureAppearences(signature, llx, lly, urx, ury); + AddFormField(signature); + return signature; + } + + /** + * @param field + * @param name + * @param llx + * @param lly + * @param urx + * @param ury + */ + public void SetSignatureParams(PdfFormField field, String name, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_INVERT); + field.FieldName = name; + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + field.MKBorderColor = Color.BLACK; + field.MKBackgroundColor = Color.WHITE; + } + + /** + * @param field + * @param llx + * @param lly + * @param urx + * @param ury + */ + public void DrawSignatureAppearences(PdfFormField field, float llx, float lly, float urx, float ury) { + PdfAppearance tp = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tp.SetGrayFill(1.0f); + tp.Rectangle(0, 0, urx - llx, ury - lly); + tp.Fill(); + tp.SetGrayStroke(0); + tp.SetLineWidth(1); + tp.Rectangle(0.5f, 0.5f, urx - llx - 0.5f, ury - lly - 0.5f); + tp.ClosePathStroke(); + tp.SaveState(); + tp.Rectangle(1, 1, urx - llx - 2, ury - lly - 2); + tp.Clip(); + tp.NewPath(); + tp.RestoreState(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAction.cs b/iTechSharp/iTextSharp/text/pdf/PdfAction.cs new file mode 100644 index 0000000..cc606de --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAction.cs @@ -0,0 +1,521 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.pdf.collection; + +/* + * $Id: PdfAction.cs,v 1.6 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** + * A PdfAction defines an action that can be triggered from a PDF file. + * + * @see PdfDictionary + */ + + public class PdfAction : PdfDictionary { + + /** A named action to go to the first page. + */ + public const int FIRSTPAGE = 1; + /** A named action to go to the previous page. + */ + public const int PREVPAGE = 2; + /** A named action to go to the next page. + */ + public const int NEXTPAGE = 3; + /** A named action to go to the last page. + */ + public const int LASTPAGE = 4; + + /** A named action to open a print dialog. + */ + public const int PRINTDIALOG = 5; + + // constructors + public const int SUBMIT_EXCLUDE = 1; + public const int SUBMIT_INCLUDE_NO_VALUE_FIELDS = 2; + public const int SUBMIT_HTML_FORMAT = 4; + public const int SUBMIT_HTML_GET = 8; + public const int SUBMIT_COORDINATES = 16; + /** a possible submitvalue */ + public const int SUBMIT_XFDF = 32; + /** a possible submitvalue */ + public const int SUBMIT_INCLUDE_APPEND_SAVES = 64; + /** a possible submitvalue */ + public const int SUBMIT_INCLUDE_ANNOTATIONS = 128; + /** a possible submitvalue */ + public const int SUBMIT_PDF = 256; + /** a possible submitvalue */ + public const int SUBMIT_CANONICAL_FORMAT = 512; + /** a possible submitvalue */ + public const int SUBMIT_EXCL_NON_USER_ANNOTS = 1024; + /** a possible submitvalue */ + public const int SUBMIT_EXCL_F_KEY = 2048; + /** a possible submitvalue */ + public const int SUBMIT_EMBED_FORM = 8196; + /** a possible submitvalue */ + public const int RESET_EXCLUDE = 1; + + /** Create an empty action. + */ + public PdfAction() { + } + + /** + * Constructs a new PdfAction of Subtype URI. + * + * @param url the Url to go to + */ + + public PdfAction(Uri url) : this(url.AbsoluteUri) {} + + public PdfAction(Uri url, bool isMap) : this(url.AbsoluteUri, isMap) {} + + /** + * Constructs a new PdfAction of Subtype URI. + * + * @param url the url to go to + */ + + public PdfAction(string url) : this(url, false) {} + + public PdfAction(string url, bool isMap) { + Put(PdfName.S, PdfName.URI); + Put(PdfName.URI, new PdfString(url)); + if (isMap) + Put(PdfName.ISMAP, PdfBoolean.PDFTRUE); + } + + /** + * Constructs a new PdfAction of Subtype GoTo. + * @param destination the destination to go to + */ + + internal PdfAction(PdfIndirectReference destination) { + Put(PdfName.S, PdfName.GOTO); + Put(PdfName.D, destination); + } + + /** + * Constructs a new PdfAction of Subtype GoToR. + * @param filename the file name to go to + * @param name the named destination to go to + */ + + public PdfAction(string filename, string name) { + Put(PdfName.S, PdfName.GOTOR); + Put(PdfName.F, new PdfString(filename)); + Put(PdfName.D, new PdfString(name)); + } + + /** + * Constructs a new PdfAction of Subtype GoToR. + * @param filename the file name to go to + * @param page the page destination to go to + */ + + public PdfAction(string filename, int page) { + Put(PdfName.S, PdfName.GOTOR); + Put(PdfName.F, new PdfString(filename)); + Put(PdfName.D, new PdfLiteral("[" + (page - 1) + " /FitH 10000]")); + } + + /** Implements name actions. The action can be FIRSTPAGE, LASTPAGE, + * NEXTPAGE and PREVPAGE. + * @param named the named action + */ + public PdfAction(int named) { + Put(PdfName.S, PdfName.NAMED); + switch (named) { + case FIRSTPAGE: + Put(PdfName.N, PdfName.FIRSTPAGE); + break; + case LASTPAGE: + Put(PdfName.N, PdfName.LASTPAGE); + break; + case NEXTPAGE: + Put(PdfName.N, PdfName.NEXTPAGE); + break; + case PREVPAGE: + Put(PdfName.N, PdfName.PREVPAGE); + break; + case PRINTDIALOG: + Put(PdfName.S, PdfName.JAVASCRIPT); + Put(PdfName.JS, new PdfString("this.print(true);\r")); + break; + default: + throw new ArgumentException("Invalid named action."); + } + } + + /** Launchs an application or a document. + * @param application the application to be launched or the document to be opened or printed. + * @param parameters (Windows-specific) A parameter string to be passed to the application. + * It can be null. + * @param operation (Windows-specific) the operation to perform: "open" - Open a document, + * "print" - Print a document. + * It can be null. + * @param defaultDir (Windows-specific) the default directory in standard DOS syntax. + * It can be null. + */ + public PdfAction(string application, string parameters, string operation, string defaultDir) { + Put(PdfName.S, PdfName.LAUNCH); + if (parameters == null && operation == null && defaultDir == null) + Put(PdfName.F, new PdfString(application)); + else { + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.F, new PdfString(application)); + if (parameters != null) + dic.Put(PdfName.P, new PdfString(parameters)); + if (operation != null) + dic.Put(PdfName.O, new PdfString(operation)); + if (defaultDir != null) + dic.Put(PdfName.D, new PdfString(defaultDir)); + Put(PdfName.WIN, dic); + } + } + + /** Launchs an application or a document. + * @param application the application to be launched or the document to be opened or printed. + * @param parameters (Windows-specific) A parameter string to be passed to the application. + * It can be null. + * @param operation (Windows-specific) the operation to perform: "open" - Open a document, + * "print" - Print a document. + * It can be null. + * @param defaultDir (Windows-specific) the default directory in standard DOS syntax. + * It can be null. + * @return a Launch action + */ + public static PdfAction CreateLaunch(String application, String parameters, String operation, String defaultDir) { + return new PdfAction(application, parameters, operation, defaultDir); + } + + /**Creates a Rendition action + * @param file + * @param fs + * @param mimeType + * @param ref + * @return a Media Clip action + * @throws IOException + */ + public static PdfAction Rendition(String file, PdfFileSpecification fs, String mimeType, PdfIndirectReference refi) { + PdfAction js = new PdfAction(); + js.Put(PdfName.S, PdfName.RENDITION); + js.Put(PdfName.R, new PdfRendition(file, fs, mimeType)); + js.Put(new PdfName("OP"), new PdfNumber(0)); + js.Put(new PdfName("AN"), refi); + return js; + } + + /** Creates a JavaScript action. If the JavaScript is smaller than + * 50 characters it will be placed as a string, otherwise it will + * be placed as a compressed stream. + * @param code the JavaScript code + * @param writer the writer for this action + * @param unicode select JavaScript unicode. Note that the internal + * Acrobat JavaScript engine does not support unicode, + * so this may or may not work for you + * @return the JavaScript action + */ + public static PdfAction JavaScript(string code, PdfWriter writer, bool unicode) { + PdfAction js = new PdfAction(); + js.Put(PdfName.S, PdfName.JAVASCRIPT); + if (unicode && code.Length < 50) { + js.Put(PdfName.JS, new PdfString(code, PdfObject.TEXT_UNICODE)); + } + else if (!unicode && code.Length < 100) { + js.Put(PdfName.JS, new PdfString(code)); + } + else { + byte[] b = PdfEncodings.ConvertToBytes(code, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING); + PdfStream stream = new PdfStream(b); + stream.FlateCompress(); + js.Put(PdfName.JS, writer.AddToBody(stream).IndirectReference); + } + return js; + } + + /** Creates a JavaScript action. If the JavaScript is smaller than + * 50 characters it will be place as a string, otherwise it will + * be placed as a compressed stream. + * @param code the JavaScript code + * @param writer the writer for this action + * @return the JavaScript action + */ + public static PdfAction JavaScript(string code, PdfWriter writer) { + return JavaScript(code, writer, false); + } + + internal static PdfAction CreateHide(PdfObject obj, bool hide) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.HIDE); + action.Put(PdfName.T, obj); + if (!hide) + action.Put(PdfName.H, PdfBoolean.PDFFALSE); + return action; + } + + public static PdfAction CreateHide(PdfAnnotation annot, bool hide) { + return CreateHide(annot.IndirectReference, hide); + } + + public static PdfAction CreateHide(string name, bool hide) { + return CreateHide(new PdfString(name), hide); + } + + internal static PdfArray BuildArray(Object[] names) { + PdfArray array = new PdfArray(); + for (int k = 0; k < names.Length; ++k) { + Object obj = names[k]; + if (obj is string) + array.Add(new PdfString((string)obj)); + else if (obj is PdfAnnotation) + array.Add(((PdfAnnotation)obj).IndirectReference); + else + throw new ArgumentException("The array must contain string or PdfAnnotation."); + } + return array; + } + + public static PdfAction CreateHide(Object[] names, bool hide) { + return CreateHide(BuildArray(names), hide); + } + + public static PdfAction CreateSubmitForm(string file, Object[] names, int flags) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.SUBMITFORM); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.F, new PdfString(file)); + dic.Put(PdfName.FS, PdfName.URL); + action.Put(PdfName.F, dic); + if (names != null) + action.Put(PdfName.FIELDS, BuildArray(names)); + action.Put(PdfName.FLAGS, new PdfNumber(flags)); + return action; + } + + public static PdfAction CreateResetForm(Object[] names, int flags) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.RESETFORM); + if (names != null) + action.Put(PdfName.FIELDS, BuildArray(names)); + action.Put(PdfName.FLAGS, new PdfNumber(flags)); + return action; + } + + public static PdfAction CreateImportData(string file) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.IMPORTDATA); + action.Put(PdfName.F, new PdfString(file)); + return action; + } + + /** Add a chained action. + * @param na the next action + */ + public void Next(PdfAction na) { + PdfObject nextAction = Get(PdfName.NEXT); + if (nextAction == null) + Put(PdfName.NEXT, na); + else if (nextAction.IsDictionary()) { + PdfArray array = new PdfArray(nextAction); + array.Add(na); + Put(PdfName.NEXT, array); + } + else { + ((PdfArray)nextAction).Add(na); + } + } + + /** Creates a GoTo action to an internal page. + * @param page the page to go. First page is 1 + * @param dest the destination for the page + * @param writer the writer for this action + * @return a GoTo action + */ + public static PdfAction GotoLocalPage(int page, PdfDestination dest, PdfWriter writer) { + PdfIndirectReference piref = writer.GetPageReference(page); + dest.AddPage(piref); + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.GOTO); + action.Put(PdfName.D, dest); + return action; + } + + /** + * Creates a GoTo action to a named destination. + * @param dest the named destination + * @param isName if true sets the destination as a name, if false sets it as a String + * @return a GoToR action + */ + public static PdfAction GotoLocalPage(String dest, bool isName) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.GOTO); + if (isName) + action.Put(PdfName.D, new PdfName(dest)); + else + action.Put(PdfName.D, new PdfString(dest, null)); + return action; + } + + /** + * Creates a GoToR action to a named destination. + * @param filename the file name to go to + * @param dest the destination name + * @param isName if true sets the destination as a name, if false sets it as a String + * @param newWindow open the document in a new window if true, if false the current document is replaced by the new document. + * @return a GoToR action + */ + public static PdfAction GotoRemotePage(String filename, String dest, bool isName, bool newWindow) { + PdfAction action = new PdfAction(); + action.Put(PdfName.F, new PdfString(filename)); + action.Put(PdfName.S, PdfName.GOTOR); + if (isName) + action.Put(PdfName.D, new PdfName(dest)); + else + action.Put(PdfName.D, new PdfString(dest, null)); + if (newWindow) + action.Put(PdfName.NEWWINDOW, PdfBoolean.PDFTRUE); + return action; + } + + /** + * Creates a GoToE action to an embedded file. + * @param filename the root document of the target (null if the target is in the same document) + * @param dest the named destination + * @param isName if true sets the destination as a name, if false sets it as a String + * @return a GoToE action + */ + public static PdfAction GotoEmbedded(String filename, PdfTargetDictionary target, String dest, bool isName, bool newWindow) { + if (isName) + return GotoEmbedded(filename, target, new PdfName(dest), newWindow); + else + return GotoEmbedded(filename, target, new PdfString(dest, null), newWindow); + } + + /** + * Creates a GoToE action to an embedded file. + * @param filename the root document of the target (null if the target is in the same document) + * @param target a path to the target document of this action + * @param dest the destination inside the target document, can be of type PdfDestination, PdfName, or PdfString + * @param newWindow if true, the destination document should be opened in a new window + * @return a GoToE action + */ + public static PdfAction GotoEmbedded(String filename, PdfTargetDictionary target, PdfObject dest, bool newWindow) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.GOTOE); + action.Put(PdfName.T, target); + action.Put(PdfName.D, dest); + action.Put(PdfName.NEWWINDOW, new PdfBoolean(newWindow)); + if (filename != null) { + action.Put(PdfName.F, new PdfString(filename)); + } + return action; + } + + /** + * A set-OCG-state action (PDF 1.5) sets the state of one or more optional content + * groups. + * @param state an array consisting of any number of sequences beginning with a PdfName + * or String (ON, OFF, or Toggle) followed by one or more optional content group dictionaries + * PdfLayer or a PdfIndirectReference to a PdfLayer.
+ * The array elements are processed from left to right; each name is applied + * to the subsequent groups until the next name is encountered: + *

    + *
  • ON sets the state of subsequent groups to ON
  • + *
  • OFF sets the state of subsequent groups to OFF
  • + *
  • Toggle reverses the state of subsequent groups
  • + *
+ * @param preserveRB if true, indicates that radio-button state relationships between optional + * content groups (as specified by the RBGroups entry in the current configuration + * dictionary) should be preserved when the states in the + * state array are applied. That is, if a group is set to ON (either by ON or Toggle) during + * processing of the state array, any other groups belong to the same radio-button + * group are turned OFF. If a group is set to OFF, there is no effect on other groups.
+ * If false, radio-button state relationships, if any, are ignored + * @return the action + */ + public static PdfAction SetOCGstate(ArrayList state, bool preserveRB) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.SETOCGSTATE); + PdfArray a = new PdfArray(); + for (int k = 0; k < state.Count; ++k) { + Object o = state[k]; + if (o == null) + continue; + if (o is PdfIndirectReference) + a.Add((PdfIndirectReference)o); + else if (o is PdfLayer) + a.Add(((PdfLayer)o).Ref); + else if (o is PdfName) + a.Add((PdfName)o); + else if (o is String) { + PdfName name = null; + String s = (String)o; + if (Util.EqualsIgnoreCase(s, "on")) + name = PdfName.ON; + else if (Util.EqualsIgnoreCase(s, "off")) + name = PdfName.OFF; + else if (Util.EqualsIgnoreCase(s, "toggle")) + name = PdfName.TOGGLE; + else + throw new ArgumentException("A string '" + s + " was passed in state. Only 'ON', 'OFF' and 'Toggle' are allowed."); + a.Add(name); + } + else + throw new ArgumentException("Invalid type was passed in state: " + o.GetType().ToString()); + } + action.Put(PdfName.STATE, a); + if (!preserveRB) + action.Put(PdfName.PRESERVERB, PdfBoolean.PDFFALSE); + return action; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs b/iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs new file mode 100644 index 0000000..05593f5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs @@ -0,0 +1,824 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +/* + * $Id: PdfAnnotation.cs,v 1.12 2008/05/24 18:41:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A PdfAnnotation is a note that is associated with a page. + * + * @see PdfDictionary + */ + public class PdfAnnotation : PdfDictionary { + + public static readonly PdfName HIGHLIGHT_NONE = PdfName.N; + public static readonly PdfName HIGHLIGHT_INVERT = PdfName.I; + public static readonly PdfName HIGHLIGHT_OUTLINE = PdfName.O; + public static readonly PdfName HIGHLIGHT_PUSH = PdfName.P; + public static readonly PdfName HIGHLIGHT_TOGGLE = PdfName.T; + public const int FLAGS_INVISIBLE = 1; + public const int FLAGS_HIDDEN = 2; + public const int FLAGS_PRINT = 4; + public const int FLAGS_NOZOOM = 8; + public const int FLAGS_NOROTATE = 16; + public const int FLAGS_NOVIEW = 32; + public const int FLAGS_READONLY = 64; + public const int FLAGS_LOCKED = 128; + public const int FLAGS_TOGGLENOVIEW = 256; + public static readonly PdfName APPEARANCE_NORMAL = PdfName.N; + public static readonly PdfName APPEARANCE_ROLLOVER = PdfName.R; + public static readonly PdfName APPEARANCE_DOWN = PdfName.D; + public static readonly PdfName AA_ENTER = PdfName.E; + public static readonly PdfName AA_EXIT = PdfName.X; + public static readonly PdfName AA_DOWN = PdfName.D; + public static readonly PdfName AA_UP = PdfName.U; + public static readonly PdfName AA_FOCUS = PdfName.FO; + public static readonly PdfName AA_BLUR = PdfName.BL; + public static readonly PdfName AA_JS_KEY = PdfName.K; + public static readonly PdfName AA_JS_FORMAT = PdfName.F; + public static readonly PdfName AA_JS_CHANGE = PdfName.V; + public static readonly PdfName AA_JS_OTHER_CHANGE = PdfName.C; + public const int MARKUP_HIGHLIGHT = 0; + public const int MARKUP_UNDERLINE = 1; + public const int MARKUP_STRIKEOUT = 2; + /** attributevalue */ + public const int MARKUP_SQUIGGLY = 3; + protected internal PdfWriter writer; + protected internal PdfIndirectReference reference; + protected internal Hashtable templates; + protected internal bool form = false; + protected internal bool annotation = true; + + /** Holds value of property used. */ + protected internal bool used = false; + + /** Holds value of property placeInPage. */ + private int placeInPage = -1; + + // constructors + public PdfAnnotation(PdfWriter writer, Rectangle rect) { + this.writer = writer; + if (rect != null) + Put(PdfName.RECT, new PdfRectangle(rect)); + } + + /** + * Constructs a new PdfAnnotation of subtype text. + */ + + public PdfAnnotation(PdfWriter writer, float llx, float lly, float urx, float ury, PdfString title, PdfString content) { + this.writer = writer; + Put(PdfName.SUBTYPE, PdfName.TEXT); + Put(PdfName.T, title); + Put(PdfName.RECT, new PdfRectangle(llx, lly, urx, ury)); + Put(PdfName.CONTENTS, content); + } + + /** + * Constructs a new PdfAnnotation of subtype link (Action). + */ + + public PdfAnnotation(PdfWriter writer, float llx, float lly, float urx, float ury, PdfAction action) { + this.writer = writer; + Put(PdfName.SUBTYPE, PdfName.LINK); + Put(PdfName.RECT, new PdfRectangle(llx, lly, urx, ury)); + Put(PdfName.A, action); + Put(PdfName.BORDER, new PdfBorderArray(0, 0, 0)); + Put(PdfName.C, new PdfColor(0x00, 0x00, 0xFF)); + } + + /** + * Creates a screen PdfAnnotation + * @param writer + * @param rect + * @param clipTitle + * @param fs + * @param mimeType + * @param playOnDisplay + * @return a screen PdfAnnotation + * @throws IOException + */ + public static PdfAnnotation CreateScreen(PdfWriter writer, Rectangle rect, String clipTitle, PdfFileSpecification fs, + String mimeType, bool playOnDisplay) { + PdfAnnotation ann = new PdfAnnotation(writer, rect); + ann.Put(PdfName.SUBTYPE, PdfName.SCREEN); + ann.Put (PdfName.F, new PdfNumber(FLAGS_PRINT)); + ann.Put(PdfName.TYPE, PdfName.ANNOT); + ann.SetPage(); + PdfIndirectReference refi = ann.IndirectReference; + PdfAction action = PdfAction.Rendition(clipTitle,fs,mimeType, refi); + PdfIndirectReference actionRef = writer.AddToBody(action).IndirectReference; + // for play on display add trigger event + if (playOnDisplay) + { + PdfDictionary aa = new PdfDictionary(); + aa.Put(new PdfName("PV"), actionRef); + ann.Put(PdfName.AA, aa); + } + ann.Put(PdfName.A, actionRef); + return ann; + } + + public PdfIndirectReference IndirectReference { + get { + if (reference == null) { + reference = writer.PdfIndirectReference; + } + return reference; + } + } + + public static PdfAnnotation CreateText(PdfWriter writer, Rectangle rect, string title, string contents, bool open, string icon) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.TEXT); + if (title != null) + annot.Put(PdfName.T, new PdfString(title, PdfObject.TEXT_UNICODE)); + if (contents != null) + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + if (open) + annot.Put(PdfName.OPEN, PdfBoolean.PDFTRUE); + if (icon != null) { + annot.Put(PdfName.NAME, new PdfName(icon)); + } + return annot; + } + + protected static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.LINK); + if (!highlight.Equals(HIGHLIGHT_INVERT)) + annot.Put(PdfName.H, highlight); + return annot; + } + + public static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight, PdfAction action) { + PdfAnnotation annot = CreateLink(writer, rect, highlight); + annot.PutEx(PdfName.A, action); + return annot; + } + + public static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight, string namedDestination) { + PdfAnnotation annot = CreateLink(writer, rect, highlight); + annot.Put(PdfName.DEST, new PdfString(namedDestination)); + return annot; + } + + public static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight, int page, PdfDestination dest) { + PdfAnnotation annot = CreateLink(writer, rect, highlight); + PdfIndirectReference piref = writer.GetPageReference(page); + dest.AddPage(piref); + annot.Put(PdfName.DEST, dest); + return annot; + } + + public static PdfAnnotation CreateFreeText(PdfWriter writer, Rectangle rect, string contents, PdfContentByte defaultAppearance) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.FREETEXT); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + annot.DefaultAppearanceString = defaultAppearance; + return annot; + } + + public static PdfAnnotation CreateLine(PdfWriter writer, Rectangle rect, string contents, float x1, float y1, float x2, float y2) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.LINE); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + PdfArray array = new PdfArray(new PdfNumber(x1)); + array.Add(new PdfNumber(y1)); + array.Add(new PdfNumber(x2)); + array.Add(new PdfNumber(y2)); + annot.Put(PdfName.L, array); + return annot; + } + + public static PdfAnnotation CreateSquareCircle(PdfWriter writer, Rectangle rect, string contents, bool square) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + if (square) + annot.Put(PdfName.SUBTYPE, PdfName.SQUARE); + else + annot.Put(PdfName.SUBTYPE, PdfName.CIRCLE); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + return annot; + } + + public static PdfAnnotation CreateMarkup(PdfWriter writer, Rectangle rect, string contents, int type, float[] quadPoints) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + PdfName name = PdfName.HIGHLIGHT; + switch (type) { + case MARKUP_UNDERLINE: + name = PdfName.UNDERLINE; + break; + case MARKUP_STRIKEOUT: + name = PdfName.STRIKEOUT; + break; + case MARKUP_SQUIGGLY: + name = PdfName.SQUIGGLY; + break; + } + annot.Put(PdfName.SUBTYPE, name); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + PdfArray array = new PdfArray(); + for (int k = 0; k < quadPoints.Length; ++k) + array.Add(new PdfNumber(quadPoints[k])); + annot.Put(PdfName.QUADPOINTS, array); + return annot; + } + + public static PdfAnnotation CreateStamp(PdfWriter writer, Rectangle rect, string contents, string name) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.STAMP); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + annot.Put(PdfName.NAME, new PdfName(name)); + return annot; + } + + public static PdfAnnotation CreateInk(PdfWriter writer, Rectangle rect, string contents, float[][] inkList) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.INK); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + PdfArray outer = new PdfArray(); + for (int k = 0; k < inkList.Length; ++k) { + PdfArray inner = new PdfArray(); + float[] deep = inkList[k]; + for (int j = 0; j < deep.Length; ++j) + inner.Add(new PdfNumber(deep[j])); + outer.Add(inner); + } + annot.Put(PdfName.INKLIST, outer); + return annot; + } + + /** Creates a file attachment annotation. + * @param writer the PdfWriter + * @param rect the dimensions in the page of the annotation + * @param contents the file description + * @param fileStore an array with the file. If it's null + * the file will be read from the disk + * @param file the path to the file. It will only be used if + * fileStore is not null + * @param fileDisplay the actual file name stored in the pdf + * @throws IOException on error + * @return the annotation + */ + public static PdfAnnotation CreateFileAttachment(PdfWriter writer, Rectangle rect, String contents, byte[] fileStore, String file, String fileDisplay) { + return CreateFileAttachment(writer, rect, contents, PdfFileSpecification.FileEmbedded(writer, file, fileDisplay, fileStore)); + } + + /** Creates a file attachment annotation + * @param writer + * @param rect + * @param contents + * @param fs + * @return the annotation + * @throws IOException + */ + public static PdfAnnotation CreateFileAttachment(PdfWriter writer, Rectangle rect, String contents, PdfFileSpecification fs) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.FILEATTACHMENT); + if (contents != null) + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + annot.Put(PdfName.FS, fs.Reference); + return annot; + } + + public static PdfAnnotation CreatePopup(PdfWriter writer, Rectangle rect, string contents, bool open) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.POPUP); + if (contents != null) + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + if (open) + annot.Put(PdfName.OPEN, PdfBoolean.PDFTRUE); + return annot; + } + + public PdfContentByte DefaultAppearanceString { + set { + byte[] b = value.InternalBuffer.ToByteArray(); + int len = b.Length; + for (int k = 0; k < len; ++k) { + if (b[k] == '\n') + b[k] = 32; + } + Put(PdfName.DA, new PdfString(b)); + } + } + + public int Flags { + set { + if (value == 0) + Remove(PdfName.F); + else + Put(PdfName.F, new PdfNumber(value)); + } + } + + public PdfBorderArray Border { + set { + Put(PdfName.BORDER, value); + } + } + + public PdfBorderDictionary BorderStyle { + set { + Put(PdfName.BS, value); + } + } + + /** + * Sets the annotation's highlighting mode. The values can be + * HIGHLIGHT_NONE, HIGHLIGHT_INVERT, + * HIGHLIGHT_OUTLINE and HIGHLIGHT_PUSH; + * @param highlight the annotation's highlighting mode + */ + public void SetHighlighting(PdfName highlight) { + if (highlight.Equals(HIGHLIGHT_INVERT)) + Remove(PdfName.H); + else + Put(PdfName.H, highlight); + } + + public void SetAppearance(PdfName ap, PdfTemplate template) { + PdfDictionary dic = (PdfDictionary)Get(PdfName.AP); + if (dic == null) + dic = new PdfDictionary(); + dic.Put(ap, template.IndirectReference); + Put(PdfName.AP, dic); + if (!form) + return; + if (templates == null) + templates = new Hashtable(); + templates[template] = null; + } + + public void SetAppearance(PdfName ap, string state, PdfTemplate template) { + PdfDictionary dicAp = (PdfDictionary)Get(PdfName.AP); + if (dicAp == null) + dicAp = new PdfDictionary(); + + PdfDictionary dic; + PdfObject obj = dicAp.Get(ap); + if (obj != null && obj.IsDictionary()) + dic = (PdfDictionary)obj; + else + dic = new PdfDictionary(); + dic.Put(new PdfName(state), template.IndirectReference); + dicAp.Put(ap, dic); + Put(PdfName.AP, dicAp); + if (!form) + return; + if (templates == null) + templates = new Hashtable(); + templates[template] = null; + } + + public string AppearanceState { + set { + if (value == null) { + Remove(PdfName.AS); + return; + } + Put(PdfName.AS, new PdfName(value)); + } + } + + public Color Color { + set { + Put(PdfName.C, new PdfColor(value)); + } + } + + public string Title { + set { + if (value == null) { + Remove(PdfName.T); + return; + } + Put(PdfName.T, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public PdfAnnotation Popup { + set { + Put(PdfName.POPUP, value.IndirectReference); + value.Put(PdfName.PARENT, this.IndirectReference); + } + } + + public PdfAction Action { + set { + Put(PdfName.A, value); + } + } + + public void SetAdditionalActions(PdfName key, PdfAction action) { + PdfDictionary dic; + PdfObject obj = Get(PdfName.AA); + if (obj != null && obj.IsDictionary()) + dic = (PdfDictionary)obj; + else + dic = new PdfDictionary(); + dic.Put(key, action); + Put(PdfName.AA, dic); + } + + internal virtual bool IsUsed() { + return used; + } + + public virtual void SetUsed() { + used = true; + } + + public Hashtable Templates { + get { + return templates; + } + } + + /** Getter for property form. + * @return Value of property form. + */ + public bool IsForm() { + return form; + } + + /** Getter for property annotation. + * @return Value of property annotation. + */ + public bool IsAnnotation() { + return annotation; + } + + public int Page { + set { + Put(PdfName.P, writer.GetPageReference(value)); + } + } + + public void SetPage() { + Put(PdfName.P, writer.CurrentPage); + } + + /** Getter for property placeInPage. + * @return Value of property placeInPage. + */ + public int PlaceInPage { + get { + return placeInPage; + } + + set { + this.placeInPage = value; + } + } + + public static PdfAnnotation ShallowDuplicate(PdfAnnotation annot) { + PdfAnnotation dup; + if (annot.IsForm()) { + dup = new PdfFormField(annot.writer); + PdfFormField dupField = (PdfFormField)dup; + PdfFormField srcField = (PdfFormField)annot; + dupField.parent = srcField.parent; + dupField.kids = srcField.kids; + } + else + dup = new PdfAnnotation(annot.writer, null); + dup.Merge(annot); + dup.form = annot.form; + dup.annotation = annot.annotation; + dup.templates = annot.templates; + return dup; + } + + public int Rotate { + set { + Put(PdfName.ROTATE, new PdfNumber(value)); + } + } + + internal PdfDictionary MK { + get { + PdfDictionary mk = (PdfDictionary)Get(PdfName.MK); + if (mk == null) { + mk = new PdfDictionary(); + Put(PdfName.MK, mk); + } + return mk; + } + } + + public int MKRotation { + set { + MK.Put(PdfName.R, new PdfNumber(value)); + } + } + + public static PdfArray GetMKColor(Color color) { + PdfArray array = new PdfArray(); + int type = ExtendedColor.GetType(color); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + array.Add(new PdfNumber(((GrayColor)color).Gray)); + break; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)color; + array.Add(new PdfNumber(cmyk.Cyan)); + array.Add(new PdfNumber(cmyk.Magenta)); + array.Add(new PdfNumber(cmyk.Yellow)); + array.Add(new PdfNumber(cmyk.Black)); + break; + } + case ExtendedColor.TYPE_SEPARATION: + case ExtendedColor.TYPE_PATTERN: + case ExtendedColor.TYPE_SHADING: + throw new Exception("Separations, patterns and shadings are not allowed in MK dictionary."); + default: + array.Add(new PdfNumber(color.R / 255f)); + array.Add(new PdfNumber(color.G / 255f)); + array.Add(new PdfNumber(color.B / 255f)); + break; + } + return array; + } + + public Color MKBorderColor { + set { + if (value == null) + MK.Remove(PdfName.BC); + else + MK.Put(PdfName.BC, GetMKColor(value)); + } + } + + public Color MKBackgroundColor { + set { + if (value == null) + MK.Remove(PdfName.BG); + else + MK.Put(PdfName.BG, GetMKColor(value)); + } + } + + public string MKNormalCaption { + set { + MK.Put(PdfName.CA, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string MKRolloverCaption { + set { + MK.Put(PdfName.RC, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string MKAlternateCaption { + set { + MK.Put(PdfName.AC, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public PdfTemplate MKNormalIcon { + set { + MK.Put(PdfName.I, value.IndirectReference); + } + } + + public PdfTemplate MKRolloverIcon { + set { + MK.Put(PdfName.RI, value.IndirectReference); + } + } + + public PdfTemplate MKAlternateIcon { + set { + MK.Put(PdfName.IX, value.IndirectReference); + } + } + + public void SetMKIconFit(PdfName scale, PdfName scalingType, float leftoverLeft, float leftoverBottom, bool fitInBounds) { + PdfDictionary dic = new PdfDictionary(); + if (!scale.Equals(PdfName.A)) + dic.Put(PdfName.SW, scale); + if (!scalingType.Equals(PdfName.P)) + dic.Put(PdfName.S, scalingType); + if (leftoverLeft != 0.5f || leftoverBottom != 0.5f) { + PdfArray array = new PdfArray(new PdfNumber(leftoverLeft)); + array.Add(new PdfNumber(leftoverBottom)); + dic.Put(PdfName.A, array); + } + if (fitInBounds) + dic.Put(PdfName.FB, PdfBoolean.PDFTRUE); + MK.Put(PdfName.IF, dic); + } + + public int MKTextPosition { + set { + MK.Put(PdfName.TP, new PdfNumber(value)); + } + } + + /** + * Sets the layer this annotation belongs to. + * @param layer the layer this annotation belongs to + */ + public IPdfOCG Layer { + set { + Put(PdfName.OC, value.Ref); + } + } + + /** + * Sets the name of the annotation. + * With this name the annotation can be identified among + * all the annotations on a page (it has to be unique). + */ + public String Name { + set { + Put(PdfName.NM, new PdfString(value)); + } + } + + /** + * This class processes links from imported pages so that they may be active. The following example code reads a group + * of files and places them all on the output PDF, four pages in a single page, keeping the links active. + *
+        * String[] files = new String[] {"input1.pdf", "input2.pdf"};
+        * String outputFile = "output.pdf";
+        * int firstPage=1;
+        * Document document = new Document();
+        * PdfWriter writer = PdfWriter.GetInstance(document, new FileOutputStream(outputFile));
+        * document.SetPageSize(PageSize.A4);
+        * float W = PageSize.A4.GetWidth() / 2;
+        * float H = PageSize.A4.GetHeight() / 2;
+        * document.Open();
+        * PdfContentByte cb = writer.GetDirectContent();
+        * for (int i = 0; i < files.length; i++) {
+        *    PdfReader currentReader = new PdfReader(files[i]);
+        *    currentReader.ConsolidateNamedDestinations();
+        *    for (int page = 1; page <= currentReader.GetNumberOfPages(); page++) {
+        *        PdfImportedPage importedPage = writer.GetImportedPage(currentReader, page);
+        *        float a = 0.5f;
+        *        float e = (page % 2 == 0) ? W : 0;
+        *        float f = (page % 4 == 1 || page % 4 == 2) ? H : 0;
+        *        ArrayList links = currentReader.GetLinks(page);
+        *        cb.AddTemplate(importedPage, a, 0, 0, a, e, f);
+        *        for (int j = 0; j < links.Size(); j++) {
+        *            PdfAnnotation.PdfImportedLink link = (PdfAnnotation.PdfImportedLink)links.Get(j);
+        *            if (link.IsInternal()) {
+        *                int dPage = link.GetDestinationPage();
+        *                int newDestPage = (dPage-1)/4 + firstPage;
+        *                float ee = (dPage % 2 == 0) ? W : 0;
+        *                float ff = (dPage % 4 == 1 || dPage % 4 == 2) ? H : 0;
+        *                link.SetDestinationPage(newDestPage);
+        *                link.TransformDestination(a, 0, 0, a, ee, ff);
+        *            }
+        *            link.TransformRect(a, 0, 0, a, e, f);
+        *            writer.AddAnnotation(link.CreateAnnotation(writer));
+        *        }
+        *        if (page % 4 == 0)
+        *        document.NewPage();
+        *    }
+        *    if (i < files.length - 1)
+        *    document.NewPage();
+        *    firstPage += (currentReader.GetNumberOfPages()+3)/4;
+        * }
+        * document.Close();
+        * 
+ */ + public class PdfImportedLink { + float llx, lly, urx, ury; + Hashtable parameters; + PdfArray destination = null; + int newPage=0; + + internal PdfImportedLink(PdfDictionary annotation) { + parameters = (Hashtable)annotation.hashMap.Clone(); + try { + destination = (PdfArray)parameters[PdfName.DEST]; + parameters.Remove(PdfName.DEST); + } catch (Exception) { + throw new ArgumentException("You have to consolidate the named destinations of your reader."); + } + if (destination != null) { + destination = new PdfArray(destination); + } + PdfArray rc = (PdfArray)parameters[PdfName.RECT]; + parameters.Remove(PdfName.RECT); + llx = rc.GetAsNumber(0).FloatValue; + lly = rc.GetAsNumber(1).FloatValue; + urx = rc.GetAsNumber(2).FloatValue; + ury = rc.GetAsNumber(3).FloatValue; + } + + public bool IsInternal() { + return destination != null; + } + + public int GetDestinationPage() { + if (!IsInternal()) return 0; + + // here destination is something like + // [132 0 R, /XYZ, 29.3898, 731.864502, null] + PdfIndirectReference refi = destination.GetAsIndirectObject(0); + + PRIndirectReference pr = (PRIndirectReference) refi; + PdfReader r = pr.Reader; + for (int i = 1; i <= r.NumberOfPages; i++) { + PRIndirectReference pp = r.GetPageOrigRef(i); + if (pp.Generation == pr.Generation && pp.Number == pr.Number) return i; + } + throw new ArgumentException("Page not found."); + } + + public void SetDestinationPage(int newPage) { + if (!IsInternal()) throw new ArgumentException("Cannot change destination of external link"); + this.newPage=newPage; + } + + public void TransformDestination(float a, float b, float c, float d, float e, float f) { + if (!IsInternal()) throw new ArgumentException("Cannot change destination of external link"); + if (destination.GetAsName(1).Equals(PdfName.XYZ)) { + float x = destination.GetAsNumber(2).FloatValue; + float y = destination.GetAsNumber(3).FloatValue; + float xx = x * a + y * c + e; + float yy = x * b + y * d + f; + destination.ArrayList[2] = new PdfNumber(xx); + destination.ArrayList[3] = new PdfNumber(yy); + } + } + + public void TransformRect(float a, float b, float c, float d, float e, float f) { + float x = llx * a + lly * c + e; + float y = llx * b + lly * d + f; + llx = x; + lly = y; + x = urx * a + ury * c + e; + y = urx * b + ury * d + f; + urx = x; + ury = y; + } + + public PdfAnnotation CreateAnnotation(PdfWriter writer) { + PdfAnnotation annotation = new PdfAnnotation(writer, new Rectangle(llx, lly, urx, ury)); + if (newPage != 0) { + PdfIndirectReference refi = writer.GetPageReference(newPage); + destination.ArrayList[0] = refi; + } + if (destination != null) annotation.Put(PdfName.DEST, destination); + foreach (object key in parameters.Keys) + annotation.hashMap[key] = parameters[key]; + return annotation; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs b/iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs new file mode 100644 index 0000000..3f780f8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Implements the appearance stream to be used with form fields.. + */ + + public class PdfAppearance : PdfTemplate { + + public static Hashtable stdFieldFontNames = new Hashtable(); + + static PdfAppearance() { + stdFieldFontNames["Courier-BoldOblique"] = new PdfName("CoBO"); + stdFieldFontNames["Courier-Bold"] = new PdfName("CoBo"); + stdFieldFontNames["Courier-Oblique"] = new PdfName("CoOb"); + stdFieldFontNames["Courier"] = new PdfName("Cour"); + stdFieldFontNames["Helvetica-BoldOblique"] = new PdfName("HeBO"); + stdFieldFontNames["Helvetica-Bold"] = new PdfName("HeBo"); + stdFieldFontNames["Helvetica-Oblique"] = new PdfName("HeOb"); + stdFieldFontNames["Helvetica"] = PdfName.HELV; + stdFieldFontNames["Symbol"] = new PdfName("Symb"); + stdFieldFontNames["Times-BoldItalic"] = new PdfName("TiBI"); + stdFieldFontNames["Times-Bold"] = new PdfName("TiBo"); + stdFieldFontNames["Times-Italic"] = new PdfName("TiIt"); + stdFieldFontNames["Times-Roman"] = new PdfName("TiRo"); + stdFieldFontNames["ZapfDingbats"] = PdfName.ZADB; + stdFieldFontNames["HYSMyeongJo-Medium"] = new PdfName("HySm"); + stdFieldFontNames["HYGoThic-Medium"] = new PdfName("HyGo"); + stdFieldFontNames["HeiseiKakuGo-W5"] = new PdfName("KaGo"); + stdFieldFontNames["HeiseiMin-W3"] = new PdfName("KaMi"); + stdFieldFontNames["MHei-Medium"] = new PdfName("MHei"); + stdFieldFontNames["MSung-Light"] = new PdfName("MSun"); + stdFieldFontNames["STSong-Light"] = new PdfName("STSo"); + stdFieldFontNames["MSungStd-Light"] = new PdfName("MSun"); + stdFieldFontNames["STSongStd-Light"] = new PdfName("STSo"); + stdFieldFontNames["HYSMyeongJoStd-Medium"] = new PdfName("HySm"); + stdFieldFontNames["KozMinPro-Regular"] = new PdfName("KaMi"); + } + + /** + *Creates a PdfAppearance. + */ + + internal PdfAppearance() : base() { + separator = ' '; + } + + internal PdfAppearance(PdfIndirectReference iref) { + thisReference = iref; + } + /** + * Creates new PdfTemplate + * + * @param wr the PdfWriter + */ + + internal PdfAppearance(PdfWriter wr) : base(wr) { + separator = ' '; + } + + /** + * Creates a new appearance to be used with form fields. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the appearance created + */ + public static PdfAppearance CreateAppearance(PdfWriter writer, float width, float height) { + return CreateAppearance(writer, width, height, null); + } + + internal static PdfAppearance CreateAppearance(PdfWriter writer, float width, float height, PdfName forcedName) { + PdfAppearance template = new PdfAppearance(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Set the font and the size for the subsequent text writing. + * + * @param bf the font + * @param size the font size in points + */ + public override void SetFontAndSize(BaseFont bf, float size) { + CheckWriter(); + state.size = size; + if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { + state.fontDetails = new FontDetails(null, ((DocumentFont)bf).IndirectReference, bf); + } + else + state.fontDetails = writer.AddSimple(bf); + PdfName psn = (PdfName)stdFieldFontNames[bf.PostscriptFontName]; + if (psn == null) { + if (bf.Subset && bf.FontType == BaseFont.FONT_TYPE_TTUNI) + psn = state.fontDetails.FontName; + else { + psn = new PdfName(bf.PostscriptFontName); + state.fontDetails.Subset = false; + } + } + PageResources prs = PageResources; + prs.AddFont(psn, state.fontDetails.IndirectReference); + content.Append(psn.GetBytes()).Append(' ').Append(size).Append(" Tf").Append_i(separator); + } + + public override PdfContentByte Duplicate { + get { + PdfAppearance tpl = new PdfAppearance(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.bBox = new Rectangle(bBox); + tpl.group = group; + tpl.layer = layer; + if (matrix != null) { + tpl.matrix = new PdfArray(matrix); + } + tpl.separator = separator; + return tpl; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfArray.cs b/iTechSharp/iTextSharp/text/pdf/PdfArray.cs new file mode 100644 index 0000000..ca8f0bf --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfArray.cs @@ -0,0 +1,295 @@ +using System; +using System.IO; +using System.Collections; +using System.util; + +/* + * $Id: PdfArray.cs,v 1.7 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * PdfArray is the PDF Array object. + *

+ * An array is a sequence of PDF objects. An array may contain a mixture of object types. + * An array is written as a left square bracket ([), followed by a sequence of objects, + * followed by a right square bracket (]).
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.6 (page 40). + * + * @see PdfObject + */ + +public class PdfArray : PdfObject { + + // membervariables + +/** this is the actual array of PdfObjects */ + protected ArrayList arrayList; + + // constructors + +/** + * Constructs an empty PdfArray-object. + */ + + public PdfArray() : base(ARRAY) { + arrayList = new ArrayList(); + } + +/** + * Constructs an PdfArray-object, containing 1 PdfObject. + * + * @param object a PdfObject that has to be added to the array + */ + + public PdfArray(PdfObject obj) : base(ARRAY) { + arrayList = new ArrayList(); + arrayList.Add(obj); + } + + public PdfArray(float[] values) : base(ARRAY) { + arrayList = new ArrayList(); + Add(values); + } + + public PdfArray(int[] values) : base(ARRAY) { + arrayList = new ArrayList(); + Add(values); + } + +/** + * Constructs an PdfArray-object, containing all the PdfObjects in a given PdfArray. + * + * @param array a PdfArray that has to be added to the array + */ + + public PdfArray(PdfArray array) : base(ARRAY) { + arrayList = new ArrayList(array.ArrayList); + } + + // methods overriding some methods in PdfObject + +/** + * Returns the PDF representation of this PdfArray. + * + * @return an array of bytes + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + os.WriteByte((byte)'['); + bool first = true; + PdfObject obj = null; + foreach (PdfObject obja in arrayList) { + obj = (obja == null) ? PdfNull.PDFNULL : obja; + type = obj.Type; + if (!first && type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) + os.WriteByte((byte)' '); + first = false; + obj.ToPdf(writer, os); + } + os.WriteByte((byte)']'); + } + + // methods concerning the ArrayList-membervalue + +/** + * Returns an ArrayList containing PdfObjects. + * + * @return an ArrayList + */ + + public ArrayList ArrayList { + get { + return arrayList; + } + } + +/** + * Returns the number of entries in the array. + * + * @return the size of the ArrayList + */ + + public int Size { + get { + return arrayList.Count; + } + } + +/** + * Adds a PdfObject to the PdfArray. + * + * @param object PdfObject to add + * @return true + */ + + public virtual bool Add(PdfObject obj) { + arrayList.Add(obj); + return true; + } + + public bool Add(float[] values) { + for (int k = 0; k < values.Length; ++k) + arrayList.Add(new PdfNumber(values[k])); + return true; + } + + public bool Add(int[] values) { + for (int k = 0; k < values.Length; ++k) + arrayList.Add(new PdfNumber(values[k])); + return true; + } + +/** + * Adds a PdfObject to the PdfArray. + *

+ * The newly added object will be the first element in the ArrayList. + * + * @param object PdfObject to add + */ + + public void AddFirst(PdfObject obj) { + arrayList.Insert(0, obj); + } + +/** + * Checks if the PdfArray allready contains a certain PdfObject. + * + * @param object PdfObject to check + * @return true + */ + + public bool Contains(PdfObject obj) { + return arrayList.Contains(obj); + } + + public ListIterator GetListIterator() { + return new ListIterator(arrayList); + } + + public override string ToString() { + return arrayList.ToString(); + } + + public PdfObject GetPdfObject( int idx ) { + return (PdfObject)arrayList[idx]; + } + + public PdfObject GetDirectObject( int idx ) { + return PdfReader.GetPdfObject(GetPdfObject(idx)); + } + + // more of the same like PdfDictionary. (MAS 2/17/06) + public PdfDictionary GetAsDict(int idx) { + PdfDictionary dict = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsDictionary()) + dict = (PdfDictionary) orig; + return dict; + } + + public PdfArray GetAsArray(int idx) { + PdfArray array = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsArray()) + array = (PdfArray) orig; + return array; + } + + public PdfStream GetAsStream(int idx) { + PdfStream stream = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsStream()) + stream = (PdfStream) orig; + return stream; + } + + public PdfString GetAsString(int idx) { + PdfString str = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsString()) + str = (PdfString) orig; + return str; + } + + public PdfNumber GetAsNumber(int idx) { + PdfNumber number = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsNumber()) + number = (PdfNumber) orig; + return number; + } + + public PdfName GetAsName(int idx) { + PdfName name = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsName()) + name = (PdfName) orig; + return name; + } + + public PdfBoolean GetAsBoolean(int idx) { + PdfBoolean b = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsBoolean()) + b = (PdfBoolean) orig; + return b; + } + + public PdfIndirectReference GetAsIndirectObject(int idx) { + PdfIndirectReference refi = null; + PdfObject orig = GetPdfObject(idx); // not getDirect this time. + if (orig != null && orig.IsIndirect()) + refi = (PdfIndirectReference) orig; + return refi; + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs b/iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs new file mode 100644 index 0000000..785308a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs @@ -0,0 +1,137 @@ +using System; + +/* + * $Id: PdfBoolean.cs,v 1.5 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfBoolean is the bool object represented by the keywords true or false. + *

+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.2 (page 37). + * + * @see PdfObject + * @see BadPdfFormatException + */ + + public class PdfBoolean : PdfObject { + + // static membervariables (possible values of a bool object) + public static readonly PdfBoolean PDFTRUE = new PdfBoolean(true); + public static readonly PdfBoolean PDFFALSE = new PdfBoolean(false); + /** A possible value of PdfBoolean */ + public const string TRUE = "true"; + + /** A possible value of PdfBoolean */ + public const string FALSE = "false"; + + // membervariables + + /** the bool value of this object */ + private bool value; + + // constructors + + /** + * Constructs a PdfBoolean-object. + * + * @param value the value of the new PdfObject + */ + + public PdfBoolean(bool value) : base(BOOLEAN) { + if (value) { + this.Content = TRUE; + } + else { + this.Content = FALSE; + } + this.value = value; + } + + /** + * Constructs a PdfBoolean-object. + * + * @param value the value of the new PdfObject, represented as a string + * + * @throws BadPdfFormatException thrown if the value isn't 'true' or 'false' + */ + + public PdfBoolean(string value) : base(BOOLEAN, value) { + if (value.Equals(TRUE)) { + this.value = true; + } + else if (value.Equals(FALSE)) { + this.value = false; + } + else { + throw new BadPdfFormatException("The value has to be 'true' of 'false', instead of '" + value + "'."); + } + } + + // methods returning the value of this object + + /** + * Returns the primitive value of the PdfBoolean-object. + * + * @return the actual value of the object. + */ + + public bool BooleanValue { + get { + return value; + } + } + + public override string ToString() { + return value ? TRUE : FALSE; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs b/iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs new file mode 100644 index 0000000..8654d8f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs @@ -0,0 +1,82 @@ +using System; + +/* + * $Id: PdfBorderArray.cs,v 1.3 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfBorderArray defines the border of a PdfAnnotation. + * + * @see PdfArray + */ + + public class PdfBorderArray : PdfArray { + + // constructors + + /** + * Constructs a new PdfBorderArray. + */ + + public PdfBorderArray(float hRadius, float vRadius, float width) : this(hRadius, vRadius, width, null) {} + + /** + * Constructs a new PdfBorderArray. + */ + + public PdfBorderArray(float hRadius, float vRadius, float width, PdfDashPattern dash) : base(new PdfNumber(hRadius)) { + Add(new PdfNumber(vRadius)); + Add(new PdfNumber(width)); + if (dash != null) + Add(dash); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs b/iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs new file mode 100644 index 0000000..1604521 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs @@ -0,0 +1,101 @@ +using System; + +/* + * $Id: PdfBorderDictionary.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfBorderDictionary define the appearance of a Border (Annotations). + * + * @see PdfDictionary + */ + + public class PdfBorderDictionary : PdfDictionary { + + public const int STYLE_SOLID = 0; + public const int STYLE_DASHED = 1; + public const int STYLE_BEVELED = 2; + public const int STYLE_INSET = 3; + public const int STYLE_UNDERLINE = 4; + // constructors + + /** + * Constructs a PdfBorderDictionary. + */ + + public PdfBorderDictionary(float borderWidth, int borderStyle, PdfDashPattern dashes) { + Put(PdfName.W, new PdfNumber(borderWidth)); + switch (borderStyle) { + case STYLE_SOLID: + Put(PdfName.S, PdfName.S); + break; + case STYLE_DASHED: + if (dashes != null) + Put(PdfName.D, dashes); + Put(PdfName.S, PdfName.D); + break; + case STYLE_BEVELED: + Put(PdfName.S, PdfName.B); + break; + case STYLE_INSET: + Put(PdfName.S, PdfName.I); + break; + case STYLE_UNDERLINE: + Put(PdfName.S, PdfName.U); + break; + default: + throw new ArgumentException("Invalid border style."); + } + } + + public PdfBorderDictionary(float borderWidth, int borderStyle) : this(borderWidth, borderStyle, null) {} + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCell.cs b/iTechSharp/iTextSharp/text/pdf/PdfCell.cs new file mode 100644 index 0000000..c0633f8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCell.cs @@ -0,0 +1,875 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfCell.cs,v 1.10 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfCell is the PDF translation of a Cell. + *

+ * A PdfCell is an ArrayList of PdfLines. + * + * @see iTextSharp.text.Rectangle + * @see iTextSharp.text.Cell + * @see PdfLine + * @see PdfTable + */ + + public class PdfCell : Rectangle { + + // membervariables + + /** These are the PdfLines in the Cell. */ + private ArrayList lines; + + /** These are the PdfLines in the Cell. */ + private PdfLine line; + + /** These are the Images in the Cell. */ + private ArrayList images; + + /** This is the leading of the lines. */ + private float leading; + + /** This is the number of the row the cell is in. */ + private int rownumber; + + /** This is the rowspan of the cell. */ + private int rowspan; + + /** This is the cellspacing of the cell. */ + private float cellspacing; + + /** This is the cellpadding of the cell. */ + private float cellpadding; + + /** Indicates if this cell belongs to the header of a PdfTable */ + private bool header = false; + + /** + * This is the total height of the content of the cell. Note that the actual cell + * height may be larger due to another cell on the row * + */ + private float contentHeight = 0.0f; + + /** + * Indicates that the largest ascender height should be used to + * determine the height of the first line. Setting this to true can help + * with vertical alignment problems. */ + private bool useAscender; + + /** + * Indicates that the largest descender height should be added to the height of + * the last line (so characters like y don't dip into the border). */ + private bool useDescender; + + /** + * Adjusts the cell contents to compensate for border widths. + */ + private bool useBorderPadding; + + private int verticalAlignment; + + private PdfLine firstLine; + private PdfLine lastLine; + + // constructors + + /** + * Constructs a PdfCell-object. + * + * @param cell the original Cell + * @param rownumber the number of the Row the Cell was in. + * @param left the left border of the PdfCell + * @param right the right border of the PdfCell + * @param top the top border of the PdfCell + * @param cellspacing the cellspacing of the Table + * @param cellpadding the cellpadding of the Table + */ + + public PdfCell(Cell cell, int rownumber, float left, float right, float top, float cellspacing, float cellpadding) : base(left, top, right, top) { + // copying the other Rectangle attributes from class Cell + CloneNonPositionParameters(cell); + this.cellpadding = cellpadding; + this.cellspacing = cellspacing; + this.verticalAlignment = cell.VerticalAlignment; + this.useAscender = cell.UseAscender; + this.useDescender = cell.UseDescender; + this.useBorderPadding = cell.UseBorderPadding; + + // initialisation of some parameters + PdfChunk chunk; + PdfChunk overflow; + lines = new ArrayList(); + images = new ArrayList(); + leading = cell.Leading; + int alignment = cell.HorizontalAlignment; + left += cellspacing + cellpadding; + right -= cellspacing + cellpadding; + + left += GetBorderWidthInside(LEFT_BORDER); + right -= GetBorderWidthInside(RIGHT_BORDER); + contentHeight = 0; + rowspan = cell.Rowspan; + + ArrayList allActions; + int aCounter; + // we loop over all the elements of the cell + foreach (IElement ele in cell.Elements) { + switch (ele.Type) { + case Element.JPEG: + case Element.JPEG2000: + case Element.IMGRAW: + case Element.IMGTEMPLATE: + AddImage((Image)ele, left, right, 0.4f * leading, alignment); + break; + // if the element is a list + case Element.LIST: + if (line != null && line.Size > 0) { + line.ResetAlignment(); + AddLine(line); + } + // we loop over all the listitems + AddList((List)ele, left, right, alignment); + line = new PdfLine(left, right, alignment, leading); + break; + // if the element is something else + default: + allActions = new ArrayList(); + ProcessActions(ele, null, allActions); + aCounter = 0; + + float currentLineLeading = leading; + float currentLeft = left; + float currentRight = right; + if (ele is Phrase) { + currentLineLeading = ((Phrase) ele).Leading; + } + if (ele is Paragraph) { + Paragraph p = (Paragraph) ele; + currentLeft += p.IndentationLeft; + currentRight -= p.IndentationRight; + } + if (line == null) { + line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); + } + // we loop over the chunks + ArrayList chunks = ele.Chunks; + if (chunks.Count == 0) { + AddLine(line); // add empty line - all cells need some lines even if they are empty + line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); + } + else { + foreach (Chunk c in chunks) { + chunk = new PdfChunk(c, (PdfAction)allActions[aCounter++]); + while ((overflow = line.Add(chunk)) != null) { + AddLine(line); + line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); + chunk = overflow; + } + } + } + // if the element is a paragraph, section or chapter, we reset the alignment and add the line + switch (ele.Type) { + case Element.PARAGRAPH: + case Element.SECTION: + case Element.CHAPTER: + line.ResetAlignment(); + FlushCurrentLine(); + break; + } + break; + } + } + FlushCurrentLine(); + if (lines.Count > cell.MaxLines) { + while (lines.Count > cell.MaxLines) { + RemoveLine(lines.Count - 1); + } + if (cell.MaxLines > 0) { + String more = cell.ShowTruncation; + if (more != null && more.Length > 0) { + // Denote that the content has been truncated + lastLine = (PdfLine) lines[lines.Count - 1]; + if (lastLine.Size >= 0) { + PdfChunk lastChunk = lastLine.GetChunk(lastLine.Size - 1); + float moreWidth = new PdfChunk(more, lastChunk).Width; + while (lastChunk.ToString().Length > 0 && lastChunk.Width + moreWidth > right - left) { + // Remove characters to leave room for the 'more' indicator + lastChunk.Value = lastChunk.ToString().Substring(0, lastChunk.Length - 1); + } + lastChunk.Value = lastChunk.ToString() + more; + } else { + lastLine.Add(new PdfChunk(new Chunk(more), null)); + } + } + } + } + // we set some additional parameters + if (useDescender && lastLine != null) { + contentHeight -= lastLine.Descender; + } + + // adjust first line height so that it touches the top + if (lines.Count > 0) { + firstLine = (PdfLine) lines[0]; + float firstLineRealHeight = FirstLineRealHeight; + contentHeight -= firstLine.Height; + firstLine.height = firstLineRealHeight; + contentHeight += firstLineRealHeight; + } + + float newBottom = top - contentHeight - (2f * Cellpadding) - (2f * Cellspacing); + newBottom -= GetBorderWidthInside(TOP_BORDER) + GetBorderWidthInside(BOTTOM_BORDER); + Bottom = newBottom; + + this.rownumber = rownumber; + } + + private void AddList(List list, float left, float right, int alignment) { + PdfChunk chunk; + PdfChunk overflow; + ArrayList allActions = new ArrayList(); + ProcessActions(list, null, allActions); + int aCounter = 0; + foreach (IElement ele in list.Items) { + switch (ele.Type) { + case Element.LISTITEM: + ListItem item = (ListItem)ele; + line = new PdfLine(left + item.IndentationLeft, right, alignment, item.Leading); + line.ListItem = item; + foreach (Chunk c in item.Chunks) { + chunk = new PdfChunk(c, (PdfAction)(allActions[aCounter++])); + while ((overflow = line.Add(chunk)) != null) { + AddLine(line); + line = new PdfLine(left + item.IndentationLeft, right, alignment, item.Leading); + chunk = overflow; + } + line.ResetAlignment(); + AddLine(line); + line = new PdfLine(left + item.IndentationLeft, right, alignment, leading); + } + break; + case Element.LIST: + List sublist = (List)ele; + AddList(sublist, left + sublist.IndentationLeft, right, alignment); + break; + } + } + } + + // overriding of the Rectangle methods + + /** + * Returns the lower left x-coordinaat. + * + * @return the lower left x-coordinaat + */ + + public override float Left { + get { + return base.GetLeft(cellspacing); + } + } + + /** + * Returns the upper right x-coordinate. + * + * @return the upper right x-coordinate + */ + + public override float Right { + get { + return base.GetRight(cellspacing); + } + } + + /** + * Returns the upper right y-coordinate. + * + * @return the upper right y-coordinate + */ + + public override float Top { + get { + return base.GetTop(cellspacing); + } + } + + /** + * Returns the lower left y-coordinate. + * + * @return the lower left y-coordinate + */ + + public override float Bottom { + get { + return base.GetBottom(cellspacing); + } + set { + base.Bottom = value; + float firstLineRealHeight = FirstLineRealHeight; + + float totalHeight = ury - value; // can't use top (already compensates for cellspacing) + float nonContentHeight = (Cellpadding * 2f) + (Cellspacing * 2f); + nonContentHeight += GetBorderWidthInside(TOP_BORDER) + GetBorderWidthInside(BOTTOM_BORDER); + + float interiorHeight = totalHeight - nonContentHeight; + float extraHeight = 0.0f; + + switch (verticalAlignment) { + case Element.ALIGN_BOTTOM: + extraHeight = interiorHeight - contentHeight; + break; + case Element.ALIGN_MIDDLE: + extraHeight = (interiorHeight - contentHeight) / 2.0f; + break; + default: // ALIGN_TOP + extraHeight = 0f; + break; + } + + extraHeight += Cellpadding + Cellspacing; + extraHeight += GetBorderWidthInside(TOP_BORDER); + if (firstLine != null) { + firstLine.height = firstLineRealHeight + extraHeight; + } + } + } + + // methods + + private void AddLine(PdfLine line) { + lines.Add(line); + contentHeight += line.Height; + lastLine = line; + this.line = null; + } + + private PdfLine RemoveLine(int index) { + PdfLine oldLine = (PdfLine)lines[index]; + lines.RemoveAt(index); + contentHeight -= oldLine.Height; + if (index == 0) { + if (lines.Count > 0) { + firstLine = (PdfLine) lines[0]; + float firstLineRealHeight = FirstLineRealHeight; + contentHeight -= firstLine.Height; + firstLine.height = firstLineRealHeight; + contentHeight += firstLineRealHeight; + } + } + return oldLine; + } + + private void FlushCurrentLine() { + if (line != null && line.Size > 0) { + AddLine(line); + } + } + + /** + * Calculates what the height of the first line should be so that the content will be + * flush with the top. For text, this is the height of the ascender. For an image, + * it is the actual height of the image. + * @return the real height of the first line + */ + private float FirstLineRealHeight { + get { + float firstLineRealHeight = 0f; + if (firstLine != null) { + PdfChunk chunk = firstLine.GetChunk(0); + if (chunk != null) { + Image image = chunk.Image; + if (image != null) { + firstLineRealHeight = firstLine.GetChunk(0).Image.ScaledHeight; + } else { + firstLineRealHeight = useAscender ? firstLine.Ascender : leading; + } + } + } + return firstLineRealHeight; + } + } + + /** + * Gets the amount of the border for the specified side that is inside the Rectangle. + * For non-variable width borders this is only 1/2 the border width on that side. This + * always returns 0 if {@link #useBorderPadding} is false; + * @param side the side to check. One of the side constants in {@link com.lowagie.text.Rectangle} + * @return the borderwidth inside the cell + */ + private float GetBorderWidthInside(int side) { + float width = 0f; + if (useBorderPadding) { + switch (side) { + case iTextSharp.text.Rectangle.LEFT_BORDER: + width = BorderWidthLeft; + break; + + case iTextSharp.text.Rectangle.RIGHT_BORDER: + width = BorderWidthRight; + break; + + case iTextSharp.text.Rectangle.TOP_BORDER: + width = BorderWidthTop; + break; + + default: // default and BOTTOM + width = BorderWidthBottom; + break; + } + // non-variable (original style) borders overlap the rectangle (only 1/2 counts) + if (!UseVariableBorders) { + width = width / 2f; + } + } + return width; + } + + + /** + * Adds an image to this Cell. + * + * @param i the image to add + * @param left the left border + * @param right the right border + * @param extraHeight extra height to add above image + * @param alignment horizontal alignment (constant from Element class) + * @return the height of the image + */ + + private float AddImage(Image i, float left, float right, float extraHeight, int alignment) { + Image image = Image.GetInstance(i); + if (image.ScaledWidth > right - left) { + image.ScaleToFit(right - left, float.MaxValue); + } + FlushCurrentLine(); + if (line == null) { + line = new PdfLine(left, right, alignment, leading); + } + PdfLine imageLine = line; + + // left and right in chunk is relative to the start of the line + right = right - left; + left = 0f; + + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) { // fix Uwe Zimmerman + left = right - image.ScaledWidth; + } else if ((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN) { + left = left + ((right - left - image.ScaledWidth) / 2f); + } + Chunk imageChunk = new Chunk(image, left, 0); + imageLine.Add(new PdfChunk(imageChunk, null)); + AddLine(imageLine); + return imageLine.Height; + } + + /** + * Gets the lines of a cell that can be drawn between certain limits. + *

+ * Remark: all the lines that can be drawn are removed from the object! + * + * @param top the top of the part of the table that can be drawn + * @param bottom the bottom of the part of the table that can be drawn + * @return an ArrayList of PdfLines + */ + + public ArrayList GetLines(float top, float bottom) { + float lineHeight; + float currentPosition = Math.Min(this.Top, top); + this.Top = currentPosition + cellspacing; + ArrayList result = new ArrayList(); + + // if the bottom of the page is higher than the top of the cell: do nothing + if (Top < bottom) { + return result; + } + + // we loop over the lines + int size = lines.Count; + bool aboveBottom = true; + for (int i = 0; i < size && aboveBottom; i++) { + line = (PdfLine) lines[i]; + lineHeight = line.Height; + currentPosition -= lineHeight; + // if the currentPosition is higher than the bottom, we add the line to the result + if (currentPosition > (bottom + cellpadding + GetBorderWidthInside(BOTTOM_BORDER))) { // bugfix by Tom Ring and Veerendra Namineni + result.Add(line); + } + else { + aboveBottom = false; + } + } + // if the bottom of the cell is higher than the bottom of the page, the cell is written, so we can remove all lines + float difference = 0f; + if (!header) { + if (aboveBottom) { + lines = new ArrayList(); + contentHeight = 0f; + } + else { + size = result.Count; + for (int i = 0; i < size; i++) { + line = RemoveLine(0); + difference += line.Height; + } + } + } + if (difference > 0) { + foreach (Image image in images) { + image.SetAbsolutePosition(image.AbsoluteX, image.AbsoluteY - difference - leading); + } + } + return result; + } + + /** + * Gets the images of a cell that can be drawn between certain limits. + *

+ * Remark: all the lines that can be drawn are removed from the object! + * + * @param top the top of the part of the table that can be drawn + * @param bottom the bottom of the part of the table that can be drawn + * @return an ArrayList of Images + */ + + public ArrayList GetImages(float top, float bottom) { + + // if the bottom of the page is higher than the top of the cell: do nothing + if (this.Top < bottom) { + return new ArrayList(); + } + top = Math.Min(this.Top, top); + // initialisations + float height; + ArrayList result = new ArrayList(); + // we loop over the images + ArrayList remove = new ArrayList(); + foreach (Image image in images) { + height = image.AbsoluteY; + // if the currentPosition is higher than the bottom, we add the line to the result + if (top - height > (bottom + cellpadding)) { + image.SetAbsolutePosition(image.AbsoluteX, top - height); + result.Add(image); + remove.Add(image); + } + } + foreach (Image image in remove) { + images.Remove(image); + } + return result; + } + + /** + * Checks if this cell belongs to the header of a PdfTable. + * + * @return void + */ + + internal void SetHeader() { + header = true; + } + + /** + * Indicates that this cell belongs to the header of a PdfTable. + */ + + internal bool Header { + get { + return header; + } + } + + /** + * Checks if the cell may be removed. + *

+ * Headers may allways be removed, even if they are drawn only partially: + * they will be repeated on each following page anyway! + * + * @return true if all the lines are allready drawn; false otherwise. + */ + + internal bool MayBeRemoved() { + return (header || (lines.Count == 0 && images.Count == 0)); + } + + /** + * Returns the number of lines in the cell. + * + * @return a value + */ + + public int Size { + get { + return lines.Count; + } + } + + /** + * Returns the total height of all the lines in the cell. + * + * @return a value + */ + + private float RemainingLinesHeight() { + if (lines.Count == 0) return 0; + float result = 0; + int size = lines.Count; + PdfLine line; + for (int i = 0; i < size; i++) { + line = (PdfLine) lines[i]; + result += line.Height; + } + return result; + } + + /** + * Returns the height needed to draw the remaining text. + * + * @return a height + */ + + public float RemainingHeight { + get { + float result = 0f; + foreach (Image image in images) { + result += image.ScaledHeight; + } + return RemainingLinesHeight() + cellspacing + 2 * cellpadding + result; + } + } + + // methods to retrieve membervariables + + /** + * Gets the leading of a cell. + * + * @return the leading of the lines is the cell. + */ + + public float Leading { + get { + return leading; + } + } + + /** + * Gets the number of the row this cell is in.. + * + * @return a number + */ + + public int Rownumber { + get { + return rownumber; + } + } + + /** + * Gets the rowspan of a cell. + * + * @return the rowspan of the cell + */ + + public int Rowspan { + get { + return rowspan; + } + } + + /** + * Gets the cellspacing of a cell. + * + * @return a value + */ + + public float Cellspacing { + get { + return cellspacing; + } + } + + /** + * Gets the cellpadding of a cell.. + * + * @return a value + */ + + public float Cellpadding { + get { + return cellpadding; + } + } + + /** + * Processes all actions contained in the cell. + */ + + protected void ProcessActions(IElement element, PdfAction action, ArrayList allActions) { + if (element.Type == Element.ANCHOR) { + string url = ((Anchor)element).Reference; + if (url != null) { + action = new PdfAction(url); + } + } + switch (element.Type) { + case Element.PHRASE: + case Element.SECTION: + case Element.ANCHOR: + case Element.CHAPTER: + case Element.LISTITEM: + case Element.PARAGRAPH: + foreach (IElement ele in ((ArrayList)element)) { + ProcessActions(ele, action, allActions); + } + break; + case Element.CHUNK: + allActions.Add(action); + break; + case Element.LIST: + foreach (IElement ele in ((List)element).Items) { + ProcessActions(ele, action, allActions); + } + break; + default: + int n = element.Chunks.Count; + while (n-- > 0) + allActions.Add(action); + break; + } + } + + /** + * This is the number of the group the cell is in. + */ + private int groupNumber; + + /** + * Gets the number of the group this cell is in.. + * + * @return a number + */ + + public int GroupNumber { + get { + return groupNumber; + } + set { + groupNumber = value; + } + } + + /** + * Gets a Rectangle that is altered to fit on the page. + * + * @param top the top position + * @param bottom the bottom position + * @return a Rectangle + */ + + public Rectangle Rectangle(float top, float bottom) { + Rectangle tmp = new Rectangle(Left, Bottom, Right, Top); + tmp.CloneNonPositionParameters(this); + if (Top > top) { + tmp.Top = top; + tmp.Border = border - (border & TOP_BORDER); + } + if (Bottom < bottom) { + tmp.Bottom = bottom; + tmp.Border = border - (border & BOTTOM_BORDER); + } + return tmp; + } + + /** + * Gets the value of {@link #useAscender} + * @return useAscender + */ + public bool UseAscender { + get { + return useAscender; + } + set { + useAscender = value; + } + } + + /** + * Gets the value of {@link #useDescender} + * @return useDescender + */ + public bool UseDescender { + get { + return useDescender; + } + set { + useDescender = value; + } + } + + /** + * Sets the value of {@link #useBorderPadding}. + * @param use adjust layour for borders if true + */ + public bool UseBorderPadding { + set { + useBorderPadding = value; + } + get { + return useBorderPadding; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfChunk.cs b/iTechSharp/iTextSharp/text/pdf/PdfChunk.cs new file mode 100644 index 0000000..bb90e36 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfChunk.cs @@ -0,0 +1,841 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text; + +/* + * $Id: PdfChunk.cs,v 1.11 2008/05/22 22:11:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfChunk is the PDF translation of a Chunk. + *

+ * A PdfChunk is a PdfString in a certain + * PdfFont and Color. + * + * @see PdfString + * @see PdfFont + * @see iTextSharp.text.Chunk + * @see iTextSharp.text.Font + */ + + public class PdfChunk { + + + private static char[] singleSpace = {' '}; + private static PdfChunk[] thisChunk = new PdfChunk[1]; + private const float ITALIC_ANGLE = 0.21256f; + + /** The allowed attributes in variable attributes. */ + private static Hashtable keysAttributes = new Hashtable(); + + /** The allowed attributes in variable noStroke. */ + private static Hashtable keysNoStroke = new Hashtable(); + + static PdfChunk() { + keysAttributes.Add(Chunk.ACTION, null); + keysAttributes.Add(Chunk.UNDERLINE, null); + keysAttributes.Add(Chunk.REMOTEGOTO, null); + keysAttributes.Add(Chunk.LOCALGOTO, null); + keysAttributes.Add(Chunk.LOCALDESTINATION, null); + keysAttributes.Add(Chunk.GENERICTAG, null); + keysAttributes.Add(Chunk.NEWPAGE, null); + keysAttributes.Add(Chunk.IMAGE, null); + keysAttributes.Add(Chunk.BACKGROUND, null); + keysAttributes.Add(Chunk.PDFANNOTATION, null); + keysAttributes.Add(Chunk.SKEW, null); + keysAttributes.Add(Chunk.HSCALE, null); + keysAttributes.Add(Chunk.SEPARATOR, null); + keysAttributes.Add(Chunk.TAB, null); + keysNoStroke.Add(Chunk.SUBSUPSCRIPT, null); + keysNoStroke.Add(Chunk.SPLITCHARACTER, null); + keysNoStroke.Add(Chunk.HYPHENATION, null); + keysNoStroke.Add(Chunk.TEXTRENDERMODE, null); + } + + // membervariables + + /** The value of this object. */ + protected string value = PdfObject.NOTHING; + + /** The encoding. */ + protected string encoding = BaseFont.WINANSI; + + + /** The font for this PdfChunk. */ + protected PdfFont font; + + protected BaseFont baseFont; + + protected ISplitCharacter splitCharacter; + /** + * Metric attributes. + *

+ * This attributes require the mesurement of characters widths when rendering + * such as underline. + */ + protected Hashtable attributes = new Hashtable(); + + /** + * Non metric attributes. + *

+ * This attributes do not require the mesurement of characters widths when rendering + * such as Color. + */ + protected Hashtable noStroke = new Hashtable(); + + /** true if the chunk split was cause by a newline. */ + protected bool newlineSplit; + + /** The image in this PdfChunk, if it has one */ + protected Image image; + + /** The offset in the x direction for the image */ + protected float offsetX; + + /** The offset in the y direction for the image */ + protected float offsetY; + + /** Indicates if the height and offset of the Image has to be taken into account */ + protected bool changeLeading = false; + + // constructors + + /** + * Constructs a PdfChunk-object. + * + * @param string the content of the PdfChunk-object + * @param font the PdfFont + * @param attributes the metrics attributes + * @param noStroke the non metric attributes + */ + + internal PdfChunk(string str, PdfChunk other) { + thisChunk[0] = this; + value = str; + this.font = other.font; + this.attributes = other.attributes; + this.noStroke = other.noStroke; + this.baseFont = other.baseFont; + Object[] obj = (Object[])attributes[Chunk.IMAGE]; + if (obj == null) + image = null; + else { + image = (Image)obj[0]; + offsetX = (float)obj[1]; + offsetY = (float)obj[2]; + changeLeading = (bool)obj[3]; + } + encoding = font.Font.Encoding; + splitCharacter = (ISplitCharacter)noStroke[Chunk.SPLITCHARACTER]; + if (splitCharacter == null) + splitCharacter = DefaultSplitCharacter.DEFAULT; + } + + /** + * Constructs a PdfChunk-object. + * + * @param chunk the original Chunk-object + * @param action the PdfAction if the Chunk comes from an Anchor + */ + + internal PdfChunk(Chunk chunk, PdfAction action) { + thisChunk[0] = this; + value = chunk.Content; + + Font f = chunk.Font; + float size = f.Size; + if (size == iTextSharp.text.Font.UNDEFINED) + size = 12; + baseFont = f.BaseFont; + BaseFont bf = f.BaseFont; + int style = f.Style; + if (style == iTextSharp.text.Font.UNDEFINED) { + style = iTextSharp.text.Font.NORMAL; + } + if (baseFont == null) { + // translation of the font-family to a PDF font-family + baseFont = f.GetCalculatedBaseFont(false); + } + else{ + // bold simulation + if ((style & iTextSharp.text.Font.BOLD) != 0) + attributes[Chunk.TEXTRENDERMODE] = new Object[]{PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, size / 30f, null}; + // italic simulation + if ((style & iTextSharp.text.Font.ITALIC) != 0) + attributes[Chunk.SKEW] = new float[]{0, ITALIC_ANGLE}; + } + font = new PdfFont(baseFont, size); + // other style possibilities + Hashtable attr = chunk.Attributes; + if (attr != null) { + foreach (DictionaryEntry entry in attr) { + string name = (string)entry.Key; + if (keysAttributes.ContainsKey(name)) { + attributes[name] = entry.Value; + } + else if (keysNoStroke.ContainsKey(name)) { + noStroke[name] = entry.Value; + } + } + if ("".Equals(attr[Chunk.GENERICTAG])) { + attributes[Chunk.GENERICTAG] = chunk.Content; + } + } + if (f.IsUnderlined()) { + Object[] obj = {null, new float[]{0, 1f / 15, 0, -1f / 3, 0}}; + Object[][] unders = Utilities.AddToArray((Object[][])attributes[Chunk.UNDERLINE], obj); + attributes[Chunk.UNDERLINE] = unders; + } + if (f.IsStrikethru()) { + Object[] obj = {null, new float[]{0, 1f / 15, 0, 1f / 3, 0}}; + Object[][] unders = Utilities.AddToArray((Object[][])attributes[Chunk.UNDERLINE], obj); + attributes[Chunk.UNDERLINE] = unders; + } + if (action != null) + attributes[Chunk.ACTION] = action; + // the color can't be stored in a PdfFont + noStroke[Chunk.COLOR] = f.Color; + noStroke[Chunk.ENCODING] = font.Font.Encoding; + Object[] obj2 = (Object[])attributes[Chunk.IMAGE]; + if (obj2 == null) + image = null; + else { + attributes.Remove(Chunk.HSCALE); // images are scaled in other ways + image = (Image)obj2[0]; + offsetX = ((float)obj2[1]); + offsetY = ((float)obj2[2]); + changeLeading = (bool)obj2[3]; + } + font.Image = image; + object hs = attributes[Chunk.HSCALE]; + if (hs != null) + font.HorizontalScaling = (float)hs; + encoding = font.Font.Encoding; + splitCharacter = (ISplitCharacter)noStroke[Chunk.SPLITCHARACTER]; + if (splitCharacter == null) + splitCharacter = DefaultSplitCharacter.DEFAULT; + } + + // methods + + /** Gets the Unicode equivalent to a CID. + * The (inexistent) CID is translated as '\n'. + * It has only meaning with CJK fonts with Identity encoding. + * @param c the CID code + * @return the Unicode equivalent + */ + public int GetUnicodeEquivalent(int c) { + return baseFont.GetUnicodeEquivalent(c); + } + + protected int GetWord(string text, int start) { + int len = text.Length; + while (start < len) { + if (!char.IsLetter(text[start])) + break; + ++start; + } + return start; + } + + /** + * Splits this PdfChunk if it's too long for the given width. + *

+ * Returns null if the PdfChunk wasn't truncated. + * + * @param width a given width + * @return the PdfChunk that doesn't fit into the width. + */ + + internal PdfChunk Split(float width) { + newlineSplit = false; + if (image != null) { + if (image.ScaledWidth > width) { + PdfChunk pc = new PdfChunk(Chunk.OBJECT_REPLACEMENT_CHARACTER, this); + value = ""; + attributes = new Hashtable(); + image = null; + font = PdfFont.DefaultFont; + return pc; + } + else + return null; + } + IHyphenationEvent hyphenationEvent = (IHyphenationEvent)noStroke[Chunk.HYPHENATION]; + int currentPosition = 0; + int splitPosition = -1; + float currentWidth = 0; + + // loop over all the characters of a string + // or until the totalWidth is reached + int lastSpace = -1; + float lastSpaceWidth = 0; + int length = value.Length; + char[] valueArray = value.ToCharArray(); + char character = (char)0; + BaseFont ft = font.Font; + bool surrogate = false; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + while (currentPosition < length) { + // the width of every character is added to the currentWidth + char cidChar = valueArray[currentPosition]; + character = (char)ft.GetUnicodeEquivalent(cidChar); + // if a newLine or carriageReturn is encountered + if (character == '\n') { + newlineSplit = true; + string returnValue = value.Substring(currentPosition + 1); + value = value.Substring(0, currentPosition); + if (value.Length < 1) { + value = "\u0001"; + } + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + currentWidth += font.Width(cidChar); + if (character == ' ') { + lastSpace = currentPosition + 1; + lastSpaceWidth = currentWidth; + } + if (currentWidth > width) + break; + // if a split-character is encountered, the splitPosition is altered + if (splitCharacter.IsSplitCharacter(0, currentPosition, length, valueArray, thisChunk)) + splitPosition = currentPosition + 1; + currentPosition++; + } + } + else { + while (currentPosition < length) { + // the width of every character is added to the currentWidth + character = valueArray[currentPosition]; + // if a newLine or carriageReturn is encountered + if (character == '\r' || character == '\n') { + newlineSplit = true; + int inc = 1; + if (character == '\r' && currentPosition + 1 < length && valueArray[currentPosition + 1] == '\n') + inc = 2; + string returnValue = value.Substring(currentPosition + inc); + value = value.Substring(0, currentPosition); + if (value.Length < 1) { + value = " "; + } + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + surrogate = Utilities.IsSurrogatePair(valueArray, currentPosition); + if (surrogate) + currentWidth += font.Width(Utilities.ConvertToUtf32(valueArray[currentPosition], valueArray[currentPosition + 1])); + else + currentWidth += font.Width(character); + if (character == ' ') { + lastSpace = currentPosition + 1; + lastSpaceWidth = currentWidth; + } + if (surrogate) + currentPosition++; + if (currentWidth > width) + break; + // if a split-character is encountered, the splitPosition is altered + if (splitCharacter.IsSplitCharacter(0, currentPosition, length, valueArray, null)) + splitPosition = currentPosition + 1; + currentPosition++; + } + } + + // if all the characters fit in the total width, null is returned (there is no overflow) + if (currentPosition == length) { + return null; + } + // otherwise, the string has to be truncated + if (splitPosition < 0) { + string returnValue = value; + value = ""; + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + if (lastSpace > splitPosition && splitCharacter.IsSplitCharacter(0, 0, 1, singleSpace, null)) + splitPosition = lastSpace; + if (hyphenationEvent != null && lastSpace >= 0 && lastSpace < currentPosition) { + int wordIdx = GetWord(value, lastSpace); + if (wordIdx > lastSpace) { + string pre = hyphenationEvent.GetHyphenatedWordPre(value.Substring(lastSpace, wordIdx - lastSpace), font.Font, font.Size, width - lastSpaceWidth); + string post = hyphenationEvent.HyphenatedWordPost; + if (pre.Length > 0) { + string returnValue = post + value.Substring(wordIdx); + value = Trim(value.Substring(0, lastSpace) + pre); + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + } + } + string retVal = value.Substring(splitPosition); + value = Trim(value.Substring(0, splitPosition)); + PdfChunk tmp = new PdfChunk(retVal, this); + return tmp; + } + + /** + * Truncates this PdfChunk if it's too long for the given width. + *

+ * Returns null if the PdfChunk wasn't truncated. + * + * @param width a given width + * @return the PdfChunk that doesn't fit into the width. + */ + + internal PdfChunk Truncate(float width) { + if (image != null) { + if (image.ScaledWidth > width) { + PdfChunk pc = new PdfChunk("", this); + value = ""; + attributes.Remove(Chunk.IMAGE); + image = null; + font = PdfFont.DefaultFont; + return pc; + } + else + return null; + } + + int currentPosition = 0; + float currentWidth = 0; + + // it's no use trying to split if there isn't even enough place for a space + if (width < font.Width()) { + string returnValue = value.Substring(1); + value = value.Substring(0, 1); + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + + // loop over all the characters of a string + // or until the totalWidth is reached + int length = value.Length; + bool surrogate = false; + while (currentPosition < length) { + // the width of every character is added to the currentWidth + surrogate = Utilities.IsSurrogatePair(value, currentPosition); + if (surrogate) + currentWidth += font.Width(Utilities.ConvertToUtf32(value, currentPosition)); + else + currentWidth += font.Width(value[currentPosition]); + if (currentWidth > width) + break; + if (surrogate) + currentPosition++; + currentPosition++; + } + + // if all the characters fit in the total width, null is returned (there is no overflow) + if (currentPosition == length) { + return null; + } + + // otherwise, the string has to be truncated + //currentPosition -= 2; + // we have to chop off minimum 1 character from the chunk + if (currentPosition == 0) { + currentPosition = 1; + if (surrogate) + ++currentPosition; + } + string retVal = value.Substring(currentPosition); + value = value.Substring(0, currentPosition); + PdfChunk tmp = new PdfChunk(retVal, this); + return tmp; + } + + // methods to retrieve the membervariables + + /** + * Returns the font of this Chunk. + * + * @return a PdfFont + */ + + internal PdfFont Font { + get { + return font; + } + } + + /** + * Returns the color of this Chunk. + * + * @return a Color + */ + + internal Color Color { + get { + return (Color)noStroke[Chunk.COLOR]; + } + } + + /** + * Returns the width of this PdfChunk. + * + * @return a width + */ + + internal float Width { + get { + return font.Width(this.value); + } + } + + /** + * Checks if the PdfChunk split was caused by a newline. + * @return true if the PdfChunk split was caused by a newline. + */ + + public bool IsNewlineSplit() { + return newlineSplit; + } + + /** + * Gets the width of the PdfChunk taking into account the + * extra character and word spacing. + * @param charSpacing the extra character spacing + * @param wordSpacing the extra word spacing + * @return the calculated width + */ + + public float GetWidthCorrected(float charSpacing, float wordSpacing) { + if (image != null) { + return image.ScaledWidth + charSpacing; + } + int numberOfSpaces = 0; + int idx = -1; + while ((idx = value.IndexOf(' ', idx + 1)) >= 0) + ++numberOfSpaces; + return Width + (value.Length * charSpacing + numberOfSpaces * wordSpacing); + } + + /** + * Gets the text displacement relatiev to the baseline. + * @return a displacement in points + */ + public float TextRise { + get { + object f = GetAttribute(Chunk.SUBSUPSCRIPT); + if (f != null) { + return (float)f; + } + return 0.0f; + } + } + + /** + * Trims the last space. + * @return the width of the space trimmed, otherwise 0 + */ + + public float TrimLastSpace() { + BaseFont ft = font.Font; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + if (value.Length > 1 && value.EndsWith("\u0001")) { + value = value.Substring(0, value.Length - 1); + return font.Width('\u0001'); + } + } + else { + if (value.Length > 1 && value.EndsWith(" ")) { + value = value.Substring(0, value.Length - 1); + return font.Width(' '); + } + } + return 0; + } + + public float TrimFirstSpace() + { + BaseFont ft = font.Font; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + if (value.Length > 1 && value.StartsWith("\u0001")) { + value = value.Substring(1); + return font.Width('\u0001'); + } + } + else { + if (value.Length > 1 && value.StartsWith(" ")) { + value = value.Substring(1); + return font.Width(' '); + } + } + return 0; + } + + /** + * Gets an attribute. The search is made in attributes + * and noStroke. + * @param name the attribute key + * @return the attribute value or null if not found + */ + + internal Object GetAttribute(string name) { + if (attributes.ContainsKey(name)) + return attributes[name]; + return noStroke[name]; + } + + /** + *Checks if the attribute exists. + * @param name the attribute key + * @return true if the attribute exists + */ + + internal bool IsAttribute(string name) { + if (attributes.ContainsKey(name)) + return true; + return noStroke.ContainsKey(name); + } + + /** + * Checks if this PdfChunk needs some special metrics handling. + * @return true if this PdfChunk needs some special metrics handling. + */ + + internal bool IsStroked() { + return (attributes.Count > 0); + } + + /** + * Checks if this PdfChunk is a Separator Chunk. + * @return true if this chunk is a separator. + * @since 2.1.2 + */ + internal bool IsSeparator() { + return IsAttribute(Chunk.SEPARATOR); + } + + /** + * Checks if this PdfChunk is a horizontal Separator Chunk. + * @return true if this chunk is a horizontal separator. + * @since 2.1.2 + */ + internal bool IsHorizontalSeparator() { + if (IsAttribute(Chunk.SEPARATOR)) { + Object[] o = (Object[])GetAttribute(Chunk.SEPARATOR); + return !(bool)o[1]; + } + return false; + } + + /** + * Checks if this PdfChunk is a tab Chunk. + * @return true if this chunk is a separator. + * @since 2.1.2 + */ + internal bool IsTab() { + return IsAttribute(Chunk.TAB); + } + + /** + * Correction for the tab position based on the left starting position. + * @param newValue the new value for the left X. + * @since 2.1.2 + */ + internal void AdjustLeft(float newValue) { + Object[] o = (Object[])attributes[Chunk.TAB]; + if (o != null) { + attributes[Chunk.TAB] = new Object[]{o[0], o[1], o[2], newValue}; + } + } + + /** + * Checks if there is an image in the PdfChunk. + * @return true if an image is present + */ + + internal bool IsImage() { + return image != null; + } + + /** + * Gets the image in the PdfChunk. + * @return the image or null + */ + + internal Image Image { + get { + return image; + } + } + + /** + * Gets the image offset in the x direction + * @return the image offset in the x direction + */ + + internal float ImageOffsetX { + get { + return offsetX; + } + + set { + this.offsetX = value; + } + } + + /** + * Gets the image offset in the y direction + * @return Gets the image offset in the y direction + */ + + internal float ImageOffsetY { + get { + return offsetY; + } + + set { + this.offsetY = value; + } + } + + /** + * sets the value. + */ + + internal string Value { + set { + this.value = value; + } + } + + public override string ToString() { + return value; + } + + /** + * Tells you if this string is in Chinese, Japanese, Korean or Identity-H. + */ + + internal bool IsSpecialEncoding() { + return encoding.Equals(CJKFont.CJK_ENCODING) || encoding.Equals(BaseFont.IDENTITY_H); + } + + /** + * Gets the encoding of this string. + * + * @return a string + */ + + internal string Encoding { + get { + return encoding; + } + } + + internal int Length { + get { + return value.Length; + } + } + + internal int LengthUtf32 { + get { + if (!BaseFont.IDENTITY_H.Equals(encoding)) + return value.Length; + int total = 0; + int len = value.Length; + for (int k = 0; k < len; ++k) { + if (Utilities.IsSurrogateHigh(value[k])) + ++k; + ++total; + } + return total; + } + } + + internal bool IsExtSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { + return splitCharacter.IsSplitCharacter(start, current, end, cc, ck); + } + + /** + * Removes all the ' ' and '-'-characters on the right of a string. + *

+ * @param string the string that has to be trimmed. + * @return the trimmed string + */ + internal string Trim(string str) { + BaseFont ft = font.Font; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + while (str.EndsWith("\u0001")) { + str = str.Substring(0, str.Length - 1); + } + } + else { + while (str.EndsWith(" ") || str.EndsWith("\t")) { + str = str.Substring(0, str.Length - 1); + } + } + return str; + } + + public bool ChangeLeading { + get { + return changeLeading; + } + } + + internal float GetCharWidth(int c) { + if (NoPrint(c)) + return 0; + return font.Width(c); + } + + public static bool NoPrint(int c) { + return ((c >= 0x200b && c <= 0x200f) || (c >= 0x202a && c <= 0x202e)); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfColor.cs b/iTechSharp/iTextSharp/text/pdf/PdfColor.cs new file mode 100644 index 0000000..4b6c831 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfColor.cs @@ -0,0 +1,80 @@ +using System; +using iTextSharp.text; + +/* + * $Id: PdfColor.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A PdfColor defines a Color (it's a PdfArray containing 3 values). + * + * @see PdfDictionary + */ + + internal class PdfColor : PdfArray { + + // constructors + + /** + * Constructs a new PdfColor. + * + * @param red a value between 0 and 255 + * @param green a value between 0 and 255 + * @param blue a value between 0 and 255 + */ + + internal PdfColor(int red, int green, int blue) : base(new PdfNumber((double)(red & 0xFF) / 0xFF)) { + Add(new PdfNumber((double)(green & 0xFF) / 0xFF)); + Add(new PdfNumber((double)(blue & 0xFF) / 0xFF)); + } + + internal PdfColor(Color color) : this(color.R, color.G, color.B) {} + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs b/iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs new file mode 100644 index 0000000..b7a817d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs @@ -0,0 +1,2898 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.intern; + +/* + * $Id: PdfContentByte.cs,v 1.23 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfContentByte is an object containing the user positioned + * text and graphic contents of a page. It knows how to apply the proper + * font encoding. + */ + + public class PdfContentByte { + + /** + * This class keeps the graphic state of the current page + */ + + public class GraphicState { + + /** This is the font in use */ + internal FontDetails fontDetails; + + /** This is the color in use */ + internal ColorDetails colorDetails; + + /** This is the font size in use */ + internal float size; + + /** The x position of the text line matrix. */ + protected internal float xTLM = 0; + /** The y position of the text line matrix. */ + protected internal float yTLM = 0; + /** The current text leading. */ + protected internal float leading = 0; + + /** The current horizontal scaling */ + protected internal float scale = 100; + + /** The current character spacing */ + protected internal float charSpace = 0; + + /** The current word spacing */ + protected internal float wordSpace = 0; + + internal GraphicState() { + } + + internal GraphicState(GraphicState cp) { + fontDetails = cp.fontDetails; + colorDetails = cp.colorDetails; + size = cp.size; + xTLM = cp.xTLM; + yTLM = cp.yTLM; + leading = cp.leading; + scale = cp.scale; + charSpace = cp.charSpace; + wordSpace = cp.wordSpace; + } + } + + /** The alignement is center */ + public const int ALIGN_CENTER = Element.ALIGN_CENTER; + + /** The alignement is left */ + public const int ALIGN_LEFT = Element.ALIGN_LEFT; + + /** The alignement is right */ + public const int ALIGN_RIGHT = Element.ALIGN_RIGHT; + + /** A possible line cap value */ + public const int LINE_CAP_BUTT = 0; + /** A possible line cap value */ + public const int LINE_CAP_ROUND = 1; + /** A possible line cap value */ + public const int LINE_CAP_PROJECTING_SQUARE = 2; + + /** A possible line join value */ + public const int LINE_JOIN_MITER = 0; + /** A possible line join value */ + public const int LINE_JOIN_ROUND = 1; + /** A possible line join value */ + public const int LINE_JOIN_BEVEL = 2; + + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL = 0; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_STROKE = 1; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL_STROKE = 2; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_INVISIBLE = 3; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL_CLIP = 4; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_STROKE_CLIP = 5; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL_STROKE_CLIP = 6; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_CLIP = 7; + + private static float[] unitRect = {0, 0, 0, 1, 1, 0, 1, 1}; + // membervariables + + /** This is the actual content */ + protected ByteBuffer content = new ByteBuffer(); + + /** This is the writer */ + protected PdfWriter writer; + + /** This is the PdfDocument */ + protected PdfDocument pdf; + + /** This is the GraphicState in use */ + protected GraphicState state = new GraphicState(); + + /** The list were we save/restore the layer depth */ + protected ArrayList layerDepth; + + /** The list were we save/restore the state */ + protected ArrayList stateList = new ArrayList(); + + /** The separator between commands. + */ + protected int separator = '\n'; + + private static Hashtable abrev = new Hashtable(); + + static PdfContentByte() { + abrev[PdfName.BITSPERCOMPONENT] = "/BPC "; + abrev[PdfName.COLORSPACE] = "/CS "; + abrev[PdfName.DECODE] = "/D "; + abrev[PdfName.DECODEPARMS] = "/DP "; + abrev[PdfName.FILTER] = "/F "; + abrev[PdfName.HEIGHT] = "/H "; + abrev[PdfName.IMAGEMASK] = "/IM "; + abrev[PdfName.INTENT] = "/Intent "; + abrev[PdfName.INTERPOLATE] = "/I "; + abrev[PdfName.WIDTH] = "/W "; + } + + // constructors + + /** + * Constructs a new PdfContentByte-object. + * + * @param wr the writer associated to this content + */ + + public PdfContentByte(PdfWriter wr) { + if (wr != null) { + writer = wr; + pdf = writer.PdfDocument; + } + } + + // methods to get the content of this object + + /** + * Returns the string representation of this PdfContentByte-object. + * + * @return a string + */ + + public override string ToString() { + return content.ToString(); + } + + /** + * Gets the internal buffer. + * @return the internal buffer + */ + public ByteBuffer InternalBuffer { + get { + return content; + } + } + + /** Returns the PDF representation of this PdfContentByte-object. + * + * @param writer the PdfWriter + * @return a byte array with the representation + */ + + public byte[] ToPdf(PdfWriter writer) { + return content.ToByteArray(); + } + + // methods to add graphical content + + /** + * Adds the content of another PdfContent-object to this object. + * + * @param other another PdfByteContent-object + */ + + public void Add(PdfContentByte other) { + if (other.writer != null && writer != other.writer) + throw new Exception("Inconsistent writers. Are you mixing two documents?"); + content.Append(other.content); + } + + /** + * Gets the x position of the text line matrix. + * + * @return the x position of the text line matrix + */ + public float XTLM { + get { + return state.xTLM; + } + } + + /** + * Gets the y position of the text line matrix. + * + * @return the y position of the text line matrix + */ + public float YTLM { + get { + return state.yTLM; + } + } + + /** + * Gets the current character spacing. + * + * @return the current character spacing + */ + public float CharacterSpacing { + get { + return state.charSpace; + } + } + + /** + * Gets the current word spacing. + * + * @return the current word spacing + */ + public float WordSpacing { + get { + return state.wordSpace; + } + } + + /** + * Gets the current character spacing. + * + * @return the current character spacing + */ + public float HorizontalScaling { + get { + return state.scale; + } + } + + /** + * Gets the current text leading. + * + * @return the current text leading + */ + public float Leading { + get { + return state.leading; + } + } + + public void SetLeading(float v) { + state.leading = v; + content.Append(v).Append(" TL").Append_i(separator); + } + + /** + * Changes the Flatness. + *

+ * Flatness sets the maximum permitted distance in device pixels between the + * mathematically correct path and an approximation constructed from straight line segments.
+ * + * @param flatness a value + */ + + public void SetFlatness(float value) { + if (value >= 0 && value <= 100) { + content.Append(value).Append(" i").Append_i(separator); + } + } + + /** + * Changes the Line cap style. + *

+ * The line cap style specifies the shape to be used at the end of open subpaths + * when they are stroked.
+ * Allowed values are 0 (Butt end caps), 1 (Round end caps) and 2 (Projecting square end caps).
+ * + * @param style a value + */ + + public void SetLineCap(int value) { + if (value >= 0 && value <= 2) { + content.Append(value).Append(" J").Append_i(separator); + } + } + + /** + * Changes the value of the line dash pattern. + *

+ * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
+ * + * @param phase the value of the phase + */ + + public void SetLineDash(float value) { + content.Append("[] ").Append(value).Append(" d").Append_i(separator); + } + + /** + * Changes the value of the line dash pattern. + *

+ * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
+ * + * @param phase the value of the phase + * @param unitsOn the number of units that must be 'on' (equals the number of units that must be 'off'). + */ + + public void SetLineDash(float unitsOn, float phase) { + content.Append('[').Append(unitsOn).Append("] ").Append(phase).Append(" d").Append_i(separator); + } + + /** + * Changes the value of the line dash pattern. + *

+ * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
+ * + * @param phase the value of the phase + * @param unitsOn the number of units that must be 'on' + * @param unitsOff the number of units that must be 'off' + */ + + public void SetLineDash(float unitsOn, float unitsOff, float phase) { + content.Append('[').Append(unitsOn).Append(' ').Append(unitsOff).Append("] ").Append(phase).Append(" d").Append_i(separator); + } + + /** + * Changes the value of the line dash pattern. + *

+ * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
+ * + * @param array length of the alternating dashes and gaps + * @param phase the value of the phase + */ + + public void SetLineDash(float[] array, float phase) { + content.Append('['); + for (int i = 0; i < array.Length; i++) { + content.Append(array[i]); + if (i < array.Length - 1) content.Append(' '); + } + content.Append("] ").Append(phase).Append(" d").Append_i(separator); + } + + /** + * Changes the Line join style. + *

+ * The line join style specifies the shape to be used at the corners of paths + * that are stroked.
+ * Allowed values are 0 (Miter joins), 1 (Round joins) and 2 (Bevel joins).
+ * + * @param style a value + */ + + public void SetLineJoin(int value) { + if (value >= 0 && value <= 2) { + content.Append(value).Append(" j").Append_i(separator); + } + } + + /** + * Changes the line width. + *

+ * The line width specifies the thickness of the line used to stroke a path and is measured + * in used space units.
+ * + * @param w a width + */ + + public void SetLineWidth(float value) { + content.Append(value).Append(" w").Append_i(separator); + } + + /** + * Changes the Miter limit. + *

+ * When two line segments meet at a sharp angle and mitered joins have been specified as the + * line join style, it is possible for the miter to extend far beyond the thickness of the line + * stroking path. The miter limit imposes a maximum on the ratio of the miter length to the line + * witdh. When the limit is exceeded, the join is converted from a miter to a bevel.
+ * + * @param miterLimit a miter limit + */ + + public void SetMiterLimit(float value) { + if (value > 1) { + content.Append(value).Append(" M").Append_i(separator); + } + } + + /** + * Modify the current clipping path by intersecting it with the current path, using the + * nonzero winding number rule to determine which regions lie inside the clipping + * path. + */ + + public void Clip() { + content.Append('W').Append_i(separator); + } + + /** + * Modify the current clipping path by intersecting it with the current path, using the + * even-odd rule to determine which regions lie inside the clipping path. + */ + + public void EoClip() { + content.Append("W*").Append_i(separator); + } + + /** + * Changes the currentgray tint for filling paths (device dependent colors!). + *

+ * Sets the color space to DeviceGray (or the DefaultGray color space), + * and sets the gray tint to use for filling paths.

+ * + * @param gray a value between 0 (black) and 1 (white) + */ + + public virtual void SetGrayFill(float value) { + content.Append(value).Append(" g").Append_i(separator); + } + + /** + * Changes the current gray tint for filling paths to black. + */ + + public virtual void ResetGrayFill() { + content.Append("0 g").Append_i(separator); + } + + /** + * Changes the currentgray tint for stroking paths (device dependent colors!). + *

+ * Sets the color space to DeviceGray (or the DefaultGray color space), + * and sets the gray tint to use for stroking paths.

+ * + * @param gray a value between 0 (black) and 1 (white) + */ + + public virtual void SetGrayStroke(float value) { + content.Append(value).Append(" G").Append_i(separator); + } + + /** + * Changes the current gray tint for stroking paths to black. + */ + + public virtual void ResetGrayStroke() { + content.Append("0 G").Append_i(separator); + } + + /** + * Helper to validate and write the RGB color components + * @param red the intensity of red. A value between 0 and 1 + * @param green the intensity of green. A value between 0 and 1 + * @param blue the intensity of blue. A value between 0 and 1 + */ + private void HelperRGB(float red, float green, float blue) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_RGB, null); + if (red < 0) + red = 0.0f; + else if (red > 1.0f) + red = 1.0f; + if (green < 0) + green = 0.0f; + else if (green > 1.0f) + green = 1.0f; + if (blue < 0) + blue = 0.0f; + else if (blue > 1.0f) + blue = 1.0f; + content.Append(red).Append(' ').Append(green).Append(' ').Append(blue); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

+ * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for filling paths.

+ *

+ * Following the PDF manual, each operand must be a number between 0 (minimum intensity) and + * 1 (maximum intensity).

+ * + * @param red the intensity of red. A value between 0 and 1 + * @param green the intensity of green. A value between 0 and 1 + * @param blue the intensity of blue. A value between 0 and 1 + */ + + public virtual void SetRGBColorFillF(float red, float green, float blue) { + HelperRGB(red, green, blue); + content.Append(" rg").Append_i(separator); + } + + /** + * Changes the current color for filling paths to black. + */ + + public virtual void ResetRGBColorFill() { + content.Append("0 g").Append_i(separator); + } + + /** + * Changes the current color for stroking paths (device dependent colors!). + *

+ * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for stroking paths.

+ *

+ * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). + * + * @param red the intensity of red. A value between 0 and 1 + * @param green the intensity of green. A value between 0 and 1 + * @param blue the intensity of blue. A value between 0 and 1 + */ + + public virtual void SetRGBColorStrokeF(float red, float green, float blue) { + HelperRGB(red, green, blue); + content.Append(" RG").Append_i(separator); + } + + /** + * Changes the current color for stroking paths to black. + * + */ + + public virtual void ResetRGBColorStroke() { + content.Append("0 G").Append_i(separator); + } + + /** + * Helper to validate and write the CMYK color components. + * + * @param cyan the intensity of cyan. A value between 0 and 1 + * @param magenta the intensity of magenta. A value between 0 and 1 + * @param yellow the intensity of yellow. A value between 0 and 1 + * @param black the intensity of black. A value between 0 and 1 + */ + private void HelperCMYK(float cyan, float magenta, float yellow, float black) { + if (cyan < 0) + cyan = 0.0f; + else if (cyan > 1.0f) + cyan = 1.0f; + if (magenta < 0) + magenta = 0.0f; + else if (magenta > 1.0f) + magenta = 1.0f; + if (yellow < 0) + yellow = 0.0f; + else if (yellow > 1.0f) + yellow = 1.0f; + if (black < 0) + black = 0.0f; + else if (black > 1.0f) + black = 1.0f; + content.Append(cyan).Append(' ').Append(magenta).Append(' ').Append(yellow).Append(' ').Append(black); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

+ * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for filling paths.

+ *

+ * Following the PDF manual, each operand must be a number between 0 (no ink) and + * 1 (maximum ink).

+ * + * @param cyan the intensity of cyan. A value between 0 and 1 + * @param magenta the intensity of magenta. A value between 0 and 1 + * @param yellow the intensity of yellow. A value between 0 and 1 + * @param black the intensity of black. A value between 0 and 1 + */ + + public virtual void SetCMYKColorFillF(float cyan, float magenta, float yellow, float black) { + HelperCMYK(cyan, magenta, yellow, black); + content.Append(" k").Append_i(separator); + } + + /** + * Changes the current color for filling paths to black. + * + */ + + public virtual void ResetCMYKColorFill() { + content.Append("0 0 0 1 k").Append_i(separator); + } + + /** + * Changes the current color for stroking paths (device dependent colors!). + *

+ * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for stroking paths.

+ *

+ * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). + * + * @param cyan the intensity of cyan. A value between 0 and 1 + * @param magenta the intensity of magenta. A value between 0 and 1 + * @param yellow the intensity of yellow. A value between 0 and 1 + * @param black the intensity of black. A value between 0 and 1 + */ + + public virtual void SetCMYKColorStrokeF(float cyan, float magenta, float yellow, float black) { + HelperCMYK(cyan, magenta, yellow, black); + content.Append(" K").Append_i(separator); + } + + /** + * Changes the current color for stroking paths to black. + * + */ + + public virtual void ResetCMYKColorStroke() { + content.Append("0 0 0 1 K").Append_i(separator); + } + + /** + * Move the current point (x, y), omitting any connecting line segment. + * + * @param x new x-coordinate + * @param y new y-coordinate + */ + + public void MoveTo(float x, float y) { + content.Append(x).Append(' ').Append(y).Append(" m").Append_i(separator); + } + + /** + * Appends a straight line segment from the current point (x, y). The new current + * point is (x, y). + * + * @param x new x-coordinate + * @param y new y-coordinate + */ + + public void LineTo(float x, float y) { + content.Append(x).Append(' ').Append(y).Append(" l").Append_i(separator); + } + + /** + * Appends a Bêzier curve to the path, starting from the current point. + * + * @param x1 x-coordinate of the first control point + * @param y1 y-coordinate of the first control point + * @param x2 x-coordinate of the second control point + * @param y2 y-coordinate of the second control point + * @param x3 x-coordinaat of the ending point (= new current point) + * @param y3 y-coordinaat of the ending point (= new current point) + */ + + public void CurveTo(float x1, float y1, float x2, float y2, float x3, float y3) { + content.Append(x1).Append(' ').Append(y1).Append(' ').Append(x2).Append(' ').Append(y2).Append(' ').Append(x3).Append(' ').Append(y3).Append(" c").Append_i(separator); + } + + /** + * Appends a Bêzier curve to the path, starting from the current point. + * + * @param x2 x-coordinate of the second control point + * @param y2 y-coordinate of the second control point + * @param x3 x-coordinaat of the ending point (= new current point) + * @param y3 y-coordinaat of the ending point (= new current point) + */ + + public void CurveTo(float x2, float y2, float x3, float y3) { + content.Append(x2).Append(' ').Append(y2).Append(' ').Append(x3).Append(' ').Append(y3).Append(" v").Append_i(separator); + } + + /** + * Appends a Bêzier curve to the path, starting from the current point. + * + * @param x1 x-coordinate of the first control point + * @param y1 y-coordinate of the first control point + * @param x3 x-coordinaat of the ending point (= new current point) + * @param y3 y-coordinaat of the ending point (= new current point) + */ + + public void CurveFromTo(float x1, float y1, float x3, float y3) { + content.Append(x1).Append(' ').Append(y1).Append(' ').Append(x3).Append(' ').Append(y3).Append(" y").Append_i(separator); + } + + /** Draws a circle. The endpoint will (x+r, y). + * + * @param x x center of circle + * @param y y center of circle + * @param r radius of circle + */ + public void Circle(float x, float y, float r) { + float b = 0.5523f; + MoveTo(x + r, y); + CurveTo(x + r, y + r * b, x + r * b, y + r, x, y + r); + CurveTo(x - r * b, y + r, x - r, y + r * b, x - r, y); + CurveTo(x - r, y - r * b, x - r * b, y - r, x, y - r); + CurveTo(x + r * b, y - r, x + r, y - r * b, x + r, y); + } + + + + /** + * Adds a rectangle to the current path. + * + * @param x x-coordinate of the starting point + * @param y y-coordinate of the starting point + * @param w width + * @param h height + */ + + public void Rectangle(float x, float y, float w, float h) { + content.Append(x).Append(' ').Append(y).Append(' ').Append(w).Append(' ').Append(h).Append(" re").Append_i(separator); + } + + private bool CompareColors(Color c1, Color c2) { + if (c1 == null && c2 == null) + return true; + if (c1 == null || c2 == null) + return false; + if (c1 is ExtendedColor) + return c1.Equals(c2); + return c2.Equals(c1); + } + + /** + * Adds a variable width border to the current path. + * Only use if {@link com.lowagie.text.Rectangle#isUseVariableBorders() Rectangle.isUseVariableBorders} + * = true. + * @param rect a Rectangle + */ + public void VariableRectangle(Rectangle rect) { + float t = rect.Top; + float b = rect.Bottom; + float r = rect.Right; + float l = rect.Left; + float wt = rect.BorderWidthTop; + float wb = rect.BorderWidthBottom; + float wr = rect.BorderWidthRight; + float wl = rect.BorderWidthLeft; + Color ct = rect.BorderColorTop; + Color cb = rect.BorderColorBottom; + Color cr = rect.BorderColorRight; + Color cl = rect.BorderColorLeft; + SaveState(); + SetLineCap(PdfContentByte.LINE_CAP_BUTT); + SetLineJoin(PdfContentByte.LINE_JOIN_MITER); + float clw = 0; + bool cdef = false; + Color ccol = null; + bool cdefi = false; + Color cfil = null; + // draw top + if (wt > 0) { + SetLineWidth(clw = wt); + cdef = true; + if (ct == null) + ResetRGBColorStroke(); + else + SetColorStroke(ct); + ccol = ct; + MoveTo(l, t - wt / 2f); + LineTo(r, t - wt / 2f); + Stroke(); + } + + // Draw bottom + if (wb > 0) { + if (wb != clw) + SetLineWidth(clw = wb); + if (!cdef || !CompareColors(ccol, cb)) { + cdef = true; + if (cb == null) + ResetRGBColorStroke(); + else + SetColorStroke(cb); + ccol = cb; + } + MoveTo(r, b + wb / 2f); + LineTo(l, b + wb / 2f); + Stroke(); + } + + // Draw right + if (wr > 0) { + if (wr != clw) + SetLineWidth(clw = wr); + if (!cdef || !CompareColors(ccol, cr)) { + cdef = true; + if (cr == null) + ResetRGBColorStroke(); + else + SetColorStroke(cr); + ccol = cr; + } + bool bt = CompareColors(ct, cr); + bool bb = CompareColors(cb, cr); + MoveTo(r - wr / 2f, bt ? t : t - wt); + LineTo(r - wr / 2f, bb ? b : b + wb); + Stroke(); + if (!bt || !bb) { + cdefi = true; + if (cr == null) + ResetRGBColorFill(); + else + SetColorFill(cr); + cfil = cr; + if (!bt) { + MoveTo(r, t); + LineTo(r, t - wt); + LineTo(r - wr, t - wt); + Fill(); + } + if (!bb) { + MoveTo(r, b); + LineTo(r, b + wb); + LineTo(r - wr, b + wb); + Fill(); + } + } + } + + // Draw Left + if (wl > 0) { + if (wl != clw) + SetLineWidth(wl); + if (!cdef || !CompareColors(ccol, cl)) { + if (cl == null) + ResetRGBColorStroke(); + else + SetColorStroke(cl); + } + bool bt = CompareColors(ct, cl); + bool bb = CompareColors(cb, cl); + MoveTo(l + wl / 2f, bt ? t : t - wt); + LineTo(l + wl / 2f, bb ? b : b + wb); + Stroke(); + if (!bt || !bb) { + if (!cdefi || !CompareColors(cfil, cl)) { + if (cl == null) + ResetRGBColorFill(); + else + SetColorFill(cl); + } + if (!bt) { + MoveTo(l, t); + LineTo(l, t - wt); + LineTo(l + wl, t - wt); + Fill(); + } + if (!bb) { + MoveTo(l, b); + LineTo(l, b + wb); + LineTo(l + wl, b + wb); + Fill(); + } + } + } + RestoreState(); + } + + /** + * Adds a border (complete or partially) to the current path.. + * + * @param rectangle a Rectangle + */ + + public void Rectangle(Rectangle rectangle) { + // the coordinates of the border are retrieved + float x1 = rectangle.Left; + float y1 = rectangle.Bottom; + float x2 = rectangle.Right; + float y2 = rectangle.Top; + + // the backgroundcolor is set + Color background = rectangle.BackgroundColor; + if (background != null) { + SetColorFill(background); + Rectangle(x1, y1, x2 - x1, y2 - y1); + Fill(); + ResetRGBColorFill(); + } + + // if the element hasn't got any borders, nothing is added + if (! rectangle.HasBorders()) { + return; + } + + // if any of the individual border colors are set + // we draw the borders all around using the + // different colors + if (rectangle.UseVariableBorders) { + VariableRectangle(rectangle); + } + else { + // the width is set to the width of the element + if (rectangle.BorderWidth != iTextSharp.text.Rectangle.UNDEFINED) { + SetLineWidth(rectangle.BorderWidth); + } + + // the color is set to the color of the element + Color color = rectangle.BorderColor; + if (color != null) { + SetColorStroke(color); + } + + // if the box is a rectangle, it is added as a rectangle + if (rectangle.HasBorder(iTextSharp.text.Rectangle.BOX)) { + this.Rectangle(x1, y1, x2 - x1, y2 - y1); + } + // if the border isn't a rectangle, the different sides are added apart + else { + if (rectangle.HasBorder(iTextSharp.text.Rectangle.RIGHT_BORDER)) { + MoveTo(x2, y1); + LineTo(x2, y2); + } + if (rectangle.HasBorder(iTextSharp.text.Rectangle.LEFT_BORDER)) { + MoveTo(x1, y1); + LineTo(x1, y2); + } + if (rectangle.HasBorder(iTextSharp.text.Rectangle.BOTTOM_BORDER)) { + MoveTo(x1, y1); + LineTo(x2, y1); + } + if (rectangle.HasBorder(iTextSharp.text.Rectangle.TOP_BORDER)) { + MoveTo(x1, y2); + LineTo(x2, y2); + } + } + + Stroke(); + + if (color != null) { + ResetRGBColorStroke(); + } + } + } + + /** + * Closes the current subpath by appending a straight line segment from the current point + * to the starting point of the subpath. + */ + + public void ClosePath() { + content.Append('h').Append_i(separator); + } + + /** + * Ends the path without filling or stroking it. + */ + + public void NewPath() { + content.Append('n').Append_i(separator); + } + + /** + * Strokes the path. + */ + + public void Stroke() { + content.Append('S').Append_i(separator); + } + + /** + * Closes the path and strokes it. + */ + + public void ClosePathStroke() { + content.Append('s').Append_i(separator); + } + + /** + * Fills the path, using the non-zero winding number rule to determine the region to fill. + */ + + public void Fill() { + content.Append('f').Append_i(separator); + } + + /** + * Fills the path, using the even-odd rule to determine the region to fill. + */ + + public void EoFill() { + content.Append("f*").Append_i(separator); + } + + /** + * Fills the path using the non-zero winding number rule to determine the region to fill and strokes it. + */ + + public void FillStroke() { + content.Append('B').Append_i(separator); + } + + /** + * Closes the path, fills it using the non-zero winding number rule to determine the region to fill and strokes it. + */ + + public void ClosePathFillStroke() { + content.Append('b').Append_i(separator); + } + + /** + * Fills the path, using the even-odd rule to determine the region to fill and strokes it. + */ + + public void EoFillStroke() { + content.Append("B*").Append_i(separator); + } + + /** + * Closes the path, fills it using the even-odd rule to determine the region to fill and strokes it. + */ + + public void ClosePathEoFillStroke() { + content.Append("b*").Append_i(separator); + } + + /** + * Adds an Image to the page. The Image must have + * absolute positioning. + * @param image the Image object + * @throws DocumentException if the Image does not have absolute positioning + */ + public virtual void AddImage(Image image) { + AddImage(image, false); + } + + /** + * Adds an Image to the page. The Image must have + * absolute positioning. The image can be placed inline. + * @param image the Image object + * @param inlineImage true to place this image inline, false otherwise + * @throws DocumentException if the Image does not have absolute positioning + */ + public virtual void AddImage(Image image, bool inlineImage) { + if (!image.HasAbsolutePosition()) + throw new DocumentException("The image must have absolute positioning."); + float[] matrix = image.Matrix; + matrix[Image.CX] = image.AbsoluteX - matrix[Image.CX]; + matrix[Image.CY] = image.AbsoluteY - matrix[Image.CY]; + AddImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], inlineImage); + } + + /** + * Adds an Image to the page. The positioning of the Image + * is done with the transformation matrix. To position an image at (x,y) + * use AddImage(image, image_width, 0, 0, image_height, x, y). + * @param image the Image object + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + * @throws DocumentException on error + */ + public virtual void AddImage(Image image, float a, float b, float c, float d, float e, float f) { + AddImage(image, a, b, c, d, e, f, false); + } + + /** + * Adds an Image to the page. The positioning of the Image + * is done with the transformation matrix. To position an image at (x,y) + * use AddImage(image, image_width, 0, 0, image_height, x, y). The image can be placed inline. + * @param image the Image object + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + * @param inlineImage true to place this image inline, false otherwise + * @throws DocumentException on error + */ + public virtual void AddImage(Image image, float a, float b, float c, float d, float e, float f, bool inlineImage) { + if (image.Layer != null) + BeginLayer(image.Layer); + if (image.IsImgTemplate()) { + writer.AddDirectImageSimple(image); + PdfTemplate template = image.TemplateData; + float w = template.Width; + float h = template.Height; + AddTemplate(template, a / w, b / w, c / h, d / h, e, f); + } + else { + content.Append("q "); + content.Append(a).Append(' '); + content.Append(b).Append(' '); + content.Append(c).Append(' '); + content.Append(d).Append(' '); + content.Append(e).Append(' '); + content.Append(f).Append(" cm"); + if (inlineImage) { + content.Append("\nBI\n"); + PdfImage pimage = new PdfImage(image, "", null); + foreach (PdfName key in pimage.Keys) { + PdfObject value = pimage.Get(key); + String s = (String)abrev[key]; + if (s == null) + continue; + content.Append(s); + bool check = true; + if (key.Equals(PdfName.COLORSPACE) && value.IsArray()) { + ArrayList ar = ((PdfArray)value).ArrayList; + if (ar.Count == 4 + && PdfName.INDEXED.Equals(ar[0]) + && ((PdfObject)ar[1]).IsName() + && ((PdfObject)ar[2]).IsNumber() + && ((PdfObject)ar[3]).IsString() + ) { + check = false; + } + + } + if (check && key.Equals(PdfName.COLORSPACE) && !value.IsName()) { + PdfName cs = writer.GetColorspaceName(); + PageResources prs = PageResources; + prs.AddColor(cs, writer.AddToBody(value).IndirectReference); + value = cs; + } + value.ToPdf(null, content); + content.Append('\n'); + } + content.Append("ID\n"); + pimage.WriteContent(content); + content.Append("\nEI\nQ").Append_i(separator); + } + else { + PdfName name; + PageResources prs = PageResources; + Image maskImage = image.ImageMask; + if (maskImage != null) { + name = writer.AddDirectImageSimple(maskImage); + prs.AddXObject(name, writer.GetImageReference(name)); + } + name = writer.AddDirectImageSimple(image); + name = prs.AddXObject(name, writer.GetImageReference(name)); + content.Append(' ').Append(name.GetBytes()).Append(" Do Q").Append_i(separator); + } + } + if (image.HasBorders()) { + SaveState(); + float w = image.Width; + float h = image.Height; + ConcatCTM(a / w, b / w, c / h, d / h, e, f); + Rectangle(image); + RestoreState(); + } + if (image.Layer != null) + EndLayer(); + Annotation annot = image.Annotation; + if (annot == null) + return; + float[] r = new float[unitRect.Length]; + for (int k = 0; k < unitRect.Length; k += 2) { + r[k] = a * unitRect[k] + c * unitRect[k + 1] + e; + r[k + 1] = b * unitRect[k] + d * unitRect[k + 1] + f; + } + float llx = r[0]; + float lly = r[1]; + float urx = llx; + float ury = lly; + for (int k = 2; k < r.Length; k += 2) { + llx = Math.Min(llx, r[k]); + lly = Math.Min(lly, r[k + 1]); + urx = Math.Max(urx, r[k]); + ury = Math.Max(ury, r[k + 1]); + } + annot = new Annotation(annot); + annot.SetDimensions(llx, lly, urx, ury); + PdfAnnotation an = PdfAnnotationsImp.ConvertAnnotation(writer, annot, new Rectangle(llx, lly, urx, ury)); + if (an == null) + return; + AddAnnotation(an); + } + + /** + * Makes this PdfContentByte empty. + */ + public void Reset() { + content.Reset(); + stateList.Clear(); + state = new GraphicState(); + } + + /** + * Starts the writing of text. + */ + public void BeginText() { + state.xTLM = 0; + state.yTLM = 0; + content.Append("BT").Append_i(separator); + } + + /** + * Ends the writing of text and makes the current font invalid. + */ + public void EndText() { + content.Append("ET").Append_i(separator); + } + + /** + * Saves the graphic state. saveState and + * restoreState must be balanced. + */ + public void SaveState() { + content.Append('q').Append_i(separator); + stateList.Add(new GraphicState(state)); + } + + /** + * Restores the graphic state. saveState and + * restoreState must be balanced. + */ + public void RestoreState() { + content.Append('Q').Append_i(separator); + int idx = stateList.Count - 1; + if (idx < 0) + throw new Exception("Unbalanced save/restore state operators."); + state = (GraphicState)stateList[idx]; + stateList.RemoveAt(idx); + } + + /** + * Sets the character spacing parameter. + * + * @param charSpace a parameter + */ + public void SetCharacterSpacing(float value) { + state.charSpace = value; + content.Append(value).Append(" Tc").Append_i(separator); + } + + /** + * Sets the word spacing parameter. + * + * @param wordSpace a parameter + */ + public void SetWordSpacing(float value) { + state.wordSpace = value; + content.Append(value).Append(" Tw").Append_i(separator); + } + + /** + * Sets the horizontal scaling parameter. + * + * @param scale a parameter + */ + public void SetHorizontalScaling(float value) { + state.scale = value; + content.Append(value).Append(" Tz").Append_i(separator); + } + + /** + * Set the font and the size for the subsequent text writing. + * + * @param bf the font + * @param size the font size in points + */ + public virtual void SetFontAndSize(BaseFont bf, float size) { + CheckWriter(); + if (size < 0.0001f && size > -0.0001f) + throw new ArgumentException("Font size too small: " + size); + state.size = size; + state.fontDetails = writer.AddSimple(bf); + PageResources prs = PageResources; + PdfName name = state.fontDetails.FontName; + name = prs.AddFont(name, state.fontDetails.IndirectReference); + content.Append(name.GetBytes()).Append(' ').Append(size).Append(" Tf").Append_i(separator); + } + + /** + * Sets the text rendering parameter. + * + * @param rendering a parameter + */ + public void SetTextRenderingMode(int value) { + content.Append(value).Append(" Tr").Append_i(separator); + } + + /** + * Sets the text rise parameter. + *

+ * This allows to write text in subscript or basescript mode.

+ * + * @param rise a parameter + */ + public void SetTextRise(float value) { + content.Append(value).Append(" Ts").Append_i(separator); + } + + /** + * A helper to insert into the content stream the text + * converted to bytes according to the font's encoding. + * + * @param text the text to write + */ + private void ShowText2(string text) { + if (state.fontDetails == null) + throw new Exception("Font and size must be set before writing any text"); + byte[] b = state.fontDetails.ConvertToBytes(text); + EscapeString(b, content); + } + + /** + * Shows the text. + * + * @param text the text to write + */ + public void ShowText(string text) { + ShowText2(text); + content.Append("Tj").Append_i(separator); + } + + /** + * Constructs a kern array for a text in a certain font + * @param text the text + * @param font the font + * @return a PdfTextArray + */ + public static PdfTextArray GetKernArray(String text, BaseFont font) { + PdfTextArray pa = new PdfTextArray(); + StringBuilder acc = new StringBuilder(); + int len = text.Length - 1; + char[] c = text.ToCharArray(); + if (len >= 0) + acc.Append(c, 0, 1); + for (int k = 0; k < len; ++k) { + char c2 = c[k + 1]; + int kern = font.GetKerning(c[k], c2); + if (kern == 0) { + acc.Append(c2); + } + else { + pa.Add(acc.ToString()); + acc.Length = 0; + acc.Append(c, k + 1, 1); + pa.Add(-kern); + } + } + pa.Add(acc.ToString()); + return pa; + } + + /** + * Shows the text kerned. + * + * @param text the text to write + */ + public void ShowTextKerned(String text) { + if (state.fontDetails == null) + throw new ArgumentNullException("Font and size must be set before writing any text"); + BaseFont bf = state.fontDetails.BaseFont; + if (bf.HasKernPairs()) + ShowText(GetKernArray(text, bf)); + else + ShowText(text); + } + + /** + * Moves to the next line and shows text. + * + * @param text the text to write + */ + public void NewlineShowText(string text) { + state.yTLM -= state.leading; + ShowText2(text); + content.Append('\'').Append_i(separator); + } + + /** + * Moves to the next line and shows text string, using the given values of the character and word spacing parameters. + * + * @param wordSpacing a parameter + * @param charSpacing a parameter + * @param text the text to write + */ + public void NewlineShowText(float wordSpacing, float charSpacing, string text) { + state.yTLM -= state.leading; + content.Append(wordSpacing).Append(' ').Append(charSpacing); + ShowText2(text); + content.Append("\"").Append_i(separator); + + // The " operator sets charSpace and wordSpace into graphics state + // (cfr PDF reference v1.6, table 5.6) + state.charSpace = charSpacing; + state.wordSpace = wordSpacing; + } + + /** + * Changes the text matrix. + *

+ * Remark: this operation also initializes the current point position.

+ * + * @param a operand 1,1 in the matrix + * @param b operand 1,2 in the matrix + * @param c operand 2,1 in the matrix + * @param d operand 2,2 in the matrix + * @param x operand 3,1 in the matrix + * @param y operand 3,2 in the matrix + */ + public void SetTextMatrix(float a, float b, float c, float d, float x, float y) { + state.xTLM = x; + state.yTLM = y; + content.Append(a).Append(' ').Append(b).Append_i(' ') + .Append(c).Append_i(' ').Append(d).Append_i(' ') + .Append(x).Append_i(' ').Append(y).Append(" Tm").Append_i(separator); + } + + /** + * Changes the text matrix. The first four parameters are {1,0,0,1}. + *

+ * Remark: this operation also initializes the current point position.

+ * + * @param x operand 3,1 in the matrix + * @param y operand 3,2 in the matrix + */ + public void SetTextMatrix(float x, float y) { + SetTextMatrix(1, 0, 0, 1, x, y); + } + + /** + * Moves to the start of the next line, offset from the start of the current line. + * + * @param x x-coordinate of the new current point + * @param y y-coordinate of the new current point + */ + public void MoveText(float x, float y) { + state.xTLM += x; + state.yTLM += y; + content.Append(x).Append(' ').Append(y).Append(" Td").Append_i(separator); + } + + /** + * Moves to the start of the next line, offset from the start of the current line. + *

+ * As a side effect, this sets the leading parameter in the text state.

+ * + * @param x offset of the new current point + * @param y y-coordinate of the new current point + */ + public void MoveTextWithLeading(float x, float y) { + state.xTLM += x; + state.yTLM += y; + state.leading = -y; + content.Append(x).Append(' ').Append(y).Append(" TD").Append_i(separator); + } + + /** + * Moves to the start of the next line. + */ + public void NewlineText() { + state.yTLM -= state.leading; + content.Append("T*").Append_i(separator); + } + + /** + * Gets the size of this content. + * + * @return the size of the content + */ + internal int Size { + get { + return content.Size; + } + } + + /** + * Escapes a byte array according to the PDF conventions. + * + * @param b the byte array to escape + * @return an escaped byte array + */ + internal static byte[] EscapeString(byte[] b) { + ByteBuffer content = new ByteBuffer(); + EscapeString(b, content); + return content.ToByteArray(); + } + + /** + * Escapes a byte array according to the PDF conventions. + * + * @param b the byte array to escape + */ + internal static void EscapeString(byte[] b, ByteBuffer content) { + content.Append_i('('); + for (int k = 0; k < b.Length; ++k) { + byte c = b[k]; + switch ((int)c) { + case '\r': + content.Append("\\r"); + break; + case '\n': + content.Append("\\n"); + break; + case '\t': + content.Append("\\t"); + break; + case '\b': + content.Append("\\b"); + break; + case '\f': + content.Append("\\f"); + break; + case '(': + case ')': + case '\\': + content.Append_i('\\').Append_i(c); + break; + default: + content.Append_i(c); + break; + } + } + content.Append(')'); + } + + /** + * Adds a named outline to the document. + * + * @param outline the outline + * @param name the name for the local destination + */ + public void AddOutline(PdfOutline outline, string name) { + CheckWriter(); + pdf.AddOutline(outline, name); + } + /** + * Gets the root outline. + * + * @return the root outline + */ + public PdfOutline RootOutline { + get { + CheckWriter(); + return pdf.RootOutline; + } + } + + /** + * Computes the width of the given string taking in account + * the current values of "Character spacing", "Word Spacing" + * and "Horizontal Scaling". + * The additional spacing is not computed for the last character + * of the string. + * @param text the string to get width of + * @param kerned the kerning option + * @return the width + */ + + public float GetEffectiveStringWidth(String text, bool kerned) { + BaseFont bf = state.fontDetails.BaseFont; + + float w; + if (kerned) + w = bf.GetWidthPointKerned(text, state.size); + else + w = bf.GetWidthPoint(text, state.size); + + if (state.charSpace != 0.0f && text.Length > 1) { + w += state.charSpace * (text.Length -1); + } + + int ft = bf.FontType; + if (state.wordSpace != 0.0f && (ft == BaseFont.FONT_TYPE_T1 || ft == BaseFont.FONT_TYPE_TT || ft == BaseFont.FONT_TYPE_T3)) { + for (int i = 0; i < (text.Length -1); i++) { + if (text[i] == ' ') + w += state.wordSpace; + } + } + if (state.scale != 100.0) + w = (w * state.scale) / 100.0f; + + //System.out.Println("String width = " + Float.ToString(w)); + return w; + } + + /** + * Shows text right, left or center aligned with rotation. + * @param alignment the alignment can be ALIGN_CENTER, ALIGN_RIGHT or ALIGN_LEFT + * @param text the text to show + * @param x the x pivot position + * @param y the y pivot position + * @param rotation the rotation to be applied in degrees counterclockwise + */ + public void ShowTextAligned(int alignment, String text, float x, float y, float rotation) { + ShowTextAligned(alignment, text, x, y, rotation, false); + } + + private void ShowTextAligned(int alignment, String text, float x, float y, float rotation, bool kerned) { + if (state.fontDetails == null) + throw new Exception("Font and size must be set before writing any text"); + if (rotation == 0) { + switch (alignment) { + case ALIGN_CENTER: + x -= GetEffectiveStringWidth(text, kerned) / 2; + break; + case ALIGN_RIGHT: + x -= GetEffectiveStringWidth(text, kerned); + break; + } + SetTextMatrix(x, y); + if (kerned) + ShowTextKerned(text); + else + ShowText(text); + } + else { + double alpha = rotation * Math.PI / 180.0; + float cos = (float)Math.Cos(alpha); + float sin = (float)Math.Sin(alpha); + float len; + switch (alignment) { + case ALIGN_CENTER: + len = GetEffectiveStringWidth(text, kerned) / 2; + x -= len * cos; + y -= len * sin; + break; + case ALIGN_RIGHT: + len = GetEffectiveStringWidth(text, kerned); + x -= len * cos; + y -= len * sin; + break; + } + SetTextMatrix(cos, sin, -sin, cos, x, y); + if (kerned) + ShowTextKerned(text); + else + ShowText(text); + SetTextMatrix(0f, 0f); + } + } + + /** + * Shows text kerned right, left or center aligned with rotation. + * @param alignment the alignment can be ALIGN_CENTER, ALIGN_RIGHT or ALIGN_LEFT + * @param text the text to show + * @param x the x pivot position + * @param y the y pivot position + * @param rotation the rotation to be applied in degrees counterclockwise + */ + public void ShowTextAlignedKerned(int alignment, String text, float x, float y, float rotation) { + ShowTextAligned(alignment, text, x, y, rotation, true); + } + + /** + * Concatenate a matrix to the current transformation matrix. + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + **/ + public void ConcatCTM(float a, float b, float c, float d, float e, float f) { + content.Append(a).Append(' ').Append(b).Append(' ').Append(c).Append(' '); + content.Append(d).Append(' ').Append(e).Append(' ').Append(f).Append(" cm").Append_i(separator); + } + + /** + * Generates an array of bezier curves to draw an arc. + *

+ * (x1, y1) and (x2, y2) are the corners of the enclosing rectangle. + * Angles, measured in degrees, start with 0 to the right (the positive X + * axis) and increase counter-clockwise. The arc extends from startAng + * to startAng+extent. I.e. startAng=0 and extent=180 yields an openside-down + * semi-circle. + *

+ * The resulting coordinates are of the form float[]{x1,y1,x2,y2,x3,y3, x4,y4} + * such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and + * (x3, y3) as their respective Bezier control points. + *

+ * Note: this code was taken from ReportLab (www.reportlab.com), an excelent + * PDF generator for Python. + * + * @param x1 a corner of the enclosing rectangle + * @param y1 a corner of the enclosing rectangle + * @param x2 a corner of the enclosing rectangle + * @param y2 a corner of the enclosing rectangle + * @param startAng starting angle in degrees + * @param extent angle extent in degrees + * @return a list of float[] with the bezier curves + */ + public static ArrayList BezierArc(float x1, float y1, float x2, float y2, float startAng, float extent) { + float tmp; + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + if (y2 > y1) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + float fragAngle; + int Nfrag; + if (Math.Abs(extent) <= 90f) { + fragAngle = extent; + Nfrag = 1; + } + else { + Nfrag = (int)(Math.Ceiling(Math.Abs(extent)/90f)); + fragAngle = extent / Nfrag; + } + float x_cen = (x1+x2)/2f; + float y_cen = (y1+y2)/2f; + float rx = (x2-x1)/2f; + float ry = (y2-y1)/2f; + float halfAng = (float)(fragAngle * Math.PI / 360.0); + float kappa = (float)(Math.Abs(4.0 / 3.0 * (1.0 - Math.Cos(halfAng)) / Math.Sin(halfAng))); + ArrayList pointList = new ArrayList(); + for (int i = 0; i < Nfrag; ++i) { + float theta0 = (float)((startAng + i*fragAngle) * Math.PI / 180.0); + float theta1 = (float)((startAng + (i+1)*fragAngle) * Math.PI / 180.0); + float cos0 = (float)Math.Cos(theta0); + float cos1 = (float)Math.Cos(theta1); + float sin0 = (float)Math.Sin(theta0); + float sin1 = (float)Math.Sin(theta1); + if (fragAngle > 0f) { + pointList.Add(new float[]{x_cen + rx * cos0, + y_cen - ry * sin0, + x_cen + rx * (cos0 - kappa * sin0), + y_cen - ry * (sin0 + kappa * cos0), + x_cen + rx * (cos1 + kappa * sin1), + y_cen - ry * (sin1 - kappa * cos1), + x_cen + rx * cos1, + y_cen - ry * sin1}); + } + else { + pointList.Add(new float[]{x_cen + rx * cos0, + y_cen - ry * sin0, + x_cen + rx * (cos0 + kappa * sin0), + y_cen - ry * (sin0 - kappa * cos0), + x_cen + rx * (cos1 - kappa * sin1), + y_cen - ry * (sin1 + kappa * cos1), + x_cen + rx * cos1, + y_cen - ry * sin1}); + } + } + return pointList; + } + + /** + * Draws a partial ellipse inscribed within the rectangle x1,y1,x2,y2, + * starting at startAng degrees and covering extent degrees. Angles + * start with 0 to the right (+x) and increase counter-clockwise. + * + * @param x1 a corner of the enclosing rectangle + * @param y1 a corner of the enclosing rectangle + * @param x2 a corner of the enclosing rectangle + * @param y2 a corner of the enclosing rectangle + * @param startAng starting angle in degrees + * @param extent angle extent in degrees + */ + public void Arc(float x1, float y1, float x2, float y2, float startAng, float extent) { + ArrayList ar = BezierArc(x1, y1, x2, y2, startAng, extent); + if (ar.Count == 0) + return; + float[] pt = (float [])ar[0]; + MoveTo(pt[0], pt[1]); + for (int k = 0; k < ar.Count; ++k) { + pt = (float [])ar[k]; + CurveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]); + } + } + + /** + * Draws an ellipse inscribed within the rectangle x1,y1,x2,y2. + * + * @param x1 a corner of the enclosing rectangle + * @param y1 a corner of the enclosing rectangle + * @param x2 a corner of the enclosing rectangle + * @param y2 a corner of the enclosing rectangle + */ + public void Ellipse(float x1, float y1, float x2, float y2) { + Arc(x1, y1, x2, y2, 0f, 360f); + } + + /** + * Create a new colored tiling pattern. + * + * @param width the width of the pattern + * @param height the height of the pattern + * @param xstep the desired horizontal spacing between pattern cells. + * May be either positive or negative, but not zero. + * @param ystep the desired vertical spacing between pattern cells. + * May be either positive or negative, but not zero. + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height, float xstep, float ystep) { + CheckWriter(); + if ( xstep == 0.0f || ystep == 0.0f ) + throw new Exception("XStep or YStep can not be ZERO."); + PdfPatternPainter painter = new PdfPatternPainter(writer); + painter.Width = width; + painter.Height = height; + painter.XStep = xstep; + painter.YStep = ystep; + writer.AddSimplePattern(painter); + return painter; + } + + /** + * Create a new colored tiling pattern. Variables xstep and ystep are set to the same values + * of width and height. + * @param width the width of the pattern + * @param height the height of the pattern + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height) { + return CreatePattern(width, height, width, height); + } + + /** + * Create a new uncolored tiling pattern. + * + * @param width the width of the pattern + * @param height the height of the pattern + * @param xstep the desired horizontal spacing between pattern cells. + * May be either positive or negative, but not zero. + * @param ystep the desired vertical spacing between pattern cells. + * May be either positive or negative, but not zero. + * @param color the default color. Can be null + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height, float xstep, float ystep, Color color) { + CheckWriter(); + if ( xstep == 0.0f || ystep == 0.0f ) + throw new Exception("XStep or YStep can not be ZERO."); + PdfPatternPainter painter = new PdfPatternPainter(writer, color); + painter.Width = width; + painter.Height = height; + painter.XStep = xstep; + painter.YStep = ystep; + writer.AddSimplePattern(painter); + return painter; + } + + /** + * Create a new uncolored tiling pattern. + * Variables xstep and ystep are set to the same values + * of width and height. + * @param width the width of the pattern + * @param height the height of the pattern + * @param color the default color. Can be null + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height, Color color) { + return CreatePattern(width, height, width, height, color); + } + + /** + * Creates a new template. + *

+ * Creates a new template that is nothing more than a form XObject. This template can be included + * in this PdfContentByte or in another template. Templates are only written + * to the output when the document is closed permitting things like showing text in the first page + * that is only defined in the last page. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the templated created + */ + public PdfTemplate CreateTemplate(float width, float height) { + return CreateTemplate(width, height, null); + } + + internal PdfTemplate CreateTemplate(float width, float height, PdfName forcedName) { + CheckWriter(); + PdfTemplate template = new PdfTemplate(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Creates a new appearance to be used with form fields. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the appearance created + */ + public PdfAppearance CreateAppearance(float width, float height) { + return CreateAppearance(width, height, null); + } + + internal PdfAppearance CreateAppearance(float width, float height, PdfName forcedName) { + CheckWriter(); + PdfAppearance template = new PdfAppearance(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Adds a PostScript XObject to this content. + * + * @param psobject the object + */ + public void AddPSXObject(PdfPSXObject psobject) { + CheckWriter(); + PdfName name = writer.AddDirectTemplateSimple(psobject, null); + PageResources prs = PageResources; + name = prs.AddXObject(name, psobject.IndirectReference); + content.Append(name.GetBytes()).Append(" Do").Append_i(separator); + } + + /** + * Adds a template to this content. + * + * @param template the template + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + */ + public virtual void AddTemplate(PdfTemplate template, float a, float b, float c, float d, float e, float f) { + CheckWriter(); + CheckNoPattern(template); + PdfName name = writer.AddDirectTemplateSimple(template, null); + PageResources prs = PageResources; + name = prs.AddXObject(name, template.IndirectReference); + content.Append("q "); + content.Append(a).Append(' '); + content.Append(b).Append(' '); + content.Append(c).Append(' '); + content.Append(d).Append(' '); + content.Append(e).Append(' '); + content.Append(f).Append(" cm "); + content.Append(name.GetBytes()).Append(" Do Q").Append_i(separator); + } + + internal void AddTemplateReference(PdfIndirectReference template, PdfName name, float a, float b, float c, float d, float e, float f) { + CheckWriter(); + PageResources prs = PageResources; + name = prs.AddXObject(name, template); + content.Append("q "); + content.Append(a).Append(' '); + content.Append(b).Append(' '); + content.Append(c).Append(' '); + content.Append(d).Append(' '); + content.Append(e).Append(' '); + content.Append(f).Append(" cm "); + content.Append(name.GetBytes()).Append(" Do Q").Append_i(separator); + } + + /** + * Adds a template to this content. + * + * @param template the template + * @param x the x location of this template + * @param y the y location of this template + */ + public void AddTemplate(PdfTemplate template, float x, float y) { + AddTemplate(template, 1, 0, 0, 1, x, y); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

+ * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for filling paths.

+ *

+ * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

+ *

+ * Following the PDF manual, each operand must be a number between 0 (no ink) and + * 1 (maximum ink). This method however accepts only ints between 0x00 and 0xFF.

+ * + * @param cyan the intensity of cyan + * @param magenta the intensity of magenta + * @param yellow the intensity of yellow + * @param black the intensity of black + */ + + public virtual void SetCMYKColorFill(int cyan, int magenta, int yellow, int black) { + content.Append((float)(cyan & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(magenta & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(yellow & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(black & 0xFF) / 0xFF); + content.Append(" k").Append_i(separator); + } + /** + * Changes the current color for stroking paths (device dependent colors!). + *

+ * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for stroking paths.

+ *

+ * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

+ * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). This method however accepts only ints between 0x00 and 0xFF. + * + * @param cyan the intensity of red + * @param magenta the intensity of green + * @param yellow the intensity of blue + * @param black the intensity of black + */ + + public virtual void SetCMYKColorStroke(int cyan, int magenta, int yellow, int black) { + content.Append((float)(cyan & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(magenta & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(yellow & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(black & 0xFF) / 0xFF); + content.Append(" K").Append_i(separator); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

+ * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for filling paths.

+ *

+ * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

+ *

+ * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). This method however accepts only ints between 0x00 and 0xFF.

+ * + * @param red the intensity of red + * @param green the intensity of green + * @param blue the intensity of blue + */ + + public virtual void SetRGBColorFill(int red, int green, int blue) { + HelperRGB((float)(red & 0xFF) / 0xFF, (float)(green & 0xFF) / 0xFF, (float)(blue & 0xFF) / 0xFF); + content.Append(" rg").Append_i(separator); + } + + /** + * Changes the current color for stroking paths (device dependent colors!). + *

+ * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for stroking paths.

+ *

+ * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

+ * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). This method however accepts only ints between 0x00 and 0xFF. + * + * @param red the intensity of red + * @param green the intensity of green + * @param blue the intensity of blue + */ + + public virtual void SetRGBColorStroke(int red, int green, int blue) { + HelperRGB((float)(red & 0xFF) / 0xFF, (float)(green & 0xFF) / 0xFF, (float)(blue & 0xFF) / 0xFF); + content.Append(" RG").Append_i(separator); + } + + /** Sets the stroke color. color can be an + * ExtendedColor. + * @param color the color + */ + public virtual void SetColorStroke(Color value) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_COLOR, value); + int type = ExtendedColor.GetType(value); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + SetGrayStroke(((GrayColor)value).Gray); + break; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)value; + SetCMYKColorStrokeF(cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black); + break; + } + case ExtendedColor.TYPE_SEPARATION: { + SpotColor spot = (SpotColor)value; + SetColorStroke(spot.PdfSpotColor, spot.Tint); + break; + } + case ExtendedColor.TYPE_PATTERN: { + PatternColor pat = (PatternColor)value; + SetPatternStroke(pat.Painter); + break; + } + case ExtendedColor.TYPE_SHADING: { + ShadingColor shading = (ShadingColor)value; + SetShadingStroke(shading.PdfShadingPattern); + break; + } + default: + SetRGBColorStroke(value.R, value.G, value.B); + break; + } + } + + /** Sets the fill color. color can be an + * ExtendedColor. + * @param color the color + */ + public virtual void SetColorFill(Color value) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_COLOR, value); + int type = ExtendedColor.GetType(value); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + SetGrayFill(((GrayColor)value).Gray); + break; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)value; + SetCMYKColorFillF(cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black); + break; + } + case ExtendedColor.TYPE_SEPARATION: { + SpotColor spot = (SpotColor)value; + SetColorFill(spot.PdfSpotColor, spot.Tint); + break; + } + case ExtendedColor.TYPE_PATTERN: { + PatternColor pat = (PatternColor)value; + SetPatternFill(pat.Painter); + break; + } + case ExtendedColor.TYPE_SHADING: { + ShadingColor shading = (ShadingColor)value; + SetShadingFill(shading.PdfShadingPattern); + break; + } + default: + SetRGBColorFill(value.R, value.G, value.B); + break; + } + } + + /** Sets the fill color to a spot color. + * @param sp the spot color + * @param tint the tint for the spot color. 0 is no color and 1 + * is 100% color + */ + public virtual void SetColorFill(PdfSpotColor sp, float tint) { + CheckWriter(); + state.colorDetails = writer.AddSimple(sp); + PageResources prs = PageResources; + PdfName name = state.colorDetails.ColorName; + name = prs.AddColor(name, state.colorDetails.IndirectReference); + content.Append(name.GetBytes()).Append(" cs ").Append(tint).Append(" scn").Append_i(separator); + } + + /** Sets the stroke color to a spot color. + * @param sp the spot color + * @param tint the tint for the spot color. 0 is no color and 1 + * is 100% color + */ + public virtual void SetColorStroke(PdfSpotColor sp, float tint) { + CheckWriter(); + state.colorDetails = writer.AddSimple(sp); + PageResources prs = PageResources; + PdfName name = state.colorDetails.ColorName; + name = prs.AddColor(name, state.colorDetails.IndirectReference); + content.Append(name.GetBytes()).Append(" CS ").Append(tint).Append(" SCN").Append_i(separator); + } + + /** Sets the fill color to a pattern. The pattern can be + * colored or uncolored. + * @param p the pattern + */ + public virtual void SetPatternFill(PdfPatternPainter p) { + if (p.IsStencil()) { + SetPatternFill(p, p.DefaultColor); + return; + } + CheckWriter(); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" cs ").Append(name.GetBytes()).Append(" scn").Append_i(separator); + } + + /** Outputs the color values to the content. + * @param color The color + * @param tint the tint if it is a spot color, ignored otherwise + */ + internal void OutputColorNumbers(Color color, float tint) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_COLOR, color); + int type = ExtendedColor.GetType(color); + switch (type) { + case ExtendedColor.TYPE_RGB: + content.Append((float)(color.R) / 0xFF); + content.Append(' '); + content.Append((float)(color.G) / 0xFF); + content.Append(' '); + content.Append((float)(color.B) / 0xFF); + break; + case ExtendedColor.TYPE_GRAY: + content.Append(((GrayColor)color).Gray); + break; + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)color; + content.Append(cmyk.Cyan).Append(' ').Append(cmyk.Magenta); + content.Append(' ').Append(cmyk.Yellow).Append(' ').Append(cmyk.Black); + break; + } + case ExtendedColor.TYPE_SEPARATION: + content.Append(tint); + break; + default: + throw new Exception("Invalid color type."); + } + } + + /** Sets the fill color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + */ + public virtual void SetPatternFill(PdfPatternPainter p, Color color) { + if (ExtendedColor.GetType(color) == ExtendedColor.TYPE_SEPARATION) + SetPatternFill(p, color, ((SpotColor)color).Tint); + else + SetPatternFill(p, color, 0); + } + + /** Sets the fill color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + * @param tint the tint if the color is a spot color, ignored otherwise + */ + public virtual void SetPatternFill(PdfPatternPainter p, Color color, float tint) { + CheckWriter(); + if (!p.IsStencil()) + throw new Exception("An uncolored pattern was expected."); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + ColorDetails csDetail = writer.AddSimplePatternColorspace(color); + PdfName cName = prs.AddColor(csDetail.ColorName, csDetail.IndirectReference); + content.Append(cName.GetBytes()).Append(" cs").Append_i(separator); + OutputColorNumbers(color, tint); + content.Append(' ').Append(name.GetBytes()).Append(" scn").Append_i(separator); + } + + /** Sets the stroke color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + */ + public virtual void SetPatternStroke(PdfPatternPainter p, Color color) { + if (ExtendedColor.GetType(color) == ExtendedColor.TYPE_SEPARATION) + SetPatternStroke(p, color, ((SpotColor)color).Tint); + else + SetPatternStroke(p, color, 0); + } + + /** Sets the stroke color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + * @param tint the tint if the color is a spot color, ignored otherwise + */ + public virtual void SetPatternStroke(PdfPatternPainter p, Color color, float tint) { + CheckWriter(); + if (!p.IsStencil()) + throw new Exception("An uncolored pattern was expected."); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + ColorDetails csDetail = writer.AddSimplePatternColorspace(color); + PdfName cName = prs.AddColor(csDetail.ColorName, csDetail.IndirectReference); + content.Append(cName.GetBytes()).Append(" CS").Append_i(separator); + OutputColorNumbers(color, tint); + content.Append(' ').Append(name.GetBytes()).Append(" SCN").Append_i(separator); + } + + /** Sets the stroke color to a pattern. The pattern can be + * colored or uncolored. + * @param p the pattern + */ + public virtual void SetPatternStroke(PdfPatternPainter p) { + if (p.IsStencil()) { + SetPatternStroke(p, p.DefaultColor); + return; + } + CheckWriter(); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" CS ").Append(name.GetBytes()).Append(" SCN").Append_i(separator); + } + + /** + * Paints using a shading object. + * @param shading the shading object + */ + public virtual void PaintShading(PdfShading shading) { + writer.AddSimpleShading(shading); + PageResources prs = PageResources; + PdfName name = prs.AddShading(shading.ShadingName, shading.ShadingReference); + content.Append(name.GetBytes()).Append(" sh").Append_i(separator); + ColorDetails details = shading.ColorDetails; + if (details != null) + prs.AddColor(details.ColorName, details.IndirectReference); + } + + /** + * Paints using a shading pattern. + * @param shading the shading pattern + */ + public virtual void PaintShading(PdfShadingPattern shading) { + PaintShading(shading.Shading); + } + + /** + * Sets the shading fill pattern. + * @param shading the shading pattern + */ + public virtual void SetShadingFill(PdfShadingPattern shading) { + writer.AddSimpleShadingPattern(shading); + PageResources prs = PageResources; + PdfName name = prs.AddPattern(shading.PatternName, shading.PatternReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" cs ").Append(name.GetBytes()).Append(" scn").Append_i(separator); + ColorDetails details = shading.ColorDetails; + if (details != null) + prs.AddColor(details.ColorName, details.IndirectReference); + } + + /** + * Sets the shading stroke pattern + * @param shading the shading pattern + */ + public virtual void SetShadingStroke(PdfShadingPattern shading) { + writer.AddSimpleShadingPattern(shading); + PageResources prs = PageResources; + PdfName name = prs.AddPattern(shading.PatternName, shading.PatternReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" CS ").Append(name.GetBytes()).Append(" SCN").Append_i(separator); + ColorDetails details = shading.ColorDetails; + if (details != null) + prs.AddColor(details.ColorName, details.IndirectReference); + } + + /** Check if we have a valid PdfWriter. + * + */ + protected virtual void CheckWriter() { + if (writer == null) + throw new ArgumentNullException("The writer in PdfContentByte is null."); + } + + /** + * Show an array of text. + * @param text array of text + */ + public void ShowText(PdfTextArray text) { + if (state.fontDetails == null) + throw new ArgumentNullException("Font and size must be set before writing any text"); + content.Append('['); + ArrayList arrayList = text.ArrayList; + bool lastWasNumber = false; + for (int k = 0; k < arrayList.Count; ++k) { + Object obj = arrayList[k]; + if (obj is string) { + ShowText2((string)obj); + lastWasNumber = false; + } + else { + if (lastWasNumber) + content.Append(' '); + else + lastWasNumber = true; + content.Append(((float)obj)); + } + } + content.Append("]TJ").Append_i(separator); + } + + /** + * Gets the PdfWriter in use by this object. + * @return the PdfWriter in use by this object + */ + public PdfWriter PdfWriter { + get { + return writer; + } + } + + /** + * Gets the PdfDocument in use by this object. + * @return the PdfDocument in use by this object + */ + public PdfDocument PdfDocument { + get { + return pdf; + } + } + + /** + * Implements a link to other part of the document. The jump will + * be made to a local destination with the same name, that must exist. + * @param name the name for this link + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public void LocalGoto(string name, float llx, float lly, float urx, float ury) { + pdf.LocalGoto(name, llx, lly, urx, ury); + } + + /** + * The local destination to where a local goto with the same + * name will jump. + * @param name the name of this local destination + * @param destination the PdfDestination with the jump coordinates + * @return true if the local destination was added, + * false if a local destination with the same name + * already exists + */ + public bool LocalDestination(string name, PdfDestination destination) { + return pdf.LocalDestination(name, destination); + } + + /** + * Gets a duplicate of this PdfContentByte. All + * the members are copied by reference but the buffer stays different. + * + * @return a copy of this PdfContentByte + */ + public virtual PdfContentByte Duplicate { + get { + return new PdfContentByte(writer); + } + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param name the name to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public void RemoteGoto(string filename, string name, float llx, float lly, float urx, float ury) { + RemoteGoto(filename, name, llx, lly, urx, ury); + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param page the page to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public void RemoteGoto(string filename, int page, float llx, float lly, float urx, float ury) { + pdf.RemoteGoto(filename, page, llx, lly, urx, ury); + } + /** + * Adds a round rectangle to the current path. + * + * @param x x-coordinate of the starting point + * @param y y-coordinate of the starting point + * @param w width + * @param h height + * @param r radius of the arc corner + */ + public void RoundRectangle(float x, float y, float w, float h, float r) { + if (w < 0) { + x += w; + w = -w; + } + if (h < 0) { + y += h; + h = -h; + } + if (r < 0) + r = -r; + float b = 0.4477f; + MoveTo(x + r, y); + LineTo(x + w - r, y); + CurveTo(x + w - r * b, y, x + w, y + r * b, x + w, y + r); + LineTo(x + w, y + h - r); + CurveTo(x + w, y + h - r * b, x + w - r * b, y + h, x + w - r, y + h); + LineTo(x + r, y + h); + CurveTo(x + r * b, y + h, x, y + h - r * b, x, y + h - r); + LineTo(x, y + r); + CurveTo(x, y + r * b, x + r * b, y, x + r, y); + } + + /** Implements an action in an area. + * @param action the PdfAction + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public virtual void SetAction(PdfAction action, float llx, float lly, float urx, float ury) { + pdf.SetAction(action, llx, lly, urx, ury); + } + + /** Outputs a string directly to the content. + * @param s the string + */ + public void SetLiteral(string s) { + content.Append(s); + } + + /** Outputs a char directly to the content. + * @param c the char + */ + public void SetLiteral(char c) { + content.Append(c); + } + + /** Outputs a float directly to the content. + * @param n the float + */ + public void SetLiteral(float n) { + content.Append(n); + } + + /** Throws an error if it is a pattern. + * @param t the object to check + */ + internal void CheckNoPattern(PdfTemplate t) { + if (t.Type == PdfTemplate.TYPE_PATTERN) + throw new ArgumentException("Invalid use of a pattern. A template was expected."); + } + + /** + * Draws a TextField. + */ + + public void DrawRadioField(float llx, float lly, float urx, float ury, bool on) { + if (llx > urx) { float x = llx; llx = urx; urx = x; } + if (lly > ury) { float y = lly; lly = ury; ury = y; } + // silver circle + SetLineWidth(1); + SetLineCap(1); + SetColorStroke(new Color(0xC0, 0xC0, 0xC0)); + Arc(llx + 1f, lly + 1f, urx - 1f, ury - 1f, 0f, 360f); + Stroke(); + // gray circle-segment + SetLineWidth(1); + SetLineCap(1); + SetColorStroke(new Color(0xA0, 0xA0, 0xA0)); + Arc(llx + 0.5f, lly + 0.5f, urx - 0.5f, ury - 0.5f, 45, 180); + Stroke(); + // black circle-segment + SetLineWidth(1); + SetLineCap(1); + SetColorStroke(new Color(0x00, 0x00, 0x00)); + Arc(llx + 1.5f, lly + 1.5f, urx - 1.5f, ury - 1.5f, 45, 180); + Stroke(); + if (on) { + // gray circle + SetLineWidth(1); + SetLineCap(1); + SetColorFill(new Color(0x00, 0x00, 0x00)); + Arc(llx + 4f, lly + 4f, urx - 4f, ury - 4f, 0, 360); + Fill(); + } + } + + /** + * Draws a TextField. + */ + + public void DrawTextField(float llx, float lly, float urx, float ury) { + if (llx > urx) { float x = llx; llx = urx; urx = x; } + if (lly > ury) { float y = lly; lly = ury; ury = y; } + // silver rectangle not filled + SetColorStroke(new Color(0xC0, 0xC0, 0xC0)); + SetLineWidth(1); + SetLineCap(0); + Rectangle(llx, lly, urx - llx, ury - lly); + Stroke(); + // white rectangle filled + SetLineWidth(1); + SetLineCap(0); + SetColorFill(new Color(0xFF, 0xFF, 0xFF)); + Rectangle(llx + 0.5f, lly + 0.5f, urx - llx - 1f, ury -lly - 1f); + Fill(); + // silver lines + SetColorStroke(new Color(0xC0, 0xC0, 0xC0)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1.5f); + LineTo(urx - 1.5f, lly + 1.5f); + LineTo(urx - 1.5f, ury - 1f); + Stroke(); + // gray lines + SetColorStroke(new Color(0xA0, 0xA0, 0xA0)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1); + LineTo(llx + 1f, ury - 1f); + LineTo(urx - 1f, ury - 1f); + Stroke(); + // black lines + SetColorStroke(new Color(0x00, 0x00, 0x00)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 2f, lly + 2f); + LineTo(llx + 2f, ury - 2f); + LineTo(urx - 2f, ury - 2f); + Stroke(); + } + + /** + * Draws a button. + */ + + public void DrawButton(float llx, float lly, float urx, float ury, string text, BaseFont bf, float size) { + if (llx > urx) { float x = llx; llx = urx; urx = x; } + if (lly > ury) { float y = lly; lly = ury; ury = y; } + // black rectangle not filled + SetColorStroke(new Color(0x00, 0x00, 0x00)); + SetLineWidth(1); + SetLineCap(0); + Rectangle(llx, lly, urx - llx, ury - lly); + Stroke(); + // silver rectangle filled + SetLineWidth(1); + SetLineCap(0); + SetColorFill(new Color(0xC0, 0xC0, 0xC0)); + Rectangle(llx + 0.5f, lly + 0.5f, urx - llx - 1f, ury -lly - 1f); + Fill(); + // white lines + SetColorStroke(new Color(0xFF, 0xFF, 0xFF)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1f); + LineTo(llx + 1f, ury - 1f); + LineTo(urx - 1f, ury - 1f); + Stroke(); + // dark grey lines + SetColorStroke(new Color(0xA0, 0xA0, 0xA0)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1f); + LineTo(urx - 1f, lly + 1f); + LineTo(urx - 1f, ury - 1f); + Stroke(); + // text + ResetRGBColorFill(); + BeginText(); + SetFontAndSize(bf, size); + ShowTextAligned(PdfContentByte.ALIGN_CENTER, text, llx + (urx - llx) / 2, lly + (ury - lly - size) / 2, 0); + EndText(); + } + + internal virtual PageResources PageResources { + get { + return pdf.PageResources; + } + } + + /** Sets the graphic state + * @param gstate the graphic state + */ + public void SetGState(PdfGState gstate) { + PdfObject[] obj = writer.AddSimpleExtGState(gstate); + PageResources prs = PageResources; + PdfName name = prs.AddExtGState((PdfName)obj[0], (PdfIndirectReference)obj[1]); + content.Append(name.GetBytes()).Append(" gs").Append_i(separator); + } + + /** + * Begins a graphic block whose visibility is controled by the layer. + * Blocks can be nested. Each block must be terminated by an {@link #endLayer()}.

+ * Note that nested layers with {@link PdfLayer#addChild(PdfLayer)} only require a single + * call to this method and a single call to {@link #endLayer()}; all the nesting control + * is built in. + * @param layer the layer + */ + public void BeginLayer(IPdfOCG layer) { + if ((layer is PdfLayer) && ((PdfLayer)layer).Title != null) + throw new ArgumentException("A title is not a layer"); + if (layerDepth == null) + layerDepth = new ArrayList(); + if (layer is PdfLayerMembership) { + layerDepth.Add(1); + BeginLayer2(layer); + return; + } + int n = 0; + PdfLayer la = (PdfLayer)layer; + while (la != null) { + if (la.Title == null) { + BeginLayer2(la); + ++n; + } + la = la.Parent; + } + layerDepth.Add(n); + } + + private void BeginLayer2(IPdfOCG layer) { + PdfName name = (PdfName)writer.AddSimpleProperty(layer, layer.Ref)[0]; + PageResources prs = PageResources; + name = prs.AddProperty(name, layer.Ref); + content.Append("/OC ").Append(name.GetBytes()).Append(" BDC").Append_i(separator); + } + + /** + * Ends a layer controled graphic block. It will end the most recent open block. + */ + public void EndLayer() { + int n = 1; + if (layerDepth != null && layerDepth.Count > 0) { + n = (int)layerDepth[layerDepth.Count - 1]; + layerDepth.RemoveAt(layerDepth.Count - 1); + } + while (n-- > 0) + content.Append("EMC").Append_i(separator); + } + + internal virtual void AddAnnotation(PdfAnnotation annot) { + writer.AddAnnotation(annot); + } + + /** + * Sets the default colorspace. + * @param name the name of the colorspace. It can be PdfName.DEFAULTGRAY, PdfName.DEFAULTRGB + * or PdfName.DEFAULTCMYK + * @param obj the colorspace. A null or PdfNull removes any colorspace with the same name + */ + public virtual void SetDefaultColorspace(PdfName name, PdfObject obj) { + PageResources prs = PageResources; + prs.AddDefaultColor(name, obj); + } + + public void Transform(System.Drawing.Drawing2D.Matrix tx) { + float[] c = tx.Elements; + ConcatCTM(c[0], c[1], c[2], c[3], c[4], c[5]); + } + + /** + * Begins a marked content sequence. This sequence will be tagged with the structure struc. + * The same structure can be used several times to connect text that belongs to the same logical segment + * but is in a different location, like the same paragraph crossing to another page, for example. + * @param struc the tagging structure + */ + public void BeginMarkedContentSequence(PdfStructureElement struc) { + PdfObject obj = struc.Get(PdfName.K); + int mark = pdf.GetMarkPoint(); + if (obj != null) { + PdfArray ar = null; + if (obj.IsNumber()) { + ar = new PdfArray(); + ar.Add(obj); + struc.Put(PdfName.K, ar); + } + else if (obj.IsArray()) { + ar = (PdfArray)obj; + if (!((PdfObject)ar.ArrayList[0]).IsNumber()) + throw new ArgumentException("The structure has kids."); + } + else + throw new ArgumentException("Unknown object at /K " + obj.GetType().ToString()); + PdfDictionary dic = new PdfDictionary(PdfName.MCR); + dic.Put(PdfName.PG, writer.CurrentPage); + dic.Put(PdfName.MCID, new PdfNumber(mark)); + ar.Add(dic); + struc.SetPageMark(writer.PageNumber - 1, -1); + } + else { + struc.SetPageMark(writer.PageNumber - 1, mark); + struc.Put(PdfName.PG, writer.CurrentPage); + } + pdf.IncMarkPoint(); + content.Append(struc.Get(PdfName.S).GetBytes()).Append(" <> BDC").Append_i(separator); + } + + /** + * Ends a marked content sequence + */ + public void EndMarkedContentSequence() { + content.Append("EMC").Append_i(separator); + } + + /** + * Begins a marked content sequence. If property is null the mark will be of the type + * BMC otherwise it will be BDC. + * @param tag the tag + * @param property the property + * @param inline true to include the property in the content or false + * to include the property in the resource dictionary with the possibility of reusing + */ + public void BeginMarkedContentSequence(PdfName tag, PdfDictionary property, bool inline) { + if (property == null) { + content.Append(tag.GetBytes()).Append(" BMC").Append_i(separator); + return; + } + content.Append(tag.GetBytes()).Append(' '); + if (inline) + property.ToPdf(writer, content); + else { + PdfObject[] objs; + if (writer.PropertyExists(property)) + objs = writer.AddSimpleProperty(property, null); + else + objs = writer.AddSimpleProperty(property, writer.PdfIndirectReference); + PdfName name = (PdfName)objs[0]; + PageResources prs = PageResources; + name = prs.AddProperty(name, (PdfIndirectReference)objs[1]); + content.Append(name.GetBytes()); + } + content.Append(" BDC").Append_i(separator); + } + + /** + * This is just a shorthand to beginMarkedContentSequence(tag, null, false). + * @param tag the tag + */ + public void BeginMarkedContentSequence(PdfName tag) { + BeginMarkedContentSequence(tag, null, false); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs b/iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs new file mode 100644 index 0000000..78e4a06 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections; +using System.IO; + +/* + * $Id: PdfContentParser.cs,v 1.4 2006/09/17 15:55:03 psoares33 Exp $ + * + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Parses the page or template content. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfContentParser { + + /** + * Commands have this type. + */ + public const int COMMAND_TYPE = 200; + /** + * Holds value of property tokeniser. + */ + private PRTokeniser tokeniser; + + /** + * Creates a new instance of PdfContentParser + * @param tokeniser the tokeniser with the content + */ + public PdfContentParser(PRTokeniser tokeniser) { + this.tokeniser = tokeniser; + } + + /** + * Parses a single command from the content. Each command is output as an array of arguments + * having the command itself as the last element. The returned array will be empty if the + * end of content was reached. + * @param ls an ArrayList to use. It will be cleared before using. If it's + * null will create a new ArrayList + * @return the same ArrayList given as argument or a new one + * @throws IOException on error + */ + public ArrayList Parse(ArrayList ls) { + if (ls == null) + ls = new ArrayList(); + else + ls.Clear(); + PdfObject ob = null; + while ((ob = ReadPRObject()) != null) { + ls.Add(ob); + if (ob.Type == COMMAND_TYPE) + break; + } + return ls; + } + + /** + * Gets the tokeniser. + * @return the tokeniser. + */ + public PRTokeniser GetTokeniser() { + return this.tokeniser; + } + + /** + * Sets the tokeniser. + * @param tokeniser the tokeniser + */ + public PRTokeniser Tokeniser { + set { + tokeniser = value; + } + get { + return tokeniser; + } + } + + /** + * Reads a dictionary. The tokeniser must be positioned past the "<<" token. + * @return the dictionary + * @throws IOException on error + */ + public PdfDictionary ReadDictionary() { + PdfDictionary dic = new PdfDictionary(); + while (true) { + if (!NextValidToken()) + throw new IOException("Unexpected end of file."); + if (tokeniser.TokenType == PRTokeniser.TK_END_DIC) + break; + if (tokeniser.TokenType != PRTokeniser.TK_NAME) + throw new IOException("Dictionary key is not a name."); + PdfName name = new PdfName(tokeniser.StringValue, false); + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_DIC) + throw new IOException("Unexpected '>>'"); + if (-type == PRTokeniser.TK_END_ARRAY) + throw new IOException("Unexpected ']'"); + dic.Put(name, obj); + } + return dic; + } + + /** + * Reads an array. The tokeniser must be positioned past the "[" token. + * @return an array + * @throws IOException on error + */ + public PdfArray ReadArray() { + PdfArray array = new PdfArray(); + while (true) { + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_ARRAY) + break; + if (-type == PRTokeniser.TK_END_DIC) + throw new IOException("Unexpected '>>'"); + array.Add(obj); + } + return array; + } + + /** + * Reads a pdf object. + * @return the pdf object + * @throws IOException on error + */ + public PdfObject ReadPRObject() { + if (!NextValidToken()) + return null; + int type = tokeniser.TokenType; + switch (type) { + case PRTokeniser.TK_START_DIC: { + PdfDictionary dic = ReadDictionary(); + return dic; + } + case PRTokeniser.TK_START_ARRAY: + return ReadArray(); + case PRTokeniser.TK_STRING: + PdfString str = new PdfString(tokeniser.StringValue, null).SetHexWriting(tokeniser.IsHexString()); + return str; + case PRTokeniser.TK_NAME: + return new PdfName(tokeniser.StringValue, false); + case PRTokeniser.TK_NUMBER: + return new PdfNumber(tokeniser.StringValue); + case PRTokeniser.TK_OTHER: + return new PdfLiteral(COMMAND_TYPE, tokeniser.StringValue); + default: + return new PdfLiteral(-type, tokeniser.StringValue); + } + } + + /** + * Reads the next token skipping over the comments. + * @return true if a token was read, false if the end of content was reached + * @throws IOException on error + */ + public bool NextValidToken() { + while (tokeniser.NextToken()) { + if (tokeniser.TokenType == PRTokeniser.TK_COMMENT) + continue; + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfContents.cs b/iTechSharp/iTextSharp/text/pdf/PdfContents.cs new file mode 100644 index 0000000..271f689 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfContents.cs @@ -0,0 +1,148 @@ +using System; +using System.IO; + +using iTextSharp.text; + +using System.util.zlib; + +/* + * $Id: PdfContents.cs,v 1.4 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfContents is a PdfStream containing the contents (text + graphics) of a PdfPage. + */ + + public class PdfContents : PdfStream { + + internal static byte[] SAVESTATE = DocWriter.GetISOBytes("q\n"); + internal static byte[] RESTORESTATE = DocWriter.GetISOBytes("Q\n"); + internal static byte[] ROTATE90 = DocWriter.GetISOBytes("0 1 -1 0 "); + internal static byte[] ROTATE180 = DocWriter.GetISOBytes("-1 0 0 -1 "); + internal static byte[] ROTATE270 = DocWriter.GetISOBytes("0 -1 1 0 "); + internal static byte[] ROTATEFINAL = DocWriter.GetISOBytes(" cm\n"); + // constructor + + /** + * Constructs a PdfContents-object, containing text and general graphics. + * + * @param under the direct content that is under all others + * @param content the graphics in a page + * @param text the text in a page + * @param secondContent the direct content that is over all others + * @throws BadPdfFormatException on error + */ + + internal PdfContents(PdfContentByte under, PdfContentByte content, PdfContentByte text, PdfContentByte secondContent, Rectangle page) : base() { + Stream ostr = null; + streamBytes = new MemoryStream(); + if (Document.Compress) { + compressed = true; + ostr = new ZDeflaterOutputStream(streamBytes); + } + else + ostr = streamBytes; + int rotation = page.Rotation; + byte[] tmp; + switch (rotation) { + case 90: + ostr.Write(ROTATE90, 0, ROTATE90.Length); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Top)); + ostr.Write(tmp, 0, tmp.Length); + ostr.WriteByte((byte)' '); + ostr.WriteByte((byte)'0'); + ostr.Write(ROTATEFINAL, 0, ROTATEFINAL.Length); + break; + case 180: + ostr.Write(ROTATE180, 0, ROTATE180.Length); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Right)); + ostr.Write(tmp, 0, tmp.Length); + ostr.WriteByte((byte)' '); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Top)); + ostr.Write(tmp, 0, tmp.Length); + ostr.Write(ROTATEFINAL, 0, ROTATEFINAL.Length); + break; + case 270: + ostr.Write(ROTATE270, 0, ROTATE270.Length); + ostr.WriteByte((byte)'0'); + ostr.WriteByte((byte)' '); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Right)); + ostr.Write(tmp, 0, tmp.Length); + ostr.Write(ROTATEFINAL, 0, ROTATEFINAL.Length); + break; + } + if (under.Size > 0) { + ostr.Write(SAVESTATE, 0, SAVESTATE.Length); + under.InternalBuffer.WriteTo(ostr); + ostr.Write(RESTORESTATE, 0, RESTORESTATE.Length); + } + if (content.Size > 0) { + ostr.Write(SAVESTATE, 0, SAVESTATE.Length); + content.InternalBuffer.WriteTo(ostr); + ostr.Write(RESTORESTATE, 0, RESTORESTATE.Length); + } + if (text != null) { + ostr.Write(SAVESTATE, 0, SAVESTATE.Length); + text.InternalBuffer.WriteTo(ostr); + ostr.Write(RESTORESTATE, 0, RESTORESTATE.Length); + } + if (secondContent.Size > 0) { + secondContent.InternalBuffer.WriteTo(ostr); + } + + if (ostr is ZDeflaterOutputStream) + ((ZDeflaterOutputStream)ostr).Finish(); + Put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); + if (compressed) + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCopy.cs b/iTechSharp/iTextSharp/text/pdf/PdfCopy.cs new file mode 100644 index 0000000..df1f91e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCopy.cs @@ -0,0 +1,759 @@ +using System; +using System.Collections; +using System.IO; +using iTextSharp.text; +/* + * $Id: PdfCopy.cs,v 1.24 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * This module by Mark Thompson. Copyright (C) 2002 Mark Thompson + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Make copies of PDF documents. Documents can be edited after reading and + * before writing them out. + * @author Mark Thompson + */ + + public class PdfCopy : PdfWriter { + /** + * This class holds information about indirect references, since they are + * renumbered by iText. + */ + internal class IndirectReferences { + PdfIndirectReference theRef; + bool hasCopied; + internal IndirectReferences(PdfIndirectReference refi) { + theRef = refi; + hasCopied = false; + } + internal void SetCopied() { hasCopied = true; } + internal bool Copied { + get { + return hasCopied; + } + } + internal PdfIndirectReference Ref { + get { + return theRef; + } + } + }; + protected Hashtable indirects; + protected Hashtable indirectMap; + protected int currentObjectNum = 1; + protected PdfReader reader; + protected PdfIndirectReference acroForm; + protected int[] namePtr = {0}; + /** Holds value of property rotateContents. */ + private bool rotateContents = true; + protected internal PdfArray fieldArray; + protected internal Hashtable fieldTemplates; + + /** + * A key to allow us to hash indirect references + */ + protected class RefKey { + internal int num; + internal int gen; + internal RefKey(int num, int gen) { + this.num = num; + this.gen = gen; + } + internal RefKey(PdfIndirectReference refi) { + num = refi.Number; + gen = refi.Generation; + } + internal RefKey(PRIndirectReference refi) { + num = refi.Number; + gen = refi.Generation; + } + public override int GetHashCode() { + return (gen<<16)+num; + } + public override bool Equals(Object o) { + if (!(o is RefKey)) return false; + RefKey other = (RefKey)o; + return this.gen == other.gen && this.num == other.num; + } + public override String ToString() { + return "" + num + " " + gen; + } + } + + /** + * Constructor + * @param document + * @param os outputstream + */ + public PdfCopy(Document document, Stream os) : base(new PdfDocument(), os) { + document.AddDocListener(pdf); + pdf.AddWriter(this); + indirectMap = new Hashtable(); + } + + /** Checks if the content is automatically adjusted to compensate + * the original page rotation. + * @return the auto-rotation status + */ + /** Flags the content to be automatically adjusted to compensate + * the original page rotation. The default is true. + * @param rotateContents true to set auto-rotation, false + * otherwise + */ + public bool RotateContents { + set { + rotateContents = value; + } + get { + return rotateContents; + } + } + + /** + * Grabs a page from the input document + * @param reader the reader of the document + * @param pageNumber which page to get + * @return the page + */ + public override PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { + if (currentPdfReaderInstance != null) { + if (currentPdfReaderInstance.Reader != reader) { + try { + currentPdfReaderInstance.Reader.Close(); + currentPdfReaderInstance.ReaderFile.Close(); + } + catch (IOException) { + // empty on purpose + } + currentPdfReaderInstance = reader.GetPdfReaderInstance(this); + } + } + else { + currentPdfReaderInstance = reader.GetPdfReaderInstance(this); + } + return currentPdfReaderInstance.GetImportedPage(pageNumber); + } + + + /** + * Translate a PRIndirectReference to a PdfIndirectReference + * In addition, translates the object numbers, and copies the + * referenced object to the output file. + * NB: PRIndirectReferences (and PRIndirectObjects) really need to know what + * file they came from, because each file has its own namespace. The translation + * we do from their namespace to ours is *at best* heuristic, and guaranteed to + * fail under some circumstances. + */ + protected virtual PdfIndirectReference CopyIndirect(PRIndirectReference inp) { + PdfIndirectReference theRef; + RefKey key = new RefKey(inp); + IndirectReferences iRef = (IndirectReferences)indirects[key] ; + if (iRef != null) { + theRef = iRef.Ref; + if (iRef.Copied) { + return theRef; + } + } + else { + theRef = body.PdfIndirectReference; + iRef = new IndirectReferences(theRef); + indirects[key] = iRef; + } + PdfObject obj = PdfReader.GetPdfObjectRelease(inp); + if (obj != null && obj.IsDictionary()) { + PdfObject type = PdfReader.GetPdfObjectRelease(((PdfDictionary)obj).Get(PdfName.TYPE)); + if (type != null && PdfName.PAGE.Equals(type)) { + return theRef; + } + } + iRef.SetCopied(); + obj = CopyObject(obj); + AddToBody(obj, theRef); + return theRef; + } + + /** + * Translate a PRDictionary to a PdfDictionary. Also translate all of the + * objects contained in it. + */ + protected PdfDictionary CopyDictionary(PdfDictionary inp) { + PdfDictionary outp = new PdfDictionary(); + PdfObject type = PdfReader.GetPdfObjectRelease(inp.Get(PdfName.TYPE)); + + foreach (PdfName key in inp.Keys) { + PdfObject value = inp.Get(key); + if (type != null && PdfName.PAGE.Equals(type)) { + if (!key.Equals(PdfName.B) && !key.Equals(PdfName.PARENT)) + outp.Put(key, CopyObject(value)); + } + else + outp.Put(key, CopyObject(value)); + } + return outp; + } + + /** + * Translate a PRStream to a PdfStream. The data part copies itself. + */ + protected PdfStream CopyStream(PRStream inp) { + PRStream outp = new PRStream(inp, null); + + foreach (PdfName key in inp.Keys) { + PdfObject value = inp.Get(key); + outp.Put(key, CopyObject(value)); + } + + return outp; + } + + + /** + * Translate a PRArray to a PdfArray. Also translate all of the objects contained + * in it + */ + protected PdfArray CopyArray(PdfArray inp) { + PdfArray outp = new PdfArray(); + + foreach (PdfObject value in inp.ArrayList) { + outp.Add(CopyObject(value)); + } + return outp; + } + + /** + * Translate a PR-object to a Pdf-object + */ + protected PdfObject CopyObject(PdfObject inp) { + if (inp == null) + return PdfNull.PDFNULL; + switch (inp.Type) { + case PdfObject.DICTIONARY: + return CopyDictionary((PdfDictionary)inp); + case PdfObject.INDIRECT: + return CopyIndirect((PRIndirectReference)inp); + case PdfObject.ARRAY: + return CopyArray((PdfArray)inp); + case PdfObject.NUMBER: + case PdfObject.NAME: + case PdfObject.STRING: + case PdfObject.NULL: + case PdfObject.BOOLEAN: + case 0: + return inp; + case PdfObject.STREAM: + return CopyStream((PRStream)inp); + // return in; + default: + if (inp.Type < 0) { + String lit = ((PdfLiteral)inp).ToString(); + if (lit.Equals("true") || lit.Equals("false")) { + return new PdfBoolean(lit); + } + return new PdfLiteral(lit); + } + return null; + } + } + + /** + * convenience method. Given an importedpage, set our "globals" + */ + protected int SetFromIPage(PdfImportedPage iPage) { + int pageNum = iPage.PageNumber; + PdfReaderInstance inst = currentPdfReaderInstance = iPage.PdfReaderInstance; + reader = inst.Reader; + SetFromReader(reader); + return pageNum; + } + + /** + * convenience method. Given a reader, set our "globals" + */ + protected void SetFromReader(PdfReader reader) { + this.reader = reader; + indirects = (Hashtable)indirectMap[reader] ; + if (indirects == null) { + indirects = new Hashtable(); + indirectMap[reader] = indirects; + PdfDictionary catalog = reader.Catalog; + PRIndirectReference refi = null; + PdfObject o = catalog.Get(PdfName.ACROFORM); + if (o == null || o.Type != PdfObject.INDIRECT) + return; + refi = (PRIndirectReference)o; + if (acroForm == null) acroForm = body.PdfIndirectReference; + indirects[new RefKey(refi)] = new IndirectReferences(acroForm); + } + } + /** + * Add an imported page to our output + * @param iPage an imported page + * @throws IOException, BadPdfFormatException + */ + public void AddPage(PdfImportedPage iPage) { + int pageNum = SetFromIPage(iPage); + + PdfDictionary thePage = reader.GetPageN(pageNum); + PRIndirectReference origRef = reader.GetPageOrigRef(pageNum); + reader.ReleasePage(pageNum); + RefKey key = new RefKey(origRef); + PdfIndirectReference pageRef; + IndirectReferences iRef = (IndirectReferences)indirects[key] ; + if (iRef != null && !iRef.Copied) { + pageReferences.Add(iRef.Ref); + iRef.SetCopied(); + } + pageRef = CurrentPage; + if (iRef == null) { + iRef = new IndirectReferences(pageRef); + indirects[key] = iRef; + } + iRef.SetCopied(); + PdfDictionary newPage = CopyDictionary(thePage); + root.AddPage(newPage); + ++currentPageNumber; + } + + /** + * Copy the acroform for an input document. Note that you can only have one, + * we make no effort to merge them. + * @param reader The reader of the input file that is being copied + * @throws IOException, BadPdfFormatException + */ + public void CopyAcroForm(PdfReader reader) { + SetFromReader(reader); + + PdfDictionary catalog = reader.Catalog; + PRIndirectReference hisRef = null; + PdfObject o = catalog.Get(PdfName.ACROFORM); + if (o != null && o.Type == PdfObject.INDIRECT) + hisRef = (PRIndirectReference)o; + if (hisRef == null) return; // bugfix by John Engla + RefKey key = new RefKey(hisRef); + PdfIndirectReference myRef; + IndirectReferences iRef = (IndirectReferences)indirects[key] ; + if (iRef != null) { + acroForm = myRef = iRef.Ref; + } + else { + acroForm = myRef = body.PdfIndirectReference; + iRef = new IndirectReferences(myRef); + indirects[key] = iRef; + } + if (! iRef.Copied) { + iRef.SetCopied(); + PdfDictionary theForm = CopyDictionary((PdfDictionary)PdfReader.GetPdfObject(hisRef)); + AddToBody(theForm, myRef); + } + } + + /* + * the getCatalog method is part of PdfWriter. + * we wrap this so that we can extend it + */ + protected override PdfDictionary GetCatalog(PdfIndirectReference rootObj) { + PdfDictionary theCat = pdf.GetCatalog(rootObj); + if (fieldArray == null) { + if (acroForm != null) theCat.Put(PdfName.ACROFORM, acroForm); + } + else + AddFieldResources(theCat); + WriteOutlines(theCat, false); + return theCat; + } + + private void AddFieldResources(PdfDictionary catalog) { + if (fieldArray == null) + return; + PdfDictionary acroForm = new PdfDictionary(); + catalog.Put(PdfName.ACROFORM, acroForm); + acroForm.Put(PdfName.FIELDS, fieldArray); + acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + if (fieldTemplates.Count == 0) + return; + PdfDictionary dr = new PdfDictionary(); + acroForm.Put(PdfName.DR, dr); + foreach (PdfTemplate template in fieldTemplates.Keys) { + PdfFormField.MergeResources(dr, (PdfDictionary)template.Resources); + } + if (dr.Get(PdfName.ENCODING) == null) + dr.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fonts == null) { + fonts = new PdfDictionary(); + dr.Put(PdfName.FONT, fonts); + } + if (!fonts.Contains(PdfName.HELV)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.HELVETICA); + dic.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + dic.Put(PdfName.NAME, PdfName.HELV); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.HELV, AddToBody(dic).IndirectReference); + } + if (!fonts.Contains(PdfName.ZADB)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS); + dic.Put(PdfName.NAME, PdfName.ZADB); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.ZADB, AddToBody(dic).IndirectReference); + } + } + + /** + * Signals that the Document was closed and that no other + * Elements will be added. + *

+ * The pages-tree is built and written to the outputstream. + * A Catalog is constructed, as well as an Info-object, + * the referencetable is composed and everything is written + * to the outputstream embedded in a Trailer. + */ + + public override void Close() { + if (open) { + PdfReaderInstance ri = currentPdfReaderInstance; + pdf.Close(); + base.Close(); + if (ri != null) { + try { + ri.Reader.Close(); + ri.ReaderFile.Close(); + } + catch (IOException) { + // empty on purpose + } + } + } + } + + public override void AddAnnotation(PdfAnnotation annot) { } + internal override PdfIndirectReference Add(PdfPage page, PdfContents contents) { return null; } + + public override void FreeReader(PdfReader reader) { + indirectMap.Remove(reader); + if (currentPdfReaderInstance != null) { + if (currentPdfReaderInstance.Reader == reader) { + try { + currentPdfReaderInstance.Reader.Close(); + currentPdfReaderInstance.ReaderFile.Close(); + } + catch (IOException) { + // empty on purpose + } + currentPdfReaderInstance = null; + } + } + } + + /** + * Create a page stamp. New content and annotations, including new fields, are allowed. + * The fields added cannot have parents in another pages. This method modifies the PdfReader instance.

+ * The general usage to stamp something in a page is: + *

+ *

+        * PdfImportedPage page = copy.getImportedPage(reader, 1);
+        * PdfCopy.PageStamp ps = copy.createPageStamp(page);
+        * ps.addAnnotation(PdfAnnotation.createText(copy, new Rectangle(50, 180, 70, 200), "Hello", "No Thanks", true, "Comment"));
+        * PdfContentByte under = ps.getUnderContent();
+        * under.addImage(img);
+        * PdfContentByte over = ps.getOverContent();
+        * over.beginText();
+        * over.setFontAndSize(bf, 18);
+        * over.setTextMatrix(30, 30);
+        * over.showText("total page " + totalPage);
+        * over.endText();
+        * ps.alterContents();
+        * copy.addPage(page);
+        * 
+ * @param iPage an imported page + * @return the PageStamp + */ + public PageStamp CreatePageStamp(PdfImportedPage iPage) { + int pageNum = iPage.PageNumber; + PdfReader reader = iPage.PdfReaderInstance.Reader; + PdfDictionary pageN = reader.GetPageN(pageNum); + return new PageStamp(reader, pageN, this); + } + + public class PageStamp { + + PdfDictionary pageN; + PdfCopy.StampContent under; + PdfCopy.StampContent over; + PageResources pageResources; + PdfReader reader; + PdfCopy cstp; + + internal PageStamp(PdfReader reader, PdfDictionary pageN, PdfCopy cstp) { + this.pageN = pageN; + this.reader = reader; + this.cstp = cstp; + } + + public PdfContentByte GetUnderContent(){ + if (under == null) { + if (pageResources == null) { + pageResources = new PageResources(); + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); + pageResources.SetOriginalResources(resources, cstp.namePtr); + } + under = new PdfCopy.StampContent(cstp, pageResources); + } + return under; + } + + public PdfContentByte GetOverContent(){ + if (over == null) { + if (pageResources == null) { + pageResources = new PageResources(); + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); + pageResources.SetOriginalResources(resources, cstp.namePtr); + } + over = new PdfCopy.StampContent(cstp, pageResources); + } + return over; + } + + public void AlterContents() { + if (over == null && under == null) + return; + PdfArray ar = null; + PdfObject content = PdfReader.GetPdfObject(pageN.Get(PdfName.CONTENTS), pageN); + if (content == null) { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + else if (content.IsArray()) { + ar = (PdfArray)content; + } + else if (content.IsStream()) { + ar = new PdfArray(); + ar.Add(pageN.Get(PdfName.CONTENTS)); + pageN.Put(PdfName.CONTENTS, ar); + } + else { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + ByteBuffer out_p = new ByteBuffer(); + if (under != null) { + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(under.InternalBuffer); + out_p.Append(PdfContents.RESTORESTATE); + } + if (over != null) + out_p.Append(PdfContents.SAVESTATE); + PdfStream stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + PdfIndirectReference ref1 = cstp.AddToBody(stream).IndirectReference; + ar.AddFirst(ref1); + out_p.Reset(); + if (over != null) { + out_p.Append(' '); + out_p.Append(PdfContents.RESTORESTATE); + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(over.InternalBuffer); + out_p.Append(PdfContents.RESTORESTATE); + stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + ar.Add(cstp.AddToBody(stream).IndirectReference); + } + pageN.Put(PdfName.RESOURCES, pageResources.Resources); + } + + void ApplyRotation(PdfDictionary pageN, ByteBuffer out_p) { + if (!cstp.rotateContents) + return; + Rectangle page = reader.GetPageSizeWithRotation(pageN); + int rotation = page.Rotation; + switch (rotation) { + case 90: + out_p.Append(PdfContents.ROTATE90); + out_p.Append(page.Top); + out_p.Append(' ').Append('0').Append(PdfContents.ROTATEFINAL); + break; + case 180: + out_p.Append(PdfContents.ROTATE180); + out_p.Append(page.Right); + out_p.Append(' '); + out_p.Append(page.Top); + out_p.Append(PdfContents.ROTATEFINAL); + break; + case 270: + out_p.Append(PdfContents.ROTATE270); + out_p.Append('0').Append(' '); + out_p.Append(page.Right); + out_p.Append(PdfContents.ROTATEFINAL); + break; + } + } + + private void AddDocumentField(PdfIndirectReference refi) { + if (cstp.fieldArray == null) + cstp.fieldArray = new PdfArray(); + cstp.fieldArray.Add(refi); + } + + private void ExpandFields(PdfFormField field, ArrayList allAnnots) { + allAnnots.Add(field); + ArrayList kids = field.Kids; + if (kids != null) { + for (int k = 0; k < kids.Count; ++k) + ExpandFields((PdfFormField)kids[k], allAnnots); + } + } + + public void AddAnnotation(PdfAnnotation annot) { + ArrayList allAnnots = new ArrayList(); + if (annot.IsForm()) { + PdfFormField field = (PdfFormField)annot; + if (field.Parent != null) + return; + ExpandFields(field, allAnnots); + if (cstp.fieldTemplates == null) + cstp.fieldTemplates = new Hashtable(); + } + else + allAnnots.Add(annot); + for (int k = 0; k < allAnnots.Count; ++k) { + annot = (PdfAnnotation)allAnnots[k]; + if (annot.IsForm()) { + if (!annot.IsUsed()) { + Hashtable templates = annot.Templates; + if (templates != null) { + foreach (object tpl in templates.Keys) { + cstp.fieldTemplates[tpl] = null; + } + } + } + PdfFormField field = (PdfFormField)annot; + if (field.Parent == null) + AddDocumentField(field.IndirectReference); + } + if (annot.IsAnnotation()) { + PdfObject pdfobj = PdfReader.GetPdfObject(pageN.Get(PdfName.ANNOTS), pageN); + PdfArray annots = null; + if (pdfobj == null || !pdfobj.IsArray()) { + annots = new PdfArray(); + pageN.Put(PdfName.ANNOTS, annots); + } + else + annots = (PdfArray)pdfobj; + annots.Add(annot.IndirectReference); + if (!annot.IsUsed()) { + PdfRectangle rect = (PdfRectangle)annot.Get(PdfName.RECT); + if (rect != null && (rect.Left != 0 || rect.Right != 0 || rect.Top != 0 || rect.Bottom != 0)) { + int rotation = reader.GetPageRotation(pageN); + Rectangle pageSize = reader.GetPageSizeWithRotation(pageN); + switch (rotation) { + case 90: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Top - rect.Bottom, + rect.Left, + pageSize.Top - rect.Top, + rect.Right)); + break; + case 180: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Right - rect.Left, + pageSize.Top - rect.Bottom, + pageSize.Right - rect.Right, + pageSize.Top - rect.Top)); + break; + case 270: + annot.Put(PdfName.RECT, new PdfRectangle( + rect.Bottom, + pageSize.Right - rect.Left, + rect.Top, + pageSize.Right - rect.Right)); + break; + } + } + } + } + if (!annot.IsUsed()) { + annot.SetUsed(); + cstp.AddToBody(annot, annot.IndirectReference); + } + } + } + } + + public class StampContent : PdfContentByte { + PageResources pageResources; + + /** Creates a new instance of StampContent */ + internal StampContent(PdfWriter writer, PageResources pageResources) : base(writer) { + this.pageResources = pageResources; + } + + /** + * Gets a duplicate of this PdfContentByte. All + * the members are copied by reference but the buffer stays different. + * + * @return a copy of this PdfContentByte + */ + public override PdfContentByte Duplicate { + get { + return new PdfCopy.StampContent(writer, pageResources); + } + } + + internal override PageResources PageResources { + get { + return pageResources; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs b/iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs new file mode 100644 index 0000000..0704eb7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections; +using System.IO; +using iTextSharp.text.pdf.interfaces; +using Org.BouncyCastle.X509; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Concatenates PDF documents including form fields. The rules for the form field + * concatenation are the same as in Acrobat. All the documents are kept in memory unlike + * PdfCopy. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfCopyFields : IPdfViewerPreferences, IPdfEncryptionSettings { + + private PdfCopyFieldsImp fc; + + /** + * Creates a new instance. + * @param os the output stream + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfCopyFields(Stream os) { + fc = new PdfCopyFieldsImp(os); + } + + /** + * Creates a new instance. + * @param os the output stream + * @param pdfVersion the pdf version the output will have + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfCopyFields(Stream os, char pdfVersion) { + fc = new PdfCopyFieldsImp(os, pdfVersion); + } + + /** + * Concatenates a PDF document. + * @param reader the PDF document + * @throws DocumentException on error + */ + public void AddDocument(PdfReader reader) { + fc.AddDocument(reader); + } + + /** + * Concatenates a PDF document selecting the pages to keep. The pages are described as a + * List of Integer. The page ordering can be changed but + * no page repetitions are allowed. + * @param reader the PDF document + * @param pagesToKeep the pages to keep + * @throws DocumentException on error + */ + public void AddDocument(PdfReader reader, ArrayList pagesToKeep) { + fc.AddDocument(reader, pagesToKeep); + } + + /** + * Concatenates a PDF document selecting the pages to keep. The pages are described as + * ranges. The page ordering can be changed but + * no page repetitions are allowed. + * @param reader the PDF document + * @param ranges the comma separated ranges as described in {@link SequenceList} + * @throws DocumentException on error + */ + public void AddDocument(PdfReader reader, String ranges) { + fc.AddDocument(reader, SequenceList.Expand(ranges, reader.NumberOfPages)); + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + fc.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? PdfWriter.STANDARD_ENCRYPTION_128 : PdfWriter.STANDARD_ENCRYPTION_40); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param strength true for 128 bit key length. false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { + SetEncryption(DocWriter.GetISOBytes(userPassword), DocWriter.GetISOBytes(ownerPassword), permissions, strength); + } + + /** + * Closes the output document. + */ + public void Close() { + fc.Close(); + } + + /** + * Opens the document. This is usually not needed as AddDocument() will do it + * automatically. + */ + public void Open() { + fc.OpenDoc(); + } + + /** + * Adds JavaScript to the global document + * @param js the JavaScript + */ + public void AddJavaScript(String js) { + fc.AddJavaScript(js, !PdfEncodings.IsPdfDocEncoding(js)); + } + + /** + * Sets the bookmarks. The list structure is defined in + * {@link SimpleBookmark}. + * @param outlines the bookmarks or null to remove any + */ + public ArrayList Outlines { + set { + fc.Outlines = value; + } + } + + /** Gets the underlying PdfWriter. + * @return the underlying PdfWriter + */ + public PdfWriter Writer { + get { + return fc; + } + } + + /** + * Gets the 1.5 compression status. + * @return true if the 1.5 compression is on + */ + public bool FullCompression { + get { + return fc.FullCompression; + } + } + + /** + * Sets the document's compression to the new 1.5 mode with object streams and xref + * streams. It can be set at any time but once set it can't be unset. + *

+ * If set before opening the document it will also set the pdf version to 1.5. + */ + public void SetFullCompression() { + fc.SetFullCompression(); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfEncryptionSettings#setEncryption(byte[], byte[], int, int) + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { + fc.SetEncryption(userPassword, ownerPassword, permissions, encryptionType); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#addViewerPreference(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfObject) + */ + public void AddViewerPreference(PdfName key, PdfObject value) { + fc.AddViewerPreference(key, value); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#setViewerPreferences(int) + */ + public int ViewerPreferences { + set { + fc.ViewerPreferences = value; + } + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfEncryptionSettings#setEncryption(java.security.cert.Certificate[], int[], int) + */ + public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { + fc.SetEncryption(certs, permissions, encryptionType); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs b/iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs new file mode 100644 index 0000000..d404fc1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs @@ -0,0 +1,600 @@ +using System; +using System.Collections; +using System.IO; +using System.util; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * + * @author psoares + */ + internal class PdfCopyFieldsImp : PdfWriter { + + private static readonly PdfName iTextTag = new PdfName("_iTextTag_"); + private static object zero = 0; + internal ArrayList readers = new ArrayList(); + internal Hashtable readers2intrefs = new Hashtable(); + internal Hashtable pages2intrefs = new Hashtable(); + internal Hashtable visited = new Hashtable(); + internal ArrayList fields = new ArrayList(); + internal RandomAccessFileOrArray file; + internal Hashtable fieldTree = new Hashtable(); + internal ArrayList pageRefs = new ArrayList(); + internal ArrayList pageDics = new ArrayList(); + internal PdfDictionary resources = new PdfDictionary(); + internal PdfDictionary form; + bool closing = false; + internal Document nd; + private Hashtable tabOrder; + private ArrayList calculationOrder = new ArrayList(); + private ArrayList calculationOrderRefs; + + internal PdfCopyFieldsImp(Stream os) : this(os, '\0') { + } + + internal PdfCopyFieldsImp(Stream os, char pdfVersion) : base(new PdfDocument(), os) { + pdf.AddWriter(this); + if (pdfVersion != 0) + base.PdfVersion = pdfVersion; + nd = new Document(); + nd.AddDocListener(pdf); + } + + internal void AddDocument(PdfReader reader, ArrayList pagesToKeep) { + if (!readers2intrefs.ContainsKey(reader) && reader.Tampered) + throw new DocumentException("The document was reused."); + reader = new PdfReader(reader); + reader.SelectPages(pagesToKeep); + if (reader.NumberOfPages == 0) + return; + reader.Tampered = false; + AddDocument(reader); + } + + internal void AddDocument(PdfReader reader) { + if (!reader.IsOpenedWithFullPermissions) + throw new ArgumentException("PdfReader not opened with owner password"); + OpenDoc(); + if (readers2intrefs.ContainsKey(reader)) { + reader = new PdfReader(reader); + } + else { + if (reader.Tampered) + throw new DocumentException("The document was reused."); + reader.ConsolidateNamedDestinations(); + reader.Tampered = true; + } + reader.ShuffleSubsetNames(); + readers2intrefs[reader] = new IntHashtable(); + readers.Add(reader); + int len = reader.NumberOfPages; + IntHashtable refs = new IntHashtable(); + for (int p = 1; p <= len; ++p) { + refs[reader.GetPageOrigRef(p).Number] = 1; + reader.ReleasePage(p); + } + pages2intrefs[reader] = refs; + visited[reader] = new IntHashtable(); + fields.Add(reader.AcroFields); + UpdateCalculationOrder(reader); + } + + private static String GetCOName(PdfReader reader, PRIndirectReference refi) { + String name = ""; + while (refi != null) { + PdfObject obj = PdfReader.GetPdfObject(refi); + if (obj == null || obj.Type != PdfObject.DICTIONARY) + break; + PdfDictionary dic = (PdfDictionary)obj; + PdfString t = (PdfString)PdfReader.GetPdfObject(dic.Get(PdfName.T)); + if (t != null) { + name = t.ToUnicodeString()+ "." + name; + } + refi = (PRIndirectReference)dic.Get(PdfName.PARENT); + } + if (name.EndsWith(".")) + name = name.Substring(0, name.Length - 1); + return name; + } + + private void UpdateCalculationOrder(PdfReader reader) { + PdfDictionary catalog = reader.Catalog; + PdfDictionary acro = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM)); + if (acro == null) + return; + PdfArray co = (PdfArray)PdfReader.GetPdfObject(acro.Get(PdfName.CO)); + if (co == null || co.Size == 0) + return; + AcroFields af = reader.AcroFields; + ArrayList coa = co.ArrayList; + for (int k = 0; k < coa.Count; ++k) { + PdfObject obj = (PdfObject)coa[k]; + if (obj == null || !obj.IsIndirect()) + continue; + String name = GetCOName(reader, (PRIndirectReference)obj) ; + if (af.GetFieldItem(name) == null) + continue; + name = "." + name; + if (calculationOrder.Contains(name)) + continue; + calculationOrder.Add(name); + } + } + + internal void Propagate(PdfObject obj, PdfIndirectReference refo, bool restricted) { + if (obj == null) + return; + // if (refo != null) + // AddToBody(obj, refo); + if (obj is PdfIndirectReference) + return; + switch (obj.Type) { + case PdfObject.DICTIONARY: + case PdfObject.STREAM: { + PdfDictionary dic = (PdfDictionary)obj; + foreach (PdfName key in dic.Keys) { + if (restricted && (key.Equals(PdfName.PARENT) || key.Equals(PdfName.KIDS))) + continue; + PdfObject ob = dic.Get(key); + if (ob != null && ob.IsIndirect()) { + PRIndirectReference ind = (PRIndirectReference)ob; + if (!SetVisited(ind) && !IsPage(ind)) { + PdfIndirectReference refi = GetNewReference(ind); + Propagate(PdfReader.GetPdfObjectRelease(ind), refi, restricted); + } + } + else + Propagate(ob, null, restricted); + } + break; + } + case PdfObject.ARRAY: { + ArrayList list = ((PdfArray)obj).ArrayList; + //PdfArray arr = new PdfArray(); + foreach (PdfObject ob in list) { + if (ob != null && ob.IsIndirect()) { + PRIndirectReference ind = (PRIndirectReference)ob; + if (!IsVisited(ind) && !IsPage(ind)) { + PdfIndirectReference refi = GetNewReference(ind); + Propagate(PdfReader.GetPdfObjectRelease(ind), refi, restricted); + } + } + else + Propagate(ob, null, restricted); + } + break; + } + case PdfObject.INDIRECT: { + throw new Exception("Reference pointing to reference."); + } + } + } + + private void AdjustTabOrder(PdfArray annots, PdfIndirectReference ind, PdfNumber nn) { + int v = nn.IntValue; + ArrayList t = (ArrayList)tabOrder[annots] ; + if (t == null) { + t = new ArrayList(); + int size = annots.Size - 1; + for (int k = 0; k < size; ++k) { + t.Add(zero); + } + t.Add(v); + tabOrder[annots] = t; + annots.Add(ind); + } + else { + int size = t.Count - 1; + for (int k = size; k >= 0; --k) { + if ((int)t[k] <= v) { + t.Insert(k + 1, v); + annots.ArrayList.Insert(k + 1, ind); + size = -2; + break; + } + } + if (size != -2) { + t.Insert(0, v); + annots.ArrayList.Insert(0, ind); + } + } + } + + protected PdfArray BranchForm(Hashtable level, PdfIndirectReference parent, String fname) { + PdfArray arr = new PdfArray(); + foreach (DictionaryEntry entry in level) { + String name = (String)entry.Key; + Object obj = entry.Value; + PdfIndirectReference ind = PdfIndirectReference; + PdfDictionary dic = new PdfDictionary(); + if (parent != null) + dic.Put(PdfName.PARENT, parent); + dic.Put(PdfName.T, new PdfString(name, PdfObject.TEXT_UNICODE)); + String fname2 = fname + "." + name; + int coidx = calculationOrder.IndexOf(fname2); + if (coidx >= 0) + calculationOrderRefs[coidx] = ind; + if (obj is Hashtable) { + dic.Put(PdfName.KIDS, BranchForm((Hashtable)obj, ind, fname2)); + arr.Add(ind); + AddToBody(dic, ind); + } + else { + ArrayList list = (ArrayList)obj; + dic.MergeDifferent((PdfDictionary)list[0]); + if (list.Count == 3) { + dic.MergeDifferent((PdfDictionary)list[2]); + int page = (int)list[1]; + PdfDictionary pageDic = (PdfDictionary)pageDics[page - 1]; + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) { + annots = new PdfArray(); + pageDic.Put(PdfName.ANNOTS, annots); + } + PdfNumber nn = (PdfNumber)dic.Get(iTextTag); + dic.Remove(iTextTag); + AdjustTabOrder(annots, ind, nn); + } + else { + PdfArray kids = new PdfArray(); + for (int k = 1; k < list.Count; k += 2) { + int page = (int)list[k]; + PdfDictionary pageDic = (PdfDictionary)pageDics[page - 1]; + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) { + annots = new PdfArray(); + pageDic.Put(PdfName.ANNOTS, annots); + } + PdfDictionary widget = new PdfDictionary(); + widget.Merge((PdfDictionary)list[k + 1]); + widget.Put(PdfName.PARENT, ind); + PdfNumber nn = (PdfNumber)widget.Get(iTextTag); + widget.Remove(iTextTag); + PdfIndirectReference wref = AddToBody(widget).IndirectReference; + AdjustTabOrder(annots, wref, nn); + kids.Add(wref); + Propagate(widget, null, false); + } + dic.Put(PdfName.KIDS, kids); + } + arr.Add(ind); + AddToBody(dic, ind); + Propagate(dic, null, false); + } + } + return arr; + } + + protected void CreateAcroForms() { + if (fieldTree.Count == 0) + return; + form = new PdfDictionary(); + form.Put(PdfName.DR, resources); + Propagate(resources, null, false); + form.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + tabOrder = new Hashtable(); + calculationOrderRefs = new ArrayList(calculationOrder); + form.Put(PdfName.FIELDS, BranchForm(fieldTree, null, "")); + PdfArray co = new PdfArray(); + for (int k = 0; k < calculationOrderRefs.Count; ++k) { + Object obj = calculationOrderRefs[k]; + if (obj is PdfIndirectReference) + co.Add((PdfIndirectReference)obj); + } + if (co.Size > 0) + form.Put(PdfName.CO, co); + } + + public override void Close() { + if (closing) { + base.Close(); + return; + } + closing = true; + CloseIt(); + } + + protected void CloseIt() { + for (int k = 0; k < readers.Count; ++k) { + ((PdfReader)readers[k]).RemoveFields(); + } + for (int r = 0; r < readers.Count; ++r) { + PdfReader reader = (PdfReader)readers[r]; + for (int page = 1; page <= reader.NumberOfPages; ++page) { + pageRefs.Add(GetNewReference(reader.GetPageOrigRef(page))); + pageDics.Add(reader.GetPageN(page)); + } + } + MergeFields(); + CreateAcroForms(); + for (int r = 0; r < readers.Count; ++r) { + PdfReader reader = (PdfReader)readers[r]; + for (int page = 1; page <= reader.NumberOfPages; ++page) { + PdfDictionary dic = reader.GetPageN(page); + PdfIndirectReference pageRef = GetNewReference(reader.GetPageOrigRef(page)); + PdfIndirectReference parent = root.AddPageRef(pageRef); + dic.Put(PdfName.PARENT, parent); + Propagate(dic, pageRef, false); + } + } + foreach (DictionaryEntry entry in readers2intrefs) { + PdfReader reader = (PdfReader)entry.Key; + try { + file = reader.SafeFile; + file.ReOpen(); + IntHashtable t = (IntHashtable)entry.Value; + int[] keys = t.ToOrderedKeys(); + for (int k = 0; k < keys.Length; ++k) { + PRIndirectReference refi = new PRIndirectReference(reader, keys[k]); + AddToBody(PdfReader.GetPdfObjectRelease(refi), t[keys[k]]); + } + } + finally { + try { + file.Close(); + reader.Close(); + } + catch { + // empty on purpose + } + } + } + pdf.Close(); + } + + internal void AddPageOffsetToField(Hashtable fd, int pageOffset) { + if (pageOffset == 0) + return; + foreach (AcroFields.Item item in fd.Values) { + ArrayList page = item.page; + for (int k = 0; k < page.Count; ++k) + page[k] = (int)page[k] + pageOffset; + } + } + + internal void CreateWidgets(ArrayList list, AcroFields.Item item) { + for (int k = 0; k < item.merged.Count; ++k) { + list.Add(item.page[k]); + PdfDictionary merged = (PdfDictionary)item.merged[k]; + PdfObject dr = merged.Get(PdfName.DR); + if (dr != null) + PdfFormField.MergeResources(resources, (PdfDictionary)PdfReader.GetPdfObject(dr)); + PdfDictionary widget = new PdfDictionary(); + foreach (PdfName key in merged.Keys) { + if (widgetKeys.ContainsKey(key)) + widget.Put(key, merged.Get(key)); + } + widget.Put(iTextTag, new PdfNumber((int)item.tabOrder[k] + 1)); + list.Add(widget); + } + } + + internal void MergeField(String name, AcroFields.Item item) { + Hashtable map = fieldTree; + StringTokenizer tk = new StringTokenizer(name, "."); + if (!tk.HasMoreTokens()) + return; + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (tk.HasMoreTokens()) { + if (obj == null) { + obj = new Hashtable(); + map[s] = obj; + map = (Hashtable)obj; + continue; + } + else if (obj is Hashtable) + map = (Hashtable)obj; + else + return; + } + else { + if (obj is Hashtable) + return; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (obj == null) { + PdfDictionary field = new PdfDictionary(); + foreach (PdfName key in merged.Keys) { + if (fieldKeys.ContainsKey(key)) + field.Put(key, merged.Get(key)); + } + ArrayList list = new ArrayList(); + list.Add(field); + CreateWidgets(list, item); + map[s] = list; + } + else { + ArrayList list = (ArrayList)obj; + PdfDictionary field = (PdfDictionary)list[0]; + PdfName type1 = (PdfName)field.Get(PdfName.FT); + PdfName type2 = (PdfName)merged.Get(PdfName.FT); + if (type1 == null || !type1.Equals(type2)) + return; + int flag1 = 0; + PdfObject f1 = field.Get(PdfName.FF); + if (f1 != null && f1.IsNumber()) + flag1 = ((PdfNumber)f1).IntValue; + int flag2 = 0; + PdfObject f2 = merged.Get(PdfName.FF); + if (f2 != null && f2.IsNumber()) + flag2 = ((PdfNumber)f2).IntValue; + if (type1.Equals(PdfName.BTN)) { + if (((flag1 ^ flag2) & PdfFormField.FF_PUSHBUTTON) != 0) + return; + if ((flag1 & PdfFormField.FF_PUSHBUTTON) == 0 && ((flag1 ^ flag2) & PdfFormField.FF_RADIO) != 0) + return; + } + else if (type1.Equals(PdfName.CH)) { + if (((flag1 ^ flag2) & PdfFormField.FF_COMBO) != 0) + return; + } + CreateWidgets(list, item); + } + return; + } + } + } + + internal void MergeWithMaster(Hashtable fd) { + foreach (DictionaryEntry entry in fd) { + String name = (String)entry.Key; + MergeField(name, (AcroFields.Item)entry.Value); + } + } + + internal void MergeFields() { + int pageOffset = 0; + for (int k = 0; k < fields.Count; ++k) { + Hashtable fd = ((AcroFields)fields[k]).Fields; + AddPageOffsetToField(fd, pageOffset); + MergeWithMaster(fd); + pageOffset += ((PdfReader)readers[k]).NumberOfPages; + } + } + + public override PdfIndirectReference GetPageReference(int page) { + return (PdfIndirectReference)pageRefs[page - 1]; + } + + protected override PdfDictionary GetCatalog(PdfIndirectReference rootObj) { + PdfDictionary cat = pdf.GetCatalog(rootObj); + if (form != null) { + PdfIndirectReference refi = AddToBody(form).IndirectReference; + cat.Put(PdfName.ACROFORM, refi); + } + WriteOutlines(cat, false); + return cat; + } + + protected PdfIndirectReference GetNewReference(PRIndirectReference refi) { + return new PdfIndirectReference(0, GetNewObjectNumber(refi.Reader, refi.Number, 0)); + } + + protected internal override int GetNewObjectNumber(PdfReader reader, int number, int generation) { + IntHashtable refs = (IntHashtable)readers2intrefs[reader]; + int n = refs[number]; + if (n == 0) { + n = IndirectReferenceNumber; + refs[number] = n; + } + return n; + } + + protected bool IsVisited(PdfReader reader, int number, int generation) { + IntHashtable refs = (IntHashtable)readers2intrefs[reader]; + return refs.ContainsKey(number); + } + + protected bool IsVisited(PRIndirectReference refi) { + IntHashtable refs = (IntHashtable)visited[refi.Reader]; + return refs.ContainsKey(refi.Number); + } + + protected bool SetVisited(PRIndirectReference refi) { + IntHashtable refs = (IntHashtable)visited[refi.Reader]; + int old = refs[refi.Number]; + refs[refi.Number] = 1; + return (old != 0); + } + + protected bool IsPage(PRIndirectReference refi) { + IntHashtable refs = (IntHashtable)pages2intrefs[refi.Reader] ; + return refs.ContainsKey(refi.Number); + } + + internal override RandomAccessFileOrArray GetReaderFile(PdfReader reader) { + return file; + } + + public void OpenDoc() { + if (!nd.IsOpen()) + nd.Open(); + } + + protected internal static Hashtable widgetKeys = new Hashtable(); + protected internal static Hashtable fieldKeys = new Hashtable(); + static PdfCopyFieldsImp() { + object one = 1; + widgetKeys[PdfName.SUBTYPE] = one; + widgetKeys[PdfName.CONTENTS] = one; + widgetKeys[PdfName.RECT] = one; + widgetKeys[PdfName.NM] = one; + widgetKeys[PdfName.M] = one; + widgetKeys[PdfName.F] = one; + widgetKeys[PdfName.BS] = one; + widgetKeys[PdfName.BORDER] = one; + widgetKeys[PdfName.AP] = one; + widgetKeys[PdfName.AS] = one; + widgetKeys[PdfName.C] = one; + widgetKeys[PdfName.A] = one; + widgetKeys[PdfName.STRUCTPARENT] = one; + widgetKeys[PdfName.OC] = one; + widgetKeys[PdfName.H] = one; + widgetKeys[PdfName.MK] = one; + widgetKeys[PdfName.DA] = one; + widgetKeys[PdfName.Q] = one; + fieldKeys[PdfName.AA] = one; + fieldKeys[PdfName.FT] = one; + fieldKeys[PdfName.TU] = one; + fieldKeys[PdfName.TM] = one; + fieldKeys[PdfName.FF] = one; + fieldKeys[PdfName.V] = one; + fieldKeys[PdfName.DV] = one; + fieldKeys[PdfName.DS] = one; + fieldKeys[PdfName.RV] = one; + fieldKeys[PdfName.OPT] = one; + fieldKeys[PdfName.MAXLEN] = one; + fieldKeys[PdfName.TI] = one; + fieldKeys[PdfName.I] = one; + fieldKeys[PdfName.LOCK] = one; + fieldKeys[PdfName.SV] = one; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs b/iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs new file mode 100644 index 0000000..386b3d6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs @@ -0,0 +1,142 @@ +using System; +using System.IO; + +using iTextSharp.text; + +/* + * $Id: PdfDashPattern.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfDashPattern defines a dash pattern as described in + * the PDF Reference Manual version 1.3 p 325 (section 8.4.3). + * + * @see PdfArray + */ + + public class PdfDashPattern : PdfArray { + + // membervariables + + /** This is the length of a dash. */ + private float dash = -1; + + /** This is the length of a gap. */ + private float gap = -1; + + /** This is the phase. */ + private float phase = -1; + + // constructors + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern() : base() {} + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern(float dash) : base(new PdfNumber(dash)) { + this.dash = dash; + } + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern(float dash, float gap) : base(new PdfNumber(dash)) { + Add(new PdfNumber(gap)); + this.dash = dash; + this.gap = gap; + } + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern(float dash, float gap, float phase) : base(new PdfNumber(dash)) { + Add(new PdfNumber(gap)); + this.dash = dash; + this.gap = gap; + this.phase = phase; + } + + public void Add(float n) { + Add(new PdfNumber(n)); + } + + /** + * Returns the PDF representation of this PdfArray. + * + * @return an array of bytes + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + os.WriteByte((byte)'['); + + if (dash >= 0) { + new PdfNumber(dash).ToPdf(writer, os); + if (gap >= 0) { + os.WriteByte((byte)' '); + new PdfNumber(gap).ToPdf(writer, os); + } + } + os.WriteByte((byte)']'); + if (phase >=0) { + os.WriteByte((byte)' '); + new PdfNumber(phase).ToPdf(writer, os); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDate.cs b/iTechSharp/iTextSharp/text/pdf/PdfDate.cs new file mode 100644 index 0000000..b189a51 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDate.cs @@ -0,0 +1,215 @@ +using System; +using System.Text; +using System.Globalization; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfDate is the PDF date object. + *

+ * PDF defines a standard date format. The PDF date format closely follows the format + * defined by the international standard ASN.1 (Abstract Syntax Notation One, defined + * in CCITT X.208 or ISO/IEC 8824). A date is a PdfString of the form: + *

+ * (D:YYYYMMDDHHmmSSOHH'mm') + *

+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.2 (page 183-184) + * + * @see PdfString + * @see java.util.GregorianCalendar + */ + + public class PdfDate : PdfString { + + // constructors + + /** + * Constructs a PdfDate-object. + * + * @param d the date that has to be turned into a PdfDate-object + */ + + public PdfDate(DateTime d) : base() { + //d = d.ToUniversalTime(); + + value = d.ToString("\\D\\:yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + string timezone = d.ToString("zzz", DateTimeFormatInfo.InvariantInfo); + timezone = timezone.Replace(":", "'"); + value += timezone + "'"; + } + + /** + * Constructs a PdfDate-object, representing the current day and time. + */ + + public PdfDate() : this(DateTime.Now) {} + + /** + * Adds a number of leading zeros to a given string in order to get a string + * of a certain length. + * + * @param i a given number + * @param length the length of the resulting string + * @return the resulting string + */ + + private static String SetLength(int i, int length) { + return i.ToString().PadLeft(length, '0'); + } + + /** + * Gives the W3C format of the PdfDate. + * @return a formatted date + */ + public String GetW3CDate() { + return GetW3CDate(value); + } + + /** + * Gives the W3C format of the PdfDate. + * @param d the date in the format D:YYYYMMDDHHmmSSOHH'mm' + * @return a formatted date + */ + public static String GetW3CDate(String d) { + if (d.StartsWith("D:")) + d = d.Substring(2); + StringBuilder sb = new StringBuilder(); + if (d.Length < 4) + return "0000"; + sb.Append(d.Substring(0, 4)); //year + d = d.Substring(4); + if (d.Length < 2) + return sb.ToString(); + sb.Append('-').Append(d.Substring(0, 2)); //month + d = d.Substring(2); + if (d.Length < 2) + return sb.ToString(); + sb.Append('-').Append(d.Substring(0, 2)); //day + d = d.Substring(2); + if (d.Length < 2) + return sb.ToString(); + sb.Append('T').Append(d.Substring(0, 2)); //hour + d = d.Substring(2); + if (d.Length < 2) { + sb.Append(":00Z"); + return sb.ToString(); + } + sb.Append(':').Append(d.Substring(0, 2)); //minute + d = d.Substring(2); + if (d.Length < 2) { + sb.Append('Z'); + return sb.ToString(); + } + sb.Append(':').Append(d.Substring(0, 2)); //second + d = d.Substring(2); + if (d.StartsWith("-") || d.StartsWith("+")) { + String sign = d.Substring(0, 1); + d = d.Substring(1); + String h = "00"; + String m = "00"; + if (d.Length >= 2) { + h = d.Substring(0, 2); + if (d.Length > 2) { + d = d.Substring(3); + if (d.Length >= 2) + m = d.Substring(0, 2); + } + sb.Append(sign).Append(h).Append(':').Append(m); + return sb.ToString(); + } + } + sb.Append('Z'); + return sb.ToString(); + } + + public static DateTime Decode(string date) { + if (date.StartsWith("D:")) + date = date.Substring(2); + int year, month = 1, day = 1, hour = 0, minute = 0, second = 0; + int offsetHour = 0, offsetMinute = 0; + char variation = '\0'; + year = int.Parse(date.Substring(0, 4)); + if (date.Length >= 6) { + month = int.Parse(date.Substring(4, 2)); + if (date.Length >= 8) { + day = int.Parse(date.Substring(6, 2)); + if (date.Length >= 10) { + hour = int.Parse(date.Substring(8, 2)); + if (date.Length >= 12) { + minute = int.Parse(date.Substring(10, 2)); + if (date.Length >= 14) { + second = int.Parse(date.Substring(12, 2)); + } + } + } + } + } + DateTime d = new DateTime(year, month, day, hour, minute, second); + if (date.Length <= 14) + return d; + variation = date[14]; + if (variation == 'Z') + return d.ToLocalTime(); + if (date.Length >= 17) { + offsetHour = int.Parse(date.Substring(15, 2)); + if (date.Length >= 20) { + offsetMinute = int.Parse(date.Substring(18, 2)); + } + } + TimeSpan span = new TimeSpan(offsetHour, offsetMinute, 0); + if (variation == '-') + d += span; + else + d -= span; + return d.ToLocalTime(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDestination.cs b/iTechSharp/iTextSharp/text/pdf/PdfDestination.cs new file mode 100644 index 0000000..db36a53 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDestination.cs @@ -0,0 +1,221 @@ +using System; + +/* + * $Id: PdfDestination.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfColor defines a Color (it's a PdfArray containing 3 values). + * + * @see PdfDictionary + */ + + public class PdfDestination : PdfArray { + + // public static member-variables + + /** This is a possible destination type */ + public const int XYZ = 0; + + /** This is a possible destination type */ + public const int FIT = 1; + + /** This is a possible destination type */ + public const int FITH = 2; + + /** This is a possible destination type */ + public const int FITV = 3; + + /** This is a possible destination type */ + public const int FITR = 4; + + /** This is a possible destination type */ + public const int FITB = 5; + + /** This is a possible destination type */ + public const int FITBH = 6; + + /** This is a possible destination type */ + public const int FITBV = 7; + + // member variables + + /** Is the indirect reference to a page already added? */ + private bool status = false; + + // constructors + + /** + * Constructs a new PdfDestination. + *

+ * If type equals FITB, the bounding box of a page + * will fit the window of the Reader. Otherwise the type will be set to + * FIT so that the entire page will fit to the window. + * + * @param type The destination type + */ + + public PdfDestination(int type) : base() { + if (type == FITB) { + Add(PdfName.FITB); + } + else { + Add(PdfName.FIT); + } + } + + /** + * Constructs a new PdfDestination. + *

+ * If type equals FITBH / FITBV, + * the width / height of the bounding box of a page will fit the window + * of the Reader. The parameter will specify the y / x coordinate of the + * top / left edge of the window. If the type equals FITH + * or FITV the width / height of the entire page will fit + * the window and the parameter will specify the y / x coordinate of the + * top / left edge. In all other cases the type will be set to FITH. + * + * @param type the destination type + * @param parameter a parameter to combined with the destination type + */ + + public PdfDestination(int type, float parameter) : base(new PdfNumber(parameter)) { + switch (type) { + default: + AddFirst(PdfName.FITH); + break; + case FITV: + AddFirst(PdfName.FITV); + break; + case FITBH: + AddFirst(PdfName.FITBH); + break; + case FITBV: + AddFirst(PdfName.FITBV); + break; + } + } + + /** Constructs a new PdfDestination. + *

+ * Display the page, with the coordinates (left, top) positioned + * at the top-left corner of the window and the contents of the page magnified + * by the factor zoom. A negative value for any of the parameters left or top, or a + * zoom value of 0 specifies that the current value of that parameter is to be retained unchanged. + * @param type must be a PdfDestination.XYZ + * @param left the left value. Negative to place a null + * @param top the top value. Negative to place a null + * @param zoom The zoom factor. A value of 0 keeps the current value + */ + + public PdfDestination(int type, float left, float top, float zoom) : base(PdfName.XYZ) { + if (left < 0) + Add(PdfNull.PDFNULL); + else + Add(new PdfNumber(left)); + if (top < 0) + Add(PdfNull.PDFNULL); + else + Add(new PdfNumber(top)); + Add(new PdfNumber(zoom)); + } + + /** Constructs a new PdfDestination. + *

+ * Display the page, with its contents magnified just enough + * to fit the rectangle specified by the coordinates left, bottom, right, and top + * entirely within the window both horizontally and vertically. If the required + * horizontal and vertical magnification factors are different, use the smaller of + * the two, centering the rectangle within the window in the other dimension. + * + * @param type must be PdfDestination.FITR + * @param left a parameter + * @param bottom a parameter + * @param right a parameter + * @param top a parameter + * @since iText0.38 + */ + + public PdfDestination(int type, float left, float bottom, float right, float top) : base(PdfName.FITR) { + Add(new PdfNumber(left)); + Add(new PdfNumber(bottom)); + Add(new PdfNumber(right)); + Add(new PdfNumber(top)); + } + + // methods + + /** + * Checks if an indirect reference to a page has been added. + * + * @return true or false + */ + + public bool HasPage() { + return status; + } + + /** Adds the indirect reference of the destination page. + * + * @param page an indirect reference + * @return true if the page reference was added + */ + + public bool AddPage(PdfIndirectReference page) { + if (!status) { + AddFirst(page); + status = true; + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs b/iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs new file mode 100644 index 0000000..a43b1c9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs @@ -0,0 +1,375 @@ +using System; +using System.IO; +using System.Collections; + +/* + * $Id: PdfDictionary.cs,v 1.10 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfDictionary is the Pdf dictionary object. + *

+ * A dictionary is an associative table containing pairs of objects. The first element + * of each pair is called the key and the second element is called the value. + * Unlike dictionaries in the PostScript language, a key must be a PdfName. + * A value can be any kind of PdfObject, including a dictionary. A dictionary is + * generally used to collect and tie together the attributes of a complex object, with each + * key-value pair specifying the name and value of an attribute.
+ * A dictionary is represented by two left angle brackets (<<), followed by a sequence of + * key-value pairs, followed by two right angle brackets (>>).
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.7 (page 40-41). + *

+ * + * @see PdfObject + * @see PdfName + * @see BadPdfFormatException + */ + + public class PdfDictionary : PdfObject { + + // static membervariables (types of dictionary's) + + /** This is a possible type of dictionary */ + public static PdfName FONT = PdfName.FONT; + + /** This is a possible type of dictionary */ + public static PdfName OUTLINES = PdfName.OUTLINES; + + /** This is a possible type of dictionary */ + public static PdfName PAGE = PdfName.PAGE; + + /** This is a possible type of dictionary */ + public static PdfName PAGES = PdfName.PAGES; + + /** This is a possible type of dictionary */ + public static PdfName CATALOG = PdfName.CATALOG; + + // membervariables + + /** This is the type of this dictionary */ + private PdfName dictionaryType = null; + + /** This is the hashmap that contains all the values and keys of the dictionary */ + protected internal Hashtable hashMap; + + // constructors + + /** + * Constructs an empty PdfDictionary-object. + */ + + public PdfDictionary() : base(DICTIONARY) { + hashMap = new Hashtable(); + } + + /** + * Constructs a PdfDictionary-object of a certain type. + * + * @param type a PdfName + */ + + public PdfDictionary(PdfName type) : this() { + dictionaryType = type; + Put(PdfName.TYPE, dictionaryType); + } + + // methods overriding some methods in PdfObject + + /** + * Returns the PDF representation of this PdfDictionary. + * + * @return an array of byte + */ + public override void ToPdf(PdfWriter writer, Stream os) { + os.WriteByte((byte)'<'); + os.WriteByte((byte)'<'); + + // loop over all the object-pairs in the Hashtable + PdfObject value; + foreach (PdfName key in hashMap.Keys) { + value = (PdfObject) hashMap[key]; + key.ToPdf(writer, os); + int type = value.Type; + if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) + os.WriteByte((byte)' '); + value.ToPdf(writer, os); + } + os.WriteByte((byte)'>'); + os.WriteByte((byte)'>'); + } + + + // methods concerning the Hashtable member value + + /** + * Adds a PdfObject and its key to the PdfDictionary. + * If the value is null or PdfNull the key is deleted. + * + * @param key key of the entry (a PdfName) + * @param value value of the entry (a PdfObject) + */ + + public void Put(PdfName key, PdfObject value) { + if (value == null || value.IsNull()) + hashMap.Remove(key); + else + hashMap[key] = value; + } + + /** + * Adds a PdfObject and its key to the PdfDictionary. + * If the value is null it does nothing. + * + * @param key key of the entry (a PdfName) + * @param value value of the entry (a PdfObject) + */ + public void PutEx(PdfName key, PdfObject value) { + if (value == null) + return; + Put(key, value); + } + + /** + * Removes a PdfObject and its key from the PdfDictionary. + * + * @param key key of the entry (a PdfName) + */ + + public void Remove(PdfName key) { + hashMap.Remove(key); + } + + /** + * Gets a PdfObject with a certain key from the PdfDictionary. + * + * @param key key of the entry (a PdfName) + * @return the previous PdfObject corresponding with the key + */ + + public PdfObject Get(PdfName key) { + return (PdfObject) hashMap[key]; + } + + // methods concerning the type of Dictionary + + /** + * Checks if a Dictionary is of the type FONT. + * + * @return true if it is, false if it isn't. + */ + + public bool IsFont() { + return FONT.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type PAGE. + * + * @return true if it is, false if it isn't. + */ + + public bool IsPage() { + return PAGE.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type PAGES. + * + * @return true if it is, false if it isn't. + */ + + public bool IsPages() { + return PAGES.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type CATALOG. + * + * @return true if it is, false if it isn't. + */ + + public bool IsCatalog() { + return CATALOG.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type OUTLINES. + * + * @return true if it is, false if it isn't. + */ + + public bool IsOutlineTree() { + return OUTLINES.Equals(dictionaryType); + } + + public void Merge(PdfDictionary other) { + foreach (object key in other.hashMap.Keys) { + hashMap[key] = other.hashMap[key]; + } + } + + public void MergeDifferent(PdfDictionary other) { + foreach (Object key in other.hashMap.Keys) { + if (!hashMap.ContainsKey(key)) { + hashMap[key] = other.hashMap[key]; + } + } + } + + public ICollection Keys { + get { + return hashMap.Keys; + } + } + + public int Size { + get { + return hashMap.Count; + } + } + + public bool Contains(PdfName key) { + return hashMap.ContainsKey(key); + } + + public virtual IDictionaryEnumerator GetEnumerator() { + return hashMap.GetEnumerator(); + } + + public override String ToString() { + if (Get(PdfName.TYPE) == null) return "Dictionary"; + return "Dictionary of type: " + Get(PdfName.TYPE); + } + + /** + * This function behaves the same as 'get', but will never return an indirect reference, + * it will always look such references up and return the actual object. + * @param key + * @return null, or a non-indirect object + */ + public PdfObject GetDirectObject(PdfName key) { + return PdfReader.GetPdfObject(Get(key)); + } + + /** + * All the getAs functions will return either null, or the specified object type + * This function will automatically look up indirect references. There's one obvious + * exception, the one that will only return an indirect reference. All direct objects + * come back as a null. + * Mark A Storer (2/17/06) + * @param key + * @return the appropriate object in its final type, or null + */ + public PdfDictionary GetAsDict(PdfName key) { + PdfDictionary dict = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsDictionary()) + dict = (PdfDictionary) orig; + return dict; + } + + public PdfArray GetAsArray(PdfName key) { + PdfArray array = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsArray()) + array = (PdfArray) orig; + return array; + } + + public PdfStream GetAsStream(PdfName key) { + PdfStream stream = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsStream()) + stream = (PdfStream) orig; + return stream; + } + + public PdfString GetAsString(PdfName key) { + PdfString str = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsString()) + str = (PdfString) orig; + return str; + } + + public PdfNumber GetAsNumber(PdfName key) { + PdfNumber number = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsNumber()) + number = (PdfNumber) orig; + return number; + } + + public PdfName GetAsName(PdfName key) { + PdfName name = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsName()) + name = (PdfName) orig; + return name; + } + + public PdfBoolean GetAsBoolean(PdfName key) { + PdfBoolean b = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsBoolean()) + b = (PdfBoolean)orig; + return b; + } + + public PdfIndirectReference GetAsIndirectObject( PdfName key ) { + PdfIndirectReference refi = null; + PdfObject orig = Get(key); // not getDirect this time. + if (orig != null && orig.IsIndirect()) + refi = (PdfIndirectReference) orig; + return refi; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDocument.cs b/iTechSharp/iTextSharp/text/pdf/PdfDocument.cs new file mode 100644 index 0000000..434eaaa --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDocument.cs @@ -0,0 +1,2987 @@ +using System; +using System.Collections; +using System.IO; +using System.util.collections; +using iTextSharp.text; +using iTextSharp.text.pdf.intern; +using iTextSharp.text.pdf.draw; +using iTextSharp.text.pdf.collection; +using System.util; +/* + * + * $Id: PdfDocument.cs,v 1.75 2008/05/13 11:25:19 psoares33 Exp $ + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfDocument is the class that is used by PdfWriter + * to translate a Document into a PDF with different pages. + *

+ * A PdfDocument always listens to a Document + * and adds the Pdf representation of every Element that is + * added to the Document. + * + * @see com.lowagie.text.Document + * @see com.lowagie.text.DocListener + * @see PdfWriter + */ + + public class PdfDocument : Document { + + /** + * PdfInfo is the PDF InfoDictionary. + *

+ * A document's trailer may contain a reference to an Info dictionary that provides information + * about the document. This optional dictionary may contain one or more keys, whose values + * should be strings.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.10 (page 120-121) + */ + + public class PdfInfo : PdfDictionary { + + // constructors + + /** + * Construct a PdfInfo-object. + */ + + internal PdfInfo() { + AddProducer(); + AddCreationDate(); + } + + /** + * Constructs a PdfInfo-object. + * + * @param author name of the author of the document + * @param title title of the document + * @param subject subject of the document + */ + + internal PdfInfo(String author, String title, String subject) : base() { + AddTitle(title); + AddSubject(subject); + AddAuthor(author); + } + + /** + * Adds the title of the document. + * + * @param title the title of the document + */ + + internal void AddTitle(String title) { + Put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the subject to the document. + * + * @param subject the subject of the document + */ + + internal void AddSubject(String subject) { + Put(PdfName.SUBJECT, new PdfString(subject, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds some keywords to the document. + * + * @param keywords the keywords of the document + */ + + internal void AddKeywords(String keywords) { + Put(PdfName.KEYWORDS, new PdfString(keywords, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the name of the author to the document. + * + * @param author the name of the author + */ + + internal void AddAuthor(String author) { + Put(PdfName.AUTHOR, new PdfString(author, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the name of the creator to the document. + * + * @param creator the name of the creator + */ + + internal void AddCreator(String creator) { + Put(PdfName.CREATOR, new PdfString(creator, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the name of the producer to the document. + */ + + internal void AddProducer() { + // This line may only be changed by Bruno Lowagie or Paulo Soares + Put(PdfName.PRODUCER, new PdfString(Version)); + // Do not edit the line above! + } + + /** + * Adds the date of creation to the document. + */ + + internal void AddCreationDate() { + PdfString date = new PdfDate(); + Put(PdfName.CREATIONDATE, date); + Put(PdfName.MODDATE, date); + } + + internal void Addkey(String key, String value) { + if (key.Equals("Producer") || key.Equals("CreationDate")) + return; + Put(new PdfName(key), new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** + * PdfCatalog is the PDF Catalog-object. + *

+ * The Catalog is a dictionary that is the root node of the document. It contains a reference + * to the tree of pages contained in the document, a reference to the tree of objects representing + * the document's outline, a reference to the document's article threads, and the list of named + * destinations. In addition, the Catalog indicates whether the document's outline or thumbnail + * page images should be displayed automatically when the document is viewed and wether some location + * other than the first page should be shown when the document is opened.
+ * In this class however, only the reference to the tree of pages is implemented.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.2 (page 67-71) + */ + + internal class PdfCatalog : PdfDictionary { + + internal PdfWriter writer; + // constructors + + /** + * Constructs a PdfCatalog. + * + * @param pages an indirect reference to the root of the document's Pages tree. + * @param writer the writer the catalog applies to + */ + + internal PdfCatalog(PdfIndirectReference pages, PdfWriter writer) : base(CATALOG) { + this.writer = writer; + Put(PdfName.PAGES, pages); + } + + /** + * Adds the names of the named destinations to the catalog. + * @param localDestinations the local destinations + * @param documentJavaScript the javascript used in the document + * @param writer the writer the catalog applies to + */ + internal void AddNames(k_Tree localDestinations, Hashtable documentLevelJS, Hashtable documentFileAttachment, PdfWriter writer) { + if (localDestinations.Count == 0 && documentLevelJS.Count == 0 && documentFileAttachment.Count == 0) + return; + PdfDictionary names = new PdfDictionary(); + if (localDestinations.Count > 0) { + PdfArray ar = new PdfArray(); + foreach (DictionaryEntry entry in localDestinations) { + String name = (String)entry.Key; + Object[] obj = (Object[])entry.Value; + PdfIndirectReference refi = (PdfIndirectReference)obj[1]; + ar.Add(new PdfString(name, null)); + ar.Add(refi); + } + PdfDictionary dests = new PdfDictionary(); + dests.Put(PdfName.NAMES, ar); + names.Put(PdfName.DESTS, writer.AddToBody(dests).IndirectReference); + } + if (documentLevelJS.Count > 0) { + PdfDictionary tree = PdfNameTree.WriteTree(documentLevelJS, writer); + names.Put(PdfName.JAVASCRIPT, writer.AddToBody(tree).IndirectReference); + } + if (documentFileAttachment.Count > 0) { + names.Put(PdfName.EMBEDDEDFILES, writer.AddToBody(PdfNameTree.WriteTree(documentFileAttachment, writer)).IndirectReference); + } + Put(PdfName.NAMES, writer.AddToBody(names).IndirectReference); + } + + internal PdfAction OpenAction { + set { + Put(PdfName.OPENACTION, value); + } + } + + + /** Sets the document level additional actions. + * @param actions dictionary of actions + */ + internal PdfDictionary AdditionalActions { + set { + Put(PdfName.AA, writer.AddToBody(value).IndirectReference); + } + } + } + + // CONSTRUCTING A PdfDocument/PdfWriter INSTANCE + + /** + * Constructs a new PDF document. + * @throws DocumentException on error + */ + internal PdfDocument() { + AddProducer(); + AddCreationDate(); + } + + /** The PdfWriter. */ + protected internal PdfWriter writer; + + /** + * Adds a PdfWriter to the PdfDocument. + * + * @param writer the PdfWriter that writes everything + * what is added to this document to an outputstream. + * @throws DocumentException on error + */ + internal void AddWriter(PdfWriter writer) { + if (this.writer == null) { + this.writer = writer; + annotationsImp = new PdfAnnotationsImp(writer); + return; + } + throw new DocumentException("You can only add a writer to a PdfDocument once."); + } + + // LISTENER METHODS START + + // [L0] ElementListener interface + + /** This is the PdfContentByte object, containing the text. */ + protected internal PdfContentByte text; + + /** This is the PdfContentByte object, containing the borders and other Graphics. */ + protected internal PdfContentByte graphics; + + /** This represents the leading of the lines. */ + protected internal float leading = 0; + + /** + * Getter for the current leading. + * @return the current leading + * @since 2.1.2 + */ + public float Leading { + get { + return leading; + } + } + /** This is the current height of the document. */ + protected internal float currentHeight = 0; + + /** + * Signals that onParagraph is valid (to avoid that a Chapter/Section title is treated as a Paragraph). + * @since 2.1.2 + */ + protected bool isSectionTitle = false; + + /** + * Signals that the current leading has to be subtracted from a YMark object. + * @since 2.1.2 + */ + protected int leadingCount = 0; + + /** This represents the current alignment of the PDF Elements. */ + protected internal int alignment = Element.ALIGN_LEFT; + + /** The current active PdfAction when processing an Anchor. */ + protected internal PdfAction anchorAction = null; + + /** + * Signals that an Element was added to the Document. + * + * @param element the element to add + * @return true if the element was added, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + public override bool Add(IElement element) { + if (writer != null && writer.IsPaused()) { + return false; + } + switch (element.Type) { + + // Information (headers) + case Element.HEADER: + info.Addkey(((Meta)element).Name, ((Meta)element).Content); + break; + case Element.TITLE: + info.AddTitle(((Meta)element).Content); + break; + case Element.SUBJECT: + info.AddSubject(((Meta)element).Content); + break; + case Element.KEYWORDS: + info.AddKeywords(((Meta)element).Content); + break; + case Element.AUTHOR: + info.AddAuthor(((Meta)element).Content); + break; + case Element.CREATOR: + info.AddCreator(((Meta)element).Content); + break; + case Element.PRODUCER: + // you can not change the name of the producer + info.AddProducer(); + break; + case Element.CREATIONDATE: + // you can not set the creation date, only reset it + info.AddCreationDate(); + break; + + // content (text) + case Element.CHUNK: { + // if there isn't a current line available, we make one + if (line == null) { + CarriageReturn(); + } + + // we cast the element to a chunk + PdfChunk chunk = new PdfChunk((Chunk) element, anchorAction); + // we try to add the chunk to the line, until we succeed + { + PdfChunk overflow; + while ((overflow = line.Add(chunk)) != null) { + CarriageReturn(); + chunk = overflow; + chunk.TrimFirstSpace(); + } + } + pageEmpty = false; + if (chunk.IsAttribute(Chunk.NEWPAGE)) { + NewPage(); + } + break; + } + case Element.ANCHOR: { + leadingCount++; + Anchor anchor = (Anchor) element; + String url = anchor.Reference; + leading = anchor.Leading; + if (url != null) { + anchorAction = new PdfAction(url); + } + + // we process the element + element.Process(this); + anchorAction = null; + leadingCount--; + break; + } + case Element.ANNOTATION: { + if (line == null) { + CarriageReturn(); + } + Annotation annot = (Annotation) element; + Rectangle rect = new Rectangle(0, 0); + if (line != null) + rect = new Rectangle(annot.GetLlx(IndentRight - line.WidthLeft), annot.GetLly(IndentTop - currentHeight), annot.GetUrx(IndentRight - line.WidthLeft + 20), annot.GetUry(IndentTop - currentHeight - 20)); + PdfAnnotation an = PdfAnnotationsImp.ConvertAnnotation(writer, annot, rect); + annotationsImp.AddPlainAnnotation(an); + pageEmpty = false; + break; + } + case Element.PHRASE: { + leadingCount++; + // we cast the element to a phrase and set the leading of the document + leading = ((Phrase) element).Leading; + // we process the element + element.Process(this); + leadingCount--; + break; + } + case Element.PARAGRAPH: { + leadingCount++; + // we cast the element to a paragraph + Paragraph paragraph = (Paragraph) element; + + AddSpacing(paragraph.SpacingBefore, leading, paragraph.Font); + + // we adjust the parameters of the document + alignment = paragraph.Alignment; + leading = paragraph.TotalLeading; + + CarriageReturn(); + // we don't want to make orphans/widows + if (currentHeight + line.Height + leading > IndentTop - IndentBottom) { + NewPage(); + } + + indentation.indentLeft += paragraph.IndentationLeft; + indentation.indentRight += paragraph.IndentationRight; + + CarriageReturn(); + + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null && !isSectionTitle) + pageEvent.OnParagraph(writer, this, IndentTop - currentHeight); + + // if a paragraph has to be kept together, we wrap it in a table object + if (paragraph.KeepTogether) { + CarriageReturn(); + PdfPTable table = new PdfPTable(1); + table.WidthPercentage = 100f; + PdfPCell cell = new PdfPCell(); + cell.AddElement(paragraph); + cell.Border = Rectangle.NO_BORDER; + cell.Padding = 0; + table.AddCell(cell); + indentation.indentLeft -= paragraph.IndentationLeft; + indentation.indentRight -= paragraph.IndentationRight; + this.Add(table); + indentation.indentLeft += paragraph.IndentationLeft; + indentation.indentRight += paragraph.IndentationRight; + } + else { + line.SetExtraIndent(paragraph.FirstLineIndent); + element.Process(this); + CarriageReturn(); + AddSpacing(paragraph.SpacingAfter, paragraph.TotalLeading, paragraph.Font); + } + + if (pageEvent != null && !isSectionTitle) + pageEvent.OnParagraphEnd(writer, this, IndentTop - currentHeight); + + alignment = Element.ALIGN_LEFT; + indentation.indentLeft -= paragraph.IndentationLeft; + indentation.indentRight -= paragraph.IndentationRight; + CarriageReturn(); + leadingCount--; + break; + } + case Element.SECTION: + case Element.CHAPTER: { + // Chapters and Sections only differ in their constructor + // so we cast both to a Section + Section section = (Section) element; + IPdfPageEvent pageEvent = writer.PageEvent; + + bool hasTitle = section.NotAddedYet && section.Title != null; + + // if the section is a chapter, we begin a new page + if (section.TriggerNewPage) { + NewPage(); + } + + if (hasTitle) { + float fith = IndentTop - currentHeight; + int rotation = pageSize.Rotation; + if (rotation == 90 || rotation == 180) + fith = pageSize.Height - fith; + PdfDestination destination = new PdfDestination(PdfDestination.FITH, fith); + while (currentOutline.Level >= section.Depth) { + currentOutline = currentOutline.Parent; + } + PdfOutline outline = new PdfOutline(currentOutline, destination, section.GetBookmarkTitle(), section.BookmarkOpen); + currentOutline = outline; + } + + // some values are set + CarriageReturn(); + indentation.sectionIndentLeft += section.IndentationLeft; + indentation.sectionIndentRight += section.IndentationRight; + if (section.NotAddedYet && pageEvent != null) + if (element.Type == Element.CHAPTER) + pageEvent.OnChapter(writer, this, IndentTop - currentHeight, section.Title); + else + pageEvent.OnSection(writer, this, IndentTop - currentHeight, section.Depth, section.Title); + + // the title of the section (if any has to be printed) + if (hasTitle) { + isSectionTitle = true; + Add(section.Title); + isSectionTitle = false; + } + indentation.sectionIndentLeft += section.Indentation; + // we process the section + element.Process(this); + // some parameters are set back to normal again + indentation.sectionIndentLeft -= (section.IndentationLeft + section.Indentation); + indentation.sectionIndentRight -= section.IndentationRight; + + if (section.ElementComplete && pageEvent != null) + if (element.Type == Element.CHAPTER) + pageEvent.OnChapterEnd(writer, this, IndentTop - currentHeight); + else + pageEvent.OnSectionEnd(writer, this, IndentTop - currentHeight); + + break; + } + case Element.LIST: { + // we cast the element to a List + List list = (List) element; + if (list.Alignindent) { + list.NormalizeIndentation(); + } + // we adjust the document + indentation.listIndentLeft += list.IndentationLeft; + indentation.indentRight += list.IndentationRight; + // we process the items in the list + element.Process(this); + // some parameters are set back to normal again + indentation.listIndentLeft -= list.IndentationLeft; + indentation.indentRight -= list.IndentationRight; + CarriageReturn(); + break; + } + case Element.LISTITEM: { + leadingCount++; + // we cast the element to a ListItem + ListItem listItem = (ListItem) element; + + AddSpacing(listItem.SpacingBefore, leading, listItem.Font); + + // we adjust the document + alignment = listItem.Alignment; + indentation.listIndentLeft += listItem.IndentationLeft; + indentation.indentRight += listItem.IndentationRight; + leading = listItem.TotalLeading; + CarriageReturn(); + // we prepare the current line to be able to show us the listsymbol + line.ListItem = listItem; + // we process the item + element.Process(this); + + AddSpacing(listItem.SpacingAfter, listItem.TotalLeading, listItem.Font); + + // if the last line is justified, it should be aligned to the left + if (line.HasToBeJustified()) { + line.ResetAlignment(); + } + // some parameters are set back to normal again + CarriageReturn(); + indentation.listIndentLeft -= listItem.IndentationLeft; + indentation.indentRight -= listItem.IndentationRight; + leadingCount--; + break; + } + case Element.RECTANGLE: { + Rectangle rectangle = (Rectangle) element; + graphics.Rectangle(rectangle); + pageEmpty = false; + break; + } + case Element.PTABLE: { + PdfPTable ptable = (PdfPTable)element; + if (ptable.Size <= ptable.HeaderRows) + break; //nothing to do + + // before every table, we add a new line and flush all lines + EnsureNewLine(); + FlushLines(); + + AddPTable(ptable); + pageEmpty = false; + NewLine(); + break; + } + case Element.MULTI_COLUMN_TEXT: { + EnsureNewLine(); + FlushLines(); + MultiColumnText multiText = (MultiColumnText) element; + float height = multiText.Write(writer.DirectContent, this, IndentTop - currentHeight); + currentHeight += height; + text.MoveText(0, -1f* height); + pageEmpty = false; + break; + } + case Element.TABLE : { + if (element is SimpleTable) { + PdfPTable ptable = ((SimpleTable)element).CreatePdfPTable(); + if (ptable.Size <= ptable.HeaderRows) + break; //nothing to do + + // before every table, we add a new line and flush all lines + EnsureNewLine(); + FlushLines(); + AddPTable(ptable); + pageEmpty = false; + break; + } else if (element is Table) { + + try { + PdfPTable ptable = ((Table)element).CreatePdfPTable(); + if (ptable.Size <= ptable.HeaderRows) + break; //nothing to do + + // before every table, we add a new line and flush all lines + EnsureNewLine(); + FlushLines(); + AddPTable(ptable); + pageEmpty = false; + break; + } + catch (BadElementException) { + // constructing the PdfTable + // Before the table, add a blank line using offset or default leading + float offset = ((Table)element).Offset; + if (float.IsNaN(offset)) + offset = leading; + CarriageReturn(); + lines.Add(new PdfLine(IndentLeft, IndentRight, alignment, offset)); + currentHeight += offset; + AddPdfTable((Table)element); + } + } else { + return false; + } + break; + } + case Element.JPEG: + case Element.JPEG2000: + case Element.IMGRAW: + case Element.IMGTEMPLATE: { + //carriageReturn(); suggestion by Marc Campforts + Add((Image) element); + break; + } + case Element.YMARK: { + IDrawInterface zh = (IDrawInterface)element; + zh.Draw(graphics, IndentLeft, IndentBottom, IndentRight, IndentTop, IndentTop - currentHeight - (leadingCount > 0 ? leading : 0)); + pageEmpty = false; + break; + } + case Element.MARKED: { + MarkedObject mo; + if (element is MarkedSection) { + mo = ((MarkedSection)element).Title; + if (mo != null) { + mo.Process(this); + } + } + mo = (MarkedObject)element; + mo.Process(this); + break; + } + default: + return false; + } + lastElementType = element.Type; + return true; + } + + // [L1] DocListener interface + + /** + * Opens the document. + *

+ * You have to open the document before you can begin to add content + * to the body of the document. + */ + public override void Open() { + if (!open) { + base.Open(); + writer.Open(); + rootOutline = new PdfOutline(writer); + currentOutline = rootOutline; + } + InitPage(); + } + + // [L2] DocListener interface + + /** + * Closes the document. + * + * Once all the content has been written in the body, you have to close + * the body. After that nothing can be written to the body anymore. + */ + public override void Close() { + if (close) { + return; + } + bool wasImage = (imageWait != null); + NewPage(); + if (imageWait != null || wasImage) NewPage(); + if (annotationsImp.HasUnusedAnnotations()) + throw new Exception("Not all annotations could be added to the document (the document doesn't have enough pages)."); + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null) + pageEvent.OnCloseDocument(writer, this); + base.Close(); + + writer.AddLocalDestinations(localDestinations); + CalculateOutlineCount(); + WriteOutlines(); + + writer.Close(); + } + + // [L3] DocListener interface + + protected internal int textEmptySize; + + // [C9] Metadata for the page + /** XMP Metadata for the page. */ + protected byte[] xmpMetadata = null; + /** + * Use this method to set the XMP Metadata. + * @param xmpMetadata The xmpMetadata to set. + */ + public byte[] XmpMetadata { + set { + xmpMetadata = value; + } + } + + /** + * Makes a new page and sends it to the PdfWriter. + * + * @return a bool + * @throws DocumentException on error + */ + public override bool NewPage() { + lastElementType = -1; + if (writer == null || (writer.DirectContent.Size == 0 && writer.DirectContentUnder.Size == 0 && (pageEmpty || writer.IsPaused()))) { + SetNewPageSizeAndMargins(); + return false; + } + if (!open || close) { + throw new Exception("The document isn't open."); + } + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null) + pageEvent.OnEndPage(writer, this); + + //Added to inform any listeners that we are moving to a new page (added by David Freels) + base.NewPage(); + + // the following 2 lines were added by Pelikan Stephan + indentation.imageIndentLeft = 0; + indentation.imageIndentRight = 0; + + // we flush the arraylist with recently written lines + FlushLines(); + // we prepare the elements of the page dictionary + + // [U1] page size and rotation + int rotation = pageSize.Rotation; + + // [C10] + if (writer.IsPdfX()) { + if (thisBoxSize.ContainsKey("art") && thisBoxSize.ContainsKey("trim")) + throw new PdfXConformanceException("Only one of ArtBox or TrimBox can exist in the page."); + if (!thisBoxSize.ContainsKey("art") && !thisBoxSize.ContainsKey("trim")) { + if (thisBoxSize.ContainsKey("crop")) + thisBoxSize["trim"] = thisBoxSize["crop"]; + else + thisBoxSize["trim"] = new PdfRectangle(pageSize, pageSize.Rotation); + } + } + + // [M1] + pageResources.AddDefaultColorDiff(writer.DefaultColorspace); + if (writer.RgbTransparencyBlending) { + PdfDictionary dcs = new PdfDictionary(); + dcs.Put(PdfName.CS, PdfName.DEVICERGB); + pageResources.AddDefaultColorDiff(dcs); + } + PdfDictionary resources = pageResources.Resources; + + // we create the page dictionary + + PdfPage page = new PdfPage(new PdfRectangle(pageSize, rotation), thisBoxSize, resources, rotation); + + // we complete the page dictionary + + // [C9] if there is XMP data to add: add it + if (xmpMetadata != null) { + PdfStream xmp = new PdfStream(xmpMetadata); + xmp.Put(PdfName.TYPE, PdfName.METADATA); + xmp.Put(PdfName.SUBTYPE, PdfName.XML); + PdfEncryption crypto = writer.Encryption; + if (crypto != null && !crypto.IsMetadataEncrypted()) { + PdfArray ar = new PdfArray(); + ar.Add(PdfName.CRYPT); + xmp.Put(PdfName.FILTER, ar); + } + page.Put(PdfName.METADATA, writer.AddToBody(xmp).IndirectReference); + } + + // [U3] page actions: transition, duration, additional actions + if (this.transition!=null) { + page.Put(PdfName.TRANS, this.transition.TransitionDictionary); + transition = null; + } + if (this.duration>0) { + page.Put(PdfName.DUR,new PdfNumber(this.duration)); + duration = 0; + } + if (pageAA != null) { + page.Put(PdfName.AA, writer.AddToBody(pageAA).IndirectReference); + pageAA = null; + } + + // [U4] we add the thumbs + if (thumb != null) { + page.Put(PdfName.THUMB, thumb); + thumb = null; + } + + // [U8] we check if the userunit is defined + if (writer.Userunit > 0f) { + page.Put(PdfName.USERUNIT, new PdfNumber(writer.Userunit)); + } + + // [C5] and [C8] we add the annotations + if (annotationsImp.HasUnusedAnnotations()) { + PdfArray array = annotationsImp.RotateAnnotations(writer, pageSize); + if (array.Size != 0) + page.Put(PdfName.ANNOTS, array); + } + + // [F12] we add tag info + if (writer.IsTagged()) + page.Put(PdfName.STRUCTPARENTS, new PdfNumber(writer.CurrentPageNumber - 1)); + + if (text.Size > textEmptySize) + text.EndText(); + else + text = null; + writer.Add(page, new PdfContents(writer.DirectContentUnder, graphics, text, writer.DirectContent, pageSize)); + // we initialize the new page + InitPage(); + return true; + } + + // [L4] DocListener interface + + /** + * Sets the pagesize. + * + * @param pageSize the new pagesize + * @return true if the page size was set + */ + public override bool SetPageSize(Rectangle pageSize) { + if (writer != null && writer.IsPaused()) { + return false; + } + nextPageSize = new Rectangle(pageSize); + return true; + } + + + /** margin in x direction starting from the left. Will be valid in the next page */ + protected float nextMarginLeft; + + /** margin in x direction starting from the right. Will be valid in the next page */ + protected float nextMarginRight; + + /** margin in y direction starting from the top. Will be valid in the next page */ + protected float nextMarginTop; + + /** margin in y direction starting from the bottom. Will be valid in the next page */ + protected float nextMarginBottom; + + /** + * Sets the margins. + * + * @param marginLeft the margin on the left + * @param marginRight the margin on the right + * @param marginTop the margin on the top + * @param marginBottom the margin on the bottom + * @return a bool + */ + public override bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) { + if (writer != null && writer.IsPaused()) { + return false; + } + nextMarginLeft = marginLeft; + nextMarginRight = marginRight; + nextMarginTop = marginTop; + nextMarginBottom = marginBottom; + return true; + } + + // [L6] DocListener interface + + /** + * @see com.lowagie.text.DocListener#setMarginMirroring(bool) + */ + public override bool SetMarginMirroring(bool MarginMirroring) { + if (writer != null && writer.IsPaused()) { + return false; + } + return base.SetMarginMirroring(MarginMirroring); + } + + // [L7] DocListener interface + + /** + * Sets the page number. + * + * @param pageN the new page number + */ + public override int PageCount { + set { + if (writer != null && writer.IsPaused()) { + return; + } + base.PageCount = value; + } + } + + // [L8] DocListener interface + + /** + * Sets the page number to 0. + */ + public override void ResetPageCount() { + if (writer != null && writer.IsPaused()) { + return; + } + base.ResetPageCount(); + } + + /** + * Changes the header of this document. + * + * @param header the new header + */ + public override HeaderFooter Header { + set { + if (writer != null && writer.IsPaused()) { + return; + } + base.Header = value; + } + } + + /** + * Resets the header of this document. + */ + public override void ResetHeader() { + if (writer != null && writer.IsPaused()) { + return; + } + base.ResetHeader(); + } + + /** + * Changes the footer of this document. + * + * @param footer the new footer + */ + public override HeaderFooter Footer { + set { + if (writer != null && writer.IsPaused()) { + return; + } + base.Footer = value; + } + } + + /** + * Resets the footer of this document. + */ + public override void ResetFooter() { + if (writer != null && writer.IsPaused()) { + return; + } + base.ResetFooter(); + } + + // DOCLISTENER METHODS END + + /** Signals that OnOpenDocument should be called. */ + protected internal bool firstPageEvent = true; + + /** + * Initializes a page. + *

+ * If the footer/header is set, it is printed. + * @throws DocumentException on error + */ + + protected internal void InitPage() { + // the pagenumber is incremented + pageN++; + + // initialisation of some page objects + annotationsImp.ResetAnnotations(); + pageResources = new PageResources(); + + writer.ResetContent(); + graphics = new PdfContentByte(writer); + text = new PdfContentByte(writer); + text.Reset(); + text.BeginText(); + textEmptySize = text.Size; + + markPoint = 0; + SetNewPageSizeAndMargins(); + imageEnd = -1; + indentation.imageIndentRight = 0; + indentation.imageIndentLeft = 0; + indentation.indentBottom = 0; + indentation.indentTop = 0; + currentHeight = 0; + + // backgroundcolors, etc... + thisBoxSize = new Hashtable(boxSize); + if (pageSize.BackgroundColor != null + || pageSize.HasBorders() + || pageSize.BorderColor != null) { + Add(pageSize); + } + + float oldleading = leading; + int oldAlignment = alignment; + // if there is a footer, the footer is added + DoFooter(); + // we move to the left/top position of the page + text.MoveText(Left, Top); + DoHeader(); + pageEmpty = true; + // if there is an image waiting to be drawn, draw it + if (imageWait != null) { + Add(imageWait); + imageWait = null; + } + leading = oldleading; + alignment = oldAlignment; + CarriageReturn(); + + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null) { + if (firstPageEvent) { + pageEvent.OnOpenDocument(writer, this); + } + pageEvent.OnStartPage(writer, this); + } + firstPageEvent = false; + } + + /** The line that is currently being written. */ + protected internal PdfLine line = null; + + /** The lines that are written until now. */ + protected internal ArrayList lines = new ArrayList(); + + /** + * Adds the current line to the list of lines and also adds an empty line. + * @throws DocumentException on error + */ + + protected internal void NewLine() { + lastElementType = -1; + CarriageReturn(); + if (lines != null && lines.Count > 0) { + lines.Add(line); + currentHeight += line.Height; + } + line = new PdfLine(IndentLeft, IndentRight, alignment, leading); + } + + /** + * If the current line is not empty or null, it is added to the arraylist + * of lines and a new empty line is added. + * @throws DocumentException on error + */ + + protected internal void CarriageReturn() { + // the arraylist with lines may not be null + if (lines == null) { + lines = new ArrayList(); + } + // If the current line is not null + if (line != null) { + // we check if the end of the page is reached (bugfix by Francois Gravel) + if (currentHeight + line.Height + leading < IndentTop - IndentBottom) { + // if so nonempty lines are added and the heigt is augmented + if (line.Size > 0) { + currentHeight += line.Height; + lines.Add(line); + pageEmpty = false; + } + } + // if the end of the line is reached, we start a new page + else { + NewPage(); + } + } + if (imageEnd > -1 && currentHeight > imageEnd) { + imageEnd = -1; + indentation.imageIndentRight = 0; + indentation.imageIndentLeft = 0; + } + // a new current line is constructed + line = new PdfLine(IndentLeft, IndentRight, alignment, leading); + } + + /** + * Gets the current vertical page position. + * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects + * for elements that do not terminate the lines they've started because those lines will get + * terminated. + * @return The current vertical page position. + */ + public float GetVerticalPosition(bool ensureNewLine) { + // ensuring that a new line has been started. + if (ensureNewLine) { + EnsureNewLine(); + } + return Top - currentHeight - indentation.indentTop; + } + + /** Holds the type of the last element, that has been added to the document. */ + protected internal int lastElementType = -1; + + /** + * Ensures that a new line has been started. + */ + protected internal void EnsureNewLine() { + if ((lastElementType == Element.PHRASE) || + (lastElementType == Element.CHUNK)) { + NewLine(); + FlushLines(); + } + } + + /** + * Writes all the lines to the text-object. + * + * @return the displacement that was caused + * @throws DocumentException on error + */ + protected internal float FlushLines() { + // checks if the ArrayList with the lines is not null + if (lines == null) { + return 0; + } + // checks if a new Line has to be made. + if (line != null && line.Size > 0) { + lines.Add(line); + line = new PdfLine(IndentLeft, IndentRight, alignment, leading); + } + + // checks if the ArrayList with the lines is empty + if (lines.Count == 0) { + return 0; + } + + // initialisation of some parameters + Object[] currentValues = new Object[2]; + PdfFont currentFont = null; + float displacement = 0; + + currentValues[1] = (float)0; + // looping over all the lines + foreach (PdfLine l in lines) { + + // this is a line in the loop + + float moveTextX = l.IndentLeft - IndentLeft + indentation.indentLeft + indentation.listIndentLeft + indentation.sectionIndentLeft; + text.MoveText(moveTextX, -l.Height); + // is the line preceeded by a symbol? + if (l.ListSymbol != null) { + ColumnText.ShowTextAligned(graphics, Element.ALIGN_LEFT, new Phrase(l.ListSymbol), text.XTLM - l.ListIndent, text.YTLM, 0); + } + + currentValues[0] = currentFont; + + WriteLineToContent(l, text, graphics, currentValues, writer.SpaceCharRatio); + + currentFont = (PdfFont)currentValues[0]; + + displacement += l.Height; + text.MoveText(-moveTextX, 0); + } + lines = new ArrayList(); + return displacement; + } + + /** The characters to be applied the hanging punctuation. */ + internal const String hangingPunctuation = ".,;:'"; + + /** + * Writes a text line to the document. It takes care of all the attributes. + *

+ * Before entering the line position must have been established and the + * text argument must be in text object scope (beginText()). + * @param line the line to be written + * @param text the PdfContentByte where the text will be written to + * @param graphics the PdfContentByte where the graphics will be written to + * @param currentValues the current font and extra spacing values + * @param ratio + * @throws DocumentException on error + */ + internal void WriteLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphics, Object[] currentValues, float ratio) { + PdfFont currentFont = (PdfFont)(currentValues[0]); + float lastBaseFactor = (float)currentValues[1]; + //PdfChunk chunkz; + int numberOfSpaces; + int lineLen; + bool isJustified; + float hangingCorrection = 0; + float hScale = 1; + float lastHScale = float.NaN; + float baseWordSpacing = 0; + float baseCharacterSpacing = 0; + float glueWidth = 0; + + numberOfSpaces = line.NumberOfSpaces; + lineLen = line.GetLineLengthUtf32(); + // does the line need to be justified? + isJustified = line.HasToBeJustified() && (numberOfSpaces != 0 || lineLen > 1); + int separatorCount = line.GetSeparatorCount(); + if (separatorCount > 0) { + glueWidth = line.WidthLeft / separatorCount; + } + else if (isJustified) { + if (line.NewlineSplit && line.WidthLeft >= (lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1))) { + if (line.RTL) { + text.MoveText(line.WidthLeft - lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1), 0); + } + baseWordSpacing = ratio * lastBaseFactor; + baseCharacterSpacing = lastBaseFactor; + } + else { + float width = line.WidthLeft; + PdfChunk last = line.GetChunk(line.Size - 1); + if (last != null) { + String s = last.ToString(); + char c; + if (s.Length > 0 && hangingPunctuation.IndexOf((c = s[s.Length - 1])) >= 0) { + float oldWidth = width; + width += last.Font.Width(c) * 0.4f; + hangingCorrection = width - oldWidth; + } + } + float baseFactor = width / (ratio * numberOfSpaces + lineLen - 1); + baseWordSpacing = ratio * baseFactor; + baseCharacterSpacing = baseFactor; + lastBaseFactor = baseFactor; + } + } + + int lastChunkStroke = line.LastStrokeChunk; + int chunkStrokeIdx = 0; + float xMarker = text.XTLM; + float baseXMarker = xMarker; + float yMarker = text.YTLM; + bool adjustMatrix = false; + float tabPosition = 0; + + // looping over all the chunks in 1 line + foreach (PdfChunk chunk in line) { + Color color = chunk.Color; + hScale = 1; + + if (chunkStrokeIdx <= lastChunkStroke) { + float width; + if (isJustified) { + width = chunk.GetWidthCorrected(baseCharacterSpacing, baseWordSpacing); + } + else { + width = chunk.Width; + } + if (chunk.IsStroked()) { + PdfChunk nextChunk = line.GetChunk(chunkStrokeIdx + 1); + if (chunk.IsSeparator()) { + width = glueWidth; + Object[] sep = (Object[])chunk.GetAttribute(Chunk.SEPARATOR); + IDrawInterface di = (IDrawInterface)sep[0]; + bool vertical = (bool)sep[1]; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + if (vertical) { + di.Draw(graphics, baseXMarker, yMarker + descender, baseXMarker + line.OriginalWidth, ascender - descender, yMarker); + } + else { + di.Draw(graphics, xMarker, yMarker + descender, xMarker + width, ascender - descender, yMarker); + } + } + if (chunk.IsTab()) { + Object[] tab = (Object[])chunk.GetAttribute(Chunk.TAB); + IDrawInterface di = (IDrawInterface)tab[0]; + tabPosition = (float)tab[1] + (float)tab[3]; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + if (tabPosition > xMarker) { + di.Draw(graphics, xMarker, yMarker + descender, tabPosition, ascender - descender, yMarker); + } + float tmp = xMarker; + xMarker = tabPosition; + tabPosition = tmp; + } + if (chunk.IsAttribute(Chunk.BACKGROUND)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.BACKGROUND)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + Object[] bgr = (Object[])chunk.GetAttribute(Chunk.BACKGROUND); + graphics.SetColorFill((Color)bgr[0]); + float[] extra = (float[])bgr[1]; + graphics.Rectangle(xMarker - extra[0], + yMarker + descender - extra[1] + chunk.TextRise, + width - subtract + extra[0] + extra[2], + ascender - descender + extra[1] + extra[3]); + graphics.Fill(); + graphics.SetGrayFill(0); + } + if (chunk.IsAttribute(Chunk.UNDERLINE)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.UNDERLINE)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + Object[][] unders = (Object[][])chunk.GetAttribute(Chunk.UNDERLINE); + Color scolor = null; + for (int k = 0; k < unders.Length; ++k) { + Object[] obj = unders[k]; + scolor = (Color)obj[0]; + float[] ps = (float[])obj[1]; + if (scolor == null) + scolor = color; + if (scolor != null) + graphics.SetColorStroke(scolor); + float fsize = chunk.Font.Size; + graphics.SetLineWidth(ps[0] + fsize * ps[1]); + float shift = ps[2] + fsize * ps[3]; + int cap2 = (int)ps[4]; + if (cap2 != 0) + graphics.SetLineCap(cap2); + graphics.MoveTo(xMarker, yMarker + shift); + graphics.LineTo(xMarker + width - subtract, yMarker + shift); + graphics.Stroke(); + if (scolor != null) + graphics.ResetGrayStroke(); + if (cap2 != 0) + graphics.SetLineCap(0); + } + graphics.SetLineWidth(1); + } + if (chunk.IsAttribute(Chunk.ACTION)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.ACTION)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + text.AddAnnotation(new PdfAnnotation(writer, xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size, (PdfAction)chunk.GetAttribute(Chunk.ACTION))); + } + if (chunk.IsAttribute(Chunk.REMOTEGOTO)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.REMOTEGOTO)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + Object[] obj = (Object[])chunk.GetAttribute(Chunk.REMOTEGOTO); + String filename = (String)obj[0]; + if (obj[1] is String) + RemoteGoto(filename, (String)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + else + RemoteGoto(filename, (int)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + } + if (chunk.IsAttribute(Chunk.LOCALGOTO)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.LOCALGOTO)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + LocalGoto((String)chunk.GetAttribute(Chunk.LOCALGOTO), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + } + if (chunk.IsAttribute(Chunk.LOCALDESTINATION)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.LOCALDESTINATION)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + LocalDestination((String)chunk.GetAttribute(Chunk.LOCALDESTINATION), new PdfDestination(PdfDestination.XYZ, xMarker, yMarker + chunk.Font.Size, 0)); + } + if (chunk.IsAttribute(Chunk.GENERICTAG)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.GENERICTAG)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + Rectangle rect = new Rectangle(xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + IPdfPageEvent pev = writer.PageEvent; + if (pev != null) + pev.OnGenericTag(writer, this, rect, (String)chunk.GetAttribute(Chunk.GENERICTAG)); + } + if (chunk.IsAttribute(Chunk.PDFANNOTATION)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.PDFANNOTATION)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + PdfAnnotation annot = PdfFormField.ShallowDuplicate((PdfAnnotation)chunk.GetAttribute(Chunk.PDFANNOTATION)); + annot.Put(PdfName.RECT, new PdfRectangle(xMarker, yMarker + descender, xMarker + width - subtract, yMarker + ascender)); + text.AddAnnotation(annot); + } + float[] paramsx = (float[])chunk.GetAttribute(Chunk.SKEW); + object hs = chunk.GetAttribute(Chunk.HSCALE); + if (paramsx != null || hs != null) { + float b = 0, c = 0; + if (paramsx != null) { + b = paramsx[0]; + c = paramsx[1]; + } + if (hs != null) + hScale = (float)hs; + text.SetTextMatrix(hScale, b, c, 1, xMarker, yMarker); + } + if (chunk.IsImage()) { + Image image = chunk.Image; + float[] matrix = image.Matrix; + matrix[Image.CX] = xMarker + chunk.ImageOffsetX - matrix[Image.CX]; + matrix[Image.CY] = yMarker + chunk.ImageOffsetY - matrix[Image.CY]; + graphics.AddImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + text.MoveText(xMarker + lastBaseFactor + image.ScaledWidth - text.XTLM, 0); + } + } + xMarker += width; + ++chunkStrokeIdx; + } + + if (chunk.Font.CompareTo(currentFont) != 0) { + currentFont = chunk.Font; + text.SetFontAndSize(currentFont.Font, currentFont.Size); + } + float rise = 0; + Object[] textRender = (Object[])chunk.GetAttribute(Chunk.TEXTRENDERMODE); + int tr = 0; + float strokeWidth = 1; + Color strokeColor = null; + object fr = chunk.GetAttribute(Chunk.SUBSUPSCRIPT); + if (textRender != null) { + tr = (int)textRender[0] & 3; + if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL) + text.SetTextRenderingMode(tr); + if (tr == PdfContentByte.TEXT_RENDER_MODE_STROKE || tr == PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE) { + strokeWidth = (float)textRender[1]; + if (strokeWidth != 1) + text.SetLineWidth(strokeWidth); + strokeColor = (Color)textRender[2]; + if (strokeColor == null) + strokeColor = color; + if (strokeColor != null) + text.SetColorStroke(strokeColor); + } + } + if (fr != null) + rise = (float)fr; + if (color != null) + text.SetColorFill(color); + if (rise != 0) + text.SetTextRise(rise); + if (chunk.IsImage()) { + adjustMatrix = true; + } + else if (chunk.IsHorizontalSeparator()) { + PdfTextArray array = new PdfTextArray(); + array.Add(-glueWidth * 1000f / chunk.Font.Size / hScale); + text.ShowText(array); + } + else if (chunk.IsTab()) { + PdfTextArray array = new PdfTextArray(); + array.Add((tabPosition - xMarker) * 1000f / chunk.Font.Size / hScale); + text.ShowText(array); + } + // If it is a CJK chunk or Unicode TTF we will have to simulate the + // space adjustment. + else if (isJustified && numberOfSpaces > 0 && chunk.IsSpecialEncoding()) { + if (hScale != lastHScale) { + lastHScale = hScale; + text.SetWordSpacing(baseWordSpacing / hScale); + text.SetCharacterSpacing(baseCharacterSpacing / hScale); + } + String s = chunk.ToString(); + int idx = s.IndexOf(' '); + if (idx < 0) + text.ShowText(s); + else { + float spaceCorrection = - baseWordSpacing * 1000f / chunk.Font.Size / hScale; + PdfTextArray textArray = new PdfTextArray(s.Substring(0, idx)); + int lastIdx = idx; + while ((idx = s.IndexOf(' ', lastIdx + 1)) >= 0) { + textArray.Add(spaceCorrection); + textArray.Add(s.Substring(lastIdx, idx - lastIdx)); + lastIdx = idx; + } + textArray.Add(spaceCorrection); + textArray.Add(s.Substring(lastIdx)); + text.ShowText(textArray); + } + } + else { + if (isJustified && hScale != lastHScale) { + lastHScale = hScale; + text.SetWordSpacing(baseWordSpacing / hScale); + text.SetCharacterSpacing(baseCharacterSpacing / hScale); + } + text.ShowText(chunk.ToString()); + } + + if (rise != 0) + text.SetTextRise(0); + if (color != null) + text.ResetRGBColorFill(); + if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL) + text.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL); + if (strokeColor != null) + text.ResetRGBColorStroke(); + if (strokeWidth != 1) + text.SetLineWidth(1); + if (chunk.IsAttribute(Chunk.SKEW) || chunk.IsAttribute(Chunk.HSCALE)) { + adjustMatrix = true; + text.SetTextMatrix(xMarker, yMarker); + } + } + if (isJustified) { + text.SetWordSpacing(0); + text.SetCharacterSpacing(0); + if (line.NewlineSplit) + lastBaseFactor = 0; + } + if (adjustMatrix) + text.MoveText(baseXMarker - text.XTLM, 0); + currentValues[0] = currentFont; + currentValues[1] = lastBaseFactor; + } + + protected internal Indentation indentation = new Indentation(); + public class Indentation { + /** This represents the current indentation of the PDF Elements on the left side. */ + internal float indentLeft = 0; + + /** Indentation to the left caused by a section. */ + internal float sectionIndentLeft = 0; + + /** This represents the current indentation of the PDF Elements on the left side. */ + internal float listIndentLeft = 0; + + /** This is the indentation caused by an image on the left. */ + internal float imageIndentLeft = 0; + + /** This represents the current indentation of the PDF Elements on the right side. */ + internal float indentRight = 0; + + /** Indentation to the right caused by a section. */ + internal float sectionIndentRight = 0; + + /** This is the indentation caused by an image on the right. */ + internal float imageIndentRight = 0; + + /** This represents the current indentation of the PDF Elements on the top side. */ + internal float indentTop = 0; + + /** This represents the current indentation of the PDF Elements on the bottom side. */ + internal float indentBottom = 0; + } + + /** + * Gets the indentation on the left side. + * + * @return a margin + */ + + protected internal float IndentLeft { + get { + return GetLeft(indentation.indentLeft + indentation.listIndentLeft + indentation.imageIndentLeft + indentation.sectionIndentLeft); + } + } + + /** + * Gets the indentation on the right side. + * + * @return a margin + */ + + protected internal float IndentRight { + get { + return GetRight(indentation.indentRight + indentation.sectionIndentRight + indentation.imageIndentRight); + } + } + + /** + * Gets the indentation on the top side. + * + * @return a margin + */ + + protected internal float IndentTop { + get { + return GetTop(indentation.indentTop); + } + } + + /** + * Gets the indentation on the bottom side. + * + * @return a margin + */ + + protected internal float IndentBottom { + get { + return GetBottom(indentation.indentBottom); + } + } + + /** + * Adds extra space. + * This method should probably be rewritten. + */ + protected internal void AddSpacing(float extraspace, float oldleading, Font f) { + if (extraspace == 0) return; + if (pageEmpty) return; + if (currentHeight + line.Height + leading > IndentTop - IndentBottom) return; + leading = extraspace; + CarriageReturn(); + if (f.IsUnderlined() || f.IsStrikethru()) { + f = new Font(f); + int style = f.Style; + style &= ~Font.UNDERLINE; + style &= ~Font.STRIKETHRU; + f.SetStyle(Font.UNDEFINED); + f.SetStyle(style); + } + Chunk space = new Chunk(" ", f); + space.Process(this); + CarriageReturn(); + leading = oldleading; + } + + // Info Dictionary and Catalog + + /** some meta information about the Document. */ + protected internal PdfInfo info = new PdfInfo(); + + /** + * Gets the PdfInfo-object. + * + * @return PdfInfo + */ + internal PdfInfo Info { + get { + return info; + } + } + + /** + * Gets the PdfCatalog-object. + * + * @param pages an indirect reference to this document pages + * @return PdfCatalog + */ + internal PdfCatalog GetCatalog(PdfIndirectReference pages) { + PdfCatalog catalog = new PdfCatalog(pages, writer); + + // [C1] outlines + if (rootOutline.Kids.Count > 0) { + catalog.Put(PdfName.PAGEMODE, PdfName.USEOUTLINES); + catalog.Put(PdfName.OUTLINES, rootOutline.IndirectReference); + } + + // [C2] version + writer.GetPdfVersion().AddToCatalog(catalog); + + // [C3] preferences + viewerPreferences.AddToCatalog(catalog); + + // [C4] pagelabels + if (pageLabels != null) { + catalog.Put(PdfName.PAGELABELS, pageLabels.GetDictionary(writer)); + } + + // [C5] named objects + catalog.AddNames(localDestinations, GetDocumentLevelJS(), documentFileAttachment, writer); + + // [C6] actions + if (openActionName != null) { + PdfAction action = GetLocalGotoAction(openActionName); + catalog.OpenAction = action; + } + else if (openActionAction != null) + catalog.OpenAction = openActionAction; + if (additionalActions != null) { + catalog.AdditionalActions = additionalActions; + } + + // [C7] portable collections + if (collection != null) { + catalog.Put(PdfName.COLLECTION, collection); + } + + // [C8] AcroForm + if (annotationsImp.HasValidAcroForm()) { + catalog.Put(PdfName.ACROFORM, writer.AddToBody(annotationsImp.AcroForm).IndirectReference); + } + + return catalog; + } + + // [C1] outlines + + /** This is the root outline of the document. */ + protected internal PdfOutline rootOutline; + + /** This is the current PdfOutline in the hierarchy of outlines. */ + protected internal PdfOutline currentOutline; + + /** + * Adds a named outline to the document . + * @param outline the outline to be added + * @param name the name of this local destination + */ + internal void AddOutline(PdfOutline outline, String name) { + LocalDestination(name, outline.PdfDestination); + } + + /** + * Gets the root outline. All the outlines must be created with a parent. + * The first level is created with this outline. + * @return the root outline + */ + public PdfOutline RootOutline { + get { + return rootOutline; + } + } + + internal void CalculateOutlineCount() { + if (rootOutline.Kids.Count == 0) + return; + TraverseOutlineCount(rootOutline); + } + + internal void TraverseOutlineCount(PdfOutline outline) { + ArrayList kids = outline.Kids; + PdfOutline parent = outline.Parent; + if (kids.Count == 0) { + if (parent != null) { + parent.Count = parent.Count + 1; + } + } + else { + for (int k = 0; k < kids.Count; ++k) { + TraverseOutlineCount((PdfOutline)kids[k]); + } + if (parent != null) { + if (outline.Open) { + parent.Count = outline.Count + parent.Count + 1; + } + else { + parent.Count = parent.Count + 1; + outline.Count = -outline.Count; + } + } + } + } + + internal void WriteOutlines() { + if (rootOutline.Kids.Count == 0) + return; + OutlineTree(rootOutline); + writer.AddToBody(rootOutline, rootOutline.IndirectReference); + } + + internal void OutlineTree(PdfOutline outline) { + outline.IndirectReference = writer.PdfIndirectReference; + if (outline.Parent != null) + outline.Put(PdfName.PARENT, outline.Parent.IndirectReference); + ArrayList kids = outline.Kids; + int size = kids.Count; + for (int k = 0; k < size; ++k) + OutlineTree((PdfOutline)kids[k]); + for (int k = 0; k < size; ++k) { + if (k > 0) + ((PdfOutline)kids[k]).Put(PdfName.PREV, ((PdfOutline)kids[k - 1]).IndirectReference); + if (k < size - 1) + ((PdfOutline)kids[k]).Put(PdfName.NEXT, ((PdfOutline)kids[k + 1]).IndirectReference); + } + if (size > 0) { + outline.Put(PdfName.FIRST, ((PdfOutline)kids[0]).IndirectReference); + outline.Put(PdfName.LAST, ((PdfOutline)kids[size - 1]).IndirectReference); + } + for (int k = 0; k < size; ++k) { + PdfOutline kid = (PdfOutline)kids[k]; + writer.AddToBody(kid, kid.IndirectReference); + } + } + + // [C3] PdfViewerPreferences interface + + /** Contains the Viewer preferences of this PDF document. */ + protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); + /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#setViewerPreferences(int) */ + internal int ViewerPreferences { + set { + this.viewerPreferences.ViewerPreferences = value; + } + } + + /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#addViewerPreference(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfObject) */ + internal void AddViewerPreference(PdfName key, PdfObject value) { + this.viewerPreferences.AddViewerPreference(key, value); + } + + // [C4] Page labels + + protected internal PdfPageLabels pageLabels; + + internal PdfPageLabels PageLabels { + set { + this.pageLabels = value; + } + } + + // [C5] named objects: local destinations, javascript, embedded files + + /** + * Implements a link to other part of the document. The jump will + * be made to a local destination with the same name, that must exist. + * @param name the name for this link + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void LocalGoto(String name, float llx, float lly, float urx, float ury) { + PdfAction action = GetLocalGotoAction(name); + annotationsImp.AddPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action)); + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param name the name to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void RemoteGoto(String filename, String name, float llx, float lly, float urx, float ury) { + annotationsImp.AddPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, name))); + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param page the page to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void RemoteGoto(String filename, int page, float llx, float lly, float urx, float ury) { + AddAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, page))); + } + + /** Implements an action in an area. + * @param action the PdfAction + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void SetAction(PdfAction action, float llx, float lly, float urx, float ury) { + AddAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action)); + } + + /** + * Stores the destinations keyed by name. Value is + * Object[]{PdfAction,PdfIndirectReference,PdfDestintion}. + */ + protected internal k_Tree localDestinations = new k_Tree(); + + internal PdfAction GetLocalGotoAction(String name) { + PdfAction action; + Object[] obj = (Object[])localDestinations[name]; + if (obj == null) + obj = new Object[3]; + if (obj[0] == null) { + if (obj[1] == null) { + obj[1] = writer.PdfIndirectReference; + } + action = new PdfAction((PdfIndirectReference)obj[1]); + obj[0] = action; + localDestinations[name] = obj; + } + else { + action = (PdfAction)obj[0]; + } + return action; + } + + /** + * The local destination to where a local goto with the same + * name will jump to. + * @param name the name of this local destination + * @param destination the PdfDestination with the jump coordinates + * @return true if the local destination was added, + * false if a local destination with the same name + * already existed + */ + internal bool LocalDestination(String name, PdfDestination destination) { + Object[] obj = (Object[])localDestinations[name]; + if (obj == null) + obj = new Object[3]; + if (obj[2] != null) + return false; + obj[2] = destination; + localDestinations[name] = obj; + destination.AddPage(writer.CurrentPage); + return true; + } + + /** + * Stores a list of document level JavaScript actions. + */ + private int jsCounter; + protected internal Hashtable documentLevelJS = new Hashtable(); + + internal void AddJavaScript(PdfAction js) { + if (js.Get(PdfName.JS) == null) + throw new ArgumentException("Only JavaScript actions are allowed."); + documentLevelJS[jsCounter.ToString().PadLeft(16, '0')] = writer.AddToBody(js).IndirectReference; + jsCounter++; + } + + internal void AddJavaScript(String name, PdfAction js) { + if (js.Get(PdfName.JS) == null) + throw new ArgumentException("Only JavaScript actions are allowed."); + documentLevelJS[name] = writer.AddToBody(js).IndirectReference; + } + + internal Hashtable GetDocumentLevelJS() { + return documentLevelJS; + } + + protected internal Hashtable documentFileAttachment = new Hashtable(); + + internal void AddFileAttachment(String description, PdfFileSpecification fs) { + if (description == null) { + PdfString desc = (PdfString)fs.Get(PdfName.DESC); + if (desc == null) { + description = ""; + } + else { + description = PdfEncodings.ConvertToString(desc.GetBytes(), null); + } + } + fs.AddDescription(description, true); + if (description.Length == 0) + description = "Unnamed"; + String fn = PdfEncodings.ConvertToString(new PdfString(description, PdfObject.TEXT_UNICODE).GetBytes(), null); + int k = 0; + while (documentFileAttachment.ContainsKey(fn)) { + ++k; + fn = PdfEncodings.ConvertToString(new PdfString(description + " " + k, PdfObject.TEXT_UNICODE).GetBytes(), null); + } + documentFileAttachment[fn] = fs.Reference; + } + + internal Hashtable GetDocumentFileAttachment() { + return documentFileAttachment; + } + + // [C6] document level actions + + protected internal String openActionName; + + internal void SetOpenAction(String name) { + openActionName = name; + openActionAction = null; + } + + protected internal PdfAction openActionAction; + + internal void SetOpenAction(PdfAction action) { + openActionAction = action; + openActionName = null; + } + + protected internal PdfDictionary additionalActions; + + internal void AddAdditionalAction(PdfName actionType, PdfAction action) { + if (additionalActions == null) { + additionalActions = new PdfDictionary(); + } + if (action == null) + additionalActions.Remove(actionType); + else + additionalActions.Put(actionType, action); + if (additionalActions.Size == 0) + additionalActions = null; + } + + // [C7] portable collections + + protected internal PdfCollection collection; + + /** + * Sets the collection dictionary. + * @param collection a dictionary of type PdfCollection + */ + public PdfCollection Collection { + set { + this.collection = value; + } + } + + // [C8] AcroForm + + internal PdfAnnotationsImp annotationsImp; + + /** + * Gets the AcroForm object. + * @return the PdfAcroform object of the PdfDocument + */ + public PdfAcroForm AcroForm { + get { + return annotationsImp.AcroForm; + } + } + + internal int SigFlags { + set { + annotationsImp.SigFlags = value; + } + } + + internal void AddCalculationOrder(PdfFormField formField) { + annotationsImp.AddCalculationOrder(formField); + } + + internal void AddAnnotation(PdfAnnotation annot) { + pageEmpty = false; + annotationsImp.AddAnnotation(annot); + } + + // [F12] tagged PDF + + protected int markPoint; + + internal int GetMarkPoint() { + return markPoint; + } + + internal void IncMarkPoint() { + ++markPoint; + } + + // [U1] page sizes + + /** This is the size of the next page. */ + protected Rectangle nextPageSize = null; + + /** This is the size of the several boxes of the current Page. */ + protected Hashtable thisBoxSize = new Hashtable(); + + /** This is the size of the several boxes that will be used in + * the next page. */ + protected Hashtable boxSize = new Hashtable(); + + internal Rectangle CropBoxSize { + set { + SetBoxSize("crop", value); + } + } + + internal void SetBoxSize(String boxName, Rectangle size) { + if (size == null) + boxSize.Remove(boxName); + else + boxSize[boxName] = new PdfRectangle(size); + } + + protected internal void SetNewPageSizeAndMargins() { + pageSize = nextPageSize; + if (marginMirroring && (PageNumber & 1) == 0) { + marginRight = nextMarginLeft; + marginLeft = nextMarginRight; + } + else { + marginLeft = nextMarginLeft; + marginRight = nextMarginRight; + } + marginTop = nextMarginTop; + marginBottom = nextMarginBottom; + } + + /** + * Gives the size of a trim, art, crop or bleed box, or null if not defined. + * @param boxName crop, trim, art or bleed + */ + internal Rectangle GetBoxSize(String boxName) { + PdfRectangle r = (PdfRectangle)thisBoxSize[boxName]; + if (r != null) return r.Rectangle; + return null; + } + + // [U2] empty pages + + /** This checks if the page is empty. */ + protected internal bool pageEmpty = true; + + internal bool PageEmpty { + set { + this.pageEmpty = value; + } + } + + + // [U3] page actions + + /** The duration of the page */ + protected int duration=-1; // negative values will indicate no duration + + /** The page transition */ + protected PdfTransition transition=null; + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page + */ + internal int Duration { + set { + if (value > 0) + this.duration=value; + else + this.duration=-1; + } + } + + /** + * Sets the transition for the page + * @param transition the PdfTransition object + */ + internal PdfTransition Transition { + set { + this.transition=value; + } + } + + protected PdfDictionary pageAA = null; + + internal void SetPageAction(PdfName actionType, PdfAction action) { + if (pageAA == null) { + pageAA = new PdfDictionary(); + } + pageAA.Put(actionType, action); + } + + // [U8] thumbnail images + + protected internal PdfIndirectReference thumb; + + internal Image Thumbnail { + set { + thumb = writer.GetImageReference(writer.AddDirectImageSimple(value)); + } + } + + // [M0] Page resources contain references to fonts, extgstate, images,... + + /** This are the page resources of the current Page. */ + protected internal PageResources pageResources; + + internal PageResources PageResources { + get { + return pageResources; + } + } + + // [M3] Images + + /** Holds value of property strictImageSequence. */ + protected internal bool strictImageSequence = false; + + /** Setter for property strictImageSequence. + * @param strictImageSequence New value of property strictImageSequence. + * + */ + internal bool StrictImageSequence { + set { + this.strictImageSequence = value; + } + get { + return strictImageSequence; + } + } + + /** This is the position where the image ends. */ + protected internal float imageEnd = -1; + + /** + * Method added by Pelikan Stephan + * @see com.lowagie.text.DocListener#clearTextWrap() + */ + public void ClearTextWrap() { + float tmpHeight = imageEnd - currentHeight; + if (line != null) { + tmpHeight += line.Height; + } + if ((imageEnd > -1) && (tmpHeight > 0)) { + CarriageReturn(); + currentHeight += tmpHeight; + } + } + + /** This is the image that could not be shown on a previous page. */ + protected internal Image imageWait = null; + + /** + * Adds an image to the document. + * @param image the Image to add + * @throws PdfException on error + * @throws DocumentException on error + */ + protected internal void Add(Image image) { + + if (image.HasAbsolutePosition()) { + graphics.AddImage(image); + pageEmpty = false; + return; + } + + // if there isn't enough room for the image on this page, save it for the next page + if (currentHeight != 0 && IndentTop - currentHeight - image.ScaledHeight < IndentBottom) { + if (!strictImageSequence && imageWait == null) { + imageWait = image; + return; + } + NewPage(); + if (currentHeight != 0 && IndentTop - currentHeight - image.ScaledHeight < IndentBottom) { + imageWait = image; + return; + } + } + pageEmpty = false; + // avoid endless loops + if (image == imageWait) + imageWait = null; + bool textwrap = (image.Alignment & Image.TEXTWRAP) == Image.TEXTWRAP + && !((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN); + bool underlying = (image.Alignment & Image.UNDERLYING) == Image.UNDERLYING; + float diff = leading / 2; + if (textwrap) { + diff += leading; + } + float lowerleft = IndentTop - currentHeight - image.ScaledHeight - diff; + float[] mt = image.Matrix; + float startPosition = IndentLeft - mt[4]; + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) startPosition = IndentRight - image.ScaledWidth - mt[4]; + if ((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN) startPosition = IndentLeft + ((IndentRight - IndentLeft - image.ScaledWidth) / 2) - mt[4]; + if (image.HasAbsoluteX()) startPosition = image.AbsoluteX; + if (textwrap) { + if (imageEnd < 0 || imageEnd < currentHeight + image.ScaledHeight + diff) { + imageEnd = currentHeight + image.ScaledHeight + diff; + } + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) { + // indentation suggested by Pelikan Stephan + indentation.imageIndentRight += image.ScaledWidth + image.IndentationLeft; + } + else { + // indentation suggested by Pelikan Stephan + indentation.imageIndentLeft += image.ScaledWidth + image.IndentationRight; + } + } + else { + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) startPosition -= image.IndentationRight; + else if ((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN) startPosition += image.IndentationLeft - image.IndentationRight; + else startPosition -= image.IndentationRight; + } + graphics.AddImage(image, mt[0], mt[1], mt[2], mt[3], startPosition, lowerleft - mt[5]); + if (!(textwrap || underlying)) { + currentHeight += image.ScaledHeight + diff; + FlushLines(); + text.MoveText(0, - (image.ScaledHeight + diff)); + NewLine(); + } + } + + // [M4] Adding a PdfPTable + + /** Adds a PdfPTable to the document. + * @param ptable the PdfPTable to be added to the document. + * @throws DocumentException on error + */ + internal void AddPTable(PdfPTable ptable) { + ColumnText ct = new ColumnText(writer.DirectContent); + if (currentHeight > 0) { + Paragraph p = new Paragraph(); + p.Leading = 0; + ct.AddElement(p); + //if the table prefers to be on a single page, and it wouldn't + //fit on the current page, start a new page. + if (ptable.KeepTogether && !FitsPage(ptable, 0f)) + NewPage(); + } + ct.AddElement(ptable); + bool he = ptable.HeadersInEvent; + ptable.HeadersInEvent = true; + int loop = 0; + while (true) { + ct.SetSimpleColumn(IndentLeft, IndentBottom, IndentRight, IndentTop - currentHeight); + int status = ct.Go(); + if ((status & ColumnText.NO_MORE_TEXT) != 0) { + text.MoveText(0, ct.YLine - IndentTop + currentHeight); + currentHeight = IndentTop - ct.YLine; + break; + } + if (IndentTop - currentHeight == ct.YLine) + ++loop; + else + loop = 0; + if (loop == 3) { + Add(new Paragraph("ERROR: Infinite table loop")); + break; + } + NewPage(); + } + ptable.HeadersInEvent = he; + } + + internal bool FitsPage(PdfPTable table, float margin) { + if (!table.LockedWidth) { + float totalWidth = (IndentRight - IndentLeft) * table.WidthPercentage / 100; + table.TotalWidth = totalWidth; + } + // ensuring that a new line has been started. + EnsureNewLine(); + return table.TotalHeight <= IndentTop - currentHeight - IndentBottom - margin; + } + + // [M4'] Adding a Table + + protected internal class RenderingContext { + internal float pagetop = -1; + internal float oldHeight = -1; + + internal PdfContentByte cellGraphics = null; + + internal float lostTableBottom; + + internal float maxCellBottom; + //internal float maxCellHeight; + + internal Hashtable rowspanMap; + internal Hashtable pageMap = new Hashtable(); + /** + * A PdfPTable + */ + public PdfTable table; + + /** + * Consumes the rowspan + * @param c + * @return a rowspan. + */ + public int ConsumeRowspan(PdfCell c) { + if (c.Rowspan == 1) { + return 1; + } + + object i = rowspanMap[c]; + if (i == null) { + i = c.Rowspan; + } + + i = (int)i - 1; + rowspanMap[c] = i; + + if ((int)i < 1) { + return 1; + } + return (int)i; + } + + /** + * Looks at the current rowspan. + * @param c + * @return the current rowspan + */ + public int CurrentRowspan(PdfCell c) { + object i = rowspanMap[c]; + if (i == null) { + return c.Rowspan; + } else { + return (int)i; + } + } + + public int CellRendered(PdfCell cell, int pageNumber) { + object i = pageMap[cell]; + if (i == null) { + i = 1; + } else { + i = (int)i + 1; + } + pageMap[cell] = i; + + Hashtable seti = (Hashtable)pageMap[pageNumber]; + + if (seti == null) { + seti = new Hashtable(); + pageMap[pageNumber] = seti; + } + + seti[cell] = null; + + return (int)i; + } + + public int NumCellRendered(PdfCell cell) { + object i = pageMap[cell]; + if (i == null) { + i = 0; + } + return (int)i; + } + + public bool IsCellRenderedOnPage(PdfCell cell, int pageNumber) { + Hashtable seti = (Hashtable) pageMap[pageNumber]; + + if (seti != null) { + return seti.ContainsKey(cell); + } + + return false; + } + }; + + /** + * Adds a new table to + * @param table Table to add. Rendered rows will be deleted after processing. + * @param onlyFirstPage Render only the first full page + * @throws DocumentException + */ + private void AddPdfTable(Table t) { + // before every table, we flush all lines + FlushLines(); + + PdfTable table = new PdfTable(t, IndentLeft, IndentRight, IndentTop - currentHeight); + RenderingContext ctx = new RenderingContext(); + ctx.pagetop = IndentTop; + ctx.oldHeight = currentHeight; + ctx.cellGraphics = new PdfContentByte(writer); + ctx.rowspanMap = new Hashtable(); + ctx.table = table; + + // initialisation of parameters + PdfCell cell; + + // drawing the table + ArrayList headercells = table.HeaderCells; + ArrayList cells = table.Cells; + ArrayList rows = ExtractRows(cells, ctx); + bool isContinue = false; + while (cells.Count != 0) { + // initialisation of some extra parameters; + ctx.lostTableBottom = 0; + + // loop over the cells + bool cellsShown = false; + + // draw the cells (line by line) + ListIterator iterator = new ListIterator(rows); + + bool atLeastOneFits = false; + while (iterator.HasNext()) { + ArrayList row = (ArrayList) iterator.Next(); + AnalyzeRow(rows, ctx); + RenderCells(ctx, row, table.HasToFitPageCells() & atLeastOneFits); + + if (!MayBeRemoved(row)) { + break; + } + + ConsumeRowspan(row, ctx); + iterator.Remove(); + atLeastOneFits = true; + } + + // compose cells array list for subsequent code + cells.Clear(); + Hashtable opt = new Hashtable(); + foreach (ArrayList row in rows) { + foreach (PdfCell cellp in row) { + if (!opt.ContainsKey(cellp)) { + cells.Add(cellp); + opt[cellp] = null; + } + } + } + // we paint the graphics of the table after looping through all the cells + Rectangle tablerec = new Rectangle(table); + tablerec.Border = table.Border; + tablerec.BorderWidth = table.BorderWidth; + tablerec.BorderColor = table.BorderColor; + tablerec.BackgroundColor = table.BackgroundColor; + PdfContentByte under = writer.DirectContentUnder; + under.Rectangle(tablerec.GetRectangle(Top, IndentBottom)); + under.Add(ctx.cellGraphics); + // bugfix by Gerald Fehringer: now again add the border for the table + // since it might have been covered by cell backgrounds + tablerec.BackgroundColor = null; + tablerec = tablerec.GetRectangle(Top, IndentBottom); + tablerec.Border = table.Border; + under.Rectangle(tablerec); + // end bugfix + ctx.cellGraphics = new PdfContentByte(null); + // if the table continues on the next page + if (rows.Count != 0) { + isContinue = true; + graphics.SetLineWidth(table.BorderWidth); + if (cellsShown && (table.Border & Rectangle.BOTTOM_BORDER) == Rectangle.BOTTOM_BORDER) { + // Draw the bottom line + + // the color is set to the color of the element + Color tColor = table.BorderColor; + if (tColor != null) { + graphics.SetColorStroke(tColor); + } + graphics.MoveTo(table.Left, Math.Max(table.Bottom, IndentBottom)); + graphics.LineTo(table.Right, Math.Max(table.Bottom, IndentBottom)); + graphics.Stroke(); + if (tColor != null) { + graphics.ResetRGBColorStroke(); + } + } + + // old page + pageEmpty = false; + float difference = ctx.lostTableBottom; + + // new page + NewPage(); + // G.F.: if something added in page event i.e. currentHeight > 0 + float heightCorrection = 0; + bool somethingAdded = false; + if (currentHeight > 0) { + heightCorrection = 6; + currentHeight += heightCorrection; + somethingAdded = true; + NewLine(); + FlushLines(); + indentation.indentTop = currentHeight - leading; + currentHeight = 0; + } + else { + FlushLines(); + } + + // this part repeats the table headers (if any) + int size = headercells.Count; + if (size > 0) { + // this is the top of the headersection + cell = (PdfCell) headercells[0]; + float oldTop = cell.GetTop(0); + // loop over all the cells of the table header + for (int ii = 0; ii < size; ii++) { + cell = (PdfCell) headercells[ii]; + // calculation of the new cellpositions + cell.Top = IndentTop - oldTop + cell.GetTop(0); + cell.Bottom = IndentTop - oldTop + cell.GetBottom(0); + ctx.pagetop = cell.Bottom; + // we paint the borders of the cell + ctx.cellGraphics.Rectangle(cell.Rectangle(IndentTop, IndentBottom)); + // we write the text of the cell + ArrayList images = cell.GetImages(IndentTop, IndentBottom); + foreach (Image image in images) { + cellsShown = true; + graphics.AddImage(image); + } + lines = cell.GetLines(IndentTop, IndentBottom); + float cellTop = cell.GetTop(IndentTop); + text.MoveText(0, cellTop-heightCorrection); + float cellDisplacement = FlushLines() - cellTop+heightCorrection; + text.MoveText(0, cellDisplacement); + } + currentHeight = IndentTop - ctx.pagetop + table.Cellspacing; + text.MoveText(0, ctx.pagetop - IndentTop - currentHeight); + } + else { + if (somethingAdded) { + ctx.pagetop = IndentTop; + text.MoveText(0, -table.Cellspacing); + } + } + ctx.oldHeight = currentHeight - heightCorrection; + // calculating the new positions of the table and the cells + size = Math.Min(cells.Count, table.Columns); + int i = 0; + while (i < size) { + cell = (PdfCell) cells[i]; + if (cell.GetTop(-table.Cellspacing) > ctx.lostTableBottom) { + float newBottom = ctx.pagetop - difference + cell.Bottom; + float neededHeight = cell.RemainingHeight; + if (newBottom > ctx.pagetop - neededHeight) { + difference += newBottom - (ctx.pagetop - neededHeight); + } + } + i++; + } + size = cells.Count; + table.Top = IndentTop; + table.Bottom = ctx.pagetop - difference + table.GetBottom(table.Cellspacing); + for (i = 0; i < size; i++) { + cell = (PdfCell) cells[i]; + float newBottom = ctx.pagetop - difference + cell.Bottom; + float newTop = ctx.pagetop - difference + cell.GetTop(-table.Cellspacing); + if (newTop > IndentTop - currentHeight) { + newTop = IndentTop - currentHeight; + } + cell.Top = newTop ; + cell.Bottom = newBottom ; + } + } + } + + float tableHeight = table.Top - table.Bottom; + // bugfix by Adauto Martins when have more than two tables and more than one page + // If continuation of table in other page (bug report #1460051) + if (isContinue) { + currentHeight = tableHeight; + text.MoveText(0, -(tableHeight - (ctx.oldHeight * 2))); + } + else { + currentHeight = ctx.oldHeight + tableHeight; + text.MoveText(0, -tableHeight); + } + pageEmpty = false; + } + + protected internal void AnalyzeRow(ArrayList rows, RenderingContext ctx) { + ctx.maxCellBottom = IndentBottom; + + // determine whether Row(index) is in a rowspan + int rowIndex = 0; + + ArrayList row = (ArrayList) rows[rowIndex]; + int maxRowspan = 1; + foreach (PdfCell cell in row) { + maxRowspan = Math.Max(ctx.CurrentRowspan(cell), maxRowspan); + } + rowIndex += maxRowspan; + + bool useTop = true; + if (rowIndex == rows.Count) { + rowIndex = rows.Count - 1; + useTop = false; + } + + if (rowIndex < 0 || rowIndex >= rows.Count) return; + + row = (ArrayList) rows[rowIndex]; + foreach (PdfCell cell in row) { + Rectangle cellRect = cell.Rectangle(ctx.pagetop, IndentBottom); + if (useTop) { + ctx.maxCellBottom = Math.Max(ctx.maxCellBottom, cellRect.Top); + } else { + if (ctx.CurrentRowspan(cell) == 1) { + ctx.maxCellBottom = Math.Max(ctx.maxCellBottom, cellRect.Bottom); + } + } + } + } + + protected internal bool MayBeRemoved(ArrayList row) { + bool mayBeRemoved = true; + foreach (PdfCell cell in row) { + mayBeRemoved &= cell.MayBeRemoved(); + } + return mayBeRemoved; + } + + protected internal void ConsumeRowspan(ArrayList row, RenderingContext ctx) { + foreach (PdfCell c in row) { + ctx.ConsumeRowspan(c); + } + } + + protected internal ArrayList ExtractRows(ArrayList cells, RenderingContext ctx) { + PdfCell cell; + PdfCell previousCell = null; + ArrayList rows = new ArrayList(); + ArrayList rowCells = new ArrayList(); + + ListIterator iterator = new ListIterator(cells); + while (iterator.HasNext()) { + cell = (PdfCell) iterator.Next(); + + bool isAdded = false; + + bool isEndOfRow = !iterator.HasNext(); + bool isCurrentCellPartOfRow = !iterator.HasNext(); + + if (previousCell != null) { + if (cell.Left <= previousCell.Left) { + isEndOfRow = true; + isCurrentCellPartOfRow = false; + } + } + + if (isCurrentCellPartOfRow) { + rowCells.Add(cell); + isAdded = true; + } + + if (isEndOfRow) { + if (rowCells.Count != 0) { + // add to rowlist + rows.Add(rowCells); + } + + // start a new list for next line + rowCells = new ArrayList(); + } + + if (!isAdded) { + rowCells.Add(cell); + } + + previousCell = cell; + } + + if (rowCells.Count != 0) { + rows.Add(rowCells); + } + + // fill row information with rowspan cells to get complete "scan lines" + for (int i = rows.Count - 1; i >= 0; i--) { + ArrayList row = (ArrayList) rows[i]; + + // iterator through row + for (int j = 0; j < row.Count; j++) { + PdfCell c = (PdfCell) row[j]; + int rowspan = c.Rowspan; + + // fill in missing rowspan cells to complete "scan line" + for (int k = 1; k < rowspan && rows.Count < i+k; k++) { + ArrayList spannedRow = ((ArrayList) rows[i + k]); + if (spannedRow.Count > j) + spannedRow.Insert(j, c); + } + } + } + + return rows; + } + + protected internal void RenderCells(RenderingContext ctx, ArrayList cells, bool hasToFit) { + if (hasToFit) { + foreach (PdfCell cell in cells) { + if (!cell.Header) { + if (cell.Bottom < IndentBottom) return; + } + } + } + foreach (PdfCell cell in cells) { + if (!ctx.IsCellRenderedOnPage(cell, PageNumber)) { + + float correction = 0; + if (ctx.NumCellRendered(cell) >= 1) { + correction = 1.0f; + } + + lines = cell.GetLines(ctx.pagetop, IndentBottom - correction); + + // if there is still text to render we render it + if (lines != null && lines.Count > 0) { + + // we write the text + float cellTop = cell.GetTop(ctx.pagetop - ctx.oldHeight); + text.MoveText(0, cellTop); + float cellDisplacement = FlushLines() - cellTop; + + text.MoveText(0, cellDisplacement); + if (ctx.oldHeight + cellDisplacement > currentHeight) { + currentHeight = ctx.oldHeight + cellDisplacement; + } + + ctx.CellRendered(cell, PageNumber); + } + + float indentBottom = Math.Max(cell.Bottom, IndentBottom); + + Rectangle tableRect = ctx.table.GetRectangle(ctx.pagetop, IndentBottom); + + indentBottom = Math.Max(tableRect.Bottom, indentBottom); + + // we paint the borders of the cells + Rectangle cellRect = cell.GetRectangle(tableRect.Top, indentBottom); + //cellRect.Bottom = cellRect.Bottom; + if (cellRect.Height > 0) { + ctx.lostTableBottom = indentBottom; + ctx.cellGraphics.Rectangle(cellRect); + } + + // and additional graphics + ArrayList images = cell.GetImages(ctx.pagetop, IndentBottom); + foreach (Image image in images) { + graphics.AddImage(image); + } + } + } + } + + /** + * Returns the bottomvalue of a Table if it were added to this document. + * + * @param table the table that may or may not be added to this document + * @return a bottom value + */ + internal float GetBottom(Table table) { + // constructing a PdfTable + PdfTable tmp = new PdfTable(table, IndentLeft, IndentRight, IndentTop - currentHeight); + return tmp.Bottom; + } + + // [M5] header/footer + protected internal void DoFooter() { + if (footer == null) return; + // Begin added by Edgar Leonardo Prieto Perilla + // Avoid footer identation + float tmpIndentLeft = indentation.indentLeft; + float tmpIndentRight = indentation.indentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + float tmpListIndentLeft = indentation.listIndentLeft; + float tmpImageIndentLeft = indentation.imageIndentLeft; + float tmpImageIndentRight = indentation.imageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + + indentation.indentLeft = indentation.indentRight = 0; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + indentation.listIndentLeft = 0; + indentation.imageIndentLeft = 0; + indentation.imageIndentRight = 0; + // End added: Bonf (Marc Schneider) 2003-07-29 + // End Added by Edgar Leonardo Prieto Perilla + footer.PageNumber = pageN; + leading = footer.Paragraph.TotalLeading; + Add(footer.Paragraph); + // adding the footer limits the height + indentation.indentBottom = currentHeight; + text.MoveText(Left, IndentBottom); + FlushLines(); + text.MoveText(-Left, -Bottom); + footer.Top = GetBottom(currentHeight); + footer.Bottom = Bottom - (0.75f * leading); + footer.Left = Left; + footer.Right = Right; + graphics.Rectangle(footer); + indentation.indentBottom = currentHeight + leading * 2; + currentHeight = 0; + // Begin added by Edgar Leonardo Prieto Perilla + indentation.indentLeft = tmpIndentLeft; + indentation.indentRight = tmpIndentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + indentation.listIndentLeft = tmpListIndentLeft; + indentation.imageIndentLeft = tmpImageIndentLeft; + indentation.imageIndentRight = tmpImageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + // End added by Edgar Leonardo Prieto Perilla + } + + protected internal void DoHeader() { + // if there is a header, the header = added + if (header == null) return; + // Begin added by Edgar Leonardo Prieto Perilla + // Avoid header identation + float tmpIndentLeft = indentation.indentLeft; + float tmpIndentRight = indentation.indentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + float tmpListIndentLeft = indentation.listIndentLeft; + float tmpImageIndentLeft = indentation.imageIndentLeft; + float tmpImageIndentRight = indentation.imageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + indentation.indentLeft = indentation.indentRight = 0; + // Added: Bonf + indentation.listIndentLeft = 0; + indentation.imageIndentLeft = 0; + indentation.imageIndentRight = 0; + // End added: Bonf + // Begin added by Edgar Leonardo Prieto Perilla + header.PageNumber = pageN; + leading = header.Paragraph.TotalLeading; + text.MoveText(0, leading); + Add(header.Paragraph); + NewLine(); + indentation.indentTop = currentHeight - leading; + header.Top = Top + leading; + header.Bottom = IndentTop + leading * 2 / 3; + header.Left = Left; + header.Right = Right; + graphics.Rectangle(header); + FlushLines(); + currentHeight = 0; + // Begin added by Edgar Leonardo Prieto Perilla + // Restore identation + indentation.indentLeft = tmpIndentLeft; + indentation.indentRight = tmpIndentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + indentation.listIndentLeft = tmpListIndentLeft; + indentation.imageIndentLeft = tmpImageIndentLeft; + indentation.imageIndentRight = tmpImageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + // End Added by Edgar Leonardo Prieto Perilla + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs b/iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs new file mode 100644 index 0000000..e06fd12 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs @@ -0,0 +1,782 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text; +using System.util; +using iTextSharp.text.xml.simpleparser; + +/* + * Copyright 2002-2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { +/** Supports fast encodings for winansi and PDFDocEncoding. + * + * @author Paulo Soares (psoares@consiste.pt) + */ +public class PdfEncodings { + + protected const int CIDNONE = 0; + protected const int CIDRANGE = 1; + protected const int CIDCHAR = 2; + + internal static char[] winansiByteToChar = { + (char)0, (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, + (char)16, (char)17, (char)18, (char)19, (char)20, (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, (char)31, + (char)32, (char)33, (char)34, (char)35, (char)36, (char)37, (char)38, (char)39, (char)40, (char)41, (char)42, (char)43, (char)44, (char)45, (char)46, (char)47, + (char)48, (char)49, (char)50, (char)51, (char)52, (char)53, (char)54, (char)55, (char)56, (char)57, (char)58, (char)59, (char)60, (char)61, (char)62, (char)63, + (char)64, (char)65, (char)66, (char)67, (char)68, (char)69, (char)70, (char)71, (char)72, (char)73, (char)74, (char)75, (char)76, (char)77, (char)78, (char)79, + (char)80, (char)81, (char)82, (char)83, (char)84, (char)85, (char)86, (char)87, (char)88, (char)89, (char)90, (char)91, (char)92, (char)93, (char)94, (char)95, + (char)96, (char)97, (char)98, (char)99, (char)100, (char)101, (char)102, (char)103, (char)104, (char)105, (char)106, (char)107, (char)108, (char)109, (char)110, (char)111, + (char)112, (char)113, (char)114, (char)115, (char)116, (char)117, (char)118, (char)119, (char)120, (char)121, (char)122, (char)123, (char)124, (char)125, (char)126, (char)127, + (char)8364, (char)65533, (char)8218, (char)402, (char)8222, (char)8230, (char)8224, (char)8225, (char)710, (char)8240, (char)352, (char)8249, (char)338, (char)65533, (char)381, (char)65533, + (char)65533, (char)8216, (char)8217, (char)8220, (char)8221, (char)8226, (char)8211, (char)8212, (char)732, (char)8482, (char)353, (char)8250, (char)339, (char)65533, (char)382, (char)376, + (char)160, (char)161, (char)162, (char)163, (char)164, (char)165, (char)166, (char)167, (char)168, (char)169, (char)170, (char)171, (char)172, (char)173, (char)174, (char)175, + (char)176, (char)177, (char)178, (char)179, (char)180, (char)181, (char)182, (char)183, (char)184, (char)185, (char)186, (char)187, (char)188, (char)189, (char)190, (char)191, + (char)192, (char)193, (char)194, (char)195, (char)196, (char)197, (char)198, (char)199, (char)200, (char)201, (char)202, (char)203, (char)204, (char)205, (char)206, (char)207, + (char)208, (char)209, (char)210, (char)211, (char)212, (char)213, (char)214, (char)215, (char)216, (char)217, (char)218, (char)219, (char)220, (char)221, (char)222, (char)223, + (char)224, (char)225, (char)226, (char)227, (char)228, (char)229, (char)230, (char)231, (char)232, (char)233, (char)234, (char)235, (char)236, (char)237, (char)238, (char)239, + (char)240, (char)241, (char)242, (char)243, (char)244, (char)245, (char)246, (char)247, (char)248, (char)249, (char)250, (char)251, (char)252, (char)253, (char)254, (char)255}; + + internal static char[] pdfEncodingByteToChar = { + (char)0, (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, + (char)16, (char)17, (char)18, (char)19, (char)20, (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, (char)31, + (char)32, (char)33, (char)34, (char)35, (char)36, (char)37, (char)38, (char)39, (char)40, (char)41, (char)42, (char)43, (char)44, (char)45, (char)46, (char)47, + (char)48, (char)49, (char)50, (char)51, (char)52, (char)53, (char)54, (char)55, (char)56, (char)57, (char)58, (char)59, (char)60, (char)61, (char)62, (char)63, + (char)64, (char)65, (char)66, (char)67, (char)68, (char)69, (char)70, (char)71, (char)72, (char)73, (char)74, (char)75, (char)76, (char)77, (char)78, (char)79, + (char)80, (char)81, (char)82, (char)83, (char)84, (char)85, (char)86, (char)87, (char)88, (char)89, (char)90, (char)91, (char)92, (char)93, (char)94, (char)95, + (char)96, (char)97, (char)98, (char)99, (char)100, (char)101, (char)102, (char)103, (char)104, (char)105, (char)106, (char)107, (char)108, (char)109, (char)110, (char)111, + (char)112, (char)113, (char)114, (char)115, (char)116, (char)117, (char)118, (char)119, (char)120, (char)121, (char)122, (char)123, (char)124, (char)125, (char)126, (char)127, + (char)0x2022, (char)0x2020, (char)0x2021, (char)0x2026, (char)0x2014, (char)0x2013, (char)0x0192, (char)0x2044, (char)0x2039, (char)0x203a, (char)0x2212, (char)0x2030, (char)0x201e, (char)0x201c, (char)0x201d, (char)0x2018, + (char)0x2019, (char)0x201a, (char)0x2122, (char)0xfb01, (char)0xfb02, (char)0x0141, (char)0x0152, (char)0x0160, (char)0x0178, (char)0x017d, (char)0x0131, (char)0x0142, (char)0x0153, (char)0x0161, (char)0x017e, (char)65533, + (char)0x20ac, (char)161, (char)162, (char)163, (char)164, (char)165, (char)166, (char)167, (char)168, (char)169, (char)170, (char)171, (char)172, (char)173, (char)174, (char)175, + (char)176, (char)177, (char)178, (char)179, (char)180, (char)181, (char)182, (char)183, (char)184, (char)185, (char)186, (char)187, (char)188, (char)189, (char)190, (char)191, + (char)192, (char)193, (char)194, (char)195, (char)196, (char)197, (char)198, (char)199, (char)200, (char)201, (char)202, (char)203, (char)204, (char)205, (char)206, (char)207, + (char)208, (char)209, (char)210, (char)211, (char)212, (char)213, (char)214, (char)215, (char)216, (char)217, (char)218, (char)219, (char)220, (char)221, (char)222, (char)223, + (char)224, (char)225, (char)226, (char)227, (char)228, (char)229, (char)230, (char)231, (char)232, (char)233, (char)234, (char)235, (char)236, (char)237, (char)238, (char)239, + (char)240, (char)241, (char)242, (char)243, (char)244, (char)245, (char)246, (char)247, (char)248, (char)249, (char)250, (char)251, (char)252, (char)253, (char)254, (char)255}; + + internal static IntHashtable winansi = new IntHashtable(); + + internal static IntHashtable pdfEncoding = new IntHashtable(); + + internal static Hashtable extraEncodings = new Hashtable(); + + static PdfEncodings() { + for (int k = 128; k < 161; ++k) { + char c = winansiByteToChar[k]; + if (c != 65533) + winansi[c] = k; + } + + for (int k = 128; k < 161; ++k) { + char c = pdfEncodingByteToChar[k]; + if (c != 65533) + pdfEncoding[c] = k; + } + + AddExtraEncoding("Wingdings", new WingdingsConversion()); + AddExtraEncoding("Symbol", new SymbolConversion(true)); + AddExtraEncoding("ZapfDingbats", new SymbolConversion(false)); + AddExtraEncoding("SymbolTT", new SymbolTTConversion()); + AddExtraEncoding("Cp437", new Cp437Conversion()); + } + + /** + * Converts a string to a byte array according + * to the font's encoding. + * @param text the string to be converted + * @return an array of byte representing the conversion according to the font's encoding + */ + public static byte[] ConvertToBytes(string text, string encoding) { + if (text == null) + return new byte[0]; + if (encoding == null || encoding.Length == 0) { + int len = text.Length; + byte[] b = new byte[len]; + for (int k = 0; k < len; ++k) + b[k] = (byte)text[k]; + return b; + } + IExtraEncoding extra = (IExtraEncoding)extraEncodings[encoding.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (extra != null) { + byte[] b = extra.CharToByte(text, encoding); + if (b != null) + return b; + } + IntHashtable hash = null; + if (encoding.Equals(BaseFont.CP1252)) + hash = winansi; + else if (encoding.Equals(PdfObject.TEXT_PDFDOCENCODING)) + hash = pdfEncoding; + if (hash != null) { + char[] cc = text.ToCharArray(); + int len = cc.Length; + int ptr = 0; + byte[] b = new byte[len]; + int c = 0; + for (int k = 0; k < len; ++k) { + char char1 = cc[k]; + if (char1 < 128 || (char1 > 160 && char1 <= 255)) + c = char1; + else + c = hash[char1]; + if (c != 0) + b[ptr++] = (byte)c; + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + Encoding encw = IanaEncodings.GetEncodingEncoding(encoding); + byte[] preamble = encw.GetPreamble(); + if (preamble.Length == 0) + return encw.GetBytes(text); + byte[] encoded = encw.GetBytes(text); + byte[] total = new byte[encoded.Length + preamble.Length]; + Array.Copy(preamble, 0, total, 0, preamble.Length); + Array.Copy(encoded, 0, total, preamble.Length, encoded.Length); + return total; + } + + /** Converts a String to a byte array according + * to the font's encoding. + * @return an array of byte representing the conversion according to the font's encoding + * @param encoding the encoding + * @param char1 the char to be converted + */ + public static byte[] ConvertToBytes(char char1, String encoding) { + if (encoding == null || encoding.Length == 0) + return new byte[]{(byte)char1}; + IExtraEncoding extra = (IExtraEncoding)extraEncodings[encoding.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (extra != null) { + byte[] b = extra.CharToByte(char1, encoding); + if (b != null) + return b; + } + IntHashtable hash = null; + if (encoding.Equals(BaseFont.WINANSI)) + hash = winansi; + else if (encoding.Equals(PdfObject.TEXT_PDFDOCENCODING)) + hash = pdfEncoding; + if (hash != null) { + int c = 0; + if (char1 < 128 || (char1 > 160 && char1 <= 255)) + c = char1; + else + c = hash[char1]; + if (c != 0) + return new byte[]{(byte)c}; + else + return new byte[0]; + } + Encoding encw = IanaEncodings.GetEncodingEncoding(encoding); + byte[] preamble = encw.GetPreamble(); + char[] text = new char[]{char1}; + if (preamble.Length == 0) + return encw.GetBytes(text); + byte[] encoded = encw.GetBytes(text); + byte[] total = new byte[encoded.Length + preamble.Length]; + Array.Copy(preamble, 0, total, 0, preamble.Length); + Array.Copy(encoded, 0, total, preamble.Length, encoded.Length); + return total; + } + + public static string ConvertToString(byte[] bytes, string encoding) { + if (bytes == null) + return PdfObject.NOTHING; + if (encoding == null || encoding.Length == 0) { + char[] c = new char[bytes.Length]; + for (int k = 0; k < bytes.Length; ++k) + c[k] = (char)(bytes[k] & 0xff); + return new String(c); + } + IExtraEncoding extra = (IExtraEncoding)extraEncodings[encoding.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (extra != null) { + String text = extra.ByteToChar(bytes, encoding); + if (text != null) + return text; + } + char[] ch = null; + if (encoding.Equals(BaseFont.WINANSI)) + ch = winansiByteToChar; + else if (encoding.Equals(PdfObject.TEXT_PDFDOCENCODING)) + ch = pdfEncodingByteToChar; + if (ch != null) { + int len = bytes.Length; + char[] c = new char[len]; + for (int k = 0; k < len; ++k) { + c[k] = ch[bytes[k] & 0xff]; + } + return new String(c); + } + String nameU = encoding.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + bool marker = false; + bool big = false; + int offset = 0; + if (bytes.Length >= 2) { + if (bytes[0] == (byte)254 && bytes[1] == (byte)255) { + marker = true; + big = true; + offset = 2; + } + else if (bytes[0] == (byte)255 && bytes[1] == (byte)254) { + marker = true; + big = false; + offset = 2; + } + } + Encoding enc = null; + if (nameU.Equals("UNICODEBIGUNMARKED") || nameU.Equals("UNICODEBIG")) + enc = new UnicodeEncoding(marker ? big : true, false); + if (nameU.Equals("UNICODELITTLEUNMARKED") || nameU.Equals("UNICODELITTLE")) + enc = new UnicodeEncoding(marker ? big : false, false); + if (enc != null) + return enc.GetString(bytes, offset, bytes.Length - offset); + return IanaEncodings.GetEncodingEncoding(encoding).GetString(bytes); + } + + /** Checks is text only has PdfDocEncoding characters. + * @param text the String to test + * @return true if only PdfDocEncoding characters are present + */ + public static bool IsPdfDocEncoding(String text) { + if (text == null) + return true; + int len = text.Length; + for (int k = 0; k < len; ++k) { + char char1 = text[k]; + if (char1 < 128 || (char1 > 160 && char1 <= 255)) + continue; + if (!pdfEncoding.ContainsKey(char1)) + return false; + } + return true; + } + + internal static Hashtable cmaps = new Hashtable(); + /** Assumes that '\\n' and '\\r\\n' are the newline sequences. It may not work for + * all CJK encodings. To be used with LoadCmap(). + */ + public static byte[][] CRLF_CID_NEWLINE = new byte[][]{new byte[]{(byte)'\n'}, new byte[]{(byte)'\r', (byte)'\n'}}; + + /** Clears the CJK cmaps from the cache. If name is the + * empty string then all the cache is cleared. Calling this method + * has no consequences other than the need to reload the cmap + * if needed. + * @param name the name of the cmap to clear or all the cmaps if the empty string + */ + public static void ClearCmap(String name) { + lock (cmaps) { + if (name.Length == 0) + cmaps.Clear(); + else + cmaps.Remove(name); + } + } + + /** Loads a CJK cmap to the cache with the option of associating + * sequences to the newline. + * @param name the CJK cmap name + * @param newline the sequences to be replaced bi a newline in the resulting CID. See CRLF_CID_NEWLINE + */ + public static void LoadCmap(String name, byte[][] newline) { + char[][] planes = null; + lock (cmaps) { + planes = (char[][])cmaps[name]; + } + if (planes == null) { + planes = ReadCmap(name, newline); + lock (cmaps) { + cmaps[name] = planes; + } + } + } + + /** Converts a byte array encoded as name + * to a CID string. This is needed to reach some CJK characters + * that don't exist in 16 bit Unicode.

+ * The font to use this result must use the encoding "Identity-H" + * or "Identity-V".

+ * See ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/. + * @param name the CJK encoding name + * @param seq the byte array to be decoded + * @return the CID string + */ + public static String ConvertCmap(String name, byte[] seq) { + return ConvertCmap(name, seq, 0, seq.Length); + } + + /** Converts a byte array encoded as name + * to a CID string. This is needed to reach some CJK characters + * that don't exist in 16 bit Unicode.

+ * The font to use this result must use the encoding "Identity-H" + * or "Identity-V".

+ * See ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/. + * @param name the CJK encoding name + * @param start the start offset in the data + * @param length the number of bytes to convert + * @param seq the byte array to be decoded + * @return the CID string + */ + public static String ConvertCmap(String name, byte[] seq, int start, int length) { + char[][] planes = null; + lock (cmaps) { + planes = (char[][])cmaps[name]; + } + if (planes == null) { + planes = ReadCmap(name, (byte[][])null); + lock (cmaps) { + cmaps[name] = planes; + } + } + return DecodeSequence(seq, start, length, planes); + } + + internal static String DecodeSequence(byte[] seq, int start, int length, char[][] planes) { + StringBuilder buf = new StringBuilder(); + int end = start + length; + int currentPlane = 0; + for (int k = start; k < end; ++k) { + int one = (int)seq[k] & 0xff; + char[] plane = planes[currentPlane]; + int cid = plane[one]; + if ((cid & 0x8000) == 0) { + buf.Append((char)cid); + currentPlane = 0; + } + else + currentPlane = cid & 0x7fff; + } + return buf.ToString(); + } + + internal static char[][] ReadCmap(String name, byte[][] newline) { + ArrayList planes = new ArrayList(); + planes.Add(new char[256]); + ReadCmap(name, planes); + if (newline != null) { + for (int k = 0; k < newline.Length; ++k) + EncodeSequence(newline[k].Length, newline[k], BaseFont.CID_NEWLINE, planes); + } + char[][] ret = new char[planes.Count][]; + planes.CopyTo(ret, 0); + return ret; + } + + internal static void ReadCmap(String name, ArrayList planes) { + String fullName = BaseFont.RESOURCE_PATH + "cmaps." + name; + Stream inp = BaseFont.GetResourceStream(fullName); + if (inp == null) + throw new IOException("The Cmap " + name + " was not found."); + EncodeStream(inp, planes); + inp.Close(); + } + + internal static void EncodeStream(Stream inp, ArrayList planes) { + StreamReader rd = new StreamReader(inp, Encoding.ASCII); + String line = null; + int state = CIDNONE; + byte[] seqs = new byte[7]; + while ((line = rd.ReadLine()) != null) { + if (line.Length < 6) + continue; + switch (state) { + case CIDNONE: { + if (line.IndexOf("begincidrange") >= 0) + state = CIDRANGE; + else if (line.IndexOf("begincidchar") >= 0) + state = CIDCHAR; + else if (line.IndexOf("usecmap") >= 0) { + StringTokenizer tk = new StringTokenizer(line); + String t = tk.NextToken(); + ReadCmap(t.Substring(1), planes); + } + break; + } + case CIDRANGE: { + if (line.IndexOf("endcidrange") >= 0) { + state = CIDNONE; + break; + } + StringTokenizer tk = new StringTokenizer(line); + String t = tk.NextToken(); + int size = t.Length / 2 - 1; + long start = long.Parse(t.Substring(1, t.Length - 2), NumberStyles.HexNumber); + t = tk.NextToken(); + long end = long.Parse(t.Substring(1, t.Length - 2), NumberStyles.HexNumber); + t = tk.NextToken(); + int cid = int.Parse(t); + for (long k = start; k <= end; ++k) { + BreakLong(k, size, seqs); + EncodeSequence(size, seqs, (char)cid, planes); + ++cid; + } + break; + } + case CIDCHAR: { + if (line.IndexOf("endcidchar") >= 0) { + state = CIDNONE; + break; + } + StringTokenizer tk = new StringTokenizer(line); + String t = tk.NextToken(); + int size = t.Length / 2 - 1; + long start = long.Parse(t.Substring(1, t.Length - 2), NumberStyles.HexNumber); + t = tk.NextToken(); + int cid = int.Parse(t); + BreakLong(start, size, seqs); + EncodeSequence(size, seqs, (char)cid, planes); + break; + } + } + } + } + + internal static void BreakLong(long n, int size, byte[] seqs) { + for (int k = 0; k < size; ++k) { + seqs[k] = (byte)(n >> ((size - 1 - k) * 8)); + } + } + + internal static void EncodeSequence(int size, byte[] seqs, char cid, ArrayList planes) { + --size; + int nextPlane = 0; + char[] plane; + for (int idx = 0; idx < size; ++idx) { + plane = (char[])planes[nextPlane]; + int one = (int)seqs[idx] & 0xff; + char c = plane[one]; + if (c != 0 && (c & 0x8000) == 0) + throw new Exception("Inconsistent mapping."); + if (c == 0) { + planes.Add(new char[256]); + c = (char)((planes.Count - 1) | 0x8000); + plane[one] = c; + } + nextPlane = c & 0x7fff; + } + plane = (char[])planes[nextPlane]; + int ones = (int)seqs[size] & 0xff; + char cc = plane[ones]; + if ((cc & 0x8000) != 0) + throw new Exception("Inconsistent mapping."); + plane[ones] = cid; + } + + /** Adds an extra encoding. + * @param name the name of the encoding. The encoding recognition is case insensitive + * @param enc the conversion class + */ + public static void AddExtraEncoding(String name, IExtraEncoding enc) { + lock (extraEncodings) { // This serializes concurrent updates + Hashtable newEncodings = (Hashtable)extraEncodings.Clone(); + newEncodings[name.ToLower(System.Globalization.CultureInfo.InvariantCulture)] = enc; + extraEncodings = newEncodings; // This swap does not require synchronization with reader + } + } + + private class WingdingsConversion : IExtraEncoding { + + public byte[] CharToByte(char char1, String encoding) { + if (char1 == ' ') + return new byte[]{(byte)char1}; + else if (char1 >= '\u2701' && char1 <= '\u27BE') { + byte v = table[char1 - 0x2700]; + if (v != 0) + return new byte[]{v}; + } + return new byte[0]; + } + + public byte[] CharToByte(String text, String encoding) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c == ' ') + b[ptr++] = (byte)c; + else if (c >= '\u2701' && c <= '\u27BE') { + byte v = table[c - 0x2700]; + if (v != 0) + b[ptr++] = v; + } + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public String ByteToChar(byte[] b, String encoding) { + return null; + } + + private static byte[] table = { + 0, 35, 34, 0, 0, 0, 41, 62, 81, 42, + 0, 0, 65, 63, 0, 0, 0, 0, 0, (byte)(256-4), + 0, 0, 0, (byte)(256-5), 0, 0, 0, 0, 0, 0, + 86, 0, 88, 89, 0, 0, 0, 0, 0, 0, + 0, 0, (byte)(256-75), 0, 0, 0, 0, 0, (byte)(256-74), 0, + 0, 0, (byte)(256-83), (byte)(256-81), (byte)(256-84), 0, 0, 0, 0, 0, + 0, 0, 0, 124, 123, 0, 0, 0, 84, 0, + 0, 0, 0, 0, 0, 0, 0, (byte)(256-90), 0, 0, + 0, 113, 114, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 0, 125, 126, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, (byte)(256-116), (byte)(256-115), + (byte)(256-114), (byte)(256-113), (byte)(256-112), (byte)(256-111), (byte)(256-110), (byte)(256-109), (byte)(256-108), (byte)(256-107), (byte)(256-127), (byte)(256-126), + (byte)(256-125), (byte)(256-124), (byte)(256-123), (byte)(256-122), (byte)(256-121), (byte)(256-120), (byte)(256-119), (byte)(256-118), (byte)(256-116), (byte)(256-115), + (byte)(256-114), (byte)(256-113), (byte)(256-112), (byte)(256-111), (byte)(256-110), (byte)(256-109), (byte)(256-108), (byte)(256-107), (byte)(256-24), 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, (byte)(256-24), (byte)(256-40), 0, 0, (byte)(256-60), (byte)(256-58), 0, 0, (byte)(256-16), + 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)(256-36), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 + }; + } + + private class Cp437Conversion : IExtraEncoding { + private static IntHashtable c2b = new IntHashtable(); + + public byte[] CharToByte(String text, String encoding) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c < 128) + b[ptr++] = (byte)c; + else { + byte v = (byte)c2b[c]; + if (v != 0) + b[ptr++] = v; + } + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public byte[] CharToByte(char char1, String encoding) { + if (char1 < 128) + return new byte[]{(byte)char1}; + else { + byte v = (byte)c2b[char1]; + if (v != 0) + return new byte[]{v}; + else + return new byte[0]; + } + } + + public String ByteToChar(byte[] b, String encoding) { + int len = b.Length; + char[] cc = new char[len]; + int ptr = 0; + for (int k = 0; k < len; ++k) { + int c = b[k] & 0xff; + if (c < ' ') + continue; + if (c < 128) + cc[ptr++] = (char)c; + else { + char v = table[c - 128]; + cc[ptr++] = v; + } + } + return new String(cc, 0, ptr); + } + + private static char[] table = { + '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', + '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', '\u00FF', '\u00D6', '\u00DC', '\u00A2', '\u00A3', '\u00A5', '\u20A7', '\u0192', + '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', '\u00AA', '\u00BA', '\u00BF', '\u2310', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', + '\u2591', '\u2592', '\u2593', '\u2502', '\u2524', '\u2561', '\u2562', '\u2556', '\u2555', '\u2563', '\u2551', '\u2557', '\u255D', '\u255C', '\u255B', '\u2510', + '\u2514', '\u2534', '\u252C', '\u251C', '\u2500', '\u253C', '\u255E', '\u255F', '\u255A', '\u2554', '\u2569', '\u2566', '\u2560', '\u2550', '\u256C', '\u2567', + '\u2568', '\u2564', '\u2565', '\u2559', '\u2558', '\u2552', '\u2553', '\u256B', '\u256A', '\u2518', '\u250C', '\u2588', '\u2584', '\u258C', '\u2590', '\u2580', + '\u03B1', '\u00DF', '\u0393', '\u03C0', '\u03A3', '\u03C3', '\u00B5', '\u03C4', '\u03A6', '\u0398', '\u03A9', '\u03B4', '\u221E', '\u03C6', '\u03B5', '\u2229', + '\u2261', '\u00B1', '\u2265', '\u2264', '\u2320', '\u2321', '\u00F7', '\u2248', '\u00B0', '\u2219', '\u00B7', '\u221A', '\u207F', '\u00B2', '\u25A0', '\u00A0' + }; + + static Cp437Conversion() { + for (int k = 0; k < table.Length; ++k) + c2b[table[k]] = k + 128; + } + } + + private class SymbolConversion : IExtraEncoding { + + private static IntHashtable t1 = new IntHashtable(); + private static IntHashtable t2 = new IntHashtable(); + private IntHashtable translation; + + internal SymbolConversion(bool symbol) { + if (symbol) + translation = t1; + else + translation = t2; + } + + public byte[] CharToByte(String text, String encoding) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + byte v = (byte)translation[(int)c]; + if (v != 0) + b[ptr++] = v; + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public byte[] CharToByte(char char1, String encoding) { + byte v = (byte)translation[(int)char1]; + if (v != 0) + return new byte[]{v}; + else + return new byte[0]; + } + + public String ByteToChar(byte[] b, String encoding) { + return null; + } + + private static char[] table1 = { + ' ','!','\u2200','#','\u2203','%','&','\u220b','(',')','*','+',',','-','.','/', + '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?', + '\u2245','\u0391','\u0392','\u03a7','\u0394','\u0395','\u03a6','\u0393','\u0397','\u0399','\u03d1','\u039a','\u039b','\u039c','\u039d','\u039f', + '\u03a0','\u0398','\u03a1','\u03a3','\u03a4','\u03a5','\u03c2','\u03a9','\u039e','\u03a8','\u0396','[','\u2234',']','\u22a5','_', + '\u0305','\u03b1','\u03b2','\u03c7','\u03b4','\u03b5','\u03d5','\u03b3','\u03b7','\u03b9','\u03c6','\u03ba','\u03bb','\u03bc','\u03bd','\u03bf', + '\u03c0','\u03b8','\u03c1','\u03c3','\u03c4','\u03c5','\u03d6','\u03c9','\u03be','\u03c8','\u03b6','{','|','}','~','\0', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\u20ac','\u03d2','\u2032','\u2264','\u2044','\u221e','\u0192','\u2663','\u2666','\u2665','\u2660','\u2194','\u2190','\u2191','\u2192','\u2193', + '\u00b0','\u00b1','\u2033','\u2265','\u00d7','\u221d','\u2202','\u2022','\u00f7','\u2260','\u2261','\u2248','\u2026','\u2502','\u2500','\u21b5', + '\u2135','\u2111','\u211c','\u2118','\u2297','\u2295','\u2205','\u2229','\u222a','\u2283','\u2287','\u2284','\u2282','\u2286','\u2208','\u2209', + '\u2220','\u2207','\u00ae','\u00a9','\u2122','\u220f','\u221a','\u2022','\u00ac','\u2227','\u2228','\u21d4','\u21d0','\u21d1','\u21d2','\u21d3', + '\u25ca','\u2329','\0','\0','\0','\u2211','\u239b','\u239c','\u239d','\u23a1','\u23a2','\u23a3','\u23a7','\u23a8','\u23a9','\u23aa', + '\0','\u232a','\u222b','\u2320','\u23ae','\u2321','\u239e','\u239f','\u23a0','\u23a4','\u23a5','\u23a6','\u23ab','\u23ac','\u23ad','\0' + }; + + private static char[] table2 = { + '\u0020','\u2701','\u2702','\u2703','\u2704','\u260e','\u2706','\u2707','\u2708','\u2709','\u261b','\u261e','\u270C','\u270D','\u270E','\u270F', + '\u2710','\u2711','\u2712','\u2713','\u2714','\u2715','\u2716','\u2717','\u2718','\u2719','\u271A','\u271B','\u271C','\u271D','\u271E','\u271F', + '\u2720','\u2721','\u2722','\u2723','\u2724','\u2725','\u2726','\u2727','\u2605','\u2729','\u272A','\u272B','\u272C','\u272D','\u272E','\u272F', + '\u2730','\u2731','\u2732','\u2733','\u2734','\u2735','\u2736','\u2737','\u2738','\u2739','\u273A','\u273B','\u273C','\u273D','\u273E','\u273F', + '\u2740','\u2741','\u2742','\u2743','\u2744','\u2745','\u2746','\u2747','\u2748','\u2749','\u274A','\u274B','\u25cf','\u274D','\u25a0','\u274F', + '\u2750','\u2751','\u2752','\u25b2','\u25bc','\u25c6','\u2756','\u25d7','\u2758','\u2759','\u275A','\u275B','\u275C','\u275D','\u275E','\u0000', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\u0000','\u2761','\u2762','\u2763','\u2764','\u2765','\u2766','\u2767','\u2663','\u2666','\u2665','\u2660','\u2460','\u2461','\u2462','\u2463', + '\u2464','\u2465','\u2466','\u2467','\u2468','\u2469','\u2776','\u2777','\u2778','\u2779','\u277A','\u277B','\u277C','\u277D','\u277E','\u277F', + '\u2780','\u2781','\u2782','\u2783','\u2784','\u2785','\u2786','\u2787','\u2788','\u2789','\u278A','\u278B','\u278C','\u278D','\u278E','\u278F', + '\u2790','\u2791','\u2792','\u2793','\u2794','\u2192','\u2194','\u2195','\u2798','\u2799','\u279A','\u279B','\u279C','\u279D','\u279E','\u279F', + '\u27A0','\u27A1','\u27A2','\u27A3','\u27A4','\u27A5','\u27A6','\u27A7','\u27A8','\u27A9','\u27AA','\u27AB','\u27AC','\u27AD','\u27AE','\u27AF', + '\u0000','\u27B1','\u27B2','\u27B3','\u27B4','\u27B5','\u27B6','\u27B7','\u27B8','\u27B9','\u27BA','\u27BB','\u27BC','\u27BD','\u27BE','\u0000' + }; + + static SymbolConversion(){ + for (int k = 0; k < table1.Length; ++k) { + int v = (int)table1[k]; + if (v != 0) + t1[v] = k + 32; + } + for (int k = 0; k < table2.Length; ++k) { + int v = (int)table2[k]; + if (v != 0) + t2[v] = k + 32; + } + } + } + + private class SymbolTTConversion : IExtraEncoding { + + public byte[] CharToByte(char char1, String encoding) { + if ((char1 & 0xff00) == 0 || (char1 & 0xff00) == 0xf000) + return new byte[]{(byte)char1}; + else + return new byte[0]; + } + + public byte[] CharToByte(String text, String encoding) { + char[] ch = text.ToCharArray(); + byte[] b = new byte[ch.Length]; + int ptr = 0; + int len = ch.Length; + for (int k = 0; k < len; ++k) { + char c = ch[k]; + if ((c & 0xff00) == 0 || (c & 0xff00) == 0xf000) + b[ptr++] = (byte)c; + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public String ByteToChar(byte[] b, String encoding) { + return null; + } + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs b/iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs new file mode 100644 index 0000000..155e1d0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs @@ -0,0 +1,512 @@ +using System; +using System.Collections; +using System.Security.Cryptography; +using System.Text; +using System.IO; +using iTextSharp.text.pdf.crypto; +using Org.BouncyCastle.X509; + +/* + * $Id: PdfEncryption.cs,v 1.13 2007/06/14 20:01:48 psoares33 Exp $ + * + * Copyright 2001-2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * + * @author Paulo Soares (psoares@consiste.pt) + */ +public class PdfEncryption { + + public const int STANDARD_ENCRYPTION_40 = 2; + public const int STANDARD_ENCRYPTION_128 = 3; + public const int AES_128 = 4; + + private static byte[] pad = { + (byte)0x28, (byte)0xBF, (byte)0x4E, (byte)0x5E, (byte)0x4E, (byte)0x75, + (byte)0x8A, (byte)0x41, (byte)0x64, (byte)0x00, (byte)0x4E, (byte)0x56, + (byte)0xFF, (byte)0xFA, (byte)0x01, (byte)0x08, (byte)0x2E, (byte)0x2E, + (byte)0x00, (byte)0xB6, (byte)0xD0, (byte)0x68, (byte)0x3E, (byte)0x80, + (byte)0x2F, (byte)0x0C, (byte)0xA9, (byte)0xFE, (byte)0x64, (byte)0x53, + (byte)0x69, (byte)0x7A}; + + private static readonly byte[] salt = {(byte)0x73, (byte)0x41, (byte)0x6c, (byte)0x54}; + internal static readonly byte[] metadataPad = {(byte)255,(byte)255,(byte)255,(byte)255}; + /** The encryption key for a particular object/generation */ + internal byte[] key; + /** The encryption key length for a particular object/generation */ + internal int keySize; + /** The global encryption key */ + internal byte[] mkey; + /** Work area to prepare the object/generation bytes */ + internal byte[] extra = new byte[5]; + /** The message digest algorithm MD5 */ + internal MD5 md5; + /** The encryption key for the owner */ + internal byte[] ownerKey = new byte[32]; + /** The encryption key for the user */ + internal byte[] userKey = new byte[32]; + /** The public key security handler for certificate encryption */ + protected PdfPublicKeySecurityHandler publicKeyHandler = null; + internal int permissions; + internal byte[] documentID; + internal static long seq = DateTime.Now.Ticks + Environment.TickCount; + private int revision; + private ARCFOUREncryption rc4 = new ARCFOUREncryption(); + /** The generic key length. It may be 40 or 128. */ + private int keyLength; + private bool encryptMetadata; + private int cryptoMode; + + public PdfEncryption() { + md5 = new MD5CryptoServiceProvider(); + publicKeyHandler = new PdfPublicKeySecurityHandler(); + } + + public PdfEncryption(PdfEncryption enc) : this() { + mkey = (byte[])enc.mkey.Clone(); + ownerKey = (byte[])enc.ownerKey.Clone(); + userKey = (byte[])enc.userKey.Clone(); + permissions = enc.permissions; + if (enc.documentID != null) + documentID = (byte[])enc.documentID.Clone(); + revision = enc.revision; + keyLength = enc.keyLength; + encryptMetadata = enc.encryptMetadata; + publicKeyHandler = enc.publicKeyHandler; + } + + public void SetCryptoMode(int mode, int kl) { + cryptoMode = mode; + encryptMetadata = (mode & PdfWriter.DO_NOT_ENCRYPT_METADATA) == 0; + mode &= PdfWriter.ENCRYPTION_MASK; + switch (mode) { + case PdfWriter.STANDARD_ENCRYPTION_40: + encryptMetadata = true; + keyLength = 40; + revision = STANDARD_ENCRYPTION_40; + break; + case PdfWriter.STANDARD_ENCRYPTION_128: + if (kl > 0) + keyLength = kl; + else + keyLength = 128; + revision = STANDARD_ENCRYPTION_128; + break; + case PdfWriter.ENCRYPTION_AES_128: + keyLength = 128; + revision = AES_128; + break; + default: + throw new ArgumentException("No valid encryption mode"); + } + } + + public int GetCryptoMode() { + return cryptoMode; + } + + public bool IsMetadataEncrypted() { + return encryptMetadata; + } + + private byte[] PadPassword(byte[] userPassword) { + byte[] userPad = new byte[32]; + if (userPassword == null) { + Array.Copy(pad, 0, userPad, 0, 32); + } + else { + Array.Copy(userPassword, 0, userPad, 0, Math.Min(userPassword.Length, 32)); + if (userPassword.Length < 32) + Array.Copy(pad, 0, userPad, userPassword.Length, 32 - userPassword.Length); + } + + return userPad; + } + + /** + */ + private byte[] ComputeOwnerKey(byte[] userPad, byte[] ownerPad) { + byte[] ownerKey = new byte[32]; + + byte[] digest = md5.ComputeHash(ownerPad); + if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { + byte[] mkey = new byte[keyLength / 8]; + // only use for the input as many bit as the key consists of + for (int k = 0; k < 50; ++k) + Array.Copy(md5.ComputeHash(digest), 0, digest, 0, mkey.Length); + Array.Copy(userPad, 0, ownerKey, 0, 32); + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < mkey.Length ; ++j) + mkey[j] = (byte)(digest[j] ^ i); + rc4.PrepareARCFOURKey(mkey); + rc4.EncryptARCFOUR(ownerKey); + } + } + else { + rc4.PrepareARCFOURKey(digest, 0, 5); + rc4.EncryptARCFOUR(userPad, ownerKey); + } + + return ownerKey; + } + + /** + * + * ownerKey, documentID must be setuped + */ + private void SetupGlobalEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions) { + this.documentID = documentID; + this.ownerKey = ownerKey; + this.permissions = permissions; + // use variable keylength + mkey = new byte[keyLength / 8]; + + //fixed by ujihara in order to follow PDF refrence + md5.Initialize(); + md5.TransformBlock(userPad, 0, userPad.Length, userPad, 0); + md5.TransformBlock(ownerKey, 0, ownerKey.Length, ownerKey, 0); + + byte[] ext = new byte[4]; + ext[0] = (byte)permissions; + ext[1] = (byte)(permissions >> 8); + ext[2] = (byte)(permissions >> 16); + ext[3] = (byte)(permissions >> 24); + md5.TransformBlock(ext, 0, 4, ext, 0); + if (documentID != null) + md5.TransformBlock(documentID, 0, documentID.Length, documentID, 0); + if (!encryptMetadata) + md5.TransformBlock(metadataPad, 0, metadataPad.Length, metadataPad, 0); + md5.TransformFinalBlock(ext, 0, 0); + + byte[] digest = new byte[mkey.Length]; + Array.Copy(md5.Hash, 0, digest, 0, mkey.Length); + + + md5.Initialize(); + // only use the really needed bits as input for the hash + if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { + for (int k = 0; k < 50; ++k) { + Array.Copy(md5.ComputeHash(digest), 0, digest, 0, mkey.Length); + md5.Initialize(); + } + } + Array.Copy(digest, 0, mkey, 0, mkey.Length); + } + + /** + * + * mkey must be setuped + */ + // use the revision to choose the setup method + private void SetupUserKey() { + if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { + md5.TransformBlock(pad, 0, pad.Length, pad, 0); + md5.TransformFinalBlock(documentID, 0, documentID.Length); + byte[] digest = md5.Hash; + md5.Initialize(); + Array.Copy(digest, 0, userKey, 0, 16); + for (int k = 16; k < 32; ++k) + userKey[k] = 0; + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < mkey.Length; ++j) + digest[j] = (byte)(mkey[j] ^ i); + rc4.PrepareARCFOURKey(digest, 0, mkey.Length); + rc4.EncryptARCFOUR(userKey, 0, 16); + } + } + else { + rc4.PrepareARCFOURKey(mkey); + rc4.EncryptARCFOUR(pad, userKey); + } + } + + // gets keylength and revision and uses revison to choose the initial values for permissions + public void SetupAllKeys(byte[] userPassword, byte[] ownerPassword, int permissions) { + if (ownerPassword == null || ownerPassword.Length == 0) + ownerPassword = md5.ComputeHash(CreateDocumentId()); + md5.Initialize(); + permissions |= (int)((revision == STANDARD_ENCRYPTION_128 || revision == AES_128) ? (uint)0xfffff0c0 : (uint)0xffffffc0); + permissions &= unchecked((int)0xfffffffc); + //PDF refrence 3.5.2 Standard Security Handler, Algorithum 3.3-1 + //If there is no owner password, use the user password instead. + byte[] userPad = PadPassword(userPassword); + byte[] ownerPad = PadPassword(ownerPassword); + + this.ownerKey = ComputeOwnerKey(userPad, ownerPad); + documentID = CreateDocumentId(); + SetupByUserPad(this.documentID, userPad, this.ownerKey, permissions); + } + + public static byte[] CreateDocumentId() { + MD5 md5 = new MD5CryptoServiceProvider(); + long time = DateTime.Now.Ticks + Environment.TickCount; + long mem = GC.GetTotalMemory(false); + String s = time + "+" + mem + "+" + (seq++); + return md5.ComputeHash(Encoding.ASCII.GetBytes(s)); + } + + public void SetupByUserPassword(byte[] documentID, byte[] userPassword, byte[] ownerKey, int permissions) { + SetupByUserPad(documentID, PadPassword(userPassword), ownerKey, permissions); + } + + /** + */ + private void SetupByUserPad(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions) { + SetupGlobalEncryptionKey(documentID, userPad, ownerKey, permissions); + SetupUserKey(); + } + + /** + */ + public void SetupByOwnerPassword(byte[] documentID, byte[] ownerPassword, byte[] userKey, byte[] ownerKey, int permissions) { + SetupByOwnerPad(documentID, PadPassword(ownerPassword), userKey, ownerKey, permissions); + } + + private void SetupByOwnerPad(byte[] documentID, byte[] ownerPad, byte[] userKey, byte[] ownerKey, int permissions) { + byte[] userPad = ComputeOwnerKey(ownerKey, ownerPad); //userPad will be set in this.ownerKey + SetupGlobalEncryptionKey(documentID, userPad, ownerKey, permissions); //step 3 + SetupUserKey(); + } + + public void SetupByEncryptionKey(byte[] key, int keylength) { + mkey = new byte[keylength/8]; + System.Array.Copy(key, 0, mkey, 0, mkey.Length); + } + + public void SetHashKey(int number, int generation) { + md5.Initialize(); //added by ujihara + extra[0] = (byte)number; + extra[1] = (byte)(number >> 8); + extra[2] = (byte)(number >> 16); + extra[3] = (byte)generation; + extra[4] = (byte)(generation >> 8); + md5.TransformBlock(mkey, 0, mkey.Length, mkey, 0); + md5.TransformBlock(extra, 0, extra.Length, extra, 0); + if (revision == AES_128) + md5.TransformBlock(salt, 0, salt.Length, salt, 0); + md5.TransformFinalBlock(extra, 0, 0); + key = md5.Hash; + md5.Initialize(); + keySize = mkey.Length + 5; + if (keySize > 16) + keySize = 16; + } + + public static PdfObject CreateInfoId(byte[] id) { + ByteBuffer buf = new ByteBuffer(90); + buf.Append('[').Append('<'); + for (int k = 0; k < 16; ++k) + buf.AppendHex(id[k]); + buf.Append('>').Append('<'); + id = CreateDocumentId(); + for (int k = 0; k < 16; ++k) + buf.AppendHex(id[k]); + buf.Append('>').Append(']'); + return new PdfLiteral(buf.ToByteArray()); + } + + public PdfDictionary GetEncryptionDictionary() { + PdfDictionary dic = new PdfDictionary(); + + if (publicKeyHandler.GetRecipientsSize() > 0) { + PdfArray recipients = null; + + dic.Put(PdfName.FILTER, PdfName.PUBSEC); + dic.Put(PdfName.R, new PdfNumber(revision)); + + recipients = publicKeyHandler.GetEncodedRecipients(); + + if (revision == STANDARD_ENCRYPTION_40) { + dic.Put(PdfName.V, new PdfNumber(1)); + dic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S4); + dic.Put(PdfName.RECIPIENTS, recipients); + } + else if (revision == STANDARD_ENCRYPTION_128 && encryptMetadata) { + dic.Put(PdfName.V, new PdfNumber(2)); + dic.Put(PdfName.LENGTH, new PdfNumber(128)); + dic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S4); + dic.Put(PdfName.RECIPIENTS, recipients); + } + else { + dic.Put(PdfName.R, new PdfNumber(AES_128)); + dic.Put(PdfName.V, new PdfNumber(4)); + dic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S5); + + PdfDictionary stdcf = new PdfDictionary(); + stdcf.Put(PdfName.RECIPIENTS, recipients); + if (!encryptMetadata) + stdcf.Put(PdfName.ENCRYPTMETADATA, PdfBoolean.PDFFALSE); + + if (revision == AES_128) + stdcf.Put(PdfName.CFM, PdfName.AESV2); + else + stdcf.Put(PdfName.CFM, PdfName.V2); + PdfDictionary cf = new PdfDictionary(); + cf.Put(PdfName.DEFAULTCRYPTFILER, stdcf); + dic.Put(PdfName.CF, cf); + dic.Put(PdfName.STRF, PdfName.DEFAULTCRYPTFILER); + dic.Put(PdfName.STMF, PdfName.DEFAULTCRYPTFILER); + } + + SHA1 sh = new SHA1CryptoServiceProvider(); + byte[] encodedRecipient = null; + byte[] seed = publicKeyHandler.GetSeed(); + sh.TransformBlock(seed, 0, seed.Length, seed, 0); + for (int i=0; iPdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException on error + * @throws IOException on error */ + public static void Encrypt(PdfReader reader, Stream os, byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits); + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @param newInfo an optional String map to add or change + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits, Hashtable newInfo) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits); + stamper.MoreInfo = newInfo; + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException on error + * @throws IOException on error */ + public static void Encrypt(PdfReader reader, Stream os, bool strength, String userPassword, String ownerPassword, int permissions) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(strength, userPassword, ownerPassword, permissions); + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param newInfo an optional String map to add or change + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, bool strength, String userPassword, String ownerPassword, int permissions, Hashtable newInfo) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(strength, userPassword, ownerPassword, permissions); + stamper.MoreInfo = newInfo; + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param type the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param newInfo an optional String map to add or change + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, int type, String userPassword, String ownerPassword, int permissions, Hashtable newInfo) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(type, userPassword, ownerPassword, permissions); + stamper.MoreInfo = newInfo; + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param type the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, int type, String userPassword, String ownerPassword, int permissions) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(type, userPassword, ownerPassword, permissions); + stamper.Close(); + } + + /** + * Give you a verbose analysis of the permissions. + * @param permissions the permissions value of a PDF file + * @return a String that explains the meaning of the permissions value + */ + public static String GetPermissionsVerbose(int permissions) { + StringBuilder buf = new StringBuilder("Allowed:"); + if ((PdfWriter.ALLOW_PRINTING & permissions) == PdfWriter.ALLOW_PRINTING) buf.Append(" Printing"); + if ((PdfWriter.ALLOW_MODIFY_CONTENTS & permissions) == PdfWriter.ALLOW_MODIFY_CONTENTS) buf.Append(" Modify contents"); + if ((PdfWriter.ALLOW_COPY & permissions) == PdfWriter.ALLOW_COPY) buf.Append(" Copy"); + if ((PdfWriter.ALLOW_MODIFY_ANNOTATIONS & permissions) == PdfWriter.ALLOW_MODIFY_ANNOTATIONS) buf.Append(" Modify annotations"); + if ((PdfWriter.ALLOW_FILL_IN & permissions) == PdfWriter.ALLOW_FILL_IN) buf.Append(" Fill in"); + if ((PdfWriter.ALLOW_SCREENREADERS & permissions) == PdfWriter.ALLOW_SCREENREADERS) buf.Append(" Screen readers"); + if ((PdfWriter.ALLOW_ASSEMBLY & permissions) == PdfWriter.ALLOW_ASSEMBLY) buf.Append(" Assembly"); + if ((PdfWriter.ALLOW_DEGRADED_PRINTING & permissions) == PdfWriter.ALLOW_DEGRADED_PRINTING) buf.Append(" Degraded printing"); + return buf.ToString(); + } + + /** + * Tells you if printing is allowed. + * @param permissions the permissions value of a PDF file + * @return true if printing is allowed + * + * @since 2.0.7 + */ + public static bool IsPrintingAllowed(int permissions) { + return (PdfWriter.ALLOW_PRINTING & permissions) == PdfWriter.ALLOW_PRINTING; + } + + /** + * Tells you if modifying content is allowed. + * @param permissions the permissions value of a PDF file + * @return true if modifying content is allowed + * + * @since 2.0.7 + */ + public static bool IsModifyContentsAllowed(int permissions) { + return (PdfWriter.ALLOW_MODIFY_CONTENTS & permissions) == PdfWriter.ALLOW_MODIFY_CONTENTS; + } + + /** + * Tells you if copying is allowed. + * @param permissions the permissions value of a PDF file + * @return true if copying is allowed + * + * @since 2.0.7 + */ + public static bool IsCopyAllowed(int permissions) { + return (PdfWriter.ALLOW_COPY & permissions) == PdfWriter.ALLOW_COPY; + } + + /** + * Tells you if modifying annotations is allowed. + * @param permissions the permissions value of a PDF file + * @return true if modifying annotations is allowed + * + * @since 2.0.7 + */ + public static bool IsModifyAnnotationsAllowed(int permissions) { + return (PdfWriter.ALLOW_MODIFY_ANNOTATIONS & permissions) == PdfWriter.ALLOW_MODIFY_ANNOTATIONS; + } + + /** + * Tells you if filling in fields is allowed. + * @param permissions the permissions value of a PDF file + * @return true if filling in fields is allowed + * + * @since 2.0.7 + */ + public static bool IsFillInAllowed(int permissions) { + return (PdfWriter.ALLOW_FILL_IN & permissions) == PdfWriter.ALLOW_FILL_IN; + } + + /** + * Tells you if repurposing for screenreaders is allowed. + * @param permissions the permissions value of a PDF file + * @return true if repurposing for screenreaders is allowed + * + * @since 2.0.7 + */ + public static bool IsScreenReadersAllowed(int permissions) { + return (PdfWriter.ALLOW_SCREENREADERS & permissions) == PdfWriter.ALLOW_SCREENREADERS; + } + + /** + * Tells you if document assembly is allowed. + * @param permissions the permissions value of a PDF file + * @return true if document assembly is allowed + * + * @since 2.0.7 + */ + public static bool IsAssemblyAllowed(int permissions) { + return (PdfWriter.ALLOW_ASSEMBLY & permissions) == PdfWriter.ALLOW_ASSEMBLY; + } + + /** + * Tells you if degraded printing is allowed. + * @param permissions the permissions value of a PDF file + * @return true if degraded printing is allowed + * + * @since 2.0.7 + */ + public static bool IsDegradedPrintingAllowed(int permissions) { + return (PdfWriter.ALLOW_DEGRADED_PRINTING & permissions) == PdfWriter.ALLOW_DEGRADED_PRINTING; + } +} +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfException.cs b/iTechSharp/iTextSharp/text/pdf/PdfException.cs new file mode 100644 index 0000000..a31ac47 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfException.cs @@ -0,0 +1,68 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfException.cs,v 1.3 2008/05/13 11:25:20 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Signals that an unspecified problem while constructing a PDF document. + * + * @see BadPdfFormatException + */ + + public class PdfException : DocumentException { + public PdfException() : base() {} + + public PdfException(string message) : base(message) {} + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs b/iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs new file mode 100644 index 0000000..d6e77d5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs @@ -0,0 +1,261 @@ +using System; +using System.IO; +using System.Net; +using iTextSharp.text.pdf.collection; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except inp compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added inp the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), inp which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed inp the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Specifies a file or an URL. The file can be extern or embedded. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfFileSpecification : PdfDictionary { + protected PdfWriter writer; + protected PdfIndirectReference refi; + + /** Creates a new instance of PdfFileSpecification. The static methods are preferred. */ + public PdfFileSpecification() : base(PdfName.FILESPEC) { + } + + /** + * Creates a file specification of type URL. + * @param writer the PdfWriter + * @param url the URL + * @return the file specification + */ + public static PdfFileSpecification Url(PdfWriter writer, String url) { + PdfFileSpecification fs = new PdfFileSpecification(); + fs.writer = writer; + fs.Put(PdfName.FS, PdfName.URL); + fs.Put(PdfName.F, new PdfString(url)); + return fs; + } + + /** + * Creates a file specification with the file embedded. The file may + * come from the file system or from a byte array. The data is flate compressed. + * @param writer the PdfWriter + * @param filePath the file path + * @param fileDisplay the file information that is presented to the user + * @param fileStore the byte array with the file. If it is not null + * it takes precedence over filePath + * @throws IOException on error + * @return the file specification + */ + public static PdfFileSpecification FileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte[] fileStore) { + return FileEmbedded(writer, filePath, fileDisplay, fileStore, true); + } + + + /** + * Creates a file specification with the file embedded. The file may + * come from the file system or from a byte array. + * @param writer the PdfWriter + * @param filePath the file path + * @param fileDisplay the file information that is presented to the user + * @param fileStore the byte array with the file. If it is not null + * it takes precedence over filePath + * @param compress sets the compression on the data. Multimedia content will benefit little + * from compression + * @throws IOException on error + * @return the file specification + */ + public static PdfFileSpecification FileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte[] fileStore, bool compress) { + return FileEmbedded(writer, filePath, fileDisplay, fileStore, compress, null, null); + } + + /** + * Creates a file specification with the file embedded. The file may + * come from the file system or from a byte array. + * @param writer the PdfWriter + * @param filePath the file path + * @param fileDisplay the file information that is presented to the user + * @param fileStore the byte array with the file. If it is not null + * it takes precedence over filePath + * @param compress sets the compression on the data. Multimedia content will benefit little + * from compression + * @param mimeType the optional mimeType + * @param fileParameter the optional extra file parameters such as the creation or modification date + * @throws IOException on error + * @return the file specification + */ + public static PdfFileSpecification FileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte[] fileStore, bool compress, String mimeType, PdfDictionary fileParameter) { + PdfFileSpecification fs = new PdfFileSpecification(); + fs.writer = writer; + fs.Put(PdfName.F, new PdfString(fileDisplay)); + PdfStream stream; + Stream inp = null; + PdfIndirectReference refi; + PdfIndirectReference refFileLength; + try { + refFileLength = writer.PdfIndirectReference; + if (fileStore == null) { + if (File.Exists(filePath)) { + inp = new FileStream(filePath, FileMode.Open, FileAccess.Read); + } + else { + if (filePath.StartsWith("file:/") || filePath.StartsWith("http://") || filePath.StartsWith("https://")) { + WebRequest w = WebRequest.Create(filePath); + inp = w.GetResponse().GetResponseStream(); + } + else { + inp = BaseFont.GetResourceStream(filePath); + if (inp == null) + throw new IOException(filePath + " not found as file or resource."); + } + } + stream = new PdfStream(inp, writer); + } + else + stream = new PdfStream(fileStore); + stream.Put(PdfName.TYPE, PdfName.EMBEDDEDFILE); + if (compress) + stream.FlateCompress(); + stream.Put(PdfName.PARAMS, refFileLength); + if (mimeType != null) + stream.Put(PdfName.SUBTYPE, new PdfName(mimeType)); + refi = writer.AddToBody(stream).IndirectReference; + if (fileStore == null) { + stream.WriteLength(); + } + PdfDictionary param = new PdfDictionary(); + if (fileParameter != null) + param.Merge(fileParameter); + param.Put(PdfName.SIZE, new PdfNumber(stream.RawLength)); + writer.AddToBody(param, refFileLength); + } + finally { + if (inp != null) + try{inp.Close();}catch{} + } + PdfDictionary f = new PdfDictionary(); + f.Put(PdfName.F, refi); + fs.Put(PdfName.EF, f); + return fs; + } + + /** + * Creates a file specification for an external file. + * @param writer the PdfWriter + * @param filePath the file path + * @return the file specification + */ + public static PdfFileSpecification FileExtern(PdfWriter writer, String filePath) { + PdfFileSpecification fs = new PdfFileSpecification(); + fs.writer = writer; + fs.Put(PdfName.F, new PdfString(filePath)); + return fs; + } + + /** + * Gets the indirect reference to this file specification. + * Multiple invocations will retrieve the same value. + * @throws IOException on error + * @return the indirect reference + */ + public PdfIndirectReference Reference { + get { + if (refi != null) + return refi; + refi = writer.AddToBody(this).IndirectReference; + return refi; + } + } + + /** + * Sets the file name (the key /F) string as an hex representation + * to support multi byte file names. The name must have the slash and + * backslash escaped according to the file specification rules + * @param fileName the file name as a byte array + */ + public byte[] MultiByteFileName { + set { + Put(PdfName.F, new PdfString(value).SetHexWriting(true)); + } + } + + /** + * Adds the unicode file name (the key /UF). This entry was introduced + * in PDF 1.7. The filename must have the slash and backslash escaped + * according to the file specification rules. + * @param filename the filename + * @param unicode if true, the filename is UTF-16BE encoded; otherwise PDFDocEncoding is used; + */ + public void SetUnicodeFileName(String filename, bool unicode) { + Put(PdfName.UF, new PdfString(filename, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING)); + } + + /** + * Sets a flag that indicates whether an external file referenced by the file + * specification is volatile. If the value is true, applications should never + * cache a copy of the file. + * @param volatile_file if true, the external file should not be cached + */ + public bool Volatile { + set { + Put(PdfName.V, new PdfBoolean(value)); + } + } + + /** + * Adds a description for the file that is specified here. + * @param description some text + * @param unicode if true, the text is added as a unicode string + */ + public void AddDescription(String description, bool unicode) { + Put(PdfName.DESC, new PdfString(description, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING)); + } + + /** + * Adds the Collection item dictionary. + */ + public void AddCollectionItem(PdfCollectionItem ci) { + Put(PdfName.CI, ci); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFont.cs b/iTechSharp/iTextSharp/text/pdf/PdfFont.cs new file mode 100644 index 0000000..c4649b6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFont.cs @@ -0,0 +1,193 @@ +using System; +using iTextSharp.text; +/* + * $Id: PdfFont.cs,v 1.4 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfFont is the Pdf Font object. + *

+ * Limitation: in this class only base 14 Type 1 fonts (courier, courier bold, courier oblique, + * courier boldoblique, helvetica, helvetica bold, helvetica oblique, helvetica boldoblique, + * symbol, times roman, times bold, times italic, times bolditalic, zapfdingbats) and their + * standard encoding (standard, MacRoman, (MacExpert,) WinAnsi) are supported.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.7 (page 198-203). + * + * @see PdfName + * @see PdfDictionary + * @see BadPdfFormatException + */ + + public class PdfFont : IComparable { + + + /** the font metrics. */ + private BaseFont font; + + /** the size. */ + private float size; + + /** an image. */ + protected Image image; + + protected float hScale = 1; + + // constructors + + internal PdfFont(BaseFont bf, float size) { + this.size = size; + font = bf; + } + + // methods + + /** + * Compares this PdfFont with another + * + * @param object the other PdfFont + * @return a value + */ + + public int CompareTo(Object obj) { + if (image != null) + return 0; + if (obj == null) { + return -1; + } + PdfFont pdfFont; + try { + pdfFont = (PdfFont) obj; + if (font != pdfFont.font) { + return 1; + } + if (this.Size != pdfFont.Size) { + return 2; + } + return 0; + } + catch (InvalidCastException) { + return -2; + } + } + + /** + * Returns the size of this font. + * + * @return a size + */ + + internal float Size { + get { + if (image == null) + return size; + else { + return image.ScaledHeight; + } + } + } + + /** + * Returns the approximative width of 1 character of this font. + * + * @return a width in Text Space + */ + + internal float Width() { + return Width(' '); + } + + /** + * Returns the width of a certain character of this font. + * + * @param character a certain character + * @return a width in Text Space + */ + + internal float Width(int character) { + if (image == null) + return font.GetWidthPoint(character, size) * hScale; + else + return image.ScaledWidth; + } + + internal float Width(String s) { + if (image == null) + return font.GetWidthPoint(s, size) * hScale; + else + return image.ScaledWidth; + } + + internal BaseFont Font { + get { + return font; + } + } + + internal Image Image { + set { + this.image = value; + } + } + + internal static PdfFont DefaultFont { + get { + BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, false); + return new PdfFont(bf, 12); + } + } + + internal float HorizontalScaling { + set { + this.hScale = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFormField.cs b/iTechSharp/iTextSharp/text/pdf/PdfFormField.cs new file mode 100644 index 0000000..d0cd5e4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFormField.cs @@ -0,0 +1,353 @@ +using System; +using System.Drawing; +using System.Collections; + +using iTextSharp.text; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Implements form fields. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfFormField : PdfAnnotation { + + public const int FF_READ_ONLY = 1; + public const int FF_REQUIRED = 2; + public const int FF_NO_EXPORT = 4; + public const int FF_NO_TOGGLE_TO_OFF = 16384; + public const int FF_RADIO = 32768; + public const int FF_PUSHBUTTON = 65536; + public const int FF_MULTILINE = 4096; + public const int FF_PASSWORD = 8192; + public const int FF_COMBO = 131072; + public const int FF_EDIT = 262144; + public const int FF_FILESELECT = 1048576; + public const int FF_MULTISELECT = 2097152; + public const int FF_DONOTSPELLCHECK = 4194304; + public const int FF_DONOTSCROLL = 8388608; + public const int FF_COMB = 16777216; + public const int FF_RADIOSINUNISON = 1 << 25; + public const int Q_LEFT = 0; + public const int Q_CENTER = 1; + public const int Q_RIGHT = 2; + public const int MK_NO_ICON = 0; + public const int MK_NO_CAPTION = 1; + public const int MK_CAPTION_BELOW = 2; + public const int MK_CAPTION_ABOVE = 3; + public const int MK_CAPTION_RIGHT = 4; + public const int MK_CAPTION_LEFT = 5; + public const int MK_CAPTION_OVERLAID = 6; + public static readonly PdfName IF_SCALE_ALWAYS = PdfName.A; + public static readonly PdfName IF_SCALE_BIGGER = PdfName.B; + public static readonly PdfName IF_SCALE_SMALLER = PdfName.S; + public static readonly PdfName IF_SCALE_NEVER = PdfName.N; + public static readonly PdfName IF_SCALE_ANAMORPHIC = PdfName.A; + public static readonly PdfName IF_SCALE_PROPORTIONAL = PdfName.P; + public const bool MULTILINE = true; + public const bool SINGLELINE = false; + public const bool PLAINTEXT = false; + public const bool PASSWORD = true; + public static PdfName[] mergeTarget = {PdfName.FONT, PdfName.XOBJECT, PdfName.COLORSPACE, PdfName.PATTERN}; + + /** Holds value of property parent. */ + internal PdfFormField parent; + + internal ArrayList kids; + + /** + * Constructs a new PdfAnnotation of subtype link (Action). + */ + + public PdfFormField(PdfWriter writer, float llx, float lly, float urx, float ury, PdfAction action) : base(writer, llx, lly, urx, ury, action) { + Put(PdfName.TYPE, PdfName.ANNOT); + Put(PdfName.SUBTYPE, PdfName.WIDGET); + annotation = true; + } + + /** Creates new PdfFormField */ + internal PdfFormField(PdfWriter writer) : base(writer, null) { + form = true; + annotation = false; + } + + public void SetWidget(Rectangle rect, PdfName highlight) { + Put(PdfName.TYPE, PdfName.ANNOT); + Put(PdfName.SUBTYPE, PdfName.WIDGET); + Put(PdfName.RECT, new PdfRectangle(rect)); + annotation = true; + if (highlight != null && !highlight.Equals(HIGHLIGHT_INVERT)) + Put(PdfName.H, highlight); + } + + public static PdfFormField CreateEmpty(PdfWriter writer) { + PdfFormField field = new PdfFormField(writer); + return field; + } + + public int Button { + set { + Put(PdfName.FT, PdfName.BTN); + if (value != 0) + Put(PdfName.FF, new PdfNumber(value)); + } + } + + protected static PdfFormField CreateButton(PdfWriter writer, int flags) { + PdfFormField field = new PdfFormField(writer); + field.Button = flags; + return field; + } + + public static PdfFormField CreatePushButton(PdfWriter writer) { + return CreateButton(writer, FF_PUSHBUTTON); + } + + public static PdfFormField CreateCheckBox(PdfWriter writer) { + return CreateButton(writer, 0); + } + + public static PdfFormField CreateRadioButton(PdfWriter writer, bool noToggleToOff) { + return CreateButton(writer, FF_RADIO + (noToggleToOff ? FF_NO_TOGGLE_TO_OFF : 0)); + } + + public static PdfFormField CreateTextField(PdfWriter writer, bool multiline, bool password, int maxLen) { + PdfFormField field = new PdfFormField(writer); + field.Put(PdfName.FT, PdfName.TX); + int flags = (multiline ? FF_MULTILINE : 0); + flags += (password ? FF_PASSWORD : 0); + field.Put(PdfName.FF, new PdfNumber(flags)); + if (maxLen > 0) + field.Put(PdfName.MAXLEN, new PdfNumber(maxLen)); + return field; + } + + protected static PdfFormField CreateChoice(PdfWriter writer, int flags, PdfArray options, int topIndex) { + PdfFormField field = new PdfFormField(writer); + field.Put(PdfName.FT, PdfName.CH); + field.Put(PdfName.FF, new PdfNumber(flags)); + field.Put(PdfName.OPT, options); + if (topIndex > 0) + field.Put(PdfName.TI, new PdfNumber(topIndex)); + return field; + } + + public static PdfFormField CreateList(PdfWriter writer, String[] options, int topIndex) { + return CreateChoice(writer, 0, ProcessOptions(options), topIndex); + } + + public static PdfFormField CreateList(PdfWriter writer, String[,] options, int topIndex) { + return CreateChoice(writer, 0, ProcessOptions(options), topIndex); + } + + public static PdfFormField CreateCombo(PdfWriter writer, bool edit, String[] options, int topIndex) { + return CreateChoice(writer, FF_COMBO + (edit ? FF_EDIT : 0), ProcessOptions(options), topIndex); + } + + public static PdfFormField CreateCombo(PdfWriter writer, bool edit, String[,] options, int topIndex) { + return CreateChoice(writer, FF_COMBO + (edit ? FF_EDIT : 0), ProcessOptions(options), topIndex); + } + + protected static PdfArray ProcessOptions(String[] options) { + PdfArray array = new PdfArray(); + for (int k = 0; k < options.Length; ++k) { + array.Add(new PdfString(options[k], PdfObject.TEXT_UNICODE)); + } + return array; + } + + protected static PdfArray ProcessOptions(String[,] options) { + PdfArray array = new PdfArray(); + for (int k = 0; k < options.GetLength(0); ++k) { + PdfArray ar2 = new PdfArray(new PdfString(options[k, 0], PdfObject.TEXT_UNICODE)); + ar2.Add(new PdfString(options[k, 1], PdfObject.TEXT_UNICODE)); + array.Add(ar2); + } + return array; + } + + public static PdfFormField CreateSignature(PdfWriter writer) { + PdfFormField field = new PdfFormField(writer); + field.Put(PdfName.FT, PdfName.SIG); + return field; + } + + /** Getter for property parent. + * @return Value of property parent. + */ + public PdfFormField Parent { + get { + return parent; + } + } + + public void AddKid(PdfFormField field) { + field.parent = this; + if (kids == null) + kids = new ArrayList(); + kids.Add(field); + } + + public ArrayList Kids { + get { + return kids; + } + } + + public int SetFieldFlags(int flags) { + PdfNumber obj = (PdfNumber)Get(PdfName.FF); + int old; + if (obj == null) + old = 0; + else + old = obj.IntValue; + int v = old | flags; + Put(PdfName.FF, new PdfNumber(v)); + return old; + } + + public string ValueAsString { + set { + Put(PdfName.V, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string ValueAsName { + set { + Put(PdfName.V, new PdfName(value)); + } + } + + public PdfSignature ValueAsSig { + set { + Put(PdfName.V, value); + } + } + + public string DefaultValueAsString { + set { + Put(PdfName.DV, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string DefaultValueAsName { + set { + Put(PdfName.DV, new PdfName(value)); + } + } + + public string FieldName { + set { + if (value != null) + Put(PdfName.T, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string UserName { + set { + Put(PdfName.TU, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string MappingName { + set { + Put(PdfName.TM, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public int Quadding { + set { + Put(PdfName.Q, new PdfNumber(value)); + } + } + + internal static void MergeResources(PdfDictionary result, PdfDictionary source, PdfStamperImp writer) { + PdfDictionary dic = null; + PdfDictionary res = null; + PdfName target = null; + for (int k = 0; k < mergeTarget.Length; ++k) { + target = mergeTarget[k]; + PdfDictionary pdfDict = (PdfDictionary)PdfReader.GetPdfObject(source.Get(target)); + if ((dic = pdfDict) != null) { + if ((res = (PdfDictionary)PdfReader.GetPdfObject(result.Get(target), result)) == null) { + res = new PdfDictionary(); + } + res.MergeDifferent(dic); + result.Put(target, res); + if (writer != null) + writer.MarkUsed(res); + } + } + } + + internal static void MergeResources(PdfDictionary result, PdfDictionary source) { + MergeResources(result, source, null); + } + + public override void SetUsed() { + used = true; + if (parent != null) + Put(PdfName.PARENT, parent.IndirectReference); + if (kids != null) { + PdfArray array = new PdfArray(); + for (int k = 0; k < kids.Count; ++k) + array.Add(((PdfFormField)kids[k]).IndirectReference); + Put(PdfName.KIDS, array); + } + if (templates == null) + return; + PdfDictionary dic = new PdfDictionary(); + foreach (PdfTemplate template in templates.Keys) { + MergeResources(dic, (PdfDictionary)template.Resources); + } + Put(PdfName.DR, dic); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs new file mode 100644 index 0000000..fc9916a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs @@ -0,0 +1,104 @@ +using System; + +/* + * $Id: PdfFormXObject.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfFormObject is a type of XObject containing a template-object. + */ + + public class PdfFormXObject : PdfStream { + + // public static variables + + /** This is a PdfNumber representing 0. */ + public static PdfNumber ZERO = new PdfNumber(0); + + /** This is a PdfNumber representing 1. */ + public static PdfNumber ONE = new PdfNumber(1); + + /** This is the 1 - matrix. */ + public static PdfLiteral MATRIX = new PdfLiteral("[1 0 0 1 0 0]"); + + // membervariables + + + // constructor + + /** + * Constructs a PdfFormXObject-object. + * + * @param template the template + */ + + internal PdfFormXObject(PdfTemplate template) : base() { + Put(PdfName.TYPE, PdfName.XOBJECT); + Put(PdfName.SUBTYPE, PdfName.FORM); + Put(PdfName.RESOURCES, template.Resources); + Put(PdfName.BBOX, new PdfRectangle(template.BoundingBox)); + Put(PdfName.FORMTYPE, ONE); + PdfArray matrix = template.Matrix; + if (template.Layer != null) + Put(PdfName.OC, template.Layer.Ref); + if (template.Group != null) + Put(PdfName.GROUP, template.Group); + if (matrix == null) + Put(PdfName.MATRIX, MATRIX); + else + Put(PdfName.MATRIX, matrix); + bytes = template.ToPdf(null); + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + FlateCompress(); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFunction.cs b/iTechSharp/iTextSharp/text/pdf/PdfFunction.cs new file mode 100644 index 0000000..ad484ec --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFunction.cs @@ -0,0 +1,141 @@ +using System; +using System.IO; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements PDF functions. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfFunction { + + protected PdfWriter writer; + + protected PdfIndirectReference reference; + + protected PdfDictionary dictionary; + + /** Creates new PdfFunction */ + protected PdfFunction(PdfWriter writer) { + this.writer = writer; + } + + internal PdfIndirectReference Reference { + get { + if (reference == null) { + reference = writer.AddToBody(dictionary).IndirectReference; + } + return reference; + } + } + + public static PdfFunction Type0(PdfWriter writer, float[] domain, float[] range, int[] size, + int bitsPerSample, int order, float[] encode, float[] decode, byte[] stream) { + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfStream(stream); + ((PdfStream)func.dictionary).FlateCompress(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(0)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + func.dictionary.Put(PdfName.SIZE, new PdfArray(size)); + func.dictionary.Put(PdfName.BITSPERSAMPLE, new PdfNumber(bitsPerSample)); + if (order != 1) + func.dictionary.Put(PdfName.ORDER, new PdfNumber(order)); + if (encode != null) + func.dictionary.Put(PdfName.ENCODE, new PdfArray(encode)); + if (decode != null) + func.dictionary.Put(PdfName.DECODE, new PdfArray(decode)); + return func; + } + + public static PdfFunction Type2(PdfWriter writer, float[] domain, float[] range, float[] c0, float[] c1, float n) { + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfDictionary(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(2)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + if (range != null) + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + if (c0 != null) + func.dictionary.Put(PdfName.C0, new PdfArray(c0)); + if (c1 != null) + func.dictionary.Put(PdfName.C1, new PdfArray(c1)); + func.dictionary.Put(PdfName.N, new PdfNumber(n)); + return func; + } + + public static PdfFunction Type3(PdfWriter writer, float[] domain, float[] range, PdfFunction[] functions, float[] bounds, float[] encode) { + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfDictionary(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(3)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + if (range != null) + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + PdfArray array = new PdfArray(); + for (int k = 0; k < functions.Length; ++k) + array.Add(functions[k].Reference); + func.dictionary.Put(PdfName.FUNCTIONS, array); + func.dictionary.Put(PdfName.BOUNDS, new PdfArray(bounds)); + func.dictionary.Put(PdfName.ENCODE, new PdfArray(encode)); + return func; + } + + public static PdfFunction Type4(PdfWriter writer, float[] domain, float[] range, string postscript) { + byte[] b = new byte[postscript.Length]; + for (int k = 0; k < b.Length; ++k) + b[k] = (byte)postscript[k]; + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfStream(b); + ((PdfStream)func.dictionary).FlateCompress(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(4)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + return func; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfGState.cs b/iTechSharp/iTextSharp/text/pdf/PdfGState.cs new file mode 100644 index 0000000..f9f81e8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfGState.cs @@ -0,0 +1,170 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** The graphic state dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfGState : PdfDictionary { + /** A possible blend mode */ + public static PdfName BM_NORMAL = new PdfName("Normal"); + /** A possible blend mode */ + public static PdfName BM_COMPATIBLE = new PdfName("Compatible"); + /** A possible blend mode */ + public static PdfName BM_MULTIPLY = new PdfName("Multiply"); + /** A possible blend mode */ + public static PdfName BM_SCREEN = new PdfName("Screen"); + /** A possible blend mode */ + public static PdfName BM_OVERLAY = new PdfName("Overlay"); + /** A possible blend mode */ + public static PdfName BM_DARKEN = new PdfName("Darken"); + /** A possible blend mode */ + public static PdfName BM_LIGHTEN = new PdfName("Lighten"); + /** A possible blend mode */ + public static PdfName BM_COLORDODGE = new PdfName("ColorDodge"); + /** A possible blend mode */ + public static PdfName BM_COLORBURN = new PdfName("ColorBurn"); + /** A possible blend mode */ + public static PdfName BM_HARDLIGHT = new PdfName("HardLight"); + /** A possible blend mode */ + public static PdfName BM_SOFTLIGHT = new PdfName("SoftLight"); + /** A possible blend mode */ + public static PdfName BM_DIFFERENCE = new PdfName("Difference"); + /** A possible blend mode */ + public static PdfName BM_EXCLUSION = new PdfName("Exclusion"); + + /** + * Sets the flag whether to apply overprint for stroking. + * @param ov + */ + public bool OverPrintStroking { + set { + Put(PdfName.OP, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * Sets the flag whether to apply overprint for non stroking painting operations. + * @param ov + */ + public bool OverPrintNonStroking { + set { + Put(PdfName.op_, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * Sets the flag whether to toggle knockout behavior for overprinted objects. + * @param ov - accepts 0 or 1 + */ + public int OverPrintMode { + set { + Put(PdfName.OPM, new PdfNumber(value == 0 ? 0 : 1)); + } + } + + /** + * Sets the current stroking alpha constant, specifying the constant shape or + * constant opacity value to be used for stroking operations in the transparent + * imaging model. + * @param n + */ + public float StrokeOpacity { + set { + Put(PdfName.CA, new PdfNumber(value)); + } + } + + /** + * Sets the current stroking alpha constant, specifying the constant shape or + * constant opacity value to be used for nonstroking operations in the transparent + * imaging model. + * @param n + */ + public float FillOpacity { + set { + Put(PdfName.ca_, new PdfNumber(value)); + } + } + + /** + * The alpha source flag specifying whether the current soft mask + * and alpha constant are to be interpreted as shape values (true) + * or opacity values (false). + * @param v + */ + public bool AlphaIsShape { + set { + Put(PdfName.AIS, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * Determines the behaviour of overlapping glyphs within a text object + * in the transparent imaging model. + * @param v + */ + public bool TextKnockout { + set { + Put(PdfName.TK, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * The current blend mode to be used in the transparent imaging model. + * @param bm + */ + public PdfName BlendMode { + set { + Put(PdfName.BM, value); + } + } + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs b/iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs new file mode 100644 index 0000000..fdcc782 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs @@ -0,0 +1,33 @@ +using System; + +namespace iTextSharp.text.pdf { + + /** + * A PdfICCBased defines a ColorSpace + * + * @see PdfStream + */ + + public class PdfICCBased : PdfStream { + + public PdfICCBased(ICC_Profile profile) { + int numberOfComponents = profile.NumComponents; + switch (numberOfComponents) { + case 1: + Put(PdfName.ALTERNATE, PdfName.DEVICEGRAY); + break; + case 3: + Put(PdfName.ALTERNATE, PdfName.DEVICERGB); + break; + case 4: + Put(PdfName.ALTERNATE, PdfName.DEVICECMYK); + break; + default: + throw new PdfException(numberOfComponents + " Component(s) is not supported in iText"); + } + Put(PdfName.N, new PdfNumber(numberOfComponents)); + bytes = profile.Data; + FlateCompress(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfImage.cs b/iTechSharp/iTextSharp/text/pdf/PdfImage.cs new file mode 100644 index 0000000..68b80f8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfImage.cs @@ -0,0 +1,281 @@ +using System; +using System.IO; +using System.Net; +using iTextSharp.text; +/* + * $Id: PdfImage.cs,v 1.6 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfImage is a PdfStream containing an image-Dictionary and -stream. + */ + + public class PdfImage : PdfStream { + + internal const int TRANSFERSIZE = 4096; + // membervariables + + /** This is the PdfName of the image. */ + protected PdfName name = null; + + // constructor + + /** + * Constructs a PdfImage-object. + * + * @param image the Image-object + * @param name the PdfName for this image + * @throws BadPdfFormatException on error + */ + + public PdfImage(Image image, String name, PdfIndirectReference maskRef) { + this.name = new PdfName(name); + Put(PdfName.TYPE, PdfName.XOBJECT); + Put(PdfName.SUBTYPE, PdfName.IMAGE); + Put(PdfName.WIDTH, new PdfNumber(image.Width)); + Put(PdfName.HEIGHT, new PdfNumber(image.Height)); + if (image.Layer != null) + Put(PdfName.OC, image.Layer.Ref); + if (image.IsMask() && (image.Bpc == 1 || image.Bpc > 0xff)) + Put(PdfName.IMAGEMASK, PdfBoolean.PDFTRUE); + if (maskRef != null) { + if (image.Smask) + Put(PdfName.SMASK, maskRef); + else + Put(PdfName.MASK, maskRef); + } + if (image.IsMask() && image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0]")); + if (image.Interpolation) + Put(PdfName.INTERPOLATE, PdfBoolean.PDFTRUE); + Stream isp = null; + try { + // Raw Image data + if (image.IsImgRaw()) { + // will also have the CCITT parameters + int colorspace = image.Colorspace; + int[] transparency = image.Transparency; + if (transparency != null && !image.IsMask() && maskRef == null) { + String s = "["; + for (int k = 0; k < transparency.Length; ++k) + s += transparency[k] + " "; + s += "]"; + Put(PdfName.MASK, new PdfLiteral(s)); + } + bytes = image.RawData; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + int bpc = image.Bpc; + if (bpc > 0xff) { + if (!image.IsMask()) + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(1)); + Put(PdfName.FILTER, PdfName.CCITTFAXDECODE); + int k = bpc - Image.CCITTG3_1D; + PdfDictionary decodeparms = new PdfDictionary(); + if (k != 0) + decodeparms.Put(PdfName.K, new PdfNumber(k)); + if ((colorspace & Image.CCITT_BLACKIS1) != 0) + decodeparms.Put(PdfName.BLACKIS1, PdfBoolean.PDFTRUE); + if ((colorspace & Image.CCITT_ENCODEDBYTEALIGN) != 0) + decodeparms.Put(PdfName.ENCODEDBYTEALIGN, PdfBoolean.PDFTRUE); + if ((colorspace & Image.CCITT_ENDOFLINE) != 0) + decodeparms.Put(PdfName.ENDOFLINE, PdfBoolean.PDFTRUE); + if ((colorspace & Image.CCITT_ENDOFBLOCK) != 0) + decodeparms.Put(PdfName.ENDOFBLOCK, PdfBoolean.PDFFALSE); + decodeparms.Put(PdfName.COLUMNS, new PdfNumber(image.Width)); + decodeparms.Put(PdfName.ROWS, new PdfNumber(image.Height)); + Put(PdfName.DECODEPARMS, decodeparms); + } + else { + switch (colorspace) { + case 1: + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + if (image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0]")); + break; + case 3: + Put(PdfName.COLORSPACE, PdfName.DEVICERGB); + if (image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0]")); + break; + case 4: + default: + Put(PdfName.COLORSPACE, PdfName.DEVICECMYK); + if (image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); + break; + } + PdfDictionary additional = image.Additional; + if (additional != null) + Merge(additional); + if (image.IsMask() && (image.Bpc == 1 || image.Bpc > 8)) + Remove(PdfName.COLORSPACE); + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.Bpc)); + if (image.Deflated) + Put(PdfName.FILTER, PdfName.FLATEDECODE); + else { + FlateCompress(); + } + } + return; + } + + // GIF, JPEG or PNG + String errorID; + if (image.RawData == null){ + isp = WebRequest.Create(image.Url).GetResponse().GetResponseStream(); + errorID = image.Url.ToString(); + } + else{ + isp = new MemoryStream(image.RawData); + errorID = "Byte array"; + } + switch (image.Type) { + case Image.JPEG: + Put(PdfName.FILTER, PdfName.DCTDECODE); + switch (image.Colorspace) { + case 1: + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + break; + case 3: + Put(PdfName.COLORSPACE, PdfName.DEVICERGB); + break; + default: + Put(PdfName.COLORSPACE, PdfName.DEVICECMYK); + if (image.Inverted) { + Put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); + } + break; + } + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(8)); + if (image.RawData != null){ + bytes = image.RawData; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + return; + } + streamBytes = new MemoryStream(); + TransferBytes(isp, streamBytes, -1); + break; + case Image.JPEG2000: + Put(PdfName.FILTER, PdfName.JPXDECODE); + if (image.Colorspace > 0) { + switch (image.Colorspace) { + case 1: + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + break; + case 3: + Put(PdfName.COLORSPACE, PdfName.DEVICERGB); + break; + default: + Put(PdfName.COLORSPACE, PdfName.DEVICECMYK); + break; + } + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.Bpc)); + } + if (image.RawData != null){ + bytes = image.RawData; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + return; + } + streamBytes = new MemoryStream(); + TransferBytes(isp, streamBytes, -1); + break; + default: + throw new IOException(errorID + " is an unknown Image format."); + } + Put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); + } + finally { + if (isp != null) { + try{ + isp.Close(); + } + catch { + // empty on purpose + } + } + } + } + + /** + * Returns the PdfName of the image. + * + * @return the name + */ + + public PdfName Name { + get { + return name; + } + } + + internal static void TransferBytes(Stream inp, Stream outp, int len) { + byte[] buffer = new byte[TRANSFERSIZE]; + if (len < 0) + len = 0x7ffffff; + int size; + while (len != 0) { + size = inp.Read(buffer, 0, Math.Min(len, TRANSFERSIZE)); + if (size <= 0) + return; + outp.Write(buffer, 0, size); + len -= size; + } + } + + protected void ImportAll(PdfImage dup) { + name = dup.name; + compressed = dup.compressed; + streamBytes = dup.streamBytes; + bytes = dup.bytes; + hashMap = dup.hashMap; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs b/iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs new file mode 100644 index 0000000..4b12b79 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs @@ -0,0 +1,162 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfImportedPage.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Represents an imported page. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfImportedPage : PdfTemplate { + + internal PdfReaderInstance readerInstance; + internal int pageNumber; + + internal PdfImportedPage(PdfReaderInstance readerInstance, PdfWriter writer, int pageNumber) { + this.readerInstance = readerInstance; + this.pageNumber = pageNumber; + thisReference = writer.PdfIndirectReference; + bBox = readerInstance.Reader.GetPageSize(pageNumber); + type = TYPE_IMPORTED; + } + + /** Reads the content from this PdfImportedPage-object from a reader. + * + * @return self + * + */ + public PdfImportedPage FromReader { + get { + return this; + } + } + + public int PageNumber { + get { + return pageNumber; + } + } + + /** Always throws an error. This operation is not allowed. + * @param image dummy + * @param a dummy + * @param b dummy + * @param c dummy + * @param d dummy + * @param e dummy + * @param f dummy + * @throws DocumentException dummy */ + public override void AddImage(Image image, float a, float b, float c, float d, float e, float f) { + ThrowError(); + } + + /** Always throws an error. This operation is not allowed. + * @param template dummy + * @param a dummy + * @param b dummy + * @param c dummy + * @param d dummy + * @param e dummy + * @param f dummy */ + public override void AddTemplate(PdfTemplate template, float a, float b, float c, float d, float e, float f) { + ThrowError(); + } + + /** Always throws an error. This operation is not allowed. + * @return dummy */ + public override PdfContentByte Duplicate { + get { + ThrowError(); + return null; + } + } + + internal override PdfStream FormXObject { + get { + return readerInstance.GetFormXObject(pageNumber); + } + } + + public override void SetColorFill(PdfSpotColor sp, float tint) { + ThrowError(); + } + + public override void SetColorStroke(PdfSpotColor sp, float tint) { + ThrowError(); + } + + internal override PdfObject Resources { + get { + return readerInstance.GetResources(pageNumber); + } + } + + /** Always throws an error. This operation is not allowed. + * @param bf dummy + * @param size dummy */ + public override void SetFontAndSize(BaseFont bf, float size) { + ThrowError(); + } + + internal void ThrowError() { + throw new Exception("Content can not be added to a PdfImportedPage."); + } + + internal PdfReaderInstance PdfReaderInstance { + get { + return readerInstance; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs new file mode 100644 index 0000000..ec01fc6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs @@ -0,0 +1,157 @@ +using System; +using System.IO; + +using iTextSharp.text; + +/* + * $Id: PdfIndirectObject.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { +/** + * PdfIndirectObject is the Pdf indirect object. + *

+ * An indirect object is an object that has been labeled so that it can be referenced by + * other objects. Any type of PdfObject may be labeled as an indirect object.
+ * An indirect object consists of an object identifier, a direct object, and the endobj + * keyword. The object identifier consists of an integer object number, an integer + * generation number, and the obj keyword.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.10 (page 53). + * + * @see PdfObject + * @see PdfIndirectReference + */ + +public class PdfIndirectObject { + + // membervariables + + /** The object number */ + protected int number; + + /** the generation number */ + protected int generation = 0; + + internal static byte[] STARTOBJ = DocWriter.GetISOBytes(" obj"); + internal static byte[] ENDOBJ = DocWriter.GetISOBytes("\nendobj\n"); + internal static int SIZEOBJ = STARTOBJ.Length + ENDOBJ.Length; + internal PdfObject objecti; + internal PdfWriter writer; + + // constructors + + /** + * Constructs a PdfIndirectObject. + * + * @param number the objecti number + * @param objecti the direct objecti + */ + + internal PdfIndirectObject(int number, PdfObject objecti, PdfWriter writer) : this(number, 0, objecti, writer) { + } + + internal PdfIndirectObject(PdfIndirectReference refi, PdfObject objecti, PdfWriter writer) : this(refi.Number,refi.Generation,objecti,writer) { + } + /** + * Constructs a PdfIndirectObject. + * + * @param number the objecti number + * @param generation the generation number + * @param objecti the direct objecti + */ + + internal PdfIndirectObject(int number, int generation, PdfObject objecti, PdfWriter writer) { + this.writer = writer; + this.number = number; + this.generation = generation; + this.objecti = objecti; + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + if (crypto != null) { + crypto.SetHashKey(number, generation); + } + } + + // methods + + /** + * Returns a PdfIndirectReference to this PdfIndirectObject. + * + * @return a PdfIndirectReference + */ + + public PdfIndirectReference IndirectReference { + get { + return new PdfIndirectReference(objecti.Type, number, generation); + } + } + + /** + * Writes eficiently to a stream + * + * @param os the stream to write to + * @throws IOException on write error + */ + internal void WriteTo(Stream os) { + byte[] tmp = DocWriter.GetISOBytes(number.ToString()); + os.Write(tmp, 0, tmp.Length); + os.WriteByte((byte)' '); + tmp = DocWriter.GetISOBytes(generation.ToString()); + os.Write(tmp, 0, tmp.Length); + os.Write(STARTOBJ, 0, STARTOBJ.Length); + int type = objecti.Type; + if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) + os.WriteByte((byte)' '); + objecti.ToPdf(writer, os); + os.Write(ENDOBJ, 0, ENDOBJ.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs b/iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs new file mode 100644 index 0000000..443751a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs @@ -0,0 +1,137 @@ +using System; +using System.Text; + +/* + * $Id: PdfIndirectReference.cs,v 1.5 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfIndirectReference contains a reference to a PdfIndirectObject. + *

+ * Any object used as an element of an array or as a value in a dictionary may be specified + * by either a direct object of an indirect reference. An indirect reference is a reference + * to an indirect object, and consists of the indirect object's object number, generation number + * and the R keyword.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.11 (page 54). + * + * @see PdfObject + * @see PdfIndirectObject + */ + + public class PdfIndirectReference : PdfObject { + + // membervariables + + /** the object number */ + protected int number; + + /** the generation number */ + protected int generation = 0; + + // constructors + + protected PdfIndirectReference() : base(0) { + } + + /** + * Constructs a PdfIndirectReference. + * + * @param type the type of the PdfObject that is referenced to + * @param number the object number. + * @param generation the generation number. + */ + + internal PdfIndirectReference(int type, int number, int generation) : base(0, new StringBuilder().Append(number).Append(' ').Append(generation).Append(" R").ToString()) { + this.number = number; + this.generation = generation; + } + + /** + * Constructs a PdfIndirectReference. + * + * @param type the type of the PdfObject that is referenced to + * @param number the object number. + */ + + internal PdfIndirectReference(int type, int number) : this(type, number, 0) {} + + // methods + + /** + * Returns the number of the object. + * + * @return a number. + */ + + public int Number { + get { + return number; + } + } + + /** + * Returns the generation of the object. + * + * @return a number. + */ + + public int Generation { + get { + return generation; + } + } + + public override String ToString() { + return new StringBuilder().Append(number).Append(' ').Append(generation).Append(" R").ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLayer.cs b/iTechSharp/iTextSharp/text/pdf/PdfLayer.cs new file mode 100644 index 0000000..4cb3f39 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLayer.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * An optional content group is a dictionary representing a collection of graphics + * that can be made visible or invisible dynamically by users of viewer applications. + * In iText they are referenced as layers. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfLayer : PdfDictionary, IPdfOCG { + protected PdfIndirectReference refi; + protected ArrayList children; + protected PdfLayer parent; + protected String title; + + /** + * Holds value of property on. + */ + private bool on = true; + + /** + * Holds value of property onPanel. + */ + private bool onPanel = true; + + internal PdfLayer(String title) { + this.title = title; + } + + /** + * Creates a title layer. A title layer is not really a layer but a collection of layers + * under the same title heading. + * @param title the title text + * @param writer the PdfWriter + * @return the title layer + */ + public static PdfLayer CreateTitle(String title, PdfWriter writer) { + if (title == null) + throw new ArgumentNullException("Title cannot be null."); + PdfLayer layer = new PdfLayer(title); + writer.RegisterLayer(layer); + return layer; + } + /** + * Creates a new layer. + * @param name the name of the layer + * @param writer the writer + */ + public PdfLayer(String name, PdfWriter writer) : base(PdfName.OCG) { + Name = name; + refi = writer.PdfIndirectReference; + writer.RegisterLayer(this); + } + + internal String Title { + get { + return title; + } + } + + /** + * Adds a child layer. Nested layers can only have one parent. + * @param child the child layer + */ + public void AddChild(PdfLayer child) { + if (child.parent != null) + throw new ArgumentException("The layer '" + ((PdfString)child.Get(PdfName.NAME)).ToUnicodeString() + "' already has a parent."); + child.parent = this; + if (children == null) + children = new ArrayList(); + children.Add(child); + } + + + /** + * Gets the parent layer. + * @return the parent layer or null if the layer has no parent + */ + public PdfLayer Parent { + get { + return parent; + } + } + + /** + * Gets the children layers. + * @return the children layers or null if the layer has no children + */ + public ArrayList Children { + get { + return children; + } + } + + /** + * Gets the PdfIndirectReference that represents this layer. + * @return the PdfIndirectReference that represents this layer + */ + public PdfIndirectReference Ref { + get { + return refi; + } + set { + refi = value; + } + } + + /** + * Sets the name of this layer. + * @param name the name of this layer + */ + public string Name { + set { + Put(PdfName.NAME, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** + * Gets the dictionary representing the layer. It just returns this. + * @return the dictionary representing the layer + */ + public PdfObject PdfObject { + get { + return this; + } + } + + /** + * Gets the initial visibility of the layer. + * @return the initial visibility of the layer + */ + public bool On { + get { + return this.on; + } + set { + on = value; + } + } + + + private PdfDictionary Usage { + get { + PdfDictionary usage = (PdfDictionary)Get(PdfName.USAGE); + if (usage == null) { + usage = new PdfDictionary(); + Put(PdfName.USAGE, usage); + } + return usage; + } + } + + /** + * Used by the creating application to store application-specific + * data associated with this optional content group. + * @param creator a text string specifying the application that created the group + * @param subtype a string defining the type of content controlled by the group. Suggested + * values include but are not limited to Artwork, for graphic-design or publishing + * applications, and Technical, for technical designs such as building plans or + * schematics + */ + public void SetCreatorInfo(String creator, String subtype) { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.CREATOR, new PdfString(creator, PdfObject.TEXT_UNICODE)); + dic.Put(PdfName.SUBTYPE, new PdfName(subtype)); + usage.Put(PdfName.CREATORINFO, dic); + } + + /** + * Specifies the language of the content controlled by this + * optional content group + * @param lang a language string which specifies a language and possibly a locale + * (for example, es-MX represents Mexican Spanish) + * @param preferred used by viewer applications when there is a partial match but no exact + * match between the system language and the language strings in all usage dictionaries + */ + public void SetLanguage(String lang, bool preferred) { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.LANG, new PdfString(lang, PdfObject.TEXT_UNICODE)); + if (preferred) + dic.Put(PdfName.PREFERRED, PdfName.ON); + usage.Put(PdfName.LANGUAGE, dic); + } + + /** + * Specifies the recommended state for content in this + * group when the document (or part of it) is saved by a viewer application to a format + * that does not support optional content (for example, an earlier version of + * PDF or a raster image format). + * @param export the export state + */ + public bool Export { + set { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.EXPORTSTATE, value ? PdfName.ON : PdfName.OFF); + usage.Put(PdfName.EXPORT, dic); + } + } + + /** + * Specifies a range of magnifications at which the content + * in this optional content group is best viewed. + * @param min the minimum recommended magnification factors at which the group + * should be ON. A negative value will set the default to 0 + * @param max the maximum recommended magnification factor at which the group + * should be ON. A negative value will set the largest possible magnification supported by the + * viewer application + */ + public void SetZoom(float min, float max) { + if (min <= 0 && max < 0) + return; + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + if (min > 0) + dic.Put(PdfName.MIN, new PdfNumber(min)); + if (max >= 0) + dic.Put(PdfName.MAX, new PdfNumber(max)); + usage.Put(PdfName.ZOOM, dic); + } + + /** + * Specifies that the content in this group is intended for + * use in printing + * @param subtype a name specifying the kind of content controlled by the group; + * for example, Trapping, PrintersMarks and Watermark + * @param printstate indicates that the group should be + * set to that state when the document is printed from a viewer application + */ + public void SetPrint(String subtype, bool printstate) { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.SUBTYPE, new PdfName(subtype)); + dic.Put(PdfName.PRINTSTATE, printstate ? PdfName.ON : PdfName.OFF); + usage.Put(PdfName.PRINT, dic); + } + + /** + * Indicates that the group should be set to that state when the + * document is opened in a viewer application. + * @param view the view state + */ + public bool View { + set { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.VIEWSTATE, value ? PdfName.ON : PdfName.OFF); + usage.Put(PdfName.VIEW, dic); + } + } + + /** + * Gets the layer visibility in Acrobat's layer panel + * @return the layer visibility in Acrobat's layer panel + */ + /** + * Sets the visibility of the layer in Acrobat's layer panel. If false + * the layer cannot be directly manipulated by the user. Note that any children layers will + * also be absent from the panel. + * @param onPanel the visibility of the layer in Acrobat's layer panel + */ + public bool OnPanel { + get { + return this.onPanel; + } + set { + onPanel = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs b/iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs new file mode 100644 index 0000000..c7130cb --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Content typically belongs to a single optional content group, + * and is visible when the group is ON and invisible when it is OFF. To express more + * complex visibility policies, content should not declare itself to belong to an optional + * content group directly, but rather to an optional content membership dictionary + * represented by this class. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfLayerMembership : PdfDictionary, IPdfOCG { + + /** + * Visible only if all of the entries are ON. + */ + public static readonly PdfName ALLON = new PdfName("AllOn"); + /** + * Visible if any of the entries are ON. + */ + public static readonly PdfName ANYON = new PdfName("AnyOn"); + /** + * Visible if any of the entries are OFF. + */ + public static readonly PdfName ANYOFF = new PdfName("AnyOff"); + /** + * Visible only if all of the entries are OFF. + */ + public static readonly PdfName ALLOFF = new PdfName("AllOff"); + + internal PdfIndirectReference refi; + internal PdfArray members = new PdfArray(); + internal Hashtable layers = new Hashtable(); + + /** + * Creates a new, empty, membership layer. + * @param writer the writer + */ + public PdfLayerMembership(PdfWriter writer) : base(PdfName.OCMD) { + Put(PdfName.OCGS, members); + refi = writer.PdfIndirectReference; + } + + /** + * Gets the PdfIndirectReference that represents this membership layer. + * @return the PdfIndirectReference that represents this layer + */ + public PdfIndirectReference Ref { + get { + return refi; + } + } + + /** + * Adds a new member to the layer. + * @param layer the new member to the layer + */ + public void AddMember(PdfLayer layer) { + if (!layers.ContainsKey(layer)) { + members.Add(layer.Ref); + layers[layer] = null; + } + } + + /** + * Gets the member layers. + * @return the member layers + */ + public ICollection Layers { + get { + return layers.Keys; + } + } + + /** + * Sets the visibility policy for content belonging to this + * membership dictionary. Possible values are ALLON, ANYON, ANYOFF and ALLOFF. + * The default value is ANYON. + * @param type the visibility policy + */ + public PdfName VisibilityPolicy { + set { + Put(PdfName.P, value); + } + } + + /** + * Gets the dictionary representing the membership layer. It just returns this. + * @return the dictionary representing the layer + */ + public PdfObject PdfObject { + get { + return this; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLine.cs b/iTechSharp/iTextSharp/text/pdf/PdfLine.cs new file mode 100644 index 0000000..8d0ef90 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLine.cs @@ -0,0 +1,539 @@ +using System; +using System.Text; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfLine.cs,v 1.7 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfLine defines an array with PdfChunk-objects + * that fit into 1 line. + */ + + public class PdfLine { + + // membervariables + + /** The arraylist containing the chunks. */ + protected internal ArrayList line; + + /** The left indentation of the line. */ + protected internal float left; + + /** The width of the line. */ + protected internal float width; + + /** The alignment of the line. */ + protected internal int alignment; + + /** The heigth of the line. */ + protected internal float height; + + /** The listsymbol (if necessary). */ + protected internal Chunk listSymbol = null; + + /** The listsymbol (if necessary). */ + protected internal float symbolIndent; + + /** true if the chunk splitting was caused by a newline. */ + protected internal bool newlineSplit = false; + + /** The original width. */ + protected internal float originalWidth; + + protected internal bool isRTL = false; + + // constructors + + /** + * Constructs a new PdfLine-object. + * + * @param left the limit of the line at the left + * @param right the limit of the line at the right + * @param alignment the alignment of the line + * @param height the height of the line + */ + + internal PdfLine(float left, float right, int alignment, float height) { + this.left = left; + this.width = right - left; + this.originalWidth = this.width; + this.alignment = alignment; + this.height = height; + this.line = new ArrayList(); + } + + /** + * Creates a PdfLine object. + * @param left the left offset + * @param originalWidth the original width of the line + * @param remainingWidth bigger than 0 if the line isn't completely filled + * @param alignment the alignment of the line + * @param newlineSplit was the line splitted (or does the paragraph end with this line) + * @param line an array of PdfChunk objects + * @param isRTL do you have to read the line from Right to Left? + */ + internal PdfLine(float left, float originalWidth, float remainingWidth, int alignment, bool newlineSplit, ArrayList line, bool isRTL) { + this.left = left; + this.originalWidth = originalWidth; + this.width = remainingWidth; + this.alignment = alignment; + this.line = line; + this.newlineSplit = newlineSplit; + this.isRTL = isRTL; + } + + // methods + + /** + * Adds a PdfChunk to the PdfLine. + * + * @param chunk the PdfChunk to add + * @return null if the chunk could be added completely; if not + * a PdfChunk containing the part of the chunk that could + * not be added is returned + */ + + internal PdfChunk Add(PdfChunk chunk) { + // nothing happens if the chunk is null. + if (chunk == null || chunk.ToString().Equals("")) { + return null; + } + + // we split the chunk to be added + PdfChunk overflow = chunk.Split(width); + newlineSplit = (chunk.IsNewlineSplit() || overflow == null); + // if (chunk.IsNewlineSplit() && alignment == Element.ALIGN_JUSTIFIED) + // alignment = Element.ALIGN_LEFT; + if (chunk.IsTab()) { + Object[] tab = (Object[])chunk.GetAttribute(Chunk.TAB); + float tabPosition = (float)tab[1]; + bool newline = (bool)tab[2]; + if (newline && tabPosition < originalWidth - width) { + return chunk; + } + width = originalWidth - tabPosition; + chunk.AdjustLeft(left); + AddToLine(chunk); + } + // if the length of the chunk > 0 we add it to the line + else if (chunk.Length > 0) { + if (overflow != null) + chunk.TrimLastSpace(); + width -= chunk.Width; + AddToLine(chunk); + } + + // if the length == 0 and there were no other chunks added to the line yet, + // we risk to end up in an endless loop trying endlessly to add the same chunk + else if (line.Count < 1) { + chunk = overflow; + overflow = chunk.Truncate(width); + width -= chunk.Width; + if (chunk.Length > 0) { + AddToLine(chunk); + return overflow; + } + // if the chunck couldn't even be truncated, we add everything, so be it + else { + if (overflow != null) + AddToLine(chunk); + return null; + } + } + else { + width += ((PdfChunk)(line[line.Count - 1])).TrimLastSpace(); + } + return overflow; + } + + private void AddToLine(PdfChunk chunk) { + if (chunk.ChangeLeading && chunk.IsImage()) { + float f = chunk.Image.ScaledHeight + chunk.ImageOffsetY; + if (f > height) height = f; + } + line.Add(chunk); + } + + // methods to retrieve information + + /** + * Returns the number of chunks in the line. + * + * @return a value + */ + + public int Size { + get { + return line.Count; + } + } + + /** + * Returns an iterator of PdfChunks. + * + * @return an Iterator + */ + + public IEnumerator GetEnumerator() { + return line.GetEnumerator(); + } + + /** + * Returns the height of the line. + * + * @return a value + */ + + internal float Height { + get { + return height; + } + } + + /** + * Returns the left indentation of the line taking the alignment of the line into account. + * + * @return a value + */ + + internal float IndentLeft { + get { + if (isRTL) { + switch (alignment) { + case Element.ALIGN_LEFT: + return left + width; + case Element.ALIGN_CENTER: + return left + (width / 2f); + default: + return left; + } + } + else { + switch (alignment) { + case Element.ALIGN_RIGHT: + return left + width; + case Element.ALIGN_CENTER: + return left + (width / 2f); + default: + return left; + } + } + } + } + + /** + * Checks if this line has to be justified. + * + * @return true if the alignment equals ALIGN_JUSTIFIED and there is some width left. + */ + + public bool HasToBeJustified() { + return ((alignment == Element.ALIGN_JUSTIFIED || alignment == Element.ALIGN_JUSTIFIED_ALL) && width != 0); + } + + /** + * Resets the alignment of this line. + *

+ * The alignment of the last line of for instance a Paragraph + * that has to be justified, has to be reset to ALIGN_LEFT. + */ + + public void ResetAlignment() { + if (alignment == Element.ALIGN_JUSTIFIED) { + alignment = Element.ALIGN_LEFT; + } + } + + /** Adds extra indentation to the left (for Paragraph.setFirstLineIndent). */ + internal void SetExtraIndent(float extra) { + left += extra; + width -= extra; + } + + /** + * Returns the width that is left, after a maximum of characters is added to the line. + * + * @return a value + */ + + internal float WidthLeft { + get { + return width; + } + } + + /** + * Returns the number of space-characters in this line. + * + * @return a value + */ + + internal int NumberOfSpaces { + get { + string str = ToString(); + int length = str.Length; + int numberOfSpaces = 0; + for (int i = 0; i < length; i++) { + if (str[i] == ' ') { + numberOfSpaces++; + } + } + return numberOfSpaces; + } + } + + /** + * Sets the listsymbol of this line. + *

+ * This is only necessary for the first line of a ListItem. + * + * @param listItem the list symbol + */ + + public ListItem ListItem { + set { + this.listSymbol = value.ListSymbol; + this.symbolIndent = value.IndentationLeft; + } + } + + /** + * Returns the listsymbol of this line. + * + * @return a PdfChunk if the line has a listsymbol; null otherwise + */ + + public Chunk ListSymbol { + get { + return listSymbol; + } + } + + /** + * Return the indentation needed to show the listsymbol. + * + * @return a value + */ + + public float ListIndent { + get { + return symbolIndent; + } + } + + /** + * Get the string representation of what is in this line. + * + * @return a string + */ + + public override string ToString() { + StringBuilder tmp = new StringBuilder(); + foreach (PdfChunk c in line) { + tmp.Append(c.ToString()); + } + return tmp.ToString(); + } + + public int GetLineLengthUtf32() { + int total = 0; + foreach (PdfChunk c in line) { + total += c.LengthUtf32; + } + return total; + } + + /** + * Checks if a newline caused the line split. + * @return true if a newline caused the line split + */ + public bool NewlineSplit { + get { + return newlineSplit && (alignment != Element.ALIGN_JUSTIFIED_ALL); + } + } + + /** + * Gets the index of the last PdfChunk with metric attributes + * @return the last PdfChunk with metric attributes + */ + public int LastStrokeChunk { + get { + int lastIdx = line.Count - 1; + for (; lastIdx >= 0; --lastIdx) { + PdfChunk chunk = (PdfChunk)line[lastIdx]; + if (chunk.IsStroked()) + break; + } + return lastIdx; + } + } + + /** + * Gets a PdfChunk by index. + * @param idx the index + * @return the PdfChunk or null if beyond the array + */ + public PdfChunk GetChunk(int idx) { + if (idx < 0 || idx >= line.Count) + return null; + return (PdfChunk)line[idx]; + } + + /** + * Gets the original width of the line. + * @return the original width of the line + */ + public float OriginalWidth { + get { + return originalWidth; + } + } + + /** + * Gets the maximum size of all the fonts used in this line + * including images. + * @return maximum size of all the fonts used in this line + */ + internal float MaxSizeSimple { + get { + float maxSize = 0; + for (int k = 0; k < line.Count; ++k) { + PdfChunk chunk = (PdfChunk)line[k]; + if (!chunk.IsImage()) { + maxSize = Math.Max(chunk.Font.Size, maxSize); + } + else { + maxSize = Math.Max(chunk.Image.ScaledHeight + chunk.ImageOffsetY , maxSize); + } + } + return maxSize; + } + } + + internal bool RTL { + get { + return isRTL; + } + } + + /** + * Gets the number of separators in the line. + * @return the number of separators in the line + * @since 2.1.2 + */ + internal int GetSeparatorCount() { + int s = 0; + foreach (PdfChunk ck in line) { + if (ck.IsTab()) { + return 0; + } + if (ck.IsHorizontalSeparator()) { + s++; + } + } + return s; + } + + public float GetWidthCorrected(float charSpacing, float wordSpacing) { + float total = 0; + for (int k = 0; k < line.Count; ++k) { + PdfChunk ck = (PdfChunk)line[k]; + total += ck.GetWidthCorrected(charSpacing, wordSpacing); + } + return total; + } + + /** + * Gets the maximum size of the ascender for all the fonts used + * in this line. + * @return maximum size of all the ascenders used in this line + */ + public float Ascender { + get { + float ascender = 0; + foreach (PdfChunk ck in line) { + if (ck.IsImage()) + ascender = Math.Max(ascender, ck.Image.ScaledHeight + ck.ImageOffsetY); + else { + PdfFont font = ck.Font; + ascender = Math.Max(ascender, font.Font.GetFontDescriptor(BaseFont.ASCENT, font.Size)); + } + } + return ascender; + } + } + + /** + * Gets the biggest descender for all the fonts used + * in this line. Note that this is a negative number. + * @return maximum size of all the ascenders used in this line + */ + public float Descender { + get { + float descender = 0; + foreach (PdfChunk ck in line) { + if (ck.IsImage()) + descender = Math.Min(descender, ck.ImageOffsetY); + else { + PdfFont font = ck.Font; + descender = Math.Min(descender, font.Font.GetFontDescriptor(BaseFont.DESCENT, font.Size)); + } + } + return descender; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs b/iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs new file mode 100644 index 0000000..4e70fa7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; + +/* + * $Id: PdfLiteral.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + + /** + * a Literal + */ + + public class PdfLiteral : PdfObject { + + private int position; + + public PdfLiteral(string text) : base(0, text) {} + + public PdfLiteral(byte[] b) : base(0, b) {} + + public PdfLiteral(int type, string text) : base(type, text) {} + + public PdfLiteral(int type, byte[] b) : base(type, b) {} + + public PdfLiteral(int size) : base(0, (byte[])null) { + bytes = new byte[size]; + for (int k = 0; k < size; ++k) { + bytes[k] = 32; + } + } + + public override void ToPdf(PdfWriter writer, Stream os) { + if (os is OutputStreamCounter) + position = ((OutputStreamCounter)os).Counter; + base.ToPdf(writer, os); + } + + public int Position { + get { + return position; + } + } + + public int PosLength { + get { + if (bytes != null) + return bytes.Length; + else + return 0; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs b/iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs new file mode 100644 index 0000000..66d1abd --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs @@ -0,0 +1,63 @@ +using System; +/* + * Copyright 2003 Galo Gimenez + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PdfMediaClipData : PdfDictionary { + + internal PdfMediaClipData(String file, PdfFileSpecification fs, String mimeType) { + Put(PdfName.TYPE,new PdfName("MediaClip")); + Put(PdfName.S, new PdfName("MCD")); + Put(PdfName.N, new PdfString("Media clip for "+file)); + Put(new PdfName("CT"), new PdfString(mimeType)); + PdfDictionary dic = new PdfDictionary(); + dic.Put(new PdfName("TF"), new PdfString("TEMPACCESS")); + Put(new PdfName("P"), dic); + Put(PdfName.D, fs.Reference); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfName.cs b/iTechSharp/iTextSharp/text/pdf/PdfName.cs new file mode 100644 index 0000000..1a0951b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfName.cs @@ -0,0 +1,1257 @@ +using System; +using System.Text; + +/* + * $Id: PdfName.cs,v 1.31 2008/05/24 18:41:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfName is an object that can be used as a name in a PDF-file. + *

+ * A name, like a string, is a sequence of characters. It must begin with a slash + * followed by a sequence of ASCII characters in the range 32 through 136 except + * %, (, ), [, ], <, >, {, }, / and #. Any character except 0x00 may be included + * in a name by writing its twocharacter hex code, preceded by #. The maximum number + * of characters in a name is 127.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.5 (page 39-40). + *

+ * + * @see PdfObject + * @see PdfDictionary + * @see BadPdfFormatException + */ + + public class PdfName : PdfObject, IComparable { + + // static membervariables (a variety of standard names used in PDF) + + /** A name */ + public static readonly PdfName A = new PdfName("A"); + /** A name */ + public static readonly PdfName AA = new PdfName("AA"); + /** A name */ + public static readonly PdfName ABSOLUTECALORIMETRIC = new PdfName("AbsoluteColorimetric"); + /** A name */ + public static readonly PdfName AC = new PdfName("AC"); + /** A name */ + public static readonly PdfName ACROFORM = new PdfName("AcroForm"); + /** A name */ + public static readonly PdfName ACTION = new PdfName("Action"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_DETACHED = new PdfName("adbe.pkcs7.detached"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_S4 =new PdfName("adbe.pkcs7.s4"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_S5 =new PdfName("adbe.pkcs7.s5"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_SHA1 = new PdfName("adbe.pkcs7.sha1"); + /** A name */ + public static readonly PdfName ADBE_X509_RSA_SHA1 = new PdfName("adbe.x509.rsa_sha1"); + /** A name */ + public static readonly PdfName ADOBE_PPKLITE = new PdfName("Adobe.PPKLite"); + /** A name */ + public static readonly PdfName ADOBE_PPKMS = new PdfName("Adobe.PPKMS"); + /** A name */ + public static readonly PdfName AESV2 = new PdfName("AESV2"); + /** A name */ + public static readonly PdfName AIS = new PdfName("AIS"); + /** A name */ + public static readonly PdfName ALLPAGES = new PdfName("AllPages"); + /** A name */ + public static readonly PdfName ALT = new PdfName("Alt"); + /** A name */ + public static readonly PdfName ALTERNATE = new PdfName("Alternate"); + /** A name */ + public static readonly PdfName ANNOT = new PdfName("Annot"); + /** A name */ + public static readonly PdfName ANTIALIAS = new PdfName("AntiAlias"); + /** A name */ + public static readonly PdfName ANNOTS = new PdfName("Annots"); + /** A name */ + public static readonly PdfName AP = new PdfName("AP"); + /** A name */ + public static readonly PdfName APPDEFAULT = new PdfName("AppDefault"); + /** A name */ + public static readonly PdfName ARTBOX = new PdfName("ArtBox"); + /** A name */ + public static readonly PdfName ASCENT = new PdfName("Ascent"); + /** A name */ + public static readonly PdfName AS = new PdfName("AS"); + /** A name */ + public static readonly PdfName ASCII85DECODE = new PdfName("ASCII85Decode"); + /** A name */ + public static readonly PdfName ASCIIHEXDECODE = new PdfName("ASCIIHexDecode"); + /** A name */ + public static readonly PdfName AUTHEVENT = new PdfName("AuthEvent"); + /** A name */ + public static readonly PdfName AUTHOR = new PdfName("Author"); + /** A name */ + public static readonly PdfName B = new PdfName("B"); + /** A name */ + public static readonly PdfName BASEENCODING = new PdfName("BaseEncoding"); + /** A name */ + public static readonly PdfName BASEFONT = new PdfName("BaseFont"); + /** A name */ + public static readonly PdfName BBOX = new PdfName("BBox"); + /** A name */ + public static readonly PdfName BC = new PdfName("BC"); + /** A name */ + public static readonly PdfName BG = new PdfName("BG"); + /** A name */ + public static readonly PdfName BIGFIVE = new PdfName("BigFive"); + /** A name */ + public static readonly PdfName BITSPERCOMPONENT = new PdfName("BitsPerComponent"); + /** A name */ + public static readonly PdfName BITSPERSAMPLE = new PdfName("BitsPerSample"); + /** A name */ + public static readonly PdfName BL = new PdfName("Bl"); + /** A name */ + public static readonly PdfName BLACKIS1 = new PdfName("BlackIs1"); + /** A name */ + public static readonly PdfName BLACKPOINT = new PdfName("BlackPoint"); + /** A name */ + public static readonly PdfName BLEEDBOX = new PdfName("BleedBox"); + /** A name */ + public static readonly PdfName BLINDS = new PdfName("Blinds"); + /** A name */ + public static readonly PdfName BM = new PdfName("BM"); + /** A name */ + public static readonly PdfName BORDER = new PdfName("Border"); + /** A name */ + public static readonly PdfName BOUNDS = new PdfName("Bounds"); + /** A name */ + public static readonly PdfName BOX = new PdfName("Box"); + /** A name */ + public static readonly PdfName BS = new PdfName("BS"); + /** A name */ + public static readonly PdfName BTN = new PdfName("Btn"); + /** A name */ + public static readonly PdfName BYTERANGE = new PdfName("ByteRange"); + /** A name */ + public static readonly PdfName C = new PdfName("C"); + /** A name */ + public static readonly PdfName C0 = new PdfName("C0"); + /** A name */ + public static readonly PdfName C1 = new PdfName("C1"); + /** A name */ + public static readonly PdfName CA = new PdfName("CA"); + /** A name */ + public static readonly PdfName ca_ = new PdfName("ca"); + /** A name */ + public static readonly PdfName CALGRAY = new PdfName("CalGray"); + /** A name */ + public static readonly PdfName CALRGB = new PdfName("CalRGB"); + /** A name */ + public static readonly PdfName CAPHEIGHT = new PdfName("CapHeight"); + /** A name */ + public static readonly PdfName CATALOG = new PdfName("Catalog"); + /** A name */ + public static readonly PdfName CATEGORY = new PdfName("Category"); + /** A name */ + public static readonly PdfName CCITTFAXDECODE = new PdfName("CCITTFaxDecode"); + /** A name */ + public static readonly PdfName CENTERWINDOW = new PdfName("CenterWindow"); + /** A name */ + public static readonly PdfName CERT = new PdfName("Cert"); + /** A name */ + public static readonly PdfName CF = new PdfName("CF"); + /** A name */ + public static readonly PdfName CFM = new PdfName("CFM"); + /** A name */ + public static readonly PdfName CH = new PdfName("Ch"); + /** A name */ + public static readonly PdfName CHARPROCS = new PdfName("CharProcs"); + /** A name */ + public static readonly PdfName CI = new PdfName("CI"); + /** A name */ + public static readonly PdfName CIDFONTTYPE0 = new PdfName("CIDFontType0"); + /** A name */ + public static readonly PdfName CIDFONTTYPE2 = new PdfName("CIDFontType2"); + /** A name */ + public static readonly PdfName CIDSET = new PdfName("CIDSet"); + /** A name */ + public static readonly PdfName CIDSYSTEMINFO = new PdfName("CIDSystemInfo"); + /** A name */ + public static readonly PdfName CIDTOGIDMAP = new PdfName("CIDToGIDMap"); + /** A name */ + public static readonly PdfName CIRCLE = new PdfName("Circle"); + /** A name */ + public static readonly PdfName CO = new PdfName("CO"); + /** A name */ + public static readonly PdfName COLORS = new PdfName("Colors"); + /** A name */ + public static readonly PdfName COLORSPACE = new PdfName("ColorSpace"); + /** A name */ + public static readonly PdfName COLLECTION = new PdfName("Collection"); + /** A name */ + public static readonly PdfName COLLECTIONFIELD = new PdfName("CollectionField"); + /** A name */ + public static readonly PdfName COLLECTIONITEM = new PdfName("CollectionItem"); + /** A name */ + public static readonly PdfName COLLECTIONSCHEMA = new PdfName("CollectionSchema"); + /** A name */ + public static readonly PdfName COLLECTIONSORT = new PdfName("CollectionSort"); + /** A name */ + public static readonly PdfName COLLECTIONSUBITEM = new PdfName("CollectionSubitem"); + /** A name */ + public static readonly PdfName COLUMNS = new PdfName("Columns"); + /** A name */ + public static readonly PdfName CONTACTINFO = new PdfName("ContactInfo"); + /** A name */ + public static readonly PdfName CONTENT = new PdfName("Content"); + /** A name */ + public static readonly PdfName CONTENTS = new PdfName("Contents"); + /** A name */ + public static readonly PdfName COORDS = new PdfName("Coords"); + /** A name */ + public static readonly PdfName COUNT = new PdfName("Count"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER = new PdfName("Courier"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER_BOLD = new PdfName("Courier-Bold"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER_OBLIQUE = new PdfName("Courier-Oblique"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER_BOLDOBLIQUE = new PdfName("Courier-BoldOblique"); + /** A name */ + public static readonly PdfName CREATIONDATE = new PdfName("CreationDate"); + /** A name */ + public static readonly PdfName CREATOR = new PdfName("Creator"); + /** A name */ + public static readonly PdfName CREATORINFO = new PdfName("CreatorInfo"); + /** A name */ + public static readonly PdfName CROPBOX = new PdfName("CropBox"); + /** A name */ + public static readonly PdfName CRYPT = new PdfName("Crypt"); + /** A name */ + public static readonly PdfName CS = new PdfName("CS"); + /** A name */ + public static readonly PdfName D = new PdfName("D"); + /** A name */ + public static readonly PdfName DA = new PdfName("DA"); + /** A name */ + public static readonly PdfName DATA = new PdfName("Data"); + /** A name */ + public static readonly PdfName DC = new PdfName("DC"); + /** A name */ + public static readonly PdfName DCTDECODE = new PdfName("DCTDecode"); + /** A name */ + public static readonly PdfName DECODE = new PdfName("Decode"); + /** A name */ + public static readonly PdfName DECODEPARMS = new PdfName("DecodeParms"); + /** A name */ + public static readonly PdfName DEFAULTCRYPTFILER = new PdfName("DefaultCryptFilter"); + /** A name */ + public static readonly PdfName DEFAULTCMYK = new PdfName("DefaultCMYK"); + /** A name */ + public static readonly PdfName DEFAULTGRAY = new PdfName("DefaultGray"); + /** A name */ + public static readonly PdfName DEFAULTRGB = new PdfName("DefaultRGB"); + /** A name */ + public static readonly PdfName DESC = new PdfName("Desc"); + /** A name */ + public static readonly PdfName DESCENDANTFONTS = new PdfName("DescendantFonts"); + /** A name */ + public static readonly PdfName DESCENT = new PdfName("Descent"); + /** A name */ + public static readonly PdfName DEST = new PdfName("Dest"); + /** A name */ + public static readonly PdfName DESTOUTPUTPROFILE = new PdfName("DestOutputProfile"); + /** A name */ + public static readonly PdfName DESTS = new PdfName("Dests"); + /** A name */ + public static readonly PdfName DEVICEGRAY = new PdfName("DeviceGray"); + /** A name */ + public static readonly PdfName DEVICERGB = new PdfName("DeviceRGB"); + /** A name */ + public static readonly PdfName DEVICECMYK = new PdfName("DeviceCMYK"); + /** A name */ + public static readonly PdfName DI = new PdfName("Di"); + /** A name */ + public static readonly PdfName DIFFERENCES = new PdfName("Differences"); + /** A name */ + public static readonly PdfName DISSOLVE = new PdfName("Dissolve"); + /** A name */ + public static readonly PdfName DIRECTION = new PdfName("Direction"); + /** A name */ + public static readonly PdfName DISPLAYDOCTITLE = new PdfName("DisplayDocTitle"); + /** A name */ + public static readonly PdfName DIV = new PdfName("Div"); + /** A name */ + public static readonly PdfName DM = new PdfName("Dm"); + /** A name */ + public static readonly PdfName DOCMDP = new PdfName("DocMDP"); + /** A name */ + public static readonly PdfName DOCOPEN = new PdfName("DocOpen"); + /** A name */ + public static readonly PdfName DOMAIN = new PdfName("Domain"); + /** A name */ + public static readonly PdfName DP = new PdfName("DP"); + /** A name */ + public static readonly PdfName DR = new PdfName("DR"); + /** A name */ + public static readonly PdfName DS = new PdfName("DS"); + /** A name */ + public static readonly PdfName DUR = new PdfName("Dur"); + /** A name */ + public static readonly PdfName DUPLEX = new PdfName("Duplex"); + /** A name */ + public static readonly PdfName DUPLEXFLIPSHORTEDGE = new PdfName("DuplexFlipShortEdge"); + /** A name */ + public static readonly PdfName DUPLEXFLIPLONGEDGE = new PdfName("DuplexFlipLongEdge"); + /** A name */ + public static readonly PdfName DV = new PdfName("DV"); + /** A name */ + public static readonly PdfName DW = new PdfName("DW"); + /** A name */ + public static readonly PdfName E = new PdfName("E"); + /** A name */ + public static readonly PdfName EARLYCHANGE = new PdfName("EarlyChange"); + /** A name */ + public static readonly PdfName EF = new PdfName("EF"); + /** A name */ + public static readonly PdfName EMBEDDEDFILE = new PdfName("EmbeddedFile"); + /** A name */ + public static readonly PdfName EMBEDDEDFILES = new PdfName("EmbeddedFiles"); + /** A name */ + public static readonly PdfName ENCODE = new PdfName("Encode"); + /** A name */ + public static readonly PdfName ENCODEDBYTEALIGN = new PdfName("EncodedByteAlign"); + /** A name */ + public static readonly PdfName ENCODING = new PdfName("Encoding"); + /** A name */ + public static readonly PdfName ENCRYPT = new PdfName("Encrypt"); + /** A name */ + public static readonly PdfName ENCRYPTMETADATA = new PdfName("EncryptMetadata"); + /** A name */ + public static readonly PdfName ENDOFBLOCK = new PdfName("EndOfBlock"); + /** A name */ + public static readonly PdfName ENDOFLINE = new PdfName("EndOfLine"); + /** A name */ + public static readonly PdfName EXTEND = new PdfName("Extend"); + /** A name */ + public static readonly PdfName EXTGSTATE = new PdfName("ExtGState"); + /** A name */ + public static readonly PdfName EXPORT = new PdfName("Export"); + /** A name */ + public static readonly PdfName EXPORTSTATE = new PdfName("ExportState"); + /** A name */ + public static readonly PdfName EVENT = new PdfName("Event"); + /** A name */ + public static readonly PdfName F = new PdfName("F"); + /** A name */ + public static readonly PdfName FB = new PdfName("FB"); + /** A name */ + public static readonly PdfName FDECODEPARMS = new PdfName("FDecodeParms"); + /** A name */ + public static readonly PdfName FDF = new PdfName("FDF"); + /** A name */ + public static readonly PdfName FF = new PdfName("Ff"); + /** A name */ + public static readonly PdfName FFILTER = new PdfName("FFilter"); + /** A name */ + public static readonly PdfName FIELDS = new PdfName("Fields"); + /** A name */ + public static readonly PdfName FILEATTACHMENT = new PdfName("FileAttachment"); + /** A name */ + public static readonly PdfName FILESPEC = new PdfName("Filespec"); + /** A name */ + public static readonly PdfName FILTER = new PdfName("Filter"); + /** A name */ + public static readonly PdfName FIRST = new PdfName("First"); + /** A name */ + public static readonly PdfName FIRSTCHAR = new PdfName("FirstChar"); + /** A name */ + public static readonly PdfName FIRSTPAGE = new PdfName("FirstPage"); + /** A name */ + public static readonly PdfName FIT = new PdfName("Fit"); + /** A name */ + public static readonly PdfName FITH = new PdfName("FitH"); + /** A name */ + public static readonly PdfName FITV = new PdfName("FitV"); + /** A name */ + public static readonly PdfName FITR = new PdfName("FitR"); + /** A name */ + public static readonly PdfName FITB = new PdfName("FitB"); + /** A name */ + public static readonly PdfName FITBH = new PdfName("FitBH"); + /** A name */ + public static readonly PdfName FITBV = new PdfName("FitBV"); + /** A name */ + public static readonly PdfName FITWINDOW = new PdfName("FitWindow"); + /** A name */ + public static readonly PdfName FLAGS = new PdfName("Flags"); + /** A name */ + public static readonly PdfName FLATEDECODE = new PdfName("FlateDecode"); + /** A name */ + public static readonly PdfName FO = new PdfName("Fo"); + /** A name */ + public static readonly PdfName FONT = new PdfName("Font"); + /** A name */ + public static readonly PdfName FONTBBOX = new PdfName("FontBBox"); + /** A name */ + public static readonly PdfName FONTDESCRIPTOR = new PdfName("FontDescriptor"); + /** A name */ + public static readonly PdfName FONTFILE = new PdfName("FontFile"); + /** A name */ + public static readonly PdfName FONTFILE2 = new PdfName("FontFile2"); + /** A name */ + public static readonly PdfName FONTFILE3 = new PdfName("FontFile3"); + /** A name */ + public static readonly PdfName FONTMATRIX = new PdfName("FontMatrix"); + /** A name */ + public static readonly PdfName FONTNAME = new PdfName("FontName"); + /** A name */ + public static readonly PdfName FORM = new PdfName("Form"); + /** A name */ + public static readonly PdfName FORMTYPE = new PdfName("FormType"); + /** A name */ + public static readonly PdfName FREETEXT = new PdfName("FreeText"); + /** A name */ + public static readonly PdfName FRM = new PdfName("FRM"); + /** A name */ + public static readonly PdfName FS = new PdfName("FS"); + /** A name */ + public static readonly PdfName FT = new PdfName("FT"); + /** A name */ + public static readonly PdfName FULLSCREEN = new PdfName("FullScreen"); + /** A name */ + public static readonly PdfName FUNCTION = new PdfName("Function"); + /** A name */ + public static readonly PdfName FUNCTIONS = new PdfName("Functions"); + /** A name */ + public static readonly PdfName FUNCTIONTYPE = new PdfName("FunctionType"); + /** A name of an attribute. */ + public static readonly PdfName GAMMA = new PdfName("Gamma"); + /** A name of an attribute. */ + public static readonly PdfName GBK = new PdfName("GBK"); + /** A name of an attribute. */ + public static readonly PdfName GLITTER = new PdfName("Glitter"); + /** A name of an attribute. */ + public static readonly PdfName GOTO = new PdfName("GoTo"); + /** A name of an attribute. */ + public static readonly PdfName GOTOE = new PdfName("GoToE"); + /** A name of an attribute. */ + public static readonly PdfName GOTOR = new PdfName("GoToR"); + /** A name of an attribute. */ + public static readonly PdfName GROUP = new PdfName("Group"); + /** A name of an attribute. */ + public static readonly PdfName GTS_PDFA1 = new PdfName("GTS_PDFA1"); + /** A name of an attribute. */ + public static readonly PdfName GTS_PDFX = new PdfName("GTS_PDFX"); + /** A name of an attribute. */ + public static readonly PdfName GTS_PDFXVERSION = new PdfName("GTS_PDFXVersion"); + /** A name of an attribute. */ + public static readonly PdfName H = new PdfName("H"); + /** A name of an attribute. */ + public static readonly PdfName HEIGHT = new PdfName("Height"); + /** A name */ + public static readonly PdfName HELV = new PdfName("Helv"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName HELVETICA = new PdfName("Helvetica"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName HELVETICA_BOLD = new PdfName("Helvetica-Bold"); + /** This is a static PdfName PdfName of a base 14 type 1 font */ + public static readonly PdfName HELVETICA_OBLIQUE = new PdfName("Helvetica-Oblique"); + /** This is a static PdfName PdfName of a base 14 type 1 font */ + public static readonly PdfName HELVETICA_BOLDOBLIQUE = new PdfName("Helvetica-BoldOblique"); + /** A name */ + public static readonly PdfName HID = new PdfName("Hid"); + /** A name */ + public static readonly PdfName HIDE = new PdfName("Hide"); + /** A name */ + public static readonly PdfName HIDEMENUBAR = new PdfName("HideMenubar"); + /** A name */ + public static readonly PdfName HIDETOOLBAR = new PdfName("HideToolbar"); + /** A name */ + public static readonly PdfName HIDEWINDOWUI = new PdfName("HideWindowUI"); + /** A name */ + public static readonly PdfName HIGHLIGHT = new PdfName("Highlight"); + /** A name */ + public static readonly PdfName I = new PdfName("I"); + /** A name */ + public static readonly PdfName ICCBASED = new PdfName("ICCBased"); + /** A name */ + public static readonly PdfName ID = new PdfName("ID"); + /** A name */ + public static readonly PdfName IDENTITY = new PdfName("Identity"); + /** A name */ + public static readonly PdfName IF = new PdfName("IF"); + /** A name */ + public static readonly PdfName IMAGE = new PdfName("Image"); + /** A name */ + public static readonly PdfName IMAGEB = new PdfName("ImageB"); + /** A name */ + public static readonly PdfName IMAGEC = new PdfName("ImageC"); + /** A name */ + public static readonly PdfName IMAGEI = new PdfName("ImageI"); + /** A name */ + public static readonly PdfName IMAGEMASK = new PdfName("ImageMask"); + /** A name */ + public static readonly PdfName INDEX = new PdfName("Index"); + /** A name */ + public static readonly PdfName INDEXED = new PdfName("Indexed"); + /** A name */ + public static readonly PdfName INFO = new PdfName("Info"); + /** A name */ + public static readonly PdfName INK = new PdfName("Ink"); + /** A name */ + public static readonly PdfName INKLIST = new PdfName("InkList"); + /** A name */ + public static readonly PdfName IMPORTDATA = new PdfName("ImportData"); + /** A name */ + public static readonly PdfName INTENT = new PdfName("Intent"); + /** A name */ + public static readonly PdfName INTERPOLATE = new PdfName("Interpolate"); + /** A name */ + public static readonly PdfName ISMAP = new PdfName("IsMap"); + /** A name */ + public static readonly PdfName IRT = new PdfName("IRT"); + /** A name */ + public static readonly PdfName ITALICANGLE = new PdfName("ItalicAngle"); + /** A name */ + public static readonly PdfName IX = new PdfName("IX"); + /** A name */ + public static readonly PdfName JAVASCRIPT = new PdfName("JavaScript"); + /** A name */ + public static readonly PdfName JPXDECODE = new PdfName("JPXDecode"); + /** A name */ + public static readonly PdfName JS = new PdfName("JS"); + /** A name */ + public static readonly PdfName K = new PdfName("K"); + /** A name */ + public static readonly PdfName KEYWORDS = new PdfName("Keywords"); + /** A name */ + public static readonly PdfName KIDS = new PdfName("Kids"); + /** A name */ + public static readonly PdfName L = new PdfName("L"); + /** A name */ + public static readonly PdfName L2R = new PdfName("L2R"); + /** A name */ + public static readonly PdfName LANG = new PdfName("Lang"); + /** A name */ + public static readonly PdfName LANGUAGE = new PdfName("Language"); + /** A name */ + public static readonly PdfName LAST = new PdfName("Last"); + /** A name */ + public static readonly PdfName LASTCHAR = new PdfName("LastChar"); + /** A name */ + public static readonly PdfName LASTPAGE = new PdfName("LastPage"); + /** A name */ + public static readonly PdfName LAUNCH = new PdfName("Launch"); + /** A name */ + public static readonly PdfName LENGTH = new PdfName("Length"); + /** A name */ + public static readonly PdfName LENGTH1 = new PdfName("Length1"); + /** A name */ + public static readonly PdfName LIMITS = new PdfName("Limits"); + /** A name */ + public static readonly PdfName LINE = new PdfName("Line"); + /** A name */ + public static readonly PdfName LINK = new PdfName("Link"); + /** A name */ + public static readonly PdfName LISTMODE = new PdfName("ListMode"); + /** A name */ + public static readonly PdfName LOCATION = new PdfName("Location"); + /** A name */ + public static readonly PdfName LOCK = new PdfName("Lock"); + /** A name */ + public static readonly PdfName LOCKED = new PdfName("Locked"); + /** A name */ + public static readonly PdfName LZWDECODE = new PdfName("LZWDecode"); + /** A name */ + public static readonly PdfName M = new PdfName("M"); + /** A name */ + public static readonly PdfName MATRIX = new PdfName("Matrix"); + /** A name of an encoding */ + public static readonly PdfName MAC_EXPERT_ENCODING = new PdfName("MacExpertEncoding"); + /** A name of an encoding */ + public static readonly PdfName MAC_ROMAN_ENCODING = new PdfName("MacRomanEncoding"); + /** A name */ + public static readonly PdfName MARKED = new PdfName("Marked"); + /** A name */ + public static readonly PdfName MARKINFO = new PdfName("MarkInfo"); + /** A name */ + public static readonly PdfName MASK = new PdfName("Mask"); + /** A name */ + public static readonly PdfName MAX = new PdfName("max"); + /** A name */ + public static readonly PdfName MAXLEN = new PdfName("MaxLen"); + /** A name */ + public static readonly PdfName MEDIABOX = new PdfName("MediaBox"); + /** A name */ + public static readonly PdfName MCID = new PdfName("MCID"); + /** A name */ + public static readonly PdfName MCR = new PdfName("MCR"); + /** A name */ + public static readonly PdfName METADATA = new PdfName("Metadata"); + /** A name */ + public static readonly PdfName MIN = new PdfName("min"); + /** A name */ + public static readonly PdfName MK = new PdfName("MK"); + /** A name */ + public static readonly PdfName MMTYPE1 = new PdfName("MMType1"); + /** A name */ + public static readonly PdfName MODDATE = new PdfName("ModDate"); + /** A name */ + public static readonly PdfName N = new PdfName("N"); + /** A name */ + public static readonly PdfName N0 = new PdfName("n0"); + /** A name */ + public static readonly PdfName N1 = new PdfName("n1"); + /** A name */ + public static readonly PdfName N2 = new PdfName("n2"); + /** A name */ + public static readonly PdfName N3 = new PdfName("n3"); + /** A name */ + public static readonly PdfName N4 = new PdfName("n4"); + /** A name */ + public new static readonly PdfName NAME = new PdfName("Name"); + /** A name */ + public static readonly PdfName NAMED = new PdfName("Named"); + /** A name */ + public static readonly PdfName NAMES = new PdfName("Names"); + /** A name */ + public static readonly PdfName NEEDAPPEARANCES = new PdfName("NeedAppearances"); + /** A name */ + public static readonly PdfName NEWWINDOW = new PdfName("NewWindow"); + /** A name */ + public static readonly PdfName NEXT = new PdfName("Next"); + /** A name */ + public static readonly PdfName NEXTPAGE = new PdfName("NextPage"); + /** A name */ + public static readonly PdfName NM = new PdfName("NM"); + /** A name */ + public static readonly PdfName NONE = new PdfName("None"); + /** A name */ + public static readonly PdfName NONFULLSCREENPAGEMODE = new PdfName("NonFullScreenPageMode"); + /** A name */ + public static readonly PdfName NUMCOPIES = new PdfName("NumCopies"); + /** A name */ + public static readonly PdfName NUMS = new PdfName("Nums"); + /** A name */ + public static readonly PdfName O = new PdfName("O"); + /** A name */ + public static readonly PdfName OBJSTM = new PdfName("ObjStm"); + /** A name */ + public static readonly PdfName OC = new PdfName("OC"); + /** A name */ + public static readonly PdfName OCG = new PdfName("OCG"); + /** A name */ + public static readonly PdfName OCGS = new PdfName("OCGs"); + /** A name */ + public static readonly PdfName OCMD = new PdfName("OCMD"); + /** A name */ + public static readonly PdfName OCPROPERTIES = new PdfName("OCProperties"); + /** A name */ + public static readonly PdfName Off_ = new PdfName("Off"); + /** A name */ + public static readonly PdfName OFF = new PdfName("OFF"); + /** A name */ + public static readonly PdfName ON = new PdfName("ON"); + /** A name */ + public static readonly PdfName ONECOLUMN = new PdfName("OneColumn"); + /** A name */ + public static readonly PdfName OPEN = new PdfName("Open"); + /** A name */ + public static readonly PdfName OPENACTION = new PdfName("OpenAction"); + /** A name */ + public static readonly PdfName OP = new PdfName("OP"); + /** A name */ + public static readonly PdfName op_ = new PdfName("op"); + /** A name */ + public static readonly PdfName OPM = new PdfName("OPM"); + /** A name */ + public static readonly PdfName OPT = new PdfName("Opt"); + /** A name */ + public static readonly PdfName ORDER = new PdfName("Order"); + /** A name */ + public static readonly PdfName ORDERING = new PdfName("Ordering"); + /** A name */ + public static readonly PdfName OUTLINES = new PdfName("Outlines"); + /** A name */ + public static readonly PdfName OUTPUTCONDITION = new PdfName("OutputCondition"); + /** A name */ + public static readonly PdfName OUTPUTCONDITIONIDENTIFIER = new PdfName("OutputConditionIdentifier"); + /** A name */ + public static readonly PdfName OUTPUTINTENT = new PdfName("OutputIntent"); + /** A name */ + public static readonly PdfName OUTPUTINTENTS = new PdfName("OutputIntents"); + /** A name */ + public static readonly PdfName P = new PdfName("P"); + /** A name */ + public static readonly PdfName PAGE = new PdfName("Page"); + /** A name */ + public static readonly PdfName PAGELABELS = new PdfName("PageLabels"); + /** A name */ + public static readonly PdfName PAGELAYOUT = new PdfName("PageLayout"); + /** A name */ + public static readonly PdfName PAGEMODE = new PdfName("PageMode"); + /** A name */ + public static readonly PdfName PAGES = new PdfName("Pages"); + /** A name */ + public static readonly PdfName PAINTTYPE = new PdfName("PaintType"); + /** A name */ + public static readonly PdfName PANOSE = new PdfName("Panose"); + /** A name */ + public static readonly PdfName PARAMS = new PdfName("Params"); + /** A name */ + public static readonly PdfName PARENT = new PdfName("Parent"); + /** A name */ + public static readonly PdfName PARENTTREE = new PdfName("ParentTree"); + /** A name */ + public static readonly PdfName PATTERN = new PdfName("Pattern"); + /** A name */ + public static readonly PdfName PATTERNTYPE = new PdfName("PatternType"); + /** A name */ + public static readonly PdfName PDF = new PdfName("PDF"); + /** A name */ + public static readonly PdfName PDFDOCENCODING = new PdfName("PDFDocEncoding"); + /** A name */ + public static readonly PdfName PERCEPTUAL = new PdfName("Perceptual"); + /** A name */ + public static readonly PdfName PERMS = new PdfName("Perms"); + /** A name */ + public static readonly PdfName PG = new PdfName("Pg"); + /** A name */ + public static readonly PdfName PICKTRAYBYPDFSIZE = new PdfName("PickTrayByPDFSize"); + /** A name */ + public static readonly PdfName POPUP = new PdfName("Popup"); + /** A name */ + public static readonly PdfName PREDICTOR = new PdfName("Predictor"); + /** A name */ + public static readonly PdfName PREFERRED = new PdfName("Preferred"); + /** A name */ + public static readonly PdfName PRESERVERB = new PdfName("PreserveRB"); + /** A name */ + public static readonly PdfName PREV = new PdfName("Prev"); + /** A name */ + public static readonly PdfName PREVPAGE = new PdfName("PrevPage"); + /** A name */ + public static readonly PdfName PRINT = new PdfName("Print"); + /** A name */ + public static readonly PdfName PRINTAREA = new PdfName("PrintArea"); + /** A name */ + public static readonly PdfName PRINTCLIP = new PdfName("PrintClip"); + /** A name */ + public static readonly PdfName PRINTPAGERANGE = new PdfName("PrintPageRange"); + /** A name */ + public static readonly PdfName PRINTSCALING = new PdfName("PrintScaling"); + /** A name */ + public static readonly PdfName PRINTSTATE = new PdfName("PrintState"); + /** A name */ + public static readonly PdfName PROCSET = new PdfName("ProcSet"); + /** A name */ + public static readonly PdfName PRODUCER = new PdfName("Producer"); + /** A name */ + public static readonly PdfName PROPERTIES = new PdfName("Properties"); + /** A name */ + public static readonly PdfName PS = new PdfName("PS"); + /** A name */ + public static readonly PdfName PUBSEC = new PdfName("Adobe.PubSec"); + /** A name */ + public static readonly PdfName Q = new PdfName("Q"); + /** A name */ + public static readonly PdfName QUADPOINTS = new PdfName("QuadPoints"); + /** A name */ + public static readonly PdfName R = new PdfName("R"); + /** A name */ + public static readonly PdfName R2L = new PdfName("R2L"); + /** A name */ + public static readonly PdfName RANGE = new PdfName("Range"); + /** A name */ + public static readonly PdfName RC = new PdfName("RC"); + /** A name */ + public static readonly PdfName RBGROUPS = new PdfName("RBGroups"); + /** A name */ + public static readonly PdfName REASON = new PdfName("Reason"); + /** A name */ + public static readonly PdfName RECIPIENTS = new PdfName("Recipients"); + /** A name */ + public static readonly PdfName RECT = new PdfName("Rect"); + /** A name */ + public static readonly PdfName REFERENCE = new PdfName("Reference"); + /** A name */ + public static readonly PdfName REGISTRY = new PdfName("Registry"); + /** A name */ + public static readonly PdfName REGISTRYNAME = new PdfName("RegistryName"); + /** A name */ + public static readonly PdfName RELATIVECALORIMETRIC = new PdfName("RelativeColorimetric"); + /** A name */ + public static readonly PdfName RENDITION = new PdfName("Rendition"); + /** A name */ + public static readonly PdfName RESETFORM = new PdfName("ResetForm"); + /** A name */ + public static readonly PdfName RESOURCES = new PdfName("Resources"); + /** A name */ + public static readonly PdfName RI = new PdfName("RI"); + /** A name */ + public static readonly PdfName ROLEMAP = new PdfName("RoleMap"); + /** A name */ + public static readonly PdfName ROOT = new PdfName("Root"); + /** A name */ + public static readonly PdfName ROTATE = new PdfName("Rotate"); + /** A name */ + public static readonly PdfName ROWS = new PdfName("Rows"); + /** A name */ + public static readonly PdfName RUNLENGTHDECODE = new PdfName("RunLengthDecode"); + /** A name */ + public static readonly PdfName RV = new PdfName("RV"); + /** A name */ + public static readonly PdfName S = new PdfName("S"); + /** A name */ + public static readonly PdfName SATURATION = new PdfName("Saturation"); + /** A name */ + public static readonly PdfName SCHEMA = new PdfName("Schema"); + /** A name */ + public static readonly PdfName SCREEN = new PdfName("Screen"); + /** A name */ + public static readonly PdfName SECT = new PdfName("Sect"); + /** A name */ + public static readonly PdfName SEPARATION = new PdfName("Separation"); + /** A name */ + public static readonly PdfName SETOCGSTATE = new PdfName("SetOCGState"); + /** A name */ + public static readonly PdfName SHADING = new PdfName("Shading"); + /** A name */ + public static readonly PdfName SHADINGTYPE = new PdfName("ShadingType"); + /** A name */ + public static readonly PdfName SHIFT_JIS = new PdfName("Shift-JIS"); + /** A name */ + public static readonly PdfName SIG = new PdfName("Sig"); + /** A name */ + public static readonly PdfName SIGFLAGS = new PdfName("SigFlags"); + /** A name */ + public static readonly PdfName SIGREF = new PdfName("SigRef"); + /** A name */ + public static readonly PdfName SIMPLEX = new PdfName("Simplex"); + /** A name */ + public static readonly PdfName SINGLEPAGE = new PdfName("SinglePage"); + /** A name */ + public static readonly PdfName SIZE = new PdfName("Size"); + /** A name */ + public static readonly PdfName SMASK = new PdfName("SMask"); + /** A name */ + public static readonly PdfName SORT = new PdfName("Sort"); + /** A name */ + public static readonly PdfName SPAN = new PdfName("Span"); + /** A name */ + public static readonly PdfName SPLIT = new PdfName("Split"); + /** A name */ + public static readonly PdfName SQUARE = new PdfName("Square"); + /** A name */ + public static readonly PdfName SQUIGGLY = new PdfName("Squiggly"); + /** A name */ + public static readonly PdfName ST = new PdfName("St"); + /** A name */ + public static readonly PdfName STAMP = new PdfName("Stamp"); + /** A name */ + public static readonly PdfName STANDARD = new PdfName("Standard"); + /** A name */ + public static readonly PdfName STATE = new PdfName("State"); + /** A name */ + public static readonly PdfName STDCF = new PdfName("StdCF"); + /** A name */ + public static readonly PdfName STEMV = new PdfName("StemV"); + /** A name */ + public static readonly PdfName STMF = new PdfName("StmF"); + /** A name */ + public static readonly PdfName STRF = new PdfName("StrF"); + /** A name */ + public static readonly PdfName STRIKEOUT = new PdfName("StrikeOut"); + /** A name */ + public static readonly PdfName STRUCTPARENT = new PdfName("StructParent"); + /** A name */ + public static readonly PdfName STRUCTPARENTS = new PdfName("StructParents"); + /** A name */ + public static readonly PdfName STRUCTTREEROOT = new PdfName("StructTreeRoot"); + /** A name */ + public static readonly PdfName STYLE = new PdfName("Style"); + /** A name */ + public static readonly PdfName SUBFILTER = new PdfName("SubFilter"); + /** A name */ + public static readonly PdfName SUBJECT = new PdfName("Subject"); + /** A name */ + public static readonly PdfName SUBMITFORM = new PdfName("SubmitForm"); + /** A name */ + public static readonly PdfName SUBTYPE = new PdfName("Subtype"); + /** A name */ + public static readonly PdfName SUPPLEMENT = new PdfName("Supplement"); + /** A name */ + public static readonly PdfName SV = new PdfName("SV"); + /** A name */ + public static readonly PdfName SW = new PdfName("SW"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName SYMBOL = new PdfName("Symbol"); + /** A name */ + public static readonly PdfName T = new PdfName("T"); + /** A name */ + public static readonly PdfName TEXT = new PdfName("Text"); + /** A name */ + public static readonly PdfName THUMB = new PdfName("Thumb"); + /** A name */ + public static readonly PdfName THREADS = new PdfName("Threads"); + /** A name */ + public static readonly PdfName TI = new PdfName("TI"); + /** A name */ + public static readonly PdfName TILINGTYPE = new PdfName("TilingType"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_ROMAN = new PdfName("Times-Roman"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_BOLD = new PdfName("Times-Bold"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_ITALIC = new PdfName("Times-Italic"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_BOLDITALIC = new PdfName("Times-BoldItalic"); + /** A name */ + public static readonly PdfName TITLE = new PdfName("Title"); + /** A name */ + public static readonly PdfName TK = new PdfName("TK"); + /** A name */ + public static readonly PdfName TM = new PdfName("TM"); + /** A name */ + public static readonly PdfName TOGGLE = new PdfName("Toggle"); + /** A name */ + public static readonly PdfName TOUNICODE = new PdfName("ToUnicode"); + /** A name */ + public static readonly PdfName TP = new PdfName("TP"); + /** A name */ + public static readonly PdfName TRANS = new PdfName("Trans"); + /** A name */ + public static readonly PdfName TRANSFORMPARAMS = new PdfName("TransformParams"); + /** A name */ + public static readonly PdfName TRANSFORMMETHOD = new PdfName("TransformMethod"); + /** A name */ + public static readonly PdfName TRANSPARENCY = new PdfName("Transparency"); + /** A name */ + public static readonly PdfName TRAPPED = new PdfName("Trapped"); + /** A name */ + public static readonly PdfName TRIMBOX = new PdfName("TrimBox"); + /** A name */ + public static readonly PdfName TRUETYPE = new PdfName("TrueType"); + /** A name */ + public static readonly PdfName TU = new PdfName("TU"); + /** A name */ + public static readonly PdfName TWOCOLUMNLEFT = new PdfName("TwoColumnLeft"); + /** A name */ + public static readonly PdfName TWOCOLUMNRIGHT = new PdfName("TwoColumnRight"); + /** A name */ + public static readonly PdfName TWOPAGELEFT = new PdfName("TwoPageLeft"); + /** A name */ + public static readonly PdfName TWOPAGERIGHT = new PdfName("TwoPageRight"); + /** A name */ + public static readonly PdfName TX = new PdfName("Tx"); + /** A name */ + public static readonly PdfName TYPE = new PdfName("Type"); + /** A name */ + public static readonly PdfName TYPE0 = new PdfName("Type0"); + /** A name */ + public static readonly PdfName TYPE1 = new PdfName("Type1"); + /** A name of an attribute. */ + public static readonly PdfName TYPE3 = new PdfName("Type3"); + /** A name of an attribute. */ + public static readonly PdfName U = new PdfName("U"); + /** A name of an attribute. */ + public static readonly PdfName UF = new PdfName("UF"); + /** A name of an attribute. */ + public static readonly PdfName UHC = new PdfName("UHC"); + /** A name of an attribute. */ + public static readonly PdfName UNDERLINE = new PdfName("Underline"); + /** A name */ + public static readonly PdfName UR = new PdfName("UR"); + /** A name */ + public static readonly PdfName UR3 = new PdfName("UR3"); + /** A name */ + public static readonly PdfName URI = new PdfName("URI"); + /** A name */ + public static readonly PdfName URL = new PdfName("URL"); + /** A name */ + public static readonly PdfName USAGE = new PdfName("Usage"); + /** A name */ + public static readonly PdfName USEATTACHMENTS = new PdfName("UseAttachments"); + /** A name */ + public static readonly PdfName USENONE = new PdfName("UseNone"); + /** A name */ + public static readonly PdfName USEOC = new PdfName("UseOC"); + /** A name */ + public static readonly PdfName USEOUTLINES = new PdfName("UseOutlines"); + /** A name */ + public static readonly PdfName USER = new PdfName("User"); + /** A name */ + public static readonly PdfName USERPROPERTIES = new PdfName("UserProperties"); + /** A name */ + public static readonly PdfName USERUNIT = new PdfName("UserUnit"); + /** A name */ + public static readonly PdfName USETHUMBS = new PdfName("UseThumbs"); + /** A name */ + public static readonly PdfName V = new PdfName("V"); + /** A name */ + public static readonly PdfName V2 = new PdfName("V2"); + /** A name */ + public static readonly PdfName VERISIGN_PPKVS = new PdfName("VeriSign.PPKVS"); + /** A name */ + public static readonly PdfName VERSION = new PdfName("Version"); + /** A name */ + public static readonly PdfName VIEW = new PdfName("View"); + /** A name */ + public static readonly PdfName VIEWAREA = new PdfName("ViewArea"); + /** A name */ + public static readonly PdfName VIEWCLIP = new PdfName("ViewClip"); + /** A name */ + public static readonly PdfName VIEWERPREFERENCES = new PdfName("ViewerPreferences"); + /** A name */ + public static readonly PdfName VIEWSTATE = new PdfName("ViewState"); + /** A name */ + public static readonly PdfName VISIBLEPAGES = new PdfName("VisiblePages"); + /** A name of an attribute. */ + public static readonly PdfName W = new PdfName("W"); + /** A name of an attribute. */ + public static readonly PdfName W2 = new PdfName("W2"); + /** A name of an attribute. */ + public static readonly PdfName WC = new PdfName("WC"); + /** A name of an attribute. */ + public static readonly PdfName WIDGET = new PdfName("Widget"); + /** A name of an attribute. */ + public static readonly PdfName WIDTH = new PdfName("Width"); + /** A name */ + public static readonly PdfName WIDTHS = new PdfName("Widths"); + /** A name of an encoding */ + public static readonly PdfName WIN = new PdfName("Win"); + /** A name of an encoding */ + public static readonly PdfName WIN_ANSI_ENCODING = new PdfName("WinAnsiEncoding"); + /** A name of an encoding */ + public static readonly PdfName WIPE = new PdfName("Wipe"); + /** A name */ + public static readonly PdfName WHITEPOINT = new PdfName("WhitePoint"); + /** A name */ + public static readonly PdfName WP = new PdfName("WP"); + /** A name of an encoding */ + public static readonly PdfName WS = new PdfName("WS"); + /** A name */ + public static readonly PdfName X = new PdfName("X"); + /** A name */ + public static readonly PdfName XFA = new PdfName("XFA"); + /** A name */ + public static readonly PdfName XML = new PdfName("XML"); + /** A name */ + public static readonly PdfName XOBJECT = new PdfName("XObject"); + /** A name */ + public static readonly PdfName XSTEP = new PdfName("XStep"); + /** A name */ + public static readonly PdfName XREF = new PdfName("XRef"); + /** A name */ + public static readonly PdfName XREFSTM = new PdfName("XRefStm"); + /** A name */ + public static readonly PdfName XYZ = new PdfName("XYZ"); + /** A name */ + public static readonly PdfName YSTEP = new PdfName("YStep"); + /** A name */ + public static readonly PdfName ZADB = new PdfName("ZaDb"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName ZAPFDINGBATS = new PdfName("ZapfDingbats"); + /** A name */ + public static readonly PdfName ZOOM = new PdfName("Zoom"); + + private int hash = 0; + + // constructors + + /** + * Constructs a new PdfName. The name length will be checked. + * @param name the new name + */ + public PdfName(String name) : this(name, true) { + } + + /** + * Constructs a new PdfName. + * @param name the new name + * @param lengthCheck if true check the lenght validity, if false the name can + * have any length + */ + public PdfName(string name, bool lengthCheck) : base(PdfObject.NAME) { + // The minimum number of characters in a name is 0, the maximum is 127 (the '/' not included) + int length = name.Length; + if (lengthCheck && length > 127) { + throw new ArgumentException("The name '" + name + "' is too long (" + length + " characters)."); + } + // every special character has to be substituted + ByteBuffer pdfName = new ByteBuffer(length + 20); + pdfName.Append('/'); + char[] chars = name.ToCharArray(); + char character; + // loop over all the characters + foreach (char cc in chars) { + character = (char)(cc & 0xff); + // special characters are escaped (reference manual p.39) + switch (character) { + case ' ': + case '%': + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + case '{': + case '}': + case '/': + case '#': + pdfName.Append('#'); + pdfName.Append(System.Convert.ToString(character, 16)); + break; + default: + if (character > 126 || character < 32) { + pdfName.Append('#'); + if (character < 16) + pdfName.Append('0'); + pdfName.Append(System.Convert.ToString(character, 16)); + } + else + pdfName.Append(character); + break; + } + } + bytes = pdfName.ToByteArray(); + } + + public PdfName(byte[] bytes) : base(PdfObject.NAME, bytes) { + } + + // methods + + /** + * Compares this object with the specified object for order. Returns a + * negative int, zero, or a positive int as this object is less + * than, equal to, or greater than the specified object.

+ * + * + * @param object the Object to be compared. + * @return a negative int, zero, or a positive int as this object + * is less than, equal to, or greater than the specified object. + * + * @throws Exception if the specified object's type prevents it + * from being compared to this Object. + */ + public int CompareTo(Object obj) { + PdfName name = (PdfName) obj; + + byte[] myBytes = bytes; + byte[] objBytes = name.bytes; + int len = Math.Min(myBytes.Length, objBytes.Length); + for (int i=0; i objBytes[i]) + return 1; + + if (myBytes[i] < objBytes[i]) + return -1; + } + if (myBytes.Length < objBytes.Length) + return -1; + if (myBytes.Length > objBytes.Length) + return 1; + return 0; + } + + /** + * Indicates whether some other object is "equal to" this one. + * + * @param obj the reference object with which to compare. + * @return true if this object is the same as the obj + * argument; false otherwise. + */ + public override bool Equals(Object obj) { + if (this == obj) + return true; + if (obj is PdfName) + return CompareTo(obj) == 0; + return false; + } + + /** + * Returns a hash code value for the object. This method is + * supported for the benefit of hashtables such as those provided by + * java.util.Hashtable. + * + * @return a hash code value for this object. + */ + public override int GetHashCode() { + int h = hash; + if (h == 0) { + int ptr = 0; + int len = bytes.Length; + + for (int i = 0; i < len; i++) + h = 31*h + (bytes[ptr++] & 0xff); + hash = h; + } + return h; + } + + /** Decodes an escaped name in the form "/AB#20CD" into "AB CD". + * @param name the name to decode + * @return the decoded name + */ + public static string DecodeName(string name) { + StringBuilder buf = new StringBuilder(); + int len = name.Length; + for (int k = 1; k < len; ++k) { + char c = name[k]; + if (c == '#') { + c = (char)((PRTokeniser.GetHex(name[k + 1]) << 4) + PRTokeniser.GetHex(name[k + 2])); + k += 2; + } + buf.Append(c); + } + return buf.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs b/iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs new file mode 100644 index 0000000..a7617ef --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a name tree. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfNameTree { + + private const int leafSize = 64; + + /** + * Creates a name tree. + * @param items the item of the name tree. The key is a String + * and the value is a PdfObject. Note that although the + * keys are strings only the lower byte is used and no check is made for chars + * with the same lower byte and different upper byte. This will generate a wrong + * tree name. + * @param writer the writer + * @throws IOException on error + * @return the dictionary with the name tree. This dictionary is the one + * generally pointed to by the key /Dests, for example + */ + public static PdfDictionary WriteTree(Hashtable items, PdfWriter writer) { + if (items.Count == 0) + return null; + String[] names = new String[items.Count]; + items.Keys.CopyTo(names, 0); + Array.Sort(names); + if (names.Length <= leafSize) { + PdfDictionary dic = new PdfDictionary(); + PdfArray ar = new PdfArray(); + for (int k = 0; k < names.Length; ++k) { + ar.Add(new PdfString(names[k], null)); + ar.Add((PdfObject)items[names[k]]); + } + dic.Put(PdfName.NAMES, ar); + return dic; + } + int skip = leafSize; + PdfIndirectReference[] kids = new PdfIndirectReference[(names.Length + leafSize - 1) / leafSize]; + for (int k = 0; k < kids.Length; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, names.Length); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfString(names[offset], null)); + arr.Add(new PdfString(names[end - 1], null)); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(new PdfString(names[offset], null)); + arr.Add((PdfObject)items[names[offset]]); + } + dic.Put(PdfName.NAMES, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + int top = kids.Length; + while (true) { + if (top <= leafSize) { + PdfArray arr = new PdfArray(); + for (int k = 0; k < top; ++k) + arr.Add(kids[k]); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.KIDS, arr); + return dic; + } + skip *= leafSize; + int tt = (names.Length + skip - 1 )/ skip; + for (int k = 0; k < tt; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, top); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfString(names[k * skip], null)); + arr.Add(new PdfString(names[Math.Min((k + 1) * skip, names.Length) - 1], null)); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(kids[offset]); + } + dic.Put(PdfName.KIDS, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + top = tt; + } + } + + private static void IterateItems(PdfDictionary dic, Hashtable items) { + PdfArray nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.NAMES)); + if (nn != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfString s = (PdfString)PdfReader.GetPdfObjectRelease((PdfObject)arr[k++]); + items[PdfEncodings.ConvertToString(s.GetBytes(), null)] = arr[k]; + } + } + else if ((nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.KIDS))) != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfDictionary kid = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)arr[k]); + IterateItems(kid, items); + } + } + } + + public static Hashtable ReadTree(PdfDictionary dic) { + Hashtable items = new Hashtable(); + if (dic != null) + IterateItems(dic, items); + return items; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNull.cs b/iTechSharp/iTextSharp/text/pdf/PdfNull.cs new file mode 100644 index 0000000..8e066a9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNull.cs @@ -0,0 +1,85 @@ +using System; + +/* + * $Id: PdfNull.cs,v 1.4 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfNull is the Null object represented by the keyword null. + *

+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.9 (page 53). + * + * @see PdfObject + */ + + public class PdfNull : PdfObject { + + // static membervariables + + /** This is an instance of the PdfNull-object. */ + public static PdfNull PDFNULL = new PdfNull(); + + // constructors + + /** + * Constructs a PdfNull-object. + *

+ * You never need to do this yourself, you can always use the static object PDFNULL. + */ + + public PdfNull() : base(NULL, "null") {} + + public override String ToString() { + return "null"; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNumber.cs b/iTechSharp/iTextSharp/text/pdf/PdfNumber.cs new file mode 100644 index 0000000..421c437 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNumber.cs @@ -0,0 +1,163 @@ +using System; + +/* + * $Id: PdfNumber.cs,v 1.4 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfNumber provides two types of numbers, int and real. + *

+ * ints may be specified by signed or unsigned constants. Reals may only be + * in decimal format.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.3 (page 37). + * + * @see PdfObject + * @see BadPdfFormatException + */ + + public class PdfNumber : PdfObject { + + /** actual value of this PdfNumber, represented as a double */ + private double value; + + // constructors + + /** + * Constructs a PdfNumber-object. + * + * @param content value of the new PdfNumber-object + */ + + public PdfNumber(string content) : base(NUMBER) { + try { + value = Double.Parse(content.Trim(), System.Globalization.NumberFormatInfo.InvariantInfo); + this.Content = content; + } + catch (Exception nfe){ + throw new Exception(content + " is not a valid number - " + nfe.ToString()); + } + } + + /** + * Constructs a new int PdfNumber-object. + * + * @param value value of the new PdfNumber-object + */ + + public PdfNumber(int value) : base(NUMBER) { + this.value = value; + this.Content = value.ToString(); + } + + /** + * Constructs a new REAL PdfNumber-object. + * + * @param value value of the new PdfNumber-object + */ + + public PdfNumber(double value) : base(NUMBER) { + this.value = value; + Content = ByteBuffer.FormatDouble(value); + } + + /** + * Constructs a new REAL PdfNumber-object. + * + * @param value value of the new PdfNumber-object + */ + + public PdfNumber(float value) : this((double)value) {} + + // methods returning the value of this object + + /** + * Returns the primitive int value of this object. + * + * @return a value + */ + + public int IntValue { + get { + return (int) value; + } + } + + /** + * Returns the primitive double value of this object. + * + * @return a value + */ + + public double DoubleValue { + get { + return value; + } + } + + public float FloatValue { + get { + return (float)value; + } + } + + // other methods + + /** + * Increments the value of the PdfNumber-object with 1. + */ + + public void Increment() { + value += 1.0; + Content = ByteBuffer.FormatDouble(value); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs b/iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs new file mode 100644 index 0000000..d41c1af --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a number tree. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfNumberTree { + + private const int leafSize = 64; + + /** + * Creates a number tree. + * @param items the item of the number tree. The key is an Integer + * and the value is a PdfObject. + * @param writer the writer + * @throws IOException on error + * @return the dictionary with the number tree. + */ + public static PdfDictionary WriteTree(Hashtable items, PdfWriter writer) { + if (items.Count == 0) + return null; + int[] numbers = new int[items.Count]; + items.Keys.CopyTo(numbers, 0); + Array.Sort(numbers); + if (numbers.Length <= leafSize) { + PdfDictionary dic = new PdfDictionary(); + PdfArray ar = new PdfArray(); + for (int k = 0; k < numbers.Length; ++k) { + ar.Add(new PdfNumber(numbers[k])); + ar.Add((PdfObject)items[numbers[k]]); + } + dic.Put(PdfName.NUMS, ar); + return dic; + } + int skip = leafSize; + PdfIndirectReference[] kids = new PdfIndirectReference[(numbers.Length + leafSize - 1) / leafSize]; + for (int k = 0; k < kids.Length; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, numbers.Length); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfNumber(numbers[offset])); + arr.Add(new PdfNumber(numbers[end - 1])); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(new PdfNumber(numbers[offset])); + arr.Add((PdfObject)items[numbers[offset]]); + } + dic.Put(PdfName.NUMS, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + int top = kids.Length; + while (true) { + if (top <= leafSize) { + PdfArray arr = new PdfArray(); + for (int k = 0; k < top; ++k) + arr.Add(kids[k]); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.KIDS, arr); + return dic; + } + skip *= leafSize; + int tt = (numbers.Length + skip - 1 )/ skip; + for (int k = 0; k < tt; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, top); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfNumber(numbers[k * skip])); + arr.Add(new PdfNumber(numbers[Math.Min((k + 1) * skip, numbers.Length) - 1])); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(kids[offset]); + } + dic.Put(PdfName.KIDS, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + top = tt; + } + } + + private static void IterateItems(PdfDictionary dic, Hashtable items) { + PdfArray nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.NUMS)); + if (nn != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfNumber s = (PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)arr[k++]); + items[s.IntValue] = arr[k]; + } + } + else if ((nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.KIDS))) != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfDictionary kid = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)arr[k]); + IterateItems(kid, items); + } + } + } + + public static Hashtable ReadTree(PdfDictionary dic) { + Hashtable items = new Hashtable(); + if (dic != null) + IterateItems(dic, items); + return items; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs b/iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs new file mode 100644 index 0000000..0b5de68 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs @@ -0,0 +1,52 @@ +using System; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PdfOCProperties : PdfDictionary { + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfObject.cs new file mode 100644 index 0000000..f08296d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfObject.cs @@ -0,0 +1,369 @@ +/* + * $Id: PdfObject.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +using System; +using System.IO; + +namespace iTextSharp.text.pdf { + /** + * PdfObject is the abstract baseclass of all PDF objects. + *

+ * PDF supports seven basic types of objects: bools, numbers, strings, names, + * arrays, dictionaries and streams. In addition, PDF provides a null object. + * Objects may be labeled so that they can be referred to by other objects.
+ * All these basic PDF objects are described in the 'Portable Document Format + * Reference Manual version 1.3' Chapter 4 (pages 37-54). + * + * @see PdfNull + * @see Pdfbool + * @see PdfNumber + * @see PdfString + * @see PdfName + * @see PdfArray + * @see PdfDictionary + * @see PdfStream + * @see PdfIndirectReference + */ + + public abstract class PdfObject { + + // static membervariables (all the possible types of a PdfObject) + + /** a possible type of PdfObject */ + public const int BOOLEAN = 1; + + /** a possible type of PdfObject */ + public const int NUMBER = 2; + + /** a possible type of PdfObject */ + public const int STRING = 3; + + /** a possible type of PdfObject */ + public const int NAME = 4; + + /** a possible type of PdfObject */ + public const int ARRAY = 5; + + /** a possible type of PdfObject */ + public const int DICTIONARY = 6; + + /** a possible type of PdfObject */ + public const int STREAM = 7; + + /** a possible type of PdfObject */ + public const int NULL = 8; + + /** a possible type of PdfObject */ + public const int INDIRECT = 10; + + /** This is an empty string used for the PdfNull-object and for an empty PdfString-object. */ + public const string NOTHING = ""; + + /** This is the default encoding to be used for converting strings into bytes and vice versa. + * The default encoding is PdfDocEcoding. + */ + public const string TEXT_PDFDOCENCODING = "PDF"; + + /** This is the encoding to be used to output text in Unicode. */ + public const string TEXT_UNICODE = "UnicodeBig"; + + // membervariables + + /** the content of this PdfObject */ + protected byte[] bytes; + + /** the type of this PdfObject */ + protected int type; + + /** + * Holds value of property indRef. + */ + protected PRIndirectReference indRef; + + // constructors + + /** + * Constructs a PdfObject of a certain type without any content. + * + * @param type type of the new PdfObject + */ + + protected PdfObject(int type) { + this.type = type; + } + + /** + * Constructs a PdfObject of a certain type with a certain content. + * + * @param type type of the new PdfObject + * @param content content of the new PdfObject as a String. + */ + + protected PdfObject(int type, string content) { + this.type = type; + bytes = PdfEncodings.ConvertToBytes(content, null); + } + + /** + * Constructs a PdfObject of a certain type with a certain content. + * + * @param type type of the new PdfObject + * @param bytes content of the new PdfObject as an array of byte. + */ + + protected PdfObject(int type, byte[] bytes) { + this.bytes = bytes; + this.type = type; + } + + // methods dealing with the content of this object + + /** + * Writes the PDF representation of this PdfObject as an array of bytes to the writer. + * @param writer for backwards compatibility + * @param os the outputstream to write the bytes to. + * @throws IOException + */ + + public virtual void ToPdf(PdfWriter writer, Stream os) { + if (bytes != null) + os.Write(bytes, 0, bytes.Length); + } + + /** + * Gets the presentation of this object in a byte array + * @return a byte array + */ + public virtual byte[] GetBytes() { + return bytes; + } + + /** + * Can this object be in an object stream? + * @return true if this object can be in an object stream. + */ + public bool CanBeInObjStm() { + return (type >= 1 && type <= 6) || type == 8; + } + + /** + * Returns the length of the PDF representation of the PdfObject. + *

+ * In some cases, namely for PdfString and PdfStream, + * this method differs from the method length because length + * returns the length of the actual content of the PdfObject.

+ *

+ * Remark: the actual content of an object is in most cases identical to its representation. + * The following statement is always true: Length() >= PdfLength().

+ * + * @return a length + */ + + // public int PdfLength() { + // return ToPdf(null).length; + // } + + /** + * Returns the String-representation of this PdfObject. + * + * @return a String + */ + + public override string ToString() { + if (bytes == null) + return ""; + else + return PdfEncodings.ConvertToString(bytes, null); + } + + /** + * Returns the length of the actual content of the PdfObject. + *

+ * In some cases, namely for PdfString and PdfStream, + * this method differs from the method pdfLength because pdfLength + * returns the length of the PDF representation of the object, not of the actual content + * as does the method length.

+ *

+ * Remark: the actual content of an object is in some cases identical to its representation. + * The following statement is always true: Length() >= PdfLength().

+ * + * @return a length + */ + + public int Length { + get { + return ToString().Length; + } + } + + /** + * Changes the content of this PdfObject. + * + * @param content the new content of this PdfObject + */ + + protected string Content { + set { + bytes = PdfEncodings.ConvertToBytes(value, null); + } + } + + // methods dealing with the type of this object + + /** + * Returns the type of this PdfObject. + * + * @return a type + */ + + public int Type { + get { + return type; + } + } + + /** + * Checks if this PdfObject is of the type PdfNull. + * + * @return true or false + */ + + public bool IsNull() { + return (this.type == NULL); + } + + /** + * Checks if this PdfObject is of the type PdfBoolean. + * + * @return true or false + */ + + public bool IsBoolean() { + return (this.type == BOOLEAN); + } + + /** + * Checks if this PdfObject is of the type PdfNumber. + * + * @return true or false + */ + + public bool IsNumber() { + return (this.type == NUMBER); + } + + /** + * Checks if this PdfObject is of the type PdfString. + * + * @return true or false + */ + + public bool IsString() { + return (this.type == STRING); + } + + /** + * Checks if this PdfObject is of the type PdfName. + * + * @return true or false + */ + + public bool IsName() { + return (this.type == NAME); + } + + /** + * Checks if this PdfObject is of the type PdfArray. + * + * @return true or false + */ + + public bool IsArray() { + return (this.type == ARRAY); + } + + /** + * Checks if this PdfObject is of the type PdfDictionary. + * + * @return true or false + */ + + public bool IsDictionary() { + return (this.type == DICTIONARY); + } + + /** + * Checks if this PdfObject is of the type PdfStream. + * + * @return true or false + */ + + public bool IsStream() { + return (this.type == STREAM); + } + + /** + * Checks if this is an indirect object. + * @return true if this is an indirect object + */ + public bool IsIndirect() { + return (this.type == INDIRECT); + } + + public PRIndirectReference IndRef { + get { + return indRef; + } + set { + indRef = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfOutline.cs b/iTechSharp/iTextSharp/text/pdf/PdfOutline.cs new file mode 100644 index 0000000..2061f4a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfOutline.cs @@ -0,0 +1,485 @@ +using System; +using System.Text; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfOutline.cs,v 1.5 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfOutline is an object that represents a PDF outline entry. + *

+ * An outline allows a user to access views of a document by name.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.7 (page 104-106) + * + * @see PdfDictionary + */ + + public class PdfOutline : PdfDictionary { + + // membervariables + + /** the PdfIndirectReference of this object */ + private PdfIndirectReference reference; + + /** value of the Count-key */ + private int count = 0; + + /** value of the Parent-key */ + private PdfOutline parent; + + /** value of the Destination-key */ + private PdfDestination destination; + + /** The PdfAction for this outline. + */ + private PdfAction action; + + protected ArrayList kids = new ArrayList(); + + protected PdfWriter writer; + + /** Holds value of property tag. */ + private string tag; + + /** Holds value of property open. */ + private bool open; + + /** Holds value of property color. */ + private Color color; + + /** Holds value of property style. */ + private int style = 0; + + // constructors + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for the outlines object. + */ + + internal PdfOutline(PdfWriter writer) : base(OUTLINES) { + open = true; + parent = null; + this.writer = writer; + } + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfAction action, string title) : this(parent, action, title, true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfAction action, string title, bool open) : base() { + this.action = action; + InitOutline(parent, title, open); + } + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfDestination destination, string title) : this(parent, destination, title, true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfDestination destination, string title, bool open) : base() { + this.destination = destination; + InitOutline(parent, title, open); + } + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + */ + public PdfOutline(PdfOutline parent, PdfAction action, PdfString title) : this(parent, action, title, true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfAction action, PdfString title, bool open) : this(parent, action, title.ToString(), open) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfDestination destination, PdfString title) : this(parent, destination, title, true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfDestination destination, PdfString title, bool open) : this(parent, destination, title.ToString(), true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfAction action, Paragraph title) : this(parent, action, title, true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfAction action, Paragraph title, bool open) : base() { + StringBuilder buf = new StringBuilder(); + foreach (Chunk chunk in title.Chunks) { + buf.Append(chunk.Content); + } + this.action = action; + InitOutline(parent, buf.ToString(), open); + } + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfDestination destination, Paragraph title) : this(parent, destination, title, true) {} + + /** + * Constructs a PdfOutline. + *

+ * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfDestination destination, Paragraph title, bool open) : base() { + StringBuilder buf = new StringBuilder(); + foreach (Chunk chunk in title.Chunks) { + buf.Append(chunk.Content); + } + this.destination = destination; + InitOutline(parent, buf.ToString(), open); + } + + + // methods + + /** Helper for the constructors. + * @param parent the parent outline + * @param title the title for this outline + * @param open true if the children are visible + */ + internal void InitOutline(PdfOutline parent, string title, bool open) { + this.open = open; + this.parent = parent; + writer = parent.writer; + Put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE)); + parent.AddKid(this); + if (destination != null && !destination.HasPage()) // bugfix Finn Bock + SetDestinationPage(writer.CurrentPage); + } + + /** + * Gets the indirect reference of this PdfOutline. + * + * @return the PdfIndirectReference to this outline. + */ + + public PdfIndirectReference IndirectReference { + get { + return reference; + } + + set { + this.reference = value; + } + } + + /** + * Gets the parent of this PdfOutline. + * + * @return the PdfOutline that is the parent of this outline. + */ + + public PdfOutline Parent { + get { + return parent; + } + } + + /** + * Set the page of the PdfDestination-object. + * + * @param pageReference indirect reference to the page + * @return true if this page was set as the PdfDestination-page. + */ + + public bool SetDestinationPage(PdfIndirectReference pageReference) { + if (destination == null) { + return false; + } + return destination.AddPage(pageReference); + } + + /** + * Gets the destination for this outline. + * @return the destination + */ + public PdfDestination PdfDestination { + get { + return destination; + } + } + + internal int Count { + get { + return count; + } + + set { + this.count = value; + } + } + + /** + * returns the level of this outline. + * + * @return a level + */ + + public int Level { + get { + if (parent == null) { + return 0; + } + return (parent.Level + 1); + } + } + + /** + * Returns the PDF representation of this PdfOutline. + * + * @param writer the encryption information + * @param os + * @throws IOException + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + if (color != null && !color.Equals(Color.BLACK)) { + Put(PdfName.C, new PdfArray(new float[]{color.R/255f,color.G/255f,color.B/255f})); + } + int flag = 0; + if ((style & Font.BOLD) != 0) + flag |= 2; + if ((style & Font.ITALIC) != 0) + flag |= 1; + if (flag != 0) + Put(PdfName.F, new PdfNumber(flag)); + if (parent != null) { + Put(PdfName.PARENT, parent.IndirectReference); + } + if (destination != null && destination.HasPage()) { + Put(PdfName.DEST, destination); + } + if (action != null) + Put(PdfName.A, action); + if (count != 0) { + Put(PdfName.COUNT, new PdfNumber(count)); + } + base.ToPdf(writer, os); + } + + public void AddKid(PdfOutline outline) { + kids.Add(outline); + } + + public ArrayList Kids { + get { + return kids; + } + + set { + this.kids = value; + } + } + + /** Getter for property tag. + * @return Value of property tag. + */ + public string Tag { + get { + return tag; + } + + set { + this.tag = value; + } + } + + public string Title { + get { + PdfString title = (PdfString)Get(PdfName.TITLE); + return title.ToString(); + } + + set { + Put(PdfName.TITLE, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** Setter for property open. + * @param open New value of property open. + */ + public bool Open { + set { + this.open = value; + } + get { + return open; + } + } + + public Color Color { + get { + return color; + } + set { + color = value; + } + } + + public int Style { + get { + return style; + } + set { + style = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPCell.cs b/iTechSharp/iTextSharp/text/pdf/PdfPCell.cs new file mode 100644 index 0000000..7bd36ae --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPCell.cs @@ -0,0 +1,696 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf.events; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** A cell in a PdfPTable. + */ + + public class PdfPCell : Rectangle{ + + private ColumnText column = new ColumnText(null); + + /** Holds value of property verticalAlignment. */ + private int verticalAlignment = Element.ALIGN_TOP; + + /** Holds value of property paddingLeft. */ + private float paddingLeft = 2; + + /** Holds value of property paddingLeft. */ + private float paddingRight = 2; + + /** Holds value of property paddingTop. */ + private float paddingTop = 2; + + /** Holds value of property paddingBottom. */ + private float paddingBottom = 2; + + /** Holds value of property fixedHeight. */ + private float fixedHeight = 0; + + /** Holds value of property noWrap. */ + private bool noWrap = false; + + /** Holds value of property table. */ + private PdfPTable table; + + /** Holds value of property minimumHeight. */ + private float minimumHeight; + + /** Holds value of property colspan. */ + private int colspan = 1; + + /** Holds value of property image. */ + private Image image; + + /** Holds value of property cellEvent. */ + private IPdfPCellEvent cellEvent; + + /** Holds value of property useDescender. */ + private bool useDescender; + + /** Increases padding to include border if true */ + private bool useBorderPadding = false; + + + /** The text in the cell. */ + protected Phrase phrase; + + /** Constructs an empty PdfPCell. + * The default padding is 2. + */ + public PdfPCell() : base(0, 0, 0, 0) { + borderWidth = 0.5f; + border = BOX; + column.SetLeading(0, 1); + } + + /** Constructs a PdfPCell with a Phrase. + * The default padding is 2. + * @param phrase the text + */ + public PdfPCell(Phrase phrase) : base(0, 0, 0, 0) { + borderWidth = 0.5f; + border = BOX; + column.AddText(this.phrase = phrase); + column.SetLeading(0, 1); + } + + /** Constructs a PdfPCell with an Image. + * The default padding is 0. + * @param image the Image + */ + public PdfPCell(Image image) : this(image, false) { + } + + /** Constructs a PdfPCell with an Image. + * The default padding is 0.25 for a border width of 0.5. + * @param image the Image + * @param fit true to fit the image to the cell + */ + public PdfPCell(Image image, bool fit) : base(0, 0, 0, 0) { + if (fit) { + borderWidth = 0.5f; + border = BOX; + this.image = image; + column.SetLeading(0, 1); + Padding = borderWidth / 2; + } + else { + borderWidth = 0.5f; + border = BOX; + column.AddText(this.phrase = new Phrase(new Chunk(image, 0, 0))); + column.SetLeading(0, 1); + Padding = 0; + } + } + + /** Constructs a PdfPCell with a PdfPtable. + * This constructor allows nested tables. + * The default padding is 0. + * @param table The PdfPTable + */ + public PdfPCell(PdfPTable table) : this(table, null) { + } + + /** Constructs a PdfPCell with a PdfPtable. + * This constructor allows nested tables. + * + * @param table The PdfPTable + * @param style The style to apply to the cell (you could use getDefaultCell()) + * @since 2.1.0 + */ + public PdfPCell(PdfPTable table, PdfPCell style) : base(0, 0, 0, 0) { + borderWidth = 0.5f; + border = BOX; + column.SetLeading(0, 1); + this.table = table; + table.WidthPercentage = 100; + table.ExtendLastRow = true; + column.AddElement(table); + if (style != null) { + CloneNonPositionParameters(style); + verticalAlignment = style.verticalAlignment; + paddingLeft = style.paddingLeft; + paddingRight = style.paddingRight; + paddingTop = style.paddingTop; + paddingBottom = style.paddingBottom; + colspan = style.colspan; + cellEvent = style.cellEvent; + useDescender = style.useDescender; + useBorderPadding = style.useBorderPadding; + rotation = style.rotation; + } + else { + Padding = 0; + } + } + + /** Constructs a deep copy of a PdfPCell. + * @param cell the PdfPCell to duplicate + */ + public PdfPCell(PdfPCell cell) : base(cell.llx, cell.lly, cell.urx, cell.ury) { + CloneNonPositionParameters(cell); + verticalAlignment = cell.verticalAlignment; + paddingLeft = cell.paddingLeft; + paddingRight = cell.paddingRight; + paddingTop = cell.paddingTop; + paddingBottom = cell.paddingBottom; + phrase = cell.phrase; + fixedHeight = cell.fixedHeight; + minimumHeight = cell.minimumHeight; + noWrap = cell.noWrap; + colspan = cell.colspan; + if (cell.table != null) + table = new PdfPTable(cell.table); + image = Image.GetInstance(cell.image); + cellEvent = cell.cellEvent; + useDescender = cell.useDescender; + column = ColumnText.Duplicate(cell.column); + useBorderPadding = cell.useBorderPadding; + rotation = cell.rotation; + } + + /** + * Adds an iText element to the cell. + * @param element + */ + public void AddElement(IElement element) { + if (table != null) { + table = null; + column.SetText(null); + } + column.AddElement(element); + } + + /** Gets the Phrase from this cell. + * @return the Phrase + */ + public Phrase Phrase { + get { + return phrase; + } + set { + table = null; + image = null; + column.SetText(this.phrase = value); + } + } + + /** Gets the horizontal alignment for the cell. + * @return the horizontal alignment for the cell + */ + public int HorizontalAlignment { + get { + return column.Alignment; + } + set { + column.Alignment = value; + } + } + + /** Gets the vertical alignment for the cell. + * @return the vertical alignment for the cell + */ + public int VerticalAlignment { + get { + return verticalAlignment; + } + set { + verticalAlignment = value; + if (table != null) + table.ExtendLastRow = (verticalAlignment == Element.ALIGN_TOP); + } + } + + /** Gets the effective left padding. This will include + * the left border width if {@link #UseBorderPadding} is true. + * @return effective value of property paddingLeft. + */ + public float EffectivePaddingLeft { + get { + return paddingLeft + (UseBorderPadding ? (BorderWidthLeft/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * @return Value of property paddingLeft. + */ + public float PaddingLeft { + get { + return paddingLeft; + } + set { + paddingLeft = value; + } + } + + /** Gets the effective right padding. This will include + * the right border width if {@link #UseBorderPadding} is true. + * @return effective value of property paddingRight. + */ + public float EffectivePaddingRight { + get { + return paddingRight + (UseBorderPadding ? (BorderWidthRight/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * Getter for property paddingRight. + * @return Value of property paddingRight. + */ + public float PaddingRight { + get { + return paddingRight; + } + set { + paddingRight = value; + } + } + + /** Gets the effective top padding. This will include + * the top border width if {@link #isUseBorderPadding()} is true. + * @return effective value of property paddingTop. + */ + public float EffectivePaddingTop { + get { + return paddingTop + (UseBorderPadding ? (BorderWidthTop/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * Getter for property paddingTop. + * @return Value of property paddingTop. + */ + public float PaddingTop { + get { + return paddingTop; + } + set { + paddingTop = value; + } + } + + /** + /** Gets the effective bottom padding. This will include + * the bottom border width if {@link #UseBorderPadding} is true. + * @return effective value of property paddingBottom. + */ + public float EffectivePaddingBottom { + get { + return paddingBottom + (UseBorderPadding ? (BorderWidthBottom/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * Getter for property paddingBottom. + * @return Value of property paddingBottom. + */ + public float PaddingBottom { + get { + return paddingBottom; + } + set { + paddingBottom = value; + } + } + + /** + * Sets the padding of the contents in the cell (space between content and border). + * @param padding + */ + public float Padding { + set { + paddingBottom = value; + paddingTop = value; + paddingLeft = value; + paddingRight = value; + } + } + + /** + * Adjusts effective padding to include border widths. + * @param use adjust effective padding if true + */ + public bool UseBorderPadding { + set { + useBorderPadding = value; + } + get { + return useBorderPadding; + } + } + + /** + * Sets the leading fixed and variable. The resultant leading will be + * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param fixedLeading the fixed leading + * @param multipliedLeading the variable leading + */ + public void SetLeading(float fixedLeading, float multipliedLeading) { + column.SetLeading(fixedLeading, multipliedLeading); + } + + /** + * Gets the fixed leading + * @return the leading + */ + public float Leading { + get { + return column.Leading; + } + } + + /** + * Gets the variable leading + * @return the leading + */ + public float MultipliedLeading { + get { + return column.MultipliedLeading; + } + } + + /** + * Gets the first paragraph line indent. + * @return the indent + */ + public float Indent { + get { + return column.Indent; + } + set { + column.Indent = value; + } + } + + /** + * Gets the extra space between paragraphs. + * @return the extra space between paragraphs + */ + public float ExtraParagraphSpace { + get { + return column.ExtraParagraphSpace; + } + set { + column.ExtraParagraphSpace = value; + } + } + + /** + * Getter for property fixedHeight. + * @return Value of property fixedHeight. + */ + public float FixedHeight { + get { + return fixedHeight; + } + set { + fixedHeight = value; + minimumHeight = 0; + } + } + + /** + * Setter for property noWrap. + * @param noWrap New value of property noWrap. + */ + public bool NoWrap { + set { + noWrap = value; + } + get { + return noWrap; + } + } + + /** + * Getter for property table. + * @return Value of property table. + */ + internal PdfPTable Table { + get { + return table; + } + set { + table = value; + column.SetText(null); + image = null; + if (table != null) { + table.ExtendLastRow = (verticalAlignment == Element.ALIGN_TOP); + column.AddElement(table); + table.WidthPercentage = 100; + } + } + } + + /** Getter for property minimumHeight. + * @return Value of property minimumHeight. + */ + public float MinimumHeight { + get { + return minimumHeight; + } + set { + this.minimumHeight = value; + fixedHeight = 0; + } + } + + /** Getter for property colspan. + * @return Value of property colspan. + */ + public int Colspan { + get { + return colspan; + } + set { + colspan = value; + } + } + + /** + * Gets the following paragraph lines indent. + * @return the indent + */ + public float FollowingIndent { + get { + return column.FollowingIndent; + } + set { + column.FollowingIndent = value; + } + } + + /** + * Gets the right paragraph lines indent. + * @return the indent + */ + public float RightIndent { + get { + return column.RightIndent; + } + set { + column.RightIndent = value; + } + } + + /** Gets the space/character extra spacing ratio for + * fully justified text. + * @return the space/character extra spacing ratio + */ + public float SpaceCharRatio { + get { + return column.SpaceCharRatio; + } + set { + column.SpaceCharRatio = value; + } + } + + /** + * Gets the run direction of the text content in the cell + * @return One of the following values: PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI, PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL. + */ + public int RunDirection { + get { + return column.RunDirection; + } + set { + column.RunDirection = value; + } + } + + /** Getter for property image. + * @return Value of property image. + * + */ + public Image Image { + get { + return this.image; + } + set { + column.SetText(null); + table = null; + this.image = value; + } + } + + /** Gets the cell event for this cell. + * @return the cell event + * + */ + public IPdfPCellEvent CellEvent { + get { + return this.cellEvent; + } + set { + if (value == null) this.cellEvent = null; + else if (this.cellEvent == null) this.cellEvent = value; + else if (this.cellEvent is PdfPCellEventForwarder) ((PdfPCellEventForwarder)this.cellEvent).AddCellEvent(value); + else { + PdfPCellEventForwarder forward = new PdfPCellEventForwarder(); + forward.AddCellEvent(this.cellEvent); + forward.AddCellEvent(value); + this.cellEvent = forward; + } + } + } + + /** Gets the arabic shaping options. + * @return the arabic shaping options + */ + public int ArabicOptions { + get { + return column.ArabicOptions; + } + set { + column.ArabicOptions = value; + } + } + + /** Gets state of first line height based on max ascender + * @return true if an ascender is to be used. + */ + public bool UseAscender { + get { + return column.UseAscender; + } + set { + column.UseAscender = value; + } + } + + /** Getter for property useDescender. + * @return Value of property useDescender. + * + */ + public bool UseDescender { + get { + return this.useDescender; + } + set { + useDescender = value; + } + } + + /** + * Gets the ColumnText with the content of the cell. + * @return a columntext object + */ + public ColumnText Column { + get { + return column; + } + set { + column = value; + } + } + + /** + * Returns the list of composite elements of the column. + * @return a List object. + * @since 2.1.1 + */ + public ArrayList CompositeElements { + get { + return column.compositeElements; + } + } + + /** + * The rotation of the cell. Possible values are + * 0, 90, 180 and 270. + */ + private new int rotation; + + /** + * Sets the rotation of the cell. Possible values are + * 0, 90, 180 and 270. + * @param rotation the rotation of the cell + */ + public new int Rotation { + set { + int rot = value % 360; + if (rot < 0) + rot += 360; + if ((rot % 90) != 0) + throw new ArgumentException("Rotation must be a multiple of 90."); + rotation = rot; + } + get { + return rotation; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs b/iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs new file mode 100644 index 0000000..7949d85 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs @@ -0,0 +1,1170 @@ +using System; +using System.Collections; +using System.Text; +using System.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; + +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** + * This class does all the processing related to signing and verifying a PKCS#7 + * signature. + *

+ * It's based in code found at org.bouncycastle. + */ + public class PdfPKCS7 { + + private byte[] sigAttr; + private byte[] digestAttr; + private int version, signerversion; + private Hashtable digestalgos; + private ArrayList certs, crls; + private X509Certificate signCert; + private byte[] digest; + private IDigest messageDigest; + private String digestAlgorithm, digestEncryptionAlgorithm; + private ISigner sig; + private ICipherParameters privKey; + private byte[] RSAdata; + private bool verified; + private bool verifyResult; + private byte[] externalDigest; + private byte[] externalRSAdata; + + private const String ID_PKCS7_DATA = "1.2.840.113549.1.7.1"; + private const String ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2"; + private const String ID_MD5 = "1.2.840.113549.2.5"; + private const String ID_MD2 = "1.2.840.113549.2.2"; + private const String ID_SHA1 = "1.3.14.3.2.26"; + private const String ID_RSA = "1.2.840.113549.1.1.1"; + private const String ID_DSA = "1.2.840.10040.4.1"; + private const String ID_CONTENT_TYPE = "1.2.840.113549.1.9.3"; + private const String ID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4"; + private const String ID_SIGNING_TIME = "1.2.840.113549.1.9.5"; + private const String ID_MD2RSA = "1.2.840.113549.1.1.2"; + private const String ID_MD5RSA = "1.2.840.113549.1.1.4"; + private const String ID_SHA1RSA = "1.2.840.113549.1.1.5"; + /** + * Holds value of property reason. + */ + private String reason; + + /** + * Holds value of property location. + */ + private String location; + + /** + * Holds value of property signDate. + */ + private DateTime signDate; + + /** + * Holds value of property signName. + */ + private String signName; + + /** + * Verifies a signature using the sub-filter adbe.x509.rsa_sha1. + * @param contentsKey the /Contents key + * @param certsKey the /Cert key + * @param provider the provider or null for the default provider + * @throws SecurityException on error + * @throws CRLException on error + * @throws InvalidKeyException on error + * @throws CertificateException on error + * @throws NoSuchProviderException on error + * @throws NoSuchAlgorithmException on error + * @throws IOException on error + */ + public PdfPKCS7(byte[] contentsKey, byte[] certsKey) { + + X509CertificateParser cf = new X509CertificateParser(); + certs = new ArrayList(); + foreach (X509Certificate cc in cf.ReadCertificates(certsKey)) { + certs.Add(cc); + } + signCert = (X509Certificate)certs[0]; + crls = new ArrayList(); + Asn1InputStream inp = new Asn1InputStream(new MemoryStream(contentsKey)); + digest = ((DerOctetString)inp.ReadObject()).GetOctets(); + sig = SignerUtilities.GetSigner("SHA1withRSA"); + sig.Init(false, signCert.GetPublicKey()); + } + + /** + * Verifies a signature using the sub-filter adbe.pkcs7.detached or + * adbe.pkcs7.sha1. + * @param contentsKey the /Contents key + * @param provider the provider or null for the default provider + * @throws SecurityException on error + * @throws CRLException on error + * @throws InvalidKeyException on error + * @throws CertificateException on error + * @throws NoSuchProviderException on error + * @throws NoSuchAlgorithmException on error + */ + public PdfPKCS7(byte[] contentsKey) { + Asn1InputStream din = new Asn1InputStream(new MemoryStream(contentsKey)); + + // + // Basic checks to make sure it's a PKCS#7 SignedData Object + // + Asn1Object pkcs; + + try { + pkcs = din.ReadObject(); + } + catch { + throw new ArgumentException("can't decode PKCS7SignedData object"); + } + if (!(pkcs is Asn1Sequence)) { + throw new ArgumentException("Not a valid PKCS#7 object - not a sequence"); + } + Asn1Sequence signedData = (Asn1Sequence)pkcs; + DerObjectIdentifier objId = (DerObjectIdentifier)signedData[0]; + if (!objId.Id.Equals(ID_PKCS7_SIGNED_DATA)) + throw new ArgumentException("Not a valid PKCS#7 object - not signed data"); + Asn1Sequence content = (Asn1Sequence)((DerTaggedObject)signedData[1]).GetObject(); + // the positions that we care are: + // 0 - version + // 1 - digestAlgorithms + // 2 - possible ID_PKCS7_DATA + // (the certificates and crls are taken out by other means) + // last - signerInfos + + // the version + version = ((DerInteger)content[0]).Value.IntValue; + + // the digestAlgorithms + digestalgos = new Hashtable(); + IEnumerator e = ((Asn1Set)content[1]).GetEnumerator(); + while (e.MoveNext()) + { + Asn1Sequence s = (Asn1Sequence)e.Current; + DerObjectIdentifier o = (DerObjectIdentifier)s[0]; + digestalgos[o.Id] = null; + } + + // the certificates and crls + X509CertificateParser cf = new X509CertificateParser(); + certs = new ArrayList(); + foreach (X509Certificate cc in cf.ReadCertificates(contentsKey)) { + certs.Add(cc); + } + crls = new ArrayList(); + + // the possible ID_PKCS7_DATA + Asn1Sequence rsaData = (Asn1Sequence)content[2]; + if (rsaData.Count > 1) { + DerOctetString rsaDataContent = (DerOctetString)((DerTaggedObject)rsaData[1]).GetObject(); + RSAdata = rsaDataContent.GetOctets(); + } + + // the signerInfos + int next = 3; + while (content[next] is DerTaggedObject) + ++next; + Asn1Set signerInfos = (Asn1Set)content[next]; + if (signerInfos.Count != 1) + throw new ArgumentException("This PKCS#7 object has multiple SignerInfos - only one is supported at this time"); + Asn1Sequence signerInfo = (Asn1Sequence)signerInfos[0]; + // the positions that we care are + // 0 - version + // 1 - the signing certificate serial number + // 2 - the digest algorithm + // 3 or 4 - digestEncryptionAlgorithm + // 4 or 5 - encryptedDigest + signerversion = ((DerInteger)signerInfo[0]).Value.IntValue; + // Get the signing certificate + Asn1Sequence issuerAndSerialNumber = (Asn1Sequence)signerInfo[1]; + BigInteger serialNumber = ((DerInteger)issuerAndSerialNumber[1]).Value; + foreach (X509Certificate cert in certs) { + if (serialNumber.Equals(cert.SerialNumber)) { + signCert = cert; + break; + } + } + if (signCert == null) { + throw new ArgumentException("Can't find signing certificate with serial " + serialNumber.ToString(16)); + } + digestAlgorithm = ((DerObjectIdentifier)((Asn1Sequence)signerInfo[2])[0]).Id; + next = 3; + if (signerInfo[next] is Asn1TaggedObject) { + Asn1TaggedObject tagsig = (Asn1TaggedObject)signerInfo[next]; + Asn1Sequence sseq = (Asn1Sequence)tagsig.GetObject(); + MemoryStream bOut = new MemoryStream(); + Asn1OutputStream dout = new Asn1OutputStream(bOut); + try { + Asn1EncodableVector attribute = new Asn1EncodableVector(); + for (int k = 0; k < sseq.Count; ++k) { + attribute.Add(sseq[k]); + } + dout.WriteObject(new DerSet(attribute)); + dout.Close(); + } + catch (IOException){} + sigAttr = bOut.ToArray(); + + for (int k = 0; k < sseq.Count; ++k) { + Asn1Sequence seq2 = (Asn1Sequence)sseq[k]; + if (((DerObjectIdentifier)seq2[0]).Id.Equals(ID_MESSAGE_DIGEST)) { + Asn1Set sset = (Asn1Set)seq2[1]; + digestAttr = ((DerOctetString)sset[0]).GetOctets(); + break; + } + } + if (digestAttr == null) + throw new ArgumentException("Authenticated attribute is missing the digest."); + ++next; + } + digestEncryptionAlgorithm = ((DerObjectIdentifier)((Asn1Sequence)signerInfo[next++])[0]).Id; + digest = ((DerOctetString)signerInfo[next]).GetOctets(); + if (RSAdata != null || digestAttr != null) { + messageDigest = GetHashClass(); + } + sig = SignerUtilities.GetSigner(GetDigestAlgorithm()); + sig.Init(false, signCert.GetPublicKey()); + } + + /** + * Generates a signature. + * @param privKey the private key + * @param certChain the certificate chain + * @param crlList the certificate revocation list + * @param hashAlgorithm the hash algorithm + * @param provider the provider or null for the default provider + * @param hasRSAdata true if the sub-filter is adbe.pkcs7.sha1 + * @throws SecurityException on error + * @throws InvalidKeyException on error + * @throws NoSuchProviderException on error + * @throws NoSuchAlgorithmException on error + */ + public PdfPKCS7(ICipherParameters privKey, X509Certificate[] certChain, object[] crlList, + String hashAlgorithm, bool hasRSAdata) { + this.privKey = privKey; + + if (hashAlgorithm.Equals("MD5")) { + digestAlgorithm = ID_MD5; + } + else if (hashAlgorithm.Equals("MD2")) { + digestAlgorithm = ID_MD2; + } + else if (hashAlgorithm.Equals("SHA")) { + digestAlgorithm = ID_SHA1; + } + else if (hashAlgorithm.Equals("SHA1")) { + digestAlgorithm = ID_SHA1; + } + else { + throw new ArgumentException("Unknown Hash Algorithm "+hashAlgorithm); + } + + version = signerversion = 1; + certs = new ArrayList(); + crls = new ArrayList(); + digestalgos = new Hashtable(); + digestalgos[digestAlgorithm] = null; + + // + // Copy in the certificates and crls used to sign the private key. + // + signCert = certChain[0]; + for (int i = 0;i < certChain.Length;i++) { + certs.Add(certChain[i]); + } + +// if (crlList != null) { +// for (int i = 0;i < crlList.length;i++) { +// crls.Add(crlList[i]); +// } +// } + + if (privKey != null) { + // + // Now we have private key, find out what the digestEncryptionAlgorithm is. + // + if (privKey is RsaKeyParameters) + digestEncryptionAlgorithm = ID_RSA; + else if (privKey is DsaKeyParameters) + digestEncryptionAlgorithm = ID_DSA; + else + throw new ArgumentException("Unknown Key Algorithm "+privKey.ToString()); + + } + if (hasRSAdata) { + RSAdata = new byte[0]; + messageDigest = GetHashClass(); + } + + if (privKey != null) { + sig = SignerUtilities.GetSigner(GetDigestAlgorithm()); + sig.Init(true, privKey); + } + } + + /** + * Update the digest with the specified bytes. This method is used both for signing and verifying + * @param buf the data buffer + * @param off the offset in the data buffer + * @param len the data length + * @throws SignatureException on error + */ + public void Update(byte[] buf, int off, int len) { + if (RSAdata != null || digestAttr != null) + messageDigest.BlockUpdate(buf, off, len); + else + sig.BlockUpdate(buf, off, len); + } + + /** + * Verify the digest. + * @throws SignatureException on error + * @return true if the signature checks out, false otherwise + */ + public bool Verify() { + if (verified) + return verifyResult; + if (sigAttr != null) { + byte[] msd = new byte[messageDigest.GetDigestSize()]; + sig.BlockUpdate(sigAttr, 0, sigAttr.Length); + if (RSAdata != null) { + messageDigest.DoFinal(msd, 0); + messageDigest.BlockUpdate(msd, 0, msd.Length); + } + messageDigest.DoFinal(msd, 0); + verifyResult = (Arrays.AreEqual(msd, digestAttr) && sig.VerifySignature(digest)); + } + else { + if (RSAdata != null){ + byte[] msd = new byte[messageDigest.GetDigestSize()]; + messageDigest.DoFinal(msd, 0); + sig.BlockUpdate(msd, 0, msd.Length); + } + verifyResult = sig.VerifySignature(digest); + } + verified = true; + return verifyResult; + } + + /** + * Get the X.509 certificates associated with this PKCS#7 object + * @return the X.509 certificates associated with this PKCS#7 object + */ + public X509Certificate[] Certificates { + get { + X509Certificate[] c = new X509Certificate[certs.Count]; + certs.CopyTo(c); + return c; + } + } + + /** + * Get the X.509 certificate revocation lists associated with this PKCS#7 object + * @return the X.509 certificate revocation lists associated with this PKCS#7 object + */ + public ArrayList CRLs { + get { + return crls; + } + } + + /** + * Get the X.509 certificate actually used to sign the digest. + * @return the X.509 certificate actually used to sign the digest + */ + public X509Certificate SigningCertificate { + get { + return signCert; + } + } + + /** + * Get the version of the PKCS#7 object. Always 1 + * @return the version of the PKCS#7 object. Always 1 + */ + public int Version { + get { + return version; + } + } + + /** + * Get the version of the PKCS#7 "SignerInfo" object. Always 1 + * @return the version of the PKCS#7 "SignerInfo" object. Always 1 + */ + public int SigningInfoVersion { + get { + return signerversion; + } + } + + /** + * Get the algorithm used to calculate the message digest + * @return the algorithm used to calculate the message digest + */ + public String GetDigestAlgorithm() { + String dea = digestEncryptionAlgorithm; + + if (digestEncryptionAlgorithm.Equals(ID_RSA) || digestEncryptionAlgorithm.Equals(ID_MD5RSA) + || digestEncryptionAlgorithm.Equals(ID_MD2RSA) || digestEncryptionAlgorithm.Equals(ID_SHA1RSA)) { + dea = "RSA"; + } + else if (digestEncryptionAlgorithm.Equals(ID_DSA)) { + dea = "DSA"; + } + + return GetHashAlgorithm() + "with" + dea; + } + + /** + * Returns the algorithm. + * @return the digest algorithm + */ + public String GetHashAlgorithm() { + String da = digestAlgorithm; + + if (digestAlgorithm.Equals(ID_MD5) || digestAlgorithm.Equals(ID_MD5RSA)) { + da = "MD5"; + } + else if (digestAlgorithm.Equals(ID_MD2) || digestAlgorithm.Equals(ID_MD2RSA)) { + da = "MD2"; + } + else if (digestAlgorithm.Equals(ID_SHA1) || digestAlgorithm.Equals(ID_SHA1RSA)) { + da = "SHA1"; + } + return da; + } + + public IDigest GetHashClass() { + if (digestAlgorithm.Equals(ID_MD5) || digestAlgorithm.Equals(ID_MD5RSA)) { + return new MD5Digest(); + } + else if (digestAlgorithm.Equals(ID_MD2) || digestAlgorithm.Equals(ID_MD2RSA)) { + return new MD2Digest(); + } + else if (digestAlgorithm.Equals(ID_SHA1) || digestAlgorithm.Equals(ID_SHA1RSA)) { + return new Sha1Digest(); + } + return null; + } + + /** + * Loads the default root certificates at <java.home>/lib/security/cacerts + * with the default provider. + * @return a KeyStore + */ +// public static KeyStore LoadCacertsKeyStore() { +// return LoadCacertsKeyStore(null); +// } + + /** + * Loads the default root certificates at <java.home>/lib/security/cacerts. + * @param provider the provider or null for the default provider + * @return a KeyStore + */ +// public static KeyStore LoadCacertsKeyStore(String provider) { +// File file = new File(System.GetProperty("java.home"), "lib"); +// file = new File(file, "security"); +// file = new File(file, "cacerts"); +// FileInputStream fin = null; +// try { +// fin = new FileInputStream(file); +// KeyStore k; +// if (provider == null) +// k = KeyStore.GetInstance("JKS"); +// else +// k = KeyStore.GetInstance("JKS", provider); +// k.Load(fin, null); +// return k; +// } +// catch (Exception e) { +// throw new ExceptionConverter(e); +// } +// finally { +// try{fin.Close();}catch(Exception ex){} +// } +// } + + /** + * Verifies a single certificate. + * @param cert the certificate to verify + * @param crls the certificate revocation list or null + * @param calendar the date or null for the current date + * @return a String with the error description or null + * if no error + */ + public static String VerifyCertificate(X509Certificate cert, object[] crls, DateTime calendar) { + try { + if (!cert.IsValid(calendar)) + return "The certificate has expired or is not yet valid"; + } + catch (Exception e) { + return e.ToString(); + } + return null; + } + + /** + * Verifies a certificate chain against a KeyStore. + * @param certs the certificate chain + * @param keystore the KeyStore + * @param crls the certificate revocation list or null + * @param calendar the date or null for the current date + * @return null if the certificate chain could be validade or a + * Object[]{cert,error} where cert is the + * failed certificate and error is the error message + */ + public static Object[] VerifyCertificates(X509Certificate[] certs, ArrayList keystore, object[] crls, DateTime calendar) { + for (int k = 0; k < certs.Length; ++k) { + X509Certificate cert = certs[k]; + String err = VerifyCertificate(cert, crls, calendar); + if (err != null) + return new Object[]{cert, err}; + foreach (X509Certificate certStoreX509 in keystore) { + try { + if (VerifyCertificate(certStoreX509, crls, calendar) != null) + continue; + try { + cert.Verify(certStoreX509.GetPublicKey()); + return null; + } + catch { + continue; + } + } + catch { + } + } + int j; + for (j = 0; j < certs.Length; ++j) { + if (j == k) + continue; + X509Certificate certNext = certs[j]; + try { + cert.Verify(certNext.GetPublicKey()); + break; + } + catch { + } + } + if (j == certs.Length) + return new Object[]{cert, "Cannot be verified against the KeyStore or the certificate chain"}; + } + return new Object[]{null, "Invalid state. Possible circular certificate chain"}; + } + + /** + * Get the "issuer" from the TBSCertificate bytes that are passed in + * @param enc a TBSCertificate in a byte array + * @return a DERObject + */ + private static Asn1Object GetIssuer(byte[] enc) { + Asn1InputStream inp = new Asn1InputStream(new MemoryStream(enc)); + Asn1Sequence seq = (Asn1Sequence)inp.ReadObject(); + return (Asn1Object)seq[seq[0] is DerTaggedObject ? 3 : 2]; + } + + /** + * Get the "subject" from the TBSCertificate bytes that are passed in + * @param enc A TBSCertificate in a byte array + * @return a DERObject + */ + private static Asn1Object GetSubject(byte[] enc) { + Asn1InputStream inp = new Asn1InputStream(new MemoryStream(enc)); + Asn1Sequence seq = (Asn1Sequence)inp.ReadObject(); + return (Asn1Object)seq[seq[0] is DerTaggedObject ? 5 : 4]; + } + + /** + * Get the issuer fields from an X509 Certificate + * @param cert an X509Certificate + * @return an X509Name + */ + public static X509Name GetIssuerFields(X509Certificate cert) { + return new X509Name((Asn1Sequence)GetIssuer(cert.GetTbsCertificate())); + } + + /** + * Get the subject fields from an X509 Certificate + * @param cert an X509Certificate + * @return an X509Name + */ + public static X509Name GetSubjectFields(X509Certificate cert) { + return new X509Name((Asn1Sequence)GetSubject(cert.GetTbsCertificate())); + } + + /** + * Gets the bytes for the PKCS#1 object. + * @return a byte array + */ + public byte[] GetEncodedPKCS1() { + if (externalDigest != null) + digest = externalDigest; + else + digest = sig.GenerateSignature(); + MemoryStream bOut = new MemoryStream(); + + Asn1OutputStream dout = new Asn1OutputStream(bOut); + dout.WriteObject(new DerOctetString(digest)); + dout.Close(); + + return bOut.ToArray(); + } + + /** + * Sets the digest/signature to an external calculated value. + * @param digest the digest. This is the actual signature + * @param RSAdata the extra data that goes into the data tag in PKCS#7 + * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest + * is also null. If the digest is not null + * then it may be "RSA" or "DSA" + */ + public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm) { + externalDigest = digest; + externalRSAdata = RSAdata; + if (digestEncryptionAlgorithm != null) { + if (digestEncryptionAlgorithm.Equals("RSA")) { + this.digestEncryptionAlgorithm = ID_RSA; + } + else if (digestEncryptionAlgorithm.Equals("DSA")) { + this.digestEncryptionAlgorithm = ID_DSA; + } + else + throw new ArgumentException("Unknown Key Algorithm "+digestEncryptionAlgorithm); + } + } + + /** + * Gets the bytes for the PKCS7SignedData object. + * @return the bytes for the PKCS7SignedData object + */ + public byte[] GetEncodedPKCS7() { + return GetEncodedPKCS7(null, DateTime.Now); + } + + /** + * Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes + * in the signerInfo can also be set. If either of the parameters is null, none will be used. + * @param secondDigest the digest in the authenticatedAttributes + * @param signingTime the signing time in the authenticatedAttributes + * @return the bytes for the PKCS7SignedData object + */ + public byte[] GetEncodedPKCS7(byte[] secondDigest, DateTime signingTime) { + if (externalDigest != null) { + digest = externalDigest; + if (RSAdata != null) + RSAdata = externalRSAdata; + } + else if (externalRSAdata != null && RSAdata != null) { + RSAdata = externalRSAdata; + sig.BlockUpdate(RSAdata, 0, RSAdata.Length); + digest = sig.GenerateSignature(); + } + else { + if (RSAdata != null) { + RSAdata = new byte[messageDigest.GetDigestSize()]; + messageDigest.DoFinal(RSAdata, 0); + sig.BlockUpdate(RSAdata, 0, RSAdata.Length); + } + digest = sig.GenerateSignature(); + } + + // Create the set of Hash algorithms + Asn1EncodableVector digestAlgorithms = new Asn1EncodableVector(); + foreach (string dal in digestalgos.Keys) { + Asn1EncodableVector algos = new Asn1EncodableVector(); + algos.Add(new DerObjectIdentifier(dal)); + algos.Add(DerNull.Instance); + digestAlgorithms.Add(new DerSequence(algos)); + } + + // Create the contentInfo. + Asn1EncodableVector v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_PKCS7_DATA)); + if (RSAdata != null) + v.Add(new DerTaggedObject(0, new DerOctetString(RSAdata))); + DerSequence contentinfo = new DerSequence(v); + + // Get all the certificates + // + v = new Asn1EncodableVector(); + foreach (X509Certificate xcert in certs) { + Asn1InputStream tempstream = new Asn1InputStream(new MemoryStream(xcert.GetEncoded())); + v.Add(tempstream.ReadObject()); + } + + DerSet dercertificates = new DerSet(v); + + // Create signerinfo structure. + // + Asn1EncodableVector signerinfo = new Asn1EncodableVector(); + + // Add the signerInfo version + // + signerinfo.Add(new DerInteger(signerversion)); + + v = new Asn1EncodableVector(); + v.Add(GetIssuer(signCert.GetTbsCertificate())); + v.Add(new DerInteger(signCert.SerialNumber)); + signerinfo.Add(new DerSequence(v)); + + // Add the digestAlgorithm + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(digestAlgorithm)); + v.Add(DerNull.Instance); + signerinfo.Add(new DerSequence(v)); + + // add the authenticated attribute if present + if (secondDigest != null /*&& signingTime != null*/) { + Asn1EncodableVector attribute = new Asn1EncodableVector(); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_CONTENT_TYPE)); + v.Add(new DerSet(new DerObjectIdentifier(ID_PKCS7_DATA))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_SIGNING_TIME)); + v.Add(new DerSet(new DerUtcTime(signingTime))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_MESSAGE_DIGEST)); + v.Add(new DerSet(new DerOctetString(secondDigest))); + attribute.Add(new DerSequence(v)); + signerinfo.Add(new DerTaggedObject(false, 0, new DerSet(attribute))); + } + // Add the digestEncryptionAlgorithm + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(digestEncryptionAlgorithm)); + v.Add(DerNull.Instance); + signerinfo.Add(new DerSequence(v)); + + // Add the digest + signerinfo.Add(new DerOctetString(digest)); + + + // Finally build the body out of all the components above + Asn1EncodableVector body = new Asn1EncodableVector(); + body.Add(new DerInteger(version)); + body.Add(new DerSet(digestAlgorithms)); + body.Add(contentinfo); + body.Add(new DerTaggedObject(false, 0, dercertificates)); + +// if (crls.Count > 0) { +// v = new Asn1EncodableVector(); +// for (Iterator i = crls.Iterator();i.HasNext();) { +// Asn1InputStream t = new Asn1InputStream(new ByteArrayInputStream((((X509CRL)i.Next()).GetEncoded()))); +// v.Add(t.ReadObject()); +// } +// DERSet dercrls = new DERSet(v); +// body.Add(new DERTaggedObject(false, 1, dercrls)); +// } + + // Only allow one signerInfo + body.Add(new DerSet(new DerSequence(signerinfo))); + + // Now we have the body, wrap it in it's PKCS7Signed shell + // and return it + // + Asn1EncodableVector whole = new Asn1EncodableVector(); + whole.Add(new DerObjectIdentifier(ID_PKCS7_SIGNED_DATA)); + whole.Add(new DerTaggedObject(0, new DerSequence(body))); + + MemoryStream bOut = new MemoryStream(); + + Asn1OutputStream dout = new Asn1OutputStream(bOut); + dout.WriteObject(new DerSequence(whole)); + dout.Close(); + + return bOut.ToArray(); + } + + + /** + * When using authenticatedAttributes the authentication process is different. + * The document digest is generated and put inside the attribute. The signing is done over the DER encoded + * authenticatedAttributes. This method provides that encoding and the parameters must be + * exactly the same as in {@link #getEncodedPKCS7(byte[],Calendar)}. + *

+ * A simple example: + *

+ *

+        * Calendar cal = Calendar.GetInstance();
+        * PdfPKCS7 pk7 = new PdfPKCS7(key, chain, null, "SHA1", null, false);
+        * MessageDigest messageDigest = MessageDigest.GetInstance("SHA1");
+        * byte buf[] = new byte[8192];
+        * int n;
+        * Stream inp = sap.GetRangeStream();
+        * while ((n = inp.Read(buf)) > 0) {
+        *    messageDigest.Update(buf, 0, n);
+        * }
+        * byte hash[] = messageDigest.Digest();
+        * byte sh[] = pk7.GetAuthenticatedAttributeBytes(hash, cal);
+        * pk7.Update(sh, 0, sh.length);
+        * byte sg[] = pk7.GetEncodedPKCS7(hash, cal);
+        * 
+ * @param secondDigest the content digest + * @param signingTime the signing time + * @return the byte array representation of the authenticatedAttributes ready to be signed + */ + public byte[] GetAuthenticatedAttributeBytes(byte[] secondDigest, DateTime signingTime) { + Asn1EncodableVector attribute = new Asn1EncodableVector(); + Asn1EncodableVector v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_CONTENT_TYPE)); + v.Add(new DerSet(new DerObjectIdentifier(ID_PKCS7_DATA))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_SIGNING_TIME)); + v.Add(new DerSet(new DerUtcTime(signingTime))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_MESSAGE_DIGEST)); + v.Add(new DerSet(new DerOctetString(secondDigest))); + attribute.Add(new DerSequence(v)); + MemoryStream bOut = new MemoryStream(); + + Asn1OutputStream dout = new Asn1OutputStream(bOut); + dout.WriteObject(new DerSet(attribute)); + dout.Close(); + + return bOut.ToArray(); + } + + + public string Reason { + get { + return reason; + } + set { + reason = value; + } + } + + + public string Location { + get { + return location; + } + set { + location = value; + } + } + + + public DateTime SignDate { + get { + return signDate; + } + set { + signDate = value; + } + } + + + public string SignName { + get { + return signName; + } + set { + signName = value; + } + } + + /** + * a class that holds an X509 name + */ + public class X509Name { + /** + * country code - StringType(SIZE(2)) + */ + public static DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11"); + + /** + * Title + */ + public static DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier SN = new DerObjectIdentifier("2.5.4.5"); + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8"); + + /** Naming attribute of type X520name */ + public static DerObjectIdentifier SURNAME = new DerObjectIdentifier("2.5.4.4"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier GIVENNAME = new DerObjectIdentifier("2.5.4.42"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier INITIALS = new DerObjectIdentifier("2.5.4.43"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier GENERATION = new DerObjectIdentifier("2.5.4.44"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier UNIQUE_IDENTIFIER = new DerObjectIdentifier("2.5.4.45"); + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + *

Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. + */ + public static DerObjectIdentifier EmailAddress = new DerObjectIdentifier("1.2.840.113549.1.9.1"); + + /** + * email address in Verisign certificates + */ + public static DerObjectIdentifier E = EmailAddress; + + /** object identifier */ + public static DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** LDAP User id. */ + public static DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** A Hashtable with default symbols */ + public static Hashtable DefaultSymbols = new Hashtable(); + + static X509Name(){ + DefaultSymbols[C] = "C"; + DefaultSymbols[O] = "O"; + DefaultSymbols[T] = "T"; + DefaultSymbols[OU] = "OU"; + DefaultSymbols[CN] = "CN"; + DefaultSymbols[L] = "L"; + DefaultSymbols[ST] = "ST"; + DefaultSymbols[SN] = "SN"; + DefaultSymbols[EmailAddress] = "E"; + DefaultSymbols[DC] = "DC"; + DefaultSymbols[UID] = "UID"; + DefaultSymbols[SURNAME] = "SURNAME"; + DefaultSymbols[GIVENNAME] = "GIVENNAME"; + DefaultSymbols[INITIALS] = "INITIALS"; + DefaultSymbols[GENERATION] = "GENERATION"; + } + /** A Hashtable with values */ + public Hashtable values = new Hashtable(); + + /** + * Constructs an X509 name + * @param seq an Asn1 Sequence + */ + public X509Name(Asn1Sequence seq) { + IEnumerator e = seq.GetEnumerator(); + + while (e.MoveNext()) { + Asn1Set sett = (Asn1Set)e.Current; + + for (int i = 0; i < sett.Count; i++) { + Asn1Sequence s = (Asn1Sequence)sett[i]; + String id = (String)DefaultSymbols[s[0]]; + if (id == null) + continue; + ArrayList vs = (ArrayList)values[id]; + if (vs == null) { + vs = new ArrayList(); + values[id] = vs; + } + vs.Add(((DerStringBase)s[1]).GetString()); + } + } + } + /** + * Constructs an X509 name + * @param dirName a directory name + */ + public X509Name(String dirName) { + X509NameTokenizer nTok = new X509NameTokenizer(dirName); + + while (nTok.HasMoreTokens()) { + String token = nTok.NextToken(); + int index = token.IndexOf('='); + + if (index == -1) { + throw new ArgumentException("badly formated directory string"); + } + + String id = token.Substring(0, index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + String value = token.Substring(index + 1); + ArrayList vs = (ArrayList)values[id]; + if (vs == null) { + vs = new ArrayList(); + values[id] = vs; + } + vs.Add(value); + } + + } + + public String GetField(String name) { + ArrayList vs = (ArrayList)values[name]; + return vs == null ? null : (String)vs[0]; + } + + /** + * gets a field array from the values Hashmap + * @param name + * @return an ArrayList + */ + public ArrayList GetFieldArray(String name) { + ArrayList vs = (ArrayList)values[name]; + return vs == null ? null : vs; + } + + /** + * getter for values + * @return a Hashtable with the fields of the X509 name + */ + public Hashtable GetFields() { + return values; + } + + /** + * @see java.lang.Object#toString() + */ + public override String ToString() { + return values.ToString(); + } + } + + /** + * class for breaking up an X500 Name into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + */ + public class X509NameTokenizer { + private String oid; + private int index; + private StringBuilder buf = new StringBuilder(); + + public X509NameTokenizer( + String oid) { + this.oid = oid; + this.index = -1; + } + + public bool HasMoreTokens() { + return (index != oid.Length); + } + + public String NextToken() { + if (index == oid.Length) { + return null; + } + + int end = index + 1; + bool quoted = false; + bool escaped = false; + + buf.Length = 0; + + while (end != oid.Length) { + char c = oid[end]; + + if (c == '"') { + if (!escaped) { + quoted = !quoted; + } + else { + buf.Append(c); + } + escaped = false; + } + else { + if (escaped || quoted) { + buf.Append(c); + escaped = false; + } + else if (c == '\\') { + escaped = true; + } + else if (c == ',') { + break; + } + else { + buf.Append(c); + } + } + end++; + } + + index = end; + return buf.ToString().Trim(); + } + } + } +} + diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPRow.cs b/iTechSharp/iTextSharp/text/pdf/PdfPRow.cs new file mode 100644 index 0000000..ecb339d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPRow.cs @@ -0,0 +1,649 @@ +using System; + +using iTextSharp.text; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A row in a PdfPTable. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class PdfPRow { + + /** the bottom limit (bottom right y) */ + public const float BOTTOM_LIMIT = -(1 << 30); + + protected PdfPCell[] cells; + + protected float[] widths; + + protected float maxHeight = 0; + + protected bool calculated = false; + + private int[] canvasesPos; + + /** + * Constructs a new PdfPRow with the cells in the array that was passed as a parameter. + * @param cells + */ + public PdfPRow(PdfPCell[] cells) { + this.cells = cells; + widths = new float[cells.Length]; + } + + /** + * Makes a copy of an existing row. + * @param row + */ + public PdfPRow(PdfPRow row) { + maxHeight = row.maxHeight; + calculated = row.calculated; + cells = new PdfPCell[row.cells.Length]; + for (int k = 0; k < cells.Length; ++k) { + if (row.cells[k] != null) + cells[k] = new PdfPCell(row.cells[k]); + } + widths = new float[cells.Length]; + Array.Copy(row.widths, 0, widths, 0, cells.Length); + } + + /** + * Sets the widths of the columns in the row. + * @param widths + * @return true if everything went right + */ + public bool SetWidths(float[] widths) { + if (widths.Length != cells.Length) + return false; + Array.Copy(widths, 0, this.widths, 0, cells.Length); + float total = 0; + calculated = false; + for (int k = 0; k < widths.Length; ++k) { + PdfPCell cell = cells[k]; + cell.Left = total; + int last = k + cell.Colspan; + for (; k < last; ++k) + total += widths[k]; + --k; + cell.Right = total; + cell.Top = 0; + } + return true; + } + + /** + * Calculates the heights of each cell in the row. + * @return the maximum height of the row. + */ + public float CalculateHeights() { + maxHeight = 0; + for (int k = 0; k < cells.Length; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + Image img = cell.Image; + if (img != null) { + img.ScalePercent(100); + float refWidth = img.ScaledWidth; + if (cell.Rotation == 90 || cell.Rotation == 270) { + refWidth = img.ScaledHeight; + } + float scale = (cell.Right - cell.EffectivePaddingRight + - cell.EffectivePaddingLeft - cell.Left) + / refWidth; + img.ScalePercent(scale * 100); + float refHeight = img.ScaledHeight; + if (cell.Rotation == 90 || cell.Rotation == 270) { + refHeight = img.ScaledWidth; + } + cell.Bottom = cell.Top - cell.EffectivePaddingTop + - cell.EffectivePaddingBottom + - refHeight; + } else { + if (cell.Rotation == 0 || cell.Rotation == 180) { + float rightLimit = cell.NoWrap ? 20000 : cell.Right + - cell.EffectivePaddingRight; + float bry = (cell.FixedHeight > 0) ? cell.Top + - cell.EffectivePaddingTop + + cell.EffectivePaddingBottom + - cell.FixedHeight : BOTTOM_LIMIT; + ColumnText ct = ColumnText.Duplicate(cell.Column); + SetColumn(ct, + cell.Left + cell.EffectivePaddingLeft, bry, + rightLimit, cell.Top - cell.EffectivePaddingTop); + ct.Go(true); + float yLine = ct.YLine; + if (cell.UseDescender) + yLine += ct.Descender; + cell.Bottom = yLine - cell.EffectivePaddingBottom; + } + else { + if (cell.FixedHeight > 0) { + cell.Bottom = cell.Top - cell.FixedHeight; + } + else { + ColumnText ct = ColumnText.Duplicate(cell.Column); + SetColumn(ct, 0, cell.Left + cell.EffectivePaddingLeft, + 20000, cell.Right - cell.EffectivePaddingRight); + ct.Go(true); + cell.Bottom = cell.Top - cell.EffectivePaddingTop + - cell.EffectivePaddingBottom - ct.FilledWidth; + } + } + } + float height = cell.FixedHeight; + if (height <= 0) + height = cell.Height; + if (height < cell.FixedHeight) + height = cell.FixedHeight; + else if (height < cell.MinimumHeight) + height = cell.MinimumHeight; + if (height > maxHeight) + maxHeight = height; + } + calculated = true; + return maxHeight; + } + + /** + * Writes the border and background of one cell in the row. + * @param xPos + * @param yPos + * @param cell + * @param canvases + */ + public void WriteBorderAndBackground(float xPos, float yPos, PdfPCell cell, + PdfContentByte[] canvases) { + PdfContentByte lines = canvases[PdfPTable.LINECANVAS]; + PdfContentByte backgr = canvases[PdfPTable.BACKGROUNDCANVAS]; + // the coordinates of the border are retrieved + float x1 = cell.Left + xPos; + float y2 = cell.Top + yPos; + float x2 = cell.Right + xPos; + float y1 = y2 - maxHeight; + + // the backgroundcolor is set + Color background = cell.BackgroundColor; + if (background != null) { + backgr.SetColorFill(background); + backgr.Rectangle(x1, y1, x2 - x1, y2 - y1); + backgr.Fill(); + } + // if the element hasn't got any borders, nothing is added + if (cell.HasBorders()) { + if (cell.UseVariableBorders) { + Rectangle borderRect = new Rectangle(cell.Left + xPos, cell.Top + - maxHeight + yPos, cell.Right + xPos, cell.Top + + yPos); + borderRect.CloneNonPositionParameters(cell); + borderRect.BackgroundColor = null; + lines.Rectangle(borderRect); + } else { + // the width is set to the width of the element + if (cell.BorderWidth != Rectangle.UNDEFINED) { + lines.SetLineWidth(cell.BorderWidth); + } + // the color is set to the color of the element + Color color = cell.BorderColor; + if (color != null) { + lines.SetColorStroke(color); + } + + // if the box is a rectangle, it is added as a rectangle + if (cell.HasBorder(Rectangle.BOX)) { + lines.Rectangle(x1, y1, x2 - x1, y2 - y1); + } + // if the border isn't a rectangle, the different sides are + // added apart + else { + if (cell.HasBorder(Rectangle.RIGHT_BORDER)) { + lines.MoveTo(x2, y1); + lines.LineTo(x2, y2); + } + if (cell.HasBorder(Rectangle.LEFT_BORDER)) { + lines.MoveTo(x1, y1); + lines.LineTo(x1, y2); + } + if (cell.HasBorder(Rectangle.BOTTOM_BORDER)) { + lines.MoveTo(x1, y1); + lines.LineTo(x2, y1); + } + if (cell.HasBorder(Rectangle.TOP_BORDER)) { + lines.MoveTo(x1, y2); + lines.LineTo(x2, y2); + } + } + lines.Stroke(); + if (color != null) { + lines.ResetRGBColorStroke(); + } + } + } + } + + private void SaveAndRotateCanvases(PdfContentByte[] canvases, float a, float b, float c, float d, float e, float f) { + int last = PdfPTable.TEXTCANVAS + 1; + if (canvasesPos == null) { + canvasesPos = new int[last * 2]; + } + for (int k = 0; k < last; ++k) { + ByteBuffer bb = canvases[k].InternalBuffer; + canvasesPos[k * 2] = bb.Size; + canvases[k].SaveState(); + canvases[k].ConcatCTM(a, b, c, d, e, f); + canvasesPos[k * 2 + 1] = bb.Size; + } + } + + private void RestoreCanvases(PdfContentByte[] canvases) { + int last = PdfPTable.TEXTCANVAS + 1; + for (int k = 0; k < last; ++k) { + ByteBuffer bb = canvases[k].InternalBuffer; + int p1 = bb.Size; + canvases[k].RestoreState(); + if (p1 == canvasesPos[k * 2 + 1]) + bb.Size = canvasesPos[k * 2]; + } + } + + private float SetColumn(ColumnText ct, float llx, float lly, float urx, float ury) { + if (llx > urx) + urx = llx; + if (lly > ury) + ury = lly; + ct.SetSimpleColumn(llx, lly, urx, ury); + return ury; + } + + /** + * Writes a number of cells (not necessarily all cells). + * @param colStart + * @param colEnd + * @param xPos + * @param yPos + * @param canvases + */ + public void WriteCells(int colStart, int colEnd, float xPos, float yPos, + PdfContentByte[] canvases) { + if (!calculated) + CalculateHeights(); + if (colEnd < 0) + colEnd = cells.Length; + colEnd = Math.Min(colEnd, cells.Length); + if (colStart < 0) + colStart = 0; + if (colStart >= colEnd) + return; + int newStart; + for (newStart = colStart; newStart >= 0; --newStart) { + if (cells[newStart] != null) + break; + xPos -= widths[newStart - 1]; + } + xPos -= cells[newStart].Left; + for (int k = newStart; k < colEnd; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + WriteBorderAndBackground(xPos, yPos, cell, canvases); + Image img = cell.Image; + float tly = 0; + switch (cell.VerticalAlignment) { + case Element.ALIGN_BOTTOM: + tly = cell.Top + yPos - maxHeight + cell.Height + - cell.EffectivePaddingTop; + break; + case Element.ALIGN_MIDDLE: + tly = cell.Top + yPos + (cell.Height - maxHeight) / 2 + - cell.EffectivePaddingTop; + break; + default: + tly = cell.Top + yPos - cell.EffectivePaddingTop; + break; + } + if (img != null) { + if (cell.Rotation != 0) { + img = Image.GetInstance(img); + img.Rotation = img.GetImageRotation() + (float)(cell.Rotation * Math.PI / 180.0); + } + bool vf = false; + if (cell.Height > maxHeight) { + img.ScalePercent(100); + float scale = (maxHeight - cell.EffectivePaddingTop - cell + .EffectivePaddingBottom) + / img.ScaledHeight; + img.ScalePercent(scale * 100); + vf = true; + } + float left = cell.Left + xPos + + cell.EffectivePaddingLeft; + if (vf) { + switch (cell.HorizontalAlignment) { + case Element.ALIGN_CENTER: + left = xPos + + (cell.Left + cell.EffectivePaddingLeft + + cell.Right + - cell.EffectivePaddingRight - img + .ScaledWidth) / 2; + break; + case Element.ALIGN_RIGHT: + left = xPos + cell.Right + - cell.EffectivePaddingRight + - img.ScaledWidth; + break; + default: + break; + } + tly = cell.Top + yPos - cell.EffectivePaddingTop; + } + img.SetAbsolutePosition(left, tly - img.ScaledHeight); + canvases[PdfPTable.TEXTCANVAS].AddImage(img); + } else { + if (cell.Rotation == 90 || cell.Rotation == 270) { + float netWidth = maxHeight - cell.EffectivePaddingTop - cell.EffectivePaddingBottom; + float netHeight = cell.Width - cell.EffectivePaddingLeft - cell.EffectivePaddingRight; + ColumnText ct = ColumnText.Duplicate(cell.Column); + ct.Canvases = canvases; + ct.SetSimpleColumn(0, 0, netWidth + 0.001f, -netHeight); + ct.Go(true); + float calcHeight = -ct.YLine; + if (netWidth <= 0 || netHeight <= 0) + calcHeight = 0; + if (calcHeight > 0) { + if (cell.UseDescender) + calcHeight -= ct.Descender; + ct = ColumnText.Duplicate(cell.Column); + ct.Canvases = canvases; + ct.SetSimpleColumn(0, -0.001f, netWidth + 0.001f, calcHeight); + float pivotX; + float pivotY; + if (cell.Rotation == 90) { + pivotY = cell.Top + yPos - maxHeight + cell.EffectivePaddingBottom; + switch (cell.VerticalAlignment) { + case Element.ALIGN_BOTTOM: + pivotX = cell.Left + xPos + cell.Width - cell.EffectivePaddingRight; + break; + case Element.ALIGN_MIDDLE: + pivotX = cell.Left + xPos + (cell.Width + cell.EffectivePaddingLeft - cell.EffectivePaddingRight + calcHeight) / 2; + break; + default: //top + pivotX = cell.Left + xPos + cell.EffectivePaddingLeft + calcHeight; + break; + } + SaveAndRotateCanvases(canvases, 0,1,-1,0,pivotX,pivotY); + } + else { + pivotY = cell.Top + yPos - cell.EffectivePaddingTop; + switch (cell.VerticalAlignment) { + case Element.ALIGN_BOTTOM: + pivotX = cell.Left + xPos + cell.EffectivePaddingLeft; + break; + case Element.ALIGN_MIDDLE: + pivotX = cell.Left + xPos + (cell.Width + cell.EffectivePaddingLeft - cell.EffectivePaddingRight - calcHeight) / 2; + break; + default: //top + pivotX = cell.Left + xPos + cell.Width - cell.EffectivePaddingRight - calcHeight; + break; + } + SaveAndRotateCanvases(canvases, 0,-1,1,0,pivotX,pivotY); + } + try { + ct.Go(); + } finally { + RestoreCanvases(canvases); + } + } + } + else { + float fixedHeight = cell.FixedHeight; + float rightLimit = cell.Right + xPos + - cell.EffectivePaddingRight; + float leftLimit = cell.Left + xPos + + cell.EffectivePaddingLeft; + if (cell.NoWrap) { + switch (cell.HorizontalAlignment) { + case Element.ALIGN_CENTER: + rightLimit += 10000; + leftLimit -= 10000; + break; + case Element.ALIGN_RIGHT: + leftLimit -= 20000; + break; + default: + rightLimit += 20000; + break; + } + } + ColumnText ct = ColumnText.Duplicate(cell.Column); + ct.Canvases = canvases; + float bry = tly + - (maxHeight /* cell.Height */ + - cell.EffectivePaddingTop - cell + .EffectivePaddingBottom); + if (fixedHeight > 0) { + if (cell.Height > maxHeight) { + tly = cell.Top + yPos - cell.EffectivePaddingTop; + bry = cell.Top + yPos - maxHeight + + cell.EffectivePaddingBottom; + } + } + if ((tly > bry || ct.ZeroHeightElement()) && leftLimit < rightLimit) { + ct.SetSimpleColumn(leftLimit, bry - 0.001f, rightLimit, tly); + if (cell.Rotation == 180) { + float shx = leftLimit + rightLimit; + float shy = yPos + yPos - maxHeight + cell.EffectivePaddingBottom - cell.EffectivePaddingTop; + SaveAndRotateCanvases(canvases, -1,0,0,-1,shx,shy); + } + try { + ct.Go(); + } finally { + if (cell.Rotation == 180) { + RestoreCanvases(canvases); + } + } + } + } + } + IPdfPCellEvent evt = cell.CellEvent; + if (evt != null) { + Rectangle rect = new Rectangle(cell.Left + xPos, cell.Top + + yPos - maxHeight, cell.Right + xPos, cell.Top + + yPos); + evt.CellLayout(cell, rect, canvases); + } + } + } + + /** + * Checks if the dimensions of the columns were calculated. + * @return true if the dimensions of the columns were calculated + */ + public bool IsCalculated() { + return calculated; + } + + /** + * Gets the maximum height of the row (i.e. of the 'highest' cell). + * @return the maximum height of the row + */ + public float MaxHeights { + get { + if (calculated) + return maxHeight; + else + return CalculateHeights(); + } + set { + this.maxHeight = value; + } + } + + + internal float[] GetEventWidth(float xPos) { + int n = 0; + for (int k = 0; k < cells.Length; ++k) { + if (cells[k] != null) + ++n; + } + float[] width = new float[n + 1]; + n = 0; + width[n++] = xPos; + for (int k = 0; k < cells.Length; ++k) { + if (cells[k] != null) { + width[n] = width[n - 1] + cells[k].Width; + ++n; + } + } + return width; + } + + /** + * Splits a row to newHeight. The returned row is the remainder. It will + * return null if the newHeight was so small that only an empty row would + * result. + * + * @param newHeight + * the new height + * @return the remainder row or null if the newHeight was so small that only + * an empty row would result + */ + public PdfPRow SplitRow(float newHeight) { + PdfPCell[] newCells = new PdfPCell[cells.Length]; + float[] fh = new float[cells.Length * 2]; + bool allEmpty = true; + for (int k = 0; k < cells.Length; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + fh[k * 2] = cell.FixedHeight; + fh[k * 2 + 1] = cell.MinimumHeight; + Image img = cell.Image; + PdfPCell c2 = new PdfPCell(cell); + if (img != null) { + if (newHeight > cell.EffectivePaddingBottom + + cell.EffectivePaddingTop + 2) { + c2.Phrase = null; + allEmpty = false; + } + } else { + int status; + float y; + ColumnText ct = ColumnText.Duplicate(cell.Column); + if (cell.Rotation == 90 || cell.Rotation == 270) { + y = SetColumn(ct, + cell.Top - newHeight + cell.EffectivePaddingBottom, + cell.Left + cell.EffectivePaddingLeft, + cell.Top - cell.EffectivePaddingTop, + cell.Right - cell.EffectivePaddingRight); + } + else { + float rightLimit = cell.NoWrap ? 20000 : cell.Right + - cell.EffectivePaddingRight; + float y1 = cell.Top - newHeight + + cell.EffectivePaddingBottom; + float y2 = cell.Top - cell.EffectivePaddingTop; + y = Math.Max(y1, y2); + y = SetColumn(ct, + cell.Left + cell.EffectivePaddingLeft, y1, + rightLimit, y2); + } + status = ct.Go(true); + bool thisEmpty = (ct.YLine == y); + if (thisEmpty) + ct = ColumnText.Duplicate(cell.Column); + allEmpty = (allEmpty && thisEmpty); + if ((status & ColumnText.NO_MORE_TEXT) == 0 || thisEmpty) { + c2.Column = ct; + ct.FilledWidth = 0; + } else { + c2.Phrase = null; + } + } + newCells[k] = c2; + cell.FixedHeight = newHeight; + } + if (allEmpty) { + for (int k = 0; k < cells.Length; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + float f = fh[k * 2]; + float m = fh[k * 2 + 1]; + if (f <= 0) + cell.MinimumHeight = m; + else + cell.FixedHeight = f; + } + return null; + } + CalculateHeights(); + PdfPRow split = new PdfPRow(newCells); + split.widths = (float[]) widths.Clone(); + split.CalculateHeights(); + return split; + } + + /** + * Returns the array of cells in the row. + * Please be extremely careful with this method. + * Use the cells as read only objects. + * @return an array of cells + * @since 2.1.1 + */ + public PdfPCell[] Cells { + get { + return cells; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs new file mode 100644 index 0000000..78f0a4f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs @@ -0,0 +1,101 @@ +using System; +/* + * Copyright 2005 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Implements the PostScript XObject. + */ + public class PdfPSXObject : PdfTemplate { + + /** Creates a new instance of PdfPSXObject */ + protected PdfPSXObject() { + } + + /** + * Constructs a PSXObject + * @param wr + */ + public PdfPSXObject(PdfWriter wr) : base(wr) { + } + + /** + * Gets the stream representing this object. + * + * @return the stream representing this object + * @throws IOException + */ + + internal override PdfStream FormXObject { + get { + PdfStream s = new PdfStream(content.ToByteArray()); + s.Put(PdfName.TYPE, PdfName.XOBJECT); + s.Put(PdfName.SUBTYPE, PdfName.PS); + s.FlateCompress(); + return s; + } + } + + /** + * Gets a duplicate of this PdfPSXObject. All + * the members are copied by reference but the buffer stays different. + * @return a copy of this PdfPSXObject + */ + + public override PdfContentByte Duplicate { + get { + PdfPSXObject tpl = new PdfPSXObject(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.separator = separator; + return tpl; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPTable.cs b/iTechSharp/iTextSharp/text/pdf/PdfPTable.cs new file mode 100644 index 0000000..3f82101 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPTable.cs @@ -0,0 +1,1050 @@ +using System; +using System.Collections; + +using iTextSharp.text; +using iTextSharp.text.pdf.events; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** This is a table that can be put at an absolute position but can also + * be added to the document as the class Table. + * In the last case when crossing pages the table always break at full rows; if a + * row is bigger than the page it is dropped silently to avoid infinite loops. + *

+ * A PdfPTableEvent can be associated to the table to do custom drawing + * when the table is rendered. + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class PdfPTable : ILargeElement{ + + /** The index of the original PdfcontentByte. + */ + public const int BASECANVAS = 0; + /** The index of the duplicate PdfContentByte where the background will be drawn. + */ + public const int BACKGROUNDCANVAS = 1; + /** The index of the duplicate PdfContentByte where the border lines will be drawn. + */ + public const int LINECANVAS = 2; + /** The index of the duplicate PdfContentByte where the text will be drawn. + */ + public const int TEXTCANVAS = 3; + + protected ArrayList rows = new ArrayList(); + protected float totalHeight = 0; + protected PdfPCell[] currentRow; + protected int currentRowIdx = 0; + protected PdfPCell defaultCell = new PdfPCell((Phrase)null); + protected float totalWidth = 0; + protected float[] relativeWidths; + protected float[] absoluteWidths; + protected IPdfPTableEvent tableEvent; + + /** Holds value of property headerRows. */ + protected int headerRows; + + /** Holds value of property widthPercentage. */ + protected float widthPercentage = 80; + + /** Holds value of property horizontalAlignment. */ + private int horizontalAlignment = Element.ALIGN_CENTER; + + /** Holds value of property skipFirstHeader. */ + private bool skipFirstHeader = false; + + protected bool isColspan = false; + + protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT; + + /** + * Holds value of property lockedWidth. + */ + private bool lockedWidth = false; + + /** + * Holds value of property splitRows. + */ + private bool splitRows = true; + + /** The spacing before the table. */ + protected float spacingBefore; + + /** The spacing after the table. */ + protected float spacingAfter; + + /** + * Holds value of property extendLastRow. + */ + private bool extendLastRow; + + /** + * Holds value of property headersInEvent. + */ + private bool headersInEvent; + + /** + * Holds value of property splitLate. + */ + private bool splitLate = true; + + /** + * Defines if the table should be kept + * on one page if possible + */ + private bool keepTogether; + + /** + * Indicates if the PdfPTable is complete once added to the document. + * @since iText 2.0.8 + */ + protected bool complete = true; + + private int footerRows; + + protected PdfPTable() { + } + + /** Constructs a PdfPTable with the relative column widths. + * @param relativeWidths the relative column widths + */ + public PdfPTable(float[] relativeWidths) { + if (relativeWidths == null) + throw new ArgumentNullException("The widths array in PdfPTable constructor can not be null."); + if (relativeWidths.Length == 0) + throw new ArgumentException("The widths array in PdfPTable constructor can not have zero length."); + this.relativeWidths = new float[relativeWidths.Length]; + Array.Copy(relativeWidths, 0, this.relativeWidths, 0, relativeWidths.Length); + absoluteWidths = new float[relativeWidths.Length]; + CalculateWidths(); + currentRow = new PdfPCell[absoluteWidths.Length]; + keepTogether = false; + } + + /** Constructs a PdfPTable with numColumns columns. + * @param numColumns the number of columns + */ + public PdfPTable(int numColumns) { + if (numColumns <= 0) + throw new ArgumentException("The number of columns in PdfPTable constructor must be greater than zero."); + relativeWidths = new float[numColumns]; + for (int k = 0; k < numColumns; ++k) + relativeWidths[k] = 1; + absoluteWidths = new float[relativeWidths.Length]; + CalculateWidths(); + currentRow = new PdfPCell[absoluteWidths.Length]; + keepTogether = false; + } + + /** Constructs a copy of a PdfPTable. + * @param table the PdfPTable to be copied + */ + public PdfPTable(PdfPTable table) { + CopyFormat(table); + for (int k = 0; k < currentRow.Length; ++k) { + if (table.currentRow[k] == null) + break; + currentRow[k] = new PdfPCell(table.currentRow[k]); + } + for (int k = 0; k < table.rows.Count; ++k) { + PdfPRow row = (PdfPRow)(table.rows[k]); + if (row != null) + row = new PdfPRow(row); + rows.Add(row); + } + } + + /** + * Makes a shallow copy of a table (format without content). + * @param table + * @return a shallow copy of the table + */ + public static PdfPTable ShallowCopy(PdfPTable table) { + PdfPTable nt = new PdfPTable(); + nt.CopyFormat(table); + return nt; + } + + /** + * Copies the format of the sourceTable without copying the content. + * @param sourceTable + */ + private void CopyFormat(PdfPTable sourceTable) { + relativeWidths = new float[sourceTable.relativeWidths.Length]; + absoluteWidths = new float[sourceTable.relativeWidths.Length]; + Array.Copy(sourceTable.relativeWidths, 0, relativeWidths, 0, relativeWidths.Length); + Array.Copy(sourceTable.absoluteWidths, 0, absoluteWidths, 0, relativeWidths.Length); + totalWidth = sourceTable.totalWidth; + totalHeight = sourceTable.totalHeight; + currentRowIdx = 0; + tableEvent = sourceTable.tableEvent; + runDirection = sourceTable.runDirection; + defaultCell = new PdfPCell(sourceTable.defaultCell); + currentRow = new PdfPCell[sourceTable.currentRow.Length]; + isColspan = sourceTable.isColspan; + splitRows = sourceTable.splitRows; + spacingAfter = sourceTable.spacingAfter; + spacingBefore = sourceTable.spacingBefore; + headerRows = sourceTable.headerRows; + footerRows = sourceTable.footerRows; + lockedWidth = sourceTable.lockedWidth; + extendLastRow = sourceTable.extendLastRow; + headersInEvent = sourceTable.headersInEvent; + widthPercentage = sourceTable.widthPercentage; + splitLate = sourceTable.splitLate; + skipFirstHeader = sourceTable.skipFirstHeader; + horizontalAlignment = sourceTable.horizontalAlignment; + keepTogether = sourceTable.keepTogether; + complete = sourceTable.complete; + } + + /** Sets the relative widths of the table. + * @param relativeWidths the relative widths of the table. + * @throws DocumentException if the number of widths is different than the number + * of columns + */ + public void SetWidths(float[] relativeWidths) { + if (relativeWidths.Length != this.relativeWidths.Length) + throw new DocumentException("Wrong number of columns."); + this.relativeWidths = new float[relativeWidths.Length]; + Array.Copy(relativeWidths, 0, this.relativeWidths, 0, relativeWidths.Length); + absoluteWidths = new float[relativeWidths.Length]; + totalHeight = 0; + CalculateWidths(); + CalculateHeights(); + } + + /** Sets the relative widths of the table. + * @param relativeWidths the relative widths of the table. + * @throws DocumentException if the number of widths is different than the number + * of columns + */ + public void SetWidths(int[] relativeWidths) { + float[] tb = new float[relativeWidths.Length]; + for (int k = 0; k < relativeWidths.Length; ++k) + tb[k] = relativeWidths[k]; + SetWidths(tb); + } + + private void CalculateWidths() { + if (totalWidth <= 0) + return; + float total = 0; + for (int k = 0; k < absoluteWidths.Length; ++k) { + total += relativeWidths[k]; + } + for (int k = 0; k < absoluteWidths.Length; ++k) { + absoluteWidths[k] = totalWidth * relativeWidths[k] / total; + } + } + + /** Sets the full width of the table from the absolute column width. + * @param columnWidth the absolute width of each column + * @throws DocumentException if the number of widths is different than the number + * of columns + */ + public void SetTotalWidth(float[] columnWidth) { + if (columnWidth.Length != this.relativeWidths.Length) + throw new DocumentException("Wrong number of columns."); + totalWidth = 0; + for (int k = 0; k < columnWidth.Length; ++k) + totalWidth += columnWidth[k]; + SetWidths(columnWidth); + } + + /** Sets the percentage width of the table from the absolute column width. + * @param columnWidth the absolute width of each column + * @param pageSize the page size + * @throws DocumentException + */ + public void SetWidthPercentage(float[] columnWidth, Rectangle pageSize) { + if (columnWidth.Length != this.relativeWidths.Length) + throw new ArgumentException("Wrong number of columns."); + float totalWidth = 0; + for (int k = 0; k < columnWidth.Length; ++k) + totalWidth += columnWidth[k]; + widthPercentage = totalWidth / (pageSize.Right - pageSize.Left) * 100f; + SetWidths(columnWidth); + } + + /** Gets the full width of the table. + * @return the full width of the table + */ + public float TotalWidth { + get { + return totalWidth; + } + set { + if (this.totalWidth == value) + return; + this.totalWidth = value; + totalHeight = 0; + CalculateWidths(); + CalculateHeights(); + } + } + + internal void CalculateHeights() { + if (totalWidth <= 0) + return; + totalHeight = 0; + for (int k = 0; k < rows.Count; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) { + row.SetWidths(absoluteWidths); + totalHeight += row.MaxHeights; + } + } + } + + /** + * Calculates the heights of the table. + */ + public void CalculateHeightsFast() { + if (totalWidth <= 0) + return; + totalHeight = 0; + for (int k = 0; k < rows.Count; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) + totalHeight += row.MaxHeights; + } + } + + /** Gets the default PdfPCell that will be used as + * reference for all the addCell methods except + * addCell(PdfPCell). + * @return default PdfPCell + */ + public PdfPCell DefaultCell { + get { + return defaultCell; + } + } + + /** Adds a cell element. + * @param cell the cell element + */ + public void AddCell(PdfPCell cell) { + PdfPCell ncell = new PdfPCell(cell); + int colspan = ncell.Colspan; + colspan = Math.Max(colspan, 1); + colspan = Math.Min(colspan, currentRow.Length - currentRowIdx); + ncell.Colspan = colspan; + if (colspan != 1) + isColspan = true; + int rdir = ncell.RunDirection; + if (rdir == PdfWriter.RUN_DIRECTION_DEFAULT) + ncell.RunDirection = runDirection; + currentRow[currentRowIdx] = ncell; + currentRowIdx += colspan; + if (currentRowIdx >= currentRow.Length) { + if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { + PdfPCell[] rtlRow = new PdfPCell[absoluteWidths.Length]; + int rev = currentRow.Length; + for (int k = 0; k < currentRow.Length; ++k) { + PdfPCell rcell = currentRow[k]; + int cspan = rcell.Colspan; + rev -= cspan; + rtlRow[rev] = rcell; + k += cspan - 1; + } + currentRow = rtlRow; + } + PdfPRow row = new PdfPRow(currentRow); + if (totalWidth > 0) { + row.SetWidths(absoluteWidths); + totalHeight += row.MaxHeights; + } + rows.Add(row); + currentRow = new PdfPCell[absoluteWidths.Length]; + currentRowIdx = 0; + } + } + + /** Adds a cell element. + * @param text the text for the cell + */ + public void AddCell(String text) { + AddCell(new Phrase(text)); + } + + /** + * Adds a nested table. + * @param table the table to be added to the cell + */ + public void AddCell(PdfPTable table) { + defaultCell.Table = table; + AddCell(defaultCell); + defaultCell.Table = null; + } + + /** + * Adds an Image as Cell. + * @param image the Image to add to the table. This image will fit in the cell + */ + public void AddCell(Image image) { + defaultCell.Image = image; + AddCell(defaultCell); + defaultCell.Image = null; + } + + /** + * Adds a cell element. + * @param phrase the Phrase to be added to the cell + */ + public void AddCell(Phrase phrase) { + defaultCell.Phrase = phrase; + AddCell(defaultCell); + defaultCell.Phrase = null; + } + + /** + * Writes the selected rows to the document. + *

+ * canvases is obtained from beginWritingRows(). + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvases an array of 4 PdfContentByte obtained from + * beginWrittingRows() + * @return the y coordinate position of the bottom of the last row + * @see #beginWritingRows(com.lowagie.text.pdf.PdfContentByte) + */ + public float WriteSelectedRows(int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte[] canvases) { + return WriteSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos, canvases); + } + + /** Writes the selected rows and columns to the document. + * This method does not clip the columns; this is only important + * if there are columns with colspan at boundaries. + *

+ * canvases is obtained from beginWritingRows(). + *

+ * The table event is only fired for complete rows. + * @param colStart the first column to be written, zero index + * @param colEnd the last column to be written + 1. If it is -1 all the + * columns to the end are written + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvases an array of 4 PdfContentByte obtained from + * beginWrittingRows() + * @return the y coordinate position of the bottom of the last row + * @see #beginWritingRows(com.lowagie.text.pdf.PdfContentByte) + */ + public float WriteSelectedRows(int colStart, int colEnd, int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte[] canvases) { + if (totalWidth <= 0) + throw new ArgumentException("The table width must be greater than zero."); + int size = rows.Count; + if (rowEnd < 0) + rowEnd = size; + rowEnd = Math.Min(rowEnd, size); + if (rowStart < 0) + rowStart = 0; + if (rowStart >= rowEnd) + return yPos; + if (colEnd < 0) + colEnd = absoluteWidths.Length; + colEnd = Math.Min(colEnd, absoluteWidths.Length); + if (colStart < 0) + colStart = 0; + colStart = Math.Min(colStart, absoluteWidths.Length); + float yPosStart = yPos; + for (int k = rowStart; k < rowEnd; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) { + row.WriteCells(colStart, colEnd, xPos, yPos, canvases); + yPos -= row.MaxHeights; + } + } + if (tableEvent != null && colStart == 0 && colEnd == absoluteWidths.Length) { + float[] heights = new float[rowEnd - rowStart + 1]; + heights[0] = yPosStart; + for (int k = rowStart; k < rowEnd; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + float hr = 0; + if (row != null) + hr = row.MaxHeights; + heights[k - rowStart + 1] = heights[k - rowStart] - hr; + } + tableEvent.TableLayout(this, GetEventWidths(xPos, rowStart, rowEnd, headersInEvent), heights, headersInEvent ? headerRows : 0, rowStart, canvases); + } + return yPos; + } + + /** + * Writes the selected rows to the document. + * + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvas the PdfContentByte where the rows will + * be written to + * @return the y coordinate position of the bottom of the last row + */ + public float WriteSelectedRows(int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte canvas) { + return WriteSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos, canvas); + } + + /** + * Writes the selected rows to the document. + * This method clips the columns; this is only important + * if there are columns with colspan at boundaries. + *

+ * The table event is only fired for complete rows. + * + * @param colStart the first column to be written, zero index + * @param colEnd the last column to be written + 1. If it is -1 all the + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvas the PdfContentByte where the rows will + * be written to + * @return the y coordinate position of the bottom of the last row + */ + public float WriteSelectedRows(int colStart, int colEnd, int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte canvas) { + if (colEnd < 0) + colEnd = absoluteWidths.Length; + colEnd = Math.Min(colEnd, absoluteWidths.Length); + if (colStart < 0) + colStart = 0; + colStart = Math.Min(colStart, absoluteWidths.Length); + if (colStart != 0 || colEnd != absoluteWidths.Length) { + float w = 0; + for (int k = colStart; k < colEnd; ++k) + w += absoluteWidths[k]; + canvas.SaveState(); + float lx = 0; + float rx = 0; + if (colStart == 0) + lx = 10000; + if (colEnd == absoluteWidths.Length) + rx = 10000; + canvas.Rectangle(xPos - lx, -10000, w + lx + rx, 20000); + canvas.Clip(); + canvas.NewPath(); + } + PdfContentByte[] canvases = BeginWritingRows(canvas); + float y = WriteSelectedRows(colStart, colEnd, rowStart, rowEnd, xPos, yPos, canvases); + EndWritingRows(canvases); + if (colStart != 0 || colEnd != absoluteWidths.Length) + canvas.RestoreState(); + return y; + } + + /** Gets and initializes the 4 layers where the table is written to. The text or graphics are added to + * one of the 4 PdfContentByte returned with the following order:

+ *

    + *
  • PdfPtable.BASECANVAS - the original PdfContentByte. Anything placed here + * will be under the table. + *
  • PdfPtable.BACKGROUNDCANVAS - the layer where the background goes to. + *
  • PdfPtable.LINECANVAS - the layer where the lines go to. + *
  • PdfPtable.TEXTCANVAS - the layer where the text go to. Anything placed here + * will be over the table. + *

+ * The layers are placed in sequence on top of each other. + * @param canvas the PdfContentByte where the rows will + * be written to + * @return an array of 4 PdfContentByte + * @see #writeSelectedRows(int, int, float, float, PdfContentByte[]) + */ + public static PdfContentByte[] BeginWritingRows(PdfContentByte canvas) { + return new PdfContentByte[]{ + canvas, + canvas.Duplicate, + canvas.Duplicate, + canvas.Duplicate, + }; + } + + /** Finishes writing the table. + * @param canvases the array returned by beginWritingRows() + */ + public static void EndWritingRows(PdfContentByte[] canvases) { + PdfContentByte canvas = canvases[BASECANVAS]; + canvas.SaveState(); + canvas.Add(canvases[BACKGROUNDCANVAS]); + canvas.RestoreState(); + canvas.SaveState(); + canvas.SetLineCap(2); + canvas.ResetRGBColorStroke(); + canvas.Add(canvases[LINECANVAS]); + canvas.RestoreState(); + canvas.Add(canvases[TEXTCANVAS]); + } + + /** Gets the number of rows in this table. + * @return the number of rows in this table + */ + public int Size { + get { + return rows.Count; + } + } + + /** Gets the total height of the table. + * @return the total height of the table + */ + public float TotalHeight { + get { + return totalHeight; + } + } + + /** Gets the height of a particular row. + * @param idx the row index (starts at 0) + * @return the height of a particular row + */ + public float GetRowHeight(int idx) { + if (totalWidth <= 0 || idx < 0 || idx >= rows.Count) + return 0; + PdfPRow row = (PdfPRow)rows[idx]; + if (row == null) + return 0; + return row.MaxHeights; + } + + /** Gets the height of the rows that constitute the header as defined by + * setHeaderRows(). + * @return the height of the rows that constitute the header and footer + */ + public float HeaderHeight { + get { + float total = 0; + int size = Math.Min(rows.Count, headerRows); + for (int k = 0; k < size; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) + total += row.MaxHeights; + } + return total; + } + } + + /** Gets the height of the rows that constitute the header as defined by + * setFooterRows(). + * @return the height of the rows that constitute the footer + * @since 2.1.1 + */ + public float FooterHeight { + get { + float total = 0; + int start = Math.Min(0, headerRows - footerRows); + int size = Math.Min(rows.Count, footerRows); + for (int k = start; k < size; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) + total += row.MaxHeights; + } + return total; + } + } + + /** Deletes a row from the table. + * @param rowNumber the row to be deleted + * @return true if the row was deleted + */ + public bool DeleteRow(int rowNumber) { + if (rowNumber < 0 || rowNumber >= rows.Count) { + return false; + } + if (totalWidth > 0) { + PdfPRow row = (PdfPRow)rows[rowNumber]; + if (row != null) + totalHeight -= row.MaxHeights; + } + rows.RemoveAt(rowNumber); + return true; + } + + /** Deletes the last row in the table. + * @return true if the last row was deleted + */ + public bool DeleteLastRow() { + return DeleteRow(rows.Count - 1); + } + + /** + * Removes all of the rows except headers + */ + public void DeleteBodyRows() { + ArrayList rows2 = new ArrayList(); + for (int k = 0; k < headerRows; ++k) + rows2.Add(rows[k]); + rows = rows2; + totalHeight = 0; + if (totalWidth > 0) + totalHeight = HeaderHeight; + } + + /** Returns the number of columns. + * @return the number of columns. + * @since 2.1.1 + */ + public int NumberOfColumns { + get { + return relativeWidths.Length; + } + } + public int HeaderRows { + get { + return headerRows; + } + set { + headerRows = value; + if (headerRows < 0) + headerRows = 0; + } + } + + public int FooterRows { + get { + return footerRows; + } + set { + footerRows = value; + if (footerRows < 0) + footerRows = 0; + } + } + + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + public ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * Gets the type of the text element. + * + * @return a type + */ + public int Type { + get { + return Element.PTABLE; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + public float WidthPercentage { + get { + return widthPercentage; + } + set { + widthPercentage = value; + } + } + + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + set { + horizontalAlignment = value; + } + } + + /** + * Gets a row with a given index + * (added by Jin-Hsia Yang). + * @param idx + * @return the row at position idx + */ + public PdfPRow GetRow(int idx) { + return (PdfPRow)rows[idx]; + } + + /** + * Gets an arraylist with all the rows in the table. + * @return an arraylist + */ + public ArrayList Rows { + get { + return rows; + } + } + + public IPdfPTableEvent TableEvent { + get { + return tableEvent; + } + set { + if (value == null) this.tableEvent = null; + else if (this.tableEvent == null) this.tableEvent = value; + else if (this.tableEvent is PdfPTableEventForwarder) ((PdfPTableEventForwarder)this.tableEvent).AddTableEvent(value); + else { + PdfPTableEventForwarder forward = new PdfPTableEventForwarder(); + forward.AddTableEvent(this.tableEvent); + forward.AddTableEvent(value); + this.tableEvent = forward; + } + } + } + + /** Gets the absolute sizes of each column width. + * @return he absolute sizes of each column width + */ + public float[] AbsoluteWidths { + get { + return absoluteWidths; + } + } + + internal float [][] GetEventWidths(float xPos, int firstRow, int lastRow, bool includeHeaders) { + if (includeHeaders) { + firstRow = Math.Max(firstRow, headerRows); + lastRow = Math.Max(lastRow, headerRows); + } + float[][] widths = new float[(includeHeaders ? headerRows : 0) + lastRow - firstRow][]; + if (isColspan) { + int n = 0; + if (includeHeaders) { + for (int k = 0; k < headerRows; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row == null) + ++n; + else + widths[n++] = row.GetEventWidth(xPos); + } + } + for (; firstRow < lastRow; ++firstRow) { + PdfPRow row = (PdfPRow)rows[firstRow]; + if (row == null) + ++n; + else + widths[n++] = row.GetEventWidth(xPos); + } + } + else { + float[] width = new float[absoluteWidths.Length + 1]; + width[0] = xPos; + for (int k = 0; k < absoluteWidths.Length; ++k) + width[k + 1] = width[k] + absoluteWidths[k]; + for (int k = 0; k < widths.Length; ++k) + widths[k] = width; + } + return widths; + } + + public bool SkipFirstHeader { + get { + return skipFirstHeader; + } + set { + skipFirstHeader = value; + } + } + + public int RunDirection { + get { + return runDirection; + } + set { + if (value < PdfWriter.RUN_DIRECTION_DEFAULT || value > PdfWriter.RUN_DIRECTION_RTL) + throw new ArgumentException("Invalid run direction: " + value); + runDirection = value; + } + } + + public bool LockedWidth { + get { + return lockedWidth; + } + set { + lockedWidth = value; + } + } + + public bool SplitRows { + get { + return splitRows; + } + set { + splitRows = value; + } + } + + public float SpacingBefore { + get { + return spacingBefore; + } + set { + spacingBefore = value; + } + } + + public float SpacingAfter { + get { + return spacingAfter; + } + set { + spacingAfter = value; + } + } + + public bool ExtendLastRow { + get { + return extendLastRow; + } + set { + extendLastRow = value; + } + } + + public bool HeadersInEvent { + get { + return headersInEvent; + } + set { + headersInEvent = value; + } + } + public bool SplitLate { + get { + return splitLate; + } + set { + splitLate = value; + } + } + + /** + * If true the table will be kept on one page if it fits, by forcing a + * new page if it doesn't fit on the current page. The default is to + * split the table over multiple pages. + * + * @param p_KeepTogether whether to try to keep the table on one page + */ + public bool KeepTogether { + set { + keepTogether = value; + } + get { + return keepTogether; + } + } + + /** + * Completes the current row with the default cell. An incomplete row will be dropped + * but calling this method will make sure that it will be present in the table. + */ + public void CompleteRow() { + while (currentRowIdx > 0) { + AddCell(defaultCell); + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#flushContent() + */ + public void FlushContent() { + DeleteBodyRows(); + SkipFirstHeader = true; + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#isComplete() + */ + public bool ElementComplete { + get { + return complete; + } + set { + complete = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPage.cs b/iTechSharp/iTextSharp/text/pdf/PdfPage.cs new file mode 100644 index 0000000..a32fd29 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPage.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfPage.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfPage is the PDF Page-object. + *

+ * A Page object is a dictionary whose keys describe a single page containing text, + * graphics, and images. A Page onjects is a leaf of the Pages tree.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.4 (page 73-81) + * + * @see PdfPageElement + * @see PdfPages + */ + + public class PdfPage : PdfDictionary { + + // membervariables + private static String[] boxStrings = {"crop", "trim", "art", "bleed"}; + private static PdfName[] boxNames = {PdfName.CROPBOX, PdfName.TRIMBOX, PdfName.ARTBOX, PdfName.BLEEDBOX}; + + /** value of the Rotate key for a page in PORTRAIT */ + public static PdfNumber PORTRAIT = new PdfNumber(0); + + /** value of the Rotate key for a page in LANDSCAPE */ + public static PdfNumber LANDSCAPE = new PdfNumber(90); + + /** value of the Rotate key for a page in INVERTEDPORTRAIT */ + public static PdfNumber INVERTEDPORTRAIT = new PdfNumber(180); + + /** value of the Rotate key for a page in SEASCAPE */ + public static PdfNumber SEASCAPE = new PdfNumber(270); + + /** value of the MediaBox key */ + PdfRectangle mediaBox; + + // constructors + + /** + * Constructs a PdfPage. + * + * @param mediaBox a value for the MediaBox key + * @param resources an indirect reference to a PdfResources-object + * @param rotate a value for the Rotate key + */ + + internal PdfPage(PdfRectangle mediaBox, Hashtable boxSize, PdfDictionary resources, int rotate) : base(PAGE) { + this.mediaBox = mediaBox; + Put(PdfName.MEDIABOX, mediaBox); + Put(PdfName.RESOURCES, resources); + if (rotate != 0) { + Put(PdfName.ROTATE, new PdfNumber(rotate)); + } + for (int k = 0; k < boxStrings.Length; ++k) { + PdfObject rect = (PdfObject)boxSize[boxStrings[k]]; + if (rect != null) + Put(boxNames[k], rect); + } + } + + /** + * Constructs a PdfPage. + * + * @param mediaBox a value for the MediaBox key + * @param resources an indirect reference to a PdfResources-object + */ + + internal PdfPage(PdfRectangle mediaBox, Hashtable boxSize, PdfDictionary resources) : this(mediaBox, boxSize, resources, 0) { + } + + /** + * Checks if this page element is a tree of pages. + *

+ * This method allways returns false. + * + * @return false because this is a single page + */ + + public bool IsParent() { + return false; + } + + // methods + + /** + * Adds an indirect reference pointing to a PdfContents-object. + * + * @param contents an indirect reference to a PdfContents-object + */ + + internal void Add(PdfIndirectReference contents) { + Put(PdfName.CONTENTS, contents); + } + + /** + * Rotates the mediabox, but not the text in it. + * + * @return a PdfRectangle + */ + + internal PdfRectangle RotateMediaBox() { + this.mediaBox = mediaBox.Rotate; + Put(PdfName.MEDIABOX, this.mediaBox); + return this.mediaBox; + } + + /** + * Returns the MediaBox of this Page. + * + * @return a PdfRectangle + */ + + internal PdfRectangle MediaBox { + get { + return mediaBox; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs b/iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs new file mode 100644 index 0000000..28afb85 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs @@ -0,0 +1,202 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfPageEventHelper.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Helps the use of PdfPageEvent by implementing all the interface methods. + * A class can extend PdfPageEventHelper and only implement the + * needed methods. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class PdfPageEventHelper : IPdfPageEvent { + + /** + * Called when the document is opened. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnOpenDocument(PdfWriter writer,Document document) { + } + + /** + * Called when a page is initialized. + *

+ * Note that if even if a page is not written this method is still + * called. It is preferable to use onEndPage to avoid + * infinite loops. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnStartPage(PdfWriter writer,Document document) { + } + + /** + * Called when a page is finished, just before being written to the document. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnEndPage(PdfWriter writer,Document document) { + } + + /** + * Called when the document is closed. + *

+ * Note that this method is called with the page number equal + * to the last page plus one. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnCloseDocument(PdfWriter writer,Document document) { + } + + /** + * Called when a Paragraph is written. + *

+ * paragraphPosition will hold the height at which the + * paragraph will be written to. This is useful to insert bookmarks with + * more control. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the paragraph will be written to + */ + public virtual void OnParagraph(PdfWriter writer,Document document,float paragraphPosition) { + } + + /** + * Called when a Paragraph is written. + *

+ * paragraphPosition will hold the height of the end of the paragraph. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position of the end of the paragraph + */ + public virtual void OnParagraphEnd(PdfWriter writer,Document document,float paragraphPosition) { + } + + /** + * Called when a Chapter is written. + *

+ * position will hold the height at which the + * chapter will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + public virtual void OnChapter(PdfWriter writer,Document document,float paragraphPosition,Paragraph title) { + } + + /** + * Called when the end of a Chapter is reached. + *

+ * position will hold the height of the end of the chapter. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param position the position of the end of the chapter. + */ + public virtual void OnChapterEnd(PdfWriter writer,Document document,float position) { + } + + /** + * Called when a Section is written. + *

+ * position will hold the height at which the + * section will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + public virtual void OnSection(PdfWriter writer,Document document,float paragraphPosition,int depth,Paragraph title) { + } + + /** + * Called when the end of a Section is reached. + *

+ * position will hold the height of the section end. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param position the position of the end of the section + */ + public virtual void OnSectionEnd(PdfWriter writer,Document document,float position) { + } + + /** + * Called when a Chunk with a generic tag is written. + *

+ * It is usefull to pinpoint the Chunk location to generate + * bookmarks, for example. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param rect the Rectangle containing the Chunk + * @param text the text of the tag + */ + public virtual void OnGenericTag(PdfWriter writer,Document document,Rectangle rect,string text) { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs b/iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs new file mode 100644 index 0000000..e8c76b7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.factories; + +/* + * $Id: PdfPageLabels.cs,v 1.9 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Page labels are used to identify each + * page visually on the screen or in print. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfPageLabels { + + /** Logical pages will have the form 1,2,3,... + */ + public const int DECIMAL_ARABIC_NUMERALS = 0; + /** Logical pages will have the form I,II,III,IV,... + */ + public const int UPPERCASE_ROMAN_NUMERALS = 1; + /** Logical pages will have the form i,ii,iii,iv,... + */ + public const int LOWERCASE_ROMAN_NUMERALS = 2; + /** Logical pages will have the form of uppercase letters + * (A to Z for the first 26 pages, AA to ZZ for the next 26, and so on) + */ + public const int UPPERCASE_LETTERS = 3; + /** Logical pages will have the form of uppercase letters + * (a to z for the first 26 pages, aa to zz for the next 26, and so on) + */ + public const int LOWERCASE_LETTERS = 4; + /** No logical page numbers are generated but fixed text may + * still exist + */ + public const int EMPTY = 5; + /** Dictionary values to set the logical page styles + */ + internal static PdfName[] numberingStyle = {PdfName.D, PdfName.R, + new PdfName("r"), PdfName.A, new PdfName("a")}; + /** The sequence of logical pages. Will contain at least a value for page 1 + */ + internal Hashtable map; + + /** Creates a new PdfPageLabel with a default logical page 1 + */ + public PdfPageLabels() { + map = new Hashtable(); + AddPageLabel(1, DECIMAL_ARABIC_NUMERALS, null, 1); + } + + /** Adds or replaces a page label. + * @param page the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + * @param text the text to prefix the number. Can be null or empty + * @param firstPage the first logical page number + */ + public void AddPageLabel(int page, int numberStyle, string text, int firstPage) { + if (page < 1 || firstPage < 1) + throw new ArgumentException("In a page label the page numbers must be greater or equal to 1."); + PdfDictionary dic = new PdfDictionary(); + if (numberStyle >= 0 && numberStyle < numberingStyle.Length) + dic.Put(PdfName.S, numberingStyle[numberStyle]); + if (text != null) + dic.Put(PdfName.P, new PdfString(text, PdfObject.TEXT_UNICODE)); + if (firstPage != 1) + dic.Put(PdfName.ST, new PdfNumber(firstPage)); + map[page - 1] = dic; + } + + /** Adds or replaces a page label. The first logical page has the default + * of 1. + * @param page the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + * @param text the text to prefix the number. Can be null or empty + */ + public void AddPageLabel(int page, int numberStyle, string text) { + AddPageLabel(page, numberStyle, text, 1); + } + + /** Adds or replaces a page label. There is no text prefix and the first + * logical page has the default of 1. + * @param page the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + */ + public void AddPageLabel(int page, int numberStyle) { + AddPageLabel(page, numberStyle, null, 1); + } + + /** Adds or replaces a page label. + */ + public void AddPageLabel(PdfPageLabelFormat format) { + AddPageLabel(format.physicalPage, format.numberStyle, format.prefix, format.logicalPage); + } + + /** Removes a page label. The first page lagel can not be removed, only changed. + * @param page the real page to remove + */ + public void RemovePageLabel(int page) { + if (page <= 1) + return; + map.Remove(page - 1); + } + + /** Gets the page label dictionary to insert into the document. + * @return the page label dictionary + */ + internal PdfDictionary GetDictionary(PdfWriter writer) { + return PdfNumberTree.WriteTree(map, writer); + } + + /** + * Retrieves the page labels from a PDF as an array of String objects. + * @param reader a PdfReader object that has the page labels you want to retrieve + * @return a String array or null if no page labels are present + */ + public static String[] GetPageLabels(PdfReader reader) { + + int n = reader.NumberOfPages; + + PdfDictionary dict = reader.Catalog; + PdfDictionary labels = (PdfDictionary)PdfReader.GetPdfObjectRelease(dict.Get(PdfName.PAGELABELS)); + if (labels == null) + return null; + + String[] labelstrings = new String[n]; + Hashtable numberTree = PdfNumberTree.ReadTree(labels); + + int pagecount = 1; + String prefix = ""; + char type = 'D'; + for (int i = 0; i < n; i++) { + if (numberTree.ContainsKey(i)) { + PdfDictionary d = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)numberTree[i]); + if (d.Contains(PdfName.ST)) { + pagecount = ((PdfNumber)d.Get(PdfName.ST)).IntValue; + } + else { + pagecount = 1; + } + if (d.Contains(PdfName.P)) { + prefix = ((PdfString)d.Get(PdfName.P)).ToUnicodeString(); + } + if (d.Contains(PdfName.S)) { + type = ((PdfName)d.Get(PdfName.S)).ToString()[1]; + } + } + switch (type) { + default: + labelstrings[i] = prefix + pagecount; + break; + case 'R': + labelstrings[i] = prefix + RomanNumberFactory.GetUpperCaseString(pagecount); + break; + case 'r': + labelstrings[i] = prefix + RomanNumberFactory.GetLowerCaseString(pagecount); + break; + case 'A': + labelstrings[i] = prefix + RomanAlphabetFactory.GetUpperCaseString(pagecount); + break; + case 'a': + labelstrings[i] = prefix + RomanAlphabetFactory.GetLowerCaseString(pagecount); + break; + } + pagecount++; + } + return labelstrings; + } + + /** + * Retrieves the page labels from a PDF as an array of {@link PdfPageLabelFormat} objects. + * @param reader a PdfReader object that has the page labels you want to retrieve + * @return a PdfPageLabelEntry array, containing an entry for each format change + * or null if no page labels are present + */ + public static PdfPageLabelFormat[] GetPageLabelFormats(PdfReader reader) { + PdfDictionary dict = reader.Catalog; + PdfDictionary labels = (PdfDictionary)PdfReader.GetPdfObjectRelease(dict.Get(PdfName.PAGELABELS)); + if (labels == null) + return null; + Hashtable numberTree = PdfNumberTree.ReadTree(labels); + int[] numbers = new int[numberTree.Count]; + numberTree.Keys.CopyTo(numbers, 0); + Array.Sort(numbers); + PdfPageLabelFormat[] formats = new PdfPageLabelFormat[numberTree.Count]; + String prefix; + int numberStyle; + int pagecount; + for (int k = 0; k < numbers.Length; ++k) { + int key = numbers[k]; + PdfDictionary d = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)numberTree[key]); + if (d.Contains(PdfName.ST)) { + pagecount = ((PdfNumber)d.Get(PdfName.ST)).IntValue; + } else { + pagecount = 1; + } + if (d.Contains(PdfName.P)) { + prefix = ((PdfString)d.Get(PdfName.P)).ToUnicodeString(); + } else { + prefix = ""; + } + if (d.Contains(PdfName.S)) { + char type = ((PdfName)d.Get(PdfName.S)).ToString()[1]; + switch (type) { + case 'R': numberStyle = UPPERCASE_ROMAN_NUMERALS; break; + case 'r': numberStyle = LOWERCASE_ROMAN_NUMERALS; break; + case 'A': numberStyle = UPPERCASE_LETTERS; break; + case 'a': numberStyle = LOWERCASE_LETTERS; break; + default: numberStyle = DECIMAL_ARABIC_NUMERALS; break; + } + } else { + numberStyle = EMPTY; + } + formats[k] = new PdfPageLabelFormat(key + 1, numberStyle, prefix, pagecount); + } + return formats; + } + + public class PdfPageLabelFormat { + + public int physicalPage; + public int numberStyle; + public String prefix; + public int logicalPage; + + /** Creates a page label format. + * @param physicalPage the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + * @param prefix the text to prefix the number. Can be null or empty + * @param logicalPage the first logical page number + */ + public PdfPageLabelFormat(int physicalPage, int numberStyle, String prefix, int logicalPage) { + this.physicalPage = physicalPage; + this.numberStyle = numberStyle; + this.prefix = prefix; + this.logicalPage = logicalPage; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPages.cs b/iTechSharp/iTextSharp/text/pdf/PdfPages.cs new file mode 100644 index 0000000..2634da6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPages.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections; +using System.IO; +/* + * $Id: PdfPages.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfPages is the PDF Pages-object. + *

+ * The Pages of a document are accessible through a tree of nodes known as the Pages tree. + * This tree defines the ordering of the pages in the document.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.3 (page 71-73) + * + * @see PdfPageElement + * @see PdfPage + */ + + public class PdfPages { + + private ArrayList pages = new ArrayList(); + private ArrayList parents = new ArrayList(); + private int leafSize = 10; + private PdfWriter writer; + private PdfIndirectReference topParent; + + // constructors + + /** + * Constructs a PdfPages-object. + */ + + internal PdfPages(PdfWriter writer) { + this.writer = writer; + } + + internal void AddPage(PdfDictionary page) { + if ((pages.Count % leafSize) == 0) + parents.Add(writer.PdfIndirectReference); + PdfIndirectReference parent = (PdfIndirectReference)parents[parents.Count - 1]; + page.Put(PdfName.PARENT, parent); + PdfIndirectReference current = writer.CurrentPage; + writer.AddToBody(page, current); + pages.Add(current); + } + + internal PdfIndirectReference AddPageRef(PdfIndirectReference pageRef) { + if ((pages.Count % leafSize) == 0) + parents.Add(writer.PdfIndirectReference); + pages.Add(pageRef); + return (PdfIndirectReference)parents[parents.Count - 1]; + } + + // returns the top parent to include in the catalog + internal PdfIndirectReference WritePageTree() { + if (pages.Count == 0) + throw new IOException("The document has no pages."); + int leaf = 1; + ArrayList tParents = parents; + ArrayList tPages = pages; + ArrayList nextParents = new ArrayList(); + while (true) { + leaf *= leafSize; + int stdCount = leafSize; + int rightCount = tPages.Count % leafSize; + if (rightCount == 0) + rightCount = leafSize; + for (int p = 0; p < tParents.Count; ++p) { + int count; + int thisLeaf = leaf; + if (p == tParents.Count - 1) { + count = rightCount; + thisLeaf = pages.Count % leaf; + if (thisLeaf == 0) + thisLeaf = leaf; + } + else + count = stdCount; + PdfDictionary top = new PdfDictionary(PdfName.PAGES); + top.Put(PdfName.COUNT, new PdfNumber(thisLeaf)); + PdfArray kids = new PdfArray(); + ArrayList intern = kids.ArrayList; + intern.AddRange(tPages.GetRange(p * stdCount, count)); + top.Put(PdfName.KIDS, kids); + if (tParents.Count > 1) { + if ((p % leafSize) == 0) + nextParents.Add(writer.PdfIndirectReference); + top.Put(PdfName.PARENT, (PdfIndirectReference)nextParents[p / leafSize]); + } + writer.AddToBody(top, (PdfIndirectReference)tParents[p]); + } + if (tParents.Count == 1) { + topParent = (PdfIndirectReference)tParents[0]; + return topParent; + } + tPages = tParents; + tParents = nextParents; + nextParents = new ArrayList(); + } + } + + internal PdfIndirectReference TopParent { + get { + return topParent; + } + } + + internal void SetLinearMode(PdfIndirectReference topParent) { + if (parents.Count > 1) + throw new Exception("Linear page mode can only be called with a single parent."); + if (topParent != null) { + this.topParent = topParent; + parents.Clear(); + parents.Add(topParent); + } + leafSize = 10000000; + } + + internal void AddPage(PdfIndirectReference page) { + pages.Add(page); + } + + internal int ReorderPages(int[] order) { + if (order == null) + return pages.Count; + if (parents.Count > 1) + throw new DocumentException("Page reordering requires a single parent in the page tree. Call PdfWriter.SetLinearMode() after open."); + if (order.Length != pages.Count) + throw new DocumentException("Page reordering requires an array with the same size as the number of pages."); + int max = pages.Count; + bool[] temp = new bool[max]; + for (int k = 0; k < max; ++k) { + int p = order[k]; + if (p < 1 || p > max) + throw new DocumentException("Page reordering requires pages between 1 and " + max + ". Found " + p + "."); + if (temp[p - 1]) + throw new DocumentException("Page reordering requires no page repetition. Page " + p + " is repeated."); + temp[p - 1] = true; + } + Object[] copy = pages.ToArray(); + for (int k = 0; k < max; ++k) { + pages[k] = copy[order[k] - 1]; + } + return max; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPattern.cs b/iTechSharp/iTextSharp/text/pdf/PdfPattern.cs new file mode 100644 index 0000000..1f1917d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPattern.cs @@ -0,0 +1,79 @@ +using System; +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfPattern defines a ColorSpace + * + * @see PdfStream + */ + + public class PdfPattern : PdfStream { + + internal PdfPattern(PdfPatternPainter painter) : base() { + PdfNumber one = new PdfNumber(1); + PdfArray matrix = painter.Matrix; + if ( matrix != null ) { + Put(PdfName.MATRIX, matrix); + } + Put(PdfName.TYPE, PdfName.PATTERN); + Put(PdfName.BBOX, new PdfRectangle(painter.BoundingBox)); + Put(PdfName.RESOURCES, painter.Resources); + Put(PdfName.TILINGTYPE, one); + Put(PdfName.PATTERNTYPE, one); + if (painter.IsStencil()) + Put(PdfName.PAINTTYPE, new PdfNumber(2)); + else + Put(PdfName.PAINTTYPE, one); + Put(PdfName.XSTEP, new PdfNumber(painter.XStep)); + Put(PdfName.YSTEP, new PdfNumber(painter.YStep)); + bytes = painter.ToPdf(null); + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + FlateCompress(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs b/iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs new file mode 100644 index 0000000..6172575 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs @@ -0,0 +1,360 @@ +using System; +using iTextSharp.text; +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Implements the pattern. + */ + + public sealed class PdfPatternPainter : PdfTemplate { + + internal float xstep, ystep; + internal bool stencil = false; + internal Color defaultColor; + + /** + *Creates a PdfPattern. + */ + + private PdfPatternPainter() : base() { + type = TYPE_PATTERN; + } + + /** + * Creates new PdfPattern + * + * @param wr the PdfWriter + */ + + internal PdfPatternPainter(PdfWriter wr) : base(wr) { + type = TYPE_PATTERN; + } + + internal PdfPatternPainter(PdfWriter wr, Color defaultColor) : this(wr) { + stencil = true; + if (defaultColor == null) + this.defaultColor = new Color(System.Drawing.Color.Gray); + else + this.defaultColor = defaultColor; + } + + public float XStep { + get { + return this.xstep; + } + + set { + this.xstep = value; + } + } + + public float YStep { + get { + return this.ystep; + } + + set { + this.ystep = value; + } + } + + public bool IsStencil() { + return stencil; + } + + public void SetPatternMatrix(float a, float b, float c, float d, float e, float f) { + SetMatrix(a, b, c, d, e, f); + } + /** + * Gets the stream representing this pattern + * + * @return the stream representing this pattern + */ + + internal PdfPattern Pattern { + get { + return new PdfPattern(this); + } + } + + /** + * Gets a duplicate of this PdfPatternPainter. All + * the members are copied by reference but the buffer stays different. + * @return a copy of this PdfPatternPainter + */ + + public override PdfContentByte Duplicate { + get { + PdfPatternPainter tpl = new PdfPatternPainter(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.bBox = new Rectangle(bBox); + tpl.xstep = xstep; + tpl.ystep = ystep; + tpl.matrix = matrix; + tpl.stencil = stencil; + tpl.defaultColor = defaultColor; + return tpl; + } + } + + public Color DefaultColor { + get { + return defaultColor; + } + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setGrayFill(float) + */ + public override void SetGrayFill(float gray) { + CheckNoColor(); + base.SetGrayFill(gray); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetGrayFill() + */ + public override void ResetGrayFill() { + CheckNoColor(); + base.ResetGrayFill(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setGrayStroke(float) + */ + public override void SetGrayStroke(float gray) { + CheckNoColor(); + base.SetGrayStroke(gray); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetGrayStroke() + */ + public override void ResetGrayStroke() { + CheckNoColor(); + base.ResetGrayStroke(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorFillF(float, float, float) + */ + public override void SetRGBColorFillF(float red, float green, float blue) { + CheckNoColor(); + base.SetRGBColorFillF(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetRGBColorFill() + */ + public override void ResetRGBColorFill() { + CheckNoColor(); + base.ResetRGBColorFill(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorStrokeF(float, float, float) + */ + public override void SetRGBColorStrokeF(float red, float green, float blue) { + CheckNoColor(); + base.SetRGBColorStrokeF(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetRGBColorStroke() + */ + public override void ResetRGBColorStroke() { + CheckNoColor(); + base.ResetRGBColorStroke(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorFillF(float, float, float, float) + */ + public override void SetCMYKColorFillF(float cyan, float magenta, float yellow, float black) { + CheckNoColor(); + base.SetCMYKColorFillF(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetCMYKColorFill() + */ + public override void ResetCMYKColorFill() { + CheckNoColor(); + base.ResetCMYKColorFill(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorStrokeF(float, float, float, float) + */ + public override void SetCMYKColorStrokeF(float cyan, float magenta, float yellow, float black) { + CheckNoColor(); + base.SetCMYKColorStrokeF(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetCMYKColorStroke() + */ + public override void ResetCMYKColorStroke() { + CheckNoColor(); + base.ResetCMYKColorStroke(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#addImage(com.lowagie.text.Image, float, float, float, float, float, float) + */ + public override void AddImage(Image image, float a, float b, float c, float d, float e, float f) { + if (stencil && !image.IsMask()) + CheckNoColor(); + base.AddImage(image, a, b, c, d, e, f); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorFill(int, int, int, int) + */ + public override void SetCMYKColorFill(int cyan, int magenta, int yellow, int black) { + CheckNoColor(); + base.SetCMYKColorFill(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorStroke(int, int, int, int) + */ + public override void SetCMYKColorStroke(int cyan, int magenta, int yellow, int black) { + CheckNoColor(); + base.SetCMYKColorStroke(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorFill(int, int, int) + */ + public override void SetRGBColorFill(int red, int green, int blue) { + CheckNoColor(); + base.SetRGBColorFill(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorStroke(int, int, int) + */ + public override void SetRGBColorStroke(int red, int green, int blue) { + CheckNoColor(); + base.SetRGBColorStroke(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorStroke(java.awt.Color) + */ + public override void SetColorStroke(Color color) { + CheckNoColor(); + base.SetColorStroke(color); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorFill(java.awt.Color) + */ + public override void SetColorFill(Color color) { + CheckNoColor(); + base.SetColorFill(color); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorFill(com.lowagie.text.pdf.PdfSpotColor, float) + */ + public override void SetColorFill(PdfSpotColor sp, float tint) { + CheckNoColor(); + base.SetColorFill(sp, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorStroke(com.lowagie.text.pdf.PdfSpotColor, float) + */ + public override void SetColorStroke(PdfSpotColor sp, float tint) { + CheckNoColor(); + base.SetColorStroke(sp, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternFill(com.lowagie.text.pdf.PdfPatternPainter) + */ + public override void SetPatternFill(PdfPatternPainter p) { + CheckNoColor(); + base.SetPatternFill(p); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternFill(com.lowagie.text.pdf.PdfPatternPainter, java.awt.Color, float) + */ + public override void SetPatternFill(PdfPatternPainter p, Color color, float tint) { + CheckNoColor(); + base.SetPatternFill(p, color, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternStroke(com.lowagie.text.pdf.PdfPatternPainter, java.awt.Color, float) + */ + public override void SetPatternStroke(PdfPatternPainter p, Color color, float tint) { + CheckNoColor(); + base.SetPatternStroke(p, color, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternStroke(com.lowagie.text.pdf.PdfPatternPainter) + */ + public override void SetPatternStroke(PdfPatternPainter p) { + CheckNoColor(); + base.SetPatternStroke(p); + } + + internal void CheckNoColor() { + if (stencil) + throw new ArgumentException("Colors are not allowed in uncolored tile patterns."); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs new file mode 100644 index 0000000..5febe94 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs @@ -0,0 +1,41 @@ +using System; +using Org.BouncyCastle.X509; + + +namespace iTextSharp.text.pdf { + + public class PdfPublicKeyRecipient { + + private X509Certificate certificate = null; + + private int permission = 0; + + protected byte[] cms = null; + + public PdfPublicKeyRecipient(X509Certificate certificate, int permission) { + this.certificate = certificate; + this.permission = permission; + } + + public X509Certificate Certificate { + get { + return certificate; + } + } + + public int Permission { + get { + return permission; + } + } + + protected internal byte[] Cms { + set { + cms = value; + } + get { + return cms; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs new file mode 100644 index 0000000..3cbcb98 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs @@ -0,0 +1,197 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.pdf.crypto; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security; + + +/** + * The below 2 methods are from pdfbox. + * + * private DERObject CreateDERForRecipient(byte[] in, X509Certificate cert) ; + * private KeyTransRecipientInfo ComputeRecipientInfo(X509Certificate x509certificate, byte[] abyte0); + * + * 2006-11-22 Aiken Sam. + */ + +/** + * Copyright (c) 2003-2006, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ + +namespace iTextSharp.text.pdf { + + /** + * @author Aiken Sam (aikensam@ieee.org) + */ + public class PdfPublicKeySecurityHandler { + + private const int SEED_LENGTH = 20; + + private ArrayList recipients = null; + + private byte[] seed; + + public PdfPublicKeySecurityHandler() { + seed = IVGenerator.GetIV(SEED_LENGTH); + recipients = new ArrayList(); + } + + + public void AddRecipient(PdfPublicKeyRecipient recipient) { + recipients.Add(recipient); + } + + protected internal byte[] GetSeed() { + return (byte[])seed.Clone(); + } + + public int GetRecipientsSize() { + return recipients.Count; + } + + public byte[] GetEncodedRecipient(int index) { + //Certificate certificate = recipient.GetX509(); + PdfPublicKeyRecipient recipient = (PdfPublicKeyRecipient)recipients[index]; + byte[] cms = recipient.Cms; + + if (cms != null) return cms; + + X509Certificate certificate = recipient.Certificate; + int permission = recipient.Permission;//PdfWriter.AllowCopy | PdfWriter.AllowPrinting | PdfWriter.AllowScreenReaders | PdfWriter.AllowAssembly; + int revision = 3; + + permission |= (int)(revision==3 ? (uint)0xfffff0c0 : (uint)0xffffffc0); + permission &= unchecked((int)0xfffffffc); + permission += 1; + + byte[] pkcs7input = new byte[24]; + + byte one = (byte)(permission); + byte two = (byte)(permission >> 8); + byte three = (byte)(permission >> 16); + byte four = (byte)(permission >> 24); + + System.Array.Copy(seed, 0, pkcs7input, 0, 20); // put this seed in the pkcs7 input + + pkcs7input[20] = four; + pkcs7input[21] = three; + pkcs7input[22] = two; + pkcs7input[23] = one; + + Asn1Object obj = CreateDERForRecipient(pkcs7input, certificate); + + MemoryStream baos = new MemoryStream(); + + DerOutputStream k = new DerOutputStream(baos); + + k.WriteObject(obj); + + cms = baos.ToArray(); + + recipient.Cms = cms; + + return cms; + } + + public PdfArray GetEncodedRecipients() { + PdfArray EncodedRecipients = new PdfArray(); + byte[] cms = null; + for (int i=0; i -1, 0 + // type 1 -> offset, 0 + // type 2 -> index, obj num + protected internal int[] xref; + protected internal Hashtable objStmMark; + protected internal IntHashtable objStmToOffset; + protected internal bool newXrefType; + private ArrayList xrefObj; + PdfDictionary rootPages; + protected internal PdfDictionary trailer; + protected internal PdfDictionary catalog; + protected internal PageRefs pageRefs; + protected internal PRAcroForm acroForm = null; + protected internal bool acroFormParsed = false; + protected internal bool encrypted = false; + protected internal bool rebuilt = false; + protected internal int freeXref; + protected internal bool tampered = false; + protected internal int lastXref; + protected internal int eofPos; + protected internal char pdfVersion; + protected internal PdfEncryption decrypt; + protected internal byte[] password = null; //added by ujihara for decryption + protected ICipherParameters certificateKey = null; //added by Aiken Sam for certificate decryption + protected X509Certificate certificate = null; //added by Aiken Sam for certificate decryption + private bool ownerPasswordUsed; + protected internal ArrayList strings = new ArrayList(); + protected internal bool sharedStreams = true; + protected internal bool consolidateNamedDestinations = false; + protected internal int rValue; + protected internal int pValue; + private int objNum; + private int objGen; + private int fileLength; + private bool hybridXref; + private int lastXrefPartial = -1; + private bool partial; + private PRIndirectReference cryptoRef; + private PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); + private bool encryptionError; + + /** + * Holds value of property appendable. + */ + private bool appendable; + + protected internal PdfReader() { + } + + /** Reads and parses a PDF document. + * @param filename the file name of the document + * @throws IOException on error + */ + public PdfReader(String filename) : this(filename, null) { + } + + /** Reads and parses a PDF document. + * @param filename the file name of the document + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(String filename, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(filename); + ReadPdf(); + } + + /** Reads and parses a PDF document. + * @param pdfIn the byte array with the document + * @throws IOException on error + */ + public PdfReader(byte[] pdfIn) : this(pdfIn, null) { + } + + /** Reads and parses a PDF document. + * @param pdfIn the byte array with the document + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(byte[] pdfIn, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(pdfIn); + ReadPdf(); + } + + /** Reads and parses a PDF document. + * @param filename the file name of the document + * @param certificate the certificate to read the document + * @param certificateKey the private key of the certificate + * @param certificateKeyProvider the security provider for certificateKey + * @throws IOException on error + */ + public PdfReader(String filename, X509Certificate certificate, ICipherParameters certificateKey) { + this.certificate = certificate; + this.certificateKey = certificateKey; + tokens = new PRTokeniser(filename); + ReadPdf(); + } + + /** Reads and parses a PDF document. + * @param url the Uri of the document + * @throws IOException on error + */ + public PdfReader(Uri url) : this(url, null) { + } + + /** Reads and parses a PDF document. + * @param url the Uri of the document + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(Uri url, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(new RandomAccessFileOrArray(url)); + ReadPdf(); + } + + /** + * Reads and parses a PDF document. + * @param is the InputStream containing the document. The stream is read to the + * end but is not closed + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(Stream isp, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(new RandomAccessFileOrArray(isp)); + ReadPdf(); + } + + /** + * Reads and parses a PDF document. + * @param isp the InputStream containing the document. The stream is read to the + * end but is not closed + * @throws IOException on error + */ + public PdfReader(Stream isp) : this(isp, null) { + } + + /** + * Reads and parses a pdf document. Contrary to the other constructors only the xref is read + * into memory. The reader is said to be working in "partial" mode as only parts of the pdf + * are read as needed. The pdf is left open but may be closed at any time with + * PdfReader.Close(), reopen is automatic. + * @param raf the document location + * @param ownerPassword the password or null for no password + * @throws IOException on error + */ + public PdfReader(RandomAccessFileOrArray raf, byte[] ownerPassword) { + password = ownerPassword; + partial = true; + tokens = new PRTokeniser(raf); + ReadPdfPartial(); + } + + /** Creates an independent duplicate. + * @param reader the PdfReader to duplicate + */ + public PdfReader(PdfReader reader) { + this.appendable = reader.appendable; + this.consolidateNamedDestinations = reader.consolidateNamedDestinations; + this.encrypted = reader.encrypted; + this.rebuilt = reader.rebuilt; + this.sharedStreams = reader.sharedStreams; + this.tampered = reader.tampered; + this.password = reader.password; + this.pdfVersion = reader.pdfVersion; + this.eofPos = reader.eofPos; + this.freeXref = reader.freeXref; + this.lastXref = reader.lastXref; + this.tokens = new PRTokeniser(reader.tokens.SafeFile); + if (reader.decrypt != null) + this.decrypt = new PdfEncryption(reader.decrypt); + this.pValue = reader.pValue; + this.rValue = reader.rValue; + this.xrefObj = new ArrayList(reader.xrefObj); + for (int k = 0; k < reader.xrefObj.Count; ++k) { + this.xrefObj[k] = DuplicatePdfObject((PdfObject)reader.xrefObj[k], this); + } + this.pageRefs = new PageRefs(reader.pageRefs, this); + this.trailer = (PdfDictionary)DuplicatePdfObject(reader.trailer, this); + this.catalog = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.ROOT)); + this.rootPages = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PAGES)); + this.fileLength = reader.fileLength; + this.partial = reader.partial; + this.hybridXref = reader.hybridXref; + this.objStmToOffset = reader.objStmToOffset; + this.xref = reader.xref; + this.cryptoRef = (PRIndirectReference)DuplicatePdfObject(reader.cryptoRef, this); + this.ownerPasswordUsed = reader.ownerPasswordUsed; + } + + /** Gets a new file instance of the original PDF + * document. + * @return a new file instance of the original PDF document + */ + public RandomAccessFileOrArray SafeFile { + get { + return tokens.SafeFile; + } + } + + protected internal PdfReaderInstance GetPdfReaderInstance(PdfWriter writer) { + return new PdfReaderInstance(this, writer); + } + + /** Gets the number of pages in the document. + * @return the number of pages in the document + */ + public int NumberOfPages { + get { + return pageRefs.Size; + } + } + + /** Returns the document's catalog. This dictionary is not a copy, + * any changes will be reflected in the catalog. + * @return the document's catalog + */ + public PdfDictionary Catalog { + get { + return catalog; + } + } + + /** Returns the document's acroform, if it has one. + * @return the document's acroform + */ + public PRAcroForm AcroForm { + get { + if (!acroFormParsed) { + acroFormParsed = true; + PdfObject form = catalog.Get(PdfName.ACROFORM); + if (form != null) { + try { + acroForm = new PRAcroForm(this); + acroForm.ReadAcroForm((PdfDictionary)GetPdfObject(form)); + } + catch { + acroForm = null; + } + } + } + return acroForm; + } + } + /** + * Gets the page rotation. This value can be 0, 90, 180 or 270. + * @param index the page number. The first page is 1 + * @return the page rotation + */ + public int GetPageRotation(int index) { + return GetPageRotation(pageRefs.GetPageNRelease(index)); + } + + internal int GetPageRotation(PdfDictionary page) { + PdfNumber rotate = (PdfNumber)GetPdfObject(page.Get(PdfName.ROTATE)); + if (rotate == null) + return 0; + else { + int n = rotate.IntValue; + n %= 360; + return n < 0 ? n + 360 : n; + } + } + /** Gets the page size, taking rotation into account. This + * is a Rectangle with the value of the /MediaBox and the /Rotate key. + * @param index the page number. The first page is 1 + * @return a Rectangle + */ + public Rectangle GetPageSizeWithRotation(int index) { + return GetPageSizeWithRotation(pageRefs.GetPageNRelease(index)); + } + + /** + * Gets the rotated page from a page dictionary. + * @param page the page dictionary + * @return the rotated page + */ + public Rectangle GetPageSizeWithRotation(PdfDictionary page) { + Rectangle rect = GetPageSize(page); + int rotation = GetPageRotation(page); + while (rotation > 0) { + rect = rect.Rotate(); + rotation -= 90; + } + return rect; + } + + /** Gets the page size without taking rotation into account. This + * is the value of the /MediaBox key. + * @param index the page number. The first page is 1 + * @return the page size + */ + public Rectangle GetPageSize(int index) { + return GetPageSize(pageRefs.GetPageNRelease(index)); + } + + /** + * Gets the page from a page dictionary + * @param page the page dictionary + * @return the page + */ + public Rectangle GetPageSize(PdfDictionary page) { + PdfArray mediaBox = (PdfArray)GetPdfObject(page.Get(PdfName.MEDIABOX)); + return GetNormalizedRectangle(mediaBox); + } + + /** Gets the crop box without taking rotation into account. This + * is the value of the /CropBox key. The crop box is the part + * of the document to be displayed or printed. It usually is the same + * as the media box but may be smaller. If the page doesn't have a crop + * box the page size will be returned. + * @param index the page number. The first page is 1 + * @return the crop box + */ + public Rectangle GetCropBox(int index) { + PdfDictionary page = pageRefs.GetPageNRelease(index); + PdfArray cropBox = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.CROPBOX)); + if (cropBox == null) + return GetPageSize(page); + return GetNormalizedRectangle(cropBox); + } + + /** Gets the box size. Allowed names are: "crop", "trim", "art", "bleed" and "media". + * @param index the page number. The first page is 1 + * @param boxName the box name + * @return the box rectangle or null + */ + public Rectangle GetBoxSize(int index, String boxName) { + PdfDictionary page = pageRefs.GetPageNRelease(index); + PdfArray box = null; + if (boxName.Equals("trim")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.TRIMBOX)); + else if (boxName.Equals("art")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.ARTBOX)); + else if (boxName.Equals("bleed")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.BLEEDBOX)); + else if (boxName.Equals("crop")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.CROPBOX)); + else if (boxName.Equals("media")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.MEDIABOX)); + if (box == null) + return null; + return GetNormalizedRectangle(box); + } + + /** Returns the content of the document information dictionary as a Hashtable + * of String. + * @return content of the document information dictionary + */ + public Hashtable Info { + get { + Hashtable map = new Hashtable(); + PdfDictionary info = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.INFO)); + if (info == null) + return map; + foreach (PdfName key in info.Keys) { + PdfObject obj = GetPdfObject(info.Get(key)); + if (obj == null) + continue; + String value = obj.ToString(); + switch (obj.Type) { + case PdfObject.STRING: { + value = ((PdfString)obj).ToUnicodeString(); + break; + } + case PdfObject.NAME: { + value = PdfName.DecodeName(value); + break; + } + } + map[PdfName.DecodeName(key.ToString())] = value; + } + return map; + } + } + + /** Normalizes a Rectangle so that llx and lly are smaller than urx and ury. + * @param box the original rectangle + * @return a normalized Rectangle + */ + public static Rectangle GetNormalizedRectangle(PdfArray box) { + ArrayList rect = box.ArrayList; + float llx = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[0])).FloatValue; + float lly = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[1])).FloatValue; + float urx = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[2])).FloatValue; + float ury = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[3])).FloatValue; + return new Rectangle(Math.Min(llx, urx), Math.Min(lly, ury), + Math.Max(llx, urx), Math.Max(lly, ury)); + } + + protected internal virtual void ReadPdf() { + try { + fileLength = tokens.File.Length; + pdfVersion = tokens.CheckPdfHeader(); + try { + ReadXref(); + } + catch (Exception e) { + try { + rebuilt = true; + RebuildXref(); + lastXref = -1; + } + catch (Exception ne) { + throw new IOException("Rebuild failed: " + ne.Message + "; Original message: " + e.Message); + } + } + try { + ReadDocObj(); + } + catch (Exception ne) { + if (rebuilt || encryptionError) + throw ne; + rebuilt = true; + encrypted = false; + RebuildXref(); + lastXref = -1; + ReadDocObj(); + } + + strings.Clear(); + ReadPages(); + EliminateSharedStreams(); + RemoveUnusedObjects(); + } + finally { + try { + tokens.Close(); + } + catch { + // empty on purpose + } + } + } + + protected internal void ReadPdfPartial() { + try { + fileLength = tokens.File.Length; + pdfVersion = tokens.CheckPdfHeader(); + try { + ReadXref(); + } + catch (Exception e) { + try { + rebuilt = true; + RebuildXref(); + lastXref = -1; + } + catch (Exception ne) { + throw new IOException("Rebuild failed: " + ne.Message + "; Original message: " + e.Message); + } + } + ReadDocObjPartial(); + ReadPages(); + } + catch (IOException e) { + try{tokens.Close();}catch{} + throw e; + } + } + + private bool EqualsArray(byte[] ar1, byte[] ar2, int size) { + for (int k = 0; k < size; ++k) { + if (ar1[k] != ar2[k]) + return false; + } + return true; + } + + /** + * @throws IOException + */ + private void ReadDecryptedDocObj() { + if (encrypted) + return; + PdfObject encDic = trailer.Get(PdfName.ENCRYPT); + if (encDic == null || encDic.ToString().Equals("null")) + return; + encryptionError = true; + byte[] encryptionKey = null; + + encrypted = true; + PdfDictionary enc = (PdfDictionary)GetPdfObject(encDic); + + String s; + PdfObject o; + + PdfArray documentIDs = (PdfArray)GetPdfObject(trailer.Get(PdfName.ID)); + byte[] documentID = null; + if (documentIDs != null) { + o = (PdfObject)documentIDs.ArrayList[0]; + strings.Remove(o); + s = o.ToString(); + documentID = DocWriter.GetISOBytes(s); + if (documentIDs.Size > 1) + strings.Remove(documentIDs.ArrayList[1]); + } + // just in case we have a broken producer + if (documentID == null) + documentID = new byte[0]; + + byte[] uValue = null; + byte[] oValue = null; + int cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40; + int lengthValue = 0; + + PdfObject filter = GetPdfObjectRelease(enc.Get(PdfName.FILTER)); + + if (filter.Equals(PdfName.STANDARD)) { + s = enc.Get(PdfName.U).ToString(); + strings.Remove(enc.Get(PdfName.U)); + uValue = DocWriter.GetISOBytes(s); + s = enc.Get(PdfName.O).ToString(); + strings.Remove(enc.Get(PdfName.O)); + oValue = DocWriter.GetISOBytes(s); + + o = enc.Get(PdfName.R); + if (!o.IsNumber()) throw new IOException("Illegal R value."); + rValue = ((PdfNumber)o).IntValue; + if (rValue != 2 && rValue != 3 && rValue != 4) throw new IOException("Unknown encryption type (" + rValue + ")"); + + o = enc.Get(PdfName.P); + if (!o.IsNumber()) throw new IOException("Illegal P value."); + pValue = ((PdfNumber)o).IntValue; + + if ( rValue == 3 ){ + o = enc.Get(PdfName.LENGTH); + if (!o.IsNumber()) + throw new IOException("Illegal Length value."); + lengthValue = ((PdfNumber)o).IntValue; + if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 != 0) + throw new IOException("Illegal Length value."); + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + } + else if (rValue == 4) { + lengthValue = 128; + PdfDictionary dic = (PdfDictionary)enc.Get(PdfName.CF); + if (dic == null) + throw new IOException("/CF not found (encryption)"); + dic = (PdfDictionary)dic.Get(PdfName.STDCF); + if (dic == null) + throw new IOException("/StdCF not found (encryption)"); + if (PdfName.V2.Equals(dic.Get(PdfName.CFM))) + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + else if (PdfName.AESV2.Equals(dic.Get(PdfName.CFM))) + cryptoMode = PdfWriter.ENCRYPTION_AES_128; + else + throw new IOException("No compatible encryption found"); + PdfObject em = enc.Get(PdfName.ENCRYPTMETADATA); + if (em != null && em.ToString().Equals("false")) + cryptoMode |= PdfWriter.DO_NOT_ENCRYPT_METADATA; + } else { + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40; + } + } else if (filter.Equals(PdfName.PUBSEC)) { + bool foundRecipient = false; + byte[] envelopedData = null; + PdfArray recipients = null; + + o = enc.Get(PdfName.V); + if (!o.IsNumber()) throw new IOException("Illegal V value."); + int vValue = ((PdfNumber)o).IntValue; + if (vValue != 1 && vValue != 2 && vValue != 4) + throw new IOException("Unknown encryption type V = " + rValue); + + if ( vValue == 2 ){ + o = enc.Get(PdfName.LENGTH); + if (!o.IsNumber()) + throw new IOException("Illegal Length value."); + lengthValue = ((PdfNumber)o).IntValue; + if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 != 0) + throw new IOException("Illegal Length value."); + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + recipients = (PdfArray)enc.Get(PdfName.RECIPIENTS); + } else if (vValue == 4) { + PdfDictionary dic = (PdfDictionary)enc.Get(PdfName.CF); + if (dic == null) + throw new IOException("/CF not found (encryption)"); + dic = (PdfDictionary)dic.Get(PdfName.DEFAULTCRYPTFILER); + if (dic == null) + throw new IOException("/DefaultCryptFilter not found (encryption)"); + if (PdfName.V2.Equals(dic.Get(PdfName.CFM))) + { + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + lengthValue = 128; + } + else if (PdfName.AESV2.Equals(dic.Get(PdfName.CFM))) + { + cryptoMode = PdfWriter.ENCRYPTION_AES_128; + lengthValue = 128; + } + else + throw new IOException("No compatible encryption found"); + PdfObject em = dic.Get(PdfName.ENCRYPTMETADATA); + if (em != null && em.ToString().Equals("false")) + cryptoMode |= PdfWriter.DO_NOT_ENCRYPT_METADATA; + + recipients = (PdfArray)dic.Get(PdfName.RECIPIENTS); + } else { + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40; + lengthValue = 40; + recipients = (PdfArray)enc.Get(PdfName.RECIPIENTS); + } + + for (int i = 0; iPdfObject resolving an indirect reference + * if needed. + * @param obj the PdfObject to read + * @return the resolved PdfObject + */ + public static PdfObject GetPdfObject(PdfObject obj) { + if (obj == null) + return null; + if (!obj.IsIndirect()) + return obj; + PRIndirectReference refi = (PRIndirectReference)obj; + int idx = refi.Number; + bool appendable = refi.Reader.appendable; + obj = refi.Reader.GetPdfObject(idx); + if (obj == null) { + return null; + } + else { + if (appendable) { + switch (obj.Type) { + case PdfObject.NULL: + obj = new PdfNull(); + break; + case PdfObject.BOOLEAN: + obj = new PdfBoolean(((PdfBoolean)obj).BooleanValue); + break; + case PdfObject.NAME: + obj = new PdfName(obj.GetBytes()); + break; + } + obj.IndRef = refi; + } + return obj; + } + } + + /** + * Reads a PdfObject resolving an indirect reference + * if needed. If the reader was opened in partial mode the object will be released + * to save memory. + * @param obj the PdfObject to read + * @param parent + * @return a PdfObject + */ + public static PdfObject GetPdfObjectRelease(PdfObject obj, PdfObject parent) { + PdfObject obj2 = GetPdfObject(obj, parent); + ReleaseLastXrefPartial(obj); + return obj2; + } + + /** + * @param obj + * @param parent + * @return a PdfObject + */ + public static PdfObject GetPdfObject(PdfObject obj, PdfObject parent) { + if (obj == null) + return null; + if (!obj.IsIndirect()) { + PRIndirectReference refi = null; + if (parent != null && (refi = parent.IndRef) != null && refi.Reader.Appendable) { + switch (obj.Type) { + case PdfObject.NULL: + obj = new PdfNull(); + break; + case PdfObject.BOOLEAN: + obj = new PdfBoolean(((PdfBoolean)obj).BooleanValue); + break; + case PdfObject.NAME: + obj = new PdfName(obj.GetBytes()); + break; + } + obj.IndRef = refi; + } + return obj; + } + return GetPdfObject(obj); + } + + /** + * @param idx + * @return a PdfObject + */ + public PdfObject GetPdfObjectRelease(int idx) { + PdfObject obj = GetPdfObject(idx); + ReleaseLastXrefPartial(); + return obj; + } + + /** + * @param idx + * @return aPdfObject + */ + public PdfObject GetPdfObject(int idx) { + lastXrefPartial = -1; + if (idx < 0 || idx >= xrefObj.Count) + return null; + PdfObject obj = (PdfObject)xrefObj[idx]; + if (!partial || obj != null) + return obj; + if (idx * 2 >= xref.Length) + return null; + obj = ReadSingleObject(idx); + lastXrefPartial = -1; + if (obj != null) + lastXrefPartial = idx; + return obj; + } + + /** + * + */ + public void ResetLastXrefPartial() { + lastXrefPartial = -1; + } + + /** + * + */ + public void ReleaseLastXrefPartial() { + if (partial && lastXrefPartial != -1) { + xrefObj[lastXrefPartial] = null; + lastXrefPartial = -1; + } + } + + /** + * @param obj + */ + public static void ReleaseLastXrefPartial(PdfObject obj) { + if (obj == null) + return; + if (!obj.IsIndirect()) + return; + PRIndirectReference refi = (PRIndirectReference)obj; + PdfReader reader = refi.Reader; + if (reader.partial && reader.lastXrefPartial != -1 && reader.lastXrefPartial == refi.Number) { + reader.xrefObj[reader.lastXrefPartial] = null; + } + reader.lastXrefPartial = -1; + } + + private void SetXrefPartialObject(int idx, PdfObject obj) { + if (!partial || idx < 0) + return; + xrefObj[idx] = obj; + } + + /** + * @param obj + * @return an indirect reference + */ + public PRIndirectReference AddPdfObject(PdfObject obj) { + xrefObj.Add(obj); + return new PRIndirectReference(this, xrefObj.Count - 1); + } + + protected internal void ReadPages() { + catalog = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.ROOT)); + rootPages = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PAGES)); + pageRefs = new PageRefs(this); + } + + protected internal void ReadDocObjPartial() { + xrefObj = ArrayList.Repeat(null, xref.Length / 2); + ReadDecryptedDocObj(); + if (objStmToOffset != null) { + int[] keys = objStmToOffset.GetKeys(); + for (int k = 0; k < keys.Length; ++k) { + int n = keys[k]; + objStmToOffset[n] = xref[n * 2]; + xref[n * 2] = -1; + } + } + } + + protected internal PdfObject ReadSingleObject(int k) { + strings.Clear(); + int k2 = k * 2; + int pos = xref[k2]; + if (pos < 0) + return null; + if (xref[k2 + 1] > 0) + pos = objStmToOffset[xref[k2 + 1]]; + if (pos == 0) + return null; + tokens.Seek(pos); + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid object number."); + objNum = tokens.IntValue; + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid generation number."); + objGen = tokens.IntValue; + tokens.NextValidToken(); + if (!tokens.StringValue.Equals("obj")) + tokens.ThrowError("Token 'obj' expected."); + PdfObject obj; + try { + obj = ReadPRObject(); + for (int j = 0; j < strings.Count; ++j) { + PdfString str = (PdfString)strings[j]; + str.Decrypt(this); + } + if (obj.IsStream()) { + CheckPRStreamLength((PRStream)obj); + } + } + catch { + obj = null; + } + if (xref[k2 + 1] > 0) { + obj = ReadOneObjStm((PRStream)obj, xref[k2]); + } + xrefObj[k] = obj; + return obj; + } + + protected internal PdfObject ReadOneObjStm(PRStream stream, int idx) { + int first = ((PdfNumber)GetPdfObject(stream.Get(PdfName.FIRST))).IntValue; + byte[] b = GetStreamBytes(stream, tokens.File); + PRTokeniser saveTokens = tokens; + tokens = new PRTokeniser(b); + try { + int address = 0; + bool ok = true; + ++idx; + for (int k = 0; k < idx; ++k) { + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + address = tokens.IntValue + first; + } + if (!ok) + throw new IOException("Error reading ObjStm"); + tokens.Seek(address); + return ReadPRObject(); + } + finally { + tokens = saveTokens; + } + } + + /** + * @return the percentage of the cross reference table that has been read + */ + public double DumpPerc() { + int total = 0; + for (int k = 0; k < xrefObj.Count; ++k) { + if (xrefObj[k] != null) + ++total; + } + return (total * 100.0 / xrefObj.Count); + } + + protected internal void ReadDocObj() { + ArrayList streams = new ArrayList(); + xrefObj = ArrayList.Repeat(null, xref.Length / 2); + for (int k = 2; k < xref.Length; k += 2) { + int pos = xref[k]; + if (pos <= 0 || xref[k + 1] > 0) + continue; + tokens.Seek(pos); + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid object number."); + objNum = tokens.IntValue; + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid generation number."); + objGen = tokens.IntValue; + tokens.NextValidToken(); + if (!tokens.StringValue.Equals("obj")) + tokens.ThrowError("Token 'obj' expected."); + PdfObject obj; + try { + obj = ReadPRObject(); + if (obj.IsStream()) { + streams.Add(obj); + } + } + catch { + obj = null; + } + xrefObj[k / 2] = obj; + } + for (int k = 0; k < streams.Count; ++k) { + CheckPRStreamLength((PRStream)streams[k]); + } + ReadDecryptedDocObj(); + if (objStmMark != null) { + foreach (DictionaryEntry entry in objStmMark) { + int n = (int)entry.Key; + IntHashtable h = (IntHashtable)entry.Value; + ReadObjStm((PRStream)xrefObj[n], h); + xrefObj[n] = null; + } + objStmMark = null; + } + xref = null; + } + + private void CheckPRStreamLength(PRStream stream) { + int fileLength = tokens.Length; + int start = stream.Offset; + bool calc = false; + int streamLength = 0; + PdfObject obj = GetPdfObjectRelease(stream.Get(PdfName.LENGTH)); + if (obj != null && obj.Type == PdfObject.NUMBER) { + streamLength = ((PdfNumber)obj).IntValue; + if (streamLength + start > fileLength - 20) + calc = true; + else { + tokens.Seek(start + streamLength); + String line = tokens.ReadString(20); + if (!line.StartsWith("\nendstream") && + !line.StartsWith("\r\nendstream") && + !line.StartsWith("\rendstream") && + !line.StartsWith("endstream")) + calc = true; + } + } + else + calc = true; + if (calc) { + byte[] tline = new byte[16]; + tokens.Seek(start); + while (true) { + int pos = tokens.FilePointer; + if (!tokens.ReadLineSegment(tline)) + break; + if (Equalsn(tline, endstream)) { + streamLength = pos - start; + break; + } + if (Equalsn(tline, endobj)) { + tokens.Seek(pos - 16); + String s = tokens.ReadString(16); + int index = s.IndexOf("endstream"); + if (index >= 0) + pos = pos - 16 + index; + streamLength = pos - start; + break; + } + } + } + stream.Length = streamLength; + } + + protected internal void ReadObjStm(PRStream stream, IntHashtable map) { + int first = ((PdfNumber)GetPdfObject(stream.Get(PdfName.FIRST))).IntValue; + int n = ((PdfNumber)GetPdfObject(stream.Get(PdfName.N))).IntValue; + byte[] b = GetStreamBytes(stream, tokens.File); + PRTokeniser saveTokens = tokens; + tokens = new PRTokeniser(b); + try { + int[] address = new int[n]; + int[] objNumber = new int[n]; + bool ok = true; + for (int k = 0; k < n; ++k) { + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + objNumber[k] = tokens.IntValue; + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + address[k] = tokens.IntValue + first; + } + if (!ok) + throw new IOException("Error reading ObjStm"); + for (int k = 0; k < n; ++k) { + if (map.ContainsKey(k)) { + tokens.Seek(address[k]); + PdfObject obj = ReadPRObject(); + xrefObj[objNumber[k]] = obj; + } + } + } + finally { + tokens = saveTokens; + } + } + + /** + * Eliminates the reference to the object freeing the memory used by it and clearing + * the xref entry. + * @param obj the object. If it's an indirect reference it will be eliminated + * @return the object or the already erased dereferenced object + */ + public static PdfObject KillIndirect(PdfObject obj) { + if (obj == null || obj.IsNull()) + return null; + PdfObject ret = GetPdfObjectRelease(obj); + if (obj.IsIndirect()) { + PRIndirectReference refi = (PRIndirectReference)obj; + PdfReader reader = refi.Reader; + int n = refi.Number; + reader.xrefObj[n] = null; + if (reader.partial) + reader.xref[n * 2] = -1; + } + return ret; + } + + private void EnsureXrefSize(int size) { + if (size == 0) + return; + if (xref == null) + xref = new int[size]; + else { + if (xref.Length < size) { + int[] xref2 = new int[size]; + Array.Copy(xref, 0, xref2, 0, xref.Length); + xref = xref2; + } + } + } + + protected internal void ReadXref() { + hybridXref = false; + newXrefType = false; + tokens.Seek(tokens.Startxref); + tokens.NextToken(); + if (!tokens.StringValue.Equals("startxref")) + throw new IOException("startxref not found."); + tokens.NextToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + throw new IOException("startxref is not followed by a number."); + int startxref = tokens.IntValue; + lastXref = startxref; + eofPos = tokens.FilePointer; + try { + if (ReadXRefStream(startxref)) { + newXrefType = true; + return; + } + } + catch {} + xref = null; + tokens.Seek(startxref); + trailer = ReadXrefSection(); + PdfDictionary trailer2 = trailer; + while (true) { + PdfNumber prev = (PdfNumber)trailer2.Get(PdfName.PREV); + if (prev == null) + break; + tokens.Seek(prev.IntValue); + trailer2 = ReadXrefSection(); + } + } + + protected internal PdfDictionary ReadXrefSection() { + tokens.NextValidToken(); + if (!tokens.StringValue.Equals("xref")) + tokens.ThrowError("xref subsection not found"); + int start = 0; + int end = 0; + int pos = 0; + int gen = 0; + while (true) { + tokens.NextValidToken(); + if (tokens.StringValue.Equals("trailer")) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Object number of the first object in this xref subsection not found"); + start = tokens.IntValue; + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Number of entries in this xref subsection not found"); + end = tokens.IntValue + start; + if (start == 1) { // fix incorrect start number + int back = tokens.FilePointer; + tokens.NextValidToken(); + pos = tokens.IntValue; + tokens.NextValidToken(); + gen = tokens.IntValue; + if (pos == 0 && gen == 65535) { + --start; + --end; + } + tokens.Seek(back); + } + EnsureXrefSize(end * 2); + for (int k = start; k < end; ++k) { + tokens.NextValidToken(); + pos = tokens.IntValue; + tokens.NextValidToken(); + gen = tokens.IntValue; + tokens.NextValidToken(); + int p = k * 2; + if (tokens.StringValue.Equals("n")) { + if (xref[p] == 0 && xref[p + 1] == 0) { + // if (pos == 0) + // tokens.ThrowError("File position 0 cross-reference entry in this xref subsection"); + xref[p] = pos; + } + } + else if (tokens.StringValue.Equals("f")) { + if (xref[p] == 0 && xref[p + 1] == 0) + xref[p] = -1; + } + else + tokens.ThrowError("Invalid cross-reference entry in this xref subsection"); + } + } + PdfDictionary trailer = (PdfDictionary)ReadPRObject(); + PdfNumber xrefSize = (PdfNumber)trailer.Get(PdfName.SIZE); + EnsureXrefSize(xrefSize.IntValue * 2); + PdfObject xrs = trailer.Get(PdfName.XREFSTM); + if (xrs != null && xrs.IsNumber()) { + int loc = ((PdfNumber)xrs).IntValue; + try { + ReadXRefStream(loc); + newXrefType = true; + hybridXref = true; + } + catch (IOException e) { + xref = null; + throw e; + } + } + return trailer; + } + + protected internal bool ReadXRefStream(int ptr) { + tokens.Seek(ptr); + int thisStream = 0; + if (!tokens.NextToken()) + return false; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + return false; + thisStream = tokens.IntValue; + if (!tokens.NextToken() || tokens.TokenType != PRTokeniser.TK_NUMBER) + return false; + if (!tokens.NextToken() || !tokens.StringValue.Equals("obj")) + return false; + PdfObject objecto = ReadPRObject(); + PRStream stm = null; + if (objecto.IsStream()) { + stm = (PRStream)objecto; + if (!PdfName.XREF.Equals(stm.Get(PdfName.TYPE))) + return false; + } + else + return false; + if (trailer == null) { + trailer = new PdfDictionary(); + trailer.Merge(stm); + } + stm.Length = ((PdfNumber)stm.Get(PdfName.LENGTH)).IntValue; + int size = ((PdfNumber)stm.Get(PdfName.SIZE)).IntValue; + PdfArray index; + PdfObject obj = stm.Get(PdfName.INDEX); + if (obj == null) { + index = new PdfArray(); + index.Add(new int[]{0, size}); + } + else + index = (PdfArray)obj; + PdfArray w = (PdfArray)stm.Get(PdfName.W); + int prev = -1; + obj = stm.Get(PdfName.PREV); + if (obj != null) + prev = ((PdfNumber)obj).IntValue; + // Each xref pair is a position + // type 0 -> -1, 0 + // type 1 -> offset, 0 + // type 2 -> index, obj num + EnsureXrefSize(size * 2); + if (objStmMark == null && !partial) + objStmMark = new Hashtable(); + if (objStmToOffset == null && partial) + objStmToOffset = new IntHashtable(); + byte[] b = GetStreamBytes(stm, tokens.File); + int bptr = 0; + ArrayList wa = w.ArrayList; + int[] wc = new int[3]; + for (int k = 0; k < 3; ++k) + wc[k] = ((PdfNumber)wa[k]).IntValue; + ArrayList sections = index.ArrayList; + for (int idx = 0; idx < sections.Count; idx += 2) { + int start = ((PdfNumber)sections[idx]).IntValue; + int length = ((PdfNumber)sections[idx + 1]).IntValue; + EnsureXrefSize((start + length) * 2); + while (length-- > 0) { + int type = 1; + if (wc[0] > 0) { + type = 0; + for (int k = 0; k < wc[0]; ++k) + type = (type << 8) + (b[bptr++] & 0xff); + } + int field2 = 0; + for (int k = 0; k < wc[1]; ++k) + field2 = (field2 << 8) + (b[bptr++] & 0xff); + int field3 = 0; + for (int k = 0; k < wc[2]; ++k) + field3 = (field3 << 8) + (b[bptr++] & 0xff); + int baseb = start * 2; + if (xref[baseb] == 0 && xref[baseb + 1] == 0) { + switch (type) { + case 0: + xref[baseb] = -1; + break; + case 1: + xref[baseb] = field2; + break; + case 2: + xref[baseb] = field3; + xref[baseb + 1] = field2; + if (partial) { + objStmToOffset[field2] = 0; + } + else { + IntHashtable seq = (IntHashtable)objStmMark[field2]; + if (seq == null) { + seq = new IntHashtable(); + seq[field3] = 1; + objStmMark[field2] = seq; + } + else + seq[field3] = 1; + } + break; + } + } + ++start; + } + } + thisStream *= 2; + if (thisStream < xref.Length) + xref[thisStream] = -1; + + if (prev == -1) + return true; + return ReadXRefStream(prev); + } + + protected internal void RebuildXref() { + hybridXref = false; + newXrefType = false; + tokens.Seek(0); + int[][] xr = new int[1024][]; + int top = 0; + trailer = null; + byte[] line = new byte[64]; + for (;;) { + int pos = tokens.FilePointer; + if (!tokens.ReadLineSegment(line)) + break; + if (line[0] == 't') { + if (!PdfEncodings.ConvertToString(line, null).StartsWith("trailer")) + continue; + tokens.Seek(pos); + tokens.NextToken(); + pos = tokens.FilePointer; + try { + PdfDictionary dic = (PdfDictionary)ReadPRObject(); + if (dic.Get(PdfName.ROOT) != null) + trailer = dic; + else + tokens.Seek(pos); + } + catch { + tokens.Seek(pos); + } + } + else if (line[0] >= '0' && line[0] <= '9') { + int[] obj = PRTokeniser.CheckObjectStart(line); + if (obj == null) + continue; + int num = obj[0]; + int gen = obj[1]; + if (num >= xr.Length) { + int newLength = num * 2; + int[][] xr2 = new int[newLength][]; + Array.Copy(xr, 0, xr2, 0, top); + xr = xr2; + } + if (num >= top) + top = num + 1; + if (xr[num] == null || gen >= xr[num][1]) { + obj[0] = pos; + xr[num] = obj; + } + } + } + if (trailer == null) + throw new IOException("trailer not found."); + xref = new int[top * 2]; + for (int k = 0; k < top; ++k) { + int[] obj = xr[k]; + if (obj != null) + xref[k * 2] = obj[0]; + } + } + + protected internal PdfDictionary ReadDictionary() { + PdfDictionary dic = new PdfDictionary(); + while (true) { + tokens.NextValidToken(); + if (tokens.TokenType == PRTokeniser.TK_END_DIC) + break; + if (tokens.TokenType != PRTokeniser.TK_NAME) + tokens.ThrowError("Dictionary key is not a name."); + PdfName name = new PdfName(tokens.StringValue, false); + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_DIC) + tokens.ThrowError("Unexpected '>>'"); + if (-type == PRTokeniser.TK_END_ARRAY) + tokens.ThrowError("Unexpected ']'"); + dic.Put(name, obj); + } + return dic; + } + + protected internal PdfArray ReadArray() { + PdfArray array = new PdfArray(); + while (true) { + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_ARRAY) + break; + if (-type == PRTokeniser.TK_END_DIC) + tokens.ThrowError("Unexpected '>>'"); + array.Add(obj); + } + return array; + } + + protected internal PdfObject ReadPRObject() { + tokens.NextValidToken(); + int type = tokens.TokenType; + switch (type) { + case PRTokeniser.TK_START_DIC: { + PdfDictionary dic = ReadDictionary(); + int pos = tokens.FilePointer; + // be careful in the trailer. May not be a "next" token. + if (tokens.NextToken() && tokens.StringValue.Equals("stream")) { + int ch = tokens.Read(); + if (ch != '\n') + ch = tokens.Read(); + if (ch != '\n') + tokens.BackOnePosition(ch); + PRStream stream = new PRStream(this, tokens.FilePointer); + stream.Merge(dic); + stream.ObjNum = objNum; + stream.ObjGen = objGen; + return stream; + } + else { + tokens.Seek(pos); + return dic; + } + } + case PRTokeniser.TK_START_ARRAY: + return ReadArray(); + case PRTokeniser.TK_NUMBER: + return new PdfNumber(tokens.StringValue); + case PRTokeniser.TK_STRING: + PdfString str = new PdfString(tokens.StringValue, null).SetHexWriting(tokens.IsHexString()); + str.SetObjNum(objNum, objGen); + if (strings != null) + strings.Add(str); + return str; + case PRTokeniser.TK_NAME: + return new PdfName(tokens.StringValue, false); + case PRTokeniser.TK_REF: + int num = tokens.Reference; + PRIndirectReference refi = new PRIndirectReference(this, num, tokens.Generation); + return refi; + default: + String sv = tokens.StringValue; + if ("null".Equals(sv)) + return PdfNull.PDFNULL; + else if ("true".Equals(sv)) + return PdfBoolean.PDFTRUE; + else if ("false".Equals(sv)) + return PdfBoolean.PDFFALSE; + return new PdfLiteral(-type, tokens.StringValue); + } + } + + /** Decodes a stream that has the FlateDecode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] FlateDecode(byte[] inp) { + byte[] b = FlateDecode(inp, true); + if (b == null) + return FlateDecode(inp, false); + return b; + } + + /** + * @param in + * @param dicPar + * @return a byte array + */ + public static byte[] DecodePredictor(byte[] inp, PdfObject dicPar) { + if (dicPar == null || !dicPar.IsDictionary()) + return inp; + PdfDictionary dic = (PdfDictionary)dicPar; + PdfObject obj = GetPdfObject(dic.Get(PdfName.PREDICTOR)); + if (obj == null || !obj.IsNumber()) + return inp; + int predictor = ((PdfNumber)obj).IntValue; + if (predictor < 10) + return inp; + int width = 1; + obj = GetPdfObject(dic.Get(PdfName.COLUMNS)); + if (obj != null && obj.IsNumber()) + width = ((PdfNumber)obj).IntValue; + int colors = 1; + obj = GetPdfObject(dic.Get(PdfName.COLORS)); + if (obj != null && obj.IsNumber()) + colors = ((PdfNumber)obj).IntValue; + int bpc = 8; + obj = GetPdfObject(dic.Get(PdfName.BITSPERCOMPONENT)); + if (obj != null && obj.IsNumber()) + bpc = ((PdfNumber)obj).IntValue; + MemoryStream dataStream = new MemoryStream(inp); + MemoryStream fout = new MemoryStream(inp.Length); + int bytesPerPixel = colors * bpc / 8; + int bytesPerRow = (colors*width*bpc + 7)/8; + byte[] curr = new byte[bytesPerRow]; + byte[] prior = new byte[bytesPerRow]; + + // Decode the (sub)image row-by-row + while (true) { + // Read the filter type byte and a row of data + int filter = 0; + try { + filter = dataStream.ReadByte(); + if (filter < 0) { + return fout.ToArray(); + } + int tot = 0; + while (tot < bytesPerRow) { + int n = dataStream.Read(curr, tot, bytesPerRow - tot); + if (n <= 0) + return fout.ToArray(); + tot += n; + } + } catch { + return fout.ToArray(); + } + + switch (filter) { + case 0: //PNG_FILTER_NONE + break; + case 1: //PNG_FILTER_SUB + for (int i = bytesPerPixel; i < bytesPerRow; i++) { + curr[i] += curr[i - bytesPerPixel]; + } + break; + case 2: //PNG_FILTER_UP + for (int i = 0; i < bytesPerRow; i++) { + curr[i] += prior[i]; + } + break; + case 3: //PNG_FILTER_AVERAGE + for (int i = 0; i < bytesPerPixel; i++) { + curr[i] += (byte)(prior[i] / 2); + } + for (int i = bytesPerPixel; i < bytesPerRow; i++) { + curr[i] += (byte)(((curr[i - bytesPerPixel] & 0xff) + (prior[i] & 0xff))/2); + } + break; + case 4: //PNG_FILTER_PAETH + for (int i = 0; i < bytesPerPixel; i++) { + curr[i] += prior[i]; + } + + for (int i = bytesPerPixel; i < bytesPerRow; i++) { + int a = curr[i - bytesPerPixel] & 0xff; + int b = prior[i] & 0xff; + int c = prior[i - bytesPerPixel] & 0xff; + + int p = a + b - c; + int pa = Math.Abs(p - a); + int pb = Math.Abs(p - b); + int pc = Math.Abs(p - c); + + int ret; + + if ((pa <= pb) && (pa <= pc)) { + ret = a; + } else if (pb <= pc) { + ret = b; + } else { + ret = c; + } + curr[i] += (byte)(ret); + } + break; + default: + // Error -- uknown filter type + throw new Exception("PNG filter unknown."); + } + fout.Write(curr, 0, curr.Length); + + // Swap curr and prior + byte[] tmp = prior; + prior = curr; + curr = tmp; + } + } + + /** A helper to FlateDecode. + * @param in the input data + * @param strict true to read a correct stream. false + * to try to read a corrupted stream + * @return the decoded data + */ + public static byte[] FlateDecode(byte[] inp, bool strict) { + MemoryStream stream = new MemoryStream(inp); + ZInflaterInputStream zip = new ZInflaterInputStream(stream); + MemoryStream outp = new MemoryStream(); + byte[] b = new byte[strict ? 4092 : 1]; + try { + int n; + while ((n = zip.Read(b, 0, b.Length)) > 0) { + outp.Write(b, 0, n); + } + zip.Close(); + outp.Close(); + return outp.ToArray(); + } + catch { + if (strict) + return null; + return outp.ToArray(); + } + } + + /** Decodes a stream that has the ASCIIHexDecode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] ASCIIHexDecode(byte[] inp) { + MemoryStream outp = new MemoryStream(); + bool first = true; + int n1 = 0; + for (int k = 0; k < inp.Length; ++k) { + int ch = inp[k] & 0xff; + if (ch == '>') + break; + if (PRTokeniser.IsWhitespace(ch)) + continue; + int n = PRTokeniser.GetHex(ch); + if (n == -1) + throw new ArgumentException("Illegal character in ASCIIHexDecode."); + if (first) + n1 = n; + else + outp.WriteByte((byte)((n1 << 4) + n)); + first = !first; + } + if (!first) + outp.WriteByte((byte)(n1 << 4)); + return outp.ToArray(); + } + + /** Decodes a stream that has the ASCII85Decode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] ASCII85Decode(byte[] inp) { + MemoryStream outp = new MemoryStream(); + int state = 0; + int[] chn = new int[5]; + for (int k = 0; k < inp.Length; ++k) { + int ch = inp[k] & 0xff; + if (ch == '~') + break; + if (PRTokeniser.IsWhitespace(ch)) + continue; + if (ch == 'z' && state == 0) { + outp.WriteByte(0); + outp.WriteByte(0); + outp.WriteByte(0); + outp.WriteByte(0); + continue; + } + if (ch < '!' || ch > 'u') + throw new ArgumentException("Illegal character in ASCII85Decode."); + chn[state] = ch - '!'; + ++state; + if (state == 5) { + state = 0; + int rx = 0; + for (int j = 0; j < 5; ++j) + rx = rx * 85 + chn[j]; + outp.WriteByte((byte)(rx >> 24)); + outp.WriteByte((byte)(rx >> 16)); + outp.WriteByte((byte)(rx >> 8)); + outp.WriteByte((byte)rx); + } + } + int r = 0; + // We'll ignore the next two lines for the sake of perpetuating broken PDFs +// if (state == 1) +// throw new ArgumentException("Illegal length in ASCII85Decode."); + if (state == 2) { + r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + 85 * 85 * 85 + 85 * 85 + 85; + outp.WriteByte((byte)(r >> 24)); + } + else if (state == 3) { + r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85 + 85 * 85 + 85; + outp.WriteByte((byte)(r >> 24)); + outp.WriteByte((byte)(r >> 16)); + } + else if (state == 4) { + r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85 + chn[3] * 85 + 85; + outp.WriteByte((byte)(r >> 24)); + outp.WriteByte((byte)(r >> 16)); + outp.WriteByte((byte)(r >> 8)); + } + return outp.ToArray(); + } + + /** Decodes a stream that has the LZWDecode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] LZWDecode(byte[] inp) { + MemoryStream outp = new MemoryStream(); + LZWDecoder lzw = new LZWDecoder(); + lzw.Decode(inp, outp); + return outp.ToArray(); + } + + /** Checks if the document had errors and was rebuilt. + * @return true if rebuilt. + * + */ + public bool IsRebuilt() { + return this.rebuilt; + } + + /** Gets the dictionary that represents a page. + * @param pageNum the page number. 1 is the first + * @return the page dictionary + */ + public PdfDictionary GetPageN(int pageNum) { + PdfDictionary dic = pageRefs.GetPageN(pageNum); + if (dic == null) + return null; + if (appendable) + dic.IndRef = pageRefs.GetPageOrigRef(pageNum); + return dic; + } + + /** + * @param pageNum + * @return a Dictionary object + */ + public PdfDictionary GetPageNRelease(int pageNum) { + PdfDictionary dic = GetPageN(pageNum); + pageRefs.ReleasePage(pageNum); + return dic; + } + + /** + * @param pageNum + */ + public void ReleasePage(int pageNum) { + pageRefs.ReleasePage(pageNum); + } + + /** + * + */ + public void ResetReleasePage() { + pageRefs.ResetReleasePage(); + } + + /** Gets the page reference to this page. + * @param pageNum the page number. 1 is the first + * @return the page reference + */ + public PRIndirectReference GetPageOrigRef(int pageNum) { + return pageRefs.GetPageOrigRef(pageNum); + } + + /** Gets the contents of the page. + * @param pageNum the page number. 1 is the first + * @param file the location of the PDF document + * @throws IOException on error + * @return the content + */ + public byte[] GetPageContent(int pageNum, RandomAccessFileOrArray file) { + PdfDictionary page = GetPageNRelease(pageNum); + if (page == null) + return null; + PdfObject contents = GetPdfObjectRelease(page.Get(PdfName.CONTENTS)); + if (contents == null) + return new byte[0]; + MemoryStream bout = null; + if (contents.IsStream()) { + return GetStreamBytes((PRStream)contents, file); + } + else if (contents.IsArray()) { + PdfArray array = (PdfArray)contents; + ArrayList list = array.ArrayList; + bout = new MemoryStream(); + for (int k = 0; k < list.Count; ++k) { + PdfObject item = GetPdfObjectRelease((PdfObject)list[k]); + if (item == null || !item.IsStream()) + continue; + byte[] b = GetStreamBytes((PRStream)item, file); + bout.Write(b, 0, b.Length); + if (k != list.Count - 1) + bout.WriteByte((byte)'\n'); + } + return bout.ToArray(); + } + else + return new byte[0]; + } + + /** Gets the contents of the page. + * @param pageNum the page number. 1 is the first + * @throws IOException on error + * @return the content + */ + public byte[] GetPageContent(int pageNum) { + RandomAccessFileOrArray rf = SafeFile; + try { + rf.ReOpen(); + return GetPageContent(pageNum, rf); + } + finally { + try{rf.Close();}catch{} + } + } + + protected internal void KillXref(PdfObject obj) { + if (obj == null) + return; + if ((obj is PdfIndirectReference) && !obj.IsIndirect()) + return; + switch (obj.Type) { + case PdfObject.INDIRECT: { + int xr = ((PRIndirectReference)obj).Number; + obj = (PdfObject)xrefObj[xr]; + xrefObj[xr] = null; + freeXref = xr; + KillXref(obj); + break; + } + case PdfObject.ARRAY: { + ArrayList t = ((PdfArray)obj).ArrayList; + for (int i = 0; i < t.Count; ++i) + KillXref((PdfObject)t[i]); + break; + } + case PdfObject.STREAM: + case PdfObject.DICTIONARY: { + PdfDictionary dic = (PdfDictionary)obj; + foreach (PdfName key in dic.Keys){ + KillXref(dic.Get(key)); + } + break; + } + } + } + + /** Sets the contents of the page. + * @param content the new page content + * @param pageNum the page number. 1 is the first + * @throws IOException on error + */ + public void SetPageContent(int pageNum, byte[] content) { + PdfDictionary page = GetPageN(pageNum); + if (page == null) + return; + PdfObject contents = page.Get(PdfName.CONTENTS); + freeXref = -1; + KillXref(contents); + if (freeXref == -1) { + xrefObj.Add(null); + freeXref = xrefObj.Count - 1; + } + page.Put(PdfName.CONTENTS, new PRIndirectReference(this, freeXref)); + xrefObj[freeXref] = new PRStream(this, content); + } + + /** Get the content from a stream applying the required filters. + * @param stream the stream + * @param file the location where the stream is + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytes(PRStream stream, RandomAccessFileOrArray file) { + PdfObject filter = GetPdfObjectRelease(stream.Get(PdfName.FILTER)); + byte[] b = GetStreamBytesRaw(stream, file); + ArrayList filters = new ArrayList(); + if (filter != null) { + if (filter.IsName()) + filters.Add(filter); + else if (filter.IsArray()) + filters = ((PdfArray)filter).ArrayList; + } + ArrayList dp = new ArrayList(); + PdfObject dpo = GetPdfObjectRelease(stream.Get(PdfName.DECODEPARMS)); + if (dpo == null || (!dpo.IsDictionary() && !dpo.IsArray())) + dpo = GetPdfObjectRelease(stream.Get(PdfName.DP)); + if (dpo != null) { + if (dpo.IsDictionary()) + dp.Add(dpo); + else if (dpo.IsArray()) + dp = ((PdfArray)dpo).ArrayList; + } + String name; + for (int j = 0; j < filters.Count; ++j) { + name = ((PdfName)GetPdfObjectRelease((PdfObject)filters[j])).ToString(); + if (name.Equals("/FlateDecode") || name.Equals("/Fl")) { + b = FlateDecode(b); + PdfObject dicParam = null; + if (j < dp.Count) { + dicParam = (PdfObject)dp[j]; + b = DecodePredictor(b, dicParam); + } + } + else if (name.Equals("/ASCIIHexDecode") || name.Equals("/AHx")) + b = ASCIIHexDecode(b); + else if (name.Equals("/ASCII85Decode") || name.Equals("/A85")) + b = ASCII85Decode(b); + else if (name.Equals("/LZWDecode")) { + b = LZWDecode(b); + PdfObject dicParam = null; + if (j < dp.Count) { + dicParam = (PdfObject)dp[j]; + b = DecodePredictor(b, dicParam); + } + } + else if (name.Equals("/Crypt")) { + } + else + throw new IOException("The filter " + name + " is not supported."); + } + return b; + } + + /** Get the content from a stream applying the required filters. + * @param stream the stream + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytes(PRStream stream) { + RandomAccessFileOrArray rf = stream.Reader.SafeFile; + try { + rf.ReOpen(); + return GetStreamBytes(stream, rf); + } + finally { + try{rf.Close();}catch{} + } + } + + /** Get the content from a stream as it is without applying any filter. + * @param stream the stream + * @param file the location where the stream is + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytesRaw(PRStream stream, RandomAccessFileOrArray file) { + PdfReader reader = stream.Reader; + byte[] b; + if (stream.Offset < 0) + b = stream.GetBytes(); + else { + b = new byte[stream.Length]; + file.Seek(stream.Offset); + file.ReadFully(b); + PdfEncryption decrypt = reader.Decrypt; + if (decrypt != null) { + PdfObject filter = GetPdfObjectRelease(stream.Get(PdfName.FILTER)); + ArrayList filters = new ArrayList(); + if (filter != null) { + if (filter.IsName()) + filters.Add(filter); + else if (filter.IsArray()) + filters = ((PdfArray)filter).ArrayList; + } + bool skip = false; + for (int k = 0; k < filters.Count; ++k) { + PdfObject obj = GetPdfObjectRelease((PdfObject)filters[k]); + if (obj != null && obj.ToString().Equals("/Crypt")) { + skip = true; + break; + } + } + if (!skip) { + decrypt.SetHashKey(stream.ObjNum, stream.ObjGen); + b = decrypt.DecryptByteArray(b); + } + } + } + return b; + } + + /** Get the content from a stream as it is without applying any filter. + * @param stream the stream + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytesRaw(PRStream stream) { + RandomAccessFileOrArray rf = stream.Reader.SafeFile; + try { + rf.ReOpen(); + return GetStreamBytesRaw(stream, rf); + } + finally { + try{rf.Close();}catch{} + } + } + + /** Eliminates shared streams if they exist. */ + public void EliminateSharedStreams() { + if (!sharedStreams) + return; + sharedStreams = false; + if (pageRefs.Size == 1) + return; + ArrayList newRefs = new ArrayList(); + ArrayList newStreams = new ArrayList(); + IntHashtable visited = new IntHashtable(); + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + if (page == null) + continue; + PdfObject contents = GetPdfObject(page.Get(PdfName.CONTENTS)); + if (contents == null) + continue; + if (contents.IsStream()) { + PRIndirectReference refi = (PRIndirectReference)page.Get(PdfName.CONTENTS); + if (visited.ContainsKey(refi.Number)) { + // need to duplicate + newRefs.Add(refi); + newStreams.Add(new PRStream((PRStream)contents, null)); + } + else + visited[refi.Number] = 1; + } + else if (contents.IsArray()) { + PdfArray array = (PdfArray)contents; + ArrayList list = array.ArrayList; + for (int j = 0; j < list.Count; ++j) { + PRIndirectReference refi = (PRIndirectReference)list[j]; + if (visited.ContainsKey(refi.Number)) { + // need to duplicate + newRefs.Add(refi); + newStreams.Add(new PRStream((PRStream)GetPdfObject(refi), null)); + } + else + visited[refi.Number] = 1; + } + } + } + if (newStreams.Count == 0) + return; + for (int k = 0; k < newStreams.Count; ++k) { + xrefObj.Add(newStreams[k]); + PRIndirectReference refi = (PRIndirectReference)newRefs[k]; + refi.SetNumber(xrefObj.Count - 1, 0); + } + } + + /** + * Sets the tampered state. A tampered PdfReader cannot be reused in PdfStamper. + * @param tampered the tampered state + */ + public bool Tampered { + get { + return tampered; + } + set { + tampered = value; + pageRefs.KeepPages(); } + } + + /** Gets the XML metadata. + * @throws IOException on error + * @return the XML metadata + */ + public byte[] Metadata { + get { + PdfObject obj = GetPdfObject(catalog.Get(PdfName.METADATA)); + if (!(obj is PRStream)) + return null; + RandomAccessFileOrArray rf = SafeFile; + byte[] b = null; + try { + rf.ReOpen(); + b = GetStreamBytes((PRStream)obj, rf); + } + finally { + try { + rf.Close(); + } + catch{ + // empty on purpose + } + } + return b; + } + } + + /** + * Gets the byte address of the last xref table. + * @return the byte address of the last xref table + */ + public int LastXref { + get { + return lastXref; + } + } + + /** + * Gets the number of xref objects. + * @return the number of xref objects + */ + public int XrefSize { + get { + return xrefObj.Count; + } + } + + /** + * Gets the byte address of the %%EOF marker. + * @return the byte address of the %%EOF marker + */ + public int EofPos { + get { + return eofPos; + } + } + + /** + * Gets the PDF version. Only the last version char is returned. For example + * version 1.4 is returned as '4'. + * @return the PDF version + */ + public char PdfVersion { + get { + return pdfVersion; + } + } + + /** + * Returns true if the PDF is encrypted. + * @return true if the PDF is encrypted + */ + public bool IsEncrypted() { + return encrypted; + } + + /** + * Gets the encryption permissions. It can be used directly in + * PdfWriter.SetEncryption(). + * @return the encryption permissions + */ + public int Permissions { + get { + return pValue; + } + } + + /** + * Returns true if the PDF has a 128 bit key encryption. + * @return true if the PDF has a 128 bit key encryption + */ + public bool Is128Key() { + return rValue == 3; + } + + /** + * Gets the trailer dictionary + * @return the trailer dictionary + */ + public PdfDictionary Trailer { + get { + return trailer; + } + } + + internal PdfEncryption Decrypt { + get { + return decrypt; + } + } + + internal static bool Equalsn(byte[] a1, byte[] a2) { + int length = a2.Length; + for (int k = 0; k < length; ++k) { + if (a1[k] != a2[k]) + return false; + } + return true; + } + + internal static bool ExistsName(PdfDictionary dic, PdfName key, PdfName value) { + PdfObject type = GetPdfObjectRelease(dic.Get(key)); + if (type == null || !type.IsName()) + return false; + PdfName name = (PdfName)type; + return name.Equals(value); + } + + internal static String GetFontName(PdfDictionary dic) { + if (dic == null) + return null; + PdfObject type = GetPdfObjectRelease(dic.Get(PdfName.BASEFONT)); + if (type == null || !type.IsName()) + return null; + return PdfName.DecodeName(type.ToString()); + } + + internal static String GetSubsetPrefix(PdfDictionary dic) { + if (dic == null) + return null; + String s = GetFontName(dic); + if (s == null) + return null; + if (s.Length < 8 || s[6] != '+') + return null; + for (int k = 0; k < 6; ++k) { + char c = s[k]; + if (c < 'A' || c > 'Z') + return null; + } + return s; + } + + /** Finds all the font subsets and changes the prefixes to some + * random values. + * @return the number of font subsets altered + */ + public int ShuffleSubsetNames() { + int total = 0; + for (int k = 1; k < xrefObj.Count; ++k) { + PdfObject obj = GetPdfObjectRelease(k); + if (obj == null || !obj.IsDictionary()) + continue; + PdfDictionary dic = (PdfDictionary)obj; + if (!ExistsName(dic, PdfName.TYPE, PdfName.FONT)) + continue; + if (ExistsName(dic, PdfName.SUBTYPE, PdfName.TYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) { + String s = GetSubsetPrefix(dic); + if (s == null) + continue; + String ns = BaseFont.CreateSubsetPrefix() + s.Substring(7); + PdfName newName = new PdfName(ns); + dic.Put(PdfName.BASEFONT, newName); + SetXrefPartialObject(k, dic); + ++total; + PdfDictionary fd = (PdfDictionary)GetPdfObject(dic.Get(PdfName.FONTDESCRIPTOR)); + if (fd == null) + continue; + fd.Put(PdfName.FONTNAME, newName); + } + else if (ExistsName(dic, PdfName.SUBTYPE, PdfName.TYPE0)) { + String s = GetSubsetPrefix(dic); + PdfArray arr = (PdfArray)GetPdfObject(dic.Get(PdfName.DESCENDANTFONTS)); + if (arr == null) + continue; + ArrayList list = arr.ArrayList; + if (list.Count == 0) + continue; + PdfDictionary desc = (PdfDictionary)GetPdfObject((PdfObject)list[0]); + String sde = GetSubsetPrefix(desc); + if (sde == null) + continue; + String ns = BaseFont.CreateSubsetPrefix(); + if (s != null) + dic.Put(PdfName.BASEFONT, new PdfName(ns + s.Substring(7))); + SetXrefPartialObject(k, dic); + PdfName newName = new PdfName(ns + sde.Substring(7)); + desc.Put(PdfName.BASEFONT, newName); + ++total; + PdfDictionary fd = (PdfDictionary)GetPdfObject(desc.Get(PdfName.FONTDESCRIPTOR)); + if (fd == null) + continue; + fd.Put(PdfName.FONTNAME, newName); + } + } + return total; + } + + /** Finds all the fonts not subset but embedded and marks them as subset. + * @return the number of fonts altered + */ + public int CreateFakeFontSubsets() { + int total = 0; + for (int k = 1; k < xrefObj.Count; ++k) { + PdfObject obj = GetPdfObjectRelease(k); + if (obj == null || !obj.IsDictionary()) + continue; + PdfDictionary dic = (PdfDictionary)obj; + if (!ExistsName(dic, PdfName.TYPE, PdfName.FONT)) + continue; + if (ExistsName(dic, PdfName.SUBTYPE, PdfName.TYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) { + String s = GetSubsetPrefix(dic); + if (s != null) + continue; + s = GetFontName(dic); + if (s == null) + continue; + String ns = BaseFont.CreateSubsetPrefix() + s; + PdfDictionary fd = (PdfDictionary)GetPdfObjectRelease(dic.Get(PdfName.FONTDESCRIPTOR)); + if (fd == null) + continue; + if (fd.Get(PdfName.FONTFILE) == null && fd.Get(PdfName.FONTFILE2) == null + && fd.Get(PdfName.FONTFILE3) == null) + continue; + fd = (PdfDictionary)GetPdfObject(dic.Get(PdfName.FONTDESCRIPTOR)); + PdfName newName = new PdfName(ns); + dic.Put(PdfName.BASEFONT, newName); + fd.Put(PdfName.FONTNAME, newName); + SetXrefPartialObject(k, dic); + ++total; + } + } + return total; + } + + private static PdfArray GetNameArray(PdfObject obj) { + if (obj == null) + return null; + obj = GetPdfObjectRelease(obj); + if (obj == null) + return null; + if (obj.IsArray()) + return (PdfArray)obj; + else if (obj.IsDictionary()) { + PdfObject arr2 = GetPdfObjectRelease(((PdfDictionary)obj).Get(PdfName.D)); + if (arr2 != null && arr2.IsArray()) + return (PdfArray)arr2; + } + return null; + } + + /** + * Gets all the named destinations as an Hashtable. The key is the name + * and the value is the destinations array. + * @return gets all the named destinations + */ + public Hashtable GetNamedDestination() { + Hashtable names = GetNamedDestinationFromNames(); + Hashtable names2 = GetNamedDestinationFromStrings(); + foreach (DictionaryEntry ie in names2) + names[ie.Key] = ie.Value; + return names; + } + + /** + * Gets the named destinations from the /Dests key in the catalog as an Hashtable. The key is the name + * and the value is the destinations array. + * @return gets the named destinations + */ + public Hashtable GetNamedDestinationFromNames() { + Hashtable names = new Hashtable(); + if (catalog.Get(PdfName.DESTS) != null) { + PdfDictionary dic = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.DESTS)); + if (dic == null) + return names; + foreach (PdfName key in dic.Keys) { + String name = PdfName.DecodeName(key.ToString()); + PdfArray arr = GetNameArray(dic.Get(key)); + if (arr != null) + names[name] = arr; + } + } + return names; + } + + /** + * Gets the named destinations from the /Names key in the catalog as an Hashtable. The key is the name + * and the value is the destinations array. + * @return gets the named destinations + */ + public Hashtable GetNamedDestinationFromStrings() { + if (catalog.Get(PdfName.NAMES) != null) { + PdfDictionary dic = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.NAMES)); + if (dic != null) { + dic = (PdfDictionary)GetPdfObjectRelease(dic.Get(PdfName.DESTS)); + if (dic != null) { + Hashtable names = PdfNameTree.ReadTree(dic); + object[] keys = new object[names.Count]; + names.Keys.CopyTo(keys, 0); + foreach (object key in keys) { + PdfArray arr = GetNameArray((PdfObject)names[key]); + if (arr != null) + names[key] = arr; + else + names.Remove(key); + } + return names; + } + } + } + return new Hashtable(); + } + + private bool ReplaceNamedDestination(PdfObject obj, Hashtable names) { + obj = GetPdfObject(obj); + int objIdx = lastXrefPartial; + ReleaseLastXrefPartial(); + if (obj != null && obj.IsDictionary()) { + PdfObject ob2 = GetPdfObjectRelease(((PdfDictionary)obj).Get(PdfName.DEST)); + String name = null; + if (ob2 != null) { + if (ob2.IsName()) + name = PdfName.DecodeName(ob2.ToString()); + else if (ob2.IsString()) + name = ob2.ToString(); + if (name != null) { + PdfArray dest = (PdfArray)names[name]; + if (dest != null) { + ((PdfDictionary)obj).Put(PdfName.DEST, dest); + SetXrefPartialObject(objIdx, obj); + return true; + } + } + } + else if ((ob2 = GetPdfObject(((PdfDictionary)obj).Get(PdfName.A))) != null) { + int obj2Idx = lastXrefPartial; + ReleaseLastXrefPartial(); + PdfDictionary dic = (PdfDictionary)ob2; + PdfName type = (PdfName)GetPdfObjectRelease(dic.Get(PdfName.S)); + if (PdfName.GOTO.Equals(type)) { + PdfObject ob3 = GetPdfObjectRelease(dic.Get(PdfName.D)); + if (ob3 != null) { + if (ob3.IsName()) + name = PdfName.DecodeName(ob3.ToString()); + else if (ob3.IsString()) + name = ob3.ToString(); + } + if (name != null) { + PdfArray dest = (PdfArray)names[name]; + if (dest != null) { + dic.Put(PdfName.D, dest); + SetXrefPartialObject(obj2Idx, ob2); + SetXrefPartialObject(objIdx, obj); + return true; + } + } + } + } + } + return false; + } + + /** + * Removes all the fields from the document. + */ + public void RemoveFields() { + pageRefs.ResetReleasePage(); + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + PdfArray annots = (PdfArray)GetPdfObject(page.Get(PdfName.ANNOTS)); + if (annots == null) { + pageRefs.ReleasePage(k); + continue; + } + ArrayList arr = annots.ArrayList; + for (int j = 0; j < arr.Count; ++j) { + PdfObject obj = GetPdfObjectRelease((PdfObject)arr[j]); + if (obj == null || !obj.IsDictionary()) + continue; + PdfDictionary annot = (PdfDictionary)obj; + if (PdfName.WIDGET.Equals(annot.Get(PdfName.SUBTYPE))) + arr.RemoveAt(j--); + } + if (arr.Count == 0) + page.Remove(PdfName.ANNOTS); + else + pageRefs.ReleasePage(k); + } + catalog.Remove(PdfName.ACROFORM); + pageRefs.ResetReleasePage(); + } + + /** + * Removes all the annotations and fields from the document. + */ + public void RemoveAnnotations() { + pageRefs.ResetReleasePage(); + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + if (page.Get(PdfName.ANNOTS) == null) + pageRefs.ReleasePage(k); + else + page.Remove(PdfName.ANNOTS); + } + catalog.Remove(PdfName.ACROFORM); + pageRefs.ResetReleasePage(); + } + + public ArrayList GetLinks(int page) { + pageRefs.ResetReleasePage(); + ArrayList result = new ArrayList(); + PdfDictionary pageDic = pageRefs.GetPageN(page); + if (pageDic.Get(PdfName.ANNOTS) != null) { + PdfArray annots = (PdfArray)GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + ArrayList arr = annots.ArrayList; + for (int j = 0; j < arr.Count; ++j) { + PdfDictionary annot = (PdfDictionary)GetPdfObjectRelease((PdfObject)arr[j]); + + if (PdfName.LINK.Equals(annot.Get(PdfName.SUBTYPE))) { + result.Add(new PdfAnnotation.PdfImportedLink(annot)); + } + } + } + pageRefs.ReleasePage(page); + pageRefs.ResetReleasePage(); + return result; + } + + private void IterateBookmarks(PdfObject outlineRef, Hashtable names) { + while (outlineRef != null) { + ReplaceNamedDestination(outlineRef, names); + PdfDictionary outline = (PdfDictionary)GetPdfObjectRelease(outlineRef); + PdfObject first = outline.Get(PdfName.FIRST); + if (first != null) { + IterateBookmarks(first, names); + } + outlineRef = outline.Get(PdfName.NEXT); + } + } + + /** Replaces all the local named links with the actual destinations. */ + public void ConsolidateNamedDestinations() { + if (consolidateNamedDestinations) + return; + consolidateNamedDestinations = true; + Hashtable names = GetNamedDestination(); + if (names.Count == 0) + return; + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + PdfObject annotsRef; + PdfArray annots = (PdfArray)GetPdfObject(annotsRef = page.Get(PdfName.ANNOTS)); + int annotIdx = lastXrefPartial; + ReleaseLastXrefPartial(); + if (annots == null) { + pageRefs.ReleasePage(k); + continue; + } + ArrayList list = annots.ArrayList; + bool commitAnnots = false; + for (int an = 0; an < list.Count; ++an) { + PdfObject objRef = (PdfObject)list[an]; + if (ReplaceNamedDestination(objRef, names) && !objRef.IsIndirect()) + commitAnnots = true; + } + if (commitAnnots) + SetXrefPartialObject(annotIdx, annots); + if (!commitAnnots || annotsRef.IsIndirect()) + pageRefs.ReleasePage(k); + } + PdfDictionary outlines = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.OUTLINES)); + if (outlines == null) + return; + IterateBookmarks(outlines.Get(PdfName.FIRST), names); + } + + protected internal static PdfDictionary DuplicatePdfDictionary(PdfDictionary original, PdfDictionary copy, PdfReader newReader) { + if (copy == null) + copy = new PdfDictionary(); + foreach (PdfName key in original.Keys) { + copy.Put(key, DuplicatePdfObject(original.Get(key), newReader)); + } + return copy; + } + + protected internal static PdfObject DuplicatePdfObject(PdfObject original, PdfReader newReader) { + if (original == null) + return null; + switch (original.Type) { + case PdfObject.DICTIONARY: { + return DuplicatePdfDictionary((PdfDictionary)original, null, newReader); + } + case PdfObject.STREAM: { + PRStream org = (PRStream)original; + PRStream stream = new PRStream(org, null, newReader); + DuplicatePdfDictionary(org, stream, newReader); + return stream; + } + case PdfObject.ARRAY: { + ArrayList list = ((PdfArray)original).ArrayList; + PdfArray arr = new PdfArray(); + foreach (PdfObject ob in list) { + arr.Add(DuplicatePdfObject(ob, newReader)); + } + return arr; + } + case PdfObject.INDIRECT: { + PRIndirectReference org = (PRIndirectReference)original; + return new PRIndirectReference(newReader, org.Number, org.Generation); + } + default: + return original; + } + } + + /** + * Closes the reader + */ + public void Close() { + if (!partial) + return; + tokens.Close(); + } + + protected internal void RemoveUnusedNode(PdfObject obj, bool[] hits) { + Stack state = new Stack(); + state.Push(obj); + while (state.Count != 0) { + Object current = state.Pop(); + if (current == null) + continue; + ArrayList ar = null; + PdfDictionary dic = null; + PdfName[] keys = null; + Object[] objs = null; + int idx = 0; + if (current is PdfObject) { + obj = (PdfObject)current; + switch (obj.Type) { + case PdfObject.DICTIONARY: + case PdfObject.STREAM: + dic = (PdfDictionary)obj; + keys = new PdfName[dic.Size]; + dic.Keys.CopyTo(keys, 0); + break; + case PdfObject.ARRAY: + ar = ((PdfArray)obj).ArrayList; + break; + case PdfObject.INDIRECT: + PRIndirectReference refi = (PRIndirectReference)obj; + int num = refi.Number; + if (!hits[num]) { + hits[num] = true; + state.Push(GetPdfObjectRelease(refi)); + } + continue; + default: + continue; + } + } + else { + objs = (Object[])current; + if (objs[0] is ArrayList) { + ar = (ArrayList)objs[0]; + idx = (int)objs[1]; + } + else { + keys = (PdfName[])objs[0]; + dic = (PdfDictionary)objs[1]; + idx = (int)objs[2]; + } + } + if (ar != null) { + for (int k = idx; k < ar.Count; ++k) { + PdfObject v = (PdfObject)ar[k]; + if (v.IsIndirect()) { + int num = ((PRIndirectReference)v).Number; + if (num >= xrefObj.Count || (!partial && xrefObj[num] == null)) { + ar[k] = PdfNull.PDFNULL; + continue; + } + } + if (objs == null) + state.Push(new Object[]{ar, k + 1}); + else { + objs[1] = k + 1; + state.Push(objs); + } + state.Push(v); + break; + } + } + else { + for (int k = idx; k < keys.Length; ++k) { + PdfName key = keys[k]; + PdfObject v = dic.Get(key); + if (v.IsIndirect()) { + int num = ((PRIndirectReference)v).Number; + if (num >= xrefObj.Count || (!partial && xrefObj[num] == null)) { + dic.Put(key, PdfNull.PDFNULL); + continue; + } + } + if (objs == null) + state.Push(new Object[]{keys, dic, k + 1}); + else { + objs[2] = k + 1; + state.Push(objs); + } + state.Push(v); + break; + } + } + } + } + + /** Removes all the unreachable objects. + * @return the number of indirect objects removed + */ + public int RemoveUnusedObjects() { + bool[] hits = new bool[xrefObj.Count]; + RemoveUnusedNode(trailer, hits); + int total = 0; + if (partial) { + for (int k = 1; k < hits.Length; ++k) { + if (!hits[k]) { + xref[k * 2] = -1; + xref[k * 2 + 1] = 0; + xrefObj[k] = null; + ++total; + } + } + } + else { + for (int k = 1; k < hits.Length; ++k) { + if (!hits[k]) { + xrefObj[k] = null; + ++total; + } + } + } + return total; + } + + /** Gets a read-only version of AcroFields. + * @return a read-only version of AcroFields + */ + public AcroFields AcroFields { + get { + return new AcroFields(this, null); + } + } + + /** + * Gets the global document JavaScript. + * @param file the document file + * @throws IOException on error + * @return the global document JavaScript + */ + public String GetJavaScript(RandomAccessFileOrArray file) { + PdfDictionary names = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.NAMES)); + if (names == null) + return null; + PdfDictionary js = (PdfDictionary)GetPdfObjectRelease(names.Get(PdfName.JAVASCRIPT)); + if (js == null) + return null; + Hashtable jscript = PdfNameTree.ReadTree(js); + String[] sortedNames = new String[jscript.Count]; + jscript.Keys.CopyTo(sortedNames, 0); + Array.Sort(sortedNames); + StringBuilder buf = new StringBuilder(); + for (int k = 0; k < sortedNames.Length; ++k) { + PdfDictionary j = (PdfDictionary)GetPdfObjectRelease((PdfIndirectReference)jscript[sortedNames[k]]); + if (j == null) + continue; + PdfObject obj = GetPdfObjectRelease(j.Get(PdfName.JS)); + if (obj != null) { + if (obj.IsString()) + buf.Append(((PdfString)obj).ToUnicodeString()).Append('\n'); + else if (obj.IsStream()) { + byte[] bytes = GetStreamBytes((PRStream)obj, file); + if (bytes.Length >= 2 && bytes[0] == (byte)254 && bytes[1] == (byte)255) + buf.Append(PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_UNICODE)); + else + buf.Append(PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_PDFDOCENCODING)); + buf.Append('\n'); + } + } + } + return buf.ToString(); + } + + /** + * Gets the global document JavaScript. + * @throws IOException on error + * @return the global document JavaScript + */ + public String JavaScript { + get { + RandomAccessFileOrArray rf = SafeFile; + try { + rf.ReOpen(); + return GetJavaScript(rf); + } + finally { + try{rf.Close();}catch{} + } + } + } + + /** + * Selects the pages to keep in the document. The pages are described as + * ranges. The page ordering can be changed but + * no page repetitions are allowed. Note that it may be very slow in partial mode. + * @param ranges the comma separated ranges as described in {@link SequenceList} + */ + public void SelectPages(String ranges) { + SelectPages(SequenceList.Expand(ranges, NumberOfPages)); + } + + /** + * Selects the pages to keep in the document. The pages are described as a + * List of Integer. The page ordering can be changed but + * no page repetitions are allowed. Note that it may be very slow in partial mode. + * @param pagesToKeep the pages to keep in the document + */ + public void SelectPages(ArrayList pagesToKeep) { + pageRefs.SelectPages(pagesToKeep); + RemoveUnusedObjects(); + } + + /** Sets the viewer preferences as the sum of several constants. + * @param preferences the viewer preferences + * @see PdfViewerPreferences#setViewerPreferences + */ + public virtual int ViewerPreferences { + set { + this.viewerPreferences.ViewerPreferences = value; + SetViewerPreferences(this.viewerPreferences); + } + } + + /** Adds a viewer preference + * @param key a key for a viewer preference + * @param value a value for the viewer preference + * @see PdfViewerPreferences#addViewerPreference + */ + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + this.viewerPreferences.AddViewerPreference(key, value); + SetViewerPreferences(this.viewerPreferences); + } + + internal virtual void SetViewerPreferences(PdfViewerPreferencesImp vp) { + vp.AddToCatalog(catalog); + } + + /** + * @return an int that contains the Viewer Preferences. + */ + public virtual int SimpleViewerPreferences { + get { + return PdfViewerPreferencesImp.GetViewerPreferences(catalog).PageLayoutAndMode; + } + } + + public bool Appendable { + set { + appendable = value; + if (appendable) + GetPdfObject(trailer.Get(PdfName.ROOT)); + } + get { + return appendable; + } + } + + /** + * Getter for property newXrefType. + * @return Value of property newXrefType. + */ + public bool IsNewXrefType() { + return newXrefType; + } + + /** + * Getter for property fileLength. + * @return Value of property fileLength. + */ + public int FileLength { + get { + return fileLength; + } + } + + /** + * Getter for property hybridXref. + * @return Value of property hybridXref. + */ + public bool IsHybridXref() { + return hybridXref; + } + + public class PageRefs { + private PdfReader reader; + private IntHashtable refsp; + private ArrayList refsn; + private ArrayList pageInh; + private int lastPageRead = -1; + private int sizep; + private bool keepPages; + + internal PageRefs(PdfReader reader) { + this.reader = reader; + if (reader.partial) { + refsp = new IntHashtable(); + PdfNumber npages = (PdfNumber)PdfReader.GetPdfObjectRelease(reader.rootPages.Get(PdfName.COUNT)); + sizep = npages.IntValue; + } + else { + ReadPages(); + } + } + + internal PageRefs(PageRefs other, PdfReader reader) { + this.reader = reader; + this.sizep = other.sizep; + if (other.refsn != null) { + refsn = new ArrayList(other.refsn); + for (int k = 0; k < refsn.Count; ++k) { + refsn[k] = DuplicatePdfObject((PdfObject)refsn[k], reader); + } + } + else + this.refsp = (IntHashtable)other.refsp.Clone(); + } + + internal int Size { + get { + if (refsn != null) + return refsn.Count; + else + return sizep; + } + } + + internal void ReadPages() { + if (refsn != null) + return; + refsp = null; + refsn = new ArrayList(); + pageInh = new ArrayList(); + IteratePages((PRIndirectReference)reader.catalog.Get(PdfName.PAGES)); + pageInh = null; + reader.rootPages.Put(PdfName.COUNT, new PdfNumber(refsn.Count)); + } + + internal void ReReadPages() { + refsn = null; + ReadPages(); + } + + /** Gets the dictionary that represents a page. + * @param pageNum the page number. 1 is the first + * @return the page dictionary + */ + public PdfDictionary GetPageN(int pageNum) { + PRIndirectReference refi = GetPageOrigRef(pageNum); + return (PdfDictionary)PdfReader.GetPdfObject(refi); + } + + /** + * @param pageNum + * @return a dictionary object + */ + public PdfDictionary GetPageNRelease(int pageNum) { + PdfDictionary page = GetPageN(pageNum); + ReleasePage(pageNum); + return page; + } + + /** + * @param pageNum + * @return an indirect reference + */ + public PRIndirectReference GetPageOrigRefRelease(int pageNum) { + PRIndirectReference refi = GetPageOrigRef(pageNum); + ReleasePage(pageNum); + return refi; + } + + /** Gets the page reference to this page. + * @param pageNum the page number. 1 is the first + * @return the page reference + */ + public PRIndirectReference GetPageOrigRef(int pageNum) { + --pageNum; + if (pageNum < 0 || pageNum >= Size) + return null; + if (refsn != null) + return (PRIndirectReference)refsn[pageNum]; + else { + int n = refsp[pageNum]; + if (n == 0) { + PRIndirectReference refi = GetSinglePage(pageNum); + if (reader.lastXrefPartial == -1) + lastPageRead = -1; + else + lastPageRead = pageNum; + reader.lastXrefPartial = -1; + refsp[pageNum] = refi.Number; + if (keepPages) + lastPageRead = -1; + return refi; + } + else { + if (lastPageRead != pageNum) + lastPageRead = -1; + if (keepPages) + lastPageRead = -1; + return new PRIndirectReference(reader, n); + } + } + } + + internal void KeepPages() { + if (refsp == null || keepPages) + return; + keepPages = true; + refsp.Clear(); + } + + /** + * @param pageNum + */ + public void ReleasePage(int pageNum) { + if (refsp == null) + return; + --pageNum; + if (pageNum < 0 || pageNum >= Size) + return; + if (pageNum != lastPageRead) + return; + lastPageRead = -1; + reader.lastXrefPartial = refsp[pageNum]; + reader.ReleaseLastXrefPartial(); + refsp.Remove(pageNum); + } + + /** + * + */ + public void ResetReleasePage() { + if (refsp == null) + return; + lastPageRead = -1; + } + + internal void InsertPage(int pageNum, PRIndirectReference refi) { + --pageNum; + if (refsn != null) { + if (pageNum >= refsn.Count) + refsn.Add(refi); + else + refsn.Insert(pageNum, refi); + } + else { + ++sizep; + lastPageRead = -1; + if (pageNum >= Size) { + refsp[Size] = refi.Number; + } + else { + IntHashtable refs2 = new IntHashtable((refsp.Size + 1) * 2); + for (IntHashtable.IntHashtableIterator it = refsp.GetEntryIterator(); it.HasNext();) { + IntHashtable.IntHashtableEntry entry = (IntHashtable.IntHashtableEntry)it.Next(); + int p = entry.Key; + refs2[p >= pageNum ? p + 1 : p] = entry.Value; + } + refs2[pageNum] = refi.Number; + refsp = refs2; + } + } + } + + private void PushPageAttributes(PdfDictionary nodePages) { + PdfDictionary dic = new PdfDictionary(); + if (pageInh.Count != 0) { + dic.Merge((PdfDictionary)pageInh[pageInh.Count - 1]); + } + for (int k = 0; k < pageInhCandidates.Length; ++k) { + PdfObject obj = nodePages.Get(pageInhCandidates[k]); + if (obj != null) + dic.Put(pageInhCandidates[k], obj); + } + pageInh.Add(dic); + } + + private void PopPageAttributes() { + pageInh.RemoveAt(pageInh.Count - 1); + } + + private void IteratePages(PRIndirectReference rpage) { + PdfDictionary page = (PdfDictionary)GetPdfObject(rpage); + PdfArray kidsPR = (PdfArray)GetPdfObject(page.Get(PdfName.KIDS)); + if (kidsPR == null) { + page.Put(PdfName.TYPE, PdfName.PAGE); + PdfDictionary dic = (PdfDictionary)pageInh[pageInh.Count - 1]; + foreach (PdfName key in dic.Keys) { + if (page.Get(key) == null) + page.Put(key, dic.Get(key)); + } + if (page.Get(PdfName.MEDIABOX) == null) { + PdfArray arr = new PdfArray(new float[]{0,0,PageSize.LETTER.Right,PageSize.LETTER.Top}); + page.Put(PdfName.MEDIABOX, arr); + } + refsn.Add(rpage); + } + else { + page.Put(PdfName.TYPE, PdfName.PAGES); + PushPageAttributes(page); + ArrayList kids = kidsPR.ArrayList; + for (int k = 0; k < kids.Count; ++k){ + PdfObject obj = (PdfObject)kids[k]; + if (!obj.IsIndirect()) { + while (k < kids.Count) + kids.RemoveAt(k); + break; + } + IteratePages((PRIndirectReference)obj); + } + PopPageAttributes(); + } + } + + protected internal PRIndirectReference GetSinglePage(int n) { + PdfDictionary acc = new PdfDictionary(); + PdfDictionary top = reader.rootPages; + int baseb = 0; + while (true) { + for (int k = 0; k < pageInhCandidates.Length; ++k) { + PdfObject obj = top.Get(pageInhCandidates[k]); + if (obj != null) + acc.Put(pageInhCandidates[k], obj); + } + PdfArray kids = (PdfArray)PdfReader.GetPdfObjectRelease(top.Get(PdfName.KIDS)); + for (ListIterator it = new ListIterator(kids.ArrayList); it.HasNext();) { + PRIndirectReference refi = (PRIndirectReference)it.Next(); + PdfDictionary dic = (PdfDictionary)GetPdfObject(refi); + int last = reader.lastXrefPartial; + PdfObject count = GetPdfObjectRelease(dic.Get(PdfName.COUNT)); + reader.lastXrefPartial = last; + int acn = 1; + if (count != null && count.Type == PdfObject.NUMBER) + acn = ((PdfNumber)count).IntValue; + if (n < baseb + acn) { + if (count == null) { + dic.MergeDifferent(acc); + return refi; + } + reader.ReleaseLastXrefPartial(); + top = dic; + break; + } + reader.ReleaseLastXrefPartial(); + baseb += acn; + } + } + } + + internal void SelectPages(ArrayList pagesToKeep) { + IntHashtable pg = new IntHashtable(); + ArrayList finalPages = new ArrayList(); + int psize = Size; + foreach (int p in pagesToKeep) { + if (p >= 1 && p <= psize && !pg.ContainsKey(p)) { + pg[p] = 1; + finalPages.Add(p); + } + } + if (reader.partial) { + for (int k = 1; k <= psize; ++k) { + GetPageOrigRef(k); + ResetReleasePage(); + } + } + PRIndirectReference parent = (PRIndirectReference)reader.catalog.Get(PdfName.PAGES); + PdfDictionary topPages = (PdfDictionary)PdfReader.GetPdfObject(parent); + ArrayList newPageRefs = new ArrayList(finalPages.Count); + PdfArray kids = new PdfArray(); + foreach (int p in finalPages) { + PRIndirectReference pref = GetPageOrigRef(p); + ResetReleasePage(); + kids.Add(pref); + newPageRefs.Add(pref); + GetPageN(p).Put(PdfName.PARENT, parent); + } + AcroFields af = reader.AcroFields; + bool removeFields = (af.Fields.Count > 0); + for (int k = 1; k <= psize; ++k) { + if (!pg.ContainsKey(k)) { + if (removeFields) + af.RemoveFieldsFromPage(k); + PRIndirectReference pref = GetPageOrigRef(k); + int nref = pref.Number; + reader.xrefObj[nref] = null; + if (reader.partial) { + reader.xref[nref * 2] = -1; + reader.xref[nref * 2 + 1] = 0; + } + } + } + topPages.Put(PdfName.COUNT, new PdfNumber(finalPages.Count)); + topPages.Put(PdfName.KIDS, kids); + refsp = null; + refsn = newPageRefs; + } + } + + internal PdfIndirectReference GetCryptoRef() { + if (cryptoRef == null) + return null; + return new PdfIndirectReference(0, cryptoRef.Number, cryptoRef.Generation); + } + + /** + * Removes any usage rights that this PDF may have. Only Adobe can grant usage rights + * and any PDF modification with iText will invalidate them. Invalidated usage rights may + * confuse Acrobat and it's advisabe to remove them altogether. + */ + public void RemoveUsageRights() { + PdfDictionary perms = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PERMS)); + if (perms == null) + return; + perms.Remove(PdfName.UR); + perms.Remove(PdfName.UR3); + if (perms.Size == 0) + catalog.Remove(PdfName.PERMS); + } + + /** + * Gets the certification level for this document. The return values can be PdfSignatureAppearance.NOT_CERTIFIED, + * PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED, + * PdfSignatureAppearance.CERTIFIED_FORM_FILLING and + * PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS. + *

+ * No signature validation is made, use the methods availabe for that in AcroFields. + *

+ * @return gets the certification level for this document + */ + public int GetCertificationLevel() { + PdfDictionary dic = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PERMS)); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + dic = (PdfDictionary)GetPdfObject(dic.Get(PdfName.DOCMDP)); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + PdfArray arr = (PdfArray)GetPdfObject(dic.Get(PdfName.REFERENCE)); + if (arr == null || arr.Size == 0) + return PdfSignatureAppearance.NOT_CERTIFIED; + dic = (PdfDictionary)GetPdfObject((PdfObject)(arr.ArrayList[0])); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + dic = (PdfDictionary)GetPdfObject(dic.Get(PdfName.TRANSFORMPARAMS)); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + PdfNumber p = (PdfNumber)GetPdfObject(dic.Get(PdfName.P)); + if (p == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + return p.IntValue; + } + + /** + * Checks if the document was opened with the owner password so that the end application + * can decide what level of access restrictions to apply. If the document is not encrypted + * it will return true. + * @return true if the document was opened with the owner password or if it's not encrypted, + * false if the document was opened with the user password + */ + public bool IsOpenedWithFullPermissions { + get { + return !encrypted || ownerPasswordUsed; + } + } + + public int GetCryptoMode() { + if (decrypt == null) + return -1; + else + return decrypt.GetCryptoMode(); + } + + public bool IsMetadataEncrypted() { + if (decrypt == null) + return false; + else + return decrypt.IsMetadataEncrypted(); + } + + public byte[] ComputeUserPassword() { + if (!encrypted || !ownerPasswordUsed) return null; + return decrypt.ComputeUserPassword(password); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs b/iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs new file mode 100644 index 0000000..e17b847 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs @@ -0,0 +1,185 @@ +using System; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Instance of PdfReader in each output document. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfReaderInstance { + internal static PdfLiteral IDENTITYMATRIX = new PdfLiteral("[1 0 0 1 0 0]"); + internal static PdfNumber ONE = new PdfNumber(1); + internal int[] myXref; + internal PdfReader reader; + internal RandomAccessFileOrArray file; + internal Hashtable importedPages = new Hashtable(); + internal PdfWriter writer; + internal Hashtable visited = new Hashtable(); + internal ArrayList nextRound = new ArrayList(); + + internal PdfReaderInstance(PdfReader reader, PdfWriter writer) { + this.reader = reader; + this.writer = writer; + file = reader.SafeFile; + myXref = new int[reader.XrefSize]; + } + + internal PdfReader Reader { + get { + return reader; + } + } + + internal PdfImportedPage GetImportedPage(int pageNumber) { + if (!reader.IsOpenedWithFullPermissions) + throw new ArgumentException("PdfReader not opened with owner password"); + if (pageNumber < 1 || pageNumber > reader.NumberOfPages) + throw new ArgumentException("Invalid page number: " + pageNumber); + PdfImportedPage pageT = (PdfImportedPage)importedPages[pageNumber]; + if (pageT == null) { + pageT = new PdfImportedPage(this, writer, pageNumber); + importedPages[pageNumber] = pageT; + } + return pageT; + } + + internal int GetNewObjectNumber(int number, int generation) { + if (myXref[number] == 0) { + myXref[number] = writer.IndirectReferenceNumber; + nextRound.Add(number); + } + return myXref[number]; + } + + internal RandomAccessFileOrArray ReaderFile { + get { + return file; + } + } + + internal PdfObject GetResources(int pageNumber) { + PdfObject obj = PdfReader.GetPdfObjectRelease(reader.GetPageNRelease(pageNumber).Get(PdfName.RESOURCES)); + return obj; + } + + + internal PdfStream GetFormXObject(int pageNumber) { + PdfDictionary page = reader.GetPageNRelease(pageNumber); + PdfObject contents = PdfReader.GetPdfObjectRelease(page.Get(PdfName.CONTENTS)); + PdfDictionary dic = new PdfDictionary(); + byte[] bout = null; + if (contents != null) { + if (contents.IsStream()) + dic.Merge((PRStream)contents); + else + bout = reader.GetPageContent(pageNumber, file); + } + else + bout = new byte[0]; + dic.Put(PdfName.RESOURCES, PdfReader.GetPdfObjectRelease(page.Get(PdfName.RESOURCES))); + dic.Put(PdfName.TYPE, PdfName.XOBJECT); + dic.Put(PdfName.SUBTYPE, PdfName.FORM); + PdfImportedPage impPage = (PdfImportedPage)importedPages[pageNumber]; + dic.Put(PdfName.BBOX, new PdfRectangle(impPage.BoundingBox)); + PdfArray matrix = impPage.Matrix; + if (matrix == null) + dic.Put(PdfName.MATRIX, IDENTITYMATRIX); + else + dic.Put(PdfName.MATRIX, matrix); + dic.Put(PdfName.FORMTYPE, ONE); + PRStream stream; + if (bout == null) { + stream = new PRStream((PRStream)contents, dic); + } + else { + stream = new PRStream(reader, bout); + stream.Merge(dic); + } + return stream; + } + + internal void WriteAllVisited() { + while (nextRound.Count > 0) { + ArrayList vec = nextRound; + nextRound = new ArrayList(); + for (int k = 0; k < vec.Count; ++k) { + int i = (int)vec[k]; + if (!visited.ContainsKey(i)) { + visited[i] = null; + writer.AddToBody(reader.GetPdfObjectRelease(i), myXref[i]); + } + } + } + } + + internal void WriteAllPages() { + try { + file.ReOpen(); + foreach (PdfImportedPage ip in importedPages.Values) { + writer.AddToBody(ip.FormXObject, ip.IndirectReference); + } + WriteAllVisited(); + } + finally { + try { + reader.Close(); + file.Close(); + } + catch { + //Empty on purpose + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs b/iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs new file mode 100644 index 0000000..42b36b5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs @@ -0,0 +1,290 @@ +using System; + +using iTextSharp.text; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfRectangle is the PDF Rectangle object. + *

+ * Rectangles are used to describe locations on the page and bounding boxes for several + * objects in PDF, such as fonts. A rectangle is represented as an array of + * four numbers, specifying the lower lef x, lower left y, upper right x, + * and upper right y coordinates of the rectangle, in that order.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.1 (page 183). + * + * @see iTextSharp.text.Rectangle + * @see PdfArray + */ + + public class PdfRectangle : PdfArray { + + // membervariables + + /** lower left x */ + private float llx = 0; + + /** lower left y */ + private float lly = 0; + + /** upper right x */ + private float urx = 0; + + /** upper right y */ + private float ury = 0; + + // constructors + + /** + * Constructs a PdfRectangle-object. + * + * @param llx lower left x + * @param lly lower left y + * @param urx upper right x + * @param ury upper right y + * + * @since rugPdf0.10 + */ + + public PdfRectangle(float llx, float lly, float urx, float ury, int rotation) : base() { + if (rotation == 90 || rotation == 270) { + this.llx = lly; + this.lly = llx; + this.urx = ury; + this.ury = urx; + } + else { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + base.Add(new PdfNumber(this.llx)); + base.Add(new PdfNumber(this.lly)); + base.Add(new PdfNumber(this.urx)); + base.Add(new PdfNumber(this.ury)); + } + + public PdfRectangle(float llx, float lly, float urx, float ury) : this(llx, lly, urx, ury, 0) {} + + /** + * Constructs a PdfRectangle-object starting from the origin (0, 0). + * + * @param urx upper right x + * @param ury upper right y + */ + + public PdfRectangle(float urx, float ury, int rotation) : this(0, 0, urx, ury, rotation) {} + + public PdfRectangle(float urx, float ury) : this(0, 0, urx, ury, 0) {} + + /** + * Constructs a PdfRectangle-object with a Rectangle-object. + * + * @param rectangle a Rectangle + */ + + public PdfRectangle(Rectangle rectangle, int rotation) : this(rectangle.Left, rectangle.Bottom, rectangle.Right, rectangle.Top, rotation) {} + + public PdfRectangle(Rectangle rectangle) : this(rectangle.Left, rectangle.Bottom, rectangle.Right, rectangle.Top, 0) {} + + // methods + + /** + * Returns the high level version of this PdfRectangle + * @return this PdfRectangle translated to class Rectangle + */ + public Rectangle Rectangle { + get { + return new Rectangle(Left, Bottom, Right, Top); + } + } + + /** + * Overrides the add-method in PdfArray in order to prevent the adding of extra object to the array. + * + * @param object PdfObject to add (will not be added here) + * @return false + */ + + public override bool Add(PdfObject obj) { + return false; + } + + /** + * Returns the lower left x-coordinate. + * + * @return the lower left x-coordinaat + */ + + public float Left { + get { + return llx; + } + } + + /** + * Returns the upper right x-coordinate. + * + * @return the upper right x-coordinate + */ + + public float Right { + get { + return urx; + } + } + + /** + * Returns the upper right y-coordinate. + * + * @return the upper right y-coordinate + */ + + public float Top { + get { + return ury; + } + } + + /** + * Returns the lower left y-coordinate. + * + * @return the lower left y-coordinate + */ + + public float Bottom { + get { + return lly; + } + } + + /** + * Returns the lower left x-coordinate, considering a given margin. + * + * @param margin a margin + * @return the lower left x-coordinate + */ + + public float GetLeft(int margin) { + return llx + margin; + } + + /** + * Returns the upper right x-coordinate, considering a given margin. + * + * @param margin a margin + * @return the upper right x-coordinate + */ + + public float GetRight(int margin) { + return urx - margin; + } + + /** + * Returns the upper right y-coordinate, considering a given margin. + * + * @param margin a margin + * @return the upper right y-coordinate + */ + + public float GetTop(int margin) { + return ury - margin; + } + + /** + * Returns the lower left y-coordinate, considering a given margin. + * + * @param margin a margin + * @return the lower left y-coordinate + */ + + public float GetBottom(int margin) { + return lly + margin; + } + + /** + * Returns the width of the rectangle. + * + * @return a width + */ + + public float Width { + get { + return urx - llx; + } + } + + /** + * Returns the height of the rectangle. + * + * @return a height + */ + + public float Height { + get { + return ury - lly; + } + } + + /** + * Swaps the values of urx and ury and of lly and llx in order to rotate the rectangle. + * + * @return a PdfRectangle + */ + + public PdfRectangle Rotate { + get { + return new PdfRectangle(lly, llx, ury, urx, 0); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfRendition.cs b/iTechSharp/iTextSharp/text/pdf/PdfRendition.cs new file mode 100644 index 0000000..f859ef9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfRendition.cs @@ -0,0 +1,60 @@ +using System; +/* + * Copyright 2003 Galo Gimenez + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A Rendition dictionary (pdf spec 1.5) + */ + public class PdfRendition : PdfDictionary { + public PdfRendition(String file, PdfFileSpecification fs, String mimeType) { + Put(PdfName.S, new PdfName("MR")); + Put(PdfName.N, new PdfString("Rendition for "+file)); + Put(PdfName.C, new PdfMediaClipData(file, fs, mimeType)); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfResources.cs b/iTechSharp/iTextSharp/text/pdf/PdfResources.cs new file mode 100644 index 0000000..1d44d88 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfResources.cs @@ -0,0 +1,92 @@ +using System; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfResources is the PDF Resources-object. + *

+ * The marking operations for drawing a page are stored in a stream that is the value of the + * Contents key in the Page object's dictionary. Each marking context includes a list + * of the named resources it uses. This resource list is stored as a dictionary that is the + * value of the context's Resources key, and it serves two functions: it enumerates + * the named resources in the contents stream, and it established the mapping from the names + * to the objects used by the marking operations.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.5 (page 195-197). + * + * @see PdfResource + * @see PdfProcSet + * @see PdfFontDictionary + * @see PdfPage + */ + + internal class PdfResources : PdfDictionary { + + // constructor + + /** + * Constructs a PDF ResourcesDictionary. + */ + + internal PdfResources() : base() {} + + // methods + + internal void Add(PdfName key, PdfDictionary resource) { + if (resource.Size == 0) + return; + PdfDictionary dic = (PdfDictionary)PdfReader.GetPdfObject(Get(key)); + if (dic == null) + Put(key, resource); + else + dic.Merge(resource); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfShading.cs b/iTechSharp/iTextSharp/text/pdf/PdfShading.cs new file mode 100644 index 0000000..5a8fb1e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfShading.cs @@ -0,0 +1,277 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements the shading dictionary (or stream). + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfShading { + + protected PdfDictionary shading; + + protected PdfWriter writer; + + protected int shadingType; + + protected ColorDetails colorDetails; + + protected PdfName shadingName; + + protected PdfIndirectReference shadingReference; + + /** Holds value of property bBox. */ + protected float[] bBox; + + /** Holds value of property antiAlias. */ + protected bool antiAlias = false; + + private Color cspace; + + /** Creates new PdfShading */ + protected PdfShading(PdfWriter writer) { + this.writer = writer; + } + + protected void SetColorSpace(Color color) { + cspace = color; + int type = ExtendedColor.GetType(color); + PdfObject colorSpace = null; + switch (type) { + case ExtendedColor.TYPE_GRAY: { + colorSpace = PdfName.DEVICEGRAY; + break; + } + case ExtendedColor.TYPE_CMYK: { + colorSpace = PdfName.DEVICECMYK; + break; + } + case ExtendedColor.TYPE_SEPARATION: { + SpotColor spot = (SpotColor)color; + colorDetails = writer.AddSimple(spot.PdfSpotColor); + colorSpace = colorDetails.IndirectReference; + break; + } + case ExtendedColor.TYPE_PATTERN: + case ExtendedColor.TYPE_SHADING: { + ThrowColorSpaceError(); + break; + } + default: + colorSpace = PdfName.DEVICERGB; + break; + } + shading.Put(PdfName.COLORSPACE, colorSpace); + } + + public Color ColorSpace { + get { + return cspace; + } + } + + public static void ThrowColorSpaceError() { + throw new ArgumentException("A tiling or shading pattern cannot be used as a color space in a shading pattern"); + } + + public static void CheckCompatibleColors(Color c1, Color c2) { + int type1 = ExtendedColor.GetType(c1); + int type2 = ExtendedColor.GetType(c2); + if (type1 != type2) + throw new ArgumentException("Both colors must be of the same type."); + if (type1 == ExtendedColor.TYPE_SEPARATION && ((SpotColor)c1).PdfSpotColor != ((SpotColor)c2).PdfSpotColor) + throw new ArgumentException("The spot color must be the same, only the tint can vary."); + if (type1 == ExtendedColor.TYPE_PATTERN || type1 == ExtendedColor.TYPE_SHADING) + ThrowColorSpaceError(); + } + + public static float[] GetColorArray(Color color) { + int type = ExtendedColor.GetType(color); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + return new float[]{((GrayColor)color).Gray}; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)color; + return new float[]{cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black}; + } + case ExtendedColor.TYPE_SEPARATION: { + return new float[]{((SpotColor)color).Tint}; + } + case ExtendedColor.TYPE_RGB: { + return new float[]{color.R / 255f, color.G / 255f, color.B / 255f}; + } + } + ThrowColorSpaceError(); + return null; + } + + public static PdfShading Type1(PdfWriter writer, Color colorSpace, float[] domain, float[] tMatrix, PdfFunction function) { + PdfShading sp = new PdfShading(writer); + sp.shading = new PdfDictionary(); + sp.shadingType = 1; + sp.shading.Put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); + sp.SetColorSpace(colorSpace); + if (domain != null) + sp.shading.Put(PdfName.DOMAIN, new PdfArray(domain)); + if (tMatrix != null) + sp.shading.Put(PdfName.MATRIX, new PdfArray(tMatrix)); + sp.shading.Put(PdfName.FUNCTION, function.Reference); + return sp; + } + + public static PdfShading Type2(PdfWriter writer, Color colorSpace, float[] coords, float[] domain, PdfFunction function, bool[] extend) { + PdfShading sp = new PdfShading(writer); + sp.shading = new PdfDictionary(); + sp.shadingType = 2; + sp.shading.Put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); + sp.SetColorSpace(colorSpace); + sp.shading.Put(PdfName.COORDS, new PdfArray(coords)); + if (domain != null) + sp.shading.Put(PdfName.DOMAIN, new PdfArray(domain)); + sp.shading.Put(PdfName.FUNCTION, function.Reference); + if (extend != null && (extend[0] || extend[1])) { + PdfArray array = new PdfArray(extend[0] ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + array.Add(extend[1] ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + sp.shading.Put(PdfName.EXTEND, array); + } + return sp; + } + + public static PdfShading Type3(PdfWriter writer, Color colorSpace, float[] coords, float[] domain, PdfFunction function, bool[] extend) { + PdfShading sp = Type2(writer, colorSpace, coords, domain, function, extend); + sp.shadingType = 3; + sp.shading.Put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); + return sp; + } + + public static PdfShading SimpleAxial(PdfWriter writer, float x0, float y0, float x1, float y1, Color startColor, Color endColor, bool extendStart, bool extendEnd) { + CheckCompatibleColors(startColor, endColor); + PdfFunction function = PdfFunction.Type2(writer, new float[]{0, 1}, null, GetColorArray(startColor), + GetColorArray(endColor), 1); + return Type2(writer, startColor, new float[]{x0, y0, x1, y1}, null, function, new bool[]{extendStart, extendEnd}); + } + + public static PdfShading SimpleAxial(PdfWriter writer, float x0, float y0, float x1, float y1, Color startColor, Color endColor) { + return SimpleAxial(writer, x0, y0, x1, y1, startColor, endColor, true, true); + } + + public static PdfShading SimpleRadial(PdfWriter writer, float x0, float y0, float r0, float x1, float y1, float r1, Color startColor, Color endColor, bool extendStart, bool extendEnd) { + CheckCompatibleColors(startColor, endColor); + PdfFunction function = PdfFunction.Type2(writer, new float[]{0, 1}, null, GetColorArray(startColor), + GetColorArray(endColor), 1); + return Type3(writer, startColor, new float[]{x0, y0, r0, x1, y1, r1}, null, function, new bool[]{extendStart, extendEnd}); + } + + public static PdfShading SimpleRadial(PdfWriter writer, float x0, float y0, float r0, float x1, float y1, float r1, Color startColor, Color endColor) { + return SimpleRadial(writer, x0, y0, r0, x1, y1, r1, startColor, endColor, true, true); + } + + internal PdfName ShadingName { + get { + return shadingName; + } + } + + internal PdfIndirectReference ShadingReference { + get { + if (shadingReference == null) + shadingReference = writer.PdfIndirectReference; + return shadingReference; + } + } + + internal int Name { + set { + shadingName = new PdfName("Sh" + value); + } + } + + internal void AddToBody() { + if (bBox != null) + shading.Put(PdfName.BBOX, new PdfArray(bBox)); + if (antiAlias) + shading.Put(PdfName.ANTIALIAS, PdfBoolean.PDFTRUE); + writer.AddToBody(shading, this.ShadingReference); + } + + internal PdfWriter Writer { + get { + return writer; + } + } + + internal ColorDetails ColorDetails { + get { + return colorDetails; + } + } + + public float[] BBox { + get { + return bBox; + } + set { + if (value.Length != 4) + throw new ArgumentException("BBox must be a 4 element array."); + this.bBox = value; + } + } + + public bool AntiAlias { + set { + this.antiAlias = value; + } + get { + return antiAlias; + } + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs b/iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs new file mode 100644 index 0000000..b633e95 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs @@ -0,0 +1,137 @@ +using System; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements the shading pattern dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfShadingPattern : PdfDictionary { + + protected PdfShading shading; + + protected PdfWriter writer; + + protected float[] matrix = {1, 0, 0, 1, 0, 0}; + + protected PdfName patternName; + + protected PdfIndirectReference patternReference; + + /** Creates new PdfShadingPattern */ + public PdfShadingPattern(PdfShading shading) { + writer = shading.Writer; + Put(PdfName.PATTERNTYPE, new PdfNumber(2)); + this.shading = shading; + } + + internal PdfName PatternName { + get { + return patternName; + } + } + + internal PdfName ShadingName { + get { + return shading.ShadingName; + } + } + + internal PdfIndirectReference PatternReference { + get { + if (patternReference == null) + patternReference = writer.PdfIndirectReference; + return patternReference; + } + } + + internal PdfIndirectReference ShadingReference { + get { + return shading.ShadingReference; + } + } + + internal int Name { + set { + patternName = new PdfName("P" + value); + } + } + + internal void AddToBody() { + Put(PdfName.SHADING, ShadingReference); + Put(PdfName.MATRIX, new PdfArray(matrix)); + writer.AddToBody(this, PatternReference); + } + + public float[] Matrix { + get { + return matrix; + } + + set { + if (value.Length != 6) + throw new Exception("The matrix size must be 6."); + this.matrix = value; + } + } + + public PdfShading Shading { + get { + return shading; + } + } + + internal ColorDetails ColorDetails { + get { + return shading.ColorDetails; + } + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs b/iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs new file mode 100644 index 0000000..469a8d5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs @@ -0,0 +1,196 @@ +using System; +using System.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * A signature dictionary representation for the standard filters. + */ + public abstract class PdfSigGenericPKCS : PdfSignature { + /** + * The hash algorith, for example "SHA1" + */ + protected String hashAlgorithm; + /** + * The class instance that calculates the PKCS#1 and PKCS#7 + */ + protected PdfPKCS7 pkcs; + /** + * The subject name in the signing certificate (the element "CN") + */ + protected String name; + + private byte[] externalDigest; + private byte[] externalRSAdata; + private String digestEncryptionAlgorithm; + + /** + * Creates a generic standard filter. + * @param filter the filter name + * @param subFilter the sub-filter name + */ + public PdfSigGenericPKCS(PdfName filter, PdfName subFilter) : base(filter, subFilter) { + } + + /** + * Sets the crypto information to sign. + * @param privKey the private key + * @param certChain the certificate chain + * @param crlList the certificate revocation list. It can be null + */ + public void SetSignInfo(ICipherParameters privKey, X509Certificate[] certChain, object[] crlList) { + pkcs = new PdfPKCS7(privKey, certChain, crlList, hashAlgorithm, PdfName.ADBE_PKCS7_SHA1.Equals(Get(PdfName.SUBFILTER))); + pkcs.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); + if (PdfName.ADBE_X509_RSA_SHA1.Equals(Get(PdfName.SUBFILTER))) { + MemoryStream bout = new MemoryStream(); + for (int k = 0; k < certChain.Length; ++k) { + byte[] tmp = certChain[k].GetEncoded(); + bout.Write(tmp, 0, tmp.Length); + } + bout.Close(); + Cert = bout.ToArray(); + Contents = pkcs.GetEncodedPKCS1(); + } + else + Contents = pkcs.GetEncodedPKCS7(); + name = PdfPKCS7.GetSubjectFields(pkcs.SigningCertificate).GetField("CN"); + if (name != null) + Put(PdfName.NAME, new PdfString(name, PdfObject.TEXT_UNICODE)); + pkcs = new PdfPKCS7(privKey, certChain, crlList, hashAlgorithm, PdfName.ADBE_PKCS7_SHA1.Equals(Get(PdfName.SUBFILTER))); + pkcs.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); + } + + /** + * Sets the digest/signature to an external calculated value. + * @param digest the digest. This is the actual signature + * @param RSAdata the extra data that goes into the data tag in PKCS#7 + * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest + * is also null. If the digest is not null + * then it may be "RSA" or "DSA" + */ + public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm) { + externalDigest = digest; + externalRSAdata = RSAdata; + this.digestEncryptionAlgorithm = digestEncryptionAlgorithm; + } + + /** + * Gets the subject name in the signing certificate (the element "CN") + * @return the subject name in the signing certificate (the element "CN") + */ + public new String Name { + get { + return name; + } + } + + /** + * Gets the class instance that does the actual signing. + * @return the class instance that does the actual signing + */ + public PdfPKCS7 Signer { + get { + return pkcs; + } + } + + /** + * Gets the signature content. This can be a PKCS#1 or a PKCS#7. It corresponds to + * the /Contents key. + * @return the signature content + */ + public byte[] SignerContents { + get { + if (PdfName.ADBE_X509_RSA_SHA1.Equals(Get(PdfName.SUBFILTER))) + return pkcs.GetEncodedPKCS1(); + else + return pkcs.GetEncodedPKCS7(); + } + } + + /** + * Creates a standard filter of the type VeriSign. + */ + public class VeriSign : PdfSigGenericPKCS { + /** + * The constructor for the default provider. + */ + public VeriSign() : base(PdfName.VERISIGN_PPKVS, PdfName.ADBE_PKCS7_DETACHED) { + hashAlgorithm = "MD5"; + Put(PdfName.R, new PdfNumber(65537)); + } + } + + /** + * Creates a standard filter of the type self signed. + */ + public class PPKLite : PdfSigGenericPKCS { + /** + * The constructor for the default provider. + */ + public PPKLite() : base(PdfName.ADOBE_PPKLITE, PdfName.ADBE_X509_RSA_SHA1) { + hashAlgorithm = "SHA1"; + Put(PdfName.R, new PdfNumber(65541)); + } + } + + /** + * Creates a standard filter of the type Windows Certificate. + */ + public class PPKMS : PdfSigGenericPKCS { + /** + * The constructor for the default provider. + */ + public PPKMS() : base(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1) { + hashAlgorithm = "SHA1"; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSignature.cs b/iTechSharp/iTextSharp/text/pdf/PdfSignature.cs new file mode 100644 index 0000000..570fae7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSignature.cs @@ -0,0 +1,115 @@ +using System; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Implements the signature dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfSignature : PdfDictionary { + + /** Creates new PdfSignature */ + public PdfSignature(PdfName filter, PdfName subFilter) : base(PdfName.SIG) { + Put(PdfName.FILTER, filter); + Put(PdfName.SUBFILTER, subFilter); + } + + public int[] ByteRange { + set { + PdfArray array = new PdfArray(); + for (int k = 0; k < value.Length; ++k) + array.Add(new PdfNumber(value[k])); + Put(PdfName.BYTERANGE, array); + } + } + + public byte[] Contents { + set { + Put(PdfName.CONTENTS, new PdfString(value).SetHexWriting(true)); + } + } + + public byte[] Cert { + set { + Put(PdfName.CERT, new PdfString(value)); + } + } + + public string Name { + set { + Put(PdfName.NAME, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public PdfDate Date { + set { + Put(PdfName.M, value); + } + } + + public string Location { + set { + Put(PdfName.LOCATION, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string Reason { + set { + Put(PdfName.REASON, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string Contact { + set { + Put(PdfName.CONTACTINFO, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs b/iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs new file mode 100644 index 0000000..2393763 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs @@ -0,0 +1,1445 @@ +using System; +using System.Collections; +using System.Text; +using System.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto; +using iTextSharp.text; +/* + * $Id: PdfSignatureAppearance.cs,v 1.13 2008/04/17 15:32:39 psoares33 Exp $ + * + * Copyright 2004-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * This class takes care of the cryptographic options and appearances that form a signature. + */ + public class PdfSignatureAppearance { + + /** + * Enumeration representing the different rendering options of a signature + */ + public enum SignatureRender { + Description, + NameAndDescription, + GraphicAndDescription + } + + /** + * The self signed filter. + */ + public static PdfName SELF_SIGNED = PdfName.ADOBE_PPKLITE; + /** + * The VeriSign filter. + */ + public static PdfName VERISIGN_SIGNED = PdfName.VERISIGN_PPKVS; + /** + * The Windows Certificate Security. + */ + public static PdfName WINCER_SIGNED = PdfName.ADOBE_PPKMS; + + public const int NOT_CERTIFIED = 0; + public const int CERTIFIED_NO_CHANGES_ALLOWED = 1; + public const int CERTIFIED_FORM_FILLING = 2; + public const int CERTIFIED_FORM_FILLING_AND_ANNOTATIONS = 3; + + private const float TOP_SECTION = 0.3f; + private const float MARGIN = 2; + private Rectangle rect; + private Rectangle pageRect; + private PdfTemplate[] app = new PdfTemplate[5]; + private PdfTemplate frm; + private PdfStamperImp writer; + private String layer2Text; + private String reason; + private String location; + private DateTime signDate; + private int page = 1; + private String fieldName; + private ICipherParameters privKey; + private X509Certificate[] certChain; + private object[] crlList; + private PdfName filter; + private bool newField; + private ByteBuffer sigout; + private Stream originalout; + private string tempFile; + private PdfDictionary cryptoDictionary; + private PdfStamper stamper; + private bool preClosed = false; + private PdfSigGenericPKCS sigStandard; + private int[] range; + private FileStream raf; + private byte[] bout; + private int boutLen; + private byte[] externalDigest; + private byte[] externalRSAdata; + private String digestEncryptionAlgorithm; + private Hashtable exclusionLocations; + + internal PdfSignatureAppearance(PdfStamperImp writer) { + this.writer = writer; + signDate = DateTime.Now; + fieldName = GetNewSigName(); + } + + /** + * Gets the rendering mode for this signature . + * @return the rectangle rendering mode for this signature. + */ + private SignatureRender render = SignatureRender.Description; + + public SignatureRender Render { + get { + return render; + } + set { + render = value; + } + } + + /** + * Sets the Image object to render when Render is set to SignatureRender.GraphicAndDescription + * @param image rendered. If null the mode is defaulted + * to SignatureRender.Description + */ + private Image signatureGraphic = null; + + public Image SignatureGraphic { + get { + return signatureGraphic; + } + set { + signatureGraphic = value; + } + } + + /** + * Sets the signature text identifying the signer. + * @param text the signature text identifying the signer. If null or not set + * a standard description will be used + */ + public string Layer2Text { + get { + return layer2Text; + } + set { + layer2Text = value; + } + } + + /** + * Sets the text identifying the signature status. + * @param text the text identifying the signature status. If null or not set + * the description "Signature Not Verified" will be used + */ + public string Layer4Text { + get { + return layer4Text; + } + set { + layer4Text = value; + } + } + + /** + * Gets the rectangle representing the signature dimensions. + * @return the rectangle representing the signature dimensions. It may be null + * or have zero width or height for invisible signatures + */ + public Rectangle Rect { + get { + return rect; + } + } + + /** + * Gets the visibility status of the signature. + * @return the visibility status of the signature + */ + public bool IsInvisible() { + return (rect == null || rect.Width == 0 || rect.Height == 0); + } + + /** + * Sets the cryptographic parameters. + * @param privKey the private key + * @param certChain the certificate chain + * @param crlList the certificate revocation list. It may be null + * @param filter the crytographic filter type. It can be SELF_SIGNED, VERISIGN_SIGNED or WINCER_SIGNED + */ + public void SetCrypto(ICipherParameters privKey, X509Certificate[] certChain, object[] crlList, PdfName filter) { + this.privKey = privKey; + this.certChain = certChain; + this.crlList = crlList; + this.filter = filter; + } + + /** + * Sets the signature to be visible. It creates a new visible signature field. + * @param pageRect the position and dimension of the field in the page + * @param page the page to place the field. The fist page is 1 + * @param fieldName the field name or null to generate automatically a new field name + */ + public void SetVisibleSignature(Rectangle pageRect, int page, String fieldName) { + if (fieldName != null) { + if (fieldName.IndexOf('.') >= 0) + throw new ArgumentException("Field names cannot contain a dot."); + AcroFields af = writer.AcroFields; + AcroFields.Item item = af.GetFieldItem(fieldName); + if (item != null) + throw new ArgumentException("The field " + fieldName + " already exists."); + this.fieldName = fieldName; + } + if (page < 1 || page > writer.reader.NumberOfPages) + throw new ArgumentException("Invalid page number: " + page); + this.pageRect = new Rectangle(pageRect); + this.pageRect.Normalize(); + rect = new Rectangle(this.pageRect.Width, this.pageRect.Height); + this.page = page; + newField = true; + } + + /** + * Sets the signature to be visible. An empty signature field with the same name must already exist. + * @param fieldName the existing empty signature field name + */ + public void SetVisibleSignature(String fieldName) { + AcroFields af = writer.AcroFields; + AcroFields.Item item = af.GetFieldItem(fieldName); + if (item == null) + throw new ArgumentException("The field " + fieldName + " does not exist."); + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (!PdfName.SIG.Equals(PdfReader.GetPdfObject(merged.Get(PdfName.FT)))) + throw new ArgumentException("The field " + fieldName + " is not a signature field."); + this.fieldName = fieldName; + PdfArray r = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT)); + ArrayList ar = r.ArrayList; + float llx = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[0])).FloatValue; + float lly = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[1])).FloatValue; + float urx = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[2])).FloatValue; + float ury = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[3])).FloatValue; + pageRect = new Rectangle(llx, lly, urx, ury); + pageRect.Normalize(); + page = (int)item.page[0]; + int rotation = writer.reader.GetPageRotation(page); + Rectangle pageSize = writer.reader.GetPageSizeWithRotation(page); + switch (rotation) { + case 90: + pageRect = new Rectangle( + pageRect.Bottom, + pageSize.Top - pageRect.Left, + pageRect.Top, + pageSize.Top - pageRect.Right); + break; + case 180: + pageRect = new Rectangle( + pageSize.Right - pageRect.Left, + pageSize.Top - pageRect.Bottom, + pageSize.Right - pageRect.Right, + pageSize.Top - pageRect.Top); + break; + case 270: + pageRect = new Rectangle( + pageSize.Right - pageRect.Bottom, + pageRect.Left, + pageSize.Right - pageRect.Top, + pageRect.Right); + break; + } + if (rotation != 0) + pageRect.Normalize(); + rect = new Rectangle(this.pageRect.Width, this.pageRect.Height); + } + + /** + * Gets a template layer to create a signature appearance. The layers can go from 0 to 4. + *

+ * Consult PPKAppearances.pdf + * for further details. + * @param layer the layer + * @return a template + */ + public PdfTemplate GetLayer(int layer) { + if (layer < 0 || layer >= app.Length) + return null; + PdfTemplate t = app[layer]; + if (t == null) { + t = app[layer] = new PdfTemplate(writer); + t.BoundingBox = rect; + writer.AddDirectTemplateSimple(t, new PdfName("n" + layer)); + } + return t; + } + + /** + * Gets the template that aggregates all appearance layers. This corresponds to the /FRM resource. + *

+ * Consult PPKAppearances.pdf + * for further details. + * @return the template that aggregates all appearance layers + */ + public PdfTemplate GetTopLayer() { + if (frm == null) { + frm = new PdfTemplate(writer); + frm.BoundingBox = rect; + writer.AddDirectTemplateSimple(frm, new PdfName("FRM")); + } + return frm; + } + + /** + * Gets the main appearance layer. + *

+ * Consult PPKAppearances.pdf + * for further details. + * @return the main appearance layer + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfTemplate GetAppearance() { + if (IsInvisible()) { + PdfTemplate t = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(0, 0); + writer.AddDirectTemplateSimple(t, null); + return t; + } + if (app[0] == null) { + PdfTemplate t = app[0] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(100, 100); + writer.AddDirectTemplateSimple(t, new PdfName("n0")); + t.SetLiteral("% DSBlank\n"); + } + if (app[1] == null && !acro6Layers) { + PdfTemplate t = app[1] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(100, 100); + writer.AddDirectTemplateSimple(t, new PdfName("n1")); + t.SetLiteral(questionMark); + } + if (app[2] == null) { + String text; + if (layer2Text == null) { + StringBuilder buf = new StringBuilder(); + buf.Append("Digitally signed by ").Append(PdfPKCS7.GetSubjectFields((X509Certificate)certChain[0]).GetField("CN")).Append('\n'); + buf.Append("Date: ").Append(signDate.ToString("yyyy.MM.dd HH:mm:ss zzz")); + if (reason != null) + buf.Append('\n').Append("Reason: ").Append(reason); + if (location != null) + buf.Append('\n').Append("Location: ").Append(location); + text = buf.ToString(); + } + else + text = layer2Text; + PdfTemplate t = app[2] = new PdfTemplate(writer); + t.BoundingBox = rect; + writer.AddDirectTemplateSimple(t, new PdfName("n2")); + if (image != null) { + if (imageScale == 0) { + t.AddImage(image, rect.Width, 0, 0, rect.Height, 0, 0); + } + else { + float usableScale = imageScale; + if (imageScale < 0) + usableScale = Math.Min(rect.Width / image.Width, rect.Height / image.Height); + float w = image.Width * usableScale; + float h = image.Height * usableScale; + float x = (rect.Width - w) / 2; + float y = (rect.Height - h) / 2; + t.AddImage(image, w, 0, 0, h, x, y); + } + } + Font font; + if (layer2Font == null) + font = new Font(); + else + font = new Font(layer2Font); + float size = font.Size; + + Rectangle dataRect = null; + Rectangle signatureRect = null; + + if (Render == SignatureRender.NameAndDescription || + (Render == SignatureRender.GraphicAndDescription && this.SignatureGraphic != null)) { + // origin is the bottom-left + signatureRect = new Rectangle( + MARGIN, + MARGIN, + rect.Width / 2 - MARGIN, + rect.Height - MARGIN); + dataRect = new Rectangle( + rect.Width / 2 + MARGIN / 2, + MARGIN, + rect.Width - MARGIN / 2, + rect.Height - MARGIN); + + if (rect.Height > rect.Width) { + signatureRect = new Rectangle( + MARGIN, + rect.Height / 2, + rect.Width - MARGIN, + rect.Height); + dataRect = new Rectangle( + MARGIN, + MARGIN, + rect.Width - MARGIN, + rect.Height / 2 - MARGIN); + } + } + else { + dataRect = new Rectangle( + MARGIN, + MARGIN, + rect.Width - MARGIN, + rect.Height * (1 - TOP_SECTION) - MARGIN); + } + + if (Render == SignatureRender.NameAndDescription) { + string signedBy = iTextSharp.text.pdf.PdfPKCS7.GetSubjectFields(this.certChain[0]).GetField("CN"); + Rectangle sr2 = new Rectangle(signatureRect.Width - MARGIN, signatureRect.Height - MARGIN ); + float signedSize = FitText(font, signedBy, sr2, -1, runDirection); + + ColumnText ct2 = new ColumnText(t); + ct2.RunDirection = runDirection; + ct2.SetSimpleColumn(new Phrase(signedBy, font), signatureRect.Left, signatureRect.Bottom, signatureRect.Right, signatureRect.Top, signedSize, Element.ALIGN_LEFT); + + ct2.Go(); + } + else if (Render == SignatureRender.GraphicAndDescription) { + ColumnText ct2 = new ColumnText(t); + ct2.RunDirection = runDirection; + ct2.SetSimpleColumn(signatureRect.Left, signatureRect.Bottom, signatureRect.Right, signatureRect.Top, 0, Element.ALIGN_RIGHT); + + Image im = Image.GetInstance(SignatureGraphic); + im.ScaleToFit(signatureRect.Width, signatureRect.Height); + + Paragraph p = new Paragraph(); + // must calculate the point to draw from to make image appear in middle of column + float x = 0; + // experimentation found this magic number to counteract Adobe's signature graphic, which + // offsets the y co-ordinate by 15 units + float y = -im.ScaledHeight + 15; + + x = x + (signatureRect.Width - im.ScaledWidth) / 2; + y = y - (signatureRect.Height - im.ScaledHeight) / 2; + p.Add(new Chunk(im, x + (signatureRect.Width - im.ScaledWidth) / 2, y, false)); + ct2.AddElement(p); + ct2.Go(); + } + + if (size <= 0) { + Rectangle sr = new Rectangle(dataRect.Width, dataRect.Height); + size = FitText(font, text, sr, 12, runDirection); + } + ColumnText ct = new ColumnText(t); + ct.RunDirection = runDirection; + ct.SetSimpleColumn(new Phrase(text, font), dataRect.Left, dataRect.Bottom, dataRect.Right, dataRect.Top, size, Element.ALIGN_LEFT); + ct.Go(); + + } + if (app[3] == null && !acro6Layers) { + PdfTemplate t = app[3] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(100, 100); + writer.AddDirectTemplateSimple(t, new PdfName("n3")); + t.SetLiteral("% DSBlank\n"); + } + if (app[4] == null && !acro6Layers) { + PdfTemplate t = app[4] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(0, rect.Height * (1 - TOP_SECTION), rect.Right, rect.Top); + writer.AddDirectTemplateSimple(t, new PdfName("n4")); + Font font; + if (layer2Font == null) + font = new Font(); + else + font = new Font(layer2Font); + float size = font.Size; + String text = "Signature Not Verified"; + if (layer4Text != null) + text = layer4Text; + Rectangle sr = new Rectangle(rect.Width - 2 * MARGIN, rect.Height * TOP_SECTION - 2 * MARGIN); + size = FitText(font, text, sr, 15, runDirection); + ColumnText ct = new ColumnText(t); + ct.RunDirection = runDirection; + ct.SetSimpleColumn(new Phrase(text, font), MARGIN, 0, rect.Width - MARGIN, rect.Height - MARGIN, size, Element.ALIGN_LEFT); + ct.Go(); + } + int rotation = writer.reader.GetPageRotation(page); + Rectangle rotated = new Rectangle(rect); + int n = rotation; + while (n > 0) { + rotated = rotated.Rotate(); + n -= 90; + } + if (frm == null) { + frm = new PdfTemplate(writer); + frm.BoundingBox = rotated; + writer.AddDirectTemplateSimple(frm, new PdfName("FRM")); + float scale = Math.Min(rect.Width, rect.Height) * 0.9f; + float x = (rect.Width - scale) / 2; + float y = (rect.Height - scale) / 2; + scale /= 100; + if (rotation == 90) + frm.ConcatCTM(0, 1, -1, 0, rect.Height, 0); + else if (rotation == 180) + frm.ConcatCTM(-1, 0, 0, -1, rect.Width, rect.Height); + else if (rotation == 270) + frm.ConcatCTM(0, -1, 1, 0, 0, rect.Width); + frm.AddTemplate(app[0], 0, 0); + if (!acro6Layers) + frm.AddTemplate(app[1], scale, 0, 0, scale, x, y); + frm.AddTemplate(app[2], 0, 0); + if (!acro6Layers) { + frm.AddTemplate(app[3], scale, 0, 0, scale, x, y); + frm.AddTemplate(app[4], 0, 0); + } + } + PdfTemplate napp = new PdfTemplate(writer); + napp.BoundingBox = rotated; + writer.AddDirectTemplateSimple(napp, null); + napp.AddTemplate(frm, 0, 0); + return napp; + } + + /** + * Fits the text to some rectangle adjusting the font size as needed. + * @param font the font to use + * @param text the text + * @param rect the rectangle where the text must fit + * @param maxFontSize the maximum font size + * @param runDirection the run direction + * @return the calculated font size that makes the text fit + */ + public static float FitText(Font font, String text, Rectangle rect, float maxFontSize, int runDirection) { + ColumnText ct = null; + int status = 0; + if (maxFontSize <= 0) { + int cr = 0; + int lf = 0; + char[] t = text.ToCharArray(); + for (int k = 0; k < t.Length; ++k) { + if (t[k] == '\n') + ++lf; + else if (t[k] == '\r') + ++cr; + } + int minLines = Math.Max(cr, lf) + 1; + maxFontSize = Math.Abs(rect.Height) / minLines - 0.001f; + } + font.Size = maxFontSize; + Phrase ph = new Phrase(text, font); + ct = new ColumnText(null); + ct.SetSimpleColumn(ph, rect.Left, rect.Bottom, rect.Right, rect.Top, maxFontSize, Element.ALIGN_LEFT); + ct.RunDirection = runDirection; + status = ct.Go(true); + if ((status & ColumnText.NO_MORE_TEXT) != 0) + return maxFontSize; + float precision = 0.1f; + float min = 0; + float max = maxFontSize; + float size = maxFontSize; + for (int k = 0; k < 50; ++k) { //just in case it doesn't converge + size = (min + max) / 2; + ct = new ColumnText(null); + font.Size = size; + ct.SetSimpleColumn(new Phrase(text, font), rect.Left, rect.Bottom, rect.Right, rect.Top, size, Element.ALIGN_LEFT); + ct.RunDirection = runDirection; + status = ct.Go(true); + if ((status & ColumnText.NO_MORE_TEXT) != 0) { + if (max - min < size * precision) + return size; + min = size; + } + else + max = size; + } + return size; + } + + /** + * Sets the digest/signature to an external calculated value. + * @param digest the digest. This is the actual signature + * @param RSAdata the extra data that goes into the data tag in PKCS#7 + * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest + * is also null. If the digest is not null + * then it may be "RSA" or "DSA" + */ + public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm) { + externalDigest = digest; + externalRSAdata = RSAdata; + this.digestEncryptionAlgorithm = digestEncryptionAlgorithm; + } + + /** + * Sets the signing reason. + * @param reason the signing reason + */ + public string Reason { + get { + return reason; + } + set { + reason = value; + } + } + + /** + * Sets the signing location. + * @param location the signing location + */ + public string Location { + get { + return location; + } + set { + location = value; + } + } + + /** + * Gets the private key. + * @return the private key + */ + public ICipherParameters PrivKey { + get { + return privKey; + } + } + + /** + * Gets the certificate chain. + * @return the certificate chain + */ + public X509Certificate[] CertChain { + get { + return this.certChain; + } + } + + /** + * Gets the certificate revocation list. + * @return the certificate revocation list + */ + public object[] CrlList { + get { + return this.crlList; + } + } + + /** + * Gets the filter used to sign the document. + * @return the filter used to sign the document + */ + public PdfName Filter { + get { + return filter; + } + } + + /** + * Checks if a new field was created. + * @return true if a new field was created, false if signing + * an existing field or if the signature is invisible + */ + public bool IsNewField() { + return this.newField; + } + + /** + * Gets the page number of the field. + * @return the page number of the field + */ + public int Page { + get { + return page; + } + } + + /** + * Gets the field name. + * @return the field name + */ + public String FieldName { + get { + return fieldName; + } + } + + /** + * Gets the rectangle that represent the position and dimension of the signature in the page. + * @return the rectangle that represent the position and dimension of the signature in the page + */ + public Rectangle PageRect { + get { + return pageRect; + } + } + + /** + * Gets the signature date. + * @return the signature date + */ + public DateTime SignDate { + get { + return signDate; + } + set { + signDate = value; + } + } + + internal ByteBuffer Sigout { + get { + return sigout; + } + set { + sigout = value; + } + } + + internal Stream Originalout { + get { + return originalout; + } + set { + originalout = value; + } + } + + /** + * Gets the temporary file. + * @return the temporary file or null is the document is created in memory + */ + public string TempFile { + get { + return tempFile; + } + } + + internal void SetTempFile(string tempFile) { + this.tempFile = tempFile; + } + + /** + * Gets a new signature fied name that doesn't clash with any existing name. + * @return a new signature fied name + */ + public String GetNewSigName() { + AcroFields af = writer.AcroFields; + String name = "Signature"; + int step = 0; + bool found = false; + while (!found) { + ++step; + String n1 = name + step; + if (af.GetFieldItem(n1) != null) + continue; + n1 += "."; + found = true; + foreach (String fn in af.Fields.Keys) { + if (fn.StartsWith(n1)) { + found = false; + break; + } + } + } + name += step; + return name; + } + + /** + * This is the first method to be called when using external signatures. The general sequence is: + * PreClose(), GetDocumentBytes() and Close(). + *

+ * If calling PreClose() dont't call PdfStamper.Close(). + *

+ * No external signatures are allowed if this methos is called. + * @throws IOException on error + * @throws DocumentException on error + */ + public void PreClose() { + PreClose(null); + } + /** + * This is the first method to be called when using external signatures. The general sequence is: + * PreClose(), GetDocumentBytes() and Close(). + *

+ * If calling PreClose() dont't call PdfStamper.Close(). + *

+ * If using an external signature exclusionSizes must contain at least + * the PdfName.CONTENTS key with the size that it will take in the + * document. Note that due to the hex string coding this size should be + * byte_size*2+2. + * @param exclusionSizes a Hashtable with names and sizes to be excluded in the signature + * calculation. The key is a PdfName and the value an + * Integer. At least the PdfName.CONTENTS must be present + * @throws IOException on error + * @throws DocumentException on error + */ + public void PreClose(Hashtable exclusionSizes) { + if (preClosed) + throw new DocumentException("Document already pre closed."); + preClosed = true; + AcroFields af = writer.AcroFields; + String name = FieldName; + bool fieldExists = !(IsInvisible() || IsNewField()); + PdfIndirectReference refSig = writer.PdfIndirectReference; + writer.SigFlags = 3; + if (fieldExists) { + ArrayList widgets = af.GetFieldItem(name).widgets; + PdfDictionary widget = (PdfDictionary)widgets[0]; + writer.MarkUsed(widget); + widget.Put(PdfName.P, writer.GetPageReference(Page)); + widget.Put(PdfName.V, refSig); + PdfObject obj = PdfReader.GetPdfObjectRelease(widget.Get(PdfName.F)); + int flags = 0; + if (obj != null && obj.IsNumber()) + flags = ((PdfNumber)obj).IntValue; + flags |= PdfAnnotation.FLAGS_LOCKED; + widget.Put(PdfName.F, new PdfNumber(flags)); + PdfDictionary ap = new PdfDictionary(); + ap.Put(PdfName.N, GetAppearance().IndirectReference); + widget.Put(PdfName.AP, ap); + } + else { + PdfFormField sigField = PdfFormField.CreateSignature(writer); + sigField.FieldName = name; + sigField.Put(PdfName.V, refSig); + sigField.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED; + + int pagen = Page; + if (!IsInvisible()) + sigField.SetWidget(PageRect, null); + else + sigField.SetWidget(new Rectangle(0, 0), null); + sigField.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, GetAppearance()); + sigField.Page = pagen; + writer.AddAnnotation(sigField, pagen); + } + + exclusionLocations = new Hashtable(); + if (cryptoDictionary == null) { + if (PdfName.ADOBE_PPKLITE.Equals(Filter)) + sigStandard = new PdfSigGenericPKCS.PPKLite(); + else if (PdfName.ADOBE_PPKMS.Equals(Filter)) + sigStandard = new PdfSigGenericPKCS.PPKMS(); + else if (PdfName.VERISIGN_PPKVS.Equals(Filter)) + sigStandard = new PdfSigGenericPKCS.VeriSign(); + else + throw new ArgumentException("Unknown filter: " + Filter); + sigStandard.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); + if (Reason != null) + sigStandard.Reason = Reason; + if (Location != null) + sigStandard.Location = Location; + if (Contact != null) + sigStandard.Contact = Contact; + sigStandard.Put(PdfName.M, new PdfDate(SignDate)); + sigStandard.SetSignInfo(PrivKey, CertChain, CrlList); + PdfString contents = (PdfString)sigStandard.Get(PdfName.CONTENTS); + PdfLiteral lit = new PdfLiteral((contents.ToString().Length + (PdfName.ADOBE_PPKLITE.Equals(Filter)?0:64)) * 2 + 2); + exclusionLocations[PdfName.CONTENTS] = lit; + sigStandard.Put(PdfName.CONTENTS, lit); + lit = new PdfLiteral(80); + exclusionLocations[PdfName.BYTERANGE] = lit; + sigStandard.Put(PdfName.BYTERANGE, lit); + if (certificationLevel > 0) + AddDocMDP(sigStandard); + if (signatureEvent != null) + signatureEvent.GetSignatureDictionary(sigStandard); + writer.AddToBody(sigStandard, refSig, false); + } + else { + PdfLiteral lit = new PdfLiteral(80); + exclusionLocations[PdfName.BYTERANGE] = lit; + cryptoDictionary.Put(PdfName.BYTERANGE, lit); + foreach (DictionaryEntry entry in exclusionSizes) { + PdfName key = (PdfName)entry.Key; + int v = (int)entry.Value; + lit = new PdfLiteral(v); + exclusionLocations[key] = lit; + cryptoDictionary.Put(key, lit); + } + if (certificationLevel > 0) + AddDocMDP(cryptoDictionary); + if (signatureEvent != null) + signatureEvent.GetSignatureDictionary(cryptoDictionary); + writer.AddToBody(cryptoDictionary, refSig, false); + } + if (certificationLevel > 0) { + // add DocMDP entry to root + PdfDictionary docmdp = new PdfDictionary(); + docmdp.Put(new PdfName("DocMDP"), refSig); + writer.reader.Catalog.Put(new PdfName("Perms"), docmdp); + } + writer.Close(stamper.MoreInfo); + + range = new int[exclusionLocations.Count * 2]; + int byteRangePosition = ((PdfLiteral)exclusionLocations[PdfName.BYTERANGE]).Position; + exclusionLocations.Remove(PdfName.BYTERANGE); + int idx = 1; + foreach (PdfLiteral lit in exclusionLocations.Values) { + int n = lit.Position; + range[idx++] = n; + range[idx++] = lit.PosLength + n; + } + Array.Sort(range, 1, range.Length - 2); + for (int k = 3; k < range.Length - 2; k += 2) + range[k] -= range[k - 1]; + + if (tempFile == null) { + bout = sigout.Buffer; + boutLen = sigout.Size; + range[range.Length - 1] = boutLen - range[range.Length - 2]; + ByteBuffer bf = new ByteBuffer(); + bf.Append('['); + for (int k = 0; k < range.Length; ++k) + bf.Append(range[k]).Append(' '); + bf.Append(']'); + Array.Copy(bf.Buffer, 0, bout, byteRangePosition, bf.Size); + } + else { + try { + raf = new FileStream(tempFile, FileMode.Open, FileAccess.ReadWrite); + int boutLen = (int)raf.Length; + range[range.Length - 1] = boutLen - range[range.Length - 2]; + ByteBuffer bf = new ByteBuffer(); + bf.Append('['); + for (int k = 0; k < range.Length; ++k) + bf.Append(range[k]).Append(' '); + bf.Append(']'); + raf.Seek(byteRangePosition, SeekOrigin.Begin); + raf.Write(bf.Buffer, 0, bf.Size); + } + catch (IOException e) { + try{raf.Close();}catch{} + try{File.Delete(tempFile);}catch{} + throw e; + } + } + } + + /** + * This is the last method to be called when using external signatures. The general sequence is: + * PreClose(), GetDocumentBytes() and Close(). + *

+ * update is a PdfDictionary that must have exactly the + * same keys as the ones provided in {@link #preClose(Hashtable)}. + * @param update a PdfDictionary with the key/value that will fill the holes defined + * in {@link #preClose(Hashtable)} + * @throws DocumentException on error + * @throws IOException on error + */ + public void Close(PdfDictionary update) { + try { + if (!preClosed) + throw new DocumentException("preClose() must be called first."); + ByteBuffer bf = new ByteBuffer(); + foreach (PdfName key in update.Keys) { + PdfObject obj = update.Get(key); + PdfLiteral lit = (PdfLiteral)exclusionLocations[key]; + if (lit == null) + throw new ArgumentException("The key " + key.ToString() + " didn't reserve space in PreClose()."); + bf.Reset(); + obj.ToPdf(null, bf); + if (bf.Size > lit.PosLength) + throw new ArgumentException("The key " + key.ToString() + " is too big. Is " + bf.Size + ", reserved " + lit.PosLength); + if (tempFile == null) + Array.Copy(bf.Buffer, 0, bout, lit.Position, bf.Size); + else { + raf.Seek(lit.Position, SeekOrigin.Begin); + raf.Write(bf.Buffer, 0, bf.Size); + } + } + if (update.Size != exclusionLocations.Count) + throw new ArgumentException("The update dictionary has less keys than required."); + if (tempFile == null) { + originalout.Write(bout, 0, boutLen); + } + else { + if (originalout != null) { + raf.Seek(0, SeekOrigin.Begin); + int length = (int)raf.Length; + byte[] buf = new byte[8192]; + while (length > 0) { + int r = raf.Read(buf, 0, Math.Min(buf.Length, length)); + if (r < 0) + throw new EndOfStreamException("Unexpected EOF"); + originalout.Write(buf, 0, r); + length -= r; + } + } + } + } + finally { + if (tempFile != null) { + try{raf.Close();}catch{} + if (originalout != null) + try{File.Delete(tempFile);}catch{} + } + if (originalout != null) + try{originalout.Close();}catch{} + } + } + + private void AddDocMDP(PdfDictionary crypto) { + PdfDictionary reference = new PdfDictionary(); + PdfDictionary transformParams = new PdfDictionary(); + transformParams.Put(PdfName.P, new PdfNumber(certificationLevel)); + transformParams.Put(PdfName.V, new PdfName("1.2")); + transformParams.Put(PdfName.TYPE, PdfName.TRANSFORMPARAMS); + reference.Put(PdfName.TRANSFORMMETHOD, PdfName.DOCMDP); + reference.Put(PdfName.TYPE, PdfName.SIGREF); + reference.Put(PdfName.TRANSFORMPARAMS, transformParams); + reference.Put(new PdfName("DigestValue"), new PdfString("aa")); + PdfArray loc = new PdfArray(); + loc.Add(new PdfNumber(0)); + loc.Add(new PdfNumber(0)); + reference.Put(new PdfName("DigestLocation"), loc); + reference.Put(new PdfName("DigestMethod"), new PdfName("MD5")); + reference.Put(PdfName.DATA, writer.reader.Trailer.Get(PdfName.ROOT)); + PdfArray types = new PdfArray(); + types.Add(reference); + crypto.Put(PdfName.REFERENCE, types); + } + + /** + * Gets the document bytes that are hashable when using external signatures. The general sequence is: + * PreClose(), GetRangeStream() and Close(). + *

+ * @return the document bytes that are hashable + */ + public Stream RangeStream { + get { + return new PdfSignatureAppearance.FRangeStream(raf, bout, range); + } + } + + /** + * Gets the user made signature dictionary. This is the dictionary at the /V key. + * @return the user made signature dictionary + */ + public PdfDictionary CryptoDictionary { + get { + return cryptoDictionary; + } + set { + cryptoDictionary = value; + } + } + + /** + * Gets the PdfStamper associated with this instance. + * @return the PdfStamper associated with this instance + */ + public PdfStamper Stamper { + get { + return stamper; + } + } + + internal void SetStamper(PdfStamper stamper) { + this.stamper = stamper; + } + + /** + * Checks if the document is in the process of closing. + * @return true if the document is in the process of closing, + * false otherwise + */ + public bool IsPreClosed() { + return preClosed; + } + + /** + * Gets the instance of the standard signature dictionary. This instance + * is only available after pre close. + *

+ * The main use is to insert external signatures. + * @return the instance of the standard signature dictionary + */ + public PdfSigGenericPKCS SigStandard { + get { + return sigStandard; + } + } + + /** + * Sets the signing contact. + * @param contact the signing contact + */ + public string Contact { + get { + return contact; + } + set { + contact = value; + } + } + + /** + * Sets the n2 and n4 layer font. If the font size is zero, auto-fit will be used. + * @param layer2Font the n2 and n4 font + */ + public Font Layer2Font { + get { + return layer2Font; + } + set { + layer2Font = value; + } + } + + /** + * Acrobat 6.0 and higher recomends that only layer n2 and n4 be present. This method sets that mode. + * @param acro6Layers if true only the layers n2 and n4 will be present + */ + public bool Acro6Layers { + get { + return acro6Layers; + } + set { + acro6Layers = value; + } + } + + /** Sets the run direction in the n2 and n4 layer. + * @param runDirection the run direction + */ + public int RunDirection { + set { + if (value < PdfWriter.RUN_DIRECTION_DEFAULT || value > PdfWriter.RUN_DIRECTION_RTL) + throw new ArgumentException("Invalid run direction: " + runDirection); + this.runDirection = value; + } + get { + return runDirection; + } + } + + /** + * Sets the signature event to allow modification of the signature dictionary. + * @param signatureEvent the signature event + */ + public ISignatureEvent SignatureEvent { + get { + return signatureEvent; + } + set { + signatureEvent = value; + } + } + /** + * Gets the background image for the layer 2. + * @return the background image for the layer 2 + */ + public Image GetImage() { + return this.image; + } + + /** + * Sets the background image for the layer 2. + * @param image the background image for the layer 2 + */ + public Image Image { + get { + return image; + } + set { + image = value; + } + } + + /** + * Sets the scaling to be applied to the background image. If it's zero the image + * will fully fill the rectangle. If it's less than zero the image will fill the rectangle but + * will keep the proportions. If it's greater than zero that scaling will be applied. + * In any of the cases the image will always be centered. It's zero by default. + * @param imageScale the scaling to be applied to the background image + */ + public float ImageScale { + get { + return imageScale; + } + set { + imageScale = value; + } + } + + /** + * Commands to draw a yellow question mark in a stream content + */ + public const String questionMark = + "% DSUnknown\n" + + "q\n" + + "1 G\n" + + "1 g\n" + + "0.1 0 0 0.1 9 0 cm\n" + + "0 J 0 j 4 M []0 d\n" + + "1 i \n" + + "0 g\n" + + "313 292 m\n" + + "313 404 325 453 432 529 c\n" + + "478 561 504 597 504 645 c\n" + + "504 736 440 760 391 760 c\n" + + "286 760 271 681 265 626 c\n" + + "265 625 l\n" + + "100 625 l\n" + + "100 828 253 898 381 898 c\n" + + "451 898 679 878 679 650 c\n" + + "679 555 628 499 538 435 c\n" + + "488 399 467 376 467 292 c\n" + + "313 292 l\n" + + "h\n" + + "308 214 170 -164 re\n" + + "f\n" + + "0.44 G\n" + + "1.2 w\n" + + "1 1 0.4 rg\n" + + "287 318 m\n" + + "287 430 299 479 406 555 c\n" + + "451 587 478 623 478 671 c\n" + + "478 762 414 786 365 786 c\n" + + "260 786 245 707 239 652 c\n" + + "239 651 l\n" + + "74 651 l\n" + + "74 854 227 924 355 924 c\n" + + "425 924 653 904 653 676 c\n" + + "653 581 602 525 512 461 c\n" + + "462 425 441 402 441 318 c\n" + + "287 318 l\n" + + "h\n" + + "282 240 170 -164 re\n" + + "B\n" + + "Q\n"; + + /** + * Holds value of property contact. + */ + private String contact; + + /** + * Holds value of property layer2Font. + */ + private Font layer2Font; + + /** + * Holds value of property layer4Text. + */ + private String layer4Text; + + /** + * Holds value of property acro6Layers. + */ + private bool acro6Layers; + + /** + * Holds value of property runDirection. + */ + private int runDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; + + /** + * Holds value of property signatureEvent. + */ + private ISignatureEvent signatureEvent; + + /** + * Holds value of property image. + */ + private Image image; + + /** + * Holds value of property imageScale. + */ + private float imageScale; + + /** + * + */ + public class FRangeStream : Stream { + private byte[] b = new byte[1]; + private FileStream raf; + private byte[] bout; + private int[] range; + private int rangePosition = 0; + + internal FRangeStream(FileStream raf, byte[] bout, int[] range) { + this.raf = raf; + this.bout = bout; + this.range = range; + } + + /** + * @see java.io.Stream#read() + */ + public override int ReadByte() { + int n = Read(b, 0, 1); + if (n != 1) + return -1; + return b[0] & 0xff; + } + + /** + * @see java.io.Stream#read(byte[], int, int) + */ + public override int Read(byte[] b, int off, int len) { + if (b == null) { + throw new ArgumentNullException(); + } else if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0)) { + throw new ArgumentOutOfRangeException(); + } else if (len == 0) { + return 0; + } + if (rangePosition >= range[range.Length - 2] + range[range.Length - 1]) { + return -1; + } + for (int k = 0; k < range.Length; k += 2) { + int start = range[k]; + int end = start + range[k + 1]; + if (rangePosition < start) + rangePosition = start; + if (rangePosition >= start && rangePosition < end) { + int lenf = Math.Min(len, end - rangePosition); + if (raf == null) + Array.Copy(bout, rangePosition, b, off, lenf); + else { + raf.Seek(rangePosition, SeekOrigin.Begin); + ReadFully(b, off, lenf); + } + rangePosition += lenf; + return lenf; + } + } + return -1; + } + + private void ReadFully(byte[] b, int offset, int count) { + while (count > 0) { + int n = raf.Read(b, offset, count); + if (n <= 0) + throw new IOException("Insufficient data."); + count -= n; + offset += n; + } + } + + public override bool CanRead { + get { + return true; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return false; + } + } + + public override long Length { + get { + return 0; + } + } + + public override long Position { + get { + return 0; + } + set { + } + } + + public override void Flush() { + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + } + + public override void WriteByte(byte value) { + } + } + + /** + * An interface to retrieve the signature dictionary for modification. + */ + public interface ISignatureEvent { + /** + * Allows modification of the signature dictionary. + * @param sig the signature dictionary + */ + void GetSignatureDictionary(PdfDictionary sig); + } + + private int certificationLevel = NOT_CERTIFIED; + + /** + * Sets the document type to certified instead of simply signed. + * @param certificationLevel the values can be: NOT_CERTIFIED, CERTIFIED_NO_CHANGES_ALLOWED, + * CERTIFIED_FORM_FILLING and CERTIFIED_FORM_FILLING_AND_ANNOTATIONS + */ + public int CertificationLevel { + get { + return certificationLevel; + } + set { + certificationLevel = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs b/iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs new file mode 100644 index 0000000..1311cfa --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs @@ -0,0 +1,228 @@ +using System; +using System.IO; +using System.Collections; +using System.Security.Cryptography; +using iTextSharp.text; +/* + * $Id: PdfSmartCopy.cs,v 1.7 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2007 Michael Neuweiler and Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * This class was written by Michael Neuweiler based on hints given by Bruno Lowagie + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * PdfSmartCopy has the same functionality as PdfCopy, + * but when resources (such as fonts, images,...) are + * encountered, a reference to these resources is saved + * in a cache, so that they can be reused. + * This requires more memory, but reduces the file size + * of the resulting PDF document. + */ + + public class PdfSmartCopy : PdfCopy { + + /** the cache with the streams and references. */ + private Hashtable streamMap = null; + + /** Creates a PdfSmartCopy instance. */ + public PdfSmartCopy(Document document, Stream os) : base(document, os) { + this.streamMap = new Hashtable(); + } + /** + * Translate a PRIndirectReference to a PdfIndirectReference + * In addition, translates the object numbers, and copies the + * referenced object to the output file if it wasn't available + * in the cache yet. If it's in the cache, the reference to + * the already used stream is returned. + * + * NB: PRIndirectReferences (and PRIndirectObjects) really need to know what + * file they came from, because each file has its own namespace. The translation + * we do from their namespace to ours is *at best* heuristic, and guaranteed to + * fail under some circumstances. + */ + protected override PdfIndirectReference CopyIndirect(PRIndirectReference inp) { + PdfObject srcObj = PdfReader.GetPdfObjectRelease(inp); + ByteStore streamKey = null; + bool validStream = false; + if (srcObj.IsStream()) { + streamKey = new ByteStore((PRStream)srcObj); + validStream = true; + PdfIndirectReference streamRef = (PdfIndirectReference) streamMap[streamKey]; + if (streamRef != null) { + return streamRef; + } + } + + PdfIndirectReference theRef; + RefKey key = new RefKey(inp); + IndirectReferences iRef = (IndirectReferences) indirects[key]; + if (iRef != null) { + theRef = iRef.Ref; + if (iRef.Copied) { + return theRef; + } + } else { + theRef = body.PdfIndirectReference; + iRef = new IndirectReferences(theRef); + indirects[key] = iRef; + } + if (srcObj != null && srcObj.IsDictionary()) { + PdfObject type = PdfReader.GetPdfObjectRelease(((PdfDictionary)srcObj).Get(PdfName.TYPE)); + if (type != null && PdfName.PAGE.Equals(type)) { + return theRef; + } + } + iRef.SetCopied(); + + if (validStream) { + streamMap[streamKey] = theRef; + } + + PdfObject obj = CopyObject(srcObj); + AddToBody(obj, theRef); + return theRef; + } + + internal class ByteStore { + private byte[] b; + private int hash; + private MD5 md5; + + private void SerObject(PdfObject obj, int level, ByteBuffer bb) { + if (level <= 0) + return; + if (obj == null) { + bb.Append("$Lnull"); + return; + } + obj = PdfReader.GetPdfObject(obj); + if (obj.IsStream()) { + bb.Append("$B"); + SerDic((PdfDictionary)obj, level - 1, bb); + if (level > 0) { + md5.Initialize(); + bb.Append(md5.ComputeHash(PdfReader.GetStreamBytesRaw((PRStream)obj))); + } + } + else if (obj.IsDictionary()) { + SerDic((PdfDictionary)obj, level - 1, bb); + } + else if (obj.IsArray()) { + SerArray((PdfArray)obj, level - 1, bb); + } + else if (obj.IsString()) { + bb.Append("$S").Append(obj.ToString()); + } + else if (obj.IsName()) { + bb.Append("$N").Append(obj.ToString()); + } + else + bb.Append("$L").Append(obj.ToString()); + } + + private void SerDic(PdfDictionary dic, int level, ByteBuffer bb) { + bb.Append("$D"); + if (level <= 0) + return; + Object[] keys = new Object[dic.Size]; + dic.Keys.CopyTo(keys, 0); + Array.Sort(keys); + for (int k = 0; k < keys.Length; ++k) { + SerObject((PdfObject)keys[k], level, bb); + SerObject(dic.Get((PdfName)keys[k]), level, bb); + } + } + + private void SerArray(PdfArray array, int level, ByteBuffer bb) { + bb.Append("$A"); + if (level <= 0) + return; + ArrayList ar = array.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + SerObject((PdfObject)ar[k], level, bb); + } + } + + internal ByteStore(PRStream str) { + md5 = new MD5CryptoServiceProvider(); + ByteBuffer bb = new ByteBuffer(); + int level = 10; + SerObject(str, level, bb); + this.b = bb.ToByteArray(); + md5 = null; + } + + public override bool Equals(Object obj) { + if (obj == null || !(obj is ByteStore)) + return false; + if (GetHashCode() != obj.GetHashCode()) + return false; + byte[] b2 = ((ByteStore)obj).b; + if (b2.Length != b.Length) + return false; + int len = b.Length; + for (int k = 0; k < len; ++k) { + if (b[k] != b2[k]) + return false; + } + return true; + } + + public override int GetHashCode() { + if (hash == 0) { + int len = b.Length; + for (int k = 0; k < len; ++k) { + hash = hash * 31 + b[k]; + } + } + return hash; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs b/iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs new file mode 100644 index 0000000..0cfe5de --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs @@ -0,0 +1,126 @@ +using System; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfSpotColor defines a ColorSpace + * + * @see PdfDictionary + */ + + public class PdfSpotColor{ + + /* The tint value */ + protected float tint; + + /* The color name */ + public PdfName name; + + /* The alternative color space */ + public Color altcs; + // constructors + + /** + * Constructs a new PdfSpotColor. + * + * @param name a string value + * @param tint a tint value between 0 and 1 + * @param altcs a altnative colorspace value + */ + + public PdfSpotColor(string name, float tint, Color altcs) { + this.name = new PdfName(name); + this.tint = tint; + this.altcs = altcs; + } + + public float Tint { + get { + return tint; + } + } + + public Color AlternativeCS { + get { + return altcs; + } + } + + protected internal PdfObject GetSpotObject(PdfWriter writer) { + PdfArray array = new PdfArray(PdfName.SEPARATION); + array.Add(name); + PdfFunction func = null; + if (altcs is ExtendedColor) { + int type = ((ExtendedColor)altcs).Type; + switch (type) { + case ExtendedColor.TYPE_GRAY: + array.Add(PdfName.DEVICEGRAY); + func = PdfFunction.Type2(writer, new float[]{0, 1}, null, new float[]{0}, new float[]{((GrayColor)altcs).Gray}, 1); + break; + case ExtendedColor.TYPE_CMYK: + array.Add(PdfName.DEVICECMYK); + CMYKColor cmyk = (CMYKColor)altcs; + func = PdfFunction.Type2(writer, new float[]{0, 1}, null, new float[]{0, 0, 0, 0}, + new float[]{cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black}, 1); + break; + default: + throw new Exception("Only RGB, Gray and CMYK are supported as alternative color spaces."); + } + } + else { + array.Add(PdfName.DEVICERGB); + func = PdfFunction.Type2(writer, new float[]{0, 1}, null, new float[]{1, 1, 1}, + new float[]{(float)altcs.R / 255, (float)altcs.G / 255, (float)altcs.B / 255}, 1); + } + array.Add(func.Reference); + return array; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStamper.cs b/iTechSharp/iTextSharp/text/pdf/PdfStamper.cs new file mode 100644 index 0000000..4ec5833 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStamper.cs @@ -0,0 +1,742 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.pdf.interfaces; +using iTextSharp.text.pdf.collection; +using Org.BouncyCastle.X509; +/* + * Copyright 2003, 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Applies extra content to the pages of a PDF document. + * This extra content can be all the objects allowed in PdfContentByte + * including pages from other Pdfs. The original PDF will keep + * all the interactive elements including bookmarks, links and form fields. + *

+ * It is also possible to change the field values and to + * flatten them. New fields can be added but not flattened. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfStamper : IPdfViewerPreferences, IPdfEncryptionSettings { + /** + * The writer + */ + protected PdfStamperImp stamper; + private Hashtable moreInfo; + private bool hasSignature; + private PdfSignatureAppearance sigApp; + + /** Starts the process of adding extra content to an existing PDF + * document. + * @param reader the original document. It cannot be reused + * @param os the output stream + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfStamper(PdfReader reader, Stream os) { + stamper = new PdfStamperImp(reader, os, '\0', false); + } + + /** + * Starts the process of adding extra content to an existing PDF + * document. + * @param reader the original document. It cannot be reused + * @param os the output stream + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfStamper(PdfReader reader, Stream os, char pdfVersion) { + stamper = new PdfStamperImp(reader, os, pdfVersion, false); + } + + /** + * Starts the process of adding extra content to an existing PDF + * document, possibly as a new revision. + * @param reader the original document. It cannot be reused + * @param os the output stream + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param append if true appends the document changes as a new revision. This is + * only useful for multiple signatures as nothing is gained in speed or memory + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfStamper(PdfReader reader, Stream os, char pdfVersion, bool append) { + stamper = new PdfStamperImp(reader, os, pdfVersion, append); + } + + /** Gets the optional String map to add or change values in + * the info dictionary. + * @return the map or null + * + */ + /** An optional String map to add or change values in + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @param moreInfo additional entries to the info dictionary + * + */ + public Hashtable MoreInfo { + set { + moreInfo = value; + } + get { + return moreInfo; + } + } + + /** + * Replaces a page from this document with a page from other document. Only the content + * is replaced not the fields and annotations. This method must be called before + * getOverContent() or getUndercontent() are called for the same page. + * @param r the PdfReader from where the new page will be imported + * @param pageImported the page number of the imported page + * @param pageReplaced the page to replace in this document + */ + public void ReplacePage(PdfReader r, int pageImported, int pageReplaced) { + stamper.ReplacePage(r, pageImported, pageReplaced); + } + + /** + * Inserts a blank page. All the pages above and including pageNumber will + * be shifted up. If pageNumber is bigger than the total number of pages + * the new page will be the last one. + * @param pageNumber the page number position where the new page will be inserted + * @param mediabox the size of the new page + */ + public void InsertPage(int pageNumber, Rectangle mediabox) { + stamper.InsertPage(pageNumber, mediabox); + } + + /** + * Gets the signing instance. The appearances and other parameters can the be set. + * @return the signing instance + */ + public PdfSignatureAppearance SignatureAppearance { + get { + return sigApp; + } + } + + /** + * Closes the document. No more content can be written after the + * document is closed. + *

+ * If closing a signed document with an external signature the closing must be done + * in the PdfSignatureAppearance instance. + * @throws DocumentException on error + * @throws IOException on error + */ + public void Close() { + if (!hasSignature) { + stamper.Close(moreInfo); + return; + } + sigApp.PreClose(); + PdfSigGenericPKCS sig = sigApp.SigStandard; + PdfLiteral lit = (PdfLiteral)sig.Get(PdfName.CONTENTS); + int totalBuf = (lit.PosLength - 2) / 2; + byte[] buf = new byte[8192]; + int n; + Stream inp = sigApp.RangeStream; + while ((n = inp.Read(buf, 0, buf.Length)) > 0) { + sig.Signer.Update(buf, 0, n); + } + buf = new byte[totalBuf]; + byte[] bsig = sig.SignerContents; + Array.Copy(bsig, 0, buf, 0, bsig.Length); + PdfString str = new PdfString(buf); + str.SetHexWriting(true); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.CONTENTS, str); + sigApp.Close(dic); + stamper.reader.Close(); + } + + /** Gets a PdfContentByte to write under the page of + * the original document. + * @param pageNum the page number where the extra content is written + * @return a PdfContentByte to write under the page of + * the original document + */ + public PdfContentByte GetUnderContent(int pageNum) { + return stamper.GetUnderContent(pageNum); + } + + /** Gets a PdfContentByte to write over the page of + * the original document. + * @param pageNum the page number where the extra content is written + * @return a PdfContentByte to write over the page of + * the original document + */ + public PdfContentByte GetOverContent(int pageNum) { + return stamper.GetOverContent(pageNum); + } + + /** Checks if the content is automatically adjusted to compensate + * the original page rotation. + * @return the auto-rotation status + */ + /** Flags the content to be automatically adjusted to compensate + * the original page rotation. The default is true. + * @param rotateContents true to set auto-rotation, false + * otherwise + */ + public bool RotateContents { + set { + stamper.RotateContents = value; + } + get { + return stamper.RotateContents; + } + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException if anything was already written to the output + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + if (stamper.append) + throw new DocumentException("Append mode does not support changing the encryption status."); + if (stamper.ContentWritten) + throw new DocumentException("Content was already written to the output."); + stamper.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? PdfWriter.STANDARD_ENCRYPTION_128 : PdfWriter.STANDARD_ENCRYPTION_40); + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { + if (stamper.IsAppend()) + throw new DocumentException("Append mode does not support changing the encryption status."); + if (stamper.ContentWritten) + throw new DocumentException("Content was already written to the output."); + stamper.SetEncryption(userPassword, ownerPassword, permissions, encryptionType); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if anything was already written to the output + */ + public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { + SetEncryption(DocWriter.GetISOBytes(userPassword), DocWriter.GetISOBytes(ownerPassword), permissions, strength); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(int encryptionType, String userPassword, String ownerPassword, int permissions) { + SetEncryption(DocWriter.GetISOBytes(userPassword), DocWriter.GetISOBytes(ownerPassword), permissions, encryptionType); + } + + /** + * Sets the certificate encryption options for this document. An array of one or more public certificates + * must be provided together with an array of the same size for the permissions for each certificate. + * The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param certs the public certificates to be used for the encryption + * @param permissions the user permissions for each of the certicates + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * @throws DocumentException if the encryption was set too late + */ + public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { + if (stamper.IsAppend()) + throw new DocumentException("Append mode does not support changing the encryption status."); + if (stamper.ContentWritten) + throw new DocumentException("Content was already written to the output."); + stamper.SetEncryption(certs, permissions, encryptionType); + } + + /** Gets a page from other PDF document. Note that calling this method more than + * once with the same parameters will retrieve the same object. + * @param reader the PDF document where the page is + * @param pageNumber the page number. The first page is 1 + * @return the template representing the imported page + */ + public PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { + return stamper.GetImportedPage(reader, pageNumber); + } + + /** Gets the underlying PdfWriter. + * @return the underlying PdfWriter + */ + public PdfWriter Writer { + get { + return stamper; + } + } + + /** Gets the underlying PdfReader. + * @return the underlying PdfReader + */ + public PdfReader Reader { + get { + return stamper.reader; + } + } + + /** Gets the AcroFields object that allows to get and set field values + * and to merge FDF forms. + * @return the AcroFields object + */ + public AcroFields AcroFields { + get { + return stamper.AcroFields; + } + } + + /** Determines if the fields are flattened on close. The fields added with + * {@link #addAnnotation(PdfAnnotation,int)} will never be flattened. + * @param flat true to flatten the fields, false + * to keep the fields + */ + public bool FormFlattening { + set { + stamper.FormFlattening = value; + } + } + + /** Determines if the FreeText annotations are flattened on close. + * @param flat true to flatten the FreeText annotations, false + * (the default) to keep the FreeText annotations as active content. + */ + public bool FreeTextFlattening { + set { + stamper.FreeTextFlattening = value; + } + } + /** + * Adds an annotation of form field in a specific page. This page number + * can be overridden with {@link PdfAnnotation#setPlaceInPage(int)}. + * @param annot the annotation + * @param page the page + */ + public void AddAnnotation(PdfAnnotation annot, int page) { + stamper.AddAnnotation(annot, page); + } + + /** + * Adds the comments present in an FDF file. + * @param fdf the FDF file + * @throws IOException on error + */ + public void AddComments(FdfReader fdf) { + stamper.AddComments(fdf); + } + + /** + * Sets the bookmarks. The list structure is defined in + * {@link SimpleBookmark}. + * @param outlines the bookmarks or null to remove any + */ + public ArrayList Outlines { + set { + stamper.Outlines = value; + } + } + + /** + * Sets the thumbnail image for a page. + * @param image the image + * @param page the page + * @throws PdfException on error + * @throws DocumentException on error + */ + public void SetThumbnail(Image image, int page) { + stamper.SetThumbnail(image, page); + } + + /** + * Adds name to the list of fields that will be flattened on close, + * all the other fields will remain. If this method is never called or is called + * with invalid field names, all the fields will be flattened. + *

+ * Calling setFormFlattening(true) is needed to have any kind of + * flattening. + * @param name the field name + * @return true if the field exists, false otherwise + */ + public bool PartialFormFlattening(String name) { + return stamper.PartialFormFlattening(name); + } + + /** Adds a JavaScript action at the document level. When the document + * opens all this JavaScript runs. The existing JavaScript will be replaced. + * @param js the JavaScript code + */ + public string JavaScript { + set { + stamper.AddJavaScript(value, !PdfEncodings.IsPdfDocEncoding(value)); + } + } + + /** Adds a file attachment at the document level. Existing attachments will be kept. + * @param description the file description + * @param fileStore an array with the file. If it's null + * the file will be read from the disk + * @param file the path to the file. It will only be used if + * fileStore is not null + * @param fileDisplay the actual file name stored in the pdf + * @throws IOException on error + */ + public void AddFileAttachment(String description, byte[] fileStore, String file, String fileDisplay) { + AddFileAttachment(description, PdfFileSpecification.FileEmbedded(stamper, file, fileDisplay, fileStore)); + } + + /** Adds a file attachment at the document level. Existing attachments will be kept. + * @param description the file description + * @param fs the file specification + */ + public void AddFileAttachment(String description, PdfFileSpecification fs) { + stamper.AddFileAttachment(description, fs); + } + + /** + * This is the most simple way to change a PDF into a + * portable collection. Choose one of the following names: + *

    + *
  • PdfName.D (detailed view) + *
  • PdfName.T (tiled view) + *
  • PdfName.H (hidden) + *
+ * Pass this name as a parameter and your PDF will be + * a portable collection with all the embedded and + * attached files as entries. + * @param initialView can be PdfName.D, PdfName.T or PdfName.H + */ + public void MakePackage( PdfName initialView ) { + PdfCollection collection = new PdfCollection(0); + collection.Put(PdfName.VIEW, initialView); + stamper.MakePackage( collection ); + } + + /** + * Adds or replaces the Collection Dictionary in the Catalog. + * @param collection the new collection dictionary. + */ + public void MakePackage(PdfCollection collection) { + stamper.MakePackage(collection); + } + + /** + * Sets the viewer preferences. + * @param preferences the viewer preferences + * @see PdfViewerPreferences#setViewerPreferences(int) + */ + public virtual int ViewerPreferences { + set { + stamper.ViewerPreferences = value; + } + } + + /** Adds a viewer preference + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + stamper.AddViewerPreference(key, value); + } + + /** + * Sets the XMP metadata. + * @param xmp + * @see PdfWriter#setXmpMetadata(byte[]) + */ + public byte[] XmpMetadata { + set { + stamper.XmpMetadata = value; + } + } + + /** + * Gets the 1.5 compression status. + * @return true if the 1.5 compression is on + */ + public bool FullCompression { + get { + return stamper.FullCompression; + } + } + + /** + * Sets the document's compression to the new 1.5 mode with object streams and xref + * streams. It can be set at any time but once set it can't be unset. + */ + public void SetFullCompression() { + if (stamper.append) + return; + stamper.SetFullCompression(); + } + + /** + * Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @param page the page where the action will be applied. The first page is 1 + * @throws PdfException if the action type is invalid + */ + public void SetPageAction(PdfName actionType, PdfAction action, int page) { + stamper.SetPageAction(actionType, action, page); + } + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page. A negative value removes the entry + * @param page the page where the duration will be applied. The first page is 1 + */ + public void SetDuration(int seconds, int page) { + stamper.SetDuration(seconds, page); + } + + /** + * Sets the transition for the page + * @param transition the transition object. A null removes the transition + * @param page the page where the transition will be applied. The first page is 1 + */ + public void SetTransition(PdfTransition transition, int page) { + stamper.SetTransition(transition, page); + } + + /** + * Applies a digital signature to a document, possibly as a new revision, making + * possible multiple signatures. The returned PdfStamper + * can be used normally as the signature is only applied when closing. + *

+ * A possible use for adding a signature without invalidating an existing one is: + *

+ *

+        * KeyStore ks = KeyStore.getInstance("pkcs12");
+        * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
+        * String alias = (String)ks.aliases().nextElement();
+        * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
+        * Certificate[] chain = ks.getCertificateChain(alias);
+        * PdfReader reader = new PdfReader("original.pdf");
+        * FileOutputStream fout = new FileOutputStream("signed.pdf");
+        * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', new
+        * File("/temp"), true);
+        * PdfSignatureAppearance sap = stp.getSignatureAppearance();
+        * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
+        * sap.setReason("I'm the author");
+        * sap.setLocation("Lisbon");
+        * // comment next line to have an invisible signature
+        * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
+        * stp.close();
+        * 
+ * @param reader the original document + * @param os the output stream or null to keep the document in the temporary file + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there. + * If it's a file it will be used directly. The file will be deleted on exit unless os is null. + * In that case the document can be retrieved directly from the temporary file. If it's null + * no temporary file will be created and memory will be used + * @param append if true the signature and all the other content will be added as a + * new revision thus not invalidating existing signatures + * @return a PdfStamper + * @throws DocumentException on error + * @throws IOException on error + */ + public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion, string tempFile, bool append) { + PdfStamper stp; + if (tempFile == null) { + ByteBuffer bout = new ByteBuffer(); + stp = new PdfStamper(reader, bout, pdfVersion, append); + stp.sigApp = new PdfSignatureAppearance(stp.stamper); + stp.sigApp.Sigout = bout; + } + else { + if (Directory.Exists(tempFile)) + tempFile = Path.GetTempFileName(); + FileStream fout = new FileStream(tempFile, FileMode.Create, FileAccess.Write); + stp = new PdfStamper(reader, fout, pdfVersion, append); + stp.sigApp = new PdfSignatureAppearance(stp.stamper); + stp.sigApp.SetTempFile(tempFile); + } + stp.sigApp.Originalout = os; + stp.sigApp.SetStamper(stp); + stp.hasSignature = true; + PdfDictionary catalog = reader.Catalog; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); + if (acroForm != null) { + acroForm.Remove(PdfName.NEEDAPPEARANCES); + stp.stamper.MarkUsed(acroForm); + } + return stp; + } + + /** + * Applies a digital signature to a document. The returned PdfStamper + * can be used normally as the signature is only applied when closing. + *

+ * Note that the pdf is created in memory. + *

+ * A possible use is: + *

+ *

+        * KeyStore ks = KeyStore.getInstance("pkcs12");
+        * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
+        * String alias = (String)ks.aliases().nextElement();
+        * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
+        * Certificate[] chain = ks.getCertificateChain(alias);
+        * PdfReader reader = new PdfReader("original.pdf");
+        * FileOutputStream fout = new FileOutputStream("signed.pdf");
+        * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
+        * PdfSignatureAppearance sap = stp.getSignatureAppearance();
+        * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
+        * sap.setReason("I'm the author");
+        * sap.setLocation("Lisbon");
+        * // comment next line to have an invisible signature
+        * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
+        * stp.close();
+        * 
+ * @param reader the original document + * @param os the output stream + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @throws DocumentException on error + * @throws IOException on error + * @return a PdfStamper + */ + public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion) { + return CreateSignature(reader, os, pdfVersion, null, false); + } + + /** + * Applies a digital signature to a document. The returned PdfStamper + * can be used normally as the signature is only applied when closing. + *

+ * A possible use is: + *

+ *

+        * KeyStore ks = KeyStore.getInstance("pkcs12");
+        * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
+        * String alias = (String)ks.aliases().nextElement();
+        * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
+        * Certificate[] chain = ks.getCertificateChain(alias);
+        * PdfReader reader = new PdfReader("original.pdf");
+        * FileOutputStream fout = new FileOutputStream("signed.pdf");
+        * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', new File("/temp"));
+        * PdfSignatureAppearance sap = stp.getSignatureAppearance();
+        * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
+        * sap.setReason("I'm the author");
+        * sap.setLocation("Lisbon");
+        * // comment next line to have an invisible signature
+        * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
+        * stp.close();
+        * 
+ * @param reader the original document + * @param os the output stream or null to keep the document in the temporary file + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there. + * If it's a file it will be used directly. The file will be deleted on exit unless os is null. + * In that case the document can be retrieved directly from the temporary file. If it's null + * no temporary file will be created and memory will be used + * @return a PdfStamper + * @throws DocumentException on error + * @throws IOException on error + */ + public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion, string tempFile) { + return CreateSignature(reader, os, pdfVersion, tempFile, false); + } + + /** + * Gets the PdfLayer objects in an existing document as a Map + * with the names/titles of the layers as keys. + * @return a Map with all the PdfLayers in the document (and the name/title of the layer as key) + * @since 2.1.2 + */ + public Hashtable GetPdfLayers() { + return stamper.GetPdfLayers(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs b/iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs new file mode 100644 index 0000000..a99a24f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs @@ -0,0 +1,1625 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using iTextSharp.text.pdf.interfaces; +using iTextSharp.text.pdf.intern; +using iTextSharp.text.pdf.collection; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PdfStamperImp : PdfWriter { + internal Hashtable readers2intrefs = new Hashtable(); + internal Hashtable readers2file = new Hashtable(); + internal RandomAccessFileOrArray file; + internal PdfReader reader; + internal IntHashtable myXref = new IntHashtable(); + /** Integer(page number) -> PageStamp */ + internal Hashtable pagesToContent = new Hashtable(); + internal bool closed = false; + /** Holds value of property rotateContents. */ + private bool rotateContents = true; + protected AcroFields acroFields; + protected bool flat = false; + protected bool flatFreeText = false; + protected int[] namePtr = {0}; + protected Hashtable partialFlattening = new Hashtable(); + protected bool useVp = false; + protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); + protected Hashtable fieldTemplates = new Hashtable(); + protected bool fieldsAdded = false; + protected int sigFlags = 0; + protected internal bool append; + protected IntHashtable marked; + protected int initialXrefSize; + protected PdfAction openAction; + + /** Creates new PdfStamperImp. + * @param reader the read PDF + * @param os the output destination + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param append + * @throws DocumentException on error + * @throws IOException + */ + internal PdfStamperImp(PdfReader reader, Stream os, char pdfVersion, bool append) : base(new PdfDocument(), os) { + if (!reader.IsOpenedWithFullPermissions) + throw new ArgumentException("PdfReader not opened with owner password"); + if (reader.Tampered) + throw new DocumentException("The original document was reused. Read it again from file."); + reader.Tampered = true; + this.reader = reader; + file = reader.SafeFile; + this.append = append; + if (append) { + if (reader.IsRebuilt()) + throw new DocumentException("Append mode requires a document without errors even if recovery was possible."); + if (reader.IsEncrypted()) + crypto = new PdfEncryption(reader.Decrypt); + pdf_version.SetAppendmode(true); + file.ReOpen(); + byte[] buf = new byte[8192]; + int n; + while ((n = file.Read(buf)) > 0) + this.os.Write(buf, 0, n); + file.Close(); + prevxref = reader.LastXref; + reader.Appendable = true; + } + else { + if (pdfVersion == 0) + base.PdfVersion = reader.PdfVersion; + else + base.PdfVersion = pdfVersion; + } + base.Open(); + pdf.AddWriter(this); + if (append) { + body.Refnum = reader.XrefSize; + marked = new IntHashtable(); + if (reader.IsNewXrefType()) + fullCompression = true; + if (reader.IsHybridXref()) + fullCompression = false; + } + initialXrefSize = reader.XrefSize; + } + + internal void Close(Hashtable moreInfo) { + if (closed) + return; + if (useVp) { + reader.SetViewerPreferences(viewerPreferences); + MarkUsed(reader.Trailer.Get(PdfName.ROOT)); + } + if (flat) + FlatFields(); + if (flatFreeText) + FlatFreeTextFields(); + AddFieldResources(); + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM), reader.Catalog); + if (acroFields != null && acroFields.Xfa.Changed) { + MarkUsed(acroForm); + if (!flat) + acroFields.Xfa.SetXfa(this); + } + if (sigFlags != 0) { + if (acroForm != null) { + acroForm.Put(PdfName.SIGFLAGS, new PdfNumber(sigFlags)); + MarkUsed(acroForm); + } + } + closed = true; + AddSharedObjectsToBody(); + SetOutlines(); + SetJavaScript(); + AddFileAttachments(); + PdfDictionary catalog = reader.Catalog; + if (openAction != null) { + catalog.Put(PdfName.OPENACTION, openAction); + } + if (pdf.pageLabels != null) + catalog.Put(PdfName.PAGELABELS, pdf.pageLabels.GetDictionary(this)); + byte[] altMetadata = null; + PdfObject xmpo = PdfReader.GetPdfObject(catalog.Get(PdfName.METADATA)); + if (xmpo != null && xmpo.IsStream()) { + altMetadata = PdfReader.GetStreamBytesRaw((PRStream)xmpo); + PdfReader.KillIndirect(catalog.Get(PdfName.METADATA)); + } + if (xmpMetadata != null) { + altMetadata = xmpMetadata; + } + // if there is XMP data to add: add it + if (altMetadata != null) { + PdfStream xmp = new PdfStream(altMetadata); + xmp.Put(PdfName.TYPE, PdfName.METADATA); + xmp.Put(PdfName.SUBTYPE, PdfName.XML); + if (crypto != null && !crypto.IsMetadataEncrypted()) { + PdfArray ar = new PdfArray(); + ar.Add(PdfName.CRYPT); + xmp.Put(PdfName.FILTER, ar); + } + catalog.Put(PdfName.METADATA, body.Add(xmp).IndirectReference); + MarkUsed(catalog); + } + if (documentOCG.Count != 0) { + FillOCProperties(false); + PdfDictionary ocdict = catalog.GetAsDict(PdfName.OCPROPERTIES); + if (ocdict == null) { + reader.Catalog.Put(PdfName.OCPROPERTIES, OCProperties); + } + else { + ocdict.Put(PdfName.OCGS, OCProperties.Get(PdfName.OCGS)); + PdfDictionary ddict = ocdict.GetAsDict(PdfName.D); + ddict.Put(PdfName.ORDER, OCProperties.GetAsDict(PdfName.D).Get(PdfName.ORDER)); + ddict.Put(PdfName.RBGROUPS, OCProperties.GetAsDict(PdfName.D).Get(PdfName.RBGROUPS)); + ddict.Put(PdfName.OFF, OCProperties.GetAsDict(PdfName.D).Get(PdfName.OFF)); + ddict.Put(PdfName.AS, OCProperties.GetAsDict(PdfName.D).Get(PdfName.AS)); + } + } + PRIndirectReference iInfo = null; + try { + file.ReOpen(); + AlterContents(); + iInfo = (PRIndirectReference)reader.trailer.Get(PdfName.INFO); + int skip = -1; + if (iInfo != null) + skip = iInfo.Number; + int rootN = ((PRIndirectReference)reader.trailer.Get(PdfName.ROOT)).Number; + if (append) { + int[] keys = marked.GetKeys(); + for (int k = 0; k < keys.Length; ++k) { + int j = keys[k]; + PdfObject obj = reader.GetPdfObjectRelease(j); + if (obj != null && skip != j && j < initialXrefSize) { + AddToBody(obj, j, j != rootN); + } + } + for (int k = initialXrefSize; k < reader.XrefSize; ++k) { + PdfObject obj = reader.GetPdfObject(k); + if (obj != null) { + AddToBody(obj, GetNewObjectNumber(reader, k, 0)); + } + } + } + else { + for (int k = 1; k < reader.XrefSize; ++k) { + PdfObject obj = reader.GetPdfObjectRelease(k); + if (obj != null && skip != k) { + AddToBody(obj, GetNewObjectNumber(reader, k, 0), k != rootN); + } + } + } + } + finally { + try { + file.Close(); + } + catch { + // empty on purpose + } + } + PdfIndirectReference encryption = null; + PdfObject fileID = null; + if (crypto != null) { + if (append) { + encryption = reader.GetCryptoRef(); + } + else { + PdfIndirectObject encryptionObject = AddToBody(crypto.GetEncryptionDictionary(), false); + encryption = encryptionObject.IndirectReference; + } + fileID = crypto.FileID; + } + else + fileID = PdfEncryption.CreateInfoId(PdfEncryption.CreateDocumentId()); + PRIndirectReference iRoot = (PRIndirectReference)reader.trailer.Get(PdfName.ROOT); + PdfIndirectReference root = new PdfIndirectReference(0, GetNewObjectNumber(reader, iRoot.Number, 0)); + PdfIndirectReference info = null; + PdfDictionary oldInfo = (PdfDictionary)PdfReader.GetPdfObject(iInfo); + PdfDictionary newInfo = new PdfDictionary(); + if (oldInfo != null) { + foreach (PdfName key in oldInfo.Keys) { + PdfObject value = PdfReader.GetPdfObject(oldInfo.Get(key)); + newInfo.Put(key, value); + } + } + if (moreInfo != null) { + foreach (DictionaryEntry entry in moreInfo) { + PdfName keyName = new PdfName((String)entry.Key); + String value = (String)entry.Value; + if (value == null) + newInfo.Remove(keyName); + else + newInfo.Put(keyName, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + if (altMetadata == null) // hack because changing the modification data makes the XMP data inconsistent + newInfo.Put(PdfName.MODDATE, new PdfDate()); + if (append) { + if (iInfo == null) + info = AddToBody(newInfo, false).IndirectReference; + else + info = AddToBody(newInfo, iInfo.Number, false).IndirectReference; + } + else { + info = AddToBody(newInfo, false).IndirectReference; + } + // write the cross-reference table of the body + body.WriteCrossReferenceTable(os, root, info, encryption, fileID, prevxref); + if (fullCompression) { + byte[] tmp = GetISOBytes("startxref\n"); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes(body.Offset.ToString()); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes("\n%%EOF\n"); + os.Write(tmp, 0, tmp.Length); + } + else { + PdfTrailer trailer = new PdfTrailer(body.Size, + body.Offset, + root, + info, + encryption, + fileID, prevxref); + trailer.ToPdf(this, os); + } + os.Flush(); + if (CloseStream) + os.Close(); + reader.Close(); + } + + internal void ApplyRotation(PdfDictionary pageN, ByteBuffer out_p) { + if (!rotateContents) + return; + Rectangle page = reader.GetPageSizeWithRotation(pageN); + int rotation = page.Rotation; + switch (rotation) { + case 90: + out_p.Append(PdfContents.ROTATE90); + out_p.Append(page.Top); + out_p.Append(' ').Append('0').Append(PdfContents.ROTATEFINAL); + break; + case 180: + out_p.Append(PdfContents.ROTATE180); + out_p.Append(page.Right); + out_p.Append(' '); + out_p.Append(page.Top); + out_p.Append(PdfContents.ROTATEFINAL); + break; + case 270: + out_p.Append(PdfContents.ROTATE270); + out_p.Append('0').Append(' '); + out_p.Append(page.Right); + out_p.Append(PdfContents.ROTATEFINAL); + break; + } + } + + internal void AlterContents() { + foreach (PageStamp ps in pagesToContent.Values) { + PdfDictionary pageN = ps.pageN; + MarkUsed(pageN); + PdfArray ar = null; + PdfObject content = PdfReader.GetPdfObject(pageN.Get(PdfName.CONTENTS), pageN); + if (content == null) { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + else if (content.IsArray()) { + ar = (PdfArray)content; + MarkUsed(ar); + } + else if (content.IsStream()) { + ar = new PdfArray(); + ar.Add(pageN.Get(PdfName.CONTENTS)); + pageN.Put(PdfName.CONTENTS, ar); + } + else { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + ByteBuffer out_p = new ByteBuffer(); + if (ps.under != null) { + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(ps.under.InternalBuffer); + out_p.Append(PdfContents.RESTORESTATE); + } + if (ps.over != null) + out_p.Append(PdfContents.SAVESTATE); + PdfStream stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + ar.AddFirst(AddToBody(stream).IndirectReference); + out_p.Reset(); + if (ps.over != null) { + out_p.Append(' '); + out_p.Append(PdfContents.RESTORESTATE); + ByteBuffer buf = ps.over.InternalBuffer; + out_p.Append(buf.Buffer, 0, ps.replacePoint); + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(buf.Buffer, ps.replacePoint, buf.Size - ps.replacePoint); + out_p.Append(PdfContents.RESTORESTATE); + stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + ar.Add(AddToBody(stream).IndirectReference); + } + AlterResources(ps); + } + } + + internal void AlterResources(PageStamp ps) { + ps.pageN.Put(PdfName.RESOURCES, ps.pageResources.Resources); + } + + protected internal override int GetNewObjectNumber(PdfReader reader, int number, int generation) { + IntHashtable ref_p = (IntHashtable)readers2intrefs[reader]; + if (ref_p != null) { + int n = ref_p[number]; + if (n == 0) { + n = IndirectReferenceNumber; + ref_p[number] = n; + } + return n; + } + if (currentPdfReaderInstance == null) { + if (append && number < initialXrefSize) + return number; + int n = myXref[number]; + if (n == 0) { + n = IndirectReferenceNumber; + myXref[number] = n; + } + return n; + } + else + return currentPdfReaderInstance.GetNewObjectNumber(number, generation); + } + + internal override RandomAccessFileOrArray GetReaderFile(PdfReader reader) { + if (readers2intrefs.ContainsKey(reader)) { + RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file[reader]; + if (raf != null) + return raf; + return reader.SafeFile; + } + if (currentPdfReaderInstance == null) + return file; + else + return currentPdfReaderInstance.ReaderFile; + } + + /** + * @param reader + * @param openFile + * @throws IOException + */ + public void RegisterReader(PdfReader reader, bool openFile) { + if (readers2intrefs.ContainsKey(reader)) + return; + readers2intrefs[reader] = new IntHashtable(); + if (openFile) { + RandomAccessFileOrArray raf = reader.SafeFile; + readers2file[reader] = raf; + raf.ReOpen(); + } + } + + /** + * @param reader + */ + public void UnRegisterReader(PdfReader reader) { + if (!readers2intrefs.ContainsKey(reader)) + return; + readers2intrefs.Remove(reader); + RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file[reader]; + if (raf == null) + return; + readers2file.Remove(reader); + try{raf.Close();}catch{} + } + + internal static void FindAllObjects(PdfReader reader, PdfObject obj, IntHashtable hits) { + if (obj == null) + return; + switch (obj.Type) { + case PdfObject.INDIRECT: + PRIndirectReference iref = (PRIndirectReference)obj; + if (reader != iref.Reader) + return; + if (hits.ContainsKey(iref.Number)) + return; + hits[iref.Number] = 1; + FindAllObjects(reader, PdfReader.GetPdfObject(obj), hits); + return; + case PdfObject.ARRAY: + ArrayList lst = ((PdfArray)obj).ArrayList; + for (int k = 0; k < lst.Count; ++k) { + FindAllObjects(reader, (PdfObject)lst[k], hits); + } + return; + case PdfObject.DICTIONARY: + case PdfObject.STREAM: + PdfDictionary dic = (PdfDictionary)obj; + foreach (PdfName name in dic.Keys) { + FindAllObjects(reader, dic.Get(name), hits); + } + return; + } + } + + /** + * @param fdf + * @throws IOException + */ + public void AddComments(FdfReader fdf) { + if (readers2intrefs.ContainsKey(fdf)) + return; + PdfDictionary catalog = fdf.Catalog; + catalog = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.FDF)); + if (catalog == null) + return; + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(catalog.Get(PdfName.ANNOTS)); + if (annots == null || annots.Size == 0) + return; + RegisterReader(fdf, false); + IntHashtable hits = new IntHashtable(); + Hashtable irt = new Hashtable(); + ArrayList an = new ArrayList(); + ArrayList ar = annots.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + PdfObject obj = (PdfObject)ar[k]; + PdfDictionary annot = (PdfDictionary)PdfReader.GetPdfObject(obj); + PdfNumber page = (PdfNumber)PdfReader.GetPdfObject(annot.Get(PdfName.PAGE)); + if (page == null || page.IntValue >= reader.NumberOfPages) + continue; + FindAllObjects(fdf, obj, hits); + an.Add(obj); + if (obj.Type == PdfObject.INDIRECT) { + PdfObject nm = PdfReader.GetPdfObject(annot.Get(PdfName.NM)); + if (nm != null && nm.Type == PdfObject.STRING) + irt[nm.ToString()] = obj; + } + } + int[] arhits = hits.GetKeys(); + for (int k = 0; k < arhits.Length; ++k) { + int n = arhits[k]; + PdfObject obj = fdf.GetPdfObject(n); + if (obj.Type == PdfObject.DICTIONARY) { + PdfObject str = PdfReader.GetPdfObject(((PdfDictionary)obj).Get(PdfName.IRT)); + if (str != null && str.Type == PdfObject.STRING) { + PdfObject i = (PdfObject)irt[str.ToString()]; + if (i != null) { + PdfDictionary dic2 = new PdfDictionary(); + dic2.Merge((PdfDictionary)obj); + dic2.Put(PdfName.IRT, i); + obj = dic2; + } + } + } + AddToBody(obj, GetNewObjectNumber(fdf, n, 0)); + } + for (int k = 0; k < an.Count; ++k) { + PdfObject obj = (PdfObject)an[k]; + PdfDictionary annot = (PdfDictionary)PdfReader.GetPdfObject(obj); + PdfNumber page = (PdfNumber)PdfReader.GetPdfObject(annot.Get(PdfName.PAGE)); + PdfDictionary dic = reader.GetPageN(page.IntValue + 1); + PdfArray annotsp = (PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.ANNOTS), dic); + if (annotsp == null) { + annotsp = new PdfArray(); + dic.Put(PdfName.ANNOTS, annotsp); + MarkUsed(dic); + } + MarkUsed(annotsp); + annotsp.Add(obj); + } + } + + internal PageStamp GetPageStamp(int pageNum) { + PdfDictionary pageN = reader.GetPageN(pageNum); + PageStamp ps = (PageStamp)pagesToContent[pageN]; + if (ps == null) { + ps = new PageStamp(this, reader, pageN); + pagesToContent[pageN] = ps; + } + return ps; + } + + internal PdfContentByte GetUnderContent(int pageNum) { + if (pageNum < 1 || pageNum > reader.NumberOfPages) + return null; + PageStamp ps = GetPageStamp(pageNum); + if (ps.under == null) + ps.under = new StampContent(this, ps); + return ps.under; + } + + internal PdfContentByte GetOverContent(int pageNum) { + if (pageNum < 1 || pageNum > reader.NumberOfPages) + return null; + PageStamp ps = GetPageStamp(pageNum); + if (ps.over == null) + ps.over = new StampContent(this, ps); + return ps.over; + } + + internal void CorrectAcroFieldPages(int page) { + if (acroFields == null) + return; + if (page > reader.NumberOfPages) + return; + Hashtable fields = acroFields.Fields; + foreach (AcroFields.Item item in fields.Values) { + ArrayList pages = item.page; + for (int k = 0; k < pages.Count; ++k) { + int p = (int)pages[k]; + if (p >= page) + pages[k] = p + 1; + } + } + } + + private static void MoveRectangle(PdfDictionary dic2, PdfReader r, int pageImported, PdfName key, String name) { + Rectangle m = r.GetBoxSize(pageImported, name); + if (m == null) + dic2.Remove(key); + else + dic2.Put(key, new PdfRectangle(m)); + } + + internal void ReplacePage(PdfReader r, int pageImported, int pageReplaced) { + PdfDictionary pageN = reader.GetPageN(pageReplaced); + if (pagesToContent.ContainsKey(pageN)) + throw new InvalidOperationException("This page cannot be replaced: new content was already added"); + PdfImportedPage p = GetImportedPage(r, pageImported); + PdfDictionary dic2 = reader.GetPageNRelease(pageReplaced); + dic2.Remove(PdfName.RESOURCES); + dic2.Remove(PdfName.CONTENTS); + MoveRectangle(dic2, r, pageImported, PdfName.MEDIABOX, "media"); + MoveRectangle(dic2, r, pageImported, PdfName.CROPBOX, "crop"); + MoveRectangle(dic2, r, pageImported, PdfName.TRIMBOX, "trim"); + MoveRectangle(dic2, r, pageImported, PdfName.ARTBOX, "art"); + MoveRectangle(dic2, r, pageImported, PdfName.BLEEDBOX, "bleed"); + dic2.Put(PdfName.ROTATE, new PdfNumber(r.GetPageRotation(pageImported))); + PdfContentByte cb = GetOverContent(pageReplaced); + cb.AddTemplate(p, 0, 0); + PageStamp ps = (PageStamp)pagesToContent[pageN]; + ps.replacePoint = ps.over.InternalBuffer.Size; + } + + internal void InsertPage(int pageNumber, Rectangle mediabox) { + Rectangle media = new Rectangle(mediabox); + int rotation = media.Rotation % 360; + PdfDictionary page = new PdfDictionary(PdfName.PAGE); + PdfDictionary resources = new PdfDictionary(); + PdfArray procset = new PdfArray(); + procset.Add(PdfName.PDF); + procset.Add(PdfName.TEXT); + procset.Add(PdfName.IMAGEB); + procset.Add(PdfName.IMAGEC); + procset.Add(PdfName.IMAGEI); + resources.Put(PdfName.PROCSET, procset); + page.Put(PdfName.RESOURCES, resources); + page.Put(PdfName.ROTATE, new PdfNumber(rotation)); + page.Put(PdfName.MEDIABOX, new PdfRectangle(media, rotation)); + PRIndirectReference pref = reader.AddPdfObject(page); + PdfDictionary parent; + PRIndirectReference parentRef; + if (pageNumber > reader.NumberOfPages) { + PdfDictionary lastPage = reader.GetPageNRelease(reader.NumberOfPages); + parentRef = (PRIndirectReference)lastPage.Get(PdfName.PARENT); + parentRef = new PRIndirectReference(reader, parentRef.Number); + parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS), parent); + kids.Add(pref); + MarkUsed(kids); + reader.pageRefs.InsertPage(pageNumber, pref); + } + else { + if (pageNumber < 1) + pageNumber = 1; + PdfDictionary firstPage = reader.GetPageN(pageNumber); + PRIndirectReference firstPageRef = reader.GetPageOrigRef(pageNumber); + reader.ReleasePage(pageNumber); + parentRef = (PRIndirectReference)firstPage.Get(PdfName.PARENT); + parentRef = new PRIndirectReference(reader, parentRef.Number); + parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS), parent); + ArrayList ar = kids.ArrayList; + int len = ar.Count; + int num = firstPageRef.Number; + for (int k = 0; k < len; ++k) { + PRIndirectReference cur = (PRIndirectReference)ar[k]; + if (num == cur.Number) { + ar.Insert(k, pref); + break; + } + } + if (len == ar.Count) + throw new Exception("Internal inconsistence."); + MarkUsed(kids); + reader.pageRefs.InsertPage(pageNumber, pref); + CorrectAcroFieldPages(pageNumber); + } + page.Put(PdfName.PARENT, parentRef); + while (parent != null) { + MarkUsed(parent); + PdfNumber count = (PdfNumber)PdfReader.GetPdfObjectRelease(parent.Get(PdfName.COUNT)); + parent.Put(PdfName.COUNT, new PdfNumber(count.IntValue + 1)); + parent = (PdfDictionary)PdfReader.GetPdfObject(parent.Get(PdfName.PARENT)); + } + } + + internal bool RotateContents { + set { + this.rotateContents = value; + } + get { + return rotateContents; + } + } + + internal bool ContentWritten { + get { + return body.Size > 1; + } + } + + internal AcroFields AcroFields { + get { + if (acroFields == null) { + acroFields = new AcroFields(reader, this); + } + return acroFields; + } + } + + internal bool FormFlattening { + set { + flat = value; + } + } + + internal bool FreeTextFlattening { + set { + flatFreeText = value; + } + } + + internal bool PartialFormFlattening(String name) { + AcroFields af = AcroFields; + if (acroFields.Xfa.XfaPresent) + throw new InvalidOperationException("Partial form flattening is not supported with XFA forms."); + if (!acroFields.Fields.ContainsKey(name)) + return false; + partialFlattening[name] = null; + return true; + } + + internal void FlatFields() { + if (append) + throw new ArgumentException("Field flattening is not supported in append mode."); + AcroFields af = AcroFields; + Hashtable fields = acroFields.Fields; + if (fieldsAdded && partialFlattening.Count == 0) { + foreach (object obf in fields.Keys) { + partialFlattening[obf] = null; + } + } + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); + ArrayList acroFds = null; + if (acroForm != null) { + PdfArray array = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); + if (array != null) + acroFds = array.ArrayList; + } + foreach (DictionaryEntry entry in fields) { + String name = (String)entry.Key; + if (partialFlattening.Count != 0 && !partialFlattening.ContainsKey(name)) + continue; + AcroFields.Item item = (AcroFields.Item)entry.Value; + for (int k = 0; k < item.merged.Count; ++k) { + PdfDictionary merged = (PdfDictionary)item.merged[k]; + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.F)); + int flags = 0; + if (ff != null) + flags = ff.IntValue; + int page = (int)item.page[k]; + PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.AP)); + if (appDic != null && (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { + PdfObject obj = appDic.Get(PdfName.N); + PdfAppearance app = null; + if (obj != null) { + PdfObject objReal = PdfReader.GetPdfObject(obj); + if (obj is PdfIndirectReference && !obj.IsIndirect()) + app = new PdfAppearance((PdfIndirectReference)obj); + else if (objReal is PdfStream) { + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + app = new PdfAppearance((PdfIndirectReference)obj); + } + else { + if (objReal != null && objReal.IsDictionary()) { + PdfName as_p = (PdfName)PdfReader.GetPdfObject(merged.Get(PdfName.AS)); + if (as_p != null) { + PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).Get(as_p); + if (iref != null) { + app = new PdfAppearance(iref); + if (iref.IsIndirect()) { + objReal = PdfReader.GetPdfObject(iref); + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + } + } + } + } + } + } + if (app != null) { + Rectangle box = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT))); + PdfContentByte cb = GetOverContent(page); + cb.SetLiteral("Q "); + cb.AddTemplate(app, box.Left, box.Bottom); + cb.SetLiteral("q "); + } + } + if (partialFlattening.Count == 0) + continue; + PdfDictionary pageDic = reader.GetPageN(page); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) + continue; + ArrayList ar = annots.ArrayList; + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject ran = (PdfObject)ar[idx]; + if (!ran.IsIndirect()) + continue; + PdfObject ran2 = (PdfObject)item.widget_refs[k]; + if (!ran2.IsIndirect()) + continue; + if (((PRIndirectReference)ran).Number == ((PRIndirectReference)ran2).Number) { + ar.RemoveAt(idx--); + PRIndirectReference wdref = (PRIndirectReference)ran2; + while (true) { + PdfDictionary wd = (PdfDictionary)PdfReader.GetPdfObject(wdref); + PRIndirectReference parentRef = (PRIndirectReference)wd.Get(PdfName.PARENT); + PdfReader.KillIndirect(wdref); + if (parentRef == null) { // reached AcroForm + for (int fr = 0; fr < acroFds.Count; ++fr) { + PdfObject h = (PdfObject)acroFds[fr]; + if (h.IsIndirect() && ((PRIndirectReference)h).Number == wdref.Number) { + acroFds.RemoveAt(fr); + --fr; + } + } + break; + } + PdfDictionary parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS)); + ArrayList kar = kids.ArrayList; + for (int fr = 0; fr < kar.Count; ++fr) { + PdfObject h = (PdfObject)kar[fr]; + if (h.IsIndirect() && ((PRIndirectReference)h).Number == wdref.Number) { + kar.RemoveAt(fr); + --fr; + } + } + if (kar.Count != 0) + break; + wdref = parentRef; + } + } + } + if (ar.Count == 0) { + PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); + pageDic.Remove(PdfName.ANNOTS); + } + } + } + if (!fieldsAdded && partialFlattening.Count == 0) { + for (int page = 1; page <= reader.NumberOfPages; ++page) { + PdfDictionary pageDic = reader.GetPageN(page); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) + continue; + ArrayList ar = annots.ArrayList; + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); + if ((annoto is PdfIndirectReference) && !annoto.IsIndirect()) + continue; + if (!annoto.IsDictionary() || PdfName.WIDGET.Equals(((PdfDictionary)annoto).Get(PdfName.SUBTYPE))) { + ar.RemoveAt(idx); + --idx; + } + } + if (ar.Count == 0) { + PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); + pageDic.Remove(PdfName.ANNOTS); + } + } + EliminateAcroformObjects(); + } + } + + internal void EliminateAcroformObjects() { + PdfObject acro = reader.Catalog.Get(PdfName.ACROFORM); + if (acro == null) + return; + PdfDictionary acrodic = (PdfDictionary)PdfReader.GetPdfObject(acro); + reader.KillXref(acrodic.Get(PdfName.XFA)); + acrodic.Remove(PdfName.XFA); + PdfObject iFields = acrodic.Get(PdfName.FIELDS); + if (iFields != null) { + PdfDictionary kids = new PdfDictionary(); + kids.Put(PdfName.KIDS, iFields); + SweepKids(kids); + PdfReader.KillIndirect(iFields); + acrodic.Put(PdfName.FIELDS, new PdfArray()); + } + // PdfReader.KillIndirect(acro); + // reader.GetCatalog().Remove(PdfName.ACROFORM); + } + + internal void SweepKids(PdfObject obj) { + PdfObject oo = PdfReader.KillIndirect(obj); + if (oo == null || !oo.IsDictionary()) + return; + PdfDictionary dic = (PdfDictionary)oo; + PdfArray kids = (PdfArray)PdfReader.KillIndirect(dic.Get(PdfName.KIDS)); + if (kids == null) + return; + ArrayList ar = kids.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + SweepKids((PdfObject)ar[k]); + } + } + + private void FlatFreeTextFields() { + if (append) + throw new ArgumentException("FreeText flattening is not supported in append mode."); + + for (int page = 1; page <= reader.NumberOfPages; ++page) { + PdfDictionary pageDic = reader.GetPageN(page); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) + continue; + ArrayList ar = annots.ArrayList; + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); + if ((annoto is PdfIndirectReference) && !annoto.IsIndirect()) + continue; + + PdfDictionary annDic = (PdfDictionary)annoto; + if (!((PdfName)annDic.Get(PdfName.SUBTYPE)).Equals(PdfName.FREETEXT)) + continue; + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(annDic.Get(PdfName.F)); + int flags = (ff != null) ? ff.IntValue : 0; + + if ( (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { + PdfObject obj1 = annDic.Get(PdfName.AP); + if (obj1 == null) + continue; + PdfDictionary appDic = (obj1 is PdfIndirectReference) ? + (PdfDictionary) PdfReader.GetPdfObject(obj1) : (PdfDictionary) obj1; + PdfObject obj = appDic.Get(PdfName.N); + PdfAppearance app = null; + if (obj != null) { + PdfObject objReal = PdfReader.GetPdfObject(obj); + + if (obj is PdfIndirectReference && !obj.IsIndirect()) + app = new PdfAppearance((PdfIndirectReference)obj); + else if (objReal is PdfStream) { + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + app = new PdfAppearance((PdfIndirectReference)obj); + } + else { + if (objReal.IsDictionary()) { + PdfName as_p = (PdfName)PdfReader.GetPdfObject(appDic.Get(PdfName.AS)); + if (as_p != null) { + PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).Get(as_p); + if (iref != null) { + app = new PdfAppearance(iref); + if (iref.IsIndirect()) { + objReal = PdfReader.GetPdfObject(iref); + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + } + } + } + } + } + } + if (app != null) { + Rectangle box = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(annDic.Get(PdfName.RECT))); + PdfContentByte cb = this.GetOverContent(page); + cb.SetLiteral("Q "); + cb.AddTemplate(app, box.Left, box.Bottom); + cb.SetLiteral("q "); + } + } + } + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); + if (annoto != null && annoto.IsDictionary()) { + PdfDictionary annot = (PdfDictionary)annoto; + if (PdfName.FREETEXT.Equals(annot.Get(PdfName.SUBTYPE))) { + ar.RemoveAt(idx); + --idx; + } + } + } + if (ar.Count == 0) { + PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); + pageDic.Remove(PdfName.ANNOTS); + } + } + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#getPageReference(int) + */ + public override PdfIndirectReference GetPageReference(int page) { + PdfIndirectReference ref_p = reader.GetPageOrigRef(page); + if (ref_p == null) + throw new ArgumentException("Invalid page number " + page); + return ref_p; + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#addAnnotation(com.lowagie.text.pdf.PdfAnnotation) + */ + public override void AddAnnotation(PdfAnnotation annot) { + throw new Exception("Unsupported in this context. Use PdfStamper.AddAnnotation()"); + } + + internal void AddDocumentField(PdfIndirectReference ref_p) { + PdfDictionary catalog = reader.Catalog; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); + if (acroForm == null) { + acroForm = new PdfDictionary(); + catalog.Put(PdfName.ACROFORM, acroForm); + MarkUsed(catalog); + } + PdfArray fields = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); + if (fields == null) { + fields = new PdfArray(); + acroForm.Put(PdfName.FIELDS, fields); + MarkUsed(acroForm); + } + if (!acroForm.Contains(PdfName.DA)) { + acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + MarkUsed(acroForm); + } + fields.Add(ref_p); + MarkUsed(fields); + } + + internal void AddFieldResources() { + if (fieldTemplates.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); + if (acroForm == null) { + acroForm = new PdfDictionary(); + catalog.Put(PdfName.ACROFORM, acroForm); + MarkUsed(catalog); + } + PdfDictionary dr = (PdfDictionary)PdfReader.GetPdfObject(acroForm.Get(PdfName.DR), acroForm); + if (dr == null) { + dr = new PdfDictionary(); + acroForm.Put(PdfName.DR, dr); + MarkUsed(acroForm); + } + MarkUsed(dr); + foreach (PdfTemplate template in fieldTemplates.Keys) { + PdfFormField.MergeResources(dr, (PdfDictionary)template.Resources, this); + } + if (dr.Get(PdfName.ENCODING) == null) + dr.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fonts == null) { + fonts = new PdfDictionary(); + dr.Put(PdfName.FONT, fonts); + } + if (!fonts.Contains(PdfName.HELV)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.HELVETICA); + dic.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + dic.Put(PdfName.NAME, PdfName.HELV); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.HELV, AddToBody(dic).IndirectReference); + } + if (!fonts.Contains(PdfName.ZADB)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS); + dic.Put(PdfName.NAME, PdfName.ZADB); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.ZADB, AddToBody(dic).IndirectReference); + } + if (acroForm.Get(PdfName.DA) == null) { + acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + MarkUsed(acroForm); + } + } + + internal void ExpandFields(PdfFormField field, ArrayList allAnnots) { + allAnnots.Add(field); + ArrayList kids = field.Kids; + if (kids != null) { + for (int k = 0; k < kids.Count; ++k) { + ExpandFields((PdfFormField)kids[k], allAnnots); + } + } + } + + internal void AddAnnotation(PdfAnnotation annot, PdfDictionary pageN) { + ArrayList allAnnots = new ArrayList(); + if (annot.IsForm()) { + fieldsAdded = true; + AcroFields afdummy = AcroFields; + PdfFormField field = (PdfFormField)annot; + if (field.Parent != null) + return; + ExpandFields(field, allAnnots); + } + else + allAnnots.Add(annot); + for (int k = 0; k < allAnnots.Count; ++k) { + annot = (PdfAnnotation)allAnnots[k]; + if (annot.PlaceInPage > 0) + pageN = reader.GetPageN(annot.PlaceInPage); + if (annot.IsForm()) { + if (!annot.IsUsed()) { + Hashtable templates = annot.Templates; + if (templates != null) { + foreach (object tpl in templates.Keys) { + fieldTemplates[tpl] = null; + } + } + } + PdfFormField field = (PdfFormField)annot; + if (field.Parent == null) + AddDocumentField(field.IndirectReference); + } + if (annot.IsAnnotation()) { + PdfObject pdfobj = PdfReader.GetPdfObject(pageN.Get(PdfName.ANNOTS), pageN); + PdfArray annots = null; + if (pdfobj == null || !pdfobj.IsArray()) { + annots = new PdfArray(); + pageN.Put(PdfName.ANNOTS, annots); + MarkUsed(pageN); + } + else + annots = (PdfArray)pdfobj; + annots.Add(annot.IndirectReference); + MarkUsed(annots); + if (!annot.IsUsed()) { + PdfRectangle rect = (PdfRectangle)annot.Get(PdfName.RECT); + if (rect != null && (rect.Left != 0 || rect.Right != 0 || rect.Top != 0 || rect.Bottom != 0)) { + int rotation = reader.GetPageRotation(pageN); + Rectangle pageSize = reader.GetPageSizeWithRotation(pageN); + switch (rotation) { + case 90: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Top - rect.Bottom, + rect.Left, + pageSize.Top - rect.Top, + rect.Right)); + break; + case 180: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Right - rect.Left, + pageSize.Top - rect.Bottom, + pageSize.Right - rect.Right, + pageSize.Top - rect.Top)); + break; + case 270: + annot.Put(PdfName.RECT, new PdfRectangle( + rect.Bottom, + pageSize.Right - rect.Left, + rect.Top, + pageSize.Right - rect.Right)); + break; + } + } + } + } + if (!annot.IsUsed()) { + annot.SetUsed(); + AddToBody(annot, annot.IndirectReference); + } + } + } + + internal override void AddAnnotation(PdfAnnotation annot, int page) { + AddAnnotation(annot, reader.GetPageN(page)); + } + + private void OutlineTravel(PRIndirectReference outline) { + while (outline != null) { + PdfDictionary outlineR = (PdfDictionary)PdfReader.GetPdfObjectRelease(outline); + PRIndirectReference first = (PRIndirectReference)outlineR.Get(PdfName.FIRST); + if (first != null) { + OutlineTravel(first); + } + PdfReader.KillIndirect(outlineR.Get(PdfName.DEST)); + PdfReader.KillIndirect(outlineR.Get(PdfName.A)); + PdfReader.KillIndirect(outline); + outline = (PRIndirectReference)outlineR.Get(PdfName.NEXT); + } + } + + internal void DeleteOutlines() { + PdfDictionary catalog = reader.Catalog; + PRIndirectReference outlines = (PRIndirectReference)catalog.Get(PdfName.OUTLINES); + if (outlines == null) + return; + OutlineTravel(outlines); + PdfReader.KillIndirect(outlines); + catalog.Remove(PdfName.OUTLINES); + MarkUsed(catalog); + } + + internal void SetJavaScript() { + Hashtable djs = pdf.GetDocumentLevelJS(); + if (djs.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + PdfDictionary names = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES), catalog); + if (names == null) { + names = new PdfDictionary(); + catalog.Put(PdfName.NAMES, names); + MarkUsed(catalog); + } + MarkUsed(names); + PdfDictionary tree = PdfNameTree.WriteTree(djs, this); + names.Put(PdfName.JAVASCRIPT, AddToBody(tree).IndirectReference); + } + + void AddFileAttachments() { + Hashtable fs = pdf.GetDocumentFileAttachment(); + if (fs.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + PdfDictionary names = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES), catalog); + if (names == null) { + names = new PdfDictionary(); + catalog.Put(PdfName.NAMES, names); + MarkUsed(catalog); + } + MarkUsed(names); + Hashtable old = PdfNameTree.ReadTree((PdfDictionary)PdfReader.GetPdfObjectRelease(names.Get(PdfName.EMBEDDEDFILES))); + foreach (DictionaryEntry entry in fs) { + String name = (String)entry.Key; + int k = 0; + String nn = name; + while (old.ContainsKey(nn)) { + ++k; + nn += " " + k; + } + old[nn] = entry.Value; + } + PdfDictionary tree = PdfNameTree.WriteTree(old, this); + names.Put(PdfName.EMBEDDEDFILES, AddToBody(tree).IndirectReference); + } + + /** + * Adds or replaces the Collection Dictionary in the Catalog. + * @param collection the new collection dictionary. + */ + internal void MakePackage(PdfCollection collection) { + PdfDictionary catalog = reader.Catalog; + catalog.Put( PdfName.COLLECTION, collection ); + } + + internal void SetOutlines() { + if (newBookmarks == null) + return; + DeleteOutlines(); + if (newBookmarks.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + bool namedAsNames = (catalog.Get(PdfName.DESTS) != null); + WriteOutlines(catalog, namedAsNames); + MarkUsed(catalog); + } + + /** + * Sets the viewer preferences. + * @param preferences the viewer preferences + * @see PdfWriter#setViewerPreferences(int) + */ + public override int ViewerPreferences { + set { + useVp = true; + this.viewerPreferences.ViewerPreferences = value; + } + } + + /** Adds a viewer preference + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + public override void AddViewerPreference(PdfName key, PdfObject value) { + useVp = true; + this.viewerPreferences.AddViewerPreference(key, value); + } + + /** + * Set the signature flags. + * @param f the flags. This flags are ORed with current ones + */ + public override int SigFlags { + set { + sigFlags |= value; + } + } + + /** Always throws an UnsupportedOperationException. + * @param actionType ignore + * @param action ignore + * @throws PdfException ignore + * @see PdfStamper#setPageAction(PdfName, PdfAction, int) + */ + public override void SetPageAction(PdfName actionType, PdfAction action) { + throw new InvalidOperationException("Use SetPageAction(PdfName actionType, PdfAction action, int page)"); + } + + /** + * Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @param page the page where the action will be applied. The first page is 1 + * @throws PdfException if the action type is invalid + */ + internal void SetPageAction(PdfName actionType, PdfAction action, int page) { + if (!actionType.Equals(PAGE_OPEN) && !actionType.Equals(PAGE_CLOSE)) + throw new PdfException("Invalid page additional action type: " + actionType.ToString()); + PdfDictionary pg = reader.GetPageN(page); + PdfDictionary aa = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.AA), pg); + if (aa == null) { + aa = new PdfDictionary(); + pg.Put(PdfName.AA, aa); + MarkUsed(pg); + } + aa.Put(actionType, action); + MarkUsed(aa); + } + + /** + * Always throws an UnsupportedOperationException. + * @param seconds ignore + */ + public override int Duration { + set { + throw new InvalidOperationException("Use the methods at Pdfstamper."); + } + } + + /** + * Always throws an UnsupportedOperationException. + * @param transition ignore + */ + public override PdfTransition Transition { + set { + throw new InvalidOperationException("Use the methods at Pdfstamper."); + } + } + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page. A negative value removes the entry + * @param page the page where the duration will be applied. The first page is 1 + */ + internal void SetDuration(int seconds, int page) { + PdfDictionary pg = reader.GetPageN(page); + if (seconds < 0) + pg.Remove(PdfName.DUR); + else + pg.Put(PdfName.DUR, new PdfNumber(seconds)); + MarkUsed(pg); + } + + /** + * Sets the transition for the page + * @param transition the transition object. A null removes the transition + * @param page the page where the transition will be applied. The first page is 1 + */ + internal void SetTransition(PdfTransition transition, int page) { + PdfDictionary pg = reader.GetPageN(page); + if (transition == null) + pg.Remove(PdfName.TRANS); + else + pg.Put(PdfName.TRANS, transition.TransitionDictionary); + MarkUsed(pg); + } + + protected internal void MarkUsed(PdfObject obj) { + if (append && obj != null) { + PRIndirectReference ref_p = null; + if (obj.Type == PdfObject.INDIRECT) + ref_p = (PRIndirectReference)obj; + else + ref_p = obj.IndRef; + if (ref_p != null) + marked[ref_p.Number] = 1; + } + } + + protected internal void MarkUsed(int num) { + if (append) + marked[num] = 1; + } + + /** + * Getter for property append. + * @return Value of property append. + */ + internal bool IsAppend() { + return append; + } + + /** Additional-actions defining the actions to be taken in + * response to various trigger events affecting the document + * as a whole. The actions types allowed are: DOCUMENT_CLOSE, + * WILL_SAVE, DID_SAVE, WILL_PRINT + * and DID_PRINT. + * + * @param actionType the action type + * @param action the action to execute in response to the trigger + * @throws PdfException on invalid action type + */ + public override void SetAdditionalAction(PdfName actionType, PdfAction action) { + if (!(actionType.Equals(DOCUMENT_CLOSE) || + actionType.Equals(WILL_SAVE) || + actionType.Equals(DID_SAVE) || + actionType.Equals(WILL_PRINT) || + actionType.Equals(DID_PRINT))) { + throw new PdfException("Invalid additional action type: " + actionType.ToString()); + } + PdfDictionary aa = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.AA)); + if (aa == null) { + if (action == null) + return; + aa = new PdfDictionary(); + reader.Catalog.Put(PdfName.AA, aa); + } + MarkUsed(aa); + if (action == null) + aa.Remove(actionType); + else + aa.Put(actionType, action); + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(com.lowagie.text.pdf.PdfAction) + */ + public override void SetOpenAction(PdfAction action) { + openAction = action; + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(java.lang.String) + */ + public override void SetOpenAction(String name) { + throw new InvalidOperationException("Open actions by name are not supported."); + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#setThumbnail(com.lowagie.text.Image) + */ + public override Image Thumbnail { + set { + throw new InvalidOperationException("Use PdfStamper.Thumbnail"); + } + } + + internal void SetThumbnail(Image image, int page) { + PdfIndirectReference thumb = GetImageReference(AddDirectImageSimple(image)); + reader.ResetReleasePage(); + PdfDictionary dic = reader.GetPageN(page); + dic.Put(PdfName.THUMB, thumb); + reader.ResetReleasePage(); + } + + /** + * Reads the OCProperties dictionary from the catalog of the existing document + * and fills the documentOCG, documentOCGorder and OCGRadioGroup variables in PdfWriter. + * Note that the original OCProperties of the existing document can contain more information. + * @since 2.1.2 + */ + protected void ReadOCProperties() { + if (documentOCG.Count != 0) { + return; + } + PdfDictionary dict = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES); + if (dict == null) { + return; + } + PdfArray ocgs = dict.GetAsArray(PdfName.OCGS); + PdfIndirectReference refi; + PdfLayer layer; + Hashtable ocgmap = new Hashtable(); + for (ListIterator i = ocgs.GetListIterator(); i.HasNext();) { + refi = (PdfIndirectReference)i.Next(); + layer = new PdfLayer(null); + layer.Ref = refi; + layer.OnPanel = false; + layer.Merge((PdfDictionary)PdfReader.GetPdfObject(refi)); + ocgmap[refi.ToString()] = layer; + } + PdfDictionary d = dict.GetAsDict(PdfName.D); + PdfArray off = d.GetAsArray(PdfName.OFF); + if (off != null) { + for (ListIterator i = off.GetListIterator(); i.HasNext(); ) { + refi = (PdfIndirectReference)i.Next(); + layer = (PdfLayer)ocgmap[refi.ToString()]; + layer.On = false; + } + } + PdfArray order = d.GetAsArray(PdfName.ORDER); + if (order != null) { + AddOrder(null, order, ocgmap); + } + foreach (object o in ocgmap.Values) + documentOCG[o] = null; + OCGRadioGroup = d.GetAsArray(PdfName.RBGROUPS); + OCGLocked = d.GetAsArray(PdfName.LOCKED); + } + + /** + * Recursive method to reconstruct the documentOCGorder variable in the writer. + * @param parent a parent PdfLayer (can be null) + * @param arr an array possibly containing children for the parent PdfLayer + * @param ocgmap a Hashtable with indirect reference Strings as keys and PdfLayer objects as values. + * @since 2.1.2 + */ + private void AddOrder(PdfLayer parent, PdfArray arr, Hashtable ocgmap) { + PdfObject obj; + PdfLayer layer; + for (int i = 0; i < arr.Size; i++) { + obj = arr.GetPdfObject(i); + if (obj.IsIndirect()) { + layer = (PdfLayer)ocgmap[obj.ToString()]; + layer.OnPanel = true; + RegisterLayer(layer); + if (parent != null) { + parent.AddChild(layer); + } + if (arr.Size > i + 1 && arr.GetPdfObject(i + 1).IsArray()) { + i++; + AddOrder(layer, (PdfArray)arr.GetPdfObject(i), ocgmap); + } + } + else if (obj.IsArray()) { + ArrayList sub = ((PdfArray)obj).ArrayList; + if (sub.Count == 0) return; + obj = (PdfObject)sub[0]; + if (obj.IsString()) { + layer = new PdfLayer(sub[0].ToString()); + layer.OnPanel = true; + RegisterLayer(layer); + if (parent != null) { + parent.AddChild(layer); + } + PdfArray array = new PdfArray(); + foreach (PdfObject o2 in sub) { + array.Add(o2); + } + AddOrder(layer, array, ocgmap); + } + else { + AddOrder(parent, (PdfArray)obj, ocgmap); + } + } + } + } + + /** + * Gets the PdfLayer objects in an existing document as a Map + * with the names/titles of the layers as keys. + * @return a Map with all the PdfLayers in the document (and the name/title of the layer as key) + * @since 2.1.2 + */ + public Hashtable GetPdfLayers() { + if (documentOCG.Count == 0) { + ReadOCProperties(); + } + Hashtable map = new Hashtable(); + String key; + foreach (PdfLayer layer in documentOCG) { + if (layer.Title == null) { + key = layer.GetAsString(PdfName.NAME).ToString(); + } + else { + key = layer.Title; + } + if (map.ContainsKey(key)) { + int seq = 2; + String tmp = key + "(" + seq + ")"; + while (map.ContainsKey(tmp)) { + seq++; + tmp = key + "(" + seq + ")"; + } + key = tmp; + } + map[key] = layer; + } + return map; + } + + internal class PageStamp { + + internal PdfDictionary pageN; + internal StampContent under; + internal StampContent over; + internal PageResources pageResources; + internal int replacePoint = 0; + + internal PageStamp(PdfStamperImp stamper, PdfReader reader, PdfDictionary pageN) { + this.pageN = pageN; + pageResources = new PageResources(); + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); + pageResources.SetOriginalResources(resources, stamper.namePtr); + } + } + + public override PdfContentByte DirectContent { + get { + throw new InvalidOperationException("Use PdfStamper.GetUnderContent() or PdfStamper.GetOverContent()"); + } + } + + public override PdfContentByte DirectContentUnder { + get { + throw new InvalidOperationException("Use PdfStamper.GetUnderContent() or PdfStamper.GetOverContent()"); + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStream.cs b/iTechSharp/iTextSharp/text/pdf/PdfStream.cs new file mode 100644 index 0000000..4abfed8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStream.cs @@ -0,0 +1,324 @@ +using System; +using System.IO; +using System.Collections; + +using System.util.zlib; + +/* + * $Id: PdfStream.cs,v 1.12 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfStream is the Pdf stream object. + *

+ * A stream, like a string, is a sequence of characters. However, an application can + * read a small portion of a stream at a time, while a string must be read in its entirety. + * For this reason, objects with potentially large amounts of data, such as images and + * page descriptions, are represented as streams.
+ * A stream consists of a dictionary that describes a sequence of characters, followed by + * the keyword stream, followed by zero or more lines of characters, followed by + * the keyword endstream.
+ * All streams must be PdfIndirectObjects. The stream dictionary must be a direct + * object. The keyword stream that follows the stream dictionary should be followed by + * a carriage return and linefeed or just a linefeed.
+ * Remark: In this version only the FLATEDECODE-filter is supported.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.8 (page 41-53).
+ * + * @see PdfObject + * @see PdfDictionary + */ + + public class PdfStream : PdfDictionary { + + // membervariables + + /** is the stream compressed? */ + protected bool compressed = false; + + protected MemoryStream streamBytes = null; + + protected Stream inputStream; + protected PdfIndirectReference iref; + protected int inputStreamLength = -1; + protected PdfWriter writer; + protected int rawLength; + + internal static byte[] STARTSTREAM = DocWriter.GetISOBytes("stream\n"); + internal static byte[] ENDSTREAM = DocWriter.GetISOBytes("\nendstream"); + internal static int SIZESTREAM = STARTSTREAM.Length + ENDSTREAM.Length; + + // constructors + + /** + * Constructs a PdfStream-object. + * + * @param bytes content of the new PdfObject as an array of byte. + */ + + public PdfStream(byte[] bytes) : base() { + type = STREAM; + this.bytes = bytes; + rawLength = bytes.Length; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + } + + /** + * Creates an efficient stream. No temporary array is ever created. The InputStream + * is totally consumed but is not closed. The general usage is: + *

+ *

+         * InputStream in = ...;
+         * PdfStream stream = new PdfStream(in, writer);
+         * stream.FlateCompress();
+         * writer.AddToBody(stream);
+         * stream.WriteLength();
+         * in.Close();
+         * 
+ * @param inputStream the data to write to this stream + * @param writer the PdfWriter for this stream + */ + public PdfStream(Stream inputStream, PdfWriter writer) { + type = STREAM; + this.inputStream = inputStream; + this.writer = writer; + iref = writer.PdfIndirectReference; + Put(PdfName.LENGTH, iref); + } + + /** + * Constructs a PdfStream-object. + */ + + protected PdfStream() : base() { + type = STREAM; + } + + // methods overriding some methods of PdfObject + + /** + * Writes the stream length to the PdfWriter. + *

+ * This method must be called and can only be called if the contructor {@link #PdfStream(InputStream,PdfWriter)} + * is used to create the stream. + * @throws IOException on error + * @see #PdfStream(InputStream,PdfWriter) + */ + public void WriteLength() { + if (inputStream == null) + throw new PdfException("WriteLength() can only be called in a contructed PdfStream(InputStream,PdfWriter)."); + if (inputStreamLength == -1) + throw new PdfException("WriteLength() can only be called after output of the stream body."); + writer.AddToBody(new PdfNumber(inputStreamLength), iref, false); + } + + public int RawLength { + get { + return rawLength; + } + } + + // methods + + /** + * Compresses the stream. + * + * @throws PdfException if a filter is allready defined + */ + + public void FlateCompress() { + if (!Document.Compress) + return; + // check if the flateCompress-method has allready been + if (compressed) { + return; + } + if (inputStream != null) { + compressed = true; + return; + } + // check if a filter allready exists + PdfObject filter = PdfReader.GetPdfObject(Get(PdfName.FILTER)); + if (filter != null) { + if (filter.IsName()) { + if (PdfName.FLATEDECODE.Equals(filter)) + return; + } + else if (filter.IsArray()) { + if (((PdfArray) filter).Contains(PdfName.FLATEDECODE)) + return; + } + else { + throw new PdfException("Stream could not be compressed: filter is not a name or array."); + } + } + // compress + MemoryStream stream = new MemoryStream(); + ZDeflaterOutputStream zip = new ZDeflaterOutputStream(stream); + if (streamBytes != null) + streamBytes.WriteTo(zip); + else + zip.Write(bytes, 0, bytes.Length); + //zip.Close(); + zip.Finish(); + // update the object + streamBytes = stream; + bytes = null; + Put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); + if (filter == null) { + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + else { + PdfArray filters = new PdfArray(filter); + filters.Add(PdfName.FLATEDECODE); + Put(PdfName.FILTER, filters); + } + compressed = true; + } + + protected virtual void SuperToPdf(PdfWriter writer, Stream os) { + base.ToPdf(writer, os); + } + + public override void ToPdf(PdfWriter writer, Stream os) { + if (inputStream != null && compressed) + Put(PdfName.FILTER, PdfName.FLATEDECODE); + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + if (crypto != null) { + PdfObject filter = Get(PdfName.FILTER); + if (filter != null) { + if (PdfName.CRYPT.Equals(filter)) + crypto = null; + else if (filter.IsArray()) { + ArrayList af = ((PdfArray)filter).ArrayList; + if (af.Count > 0 && PdfName.CRYPT.Equals(af[0])) + crypto = null; + } + } + } + PdfObject nn = Get(PdfName.LENGTH); + if (crypto != null && nn != null && nn.IsNumber()) { + int sz = ((PdfNumber)nn).IntValue; + Put(PdfName.LENGTH, new PdfNumber(crypto.CalculateStreamSize(sz))); + SuperToPdf(writer, os); + Put(PdfName.LENGTH, nn); + } + else + SuperToPdf(writer, os); + os.Write(STARTSTREAM, 0, STARTSTREAM.Length); + if (inputStream != null) { + rawLength = 0; + ZDeflaterOutputStream def = null; + OutputStreamCounter osc = new OutputStreamCounter(os); + OutputStreamEncryption ose = null; + Stream fout = osc; + if (crypto != null) + fout = ose = crypto.GetEncryptionStream(fout); + if (compressed) + fout = def = new ZDeflaterOutputStream(fout); + + byte[] buf = new byte[4192]; + while (true) { + int n = inputStream.Read(buf, 0, buf.Length); + if (n <= 0) + break; + fout.Write(buf, 0, n); + rawLength += n; + } + if (def != null) + def.Finish(); + if (ose != null) + ose.Finish(); + inputStreamLength = osc.Counter; + } + else { + if (crypto == null) { + if (streamBytes != null) + streamBytes.WriteTo(os); + else + os.Write(bytes, 0, bytes.Length); + } + else { + byte[] b; + if (streamBytes != null) { + b = crypto.EncryptByteArray(streamBytes.ToArray()); + } + else { + b = crypto.EncryptByteArray(bytes); + } + os.Write(b, 0, b.Length); + } + } + os.Write(ENDSTREAM, 0, ENDSTREAM.Length); + } + + /** + * Writes the data content to an Stream. + * @param os the destination to write to + * @throws IOException on error + */ + public void WriteContent(Stream os) { + if (streamBytes != null) + streamBytes.WriteTo(os); + else if (bytes != null) + os.Write(bytes, 0, bytes.Length); + } + + /** + * @see com.lowagie.text.pdf.PdfObject#toString() + */ + public override String ToString() { + if (Get(PdfName.TYPE) == null) return "Stream"; + return "Stream of type: " + Get(PdfName.TYPE); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfString.cs b/iTechSharp/iTextSharp/text/pdf/PdfString.cs new file mode 100644 index 0000000..01eedef --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfString.cs @@ -0,0 +1,232 @@ +using System; +using System.IO; + +/* + * $Id: PdfString.cs,v 1.6 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfString-class is the PDF-equivalent of a JAVA-string-object. + *

+ * A string is a sequence of characters delimited by parenthesis. If a string is too long + * to be conveniently placed on a single line, it may be split across multiple lines by using + * the backslash character (\) at the end of a line to indicate that the string continues + * on the following line. Within a string, the backslash character is used as an escape to + * specify unbalanced parenthesis, non-printing ASCII characters, and the backslash character + * itself. Use of the \ddd escape sequence is the preferred way to represent characters + * outside the printable ASCII character set.
+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.4 (page 37-39). + * + * @see PdfObject + * @see BadPdfFormatException + */ + + public class PdfString : PdfObject { + + // membervariables + + /** The value of this object. */ + protected string value = NOTHING; + protected string originalValue = null; + + /** The encoding. */ + protected string encoding = TEXT_PDFDOCENCODING; + protected int objNum = 0; + protected int objGen = 0; + protected bool hexWriting = false; + // constructors + + /** + * Constructs an empty PdfString-object. + */ + + public PdfString() : base(STRING) {} + + /** + * Constructs a PdfString-object. + * + * @param value the content of the string + */ + + public PdfString(string value) : base(STRING) { + this.value = value; + } + + /** + * Constructs a PdfString-object. + * + * @param value the content of the string + * @param encoding an encoding + */ + + public PdfString(string value, string encoding) : base(STRING) { + this.value = value; + this.encoding = encoding; + } + + /** + * Constructs a PdfString-object. + * + * @param bytes an array of byte + */ + + public PdfString(byte[] bytes) : base(STRING) { + value = PdfEncodings.ConvertToString(bytes, null); + encoding = NOTHING; + } + + // methods overriding some methods in PdfObject + + /** + * Returns the PDF representation of this PdfString. + * + * @return an array of bytes + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + byte[] b = GetBytes(); + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + if (crypto != null) { + b = crypto.EncryptByteArray(b); + } + if (hexWriting) { + ByteBuffer buf = new ByteBuffer(); + buf.Append('<'); + int len = b.Length; + for (int k = 0; k < len; ++k) + buf.AppendHex(b[k]); + buf.Append('>'); + os.Write(buf.ToByteArray(), 0, buf.Size); + } + else { + b = PdfContentByte.EscapeString(b); + os.Write(b, 0, b.Length); + } + } + + /** + * Returns the string value of the PdfString-object. + * + * @return a string + */ + + public override string ToString() { + return value; + } + + // other methods + + /** + * Gets the encoding of this string. + * + * @return a string + */ + + public string Encoding { + get { + return encoding; + } + } + public String ToUnicodeString() { + if (encoding != null && encoding.Length != 0) + return value; + GetBytes(); + if (bytes.Length >= 2 && bytes[0] == (byte)254 && bytes[1] == (byte)255) + return PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_UNICODE); + else + return PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_PDFDOCENCODING); + } + + internal void SetObjNum(int objNum, int objGen) { + this.objNum = objNum; + this.objGen = objGen; + } + + internal void Decrypt(PdfReader reader) { + PdfEncryption decrypt = reader.Decrypt; + if (decrypt != null) { + originalValue = value; + decrypt.SetHashKey(objNum, objGen); + bytes = PdfEncodings.ConvertToBytes(value, null); + bytes = decrypt.DecryptByteArray(bytes); + value = PdfEncodings.ConvertToString(bytes, null); + } + } + + public override byte[] GetBytes() { + if (bytes == null) { + if (encoding != null && encoding.Equals(TEXT_UNICODE) && PdfEncodings.IsPdfDocEncoding(value)) + bytes = PdfEncodings.ConvertToBytes(value, TEXT_PDFDOCENCODING); + else + bytes = PdfEncodings.ConvertToBytes(value, encoding); + } + return bytes; + } + + public byte[] GetOriginalBytes() { + if (originalValue == null) + return GetBytes(); + return PdfEncodings.ConvertToBytes(originalValue, null); + } + + public PdfString SetHexWriting(bool hexWriting) { + this.hexWriting = hexWriting; + return this; + } + + public bool IsHexWriting() { + return hexWriting; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs b/iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs new file mode 100644 index 0000000..08c8608 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs @@ -0,0 +1,136 @@ +using System; + +/* + * $Id: PdfStructureElement.cs,v 1.3 2005/11/02 12:24:06 psoares33 Exp $ + * + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * This is a node in a document logical structure. It may contain a mark point or it may contain + * other nodes. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfStructureElement : PdfDictionary { + + /** + * Holds value of property kids. + */ + private PdfStructureElement parent; + private PdfStructureTreeRoot top; + + /** + * Holds value of property reference. + */ + private PdfIndirectReference reference; + + /** + * Creates a new instance of PdfStructureElement. + * @param parent the parent of this node + * @param structureType the type of structure. It may be a standard type or a user type mapped by the role map + */ + public PdfStructureElement(PdfStructureElement parent, PdfName structureType) { + top = parent.top; + Init(parent, structureType); + this.parent = parent; + Put(PdfName.P, parent.reference); + } + + /** + * Creates a new instance of PdfStructureElement. + * @param parent the parent of this node + * @param structureType the type of structure. It may be a standard type or a user type mapped by the role map + */ + public PdfStructureElement(PdfStructureTreeRoot parent, PdfName structureType) { + top = parent; + Init(parent, structureType); + Put(PdfName.P, parent.Reference); + } + + private void Init(PdfDictionary parent, PdfName structureType) { + PdfObject kido = parent.Get(PdfName.K); + PdfArray kids = null; + if (kido != null && !kido.IsArray()) + throw new ArgumentException("The parent has already another function."); + if (kido == null) { + kids = new PdfArray(); + parent.Put(PdfName.K, kids); + } + else + kids = (PdfArray)kido; + kids.Add(this); + Put(PdfName.S, structureType); + reference = top.Writer.PdfIndirectReference; + } + + /** + * Gets the parent of this node. + * @return the parent of this node + */ + public PdfDictionary Parent { + get { + return parent; + } + } + + internal void SetPageMark(int page, int mark) { + if (mark >= 0) + Put(PdfName.K, new PdfNumber(mark)); + top.SetPageMark(page, reference); + } + + /** + * Gets the reference this object will be written to. + * @return the reference this object will be written to + */ + public PdfIndirectReference Reference { + get { + return this.reference; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs b/iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs new file mode 100644 index 0000000..f5c47ba --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections; + +/* + * $Id: PdfStructureTreeRoot.cs,v 1.2 2005/10/18 15:29:53 psoares33 Exp $ + * + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * The structure tree root corresponds to the highest hierarchy level in a tagged PDF. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfStructureTreeRoot : PdfDictionary { + + private Hashtable parentTree = new Hashtable(); + private PdfIndirectReference reference; + + /** + * Holds value of property writer. + */ + private PdfWriter writer; + + /** Creates a new instance of PdfStructureTreeRoot */ + internal PdfStructureTreeRoot(PdfWriter writer) : base(PdfName.STRUCTTREEROOT) { + this.writer = writer; + reference = writer.PdfIndirectReference; + } + + /** + * Maps the user tags to the standard tags. The mapping will allow a standard application to make some sense of the tagged + * document whatever the user tags may be. + * @param used the user tag + * @param standard the standard tag + */ + public void MapRole(PdfName used, PdfName standard) { + PdfDictionary rm = (PdfDictionary)Get(PdfName.ROLEMAP); + if (rm == null) { + rm = new PdfDictionary(); + Put(PdfName.ROLEMAP, rm); + } + rm.Put(used, standard); + } + + /** + * Gets the writer. + * @return the writer + */ + public PdfWriter Writer { + get { + return this.writer; + } + } + + /** + * Gets the reference this object will be written to. + * @return the reference this object will be written to + */ + public PdfIndirectReference Reference { + get { + return this.reference; + } + } + + internal void SetPageMark(int page, PdfIndirectReference struc) { + PdfArray ar = (PdfArray)parentTree[page]; + if (ar == null) { + ar = new PdfArray(); + parentTree[page] = ar; + } + ar.Add(struc); + } + + private void NodeProcess(PdfDictionary struc, PdfIndirectReference reference) { + PdfObject obj = struc.Get(PdfName.K); + if (obj != null && obj.IsArray() && !((PdfObject)((PdfArray)obj).ArrayList[0]).IsNumber()) { + PdfArray ar = (PdfArray)obj; + ArrayList a = ar.ArrayList; + for (int k = 0; k < a.Count; ++k) { + PdfStructureElement e = (PdfStructureElement)a[k]; + a[k] = e.Reference; + NodeProcess(e, e.Reference); + } + } + if (reference != null) + writer.AddToBody(struc, reference); + } + + internal void BuildTree() { + Hashtable numTree = new Hashtable(); + foreach (int i in parentTree.Keys) { + PdfArray ar = (PdfArray)parentTree[i]; + numTree[i] = writer.AddToBody(ar).IndirectReference; + } + PdfDictionary dicTree = PdfNumberTree.WriteTree(numTree, writer); + if (dicTree != null) + Put(PdfName.PARENTTREE, writer.AddToBody(dicTree).IndirectReference); + + NodeProcess(this, reference); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTable.cs b/iTechSharp/iTextSharp/text/pdf/PdfTable.cs new file mode 100644 index 0000000..f8d567e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTable.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfTable is an object that contains the graphics and text of a table. + * + * @see iTextSharp.text.Table + * @see iTextSharp.text.Row + * @see iTextSharp.text.Cell + * @see PdfCell + */ + + public class PdfTable : Rectangle { + + // membervariables + + /** this is the number of columns in the table. */ + private int columns; + + /** this is the ArrayList with all the cell of the table header. */ + private ArrayList headercells; + + /** this is the ArrayList with all the cells in the table. */ + private ArrayList cells; + + /** Original table used to build this object*/ + protected Table table; + + /** Cached column widths. */ + protected float[] positions; + + // constructors + + /** + * Constructs a PdfTable-object. + * + * @param table a Table + * @param left the left border on the page + * @param right the right border on the page + * @param top the start position of the top of the table + */ + + internal PdfTable(Table table, float left, float right, float top) : base(left, top, right, top) { + // constructs a Rectangle (the bottomvalue will be changed afterwards) + this.table = table; + table.Complete(); + + // copying the attributes from class Table + CloneNonPositionParameters(table); + + this.columns = table.Columns; + positions = table.GetWidths(left, right - left); + + // initialisation of some parameters + Left = positions[0]; + Right = positions[positions.Length - 1]; + + headercells = new ArrayList(); + cells = new ArrayList(); + + UpdateRowAdditionsInternal(); + } + + // methods + + /** + * Updates the table row additions in the underlying table object and deletes all table rows, + * in order to preserve memory and detect future row additions. + *

Pre-requisite: the object must have been built with the parameter supportUpdateRowAdditions equals to true. + */ + + internal void UpdateRowAdditions() { + table.Complete(); + UpdateRowAdditionsInternal(); + table.DeleteAllRows(); + } + + /** + * Updates the table row additions in the underlying table object + */ + + private void UpdateRowAdditionsInternal() { + // correct table : fill empty cells/ parse table in table + int prevRows = Rows; + int rowNumber = 0; + int groupNumber = 0; + bool groupChange; + int firstDataRow = table.LastHeaderRow + 1; + Cell cell; + PdfCell currentCell; + ArrayList newCells = new ArrayList(); + int rows = table.Size + 1; + float[] offsets = new float[rows]; + for (int i = 0; i < rows; i++) { + offsets[i] = Bottom; + } + + // loop over all the rows + foreach (Row row in table) { + groupChange = false; + if (row.IsEmpty()) { + if (rowNumber < rows - 1 && offsets[rowNumber + 1] > offsets[rowNumber]) offsets[rowNumber + 1] = offsets[rowNumber]; + } + else { + for (int i = 0; i < row.Columns; i++) { + cell = (Cell) row.GetCell(i); + if (cell != null) { + currentCell = new PdfCell(cell, rowNumber+prevRows, positions[i], positions[i + cell.Colspan], offsets[rowNumber], Cellspacing, Cellpadding); + if (rowNumber < firstDataRow) { + currentCell.SetHeader(); + headercells.Add(currentCell); + if (!table.NotAddedYet) + continue; + } + try { + if (offsets[rowNumber] - currentCell.Height - Cellpadding < offsets[rowNumber + currentCell.Rowspan]) { + offsets[rowNumber + currentCell.Rowspan] = offsets[rowNumber] - currentCell.Height - Cellpadding; + } + } + catch (ArgumentOutOfRangeException) { + if (offsets[rowNumber] - currentCell.Height < offsets[rows - 1]) { + offsets[rows - 1] = offsets[rowNumber] - currentCell.Height; + } + } + currentCell.GroupNumber = groupNumber; + groupChange |= cell.GroupChange; + newCells.Add(currentCell); + } + } + } + rowNumber++; + if ( groupChange ) groupNumber++; + } + + // loop over all the cells + int n = newCells.Count; + for (int i = 0; i < n; i++) { + currentCell = (PdfCell) newCells[i]; + try { + currentCell.Bottom = offsets[currentCell.Rownumber-prevRows + currentCell.Rowspan]; + } + catch (ArgumentOutOfRangeException) { + currentCell.Bottom = offsets[rows - 1]; + } + } + cells.AddRange(newCells); + Bottom = offsets[rows - 1]; + } + + /** + * Get the number of rows + */ + + internal int Rows { + get { + return cells.Count == 0 ? 0 : ((PdfCell)cells[cells.Count-1]).Rownumber+1; + } + } + + /** @see com.lowagie.text.Element#type() */ + public override int Type { + get { + return Element.TABLE; + } + } + + /** + * Returns the arraylist with the cells of the table header. + * + * @return an ArrayList + */ + + internal ArrayList HeaderCells { + get { + return headercells; + } + } + + /** + * Checks if there is a table header. + * + * @return an ArrayList + */ + + internal bool HasHeader() { + return headercells.Count > 0; + } + + /** + * Returns the arraylist with the cells of the table. + * + * @return an ArrayList + */ + + internal ArrayList Cells { + get { + return cells; + } + } + + /** + * Returns the number of columns of the table. + * + * @return the number of columns + */ + + internal int Columns { + get { + return columns; + } + } + + /** + * Returns the cellpadding of the table. + * + * @return the cellpadding + */ + + internal float Cellpadding { + get { + return table.Cellpadding; + } + } + + /** + * Returns the cellspacing of the table. + * + * @return the cellspacing + */ + + internal float Cellspacing { + get { + return table.Cellspacing; + } + } + + /** + * Checks if this Table has to fit a page. + * + * @return true if the table may not be split + */ + + public bool HasToFitPageTable() { + return table.TableFitsPage; + } + + /** + * Checks if the cells of this Table have to fit a page. + * + * @return true if the cells may not be split + */ + + public bool HasToFitPageCells() { + return table.CellsFitPage; + } + + /** + * Gets the offset of this table. + * + * @return the space between this table and the previous element. + */ + public float Offset { + get { + return table.Offset; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs b/iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs new file mode 100644 index 0000000..f1af760 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs @@ -0,0 +1,281 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Implements the form XObject. + */ + + public class PdfTemplate : PdfContentByte { + public const int TYPE_TEMPLATE = 1; + public const int TYPE_IMPORTED = 2; + public const int TYPE_PATTERN = 3; + protected int type; + /** The indirect reference to this template */ + protected PdfIndirectReference thisReference; + + /** The resources used by this template */ + protected PageResources pageResources; + + /** The bounding box of this template */ + protected Rectangle bBox = new Rectangle(0, 0); + + protected PdfArray matrix; + + protected PdfTransparencyGroup group; + + protected IPdfOCG layer; + + /** + *Creates a PdfTemplate. + */ + + protected PdfTemplate() : base(null) { + type = TYPE_TEMPLATE; + } + + /** + * Creates new PdfTemplate + * + * @param wr the PdfWriter + */ + + internal PdfTemplate(PdfWriter wr) : base(wr) { + type = TYPE_TEMPLATE; + pageResources = new PageResources(); + pageResources.AddDefaultColor(wr.DefaultColorspace); + thisReference = writer.PdfIndirectReference; + } + + /** + * Creates a new template. + *

+ * Creates a new template that is nothing more than a form XObject. This template can be included + * in this PdfContentByte or in another template. Templates are only written + * to the output when the document is closed permitting things like showing text in the first page + * that is only defined in the last page. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the templated created + */ + public static PdfTemplate CreateTemplate(PdfWriter writer, float width, float height) { + return CreateTemplate(writer, width, height, null); + } + + internal static PdfTemplate CreateTemplate(PdfWriter writer, float width, float height, PdfName forcedName) { + PdfTemplate template = new PdfTemplate(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Gets the bounding width of this template. + * + * @return width the bounding width + */ + public float Width { + get { + return bBox.Width; + } + + set { + bBox.Left = 0; + bBox.Right = value; + } + } + + /** + * Gets the bounding heigth of this template. + * + * @return heigth the bounding height + */ + + public float Height { + get { + return bBox.Height; + } + + set { + bBox.Bottom = 0; + bBox.Top = value; + } + } + + public Rectangle BoundingBox { + get { + return bBox; + } + set { + this.bBox = value; + } + } + + /** + * Gets the layer this template belongs to. + * @return the layer this template belongs to or null for no layer defined + */ + public IPdfOCG Layer { + get { + return layer; + } + set { + layer = value; + } + } + + public void SetMatrix(float a, float b, float c, float d, float e, float f) { + matrix = new PdfArray(); + matrix.Add(new PdfNumber(a)); + matrix.Add(new PdfNumber(b)); + matrix.Add(new PdfNumber(c)); + matrix.Add(new PdfNumber(d)); + matrix.Add(new PdfNumber(e)); + matrix.Add(new PdfNumber(f)); + } + + internal PdfArray Matrix { + get { + return matrix; + } + } + + /** + * Gets the indirect reference to this template. + * + * @return the indirect reference to this template + */ + + public PdfIndirectReference IndirectReference { + get { + return thisReference; + } + } + + public void BeginVariableText() { + content.Append("/Tx BMC "); + } + + public void EndVariableText() { + content.Append("EMC "); + } + + /** + * Constructs the resources used by this template. + * + * @return the resources used by this template + */ + + internal virtual PdfObject Resources { + get { + return PageResources.Resources; + } + } + + /** + * Gets the stream representing this template. + * + * @return the stream representing this template + */ + + internal virtual PdfStream FormXObject { + get { + return new PdfFormXObject(this); + } + } + + /** + * Gets a duplicate of this PdfTemplate. All + * the members are copied by reference but the buffer stays different. + * @return a copy of this PdfTemplate + */ + + public override PdfContentByte Duplicate { + get { + PdfTemplate tpl = new PdfTemplate(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.bBox = new Rectangle(bBox); + tpl.group = group; + tpl.layer = layer; + if (matrix != null) { + tpl.matrix = new PdfArray(matrix); + } + tpl.separator = separator; + return tpl; + } + } + + public int Type { + get { + return type; + } + } + + internal override PageResources PageResources { + get { + return pageResources; + } + } + + public PdfTransparencyGroup Group { + get { + return this.group; + } + set { + group = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs b/iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs new file mode 100644 index 0000000..f86d366 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfTextArray defines an array with displacements and PdfString-objects. + *

+ * A TextArray is used with the operator TJ in PdfText. + * The first object in this array has to be a PdfString; + * see reference manual version 1.3 section 8.7.5, pages 346-347. + * OR + * see reference manual version 1.6 section 5.3.2, pages 378-379. + */ + + public class PdfTextArray{ + ArrayList arrayList = new ArrayList(); + + // To emit a more efficient array, we consolidate + // repeated numbers or strings into single array entries. + // "add( 50 ); Add( -50 );" will REMOVE the combined zero from the array. + // the alternative (leaving a zero in there) was Just Weird. + // --Mark Storer, May 12, 2008 + private String lastStr; + private float lastNum = float.NaN; + + // constructors + public PdfTextArray(String str) { + Add(str); + } + + public PdfTextArray() { + } + + /** + * Adds a PdfNumber to the PdfArray. + * + * @param number displacement of the string + */ + public void Add(PdfNumber number) { + Add((float)number.DoubleValue); + } + + public void Add(float number) { + if (number != 0) { + if (!float.IsNaN(lastNum)) { + lastNum += number; + if (lastNum != 0) { + ReplaceLast(lastNum); + } else { + arrayList.RemoveAt(arrayList.Count - 1); + } + } else { + lastNum = number; + arrayList.Add(lastNum); + } + lastStr = null; + } + // adding zero doesn't modify the TextArray at all + } + + public void Add(String str) { + if (str.Length > 0) { + if (lastStr != null) { + lastStr = lastStr + str; + ReplaceLast(lastStr); + } else { + lastStr = str; + arrayList.Add(lastStr); + } + lastNum = float.NaN; + } + // adding an empty string doesn't modify the TextArray at all + } + + internal ArrayList ArrayList { + get { + return arrayList; + } + } + + private void ReplaceLast(Object obj) { + // deliberately throw the IndexOutOfBoundsException if we screw up. + arrayList[arrayList.Count - 1] = obj; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTransition.cs b/iTechSharp/iTextSharp/text/pdf/PdfTransition.cs new file mode 100644 index 0000000..993d0dd --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTransition.cs @@ -0,0 +1,257 @@ +using System; + +/* + * Copyright 2002 by Josselin PUJO. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class PdfTransition { + /** + * Out Vertical Split + */ + public const int SPLITVOUT = 1; + /** + * Out Horizontal Split + */ + public const int SPLITHOUT = 2; + /** + * In Vertical Split + */ + public const int SPLITVIN = 3; + /** + * IN Horizontal Split + */ + public const int SPLITHIN = 4; + /** + * Vertical Blinds + */ + public const int BLINDV = 5; + /** + * Vertical Blinds + */ + public const int BLINDH = 6; + /** + * Inward Box + */ + public const int INBOX = 7; + /** + * Outward Box + */ + public const int OUTBOX = 8; + /** + * Left-Right Wipe + */ + public const int LRWIPE = 9; + /** + * Right-Left Wipe + */ + public const int RLWIPE = 10; + /** + * Bottom-Top Wipe + */ + public const int BTWIPE = 11; + /** + * Top-Bottom Wipe + */ + public const int TBWIPE = 12; + /** + * Dissolve + */ + public const int DISSOLVE = 13; + /** + * Left-Right Glitter + */ + public const int LRGLITTER = 14; + /** + * Top-Bottom Glitter + */ + public const int TBGLITTER = 15; + /** + * Diagonal Glitter + */ + public const int DGLITTER = 16; + + /** + * duration of the transition effect + */ + protected int duration; + /** + * type of the transition effect + */ + protected int type; + + /** + * Constructs a Transition. + * + */ + public PdfTransition() : this(BLINDH) {} + + /** + * Constructs a Transition. + * + *@param type type of the transition effect + */ + public PdfTransition(int type) : this(type,1) {} + + /** + * Constructs a Transition. + * + *@param type type of the transition effect + *@param duration duration of the transition effect + */ + public PdfTransition(int type, int duration) { + this.duration = duration; + this.type = type; + } + + + public int Duration { + get { + return duration; + } + } + + + public int Type { + get { + return type; + } + } + + public PdfDictionary TransitionDictionary { + get { + PdfDictionary trans = new PdfDictionary(PdfName.TRANS); + switch (type) { + case SPLITVOUT: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.V); + trans.Put(PdfName.M,PdfName.O); + break; + case SPLITHOUT: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.H); + trans.Put(PdfName.M,PdfName.O); + break; + case SPLITVIN: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.V); + trans.Put(PdfName.M,PdfName.I); + break; + case SPLITHIN: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.H); + trans.Put(PdfName.M,PdfName.I); + break; + case BLINDV: + trans.Put(PdfName.S,PdfName.BLINDS); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.V); + break; + case BLINDH: + trans.Put(PdfName.S,PdfName.BLINDS); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.H); + break; + case INBOX: + trans.Put(PdfName.S,PdfName.BOX); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.M,PdfName.I); + break; + case OUTBOX: + trans.Put(PdfName.S,PdfName.BOX); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.M,PdfName.O); + break; + case LRWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(0)); + break; + case RLWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(180)); + break; + case BTWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(90)); + break; + case TBWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(270)); + break; + case DISSOLVE: + trans.Put(PdfName.S,PdfName.DISSOLVE); + trans.Put(PdfName.D,new PdfNumber(duration)); + break; + case LRGLITTER: + trans.Put(PdfName.S,PdfName.GLITTER); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(0)); + break; + case TBGLITTER: + trans.Put(PdfName.S,PdfName.GLITTER); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(270)); + break; + case DGLITTER: + trans.Put(PdfName.S,PdfName.GLITTER); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(315)); + break; + } + return trans; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs b/iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs new file mode 100644 index 0000000..214bd95 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs @@ -0,0 +1,90 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** The transparency group dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfTransparencyGroup : PdfDictionary { + + /** + * Constructs a transparencyGroup. + */ + public PdfTransparencyGroup() { + Put(PdfName.S, PdfName.TRANSPARENCY); + } + + /** + * Determining the initial backdrop against which its stack is composited. + * @param isolated + */ + public bool Isolated { + set { + if (value) + Put(PdfName.I, PdfBoolean.PDFTRUE); + else + Remove(PdfName.I); + } + } + + /** + * Determining whether the objects within the stack are composited with one another or only with the group's backdrop. + * @param knockout + */ + public bool Knockout { + set { + if (value) + Put(PdfName.K, PdfBoolean.PDFTRUE); + else + Remove(PdfName.K); + } + } + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfWriter.cs b/iTechSharp/iTextSharp/text/pdf/PdfWriter.cs new file mode 100644 index 0000000..dafd59d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfWriter.cs @@ -0,0 +1,2973 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.util.collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf.events; +using iTextSharp.text.pdf.interfaces; +using iTextSharp.text.pdf.intern; +using iTextSharp.text.pdf.collection; +using iTextSharp.text.xml.xmp; +using Org.BouncyCastle.X509; +/* + * $Id: PdfWriter.cs,v 1.48 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A DocWriter class for PDF. + *

+ * When this PdfWriter is added + * to a certain PdfDocument, the PDF representation of every Element + * added to this Document will be written to the outputstream.

+ */ + + public class PdfWriter : DocWriter, + IPdfViewerPreferences, + IPdfEncryptionSettings, + IPdfVersion, + IPdfDocumentActions, + IPdfPageActions, + IPdfXConformance, + IPdfRunDirection, + IPdfAnnotations { + + // INNER CLASSES + + /** + * This class generates the structure of a PDF document. + *

+ * This class covers the third section of Chapter 5 in the 'Portable Document Format + * Reference Manual version 1.3' (page 55-60). It contains the body of a PDF document + * (section 5.14) and it can also generate a Cross-reference Table (section 5.15). + * + * @see PdfWriter + * @see PdfObject + * @see PdfIndirectObject + */ + + public class PdfBody { + + // inner classes + + /** + * PdfCrossReference is an entry in the PDF Cross-Reference table. + */ + + internal class PdfCrossReference : IComparable { + + // membervariables + private int type; + + /** Byte offset in the PDF file. */ + private int offset; + + private int refnum; + /** generation of the object. */ + private int generation; + + // constructors + /** + * Constructs a cross-reference element for a PdfIndirectObject. + * @param refnum + * @param offset byte offset of the object + * @param generation generationnumber of the object + */ + + internal PdfCrossReference(int refnum, int offset, int generation) { + type = 0; + this.offset = offset; + this.refnum = refnum; + this.generation = generation; + } + + /** + * Constructs a cross-reference element for a PdfIndirectObject. + * @param refnum + * @param offset byte offset of the object + */ + + internal PdfCrossReference(int refnum, int offset) { + type = 1; + this.offset = offset; + this.refnum = refnum; + this.generation = 0; + } + + internal PdfCrossReference(int type, int refnum, int offset, int generation) { + this.type = type; + this.offset = offset; + this.refnum = refnum; + this.generation = generation; + } + + internal int Refnum { + get { + return refnum; + } + } + + /** + * Returns the PDF representation of this PdfObject. + * @param os + * @throws IOException + */ + + public void ToPdf(Stream os) { + String s1 = offset.ToString().PadLeft(10, '0'); + String s2 = generation.ToString().PadLeft(5, '0'); + ByteBuffer buf = new ByteBuffer(40); + if (generation == 65535) { + buf.Append(s1).Append(' ').Append(s2).Append(" f \n"); + } + else { + buf.Append(s1).Append(' ').Append(s2).Append(" n \n"); + } + os.Write(buf.Buffer, 0, buf.Size); + } + + /** + * Writes PDF syntax to the Stream + * @param midSize + * @param os + * @throws IOException + */ + public void ToPdf(int midSize, Stream os) { + os.WriteByte((byte)type); + while (--midSize >= 0) + os.WriteByte((byte)((offset >> (8 * midSize)) & 0xff)); + os.WriteByte((byte)((generation >> 8) & 0xff)); + os.WriteByte((byte)(generation & 0xff)); + } + + /** + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int CompareTo(Object o) { + PdfCrossReference other = (PdfCrossReference)o; + return (refnum < other.refnum ? -1 : (refnum==other.refnum ? 0 : 1)); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public override bool Equals(Object obj) { + if (obj is PdfCrossReference) { + PdfCrossReference other = (PdfCrossReference)obj; + return (refnum == other.refnum); + } + else + return false; + } + + + public override int GetHashCode() { + return refnum; + } + } + + // membervariables + + private const int OBJSINSTREAM = 200; + + /** array containing the cross-reference table of the normal objects. */ + private k_Tree xrefs; + private int refnum; + /** the current byteposition in the body. */ + private int position; + private PdfWriter writer; + private ByteBuffer index; + private ByteBuffer streamObjects; + private int currentObjNum; + private int numObj = 0; + + // constructors + + /** + * Constructs a new PdfBody. + * @param writer + */ + internal PdfBody(PdfWriter writer) { + xrefs = new k_Tree(); + xrefs[new PdfCrossReference(0, 0, 65535)] = null; + position = writer.Os.Counter; + refnum = 1; + this.writer = writer; + } + + // methods + + internal int Refnum { + set { + this.refnum = value; + } + } + + private PdfWriter.PdfBody.PdfCrossReference AddToObjStm(PdfObject obj, int nObj) { + if (numObj >= OBJSINSTREAM) + FlushObjStm(); + if (index == null) { + index = new ByteBuffer(); + streamObjects = new ByteBuffer(); + currentObjNum = IndirectReferenceNumber; + numObj = 0; + } + int p = streamObjects.Size; + int idx = numObj++; + PdfEncryption enc = writer.crypto; + writer.crypto = null; + obj.ToPdf(writer, streamObjects); + writer.crypto = enc; + streamObjects.Append(' '); + index.Append(nObj).Append(' ').Append(p).Append(' '); + return new PdfWriter.PdfBody.PdfCrossReference(2, nObj, currentObjNum, idx); + } + + internal void FlushObjStm() { + if (numObj == 0) + return; + int first = index.Size; + index.Append(streamObjects); + PdfStream stream = new PdfStream(index.ToByteArray()); + stream.FlateCompress(); + stream.Put(PdfName.TYPE, PdfName.OBJSTM); + stream.Put(PdfName.N, new PdfNumber(numObj)); + stream.Put(PdfName.FIRST, new PdfNumber(first)); + Add(stream, currentObjNum); + index = null; + streamObjects = null; + numObj = 0; + } + + /** + * Adds a PdfObject to the body. + *

+ * This methods creates a PdfIndirectObject with a + * certain number, containing the given PdfObject. + * It also adds a PdfCrossReference for this object + * to an ArrayList that will be used to build the + * Cross-reference Table. + * + * @param object a PdfObject + * @return a PdfIndirectObject + * @throws IOException + */ + + internal PdfIndirectObject Add(PdfObject objecta) { + return Add(objecta, IndirectReferenceNumber); + } + + internal PdfIndirectObject Add(PdfObject objecta, bool inObjStm) { + return Add(objecta, IndirectReferenceNumber, inObjStm); + } + + /** + * Gets a PdfIndirectReference for an object that will be created in the future. + * @return a PdfIndirectReference + */ + + internal PdfIndirectReference PdfIndirectReference { + get { + return new PdfIndirectReference(0, IndirectReferenceNumber); + } + } + + internal int IndirectReferenceNumber { + get { + int n = refnum++; + xrefs[new PdfCrossReference(n, 0, 65536)] = null; + return n; + } + } + + /** + * Adds a PdfObject to the body given an already existing + * PdfIndirectReference. + *

+ * This methods creates a PdfIndirectObject with the number given by + * ref, containing the given PdfObject. + * It also adds a PdfCrossReference for this object + * to an ArrayList that will be used to build the + * Cross-reference Table. + * + * @param object a PdfObject + * @param ref a PdfIndirectReference + * @return a PdfIndirectObject + * @throws IOException + */ + + internal PdfIndirectObject Add(PdfObject objecta, PdfIndirectReference refa) { + return Add(objecta, refa.Number); + } + + internal PdfIndirectObject Add(PdfObject objecta, PdfIndirectReference refa, bool inObjStm) { + return Add(objecta, refa.Number, inObjStm); + } + + internal PdfIndirectObject Add(PdfObject objecta, int refNumber) { + return Add(objecta, refNumber, true); // to false + } + + internal PdfIndirectObject Add(PdfObject objecta, int refNumber, bool inObjStm) { + if (inObjStm && objecta.CanBeInObjStm() && writer.FullCompression) { + PdfCrossReference pxref = AddToObjStm(objecta, refNumber); + PdfIndirectObject indirect = new PdfIndirectObject(refNumber, objecta, writer); + xrefs.Remove(pxref); + xrefs[pxref] = null; + return indirect; + } + else { + PdfIndirectObject indirect = new PdfIndirectObject(refNumber, objecta, writer); + PdfCrossReference pxref = new PdfCrossReference(refNumber, position); + xrefs.Remove(pxref); + xrefs[pxref] = null; + indirect.WriteTo(writer.Os); + position = writer.Os.Counter; + return indirect; + } + } + + /** + * Returns the offset of the Cross-Reference table. + * + * @return an offset + */ + + internal int Offset { + get { + return position; + } + } + + /** + * Returns the total number of objects contained in the CrossReferenceTable of this Body. + * + * @return a number of objects + */ + + internal int Size { + get { + k_Iterator it = xrefs.End.Clone(); + it.Prev(); + return Math.Max(((PdfCrossReference)((DictionaryEntry)it.Current).Key).Refnum + 1, refnum); + } + } + + /** + * Returns the CrossReferenceTable of the Body. + * @param os + * @param root + * @param info + * @param encryption + * @param fileID + * @param prevxref + * @throws IOException + */ + + internal void WriteCrossReferenceTable(Stream os, PdfIndirectReference root, PdfIndirectReference info, PdfIndirectReference encryption, PdfObject fileID, int prevxref) { + int refNumber = 0; + if (writer.FullCompression) { + FlushObjStm(); + refNumber = IndirectReferenceNumber; + xrefs[new PdfCrossReference(refNumber, position)] = null; + } + PdfCrossReference entry = (PdfCrossReference)((DictionaryEntry)xrefs.Begin.Current).Key; + int first = entry.Refnum; + int len = 0; + ArrayList sections = new ArrayList(); + for (k_Iterator i = xrefs.Begin.Clone(); i != xrefs.End; i.Next()) { + entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; + if (first + len == entry.Refnum) + ++len; + else { + sections.Add(first); + sections.Add(len); + first = entry.Refnum; + len = 1; + } + } + sections.Add(first); + sections.Add(len); + if (writer.FullCompression) { + int mid = 4; + uint mask = 0xff000000; + for (; mid > 1; --mid) { + if ((mask & position) != 0) + break; + mask >>= 8; + } + ByteBuffer buf = new ByteBuffer(); + + for (k_Iterator i = xrefs.Begin.Clone(); i != xrefs.End; i.Next()) { + entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; + entry.ToPdf(mid, buf); + } + PdfStream xr = new PdfStream(buf.ToByteArray()); + buf = null; + xr.FlateCompress(); + xr.Put(PdfName.SIZE, new PdfNumber(Size)); + xr.Put(PdfName.ROOT, root); + if (info != null) { + xr.Put(PdfName.INFO, info); + } + if (encryption != null) + xr.Put(PdfName.ENCRYPT, encryption); + if (fileID != null) + xr.Put(PdfName.ID, fileID); + xr.Put(PdfName.W, new PdfArray(new int[]{1, mid, 2})); + xr.Put(PdfName.TYPE, PdfName.XREF); + PdfArray idx = new PdfArray(); + for (int k = 0; k < sections.Count; ++k) + idx.Add(new PdfNumber((int)sections[k])); + xr.Put(PdfName.INDEX, idx); + if (prevxref > 0) + xr.Put(PdfName.PREV, new PdfNumber(prevxref)); + PdfEncryption enc = writer.crypto; + writer.crypto = null; + PdfIndirectObject indirect = new PdfIndirectObject(refNumber, xr, writer); + indirect.WriteTo(writer.Os); + writer.crypto = enc; + } + else { + byte[] tmp = GetISOBytes("xref\n"); + os.Write(tmp, 0, tmp.Length); + k_Iterator i = xrefs.Begin.Clone(); + for (int k = 0; k < sections.Count; k += 2) { + first = (int)sections[k]; + len = (int)sections[k + 1]; + tmp = GetISOBytes(first.ToString()); + os.Write(tmp, 0, tmp.Length); + os.WriteByte((byte)' '); + tmp = GetISOBytes(len.ToString()); + os.Write(tmp, 0, tmp.Length); + os.WriteByte((byte)'\n'); + while (len-- > 0) { + entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; + entry.ToPdf(os); + i.Next(); + } + } + } + } + } + + /** + * PdfTrailer is the PDF Trailer object. + *

+ * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 5.16 (page 59-60). + */ + + internal class PdfTrailer : PdfDictionary { + + // membervariables + + internal int offset; + + // constructors + + /** + * Constructs a PDF-Trailer. + * + * @param size the number of entries in the PdfCrossReferenceTable + * @param offset offset of the PdfCrossReferenceTable + * @param root an indirect reference to the root of the PDF document + * @param info an indirect reference to the info object of the PDF document + * @param encryption + * @param fileID + * @param prevxref + */ + + internal PdfTrailer(int size, int offset, PdfIndirectReference root, PdfIndirectReference info, PdfIndirectReference encryption, PdfObject fileID, int prevxref) { + this.offset = offset; + Put(PdfName.SIZE, new PdfNumber(size)); + Put(PdfName.ROOT, root); + if (info != null) { + Put(PdfName.INFO, info); + } + if (encryption != null) + Put(PdfName.ENCRYPT, encryption); + if (fileID != null) + Put(PdfName.ID, fileID); + if (prevxref > 0) + Put(PdfName.PREV, new PdfNumber(prevxref)); + } + + /** + * Returns the PDF representation of this PdfObject. + * @param writer + * @param os + * @throws IOException + */ + public override void ToPdf(PdfWriter writer, Stream os) { + byte[] tmp = GetISOBytes("trailer\n"); + os.Write(tmp, 0, tmp.Length); + base.ToPdf(null, os); + tmp = GetISOBytes("\nstartxref\n"); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes(offset.ToString()); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes("\n%%EOF\n"); + os.Write(tmp, 0, tmp.Length); + } + } + + // ESSENTIALS + + // Construct a PdfWriter instance + + /** + * Constructs a PdfWriter. + */ + protected PdfWriter() { + root = new PdfPages(this); + } + + /** + * Constructs a PdfWriter. + *

+ * Remark: a PdfWriter can only be constructed by calling the method + * getInstance(Document document, Stream os). + * + * @param document The PdfDocument that has to be written + * @param os The Stream the writer has to write to. + */ + + protected PdfWriter(PdfDocument document, Stream os) : base(document, os) { + root = new PdfPages(this); + pdf = document; + directContent = new PdfContentByte(this); + directContentUnder = new PdfContentByte(this); + } + + // get an instance of the PdfWriter + + /** + * Use this method to get an instance of the PdfWriter. + * + * @param document The Document that has to be written + * @param os The Stream the writer has to write to. + * @return a new PdfWriter + * + * @throws DocumentException on error + */ + + public static PdfWriter GetInstance(Document document, Stream os) + { + PdfDocument pdf = new PdfDocument(); + document.AddDocListener(pdf); + PdfWriter writer = new PdfWriter(pdf, os); + pdf.AddWriter(writer); + return writer; + } + + /** + * Use this method to get an instance of the PdfWriter. + * + * @return a new PdfWriter + * @param document The Document that has to be written + * @param os The Stream the writer has to write to. + * @param listener A DocListener to pass to the PdfDocument. + * @throws DocumentException on error + */ + + public static PdfWriter GetInstance(Document document, Stream os, IDocListener listener) + { + PdfDocument pdf = new PdfDocument(); + pdf.AddDocListener(listener); + document.AddDocListener(pdf); + PdfWriter writer = new PdfWriter(pdf, os); + pdf.AddWriter(writer); + return writer; + } + + // the PdfDocument instance + /** the pdfdocument object. */ + protected internal PdfDocument pdf; + + /** + * Gets the PdfDocument associated with this writer. + * @return the PdfDocument + */ + internal PdfDocument PdfDocument { + get { + return pdf; + } + } + + /** + * Use this method to get the info dictionary if you want to + * change it directly (add keys and values to the info dictionary). + * @return the info dictionary + */ + public PdfDictionary Info { + get { + return ((PdfDocument)document).Info; + } + } + + /** + * Use this method to get the current vertical page position. + * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects + * for elements that do not terminate the lines they've started because those lines will get + * terminated. + * @return The current vertical page position. + */ + public float GetVerticalPosition(bool ensureNewLine) { + return pdf.GetVerticalPosition(ensureNewLine); + } + + // the PdfDirectContentByte instances + + /* + * You should see Direct Content as a canvas on which you can draw + * graphics and text. One canvas goes on top of the page (getDirectContent), + * the other goes underneath (getDirectContentUnder). + * You can always the same object throughout your document, + * even if you have moved to a new page. Whatever you add on + * the canvas will be displayed on top or under the current page. + */ + + /** The direct content in this document. */ + protected PdfContentByte directContent; + + /** The direct content under in this document. */ + protected PdfContentByte directContentUnder; + + /** + * Use this method to get the direct content for this document. + * There is only one direct content, multiple calls to this method + * will allways retrieve the same object. + * @return the direct content + */ + public virtual PdfContentByte DirectContent { + get { + if (!open) + throw new Exception("The document is not open."); + return directContent; + } + } + + /** + * Use this method to get the direct content under for this document. + * There is only one direct content, multiple calls to this method + * will allways retrieve the same object. + * @return the direct content + */ + public virtual PdfContentByte DirectContentUnder { + get { + if (!open) + throw new Exception("The document is not open."); + return directContentUnder; + } + } + + /** + * Resets all the direct contents to empty. + * This happens when a new page is started. + */ + internal void ResetContent() { + directContent.Reset(); + directContentUnder.Reset(); + } + + // PDF body + + /* + * A PDF file has 4 parts: a header, a body, a cross-reference table, and a trailer. + * The body contains all the PDF objects that make up the PDF document. + * Each element gets a reference (a set of numbers) and the byte position of + * every object is stored in the cross-reference table. + * Use these methods only if you know what you're doing. + */ + + /** body of the PDF document */ + protected internal PdfBody body; + + /** + * Adds the local destinations to the body of the document. + * @param dest the Hashtable containing the destinations + * @throws IOException on error + */ + internal void AddLocalDestinations(k_Tree dest) { + foreach (String name in dest.Keys) { + Object[] obj = (Object[])dest[name]; + PdfDestination destination = (PdfDestination)obj[2]; + if (destination == null) + throw new Exception("The name '" + name + "' has no local destination."); + if (obj[1] == null) + obj[1] = PdfIndirectReference; + AddToBody(destination, (PdfIndirectReference)obj[1]); + } + } + + /** + * Adds an object to the PDF body. + * @param object + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta) { + PdfIndirectObject iobj = body.Add(objecta); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param inObjStm + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, bool inObjStm) { + PdfIndirectObject iobj = body.Add(objecta, inObjStm); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param ref + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, PdfIndirectReference refa) { + PdfIndirectObject iobj = body.Add(objecta, refa); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param ref + * @param inObjStm + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, PdfIndirectReference refa, bool inObjStm) { + PdfIndirectObject iobj = body.Add(objecta, refa, inObjStm); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param refNumber + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, int refNumber) { + PdfIndirectObject iobj = body.Add(objecta, refNumber); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param refNumber + * @param inObjStm + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, int refNumber, bool inObjStm) { + PdfIndirectObject iobj = body.Add(objecta, refNumber, inObjStm); + return iobj; + } + + /** + * Gets a PdfIndirectReference for an object that + * will be created in the future. + * @return the PdfIndirectReference + */ + public PdfIndirectReference PdfIndirectReference { + get { + return body.PdfIndirectReference; + } + } + + internal int IndirectReferenceNumber { + get { + return body.IndirectReferenceNumber; + } + } + + /** + * Returns the outputStreamCounter. + * @return the outputStreamCounter + */ + internal OutputStreamCounter Os { + get { + return os; + } + } + + // PDF Catalog + + /* + * The Catalog is also called the root object of the document. + * Whereas the Cross-Reference maps the objects number with the + * byte offset so that the viewer can find the objects, the + * Catalog tells the viewer the numbers of the objects needed + * to render the document. + */ + + protected virtual PdfDictionary GetCatalog(PdfIndirectReference rootObj) { + PdfDictionary catalog = pdf.GetCatalog(rootObj); + // [F12] tagged PDF + if (tagged) { + this.StructureTreeRoot.BuildTree(); + catalog.Put(PdfName.STRUCTTREEROOT, structureTreeRoot.Reference); + PdfDictionary mi = new PdfDictionary(); + mi.Put(PdfName.MARKED, PdfBoolean.PDFTRUE); + if (userProperties) + mi.Put(PdfName.USERPROPERTIES, PdfBoolean.PDFTRUE); + catalog.Put(PdfName.MARKINFO, mi); + } + // [F13] OCG + if (documentOCG.Count != 0) { + FillOCProperties(false); + catalog.Put(PdfName.OCPROPERTIES, vOCProperties); + } + return catalog; + } + + /** Holds value of property extraCatalog. */ + protected internal PdfDictionary extraCatalog; + + /** + * Sets extra keys to the catalog. + * @return the catalog to change + */ + public PdfDictionary ExtraCatalog { + get { + if (extraCatalog == null) + extraCatalog = new PdfDictionary(); + return this.extraCatalog; + } + } + + // PdfPages + + /* + * The page root keeps the complete page tree of the document. + * There's an entry in the Catalog that refers to the root + * of the page tree, the page tree contains the references + * to pages and other page trees. + */ + + /** The root of the page tree. */ + protected PdfPages root; + /** The PdfIndirectReference to the pages. */ + protected ArrayList pageReferences = new ArrayList(); + /** The current page number. */ + protected int currentPageNumber = 1; + + /** + * Use this method to make sure the page tree has a lineair structure + * (every leave is attached directly to the root). + * Use this method to allow page reordering with method reorderPages. + */ + public void SetLinearPageMode() { + root.SetLinearMode(null); + } + + /** + * Use this method to reorder the pages in the document. + * A null argument value only returns the number of pages to process. + * It is advisable to issue a Document.newPage() before using this method. + * @return the total number of pages + * @param order an array with the new page sequence. It must have the + * same size as the number of pages. + * @throws DocumentException if all the pages are not present in the array + */ + public int ReorderPages(int[] order) { + return root.ReorderPages(order); + } + + /** + * Use this method to get a reference to a page existing or not. + * If the page does not exist yet the reference will be created + * in advance. If on closing the document, a page number greater + * than the total number of pages was requested, an exception + * is thrown. + * @param page the page number. The first page is 1 + * @return the reference to the page + */ + public virtual PdfIndirectReference GetPageReference(int page) { + --page; + if (page < 0) + throw new ArgumentOutOfRangeException("The page numbers start at 1."); + PdfIndirectReference refa; + if (page < pageReferences.Count) { + refa = (PdfIndirectReference)pageReferences[page]; + if (refa == null) { + refa = body.PdfIndirectReference; + pageReferences[page] = refa; + } + } + else { + int empty = page - pageReferences.Count; + for (int k = 0; k < empty; ++k) + pageReferences.Add(null); + refa = body.PdfIndirectReference; + pageReferences.Add(refa); + } + return refa; + } + + /** + * Gets the pagenumber of this document. + * This number can be different from the real pagenumber, + * if you have (re)set the page number previously. + * @return a page number + */ + public int PageNumber { + get { + return pdf.PageNumber; + } + } + + internal virtual PdfIndirectReference CurrentPage { + get { + return GetPageReference(currentPageNumber); + } + } + + public virtual int CurrentPageNumber { + get { + return currentPageNumber; + } + } + + /** + * Adds some PdfContents to this Writer. + *

+ * The document has to be open before you can begin to add content + * to the body of the document. + * + * @return a PdfIndirectReference + * @param page the PdfPage to add + * @param contents the PdfContents of the page + * @throws PdfException on error + */ + internal virtual PdfIndirectReference Add(PdfPage page, PdfContents contents) { + if (!open) { + throw new PdfException("The document isn't open."); + } + PdfIndirectObject objecta; + objecta = AddToBody(contents); + page.Add(objecta.IndirectReference); + if (group != null) { + page.Put(PdfName.GROUP, group); + group = null; + } + else if (rgbTransparencyBlending) { + PdfDictionary pp = new PdfDictionary(); + pp.Put(PdfName.TYPE, PdfName.GROUP); + pp.Put(PdfName.S, PdfName.TRANSPARENCY); + pp.Put(PdfName.CS, PdfName.DEVICERGB); + page.Put(PdfName.GROUP, pp); + } + root.AddPage(page); + currentPageNumber++; + return null; + } + + // page events + + /* + * Page events are specific for iText, not for PDF. + * Upon specific events (for instance when a page starts + * or ends), the corresponing method in the page event + * implementation that is added to the writer is invoked. + */ + + /** The PdfPageEvent for this document. */ + private IPdfPageEvent pageEvent; + + /** + * Gets the PdfPageEvent for this document or null + * if none is set. + * @return the PdfPageEvent for this document or null + * if none is set + */ + public IPdfPageEvent PageEvent { + get { + return pageEvent; + } + set { + if (value == null) this.pageEvent = null; + else if (this.pageEvent == null) this.pageEvent = value; + else if (this.pageEvent is PdfPageEventForwarder) ((PdfPageEventForwarder)this.pageEvent).AddPageEvent(value); + else { + PdfPageEventForwarder forward = new PdfPageEventForwarder(); + forward.AddPageEvent(this.pageEvent); + forward.AddPageEvent(value); + this.pageEvent = forward; + } + } + } + + // Open en Close method + method that create the PDF + + /** A number refering to the previous Cross-Reference Table. */ + protected int prevxref = 0; + + /** + * Signals that the Document has been opened and that + * Elements can be added. + *

+ * When this method is called, the PDF-document header is + * written to the outputstream. + */ + public override void Open() { + base.Open(); + pdf_version.WriteHeader(os); + body = new PdfBody(this); + if (pdfxConformance.IsPdfX32002()) { + PdfDictionary sec = new PdfDictionary(); + sec.Put(PdfName.GAMMA, new PdfArray(new float[]{2.2f,2.2f,2.2f})); + sec.Put(PdfName.MATRIX, new PdfArray(new float[]{0.4124f,0.2126f,0.0193f,0.3576f,0.7152f,0.1192f,0.1805f,0.0722f,0.9505f})); + sec.Put(PdfName.WHITEPOINT, new PdfArray(new float[]{0.9505f,1f,1.089f})); + PdfArray arr = new PdfArray(PdfName.CALRGB); + arr.Add(sec); + SetDefaultColorspace(PdfName.DEFAULTRGB, AddToBody(arr).IndirectReference); + } + } + + /** + * Signals that the Document was closed and that no other + * Elements will be added. + *

+ * The pages-tree is built and written to the outputstream. + * A Catalog is constructed, as well as an Info-object, + * the referencetable is composed and everything is written + * to the outputstream embedded in a Trailer. + */ + public override void Close() { + if (open) { + if ((currentPageNumber - 1) != pageReferences.Count) + throw new Exception("The page " + pageReferences.Count + + " was requested but the document has only " + (currentPageNumber - 1) + " pages."); + pdf.Close(); + AddSharedObjectsToBody(); + // add the root to the body + PdfIndirectReference rootRef = root.WritePageTree(); + // make the catalog-object and add it to the body + PdfDictionary catalog = GetCatalog(rootRef); + // [C9] if there is XMP data to add: add it + if (xmpMetadata != null) { + PdfStream xmp = new PdfStream(xmpMetadata); + xmp.Put(PdfName.TYPE, PdfName.METADATA); + xmp.Put(PdfName.SUBTYPE, PdfName.XML); + if (crypto != null && !crypto.IsMetadataEncrypted()) { + PdfArray ar = new PdfArray(); + ar.Add(PdfName.CRYPT); + xmp.Put(PdfName.FILTER, ar); + } + catalog.Put(PdfName.METADATA, body.Add(xmp).IndirectReference); + } + // [C10] make pdfx conformant + if (IsPdfX()) { + pdfxConformance.CompleteInfoDictionary(Info); + pdfxConformance.CompleteExtraCatalog(ExtraCatalog); + } + // [C11] Output Intents + if (extraCatalog != null) { + catalog.MergeDifferent(extraCatalog); + } + + WriteOutlines(catalog, false); + + // add the Catalog to the body + PdfIndirectObject indirectCatalog = AddToBody(catalog, false); + // add the info-object to the body + PdfIndirectObject infoObj = AddToBody(Info, false); + + // [F1] encryption + PdfIndirectReference encryption = null; + PdfObject fileID = null; + body.FlushObjStm(); + if (crypto != null) { + PdfIndirectObject encryptionObject = AddToBody(crypto.GetEncryptionDictionary(), false); + encryption = encryptionObject.IndirectReference; + fileID = crypto.FileID; + } + else + fileID = PdfEncryption.CreateInfoId(PdfEncryption.CreateDocumentId()); + + // write the cross-reference table of the body + body.WriteCrossReferenceTable(os, indirectCatalog.IndirectReference, + infoObj.IndirectReference, encryption, fileID, prevxref); + + // make the trailer + // [F2] full compression + if (fullCompression) { + byte[] tmp = GetISOBytes("startxref\n"); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes(body.Offset.ToString()); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes("\n%%EOF\n"); + os.Write(tmp, 0, tmp.Length); + } + else { + PdfTrailer trailer = new PdfTrailer(body.Size, + body.Offset, + indirectCatalog.IndirectReference, + infoObj.IndirectReference, + encryption, + fileID, prevxref); + trailer.ToPdf(this, os); + } + base.Close(); + } + } + + protected void AddSharedObjectsToBody() { + // add the fonts + foreach (FontDetails details in documentFonts.Values) { + details.WriteFont(this); + } + // add the form XObjects + foreach (Object[] objs in formXObjects.Values) { + PdfTemplate template = (PdfTemplate)objs[1]; + if (template != null && template.IndirectReference is PRIndirectReference) + continue; + if (template != null && template.Type == PdfTemplate.TYPE_TEMPLATE) { + AddToBody(template.FormXObject, template.IndirectReference); + } + } + // add all the dependencies in the imported pages + foreach (PdfReaderInstance rd in importedPages.Values) { + currentPdfReaderInstance = rd; + currentPdfReaderInstance.WriteAllPages(); + } + currentPdfReaderInstance = null; + // add the color + foreach (ColorDetails color in documentColors.Values) { + AddToBody(color.GetSpotColor(this), color.IndirectReference); + } + // add the pattern + foreach (PdfPatternPainter pat in documentPatterns.Keys) { + AddToBody(pat.Pattern, pat.IndirectReference); + } + // add the shading patterns + foreach (PdfShadingPattern shadingPattern in documentShadingPatterns.Keys) { + shadingPattern.AddToBody(); + } + // add the shadings + foreach (PdfShading shading in documentShadings.Keys) { + shading.AddToBody(); + } + // add the extgstate + foreach (DictionaryEntry entry in documentExtGState) { + PdfDictionary gstate = (PdfDictionary)entry.Key; + PdfObject[] obj = (PdfObject[])entry.Value; + AddToBody(gstate, (PdfIndirectReference)obj[1]); + } + + // add the properties + foreach (DictionaryEntry entry in documentProperties) { + Object prop = entry.Key; + PdfObject[] obj = (PdfObject[])entry.Value; + if (prop is PdfLayerMembership){ + PdfLayerMembership layer = (PdfLayerMembership)prop; + AddToBody(layer.PdfObject, layer.Ref); + } + else if ((prop is PdfDictionary) && !(prop is PdfLayer)){ + AddToBody((PdfDictionary)prop, (PdfIndirectReference)obj[1]); + } + } + foreach (IPdfOCG layer in documentOCG.Keys) { + AddToBody(layer.PdfObject, layer.Ref); + } + } + + // Root data for the PDF document (used when composing the Catalog) + + // [C1] Outlines (bookmarks) + + /** + * Use this method to get the root outline + * and construct bookmarks. + * @return the root outline + */ + public PdfOutline RootOutline { + get { + return directContent.RootOutline; + } + } + + protected ArrayList newBookmarks; + + /** + * Sets the bookmarks. The list structure is defined in + * {@link SimpleBookmark}. + * @param outlines the bookmarks or null to remove any + */ + public ArrayList Outlines { + set { + newBookmarks = value; + } + } + + protected internal void WriteOutlines(PdfDictionary catalog, bool namedAsNames) { + if (newBookmarks == null || newBookmarks.Count == 0) + return; + PdfDictionary top = new PdfDictionary(); + PdfIndirectReference topRef = this.PdfIndirectReference; + Object[] kids = SimpleBookmark.IterateOutlines(this, topRef, newBookmarks, namedAsNames); + top.Put(PdfName.FIRST, (PdfIndirectReference)kids[0]); + top.Put(PdfName.LAST, (PdfIndirectReference)kids[1]); + top.Put(PdfName.COUNT, new PdfNumber((int)kids[2])); + AddToBody(top, topRef); + catalog.Put(PdfName.OUTLINES, topRef); + } + + // [C2] PdfVersion interface + /** possible PDF version (header) */ + public const char VERSION_1_2 = '2'; + /** possible PDF version (header) */ + public const char VERSION_1_3 = '3'; + /** possible PDF version (header) */ + public const char VERSION_1_4 = '4'; + /** possible PDF version (header) */ + public const char VERSION_1_5 = '5'; + /** possible PDF version (header) */ + public const char VERSION_1_6 = '6'; + /** possible PDF version (header) */ + public const char VERSION_1_7 = '7'; + + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_2 = new PdfName("1.2"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_3 = new PdfName("1.3"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_4 = new PdfName("1.4"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_5 = new PdfName("1.5"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_6 = new PdfName("1.6"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_7 = new PdfName("1.7"); + + /** Stores the version information for the header and the catalog. */ + protected PdfVersionImp pdf_version = new PdfVersionImp(); + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(char) + */ + public virtual char PdfVersion { + set { + pdf_version.PdfVersion = value; + } + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setAtLeastPdfVersion(char) + */ + public void SetAtLeastPdfVersion(char version) { + pdf_version.SetAtLeastPdfVersion(version); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(com.lowagie.text.pdf.PdfName) + */ + public void SetPdfVersion(PdfName version) { + pdf_version.SetPdfVersion(version); + } + + /** + * Returns the version information. + */ + internal PdfVersionImp GetPdfVersion() { + return pdf_version; + } + + // [C3] PdfViewerPreferences interface + + // page layout (section 13.1.1 of "iText in Action") + + /** A viewer preference */ + public const int PageLayoutSinglePage = 1; + /** A viewer preference */ + public const int PageLayoutOneColumn = 2; + /** A viewer preference */ + public const int PageLayoutTwoColumnLeft = 4; + /** A viewer preference */ + public const int PageLayoutTwoColumnRight = 8; + /** A viewer preference */ + public const int PageLayoutTwoPageLeft = 16; + /** A viewer preference */ + public const int PageLayoutTwoPageRight = 32; + + // page mode (section 13.1.2 of "iText in Action") + + /** A viewer preference */ + public const int PageModeUseNone = 64; + /** A viewer preference */ + public const int PageModeUseOutlines = 128; + /** A viewer preference */ + public const int PageModeUseThumbs = 256; + /** A viewer preference */ + public const int PageModeFullScreen = 512; + /** A viewer preference */ + public const int PageModeUseOC = 1024; + /** A viewer preference */ + public const int PageModeUseAttachments = 2048; + + // values for setting viewer preferences in iText versions older than 2.x + + /** A viewer preference */ + public const int HideToolbar = 1 << 12; + /** A viewer preference */ + public const int HideMenubar = 1 << 13; + /** A viewer preference */ + public const int HideWindowUI = 1 << 14; + /** A viewer preference */ + public const int FitWindow = 1 << 15; + /** A viewer preference */ + public const int CenterWindow = 1 << 16; + /** A viewer preference */ + public const int DisplayDocTitle = 1 << 17; + + /** A viewer preference */ + public const int NonFullScreenPageModeUseNone = 1 << 18; + /** A viewer preference */ + public const int NonFullScreenPageModeUseOutlines = 1 << 19; + /** A viewer preference */ + public const int NonFullScreenPageModeUseThumbs = 1 << 20; + /** A viewer preference */ + public const int NonFullScreenPageModeUseOC = 1 << 21; + + /** A viewer preference */ + public const int DirectionL2R = 1 << 22; + /** A viewer preference */ + public const int DirectionR2L = 1 << 23; + + /** A viewer preference */ + public const int PrintScalingNone = 1 << 24; + + /** + * Sets the viewer preferences as the sum of several constants. + * @param preferences the viewer preferences + * @see PdfViewerPreferences#setViewerPreferences + */ + public virtual int ViewerPreferences { + set { + pdf.ViewerPreferences = value; + } + } + + /** Adds a viewer preference + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + pdf.AddViewerPreference(key, value); + } + + // [C4] Page labels + + /** + * Use this method to add page labels + * @param pageLabels the page labels + */ + public virtual PdfPageLabels PageLabels { + set { + pdf.PageLabels = value; + } + } + + // [C5] named objects: named destinations, javascript, embedded files + + /** + * Use this method to add a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param js The JavaScript action + */ + public virtual void AddJavaScript(PdfAction js) { + pdf.AddJavaScript(js); + } + + /** Adds a JavaScript action at the document level. When the document + * opens all this JavaScript runs. + * @param code the JavaScript code + * @param unicode select JavaScript unicode. Note that the internal + * Acrobat JavaScript engine does not support unicode, + * so this may or may not work for you + */ + public virtual void AddJavaScript(String code, bool unicode) { + AddJavaScript(PdfAction.JavaScript(code, this, unicode)); + } + + /** Adds a JavaScript action at the document level. When the document + * opens all this JavaScript runs. + * @param code the JavaScript code + */ + public virtual void AddJavaScript(String code) { + AddJavaScript(code, false); + } + + /** + * Use this method to add a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param name The name of the JS Action in the name tree + * @param js The JavaScript action + */ + public void AddJavaScript(String name, PdfAction js) { + pdf.AddJavaScript(name, js); + } + + /** + * Use this method to add a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param name The name of the JS Action in the name tree + * @param code the JavaScript code + * @param unicode select JavaScript unicode. Note that the internal + * Acrobat JavaScript engine does not support unicode, + * so this may or may not work for you + */ + public void AddJavaScript(String name, String code, bool unicode) { + AddJavaScript(name, PdfAction.JavaScript(code, this, unicode)); + } + + /** + * Use this method to adds a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param name The name of the JS Action in the name tree + * @param code the JavaScript code + */ + public void AddJavaScript(String name, String code) { + AddJavaScript(name, code, false); + } + + /** Adds a file attachment at the document level. + * @param description the file description + * @param fileStore an array with the file. If it's null + * the file will be read from the disk + * @param file the path to the file. It will only be used if + * fileStore is not null + * @param fileDisplay the actual file name stored in the pdf + * @throws IOException on error + */ + public virtual void AddFileAttachment(String description, byte[] fileStore, String file, String fileDisplay) { + AddFileAttachment(description, PdfFileSpecification.FileEmbedded(this, file, fileDisplay, fileStore)); + } + + /** Adds a file attachment at the document level. + * @param description the file description + * @param fs the file specification + */ + public virtual void AddFileAttachment(String description, PdfFileSpecification fs) { + pdf.AddFileAttachment(description, fs); + } + + /** Adds a file attachment at the document level. + * @param fs the file specification + */ + public void AddFileAttachment(PdfFileSpecification fs) { + pdf.AddFileAttachment(null, fs); + } + + // [C6] Actions (open and additional) + + /** action value */ + public static PdfName DOCUMENT_CLOSE = PdfName.WC; + /** action value */ + public static PdfName WILL_SAVE = PdfName.WS; + /** action value */ + public static PdfName DID_SAVE = PdfName.DS; + /** action value */ + public static PdfName WILL_PRINT = PdfName.WP; + /** action value */ + public static PdfName DID_PRINT = PdfName.DP; + + /** When the document opens it will jump to the destination with + * this name. + * @param name the name of the destination to jump to + */ + public virtual void SetOpenAction(String name) { + pdf.SetOpenAction(name); + } + + /** When the document opens this action will be + * invoked. + * @param action the action to be invoked + */ + public virtual void SetOpenAction(PdfAction action) { + pdf.SetOpenAction(action); + } + + /** Additional-actions defining the actions to be taken in + * response to various trigger events affecting the document + * as a whole. The actions types allowed are: DOCUMENT_CLOSE, + * WILL_SAVE, DID_SAVE, WILL_PRINT + * and DID_PRINT. + * + * @param actionType the action type + * @param action the action to execute in response to the trigger + * @throws PdfException on invalid action type + */ + public virtual void SetAdditionalAction(PdfName actionType, PdfAction action) { + if (!(actionType.Equals(DOCUMENT_CLOSE) || + actionType.Equals(WILL_SAVE) || + actionType.Equals(DID_SAVE) || + actionType.Equals(WILL_PRINT) || + actionType.Equals(DID_PRINT))) { + throw new PdfException("Invalid additional action type: " + actionType.ToString()); + } + pdf.AddAdditionalAction(actionType, action); + } + + // [C7] portable collections + /** + * Sets the Collection dictionary. + * @param collection a dictionary of type PdfCollection + */ + public PdfCollection Collection { + set { + SetAtLeastPdfVersion(VERSION_1_7); + pdf.Collection = value; + } + } + + // [C8] AcroForm + + /** signature value */ + public const int SIGNATURE_EXISTS = 1; + /** signature value */ + public const int SIGNATURE_APPEND_ONLY = 2; + + /** Gets the AcroForm object. + * @return the PdfAcroForm + */ + + public PdfAcroForm AcroForm { + get { + return pdf.AcroForm; + } + } + + /** Adds a PdfAnnotation or a PdfFormField + * to the document. Only the top parent of a PdfFormField + * needs to be added. + * @param annot the PdfAnnotation or the PdfFormField to add + */ + public virtual void AddAnnotation(PdfAnnotation annot) { + pdf.AddAnnotation(annot); + } + + internal virtual void AddAnnotation(PdfAnnotation annot, int page) { + AddAnnotation(annot); + } + + /** Adds the PdfAnnotation to the calculation order + * array. + * @param annot the PdfAnnotation to be added + */ + public virtual void AddCalculationOrder(PdfFormField annot) { + pdf.AddCalculationOrder(annot); + } + + /** Set the signature flags. + * @param f the flags. This flags are ORed with current ones + */ + public virtual int SigFlags { + set { + pdf.SigFlags = value; + } + } + + // [C9] Metadata + + /** XMP Metadata for the document. */ + protected byte[] xmpMetadata = null; + + /** + * Sets XMP Metadata. + * @param xmpMetadata The xmpMetadata to set. + */ + public byte[] XmpMetadata { + set { + this.xmpMetadata = value; + } + get { + return this.xmpMetadata; + } + } + + /** + * Use this method to set the XMP Metadata for each page. + * @param xmpMetadata The xmpMetadata to set. + */ + public byte[] PageXmpMetadata { + set { + pdf.XmpMetadata = value; + } + } + + /** + * Creates XMP Metadata based on the metadata in the PdfDocument. + */ + public void CreateXmpMetadata() { + XmpMetadata = CreateXmpMetadataBytes(); + } + + /** + * @return an XmpMetadata byte array + */ + private byte[] CreateXmpMetadataBytes() { + MemoryStream baos = new MemoryStream(); + try { + XmpWriter xmp = new XmpWriter(baos, pdf.Info, pdfxConformance.PDFXConformance); + xmp.Close(); + } + catch(IOException) { + } + return baos.ToArray(); + } + + // [C10] PDFX Conformance + + /** PDF/X level */ + public const int PDFXNONE = 0; + /** PDF/X level */ + public const int PDFX1A2001 = 1; + /** PDF/X level */ + public const int PDFX32002 = 2; + /** PDFA-1A level. */ + public const int PDFA1A = 3; + /** PDFA-1B level. */ + public const int PDFA1B = 4; + + /** Stores the PDF/X level. */ + private PdfXConformanceImp pdfxConformance = new PdfXConformanceImp(); + + /** + * Sets the PDFX conformance level. Allowed values are PDFX1A2001 and PDFX32002. It + * must be called before opening the document. + * @param pdfxConformance the conformance level + */ + public int PDFXConformance { + set { + if (pdfxConformance.PDFXConformance == value) + return; + if (pdf.IsOpen()) + throw new PdfXConformanceException("PDFX conformance can only be set before opening the document."); + if (crypto != null) + throw new PdfXConformanceException("A PDFX conforming document cannot be encrypted."); + if (value == PDFA1A || value == PDFA1B) + PdfVersion = VERSION_1_4; + else if (value != PDFXNONE) + PdfVersion = VERSION_1_3; + pdfxConformance.PDFXConformance = value; + } + get { + return pdfxConformance.PDFXConformance; + } + } + + /** @see com.lowagie.text.pdf.interfaces.PdfXConformance#isPdfX() */ + public bool IsPdfX() { + return pdfxConformance.IsPdfX(); + } + + // [C11] Output intents + + /** + * Sets the values of the output intent dictionary. Null values are allowed to + * suppress any key. + * @param outputConditionIdentifier a value + * @param outputCondition a value + * @param registryName a value + * @param info a value + * @param destOutputProfile a value + * @throws IOException on error + */ + public void SetOutputIntents(String outputConditionIdentifier, String outputCondition, String registryName, String info, byte[] destOutputProfile) { + PdfDictionary outa = ExtraCatalog; //force the creation + outa = new PdfDictionary(PdfName.OUTPUTINTENT); + if (outputCondition != null) + outa.Put(PdfName.OUTPUTCONDITION, new PdfString(outputCondition, PdfObject.TEXT_UNICODE)); + if (outputConditionIdentifier != null) + outa.Put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString(outputConditionIdentifier, PdfObject.TEXT_UNICODE)); + if (registryName != null) + outa.Put(PdfName.REGISTRYNAME, new PdfString(registryName, PdfObject.TEXT_UNICODE)); + if (info != null) + outa.Put(PdfName.INFO, new PdfString(info, PdfObject.TEXT_UNICODE)); + if (destOutputProfile != null) { + PdfStream stream = new PdfStream(destOutputProfile); + stream.FlateCompress(); + outa.Put(PdfName.DESTOUTPUTPROFILE, AddToBody(stream).IndirectReference); + } + outa.Put(PdfName.S, PdfName.GTS_PDFX); + extraCatalog.Put(PdfName.OUTPUTINTENTS, new PdfArray(outa)); + } + + /** + * Copies the output intent dictionary from other document to this one. + * @param reader the other document + * @param checkExistence true to just check for the existence of a valid output intent + * dictionary, false to insert the dictionary if it exists + * @throws IOException on error + * @return true if the output intent dictionary exists, false + * otherwise + */ + public bool SetOutputIntents(PdfReader reader, bool checkExistence) { + PdfDictionary catalog = reader.Catalog; + PdfArray outs = (PdfArray)PdfReader.GetPdfObject(catalog.Get(PdfName.OUTPUTINTENTS)); + if (outs == null) + return false; + ArrayList arr = outs.ArrayList; + if (arr.Count == 0) + return false; + PdfDictionary outa = (PdfDictionary)PdfReader.GetPdfObject((PdfObject)arr[0]); + PdfObject obj = PdfReader.GetPdfObject(outa.Get(PdfName.S)); + if (obj == null || !PdfName.GTS_PDFX.Equals(obj)) + return false; + if (checkExistence) + return true; + PRStream stream = (PRStream)PdfReader.GetPdfObject(outa.Get(PdfName.DESTOUTPUTPROFILE)); + byte[] destProfile = null; + if (stream != null) { + destProfile = PdfReader.GetStreamBytes(stream); + } + SetOutputIntents(GetNameString(outa, PdfName.OUTPUTCONDITIONIDENTIFIER), GetNameString(outa, PdfName.OUTPUTCONDITION), + GetNameString(outa, PdfName.REGISTRYNAME), GetNameString(outa, PdfName.INFO), destProfile); + return true; + } + + private static String GetNameString(PdfDictionary dic, PdfName key) { + PdfObject obj = PdfReader.GetPdfObject(dic.Get(key)); + if (obj == null || !obj.IsString()) + return null; + return ((PdfString)obj).ToUnicodeString(); + } + + // PDF Objects that have an impact on the PDF body + + // [F1] PdfEncryptionSettings interface + + // types of encryption + + /** Type of encryption */ + public const int STANDARD_ENCRYPTION_40 = 0; + /** Type of encryption */ + public const int STANDARD_ENCRYPTION_128 = 1; + /** Type of encryption */ + public const int ENCRYPTION_AES_128 = 2; + /** Mask to separate the encryption type from the encryption mode. */ + internal const int ENCRYPTION_MASK = 7; + /** Add this to the mode to keep the metadata in clear text */ + public const int DO_NOT_ENCRYPT_METADATA = 8; + + // permissions + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_PRINTING = 4 + 2048; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_MODIFY_CONTENTS = 8; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_COPY = 16; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_MODIFY_ANNOTATIONS = 32; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_FILL_IN = 256; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_SCREENREADERS = 512; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_ASSEMBLY = 1024; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_DEGRADED_PRINTING = 4; + + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_PRINTING} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowPrinting = ALLOW_PRINTING; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_MODIFY_CONTENTS} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowModifyContents = ALLOW_MODIFY_CONTENTS; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_COPY} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowCopy = ALLOW_COPY; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_MODIFY_ANNOTATIONS} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowModifyAnnotations = ALLOW_MODIFY_ANNOTATIONS; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_FILL_IN} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowFillIn = ALLOW_FILL_IN; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_SCREENREADERS} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowScreenReaders = ALLOW_SCREENREADERS; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_ASSEMBLY} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowAssembly = ALLOW_ASSEMBLY; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_DEGRADED_PRINTING} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowDegradedPrinting = ALLOW_DEGRADED_PRINTING; + + // Strength of the encryption (kept for historical reasons) + /** @deprecated As of iText 2.0.7, use {@link #STANDARD_ENCRYPTION_40} instead. Scheduled for removal at or after 2.2.0 */ + public const bool STRENGTH40BITS = false; + /** @deprecated As of iText 2.0.7, use {@link #STANDARD_ENCRYPTION_128} instead. Scheduled for removal at or after 2.2.0 */ + public const bool STRENGTH128BITS = true; + + /** Contains the business logic for cryptography. */ + protected PdfEncryption crypto; + + internal PdfEncryption Encryption { + get { + return crypto; + } + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { + if (pdf.IsOpen()) + throw new DocumentException("Encryption can only be added before opening the document."); + crypto = new PdfEncryption(); + crypto.SetCryptoMode(encryptionType, 0); + crypto.SetupAllKeys(userPassword, ownerPassword, permissions); + } + + /** + * Sets the certificate encryption options for this document. An array of one or more public certificates + * must be provided together with an array of the same size for the permissions for each certificate. + * The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param certs the public certificates to be used for the encryption + * @param permissions the user permissions for each of the certicates + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * @throws DocumentException if the document is already open + */ + public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { + if (pdf.IsOpen()) + throw new DocumentException("Encryption can only be added before opening the document."); + crypto = new PdfEncryption(); + if (certs != null) { + for (int i=0; i < certs.Length; i++) { + crypto.AddRecipient(certs[i], permissions[i]); + } + } + crypto.SetCryptoMode(encryptionType, 0); + crypto.GetEncryptionDictionary(); + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? STANDARD_ENCRYPTION_128 : STANDARD_ENCRYPTION_40); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { + SetEncryption(GetISOBytes(userPassword), GetISOBytes(ownerPassword), permissions, strength); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(int encryptionType, String userPassword, String ownerPassword, int permissions) { + SetEncryption(GetISOBytes(userPassword), GetISOBytes(ownerPassword), permissions, encryptionType); + } + + // [F2] compression + + /** + * Holds value of property fullCompression. + */ + protected bool fullCompression = false; + + /** + * Gets the 1.5 compression status. + * @return true if the 1.5 compression is on + */ + public bool FullCompression { + get { + return this.fullCompression; + } + } + + /** + * Sets the document's compression to the new 1.5 mode with object streams and xref + * streams. It can be set at any time but once set it can't be unset. + *

+ * If set before opening the document it will also set the pdf version to 1.5. + */ + public void SetFullCompression() { + this.fullCompression = true; + SetAtLeastPdfVersion(VERSION_1_5); + } + + // [F3] adding fonts + + /** The fonts of this document */ + protected Hashtable documentFonts = new Hashtable(); + + /** The font number counter for the fonts in the document. */ + protected int fontNumber = 1; + + /** + * Adds a BaseFont to the document but not to the page resources. + * It is used for templates. + * @param bf the BaseFont to add + * @return an Object[] where position 0 is a PdfName + * and position 1 is an PdfIndirectReference + */ + internal FontDetails AddSimple(BaseFont bf) { + if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { + return new FontDetails(new PdfName("F" + (fontNumber++)), ((DocumentFont)bf).IndirectReference, bf); + } + FontDetails ret = (FontDetails)documentFonts[bf]; + if (ret == null) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_FONT, bf); + ret = new FontDetails(new PdfName("F" + (fontNumber++)), body.PdfIndirectReference, bf); + documentFonts[bf] = ret; + } + return ret; + } + + internal void EliminateFontSubset(PdfDictionary fonts) { + foreach (FontDetails ft in documentFonts.Values) { + if (fonts.Get(ft.FontName) != null) + ft.Subset = false; + } + } + + // [F4] adding (and releasing) form XObjects + + /** The form XObjects in this document. The key is the xref and the value + is Object[]{PdfName, template}.*/ + protected Hashtable formXObjects = new Hashtable(); + + /** The name counter for the form XObjects name. */ + protected int formXObjectsCounter = 1; + + /** + * Adds a template to the document but not to the page resources. + * @param template the template to add + * @param forcedName the template name, rather than a generated one. Can be null + * @return the PdfName for this template + */ + internal PdfName AddDirectTemplateSimple(PdfTemplate template, PdfName forcedName) { + PdfIndirectReference refa = template.IndirectReference; + Object[] obj = (Object[])formXObjects[refa]; + PdfName name = null; + if (obj == null) { + if (forcedName == null) { + name = new PdfName("Xf" + formXObjectsCounter); + ++formXObjectsCounter; + } + else + name = forcedName; + if (template.Type == PdfTemplate.TYPE_IMPORTED) { + // If we got here from PdfCopy we'll have to fill importedPages + PdfImportedPage ip = (PdfImportedPage)template; + PdfReader r = ip.PdfReaderInstance.Reader; + if (!importedPages.ContainsKey(r)) { + importedPages[r] = ip.PdfReaderInstance; + } + template = null; + } + formXObjects[refa] = new Object[]{name, template}; + } + else + name = (PdfName)obj[0]; + return name; + } + + /** + * Releases the memory used by a template by writing it to the output. The template + * can still be added to any content but changes to the template itself won't have + * any effect. + * @param tp the template to release + * @throws IOException on error + */ + public void ReleaseTemplate(PdfTemplate tp) { + PdfIndirectReference refi = tp.IndirectReference; + Object[] objs = (Object[])formXObjects[refi]; + if (objs == null || objs[1] == null) + return; + PdfTemplate template = (PdfTemplate)objs[1]; + if (template.IndirectReference is PRIndirectReference) + return; + if (template.Type == PdfTemplate.TYPE_TEMPLATE) { + AddToBody(template.FormXObject, template.IndirectReference); + objs[1] = null; + } + } + + // [F5] adding pages imported form other PDF documents + + protected Hashtable importedPages = new Hashtable(); + + /** Gets a page from other PDF document. The page can be used as + * any other PdfTemplate. Note that calling this method more than + * once with the same parameters will retrieve the same object. + * @param reader the PDF document where the page is + * @param pageNumber the page number. The first page is 1 + * @return the template representing the imported page + */ + public virtual PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { + PdfReaderInstance inst = (PdfReaderInstance)importedPages[reader]; + if (inst == null) { + inst = reader.GetPdfReaderInstance(this); + importedPages[reader] = inst; + } + return inst.GetImportedPage(pageNumber); + } + + /** Writes the reader to the document and frees the memory used by it. + * The main use is when concatenating multiple documents to keep the + * memory usage restricted to the current appending document. + * @param reader the PdfReader to free + * @throws IOException on error + */ + public virtual void FreeReader(PdfReader reader) { + currentPdfReaderInstance = (PdfReaderInstance)importedPages[reader]; + if (currentPdfReaderInstance == null) + return; + currentPdfReaderInstance.WriteAllPages(); + currentPdfReaderInstance = null; + importedPages.Remove(reader); + } + + /** Gets the current document size. This size only includes + * the data already writen to the output stream, it does not + * include templates or fonts. It is usefull if used with + * freeReader() when concatenating many documents + * and an idea of the current size is needed. + * @return the approximate size without fonts or templates + */ + public int CurrentDocumentSize { + get { + return body.Offset + body.Size * 20 + 0x48; + } + } + + protected PdfReaderInstance currentPdfReaderInstance; + + protected internal virtual int GetNewObjectNumber(PdfReader reader, int number, int generation) { + return currentPdfReaderInstance.GetNewObjectNumber(number, generation); + } + + internal virtual RandomAccessFileOrArray GetReaderFile(PdfReader reader) { + return currentPdfReaderInstance.ReaderFile; + } + + // [F6] spot colors + + /** The colors of this document */ + protected Hashtable documentColors = new Hashtable(); + + /** The color number counter for the colors in the document. */ + protected int colorNumber = 1; + + internal PdfName GetColorspaceName() { + return new PdfName("CS" + (colorNumber++)); + } + + /** + * Adds a SpotColor to the document but not to the page resources. + * @param spc the SpotColor to add + * @return an Object[] where position 0 is a PdfName + * and position 1 is an PdfIndirectReference + */ + internal ColorDetails AddSimple(PdfSpotColor spc) { + ColorDetails ret = (ColorDetails)documentColors[spc]; + if (ret == null) { + ret = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, spc); + documentColors[spc] = ret; + } + return ret; + } + + // [F7] document patterns + + /** The patterns of this document */ + protected Hashtable documentPatterns = new Hashtable(); + + /** The patten number counter for the colors in the document. */ + protected int patternNumber = 1; + + internal PdfName AddSimplePattern(PdfPatternPainter painter) { + PdfName name = (PdfName)documentPatterns[painter]; + if ( name == null ) { + name = new PdfName("P" + patternNumber); + ++patternNumber; + documentPatterns[painter] = name; + } + return name; + } + + // [F8] shading patterns + + protected Hashtable documentShadingPatterns = new Hashtable(); + + internal void AddSimpleShadingPattern(PdfShadingPattern shading) { + if (!documentShadingPatterns.ContainsKey(shading)) { + shading.Name = patternNumber; + ++patternNumber; + documentShadingPatterns[shading] = null; + AddSimpleShading(shading.Shading); + } + } + + // [F9] document shadings + + protected Hashtable documentShadings = new Hashtable(); + + internal void AddSimpleShading(PdfShading shading) { + if (!documentShadings.ContainsKey(shading)) { + documentShadings[shading] = null; + shading.Name = documentShadings.Count; + } + } + + // [F10] extended graphics state (for instance for transparency) + + protected Hashtable documentExtGState = new Hashtable(); + + internal PdfObject[] AddSimpleExtGState(PdfDictionary gstate) { + if (!documentExtGState.ContainsKey(gstate)) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_GSTATE, gstate); + documentExtGState[gstate] = new PdfObject[]{new PdfName("GS" + (documentExtGState.Count + 1)), PdfIndirectReference}; + } + return (PdfObject[])documentExtGState[gstate]; + } + + // [F11] adding properties (OCG, marked content) + + protected Hashtable documentProperties = new Hashtable(); + + internal PdfObject[] AddSimpleProperty(Object prop, PdfIndirectReference refi) { + if (!documentProperties.ContainsKey(prop)) { + if (prop is IPdfOCG) + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_LAYER, null); + documentProperties[prop] = new PdfObject[]{new PdfName("Pr" + (documentProperties.Count + 1)), refi}; + } + return (PdfObject[])documentProperties[prop]; + } + + internal bool PropertyExists(Object prop) { + return documentProperties.ContainsKey(prop); + } + + // [F12] tagged PDF + + protected bool tagged = false; + protected PdfStructureTreeRoot structureTreeRoot; + + /** + * Mark this document for tagging. It must be called before open. + */ + public void SetTagged() { + if (open) + throw new ArgumentException("Tagging must be set before opening the document."); + tagged = true; + } + + /** + * Check if the document is marked for tagging. + * @return true if the document is marked for tagging + */ + public bool IsTagged() { + return tagged; + } + + /** + * Gets the structure tree root. If the document is not marked for tagging it will return null. + * @return the structure tree root + */ + public PdfStructureTreeRoot StructureTreeRoot { + get { + if (tagged && structureTreeRoot == null) + structureTreeRoot = new PdfStructureTreeRoot(this); + return structureTreeRoot; + } + } + + // [F13] Optional Content Groups + + protected Hashtable documentOCG = new Hashtable(); + protected ArrayList documentOCGorder = new ArrayList(); + protected PdfOCProperties vOCProperties; + protected PdfArray OCGRadioGroup = new PdfArray(); + protected PdfArray OCGLocked = new PdfArray(); + + /** + * Gets the Optional Content Properties Dictionary. Each call fills the dictionary with the current layer + * state. It's advisable to only call this method right before close and do any modifications + * at that time. + * @return the Optional Content Properties Dictionary + */ + public PdfOCProperties OCProperties { + get { + FillOCProperties(true); + return vOCProperties; + } + } + + /** + * Sets a collection of optional content groups whose states are intended to follow + * a "radio button" paradigm. That is, the state of at most one optional + * content group in the array should be ON at a time: if one group is turned + * ON, all others must be turned OFF. + * @param group the radio group + */ + public void AddOCGRadioGroup(ArrayList group) { + PdfArray ar = new PdfArray(); + for (int k = 0; k < group.Count; ++k) { + PdfLayer layer = (PdfLayer)group[k]; + if (layer.Title == null) + ar.Add(layer.Ref); + } + if (ar.Size == 0) + return; + OCGRadioGroup.Add(ar); + } + + /** + * Use this method to lock an optional content group. + * The state of a locked group cannot be changed through the user interface + * of a viewer application. Producers can use this entry to prevent the visibility + * of content that depends on these groups from being changed by users. + * @param layer the layer that needs to be added to the array of locked OCGs + * @since 2.1.2 + */ + public void LockLayer(PdfLayer layer) { + OCGLocked.Add(layer.Ref); + } + + private static void GetOCGOrder(PdfArray order, PdfLayer layer) { + if (!layer.OnPanel) + return; + if (layer.Title == null) + order.Add(layer.Ref); + ArrayList children = layer.Children; + if (children == null) + return; + PdfArray kids = new PdfArray(); + if (layer.Title != null) + kids.Add(new PdfString(layer.Title, PdfObject.TEXT_UNICODE)); + for (int k = 0; k < children.Count; ++k) { + GetOCGOrder(kids, (PdfLayer)children[k]); + } + if (kids.Size > 0) + order.Add(kids); + } + + private void AddASEvent(PdfName eventa, PdfName category) { + PdfArray arr = new PdfArray(); + foreach (PdfLayer layer in documentOCG.Keys) { + PdfDictionary usage = (PdfDictionary)layer.Get(PdfName.USAGE); + if (usage != null && usage.Get(category) != null) + arr.Add(layer.Ref); + } + if (arr.Size == 0) + return; + PdfDictionary d = (PdfDictionary)vOCProperties.Get(PdfName.D); + PdfArray arras = (PdfArray)d.Get(PdfName.AS); + if (arras == null) { + arras = new PdfArray(); + d.Put(PdfName.AS, arras); + } + PdfDictionary asa = new PdfDictionary(); + asa.Put(PdfName.EVENT, eventa); + asa.Put(PdfName.CATEGORY, new PdfArray(category)); + asa.Put(PdfName.OCGS, arr); + arras.Add(asa); + } + + protected void FillOCProperties(bool erase) { + if (vOCProperties == null) + vOCProperties = new PdfOCProperties(); + if (erase) { + vOCProperties.Remove(PdfName.OCGS); + vOCProperties.Remove(PdfName.D); + } + if (vOCProperties.Get(PdfName.OCGS) == null) { + PdfArray gr = new PdfArray(); + foreach (PdfLayer layer in documentOCG.Keys) { + gr.Add(layer.Ref); + } + vOCProperties.Put(PdfName.OCGS, gr); + } + if (vOCProperties.Get(PdfName.D) != null) + return; + ArrayList docOrder = new ArrayList(documentOCGorder); + for (ListIterator it = new ListIterator(docOrder); it.HasNext();) { + PdfLayer layer = (PdfLayer)it.Next(); + if (layer.Parent != null) + it.Remove(); + } + PdfArray order = new PdfArray(); + foreach (PdfLayer layer in docOrder) { + GetOCGOrder(order, layer); + } + PdfDictionary d = new PdfDictionary(); + vOCProperties.Put(PdfName.D, d); + d.Put(PdfName.ORDER, order); + PdfArray grx = new PdfArray(); + foreach (PdfLayer layer in documentOCG.Keys) { + if (!layer.On) + grx.Add(layer.Ref); + } + if (grx.Size > 0) + d.Put(PdfName.OFF, grx); + if (OCGRadioGroup.Size > 0) + d.Put(PdfName.RBGROUPS, OCGRadioGroup); + if (OCGLocked.Size > 0) + d.Put(PdfName.LOCKED, OCGLocked); + AddASEvent(PdfName.VIEW, PdfName.ZOOM); + AddASEvent(PdfName.VIEW, PdfName.VIEW); + AddASEvent(PdfName.PRINT, PdfName.PRINT); + AddASEvent(PdfName.EXPORT, PdfName.EXPORT); + d.Put(PdfName.LISTMODE, PdfName.VISIBLEPAGES); + } + + internal void RegisterLayer(IPdfOCG layer) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_LAYER, null); + if (layer is PdfLayer) { + PdfLayer la = (PdfLayer)layer; + if (la.Title == null) { + if (!documentOCG.ContainsKey(layer)) { + documentOCG[layer] = null; + documentOCGorder.Add(layer); + } + } + else { + documentOCGorder.Add(layer); + } + } + else + throw new ArgumentException("Only PdfLayer is accepted."); + } + + // User methods to change aspects of the page + + // [U1] page size + + /** + * Gives the size of the media box. + * @return a Rectangle + */ + public Rectangle PageSize { + get { + return pdf.PageSize; + } + } + + /** Sets the crop box. The crop box should not be rotated even if the + * page is rotated. This change only takes effect in the next + * page. + * @param crop the crop box + */ + public virtual Rectangle CropBoxSize { + set { + pdf.CropBoxSize = value; + } + } + + /** + * Sets the page box sizes. Allowed names are: "crop", "trim", "art" and "bleed". + * @param boxName the box size + * @param size the size + */ + public void SetBoxSize(String boxName, Rectangle size) { + pdf.SetBoxSize(boxName, size); + } + + /** + * Gives the size of a trim, art, crop or bleed box, or null if not defined. + * @param boxName crop, trim, art or bleed + */ + public Rectangle GetBoxSize(String boxName) { + return pdf.GetBoxSize(boxName); + } + + // [U2] take care of empty pages + + /** + * If you use SetPageEmpty(false), invoking NewPage() after a blank page will add a newPage. + * @param pageEmpty the state + */ + public bool PageEmpty { + set { + pdf.PageEmpty = value; + } + } + + // [U3] page actions (open and close) + + /** action value */ + public static readonly PdfName PAGE_OPEN = PdfName.O; + /** action value */ + public static readonly PdfName PAGE_CLOSE = PdfName.C; + + /** Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @throws PdfException if the action type is invalid + */ + public virtual void SetPageAction(PdfName actionType, PdfAction action) { + if (!actionType.Equals(PAGE_OPEN) && !actionType.Equals(PAGE_CLOSE)) + throw new PdfException("Invalid page additional action type: " + actionType.ToString()); + pdf.SetPageAction(actionType, action); + } + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page + */ + public virtual int Duration { + set { + pdf.Duration = value; + } + } + + /** + * Sets the transition for the page + * @param transition the Transition object + */ + public virtual PdfTransition Transition { + set { + pdf.Transition = value; + } + } + + // [U4] Thumbnail image + + /** + * Sets the the thumbnail image for the current page. + * @param image the image + * @throws PdfException on error + * @throws DocumentException or error + */ + public virtual Image Thumbnail { + set { + pdf.Thumbnail = value; + } + } + + // [U5] Transparency groups + + /** + * A group attributes dictionary specifying the attributes + * of the page’s page group for use in the transparent + * imaging model + */ + protected PdfDictionary group; + + public PdfDictionary Group { + get { + return this.group; + } + set { + group = value; + } + } + + // [U6] space char ratio + + /** The default space-char ratio. */ + public const float SPACE_CHAR_RATIO_DEFAULT = 2.5f; + /** Disable the inter-character spacing. */ + public const float NO_SPACE_CHAR_RATIO = 10000000f; + + /** + * The ratio between the extra word spacing and the extra character spacing. + * Extra word spacing will grow ratio times more than extra character spacing. + */ + private float spaceCharRatio = SPACE_CHAR_RATIO_DEFAULT; + + /** Sets the ratio between the extra word spacing and the extra character spacing + * when the text is fully justified. + * Extra word spacing will grow spaceCharRatio times more than extra character spacing. + * If the ratio is PdfWriter.NO_SPACE_CHAR_RATIO then the extra character spacing + * will be zero. + * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing + */ + public virtual float SpaceCharRatio { + set { + if (value < 0.001f) + this.spaceCharRatio = 0.001f; + else + this.spaceCharRatio = value; + } + get { + return spaceCharRatio; + } + } + + // [U7] run direction (doesn't actually do anything) + + /** Use the default run direction. */ + public const int RUN_DIRECTION_DEFAULT = 0; + /** Do not use bidirectional reordering. */ + public const int RUN_DIRECTION_NO_BIDI = 1; + /** Use bidirectional reordering with left-to-right + * preferential run direction. + */ + public const int RUN_DIRECTION_LTR = 2; + /** Use bidirectional reordering with right-to-left + * preferential run direction. + */ + public const int RUN_DIRECTION_RTL = 3; + protected int runDirection = RUN_DIRECTION_NO_BIDI; + + /** Sets the run direction. This is only used as a placeholder + * as it does not affect anything. + * @param runDirection the run direction + */ + public virtual int RunDirection { + set { + if (value < RUN_DIRECTION_NO_BIDI || value > RUN_DIRECTION_RTL) + throw new Exception("Invalid run direction: " + value); + this.runDirection = value; + } + get { + return runDirection; + } + } + + // [U8] user units + + protected float userunit = 0f; + + /** + * A UserUnit is a value that defines the default user space unit. + * The minimum UserUnit is 1 (1 unit = 1/72 inch). + * The maximum UserUnit is 75,000. + * Remark that this userunit only works starting with PDF1.6! + */ + public float Userunit { + get { + return userunit; + } + set { + if (value < 1f || value > 75000f) throw new DocumentException("UserUnit should be a value between 1 and 75000."); + this.userunit = value; + SetAtLeastPdfVersion(VERSION_1_6); + } + } + + // Miscellaneous topics + + // [M1] Color settings + + protected PdfDictionary defaultColorspace = new PdfDictionary(); + + /** + * Gets the default colorspaces. + * @return the default colorspaces + */ + public PdfDictionary DefaultColorspace { + get { + return defaultColorspace; + } + } + + /** + * Sets the default colorspace that will be applied to all the document. + * The colorspace is only applied if another colorspace with the same name + * is not present in the content. + *

+ * The colorspace is applied immediately when creating templates and at the page + * end for the main document content. + * @param key the name of the colorspace. It can be PdfName.DEFAULTGRAY, PdfName.DEFAULTRGB + * or PdfName.DEFAULTCMYK + * @param cs the colorspace. A null or PdfNull removes any colorspace with the same name + */ + public void SetDefaultColorspace(PdfName key, PdfObject cs) { + if (cs == null || cs.IsNull()) + defaultColorspace.Remove(key); + defaultColorspace.Put(key, cs); + } + + // [M2] spot patterns + + protected Hashtable documentSpotPatterns = new Hashtable(); + protected ColorDetails patternColorspaceRGB; + protected ColorDetails patternColorspaceGRAY; + protected ColorDetails patternColorspaceCMYK; + + internal ColorDetails AddSimplePatternColorspace(Color color) { + int type = ExtendedColor.GetType(color); + if (type == ExtendedColor.TYPE_PATTERN || type == ExtendedColor.TYPE_SHADING) + throw new Exception("An uncolored tile pattern can not have another pattern or shading as color."); + switch (type) { + case ExtendedColor.TYPE_RGB: + if (patternColorspaceRGB == null) { + patternColorspaceRGB = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(PdfName.DEVICERGB); + AddToBody(array, patternColorspaceRGB.IndirectReference); + } + return patternColorspaceRGB; + case ExtendedColor.TYPE_CMYK: + if (patternColorspaceCMYK == null) { + patternColorspaceCMYK = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(PdfName.DEVICECMYK); + AddToBody(array, patternColorspaceCMYK.IndirectReference); + } + return patternColorspaceCMYK; + case ExtendedColor.TYPE_GRAY: + if (patternColorspaceGRAY == null) { + patternColorspaceGRAY = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(PdfName.DEVICEGRAY); + AddToBody(array, patternColorspaceGRAY.IndirectReference); + } + return patternColorspaceGRAY; + case ExtendedColor.TYPE_SEPARATION: { + ColorDetails details = AddSimple(((SpotColor)color).PdfSpotColor); + ColorDetails patternDetails = (ColorDetails)documentSpotPatterns[details]; + if (patternDetails == null) { + patternDetails = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(details.IndirectReference); + AddToBody(array, patternDetails.IndirectReference); + documentSpotPatterns[details] = patternDetails; + } + return patternDetails; + } + default: + throw new Exception("Invalid color type in PdfWriter.AddSimplePatternColorspace()."); + } + } + + // [M3] Images + + /** Sets the image sequence to follow the text in strict order. + * @param strictImageSequence new value of property strictImageSequence + * + */ + public bool StrictImageSequence { + set { + pdf.StrictImageSequence = value; + } + get { + return pdf.StrictImageSequence; + } + } + + /** + * Clears text wrapping around images (if applicable). + * Method suggested by Pelikan Stephan + * @throws DocumentException + */ + public void ClearTextWrap() { + pdf.ClearTextWrap(); + } + + /** Dictionary, containing all the images of the PDF document */ + protected PdfDictionary imageDictionary = new PdfDictionary(); + + /** This is the list with all the images in the document. */ + private Hashtable images = new Hashtable(); + + /** + * Adds an image to the document but not to the page resources. It is used with + * templates and Document.Add(Image). + * @param image the Image to add + * @return the name of the image added + * @throws PdfException on error + * @throws DocumentException on error + */ + public PdfName AddDirectImageSimple(Image image) { + return AddDirectImageSimple(image, null); + } + + /** + * Adds an image to the document but not to the page resources. It is used with + * templates and Document.Add(Image). + * @param image the Image to add + * @param fixedRef the reference to used. It may be null, + * a PdfIndirectReference or a PRIndirectReference. + * @return the name of the image added + * @throws PdfException on error + * @throws DocumentException on error + */ + public PdfName AddDirectImageSimple(Image image, PdfIndirectReference fixedRef) { + PdfName name; + // if the images is already added, just retrieve the name + if (images.ContainsKey(image.MySerialId)) { + name = (PdfName) images[image.MySerialId]; + } + // if it's a new image, add it to the document + else { + if (image.IsImgTemplate()) { + name = new PdfName("img" + images.Count); + if (image is ImgWMF){ + ImgWMF wmf = (ImgWMF)image; + wmf.ReadWMF(PdfTemplate.CreateTemplate(this, 0, 0)); + } + } + else { + PdfIndirectReference dref = image.DirectReference; + if (dref != null) { + PdfName rname = new PdfName("img" + images.Count); + images[image.MySerialId] = rname; + imageDictionary.Put(rname, dref); + return rname; + } + Image maskImage = image.ImageMask; + PdfIndirectReference maskRef = null; + if (maskImage != null) { + PdfName mname = (PdfName)images[maskImage.MySerialId]; + maskRef = GetImageReference(mname); + } + PdfImage i = new PdfImage(image, "img" + images.Count, maskRef); + if (image.HasICCProfile()) { + PdfICCBased icc = new PdfICCBased(image.TagICC); + PdfIndirectReference iccRef = Add(icc); + PdfArray iccArray = new PdfArray(); + iccArray.Add(PdfName.ICCBASED); + iccArray.Add(iccRef); + PdfObject colorspace = i.Get(PdfName.COLORSPACE); + if (colorspace != null && colorspace.IsArray()) { + ArrayList ar = ((PdfArray)colorspace).ArrayList; + if (ar.Count > 1 && PdfName.INDEXED.Equals(ar[0])) + ar[1] = iccArray; + else + i.Put(PdfName.COLORSPACE, iccArray); + } + else + i.Put(PdfName.COLORSPACE, iccArray); + } + Add(i, fixedRef); + name = i.Name; + } + images[image.MySerialId] = name; + } + return name; + } + + /** + * Writes a PdfImage to the outputstream. + * + * @param pdfImage the image to be added + * @return a PdfIndirectReference to the encapsulated image + * @throws PdfException when a document isn't open yet, or has been closed + */ + internal virtual PdfIndirectReference Add(PdfImage pdfImage, PdfIndirectReference fixedRef) { + if (! imageDictionary.Contains(pdfImage.Name)) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_IMAGE, pdfImage); + if (fixedRef is PRIndirectReference) { + PRIndirectReference r2 = (PRIndirectReference)fixedRef; + fixedRef = new PdfIndirectReference(0, GetNewObjectNumber(r2.Reader, r2.Number, r2.Generation)); + } + if (fixedRef == null) + fixedRef = AddToBody(pdfImage).IndirectReference; + else + AddToBody(pdfImage, fixedRef); + imageDictionary.Put(pdfImage.Name, fixedRef); + return fixedRef; + } + return (PdfIndirectReference)imageDictionary.Get(pdfImage.Name); + } + + /** + * return the PdfIndirectReference to the image with a given name. + * + * @param name the name of the image + * @return a PdfIndirectReference + */ + internal virtual PdfIndirectReference GetImageReference(PdfName name) { + return (PdfIndirectReference) imageDictionary.Get(name); + } + + protected virtual PdfIndirectReference Add(PdfICCBased icc) { + PdfIndirectObject objecta; + objecta = AddToBody(icc); + return objecta.IndirectReference; + } + + // [M4] Old table functionality; do we still need it? + + /** + * Checks if a Table fits the current page of the PdfDocument. + * + * @param table the table that has to be checked + * @param margin a certain margin + * @return true if the Table fits the page, false otherwise. + */ + public bool FitsPage(Table table, float margin) { + return pdf.GetBottom(table) > pdf.IndentBottom + margin; + } + + /** + * Checks if a Table fits the current page of the PdfDocument. + * + * @param table the table that has to be checked + * @return true if the Table fits the page, false otherwise. + */ + public bool FitsPage(Table table) { + return FitsPage(table, 0); + } + + // [F12] tagged PDF + /** + * A flag indicating the presence of structure elements that contain user properties attributes. + */ + private bool userProperties; + + /** + * Sets the flag indicating the presence of structure elements that contain user properties attributes. + * @param userProperties the user properties flag + */ + public bool UserProperties { + set { + userProperties = value; + } + get { + return userProperties; + } + } + + /** + * Holds value of property RGBTranparency. + */ + private bool rgbTransparencyBlending; + + /** + * Sets the transparency blending colorspace to RGB. The default blending colorspace is + * CMYK and will result in faded colors in the screen and in printing. Calling this method + * will return the RGB colors to what is expected. The RGB blending will be applied to all subsequent pages + * until other value is set. + * Note that this is a generic solution that may not work in all cases. + * @param rgbTransparencyBlending true to set the transparency blending colorspace to RGB, false + * to use the default blending colorspace + */ + public bool RgbTransparencyBlending { + get { + return this.rgbTransparencyBlending; + } + set { + this.rgbTransparencyBlending = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs b/iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs new file mode 100644 index 0000000..78b7490 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs @@ -0,0 +1,67 @@ +using System; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * + * @author psoares + */ + public class PdfXConformanceException : Exception { + + /** Creates a new instance of PdfXConformanceException. */ + public PdfXConformanceException() { + } + + /** + * Creates a new instance of PdfXConformanceException. + * @param s + */ + public PdfXConformanceException(String s) : base(s) { + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs b/iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs new file mode 100644 index 0000000..3f96e12 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs @@ -0,0 +1,805 @@ +using System; +using System.IO; +using System.Text; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except inp compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added inp the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), inp which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed inp the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +/******************************************************************** + * * + * Title: pfm2afm - Convert Windows .pfm files to .afm files * + * * + * Author: Ken Borgendale 10/9/91 Version 1.0 * + * * + * Function: * + * Convert a Windows .pfm (Printer Font Metrics) file to a * + * .afm (Adobe Font Metrics) file. The purpose of this is * + * to allow fonts put outp for Windows to be used with OS/2. * + * * + * Syntax: * + * pfm2afm infile [outfile] -a * + * * + * Copyright: * + * pfm2afm - Copyright (C) IBM Corp., 1991 * + * * + * This code is released for public use as long as the * + * copyright remains intact. This code is provided asis * + * without any warrenties, express or implied. * + * * + * Notes: * + * 1. Much of the information inp the original .afm file is * + * lost when the .pfm file is created, and thus cannot be * + * reconstructed by this utility. This is especially true * + * of data for characters not inp the Windows character set. * + * * + * 2. This module is coded to be compiled by the MSC 6.0. * + * For other compilers, be careful of the packing of the * + * PFM structure. * + * * + ********************************************************************/ + +/******************************************************************** + * * + * Modifications by Rod Smith, 5/22/96 * + * * + * These changes look for the strings "italic", "bold", "black", * + * and "light" inp the font's name and set the weight accordingly * + * and adds an ItalicAngle line with a value of "0" or "-12.00". * + * This allows OS/2 programs such as DeScribe to handle the bold * + * and italic attributes appropriately, which was not the case * + * when I used the original version on fonts from the KeyFonts * + * Pro 2002 font CD. * + * * + * I've also increased the size of the buffer used to load the * + * .PFM file; the old size was inadequate for most of the fonts * + * from the SoftKey collection. * + * * + * Compiled with Watcom C 10.6 * + * * + ********************************************************************/ + +/******************************************************************** + * * + * Further modifications, 4/21/98, by Rod Smith * + * * + * Minor changes to get the program to compile with gcc under * + * Linux (Red Hat 5.0, to be precise). I had to add an itoa * + * function from the net (the function was buggy, so I had to fix * + * it, too!). I also made the program more friendly towards * + * files with mixed-case filenames. * + * * + ********************************************************************/ + +/******************************************************************** + * * + * 1/31/2005, by Paulo Soares * + * * + * This code was integrated into iText. * + * Note that the itoa function mentioned in the comment by Rod * + * Smith is no longer in the code because Java has native support * + * in PrintWriter to convert integers to strings * + * * + ********************************************************************/ + +/******************************************************************** + * * + * 7/16/2005, by Bruno Lowagie * + * * + * I solved an Eclipse Warning. * + * * + ********************************************************************/ + +/******************************************************************** + * * + * 9/14/2006, by Xavier Le Vourch * + * * + * expand import clauses (import java.io.*) * + * the removal of an exception in readString was restored on 9/16 * + * * + ********************************************************************/ + +namespace iTextSharp.text.pdf { + /** + * Converts a PFM file into an AFM file. + */ + public sealed class Pfm2afm { + private RandomAccessFileOrArray inp; + private StreamWriter outp; + private Encoding encoding; + + /** Creates a new instance of Pfm2afm */ + private Pfm2afm(RandomAccessFileOrArray inp, Stream outp) { + this.inp = inp; + encoding = Encoding.GetEncoding(1252); + this.outp = new StreamWriter(outp, encoding); + } + + /** + * Converts a PFM file into an AFM file. + * @param inp the PFM file + * @param outp the AFM file + * @throws IOException on error + */ + public static void Convert(RandomAccessFileOrArray inp, Stream outp) { + Pfm2afm p = new Pfm2afm(inp, outp); + p.Openpfm(); + p.Putheader(); + p.Putchartab(); + p.Putkerntab(); + p.Puttrailer(); + p.outp.Flush(); + } + +/* public static void Main(String[] args) { + try { + RandomAccessFileOrArray inp = new RandomAccessFileOrArray(args[0]); + Stream outp = new FileOutputStream(args[1]); + Convert(inp, outp); + inp.Close(); + outp.Close(); + } + catch (Exception e) { + e.PrintStackTrace(); + } + }*/ + + private String ReadString(int n) { + byte[] b = new byte[n]; + inp.ReadFully(b); + int k; + for (k = 0; k < b.Length; ++k) { + if (b[k] == 0) + break; + } + return encoding.GetString(b, 0, k); + } + + private String ReadString() { + StringBuilder buf = new StringBuilder(); + while (true) { + int c = inp.Read(); + if (c <= 0) + break; + buf.Append((char)c); + } + return buf.ToString(); + } + + private void Outval(int n) { + outp.Write(' '); + outp.Write(n); + } + + /* + * Output a character entry + */ + private void Outchar(int code, int width, String name) { + outp.Write("C "); + Outval(code); + outp.Write(" ; WX "); + Outval(width); + if (name != null) { + outp.Write(" ; N "); + outp.Write(name); + } + outp.Write(" ;\n"); + } + + private void Openpfm() { + inp.Seek(0); + vers = inp.ReadShortLE(); + h_len = inp.ReadIntLE(); + copyright = ReadString(60); + type = inp.ReadShortLE(); + points = inp.ReadShortLE(); + verres = inp.ReadShortLE(); + horres = inp.ReadShortLE(); + ascent = inp.ReadShortLE(); + intleading = inp.ReadShortLE(); + extleading = inp.ReadShortLE(); + italic = (byte)inp.Read(); + uline = (byte)inp.Read(); + overs = (byte)inp.Read(); + weight = inp.ReadShortLE(); + charset = (byte)inp.Read(); + pixwidth = inp.ReadShortLE(); + pixheight = inp.ReadShortLE(); + kind = (byte)inp.Read(); + avgwidth = inp.ReadShortLE(); + maxwidth = inp.ReadShortLE(); + firstchar = inp.Read(); + lastchar = inp.Read(); + defchar = (byte)inp.Read(); + brkchar = (byte)inp.Read(); + widthby = inp.ReadShortLE(); + device = inp.ReadIntLE(); + face = inp.ReadIntLE(); + bits = inp.ReadIntLE(); + bitoff = inp.ReadIntLE(); + extlen = inp.ReadShortLE(); + psext = inp.ReadIntLE(); + chartab = inp.ReadIntLE(); + res1 = inp.ReadIntLE(); + kernpairs = inp.ReadIntLE(); + res2 = inp.ReadIntLE(); + fontname = inp.ReadIntLE(); + if (h_len != inp.Length || extlen != 30 || fontname < 75 || fontname > 512) + throw new IOException("Not a valid PFM file."); + inp.Seek(psext + 14); + capheight = inp.ReadShortLE(); + xheight = inp.ReadShortLE(); + ascender = inp.ReadShortLE(); + descender = inp.ReadShortLE(); + } + + private void Putheader() { + outp.Write("StartFontMetrics 2.0\n"); + if (copyright.Length > 0) + outp.Write("Comment " + copyright + '\n'); + outp.Write("FontName "); + inp.Seek(fontname); + String fname = ReadString(); + outp.Write(fname); + outp.Write("\nEncodingScheme "); + if (charset != 0) + outp.Write("FontSpecific\n"); + else + outp.Write("AdobeStandardEncoding\n"); + /* + * The .pfm is missing full name, so construct from font name by + * changing the hyphen to a space. This actually works inp a lot + * of cases. + */ + outp.Write("FullName " + fname.Replace('-', ' ')); + if (face != 0) { + inp.Seek(face); + outp.Write("\nFamilyName " + ReadString()); + } + + outp.Write("\nWeight "); + if (weight > 475 || fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("bold") >= 0) + outp.Write("Bold"); + else if ((weight < 325 && weight != 0) || fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("light") >= 0) + outp.Write("Light"); + else if (fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("black") >= 0) + outp.Write("Black"); + else + outp.Write("Medium"); + + outp.Write("\nItalicAngle "); + if (italic != 0 || fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("italic") >= 0) + outp.Write("-12.00"); + /* this is a typical value; something else may work better for a + specific font */ + else + outp.Write("0"); + + /* + * The mono flag inp the pfm actually indicates whether there is a + * table of font widths, not if they are all the same. + */ + outp.Write("\nIsFixedPitch "); + if ((kind & 1) == 0 || /* Flag for mono */ + avgwidth == maxwidth ) { /* Avg width = max width */ + outp.Write("true"); + isMono = true; + } + else { + outp.Write("false"); + isMono = false; + } + + /* + * The font bounding box is lost, but try to reconstruct it. + * Much of this is just guess work. The bounding box is required inp + * the .afm, but is not used by the PM font installer. + */ + outp.Write("\nFontBBox"); + if (isMono) + Outval(-20); /* Just guess at left bounds */ + else + Outval(-100); + Outval(-(descender+5)); /* Descender is given as positive value */ + Outval(maxwidth+10); + Outval(ascent+5); + + /* + * Give other metrics that were kept + */ + outp.Write("\nCapHeight"); + Outval(capheight); + outp.Write("\nXHeight"); + Outval(xheight); + outp.Write("\nDescender"); + Outval(descender); + outp.Write("\nAscender"); + Outval(ascender); + outp.Write('\n'); + } + + private void Putchartab() { + int count = lastchar - firstchar + 1; + int[] ctabs = new int[count]; + inp.Seek(chartab); + for (int k = 0; k < count; ++k) + ctabs[k] = inp.ReadUnsignedShortLE(); + int[] back = new int[256]; + if (charset == 0) { + for (int i = firstchar; i <= lastchar; ++i) { + if (Win2PSStd[i] != 0) + back[Win2PSStd[i]] = i; + } + } + /* Put outp the header */ + outp.Write("StartCharMetrics"); + Outval(count); + outp.Write('\n'); + + /* Put outp all encoded chars */ + if (charset != 0) { + /* + * If the charset is not the Windows standard, just put outp + * unnamed entries. + */ + for (int i = firstchar; i <= lastchar; i++) { + if (ctabs[i - firstchar] != 0) { + Outchar(i, ctabs[i - firstchar], null); + } + } + } + else { + for (int i = 0; i < 256; i++) { + int j = back[i]; + if (j != 0) { + Outchar(i, ctabs[j - firstchar], WinChars[j]); + ctabs[j - firstchar] = 0; + } + } + /* Put outp all non-encoded chars */ + for (int i = firstchar; i <= lastchar; i++) { + if (ctabs[i - firstchar] != 0) { + Outchar(-1, ctabs[i - firstchar], WinChars[i]); + } + } + } + /* Put outp the trailer */ + outp.Write("EndCharMetrics\n"); + + } + + private void Putkerntab() { + if (kernpairs == 0) + return; + inp.Seek(kernpairs); + int count = inp.ReadUnsignedShortLE(); + int nzero = 0; + int[] kerns = new int[count * 3]; + for (int k = 0; k < kerns.Length;) { + kerns[k++] = inp.Read(); + kerns[k++] = inp.Read(); + if ((kerns[k++] = inp.ReadShortLE()) != 0) + ++nzero; + } + if (nzero == 0) + return; + outp.Write("StartKernData\nStartKernPairs"); + Outval(nzero); + outp.Write('\n'); + for (int k = 0; k < kerns.Length; k += 3) { + if (kerns[k + 2] != 0) { + outp.Write("KPX "); + outp.Write(WinChars[kerns[k]]); + outp.Write(' '); + outp.Write(WinChars[kerns[k + 1]]); + Outval(kerns[k + 2]); + outp.Write('\n'); + } + } + /* Put outp trailer */ + outp.Write("EndKernPairs\nEndKernData\n"); + } + + + private void Puttrailer() { + outp.Write("EndFontMetrics\n"); + } + + private short vers; + private int h_len; /* Total length of .pfm file */ + private String copyright; /* Copyright string [60]*/ + private short type; + private short points; + private short verres; + private short horres; + private short ascent; + private short intleading; + private short extleading; + private byte italic; + private byte uline; + private byte overs; + private short weight; + private byte charset; /* 0=windows, otherwise nomap */ + private short pixwidth; /* Width for mono fonts */ + private short pixheight; + private byte kind; /* Lower bit off inp mono */ + private short avgwidth; /* Mono if avg=max width */ + private short maxwidth; /* Use to compute bounding box */ + private int firstchar; /* First char inp table */ + private int lastchar; /* Last char inp table */ + private byte defchar; + private byte brkchar; + private short widthby; + private int device; + private int face; /* Face name */ + private int bits; + private int bitoff; + private short extlen; + private int psext; /* PostScript extension */ + private int chartab; /* Character width tables */ + private int res1; + private int kernpairs; /* Kerning pairs */ + private int res2; + private int fontname; /* Font name */ + + /* + * Some metrics from the PostScript extension + */ + private short capheight; /* Cap height */ + private short xheight; /* X height */ + private short ascender; /* Ascender */ + private short descender; /* Descender (positive) */ + + + private bool isMono; + /* + * Translate table from 1004 to psstd. 1004 is an extension of the + * Windows translate table used inp PM. + */ + private int[] Win2PSStd = { + 0, 0, 0, 0, 197, 198, 199, 0, 202, 0, 205, 206, 207, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 169, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 193, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 0, 0, 184, 0, 185, 188, 178, 179, 94, 189, 0, 172, 234, 0, 0, 0, + 0, 96, 0, 170, 186, 0, 177, 208, 126, 0, 0, 173, 250, 0, 0, 0, + 0, 161, 162, 163, 168, 165, 0, 167, 200, 0, 227, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 194, 0, 182, 180, 203, 0, 235, 187, 0, 0, 0, 191, + 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 251, + 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0 + }; + + /* + * Character class. This is a minor attempt to overcome the problem that + * inp the pfm file, all unused characters are given the width of space. + */ + private int[] WinClass = { + 0, 0, 0, 0, 2, 2, 2, 0, 2, 0, 2, 2, 2, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, /* 70 */ + 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, /* 80 */ + 0, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, /* 90 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f0 */ + }; + + /* + * Windows chararacter names. Give a name to the usused locations + * for when the all flag is specified. + */ + private String[] WinChars = { + "W00", /* 00 */ + "W01", /* 01 */ + "W02", /* 02 */ + "W03", /* 03 */ + "macron", /* 04 */ + "breve", /* 05 */ + "dotaccent", /* 06 */ + "W07", /* 07 */ + "ring", /* 08 */ + "W09", /* 09 */ + "W0a", /* 0a */ + "W0b", /* 0b */ + "W0c", /* 0c */ + "W0d", /* 0d */ + "W0e", /* 0e */ + "W0f", /* 0f */ + "hungarumlaut", /* 10 */ + "ogonek", /* 11 */ + "caron", /* 12 */ + "W13", /* 13 */ + "W14", /* 14 */ + "W15", /* 15 */ + "W16", /* 16 */ + "W17", /* 17 */ + "W18", /* 18 */ + "W19", /* 19 */ + "W1a", /* 1a */ + "W1b", /* 1b */ + "W1c", /* 1c */ + "W1d", /* 1d */ + "W1e", /* 1e */ + "W1f", /* 1f */ + "space", /* 20 */ + "exclam", /* 21 */ + "quotedbl", /* 22 */ + "numbersign", /* 23 */ + "dollar", /* 24 */ + "percent", /* 25 */ + "ampersand", /* 26 */ + "quotesingle", /* 27 */ + "parenleft", /* 28 */ + "parenright", /* 29 */ + "asterisk", /* 2A */ + "plus", /* 2B */ + "comma", /* 2C */ + "hyphen", /* 2D */ + "period", /* 2E */ + "slash", /* 2F */ + "zero", /* 30 */ + "one", /* 31 */ + "two", /* 32 */ + "three", /* 33 */ + "four", /* 34 */ + "five", /* 35 */ + "six", /* 36 */ + "seven", /* 37 */ + "eight", /* 38 */ + "nine", /* 39 */ + "colon", /* 3A */ + "semicolon", /* 3B */ + "less", /* 3C */ + "equal", /* 3D */ + "greater", /* 3E */ + "question", /* 3F */ + "at", /* 40 */ + "A", /* 41 */ + "B", /* 42 */ + "C", /* 43 */ + "D", /* 44 */ + "E", /* 45 */ + "F", /* 46 */ + "G", /* 47 */ + "H", /* 48 */ + "I", /* 49 */ + "J", /* 4A */ + "K", /* 4B */ + "L", /* 4C */ + "M", /* 4D */ + "N", /* 4E */ + "O", /* 4F */ + "P", /* 50 */ + "Q", /* 51 */ + "R", /* 52 */ + "S", /* 53 */ + "T", /* 54 */ + "U", /* 55 */ + "V", /* 56 */ + "W", /* 57 */ + "X", /* 58 */ + "Y", /* 59 */ + "Z", /* 5A */ + "bracketleft", /* 5B */ + "backslash", /* 5C */ + "bracketright", /* 5D */ + "asciicircum", /* 5E */ + "underscore", /* 5F */ + "grave", /* 60 */ + "a", /* 61 */ + "b", /* 62 */ + "c", /* 63 */ + "d", /* 64 */ + "e", /* 65 */ + "f", /* 66 */ + "g", /* 67 */ + "h", /* 68 */ + "i", /* 69 */ + "j", /* 6A */ + "k", /* 6B */ + "l", /* 6C */ + "m", /* 6D */ + "n", /* 6E */ + "o", /* 6F */ + "p", /* 70 */ + "q", /* 71 */ + "r", /* 72 */ + "s", /* 73 */ + "t", /* 74 */ + "u", /* 75 */ + "v", /* 76 */ + "w", /* 77 */ + "x", /* 78 */ + "y", /* 79 */ + "z", /* 7A */ + "braceleft", /* 7B */ + "bar", /* 7C */ + "braceright", /* 7D */ + "asciitilde", /* 7E */ + "W7f", /* 7F */ + "W80", /* 80 */ + "W81", /* 81 */ + "quotesinglbase", /* 82 */ + "W83", /* 83 */ + "quotedblbase", /* 84 */ + "ellipsis", /* 85 */ + "dagger", /* 86 */ + "daggerdbl", /* 87 */ + "asciicircum", /* 88 */ + "perthousand", /* 89 */ + "Scaron", /* 8A */ + "guilsinglleft", /* 8B */ + "OE", /* 8C */ + "W8d", /* 8D */ + "W8e", /* 8E */ + "W8f", /* 8F */ + "W90", /* 90 */ + "quoteleft", /* 91 */ + "quoteright", /* 92 */ + "quotedblleft", /* 93 */ + "quotedblright", /* 94 */ + "bullet1", /* 95 */ + "endash", /* 96 */ + "emdash", /* 97 */ + "asciitilde", /* 98 */ + "trademark", /* 99 */ + "scaron", /* 9A */ + "guilsinglright", /* 9B */ + "oe", /* 9C */ + "W9d", /* 9D */ + "W9e", /* 9E */ + "Ydieresis", /* 9F */ + "reqspace", /* A0 */ + "exclamdown", /* A1 */ + "cent", /* A2 */ + "sterling", /* A3 */ + "currency", /* A4 */ + "yen", /* A5 */ + "brokenbar", /* A6 */ + "section", /* A7 */ + "dieresis", /* A8 */ + "copyright", /* A9 */ + "ordfeminine", /* AA */ + "guillemotleft", /* AB */ + "logicalnot", /* AC */ + "syllable", /* AD */ + "registered", /* AE */ + "overbar", /* AF */ + "degree", /* B0 */ + "plusminus", /* B1 */ + "twosuperior", /* B2 */ + "threesuperior", /* B3 */ + "acute", /* B4 */ + "mu", /* B5 */ + "paragraph", /* B6 */ + "periodcentered", /* B7 */ + "cedilla", /* B8 */ + "onesuperior", /* B9 */ + "ordmasculine", /* BA */ + "guillemotright", /* BB */ + "onequarter", /* BC */ + "onehalf", /* BD */ + "threequarters", /* BE */ + "questiondown", /* BF */ + "Agrave", /* C0 */ + "Aacute", /* C1 */ + "Acircumflex", /* C2 */ + "Atilde", /* C3 */ + "Adieresis", /* C4 */ + "Aring", /* C5 */ + "AE", /* C6 */ + "Ccedilla", /* C7 */ + "Egrave", /* C8 */ + "Eacute", /* C9 */ + "Ecircumflex", /* CA */ + "Edieresis", /* CB */ + "Igrave", /* CC */ + "Iacute", /* CD */ + "Icircumflex", /* CE */ + "Idieresis", /* CF */ + "Eth", /* D0 */ + "Ntilde", /* D1 */ + "Ograve", /* D2 */ + "Oacute", /* D3 */ + "Ocircumflex", /* D4 */ + "Otilde", /* D5 */ + "Odieresis", /* D6 */ + "multiply", /* D7 */ + "Oslash", /* D8 */ + "Ugrave", /* D9 */ + "Uacute", /* DA */ + "Ucircumflex", /* DB */ + "Udieresis", /* DC */ + "Yacute", /* DD */ + "Thorn", /* DE */ + "germandbls", /* DF */ + "agrave", /* E0 */ + "aacute", /* E1 */ + "acircumflex", /* E2 */ + "atilde", /* E3 */ + "adieresis", /* E4 */ + "aring", /* E5 */ + "ae", /* E6 */ + "ccedilla", /* E7 */ + "egrave", /* E8 */ + "eacute", /* E9 */ + "ecircumflex", /* EA */ + "edieresis", /* EB */ + "igrave", /* EC */ + "iacute", /* ED */ + "icircumflex", /* EE */ + "idieresis", /* EF */ + "eth", /* F0 */ + "ntilde", /* F1 */ + "ograve", /* F2 */ + "oacute", /* F3 */ + "ocircumflex", /* F4 */ + "otilde", /* F5 */ + "odieresis", /* F6 */ + "divide", /* F7 */ + "oslash", /* F8 */ + "ugrave", /* F9 */ + "uacute", /* FA */ + "ucircumflex", /* FB */ + "udieresis", /* FC */ + "yacute", /* FD */ + "thorn", /* FE */ + "ydieresis" /* FF */ + }; + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs b/iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs new file mode 100644 index 0000000..df38a5a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs @@ -0,0 +1,628 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a pushbutton field. It supports all the text and icon alignments. + * The icon may be an image or a template. + *

+ * Example usage: + *

+ *

+    * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
+    * PdfWriter writer = PdfWriter.GetInstance(document, new FileOutputStream("output.pdf"));
+    * document.Open();
+    * PdfContentByte cb = writer.GetDirectContent();
+    * Image img = Image.GetInstance("image.png");
+    * PushbuttonField bt = new PushbuttonField(writer, new Rectangle(100, 100, 200, 200), "Button1");
+    * bt.SetText("My Caption");
+    * bt.SetFontSize(0);
+    * bt.SetImage(img);
+    * bt.SetLayout(PushbuttonField.LAYOUT_ICON_TOP_LABEL_BOTTOM);
+    * bt.SetBackgroundColor(Color.cyan);
+    * bt.SetBorderStyle(PdfBorderDictionary.STYLE_SOLID);
+    * bt.SetBorderColor(Color.red);
+    * bt.SetBorderWidth(3);
+    * PdfFormField ff = bt.GetField();
+    * PdfAction ac = PdfAction.CreateSubmitForm("http://www.submit-site.com", null, 0);
+    * ff.SetAction(ac);
+    * writer.AddAnnotation(ff);
+    * document.Close();
+    * 
+ * @author Paulo Soares (psoares@consiste.pt) + */ + public class PushbuttonField : BaseField { + + /** A layout option */ + public const int LAYOUT_LABEL_ONLY = 1; + /** A layout option */ + public const int LAYOUT_ICON_ONLY = 2; + /** A layout option */ + public const int LAYOUT_ICON_TOP_LABEL_BOTTOM = 3; + /** A layout option */ + public const int LAYOUT_LABEL_TOP_ICON_BOTTOM = 4; + /** A layout option */ + public const int LAYOUT_ICON_LEFT_LABEL_RIGHT = 5; + /** A layout option */ + public const int LAYOUT_LABEL_LEFT_ICON_RIGHT = 6; + /** A layout option */ + public const int LAYOUT_LABEL_OVER_ICON = 7; + /** An icon scaling option */ + public const int SCALE_ICON_ALWAYS = 1; + /** An icon scaling option */ + public const int SCALE_ICON_NEVER = 2; + /** An icon scaling option */ + public const int SCALE_ICON_IS_TOO_BIG = 3; + /** An icon scaling option */ + public const int SCALE_ICON_IS_TOO_SMALL = 4; + + /** + * Holds value of property layout. + */ + private int layout = LAYOUT_LABEL_ONLY; + + /** + * Holds value of property image. + */ + private Image image; + + /** + * Holds value of property template. + */ + private PdfTemplate template; + + /** + * Holds value of property scaleIcon. + */ + private int scaleIcon = SCALE_ICON_ALWAYS; + + /** + * Holds value of property proportionalIcon. + */ + private bool proportionalIcon = true; + + /** + * Holds value of property iconVerticalAdjustment. + */ + private float iconVerticalAdjustment = 0.5f; + + /** + * Holds value of property iconHorizontalAdjustment. + */ + private float iconHorizontalAdjustment = 0.5f; + + /** + * Holds value of property iconFitToBounds. + */ + private bool iconFitToBounds; + + private PdfTemplate tp; + + /** + * Creates a new instance of PushbuttonField + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public PushbuttonField(PdfWriter writer, Rectangle box, String fieldName) : base(writer, box, fieldName) { + } + + /** + * Sets the icon and label layout. Possible values are LAYOUT_LABEL_ONLY, + * LAYOUT_ICON_ONLY, LAYOUT_ICON_TOP_LABEL_BOTTOM, + * LAYOUT_LABEL_TOP_ICON_BOTTOM, LAYOUT_ICON_LEFT_LABEL_RIGHT, + * LAYOUT_LABEL_LEFT_ICON_RIGHT and LAYOUT_LABEL_OVER_ICON. + * The default is LAYOUT_LABEL_ONLY. + * @param layout New value of property layout. + */ + public int Layout { + set { + if (value < LAYOUT_LABEL_ONLY || value > LAYOUT_LABEL_OVER_ICON) + throw new ArgumentException("Layout out of bounds."); + this.layout = value; + } + get { + return layout; + } + } + + /** + * Sets the icon as an image. + * @param image the image + */ + public Image Image { + get { + return this.image; + } + set { + image = value; + template = null; + } + } + + /** + * Sets the icon as a template. + * @param template the template + */ + public PdfTemplate Template { + set { + this.template = value; + image = null; + } + get { + return template; + } + } + + /** + * Sets the way the icon will be scaled. Possible values are + * SCALE_ICON_ALWAYS, SCALE_ICON_NEVER, + * SCALE_ICON_IS_TOO_BIG and SCALE_ICON_IS_TOO_SMALL. + * The default is SCALE_ICON_ALWAYS. + * @param scaleIcon the way the icon will be scaled + */ + public int ScaleIcon { + set { + if (value < SCALE_ICON_ALWAYS || value > SCALE_ICON_IS_TOO_SMALL) + scaleIcon = SCALE_ICON_ALWAYS; + else + scaleIcon = value; + } + get { + return scaleIcon; + } + } + + /** + * Sets the way the icon is scaled. If true the icon is scaled proportionally, + * if false the scaling is done anamorphicaly. + * @param proportionalIcon the way the icon is scaled + */ + public bool ProportionalIcon { + get { + return proportionalIcon; + } + set { + proportionalIcon = value; + } + } + + /** + * A number between 0 and 1 indicating the fraction of leftover space to allocate at the bottom of the icon. + * A value of 0 positions the icon at the bottom of the annotation rectangle. + * A value of 0.5 centers it within the rectangle. The default is 0.5. + * @param iconVerticalAdjustment a number between 0 and 1 indicating the fraction of leftover space to allocate at the bottom of the icon + */ + public float IconVerticalAdjustment { + get { + return iconVerticalAdjustment; + } + set { + iconVerticalAdjustment = value; + if (iconVerticalAdjustment < 0) + iconVerticalAdjustment = 0; + else if (iconVerticalAdjustment > 1) + iconVerticalAdjustment = 1; + } + } + + /** + * A number between 0 and 1 indicating the fraction of leftover space to allocate at the left of the icon. + * A value of 0 positions the icon at the left of the annotation rectangle. + * A value of 0.5 centers it within the rectangle. The default is 0.5. + * @param iconHorizontalAdjustment a number between 0 and 1 indicating the fraction of leftover space to allocate at the left of the icon + */ + public float IconHorizontalAdjustment { + get { + return iconHorizontalAdjustment; + } + set { + iconHorizontalAdjustment = value; + if (iconHorizontalAdjustment < 0) + iconHorizontalAdjustment = 0; + else if (iconHorizontalAdjustment > 1) + iconHorizontalAdjustment = 1; + } + } + private float CalculateFontSize(float w, float h) { + BaseFont ufont = RealFont; + float fsize = fontSize; + if (fsize == 0) { + float bw = ufont.GetWidthPoint(text, 1); + if (bw == 0) + fsize = 12; + else + fsize = w / bw; + float nfsize = h / (1 - ufont.GetFontDescriptor(BaseFont.DESCENT, 1)); + fsize = Math.Min(fsize, nfsize); + if (fsize < 4) + fsize = 4; + } + return fsize; + } + + /** + * Gets the button appearance. + * @throws IOException on error + * @throws DocumentException on error + * @return the button appearance + */ + public PdfAppearance GetAppearance() { + PdfAppearance app = GetBorderAppearance(); + Rectangle box = new Rectangle(app.BoundingBox); + if ((text == null || text.Length == 0) && (layout == LAYOUT_LABEL_ONLY || (image == null && template == null && iconReference == null))) { + return app; + } + if (layout == LAYOUT_ICON_ONLY && image == null && template == null && iconReference == null) + return app; + BaseFont ufont = RealFont; + bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; + float h = box.Height - borderWidth * 2; + float bw2 = borderWidth; + if (borderExtra) { + h -= borderWidth * 2; + bw2 *= 2; + } + float offsetX = (borderExtra ? 2 * borderWidth : borderWidth); + offsetX = Math.Max(offsetX, 1); + float offX = Math.Min(bw2, offsetX); + tp = null; + float textX = float.NaN; + float textY = 0; + float fsize = fontSize; + float wt = box.Width - 2 * offX - 2; + float ht = box.Height - 2 * offX; + float adj = (iconFitToBounds ? 0 : offX + 1); + int nlayout = layout; + if (image == null && template == null && iconReference == null) + nlayout = LAYOUT_LABEL_ONLY; + Rectangle iconBox = null; + while (true) { + switch (nlayout) { + case LAYOUT_LABEL_ONLY: + case LAYOUT_LABEL_OVER_ICON: + if (text != null && text.Length > 0 && wt > 0 && ht > 0) { + fsize = CalculateFontSize(wt, ht); + textX = (box.Width - ufont.GetWidthPoint(text, fsize)) / 2; + textY = (box.Height - ufont.GetFontDescriptor(BaseFont.ASCENT, fsize)) / 2; + } + goto case LAYOUT_ICON_ONLY; + case LAYOUT_ICON_ONLY: + if (nlayout == LAYOUT_LABEL_OVER_ICON || nlayout == LAYOUT_ICON_ONLY) + iconBox = new Rectangle(box.Left + adj, box.Bottom + adj, box.Right - adj, box.Top - adj); + break; + case LAYOUT_ICON_TOP_LABEL_BOTTOM: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + float nht = box.Height * 0.35f - offX; + if (nht > 0) + fsize = CalculateFontSize(wt, nht); + else + fsize = 4; + textX = (box.Width - ufont.GetWidthPoint(text, fsize)) / 2; + textY = offX - ufont.GetFontDescriptor(BaseFont.DESCENT, fsize); + iconBox = new Rectangle(box.Left + adj, textY + fsize, box.Right - adj, box.Top - adj); + break; + case LAYOUT_LABEL_TOP_ICON_BOTTOM: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + nht = box.Height * 0.35f - offX; + if (nht > 0) + fsize = CalculateFontSize(wt, nht); + else + fsize = 4; + textX = (box.Width - ufont.GetWidthPoint(text, fsize)) / 2; + textY = box.Height - offX - fsize; + if (textY < offX) + textY = offX; + iconBox = new Rectangle(box.Left + adj, box.Bottom + adj, box.Right - adj, textY + ufont.GetFontDescriptor(BaseFont.DESCENT, fsize)); + break; + case LAYOUT_LABEL_LEFT_ICON_RIGHT: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + float nw = box.Width * 0.35f - offX; + if (nw > 0) + fsize = CalculateFontSize(wt, nw); + else + fsize = 4; + if (ufont.GetWidthPoint(text, fsize) >= wt) { + nlayout = LAYOUT_LABEL_ONLY; + fsize = fontSize; + continue; + } + textX = offX + 1; + textY = (box.Height - ufont.GetFontDescriptor(BaseFont.ASCENT, fsize)) / 2; + iconBox = new Rectangle(textX + ufont.GetWidthPoint(text, fsize), box.Bottom + adj, box.Right - adj, box.Top - adj); + break; + case LAYOUT_ICON_LEFT_LABEL_RIGHT: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + nw = box.Width * 0.35f - offX; + if (nw > 0) + fsize = CalculateFontSize(wt, nw); + else + fsize = 4; + if (ufont.GetWidthPoint(text, fsize) >= wt) { + nlayout = LAYOUT_LABEL_ONLY; + fsize = fontSize; + continue; + } + textX = box.Width - ufont.GetWidthPoint(text, fsize) - offX - 1; + textY = (box.Height - ufont.GetFontDescriptor(BaseFont.ASCENT, fsize)) / 2; + iconBox = new Rectangle(box.Left + adj, box.Bottom + adj, textX - 1, box.Top - adj); + break; + } + break; + } + if (textY < box.Bottom + offX) + textY = box.Bottom + offX; + if (iconBox != null && (iconBox.Width <= 0 || iconBox.Height <= 0)) + iconBox = null; + bool haveIcon = false; + float boundingBoxWidth = 0; + float boundingBoxHeight = 0; + PdfArray matrix = null; + if (iconBox != null) { + if (image != null) { + tp = new PdfTemplate(writer); + tp.BoundingBox = new Rectangle(image); + writer.AddDirectTemplateSimple(tp, PdfName.FRM); + tp.AddImage(image, image.Width, 0, 0, image.Height, 0, 0); + haveIcon = true; + boundingBoxWidth = tp.BoundingBox.Width; + boundingBoxHeight = tp.BoundingBox.Height; + } + else if (template != null) { + tp = new PdfTemplate(writer); + tp.BoundingBox = new Rectangle(template.Width, template.Height); + writer.AddDirectTemplateSimple(tp, PdfName.FRM); + tp.AddTemplate(template, template.BoundingBox.Left, template.BoundingBox.Bottom); + haveIcon = true; + boundingBoxWidth = tp.BoundingBox.Width; + boundingBoxHeight = tp.BoundingBox.Height; + } + else if (iconReference != null) { + PdfDictionary dic = (PdfDictionary)PdfReader.GetPdfObject(iconReference); + if (dic != null) { + Rectangle r2 = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.BBOX))); + matrix = (PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.MATRIX)); + haveIcon = true; + boundingBoxWidth = r2.Width; + boundingBoxHeight = r2.Height; + } + } + } + if (haveIcon) { + float icx = iconBox.Width / boundingBoxWidth; + float icy = iconBox.Height / boundingBoxHeight; + if (proportionalIcon) { + switch (scaleIcon) { + case SCALE_ICON_IS_TOO_BIG: + icx = Math.Min(icx, icy); + icx = Math.Min(icx, 1); + break; + case SCALE_ICON_IS_TOO_SMALL: + icx = Math.Min(icx, icy); + icx = Math.Max(icx, 1); + break; + case SCALE_ICON_NEVER: + icx = 1; + break; + default: + icx = Math.Min(icx, icy); + break; + } + icy = icx; + } + else { + switch (scaleIcon) { + case SCALE_ICON_IS_TOO_BIG: + icx = Math.Min(icx, 1); + icy = Math.Min(icy, 1); + break; + case SCALE_ICON_IS_TOO_SMALL: + icx = Math.Max(icx, 1); + icy = Math.Max(icy, 1); + break; + case SCALE_ICON_NEVER: + icx = icy = 1; + break; + default: + break; + } + } + float xpos = iconBox.Left + (iconBox.Width - (boundingBoxWidth * icx)) * iconHorizontalAdjustment; + float ypos = iconBox.Bottom + (iconBox.Height - (boundingBoxHeight * icy)) * iconVerticalAdjustment; + app.SaveState(); + app.Rectangle(iconBox.Left, iconBox.Bottom, iconBox.Width, iconBox.Height); + app.Clip(); + app.NewPath(); + if (tp != null) + app.AddTemplate(tp, icx, 0, 0, icy, xpos, ypos); + else { + float cox = 0; + float coy = 0; + if (matrix != null && matrix.Size == 6) { + PdfNumber nm = (PdfNumber)PdfReader.GetPdfObject((PdfObject)matrix.ArrayList[4]); + if (nm != null) + cox = nm.FloatValue; + nm = (PdfNumber)PdfReader.GetPdfObject((PdfObject)matrix.ArrayList[5]); + if (nm != null) + coy = nm.FloatValue; + } + app.AddTemplateReference(iconReference, PdfName.FRM, icx, 0, 0, icy, xpos - cox * icx, ypos - coy * icy); + } + app.RestoreState(); + } + if (!float.IsNaN(textX)) { + app.SaveState(); + app.Rectangle(offX, offX, box.Width - 2 * offX, box.Height - 2 * offX); + app.Clip(); + app.NewPath(); + if (textColor == null) + app.ResetGrayFill(); + else + app.SetColorFill(textColor); + app.BeginText(); + app.SetFontAndSize(ufont, fsize); + app.SetTextMatrix(textX, textY); + app.ShowText(text); + app.EndText(); + app.RestoreState(); + } + return app; + } + + /** + * Gets the pushbutton field. + * @throws IOException on error + * @throws DocumentException on error + * @return the pushbutton field + */ + public PdfFormField Field { + get { + PdfFormField field = PdfFormField.CreatePushButton(writer); + field.SetWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); + if (fieldName != null) { + field.FieldName = fieldName; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + } + if (text != null) + field.MKNormalCaption = text; + if (rotation != 0) + field.MKRotation = rotation; + field.BorderStyle = new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3)); + PdfAppearance tpa = GetAppearance(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tpa); + PdfAppearance da = (PdfAppearance)tpa.Duplicate; + da.SetFontAndSize(RealFont, fontSize); + if (textColor == null) + da.SetGrayFill(0); + else + da.SetColorFill(textColor); + field.DefaultAppearanceString = da; + if (borderColor != null) + field.MKBorderColor = borderColor; + if (backgroundColor != null) + field.MKBackgroundColor = backgroundColor; + switch (visibility) { + case HIDDEN: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN; + break; + case VISIBLE_BUT_DOES_NOT_PRINT: + break; + case HIDDEN_BUT_PRINTABLE: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW; + break; + default: + field.Flags = PdfAnnotation.FLAGS_PRINT; + break; + } + if (tp != null) + field.MKNormalIcon = tp; + field.MKTextPosition = layout - 1; + PdfName scale = PdfName.A; + if (scaleIcon == SCALE_ICON_IS_TOO_BIG) + scale = PdfName.B; + else if (scaleIcon == SCALE_ICON_IS_TOO_SMALL) + scale = PdfName.S; + else if (scaleIcon == SCALE_ICON_NEVER) + scale = PdfName.N; + field.SetMKIconFit(scale, proportionalIcon ? PdfName.P : PdfName.A, iconHorizontalAdjustment, + iconVerticalAdjustment, iconFitToBounds); + return field; + } + } + + /** + * If true the icon will be scaled to fit fully within the bounds of the annotation, + * if false the border width will be taken into account. The default + * is false. + * @param iconFitToBounds if true the icon will be scaled to fit fully within the bounds of the annotation, + * if false the border width will be taken into account + */ + public bool IconFitToBounds { + get { + return iconFitToBounds; + } + set { + iconFitToBounds = value; + } + } + /** + * Holds value of property iconReference. + */ + private PRIndirectReference iconReference; + + /** + * Sets the reference to an existing icon. + * @param iconReference the reference to an existing icon + */ + public PRIndirectReference IconReference { + get { + return iconReference; + } + set { + iconReference = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs b/iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs new file mode 100644 index 0000000..f373fb0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs @@ -0,0 +1,401 @@ +using System; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a radio or a check field. + *

+ * Example usage: + *

+ *

+    * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
+    * PdfWriter writer = PdfWriter.GetInstance(document, new FileOutputStream("output.pdf"));
+    * document.Open();
+    * PdfContentByte cb = writer.GetDirectContent();
+    * RadioCheckField bt = new RadioCheckField(writer, new Rectangle(100, 100, 200, 200), "radio", "v1");
+    * bt.SetCheckType(RadioCheckField.TYPE_CIRCLE);
+    * bt.SetBackgroundColor(Color.CYAN);
+    * bt.SetBorderStyle(PdfBorderDictionary.STYLE_SOLID);
+    * bt.SetBorderColor(Color.red);
+    * bt.SetTextColor(Color.yellow);
+    * bt.SetBorderWidth(BaseField.BORDER_WIDTH_THICK);
+    * bt.SetChecked(false);
+    * PdfFormField f1 = bt.GetRadioField();
+    * bt.SetOnValue("v2");
+    * bt.SetChecked(true);
+    * bt.SetBox(new Rectangle(100, 300, 200, 400));
+    * PdfFormField f2 = bt.GetRadioField();
+    * bt.SetChecked(false);
+    * PdfFormField top = bt.GetRadioGroup(true, false);
+    * bt.SetOnValue("v3");
+    * bt.SetBox(new Rectangle(100, 500, 200, 600));
+    * PdfFormField f3 = bt.GetRadioField();
+    * top.AddKid(f1);
+    * top.AddKid(f2);
+    * top.AddKid(f3);
+    * writer.AddAnnotation(top);
+    * bt = new RadioCheckField(writer, new Rectangle(300, 300, 400, 400), "check1", "Yes");
+    * bt.SetCheckType(RadioCheckField.TYPE_CHECK);
+    * bt.SetBorderWidth(BaseField.BORDER_WIDTH_THIN);
+    * bt.SetBorderColor(Color.black);
+    * bt.SetBackgroundColor(Color.white);
+    * PdfFormField ck = bt.GetCheckField();
+    * writer.AddAnnotation(ck);
+    * document.Close();
+    * 
+ * @author Paulo Soares (psoares@consiste.pt) + */ + public class RadioCheckField : BaseField { + + /** A field with the symbol check */ + public const int TYPE_CHECK = 1; + /** A field with the symbol circle */ + public const int TYPE_CIRCLE = 2; + /** A field with the symbol cross */ + public const int TYPE_CROSS = 3; + /** A field with the symbol diamond */ + public const int TYPE_DIAMOND = 4; + /** A field with the symbol square */ + public const int TYPE_SQUARE = 5; + /** A field with the symbol star */ + public const int TYPE_STAR = 6; + + private static String[] typeChars = {"4", "l", "8", "u", "n", "H"}; + + /** + * Holds value of property checkType. + */ + private int checkType; + + /** + * Holds value of property onValue. + */ + private String onValue; + + /** + * Holds value of property checked. + */ + private bool vchecked; + + /** + * Creates a new instance of RadioCheckField + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. It must not be null + * @param onValue the value when the field is checked + */ + public RadioCheckField(PdfWriter writer, Rectangle box, String fieldName, String onValue) : base(writer, box, fieldName) { + OnValue = onValue; + CheckType = TYPE_CIRCLE; + } + + /** + * Sets the checked symbol. It can be + * TYPE_CHECK, + * TYPE_CIRCLE, + * TYPE_CROSS, + * TYPE_DIAMOND, + * TYPE_SQUARE and + * TYPE_STAR. + * @param checkType the checked symbol + */ + public int CheckType { + get { + return checkType; + } + set { + checkType = value; + if (checkType < TYPE_CHECK || checkType > TYPE_STAR) + checkType = TYPE_CIRCLE; + Text = typeChars[checkType - 1]; + Font = BaseFont.CreateFont(BaseFont.ZAPFDINGBATS, BaseFont.WINANSI, false); + } + } + + /** + * Sets the value when the field is checked. + * @param onValue the value when the field is checked + */ + public string OnValue { + get { + return onValue; + } + set { + onValue = value; + } + } + + /** + * Sets the state of the field to checked or unchecked. + * @param checked the state of the field, true for checked + * and false for unchecked + */ + public bool Checked { + get { + return vchecked; + } + set { + vchecked = value; + } + } + /** + * Gets the field appearance. + * @param isRadio true for a radio field and false + * for a check field + * @param on true for the checked state, false + * otherwise + * @throws IOException on error + * @throws DocumentException on error + * @return the appearance + */ + public PdfAppearance GetAppearance(bool isRadio, bool on) { + if (isRadio && checkType == TYPE_CIRCLE) + return GetAppearanceRadioCircle(on); + PdfAppearance app = GetBorderAppearance(); + if (!on) + return app; + BaseFont ufont = RealFont; + bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; + float h = box.Height - borderWidth * 2; + float bw2 = borderWidth; + if (borderExtra) { + h -= borderWidth * 2; + bw2 *= 2; + } + float offsetX = (borderExtra ? 2 * borderWidth : borderWidth); + offsetX = Math.Max(offsetX, 1); + float offX = Math.Min(bw2, offsetX); + float wt = box.Width - 2 * offX; + float ht = box.Height - 2 * offX; + float fsize = fontSize; + if (fsize == 0) { + float bw = ufont.GetWidthPoint(text, 1); + if (bw == 0) + fsize = 12; + else + fsize = wt / bw; + float nfsize = h / (ufont.GetFontDescriptor(BaseFont.ASCENT, 1)); + fsize = Math.Min(fsize, nfsize); + } + app.SaveState(); + app.Rectangle(offX, offX, wt, ht); + app.Clip(); + app.NewPath(); + if (textColor == null) + app.ResetGrayFill(); + else + app.SetColorFill(textColor); + app.BeginText(); + app.SetFontAndSize(ufont, fsize); + app.SetTextMatrix((box.Width - ufont.GetWidthPoint(text, fsize)) / 2, + (box.Height - ufont.GetAscentPoint(text, fsize)) / 2); + app.ShowText(text); + app.EndText(); + app.RestoreState(); + return app; + } + + /** + * Gets the special field appearance for the radio circle. + * @param on true for the checked state, false + * otherwise + * @return the appearance + */ + public PdfAppearance GetAppearanceRadioCircle(bool on) { + PdfAppearance app = PdfAppearance.CreateAppearance(writer, box.Width, box.Height); + switch (rotation) { + case 90: + app.SetMatrix(0, 1, -1, 0, box.Height, 0); + break; + case 180: + app.SetMatrix(-1, 0, 0, -1, box.Width, box.Height); + break; + case 270: + app.SetMatrix(0, -1, 1, 0, 0, box.Width); + break; + } + Rectangle boxc = new Rectangle(app.BoundingBox); + float cx = boxc.Width / 2; + float cy = boxc.Height / 2; + float r = (Math.Min(boxc.Width, boxc.Height) - borderWidth) / 2; + if (r <= 0) + return app; + if (backgroundColor != null) { + app.SetColorFill(backgroundColor); + app.Circle(cx, cy, r + borderWidth / 2); + app.Fill(); + } + if (borderWidth > 0 && borderColor != null) { + app.SetLineWidth(borderWidth); + app.SetColorStroke(borderColor); + app.Circle(cx, cy, r); + app.Stroke(); + } + if (on) { + if (textColor == null) + app.ResetGrayFill(); + else + app.SetColorFill(textColor); + app.Circle(cx, cy, r / 2); + app.Fill(); + } + return app; + } + + /** + * Gets a radio group. It's composed of the field specific keys, without the widget + * ones. This field is to be used as a field aggregator with {@link PdfFormField#addKid(PdfFormField) AddKid()}. + * @param noToggleToOff if true, exactly one radio button must be selected at all + * times; clicking the currently selected button has no effect. + * If false, clicking + * the selected button deselects it, leaving no button selected. + * @param radiosInUnison if true, a group of radio buttons within a radio button field that + * use the same value for the on state will turn on and off in unison; that is if + * one is checked, they are all checked. If false, the buttons are mutually exclusive + * (the same behavior as HTML radio buttons) + * @return the radio group + */ + public PdfFormField GetRadioGroup(bool noToggleToOff, bool radiosInUnison) { + PdfFormField field = PdfFormField.CreateRadioButton(writer, noToggleToOff); + if (radiosInUnison) + field.SetFieldFlags(PdfFormField.FF_RADIOSINUNISON); + field.FieldName = fieldName; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + field.ValueAsName = vchecked ? onValue : "Off"; + return field; + } + + /** + * Gets the radio field. It's only composed of the widget keys and must be used + * with {@link #getRadioGroup(bool,bool)}. + * @return the radio field + * @throws IOException on error + * @throws DocumentException on error + */ + public PdfFormField RadioField { + get { + return GetField(true); + } + } + + /** + * Gets the check field. + * @return the check field + * @throws IOException on error + * @throws DocumentException on error + */ + public PdfFormField CheckField { + get { + return GetField(false); + } + } + + /** + * Gets a radio or check field. + * @param isRadio true to get a radio field, false to get + * a check field + * @throws IOException on error + * @throws DocumentException on error + * @return the field + */ + protected PdfFormField GetField(bool isRadio) { + PdfFormField field = null; + if (isRadio) + field = PdfFormField.CreateEmpty(writer); + else + field = PdfFormField.CreateCheckBox(writer); + field.SetWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); + if (!isRadio) { + field.FieldName = fieldName; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + field.ValueAsName = vchecked ? onValue : "Off"; + } + if (text != null) + field.MKNormalCaption = text; + if (rotation != 0) + field.MKRotation = rotation; + field.BorderStyle = new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3)); + PdfAppearance tpon = GetAppearance(isRadio, true); + PdfAppearance tpoff = GetAppearance(isRadio, false); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, onValue, tpon); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", tpoff); + field.AppearanceState = vchecked ? onValue : "Off"; + PdfAppearance da = (PdfAppearance)tpon.Duplicate; + da.SetFontAndSize(RealFont, fontSize); + if (textColor == null) + da.SetGrayFill(0); + else + da.SetColorFill(textColor); + field.DefaultAppearanceString = da; + if (borderColor != null) + field.MKBorderColor = borderColor; + if (backgroundColor != null) + field.MKBackgroundColor = backgroundColor; + switch (visibility) { + case HIDDEN: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN; + break; + case VISIBLE_BUT_DOES_NOT_PRINT: + break; + case HIDDEN_BUT_PRINTABLE: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW; + break; + default: + field.Flags = PdfAnnotation.FLAGS_PRINT; + break; + } + return field; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs b/iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs new file mode 100644 index 0000000..ea6a7b0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs @@ -0,0 +1,607 @@ +using System; +using System.IO; +using System.Text; +using System.Net; +/* + * $Id: RandomAccessFileOrArray.cs,v 1.9 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** An implementation of a RandomAccessFile for input only + * that accepts a file or a byte array as data source. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class RandomAccessFileOrArray { + + internal FileStream rf; + internal String filename; + internal byte[] arrayIn; + internal int arrayInPtr; + internal byte back; + internal bool isBack = false; + + /** Holds value of property startOffset. */ + private int startOffset = 0; + + public RandomAccessFileOrArray(String filename) : this(filename, false) { + } + + public RandomAccessFileOrArray(String filename, bool forceRead) { + if (!File.Exists(filename)) { + if (filename.StartsWith("file:/") || filename.StartsWith("http://") || filename.StartsWith("https://")) { + Stream isp = WebRequest.Create(new Uri(filename)).GetResponse().GetResponseStream(); + try { + this.arrayIn = InputStreamToArray(isp); + return; + } + finally { + try {isp.Close();}catch{} + } + } + else { + Stream isp = BaseFont.GetResourceStream(filename); + if (isp == null) + throw new IOException(filename + " not found as file or resource."); + try { + this.arrayIn = InputStreamToArray(isp); + return; + } + finally { + try {isp.Close();}catch{} + } + } + } + else if (forceRead) { + Stream s = null; + try { + s = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + this.arrayIn = InputStreamToArray(s); + } + finally { + try{if (s != null) s.Close();}catch{} + } + return; + } + this.filename = filename; + rf = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + } + + public RandomAccessFileOrArray(Uri url) { + Stream isp = WebRequest.Create(url).GetResponse().GetResponseStream(); + try { + this.arrayIn = InputStreamToArray(isp); + } + finally { + try {isp.Close();}catch{} + } + } + + public RandomAccessFileOrArray(Stream isp) { + this.arrayIn = InputStreamToArray(isp); + } + + public static byte[] InputStreamToArray(Stream isp) { + byte[] b = new byte[8192]; + MemoryStream outp = new MemoryStream(); + while (true) { + int read = isp.Read(b, 0, b.Length); + if (read < 1) + break; + outp.Write(b, 0, read); + } + return outp.ToArray(); + } + + public RandomAccessFileOrArray(byte[] arrayIn) { + this.arrayIn = arrayIn; + } + + public RandomAccessFileOrArray(RandomAccessFileOrArray file) { + filename = file.filename; + arrayIn = file.arrayIn; + startOffset = file.startOffset; + } + + public void PushBack(byte b) { + back = b; + isBack = true; + } + + public int Read() { + if (isBack) { + isBack = false; + return back & 0xff; + } + if (arrayIn == null) + return rf.ReadByte(); + else { + if (arrayInPtr >= arrayIn.Length) + return -1; + return arrayIn[arrayInPtr++] & 0xff; + } + } + + public int Read(byte[] b, int off, int len) { + if (len == 0) + return 0; + int n = 0; + if (isBack) { + isBack = false; + if (len == 1) { + b[off] = back; + return 1; + } + else { + n = 1; + b[off++] = back; + --len; + } + } + if (arrayIn == null) { + return rf.Read(b, off, len) + n; + } + else { + if (arrayInPtr >= arrayIn.Length) + return -1; + if (arrayInPtr + len > arrayIn.Length) + len = arrayIn.Length - arrayInPtr; + Array.Copy(arrayIn, arrayInPtr, b, off, len); + arrayInPtr += len; + return len + n; + } + } + + public int Read(byte[] b) { + return Read(b, 0, b.Length); + } + + public void ReadFully(byte[] b) { + ReadFully(b, 0, b.Length); + } + + public void ReadFully(byte[] b, int off, int len) { + if (len == 0) + return; + int n = 0; + do { + int count = Read(b, off + n, len - n); + if (count <= 0) + throw new EndOfStreamException(); + n += count; + } while (n < len); + } + + public long Skip(long n) { + return SkipBytes((int)n); + } + + public int SkipBytes(int n) { + if (n <= 0) { + return 0; + } + int adj = 0; + if (isBack) { + isBack = false; + if (n == 1) { + return 1; + } + else { + --n; + adj = 1; + } + } + int pos; + int len; + int newpos; + + pos = FilePointer; + len = Length; + newpos = pos + n; + if (newpos > len) { + newpos = len; + } + Seek(newpos); + + /* return the actual number of bytes skipped */ + return newpos - pos + adj; + } + + public void ReOpen() { + if (filename != null && rf == null) + rf = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + Seek(0); + } + + protected void InsureOpen() { + if (filename != null && rf == null) { + ReOpen(); + } + } + + public bool IsOpen() { + return (filename == null || rf != null); + } + + public void Close() { + isBack = false; + if (rf != null) { + rf.Close(); + rf = null; + } + } + + public int Length { + get { + if (arrayIn == null) { + InsureOpen(); + return (int)rf.Length - startOffset; + } + else + return arrayIn.Length - startOffset; + } + } + + public void Seek(int pos) { + pos += startOffset; + isBack = false; + if (arrayIn == null) { + InsureOpen(); + rf.Position = pos; + } + else + arrayInPtr = pos; + } + + public void Seek(long pos) { + Seek((int)pos); + } + + public int FilePointer { + get { + InsureOpen(); + int n = isBack ? 1 : 0; + if (arrayIn == null) { + return (int)rf.Position - n - startOffset; + } + else + return arrayInPtr - n - startOffset; + } + } + + public bool ReadBoolean() { + int ch = this.Read(); + if (ch < 0) + throw new EndOfStreamException(); + return (ch != 0); + } + + public byte ReadByte() { + int ch = this.Read(); + if (ch < 0) + throw new EndOfStreamException(); + return (byte)(ch); + } + + public int ReadUnsignedByte() { + int ch = this.Read(); + if (ch < 0) + throw new EndOfStreamException(); + return ch; + } + + public short ReadShort() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (short)((ch1 << 8) + ch2); + } + + /** + * Reads a signed 16-bit number from this stream in little-endian order. + * The method reads two + * bytes from this stream, starting at the current stream pointer. + * If the two bytes read, in order, are + * b1 and b2, where each of the two values is + * between 0 and 255, inclusive, then the + * result is equal to: + *
+        *     (short)((b2 << 8) | b1)
+        * 
+ *

+ * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this stream, interpreted as a signed + * 16-bit number. + * @exception EOFException if this stream reaches the end before reading + * two bytes. + * @exception IOException if an I/O error occurs. + */ + public short ReadShortLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (short)((ch2 << 8) + (ch1 << 0)); + } + + public int ReadUnsignedShort() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (ch1 << 8) + ch2; + } + + /** + * Reads an unsigned 16-bit number from this stream in little-endian order. + * This method reads + * two bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are + * b1 and b2, where + * 0 <= b1, b2 <= 255, + * then the result is equal to: + *

+        *     (b2 << 8) | b1
+        * 
+ *

+ * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this stream, interpreted as an + * unsigned 16-bit integer. + * @exception EOFException if this stream reaches the end before reading + * two bytes. + * @exception IOException if an I/O error occurs. + */ + public int ReadUnsignedShortLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (ch2 << 8) + (ch1 << 0); + } + + public char ReadChar() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (char)((ch1 << 8) + ch2); + } + + /** + * Reads a Unicode character from this stream in little-endian order. + * This method reads two + * bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are + * b1 and b2, where + * 0 <= b1, b2 <= 255, + * then the result is equal to: + *

+        *     (char)((b2 << 8) | b1)
+        * 
+ *

+ * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this stream as a Unicode character. + * @exception EOFException if this stream reaches the end before reading + * two bytes. + * @exception IOException if an I/O error occurs. + */ + public char ReadCharLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (char)((ch2 << 8) + (ch1 << 0)); + } + + public int ReadInt() { + int ch1 = this.Read(); + int ch2 = this.Read(); + int ch3 = this.Read(); + int ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); + } + + /** + * Reads a signed 32-bit integer from this stream in little-endian order. + * This method reads 4 + * bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are b1, + * b2, b3, and b4, where + * 0 <= b1, b2, b3, b4 <= 255, + * then the result is equal to: + *

+        *     (b4 << 24) | (b3 << 16) + (b2 << 8) + b1
+        * 
+ *

+ * This method blocks until the four bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next four bytes of this stream, interpreted as an + * int. + * @exception EOFException if this stream reaches the end before reading + * four bytes. + * @exception IOException if an I/O error occurs. + */ + public int ReadIntLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + int ch3 = this.Read(); + int ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + } + + /** + * Reads an unsigned 32-bit integer from this stream. This method reads 4 + * bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are b1, + * b2, b3, and b4, where + * 0 <= b1, b2, b3, b4 <= 255, + * then the result is equal to: + *

+        *     (b1 << 24) | (b2 << 16) + (b3 << 8) + b4
+        * 
+ *

+ * This method blocks until the four bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next four bytes of this stream, interpreted as a + * long. + * @exception EOFException if this stream reaches the end before reading + * four bytes. + * @exception IOException if an I/O error occurs. + */ + public long ReadUnsignedInt() { + long ch1 = this.Read(); + long ch2 = this.Read(); + long ch3 = this.Read(); + long ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } + + public long ReadUnsignedIntLE() { + long ch1 = this.Read(); + long ch2 = this.Read(); + long ch3 = this.Read(); + long ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + } + + public long ReadLong() { + return ((long)(ReadInt()) << 32) + (ReadInt() & 0xFFFFFFFFL); + } + + public long ReadLongLE() { + int i1 = ReadIntLE(); + int i2 = ReadIntLE(); + return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL); + } + + public float ReadFloat() { + int[] a = {ReadInt()}; + float[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 4); + return b[0]; + } + + public float ReadFloatLE() { + int[] a = {ReadIntLE()}; + float[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 4); + return b[0]; + } + + public double ReadDouble() { + long[] a = {ReadLong()}; + double[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 8); + return b[0]; + } + + public double ReadDoubleLE() { + long[] a = {ReadLongLE()}; + double[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 8); + return b[0]; + } + + public String ReadLine() { + StringBuilder input = new StringBuilder(); + int c = -1; + bool eol = false; + + while (!eol) { + switch (c = Read()) { + case -1: + case '\n': + eol = true; + break; + case '\r': + eol = true; + int cur = FilePointer; + if ((Read()) != '\n') { + Seek(cur); + } + break; + default: + input.Append((char)c); + break; + } + } + + if ((c == -1) && (input.Length == 0)) { + return null; + } + return input.ToString(); + } + + public int StartOffset { + get { + return startOffset; + } + set { + startOffset = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/SequenceList.cs b/iTechSharp/iTextSharp/text/pdf/SequenceList.cs new file mode 100644 index 0000000..04b6b7b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/SequenceList.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * This class expands a string into a list of numbers. The main use is to select a + * range of pages. + *

+ * The general systax is:
+ * [!][o][odd][e][even]start-end + *

+ * You can have multiple ranges separated by commas ','. The '!' modifier removes the + * range from what is already selected. The range changes are incremental, that is, + * numbers are added or deleted as the range appears. The start or the end, but not both, can be ommited. + */ + public class SequenceList { + protected const int COMMA = 1; + protected const int MINUS = 2; + protected const int NOT = 3; + protected const int TEXT = 4; + protected const int NUMBER = 5; + protected const int END = 6; + protected const char EOT = '\uffff'; + + private const int FIRST = 0; + private const int DIGIT = 1; + private const int OTHER = 2; + private const int DIGIT2 = 3; + private const String NOT_OTHER = "-,!0123456789"; + + protected char[] text; + protected int ptr; + protected int number; + protected String other; + + protected int low; + protected int high; + protected bool odd; + protected bool even; + protected bool inverse; + + protected SequenceList(String range) { + ptr = 0; + text = range.ToCharArray(); + } + + protected char NextChar() { + while (true) { + if (ptr >= text.Length) + return EOT; + char c = text[ptr++]; + if (c > ' ') + return c; + } + } + + protected void PutBack() { + --ptr; + if (ptr < 0) + ptr = 0; + } + + protected int Type { + get { + StringBuilder buf = new StringBuilder(); + int state = FIRST; + while (true) { + char c = NextChar(); + if (c == EOT) { + if (state == DIGIT) { + number = int.Parse(other = buf.ToString()); + return NUMBER; + } + else if (state == OTHER) { + other = buf.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture); + return TEXT; + } + return END; + } + switch (state) { + case FIRST: + switch (c) { + case '!': + return NOT; + case '-': + return MINUS; + case ',': + return COMMA; + } + buf.Append(c); + if (c >= '0' && c <= '9') + state = DIGIT; + else + state = OTHER; + break; + case DIGIT: + if (c >= '0' && c <= '9') + buf.Append(c); + else { + PutBack(); + number = int.Parse(other = buf.ToString()); + return NUMBER; + } + break; + case OTHER: + if (NOT_OTHER.IndexOf(c) < 0) + buf.Append(c); + else { + PutBack(); + other = buf.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture); + return TEXT; + } + break; + } + } + } + } + + private void OtherProc() { + if (other.Equals("odd") || other.Equals("o")) { + odd = true; + even = false; + } + else if (other.Equals("even") || other.Equals("e")) { + odd = false; + even = true; + } + } + + protected bool GetAttributes() { + low = -1; + high = -1; + odd = even = inverse = false; + int state = OTHER; + while (true) { + int type = Type; + if (type == END || type == COMMA) { + if (state == DIGIT) + high = low; + return (type == END); + } + switch (state) { + case OTHER: + switch (type) { + case NOT: + inverse = true; + break; + case MINUS: + state = DIGIT2; + break; + default: + if (type == NUMBER) { + low = number; + state = DIGIT; + } + else + OtherProc(); + break; + } + break; + case DIGIT: + switch (type) { + case NOT: + inverse = true; + state = OTHER; + high = low; + break; + case MINUS: + state = DIGIT2; + break; + default: + high = low; + state = OTHER; + OtherProc(); + break; + } + break; + case DIGIT2: + switch (type) { + case NOT: + inverse = true; + state = OTHER; + break; + case MINUS: + break; + case NUMBER: + high = number; + state = OTHER; + break; + default: + state = OTHER; + OtherProc(); + break; + } + break; + } + } + } + + /** + * Generates a list of numbers from a string. + * @param ranges the comma separated ranges + * @param maxNumber the maximum number in the range + * @return a list with the numbers as Integer + */ + public static ArrayList Expand(String ranges, int maxNumber) { + SequenceList parse = new SequenceList(ranges); + ArrayList list = new ArrayList(); + bool sair = false; + while (!sair) { + sair = parse.GetAttributes(); + if (parse.low == -1 && parse.high == -1 && !parse.even && !parse.odd) + continue; + if (parse.low < 1) + parse.low = 1; + if (parse.high < 1 || parse.high > maxNumber) + parse.high = maxNumber; + if (parse.low > maxNumber) + parse.low = maxNumber; + + //System.out.Println("low="+parse.low+",high="+parse.high+",odd="+parse.odd+",even="+parse.even+",inverse="+parse.inverse); + int inc = 1; + if (parse.inverse) { + if (parse.low > parse.high) { + int t = parse.low; + parse.low = parse.high; + parse.high = t; + } + for (ListIterator it = new ListIterator(list); it.HasNext();) { + int n = (int)it.Next(); + if (parse.even && (n & 1) == 1) + continue; + if (parse.odd && (n & 1) == 0) + continue; + if (n >= parse.low && n <= parse.high) + it.Remove(); + } + } + else { + if (parse.low > parse.high) { + inc = -1; + if (parse.odd || parse.even) { + --inc; + if (parse.even) + parse.low &= ~1; + else + parse.low -= ((parse.low & 1) == 1 ? 0 : 1); + } + for (int k = parse.low; k >= parse.high; k += inc) { + list.Add(k); + } + } + else { + if (parse.odd || parse.even) { + ++inc; + if (parse.odd) + parse.low |= 1; + else + parse.low += ((parse.low & 1) == 1 ? 1 : 0); + } + for (int k = parse.low; k <= parse.high; k += inc) + list.Add(k); + } + } + } + return list; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/ShadingColor.cs b/iTechSharp/iTextSharp/text/pdf/ShadingColor.cs new file mode 100644 index 0000000..3a4d7c3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ShadingColor.cs @@ -0,0 +1,78 @@ +using System; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Implements a shading pattern as a Color. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class ShadingColor : ExtendedColor { + + PdfShadingPattern shadingPattern; + + public ShadingColor(PdfShadingPattern shadingPattern) : base(TYPE_SHADING, .5f, .5f, .5f) { + this.shadingPattern = shadingPattern; + } + + public PdfShadingPattern PdfShadingPattern { + get { + return shadingPattern; + } + } + + public override bool Equals(Object obj) { + return this == obj; + } + + public override int GetHashCode() { + return shadingPattern.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs b/iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs new file mode 100644 index 0000000..c7c5a50 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs @@ -0,0 +1,799 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.xml.simpleparser; + +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Bookmark processing in a simple way. It has some limitations, mainly the only + * action types supported are GoTo, GoToR, URI and Launch. + *

+ * The list structure is composed by a number of Hashtable, keyed by strings, one Hashtable + * for each bookmark. + * The element values are all strings with the exception of the key "Kids" that has + * another list for the child bookmarks. + *

+ * All the bookmarks have a "Title" with the + * bookmark title and optionally a "Style" that can be "bold", "italic" or a + * combination of both. They can also have a "Color" key with a value of three + * floats separated by spaces. The key "Open" can have the values "true" or "false" and + * signals the open status of the children. It's "true" by default. + *

+ * The actions and the parameters can be: + *

    + *
  • "Action" = "GoTo" - "Page" | "Named" + *
      + *
    • "Page" = "3 XYZ 70 400 null" - page number followed by a destination (/XYZ is also accepted) + *
    • "Named" = "named_destination" + *
    + *
  • "Action" = "GoToR" - "Page" | "Named" | "NamedN", "File", ["NewWindow"] + *
      + *
    • "Page" = "3 XYZ 70 400 null" - page number followed by a destination (/XYZ is also accepted) + *
    • "Named" = "named_destination_as_a_string" + *
    • "NamedN" = "named_destination_as_a_name" + *
    • "File" - "the_file_to_open" + *
    • "NewWindow" - "true" or "false" + *
    + *
  • "Action" = "URI" - "URI" + *
      + *
    • "URI" = "http://sf.net" - URI to jump to + *
    + *
  • "Action" = "Launch" - "File" + *
      + *
    • "File" - "the_file_to_open_or_execute" + *
    + * @author Paulo Soares (psoares@consiste.pt) + */ + public sealed class SimpleBookmark : ISimpleXMLDocHandler { + + private ArrayList topList; + private Stack attr = new Stack(); + + /** Creates a new instance of SimpleBookmark */ + private SimpleBookmark() { + } + + private static ArrayList BookmarkDepth(PdfReader reader, PdfDictionary outline, IntHashtable pages) { + ArrayList list = new ArrayList(); + while (outline != null) { + Hashtable map = new Hashtable(); + PdfString title = (PdfString)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.TITLE)); + map["Title"] = title.ToUnicodeString(); + PdfArray color = (PdfArray)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.C)); + if (color != null && color.ArrayList.Count == 3) { + ByteBuffer outp = new ByteBuffer(); + ArrayList arr = color.ArrayList; + outp.Append(((PdfNumber)arr[0]).FloatValue).Append(' '); + outp.Append(((PdfNumber)arr[1]).FloatValue).Append(' '); + outp.Append(((PdfNumber)arr[2]).FloatValue); + map["Color"] = PdfEncodings.ConvertToString(outp.ToByteArray(), null); + } + PdfNumber style = (PdfNumber)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.F)); + if (style != null) { + int f = style.IntValue; + String s = ""; + if ((f & 1) != 0) + s += "italic "; + if ((f & 2) != 0) + s += "bold "; + s = s.Trim(); + if (s.Length != 0) + map["Style"] = s; + } + PdfNumber count = (PdfNumber)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.COUNT)); + if (count != null && count.IntValue < 0) + map["Open"] = "false"; + try { + PdfObject dest = PdfReader.GetPdfObjectRelease(outline.Get(PdfName.DEST)); + if (dest != null) { + MapGotoBookmark(map, dest, pages); //changed by ujihara 2004-06-13 + } + else { + PdfDictionary action = (PdfDictionary)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.A)); + if (action != null) { + if (PdfName.GOTO.Equals(PdfReader.GetPdfObjectRelease(action.Get(PdfName.S)))) { + dest = PdfReader.GetPdfObjectRelease(action.Get(PdfName.D)); + if (dest != null) { + MapGotoBookmark(map, dest, pages); + } + } + else if (PdfName.URI.Equals(PdfReader.GetPdfObjectRelease(action.Get(PdfName.S)))) { + map["Action"] = "URI"; + map["URI"] = ((PdfString)PdfReader.GetPdfObjectRelease(action.Get(PdfName.URI))).ToUnicodeString(); + } + else if (PdfName.GOTOR.Equals(PdfReader.GetPdfObjectRelease(action.Get(PdfName.S)))) { + dest = PdfReader.GetPdfObjectRelease(action.Get(PdfName.D)); + if (dest != null) { + if (dest.IsString()) + map["Named"] = dest.ToString(); + else if (dest.IsName()) + map["NamedN"] = PdfName.DecodeName(dest.ToString()); + else if (dest.IsArray()) { + ArrayList arr = ((PdfArray)dest).ArrayList; + StringBuilder s = new StringBuilder(); + s.Append(arr[0].ToString()); + s.Append(' ').Append(arr[1].ToString()); + for (int k = 2; k < arr.Count; ++k) + s.Append(' ').Append(arr[k].ToString()); + map["Page"] = s.ToString(); + } + } + map["Action"] = "GoToR"; + PdfObject file = PdfReader.GetPdfObjectRelease(action.Get(PdfName.F)); + if (file != null) { + if (file.IsString()) + map["File"] = ((PdfString)file).ToUnicodeString(); + else if (file.IsDictionary()) { + file = PdfReader.GetPdfObject(((PdfDictionary)file).Get(PdfName.F)); + if (file.IsString()) + map["File"] = ((PdfString)file).ToUnicodeString(); + } + } + PdfObject newWindow = PdfReader.GetPdfObjectRelease(action.Get(PdfName.NEWWINDOW)); + if (newWindow != null) + map["NewWindow"] = newWindow.ToString(); + } + else if (PdfName.LAUNCH.Equals(PdfReader.GetPdfObjectRelease(action.Get(PdfName.S)))) { + map["Action"] = "Launch"; + PdfObject file = PdfReader.GetPdfObjectRelease(action.Get(PdfName.F)); + if (file == null) + file = PdfReader.GetPdfObjectRelease(action.Get(PdfName.WIN)); + if (file != null) { + if (file.IsString()) + map["File"] = ((PdfString)file).ToUnicodeString(); + else if (file.IsDictionary()) { + file = PdfReader.GetPdfObjectRelease(((PdfDictionary)file).Get(PdfName.F)); + if (file.IsString()) + map["File"] = ((PdfString)file).ToUnicodeString(); + } + } + } + } + } + } + catch { + //empty on purpose + } + PdfDictionary first = (PdfDictionary)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.FIRST)); + if (first != null) { + map["Kids"] = BookmarkDepth(reader, first, pages); + } + list.Add(map); + outline = (PdfDictionary)PdfReader.GetPdfObjectRelease(outline.Get(PdfName.NEXT)); + } + return list; + } + + private static void MapGotoBookmark(Hashtable map, PdfObject dest, IntHashtable pages) + { + if (dest.IsString()) + map["Named"] = dest.ToString(); + else if (dest.IsName()) + map["Named"] = PdfName.DecodeName(dest.ToString()); + else if (dest.IsArray()) + map["Page"] = MakeBookmarkParam((PdfArray)dest, pages); //changed by ujihara 2004-06-13 + map["Action"] = "GoTo"; + } + + private static String MakeBookmarkParam(PdfArray dest, IntHashtable pages) + { + ArrayList arr = dest.ArrayList; + StringBuilder s = new StringBuilder(); + s.Append(pages[GetNumber((PdfIndirectReference)arr[0])]); //changed by ujihara 2004-06-13 + s.Append(' ').Append(arr[1].ToString().Substring(1)); + for (int k = 2; k < arr.Count; ++k) + s.Append(' ').Append(arr[k].ToString()); + return s.ToString(); + } + + /** + * Gets number of indirect. If type of directed indirect is PAGES, it refers PAGE object through KIDS. + * (Contributed by Kazuya Ujihara) + * @param indirect + * 2004-06-13 + */ + private static int GetNumber(PdfIndirectReference indirect) + { + PdfDictionary pdfObj = (PdfDictionary)PdfReader.GetPdfObjectRelease(indirect); + if (pdfObj.Contains(PdfName.TYPE) && pdfObj.Get(PdfName.TYPE).Equals(PdfName.PAGES) && pdfObj.Contains(PdfName.KIDS)) + { + PdfArray kids = (PdfArray)pdfObj.Get(PdfName.KIDS); + indirect = (PdfIndirectReference)kids.ArrayList[0]; + } + return indirect.Number; + } + + /** + * Gets a List with the bookmarks. It returns null if + * the document doesn't have any bookmarks. + * @param reader the document + * @return a List with the bookmarks or null if the + * document doesn't have any + */ + public static ArrayList GetBookmark(PdfReader reader) { + PdfDictionary catalog = reader.Catalog; + PdfObject obj = PdfReader.GetPdfObjectRelease(catalog.Get(PdfName.OUTLINES)); + if (obj == null || !obj.IsDictionary()) + return null; + PdfDictionary outlines = (PdfDictionary)obj; + IntHashtable pages = new IntHashtable(); + int numPages = reader.NumberOfPages; + for (int k = 1; k <= numPages; ++k) { + pages[reader.GetPageOrigRef(k).Number] = k; + reader.ReleasePage(k); + } + return BookmarkDepth(reader, (PdfDictionary)PdfReader.GetPdfObjectRelease(outlines.Get(PdfName.FIRST)), pages); + } + + /** + * Removes the bookmark entries for a number of page ranges. The page ranges + * consists of a number of pairs with the start/end page range. The page numbers + * are inclusive. + * @param list the bookmarks + * @param pageRange the page ranges, always in pairs. + */ + public static void EliminatePages(ArrayList list, int[] pageRange) { + if (list == null) + return; + + for (ListIterator it = new ListIterator(list); it.HasNext();) { + Hashtable map = (Hashtable)it.Next(); + bool hit = false; + if ("GoTo".Equals(map["Action"])) { + String page = (String)map["Page"]; + if (page != null) { + page = page.Trim(); + int idx = page.IndexOf(' '); + int pageNum; + if (idx < 0) + pageNum = int.Parse(page); + else + pageNum = int.Parse(page.Substring(0, idx)); + int len = pageRange.Length & 0x7ffffffe; + for (int k = 0; k < len; k += 2) { + if (pageNum >= pageRange[k] && pageNum <= pageRange[k + 1]) { + hit = true; + break; + } + } + } + } + ArrayList kids = (ArrayList)map["Kids"]; + if (kids != null) { + EliminatePages(kids, pageRange); + if (kids.Count == 0) { + map.Remove("Kids"); + kids = null; + } + } + if (hit) { + if (kids == null) + it.Remove(); + else { + map.Remove("Action"); + map.Remove("Page"); + map.Remove("Named"); + } + } + } + } + + /** + * For the pages in range add the pageShift to the page number. + * The page ranges + * consists of a number of pairs with the start/end page range. The page numbers + * are inclusive. + * @param list the bookmarks + * @param pageShift the number to add to the pages in range + * @param pageRange the page ranges, always in pairs. It can be null + * to include all the pages + */ + public static void ShiftPageNumbers(ArrayList list, int pageShift, int[] pageRange) { + if (list == null) + return; + foreach (Hashtable map in list) { + if ("GoTo".Equals(map["Action"])) { + String page = (String)map["Page"]; + if (page != null) { + page = page.Trim(); + int idx = page.IndexOf(' '); + int pageNum; + if (idx < 0) + pageNum = int.Parse(page); + else + pageNum = int.Parse(page.Substring(0, idx)); + bool hit = false; + if (pageRange == null) + hit = true; + else { + int len = pageRange.Length & 0x7ffffffe; + for (int k = 0; k < len; k += 2) { + if (pageNum >= pageRange[k] && pageNum <= pageRange[k + 1]) { + hit = true; + break; + } + } + } + if (hit) { + if (idx < 0) + page = (pageNum + pageShift) + ""; + else + page = (pageNum + pageShift) + page.Substring(idx); + } + map["Page"] = page; + } + } + ArrayList kids = (ArrayList)map["Kids"]; + if (kids != null) + ShiftPageNumbers(kids, pageShift, pageRange); + } + } + + internal static void CreateOutlineAction(PdfDictionary outline, Hashtable map, PdfWriter writer, bool namedAsNames) { + try { + String action = (String)map["Action"]; + if ("GoTo".Equals(action)) { + String p; + if ((p = (String)map["Named"]) != null) { + if (namedAsNames) + outline.Put(PdfName.DEST, new PdfName(p)); + else + outline.Put(PdfName.DEST, new PdfString(p, null)); + } + else if ((p = (String)map["Page"]) != null) { + PdfArray ar = new PdfArray(); + StringTokenizer tk = new StringTokenizer(p); + int n = int.Parse(tk.NextToken()); + ar.Add(writer.GetPageReference(n)); + if (!tk.HasMoreTokens()) { + ar.Add(PdfName.XYZ); + ar.Add(new float[]{0, 10000, 0}); + } + else { + String fn = tk.NextToken(); + if (fn.StartsWith("/")) + fn = fn.Substring(1); + ar.Add(new PdfName(fn)); + for (int k = 0; k < 4 && tk.HasMoreTokens(); ++k) { + fn = tk.NextToken(); + if (fn.Equals("null")) + ar.Add(PdfNull.PDFNULL); + else + ar.Add(new PdfNumber(fn)); + } + } + outline.Put(PdfName.DEST, ar); + } + } + else if ("GoToR".Equals(action)) { + String p; + PdfDictionary dic = new PdfDictionary(); + if ((p = (String)map["Named"]) != null) + dic.Put(PdfName.D, new PdfString(p, null)); + else if ((p = (String)map["NamedN"]) != null) + dic.Put(PdfName.D, new PdfName(p)); + else if ((p = (String)map["Page"]) != null){ + PdfArray ar = new PdfArray(); + StringTokenizer tk = new StringTokenizer(p); + ar.Add(new PdfNumber(tk.NextToken())); + if (!tk.HasMoreTokens()) { + ar.Add(PdfName.XYZ); + ar.Add(new float[]{0, 10000, 0}); + } + else { + String fn = tk.NextToken(); + if (fn.StartsWith("/")) + fn = fn.Substring(1); + ar.Add(new PdfName(fn)); + for (int k = 0; k < 4 && tk.HasMoreTokens(); ++k) { + fn = tk.NextToken(); + if (fn.Equals("null")) + ar.Add(PdfNull.PDFNULL); + else + ar.Add(new PdfNumber(fn)); + } + } + dic.Put(PdfName.D, ar); + } + String file = (String)map["File"]; + if (dic.Size > 0 && file != null) { + dic.Put(PdfName.S, PdfName.GOTOR); + dic.Put(PdfName.F, new PdfString(file)); + String nw = (String)map["NewWindow"]; + if (nw != null) { + if (nw.Equals("true")) + dic.Put(PdfName.NEWWINDOW, PdfBoolean.PDFTRUE); + else if (nw.Equals("false")) + dic.Put(PdfName.NEWWINDOW, PdfBoolean.PDFFALSE); + } + outline.Put(PdfName.A, dic); + } + } + else if ("URI".Equals(action)) { + String uri = (String)map["URI"]; + if (uri != null) { + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.S, PdfName.URI); + dic.Put(PdfName.URI, new PdfString(uri)); + outline.Put(PdfName.A, dic); + } + } + else if ("Launch".Equals(action)) { + String file = (String)map["File"]; + if (file != null) { + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.S, PdfName.LAUNCH); + dic.Put(PdfName.F, new PdfString(file)); + outline.Put(PdfName.A, dic); + } + } + } + catch { + // empty on purpose + } + } + + public static Object[] IterateOutlines(PdfWriter writer, PdfIndirectReference parent, ArrayList kids, bool namedAsNames) { + PdfIndirectReference[] refs = new PdfIndirectReference[kids.Count]; + for (int k = 0; k < refs.Length; ++k) + refs[k] = writer.PdfIndirectReference; + int ptr = 0; + int count = 0; + foreach (Hashtable map in kids) { + Object[] lower = null; + ArrayList subKid = (ArrayList)map["Kids"]; + if (subKid != null && subKid.Count > 0) + lower = IterateOutlines(writer, refs[ptr], subKid, namedAsNames); + PdfDictionary outline = new PdfDictionary(); + ++count; + if (lower != null) { + outline.Put(PdfName.FIRST, (PdfIndirectReference)lower[0]); + outline.Put(PdfName.LAST, (PdfIndirectReference)lower[1]); + int n = (int)lower[2]; + if ("false".Equals(map["Open"])) { + outline.Put(PdfName.COUNT, new PdfNumber(-n)); + } + else { + outline.Put(PdfName.COUNT, new PdfNumber(n)); + count += n; + } + } + outline.Put(PdfName.PARENT, parent); + if (ptr > 0) + outline.Put(PdfName.PREV, refs[ptr - 1]); + if (ptr < refs.Length - 1) + outline.Put(PdfName.NEXT, refs[ptr + 1]); + outline.Put(PdfName.TITLE, new PdfString((String)map["Title"], PdfObject.TEXT_UNICODE)); + String color = (String)map["Color"]; + if (color != null) { + try { + PdfArray arr = new PdfArray(); + StringTokenizer tk = new StringTokenizer(color); + for (int k = 0; k < 3; ++k) { + float f = float.Parse(tk.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + if (f < 0) f = 0; + if (f > 1) f = 1; + arr.Add(new PdfNumber(f)); + } + outline.Put(PdfName.C, arr); + } catch {} //in case it's malformed + } + String style = (String)map["Style"]; + if (style != null) { + style = style.ToLower(System.Globalization.CultureInfo.InvariantCulture); + int bits = 0; + if (style.IndexOf("italic") >= 0) + bits |= 1; + if (style.IndexOf("bold") >= 0) + bits |= 2; + if (bits != 0) + outline.Put(PdfName.F, new PdfNumber(bits)); + } + CreateOutlineAction(outline, map, writer, namedAsNames); + writer.AddToBody(outline, refs[ptr]); + ++ptr; + } + return new Object[]{refs[0], refs[refs.Length - 1], count}; + } + + /** + * Exports the bookmarks to XML. Only of use if the generation is to be include in + * some other XML document. + * @param list the bookmarks + * @param out the export destination. The writer is not closed + * @param indent the indentation level. Pretty printing significant only + * @param onlyASCII codes above 127 will always be escaped with &#nn; if true, + * whatever the encoding + * @throws IOException on error + */ + public static void ExportToXMLNode(ArrayList list, TextWriter outp, int indent, bool onlyASCII) { + String dep = ""; + for (int k = 0; k < indent; ++k) + dep += " "; + foreach (Hashtable map in list) { + String title = null; + outp.Write(dep); + outp.Write(""); + if (title == null) + title = ""; + outp.Write(SimpleXMLParser.EscapeXML(title, onlyASCII)); + if (kids != null) { + outp.Write("\n"); + ExportToXMLNode(kids, outp, indent + 1, onlyASCII); + outp.Write(dep); + } + outp.Write("\n"); + } + } + + /** + * Exports the bookmarks to XML. The DTD for this XML is: + *

    + *

    +        * <?xml version='1.0' encoding='UTF-8'?>
    +        * <!ELEMENT Title (#PCDATA|Title)*>
    +        * <!ATTLIST Title
    +        *    Action CDATA #IMPLIED
    +        *    Open CDATA #IMPLIED
    +        *    Page CDATA #IMPLIED
    +        *    URI CDATA #IMPLIED
    +        *    File CDATA #IMPLIED
    +        *    Named CDATA #IMPLIED
    +        *    NamedN CDATA #IMPLIED
    +        *    NewWindow CDATA #IMPLIED
    +        *    Style CDATA #IMPLIED
    +        *    Color CDATA #IMPLIED
    +        * >
    +        * <!ELEMENT Bookmark (Title)*>
    +        * 
    + * @param list the bookmarks + * @param out the export destination. The stream is not closed + * @param encoding the encoding according to IANA conventions + * @param onlyASCII codes above 127 will always be escaped with &#nn; if true, + * whatever the encoding + * @throws IOException on error + */ + public static void ExportToXML(ArrayList list, Stream outp, String encoding, bool onlyASCII) { + StreamWriter wrt = new StreamWriter(outp, IanaEncodings.GetEncodingEncoding(encoding)); + ExportToXML(list, wrt, encoding, onlyASCII); + } + + /** + * Exports the bookmarks to XML. + * @param list the bookmarks + * @param wrt the export destination. The writer is not closed + * @param encoding the encoding according to IANA conventions + * @param onlyASCII codes above 127 will always be escaped with &#nn; if true, + * whatever the encoding + * @throws IOException on error + */ + public static void ExportToXML(ArrayList list, TextWriter wrt, String encoding, bool onlyASCII) { + wrt.Write("\n\n"); + ExportToXMLNode(list, wrt, 1, onlyASCII); + wrt.Write("\n"); + wrt.Flush(); + } + + /** + * Import the bookmarks from XML. + * @param in the XML source. The stream is not closed + * @throws IOException on error + * @return the bookmarks + */ + public static ArrayList ImportFromXML(Stream inp) { + SimpleBookmark book = new SimpleBookmark(); + SimpleXMLParser.Parse(book, inp); + return book.topList; + } + + /** + * Import the bookmarks from XML. + * @param in the XML source. The reader is not closed + * @throws IOException on error + * @return the bookmarks + */ + public static ArrayList ImportFromXML(TextReader inp) { + SimpleBookmark book = new SimpleBookmark(); + SimpleXMLParser.Parse(book, inp); + return book.topList; + } + + public static String EscapeBinaryString(String s) { + StringBuilder buf = new StringBuilder(); + char[] cc = s.ToCharArray(); + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c < ' ') { + buf.Append('\\'); + int v = (int)c; + string octal = ""; + do { + int x = v % 8; + octal = x.ToString() + octal; + v /= 8; + } while (v > 0); + buf.Append(octal.PadLeft(3, '0')); + } + else if (c == '\\') + buf.Append("\\\\"); + else + buf.Append(c); + } + return buf.ToString(); + } + + public static String UnEscapeBinaryString(String s) { + StringBuilder buf = new StringBuilder(); + char[] cc = s.ToCharArray(); + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c == '\\') { + if (++k >= len) { + buf.Append('\\'); + break; + } + c = cc[k]; + if (c >= '0' && c <= '7') { + int n = c - '0'; + ++k; + for (int j = 0; j < 2 && k < len; ++j) { + c = cc[k]; + if (c >= '0' && c <= '7') { + ++k; + n = n * 8 + c - '0'; + } + else { + break; + } + } + --k; + buf.Append((char)n); + } + else + buf.Append(c); + } + else + buf.Append(c); + } + return buf.ToString(); + } + + public void EndDocument() { + } + + public void EndElement(String tag) { + if (tag.Equals("Bookmark")) { + if (attr.Count == 0) + return; + else + throw new Exception("Bookmark end tag out of place."); + } + if (!tag.Equals("Title")) + throw new Exception("Invalid end tag - " + tag); + Hashtable attributes = (Hashtable)attr.Pop(); + String title = (String)attributes["Title"]; + attributes["Title"] = title.Trim(); + String named = (String)attributes["Named"]; + if (named != null) + attributes["Named"] = UnEscapeBinaryString(named); + named = (String)attributes["NamedN"]; + if (named != null) + attributes["NamedN"] = UnEscapeBinaryString(named); + if (attr.Count == 0) + topList.Add(attributes); + else { + Hashtable parent = (Hashtable)attr.Peek(); + ArrayList kids = (ArrayList)parent["Kids"]; + if (kids == null) { + kids = new ArrayList(); + parent["Kids"] = kids; + } + kids.Add(attributes); + } + } + + public void StartDocument() { + } + + public void StartElement(String tag, Hashtable h) { + if (topList == null) { + if (tag.Equals("Bookmark")) { + topList = new ArrayList(); + return; + } + else + throw new Exception("Root element is not Bookmark: " + tag); + } + if (!tag.Equals("Title")) + throw new Exception("Tag " + tag + " not allowed."); + Hashtable attributes = new Hashtable(h); + attributes["Title"] = ""; + attributes.Remove("Kids"); + attr.Push(attributes); + } + + public void Text(String str) { + if (attr.Count == 0) + return; + Hashtable attributes = (Hashtable)attr.Peek(); + String title = (String)attributes["Title"]; + title += str; + attributes["Title"] = title; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/SimpleNamedDestination.cs b/iTechSharp/iTextSharp/text/pdf/SimpleNamedDestination.cs new file mode 100644 index 0000000..5d35867 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/SimpleNamedDestination.cs @@ -0,0 +1,325 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.xml.simpleparser; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public sealed class SimpleNamedDestination : ISimpleXMLDocHandler { + + private Hashtable xmlNames; + private Hashtable xmlLast; + + private SimpleNamedDestination() { + } + + public static Hashtable GetNamedDestination(PdfReader reader, bool fromNames) { + IntHashtable pages = new IntHashtable(); + int numPages = reader.NumberOfPages; + for (int k = 1; k <= numPages; ++k) + pages[reader.GetPageOrigRef(k).Number] = k; + Hashtable names = fromNames ? reader.GetNamedDestinationFromNames() : reader.GetNamedDestinationFromStrings(); + String[] keys = new String[names.Count]; + names.Keys.CopyTo(keys, 0); + foreach (String name in keys) { + ArrayList arr = ((PdfArray)names[name]).ArrayList; + StringBuilder s = new StringBuilder(); + try { + s.Append(pages[((PdfIndirectReference)arr[0]).Number]); + s.Append(' ').Append(arr[1].ToString().Substring(1)); + for (int k = 2; k < arr.Count; ++k) + s.Append(' ').Append(arr[k].ToString()); + names[name] = s.ToString(); + } + catch { + names.Remove(name); + } + } + return names; + } + + /** + * Exports the destinations to XML. The DTD for this XML is: + *

    + *

    +        * <?xml version='1.0' encoding='UTF-8'?>
    +        * <!ELEMENT Name (#PCDATA)>
    +        * <!ATTLIST Name
    +        *    Page CDATA #IMPLIED
    +        * >
    +        * <!ELEMENT Destination (Name)*>
    +        * 
    + * @param names the names + * @param outp the export destination. The stream is not closed + * @param encoding the encoding according to IANA conventions + * @param onlyASCII codes above 127 will always be escaped with &#nn; if true, + * whatever the encoding + * @throws IOException on error + */ + public static void ExportToXML(Hashtable names, Stream outp, String encoding, bool onlyASCII) { + StreamWriter wrt = new StreamWriter(outp, IanaEncodings.GetEncodingEncoding(encoding)); + ExportToXML(names, wrt, encoding, onlyASCII); + } + + /** + * Exports the bookmarks to XML. + * @param names the names + * @param wrt the export destination. The writer is not closed + * @param encoding the encoding according to IANA conventions + * @param onlyASCII codes above 127 will always be escaped with &#nn; if true, + * whatever the encoding + * @throws IOException on error + */ + public static void ExportToXML(Hashtable names, TextWriter wrt, String encoding, bool onlyASCII) { + wrt.Write("\n\n"); + foreach (String key in names.Keys) { + String value = (String)names[key]; + wrt.Write(" "); + wrt.Write(SimpleXMLParser.EscapeXML(EscapeBinaryString(key), onlyASCII)); + wrt.Write("\n"); + } + wrt.Write("\n"); + wrt.Flush(); + } + + /** + * Import the names from XML. + * @param inp the XML source. The stream is not closed + * @throws IOException on error + * @return the names + */ + public static Hashtable ImportFromXML(Stream inp) { + SimpleNamedDestination names = new SimpleNamedDestination(); + SimpleXMLParser.Parse(names, inp); + return names.xmlNames; + } + + /** + * Import the names from XML. + * @param inp the XML source. The reader is not closed + * @throws IOException on error + * @return the names + */ + public static Hashtable ImportFromXML(TextReader inp) { + SimpleNamedDestination names = new SimpleNamedDestination(); + SimpleXMLParser.Parse(names, inp); + return names.xmlNames; + } + + internal static PdfArray CreateDestinationArray(String value, PdfWriter writer) { + PdfArray ar = new PdfArray(); + StringTokenizer tk = new StringTokenizer(value); + int n = int.Parse(tk.NextToken()); + ar.Add(writer.GetPageReference(n)); + if (!tk.HasMoreTokens()) { + ar.Add(PdfName.XYZ); + ar.Add(new float[]{0, 10000, 0}); + } + else { + String fn = tk.NextToken(); + if (fn.StartsWith("/")) + fn = fn.Substring(1); + ar.Add(new PdfName(fn)); + for (int k = 0; k < 4 && tk.HasMoreTokens(); ++k) { + fn = tk.NextToken(); + if (fn.Equals("null")) + ar.Add(PdfNull.PDFNULL); + else + ar.Add(new PdfNumber(fn)); + } + } + return ar; + } + + public static PdfDictionary OutputNamedDestinationAsNames(Hashtable names, PdfWriter writer) { + PdfDictionary dic = new PdfDictionary(); + foreach (String key in names.Keys) { + try { + String value = (String)names[key]; + PdfArray ar = CreateDestinationArray(value, writer); + PdfName kn = new PdfName(key); + dic.Put(kn, ar); + } + catch { + // empty on purpose + } + } + return dic; + } + + public static PdfDictionary OutputNamedDestinationAsStrings(Hashtable names, PdfWriter writer) { + Hashtable n2 = new Hashtable(); + foreach (String key in names.Keys) { + try { + String value = (String)names[key]; + PdfArray ar = CreateDestinationArray(value, writer); + n2[key] = writer.AddToBody(ar).IndirectReference; + } + catch { + // empty on purpose + } + } + return PdfNameTree.WriteTree(n2, writer); + } + + public static String EscapeBinaryString(String s) { + StringBuilder buf = new StringBuilder(); + char[] cc = s.ToCharArray(); + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c < ' ') { + buf.Append('\\'); + ((int)c).ToString("", System.Globalization.CultureInfo.InvariantCulture); + String octal = "00" + Convert.ToString((int)c, 8); + buf.Append(octal.Substring(octal.Length - 3)); + } + else if (c == '\\') + buf.Append("\\\\"); + else + buf.Append(c); + } + return buf.ToString(); + } + + public static String UnEscapeBinaryString(String s) { + StringBuilder buf = new StringBuilder(); + char[] cc = s.ToCharArray(); + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c == '\\') { + if (++k >= len) { + buf.Append('\\'); + break; + } + c = cc[k]; + if (c >= '0' && c <= '7') { + int n = c - '0'; + ++k; + for (int j = 0; j < 2 && k < len; ++j) { + c = cc[k]; + if (c >= '0' && c <= '7') { + ++k; + n = n * 8 + c - '0'; + } + else { + break; + } + } + --k; + buf.Append((char)n); + } + else + buf.Append(c); + } + else + buf.Append(c); + } + return buf.ToString(); + } + + public void EndDocument() { + } + + public void EndElement(String tag) { + if (tag.Equals("Destination")) { + if (xmlLast == null && xmlNames != null) + return; + else + throw new ArgumentException("Destination end tag out of place."); + } + if (!tag.Equals("Name")) + throw new ArgumentException("Invalid end tag - " + tag); + if (xmlLast == null || xmlNames == null) + throw new ArgumentException("Name end tag out of place."); + if (!xmlLast.ContainsKey("Page")) + throw new ArgumentException("Page attribute missing."); + xmlNames[UnEscapeBinaryString((String)xmlLast["Name"])] = xmlLast["Page"]; + xmlLast = null; + } + + public void StartDocument() { + } + + public void StartElement(String tag, Hashtable h) { + if (xmlNames == null) { + if (tag.Equals("Destination")) { + xmlNames = new Hashtable(); + return; + } + else + throw new ArgumentException("Root element is not Destination."); + } + if (!tag.Equals("Name")) + throw new ArgumentException("Tag " + tag + " not allowed."); + if (xmlLast != null) + throw new ArgumentException("Nested tags are not allowed."); + xmlLast = new Hashtable(h); + xmlLast["Name"] = ""; + } + + public void Text(String str) { + if (xmlLast == null) + return; + String name = (String)xmlLast["Name"]; + name += str; + xmlLast["Name"] = name; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/SpotColor.cs b/iTechSharp/iTextSharp/text/pdf/SpotColor.cs new file mode 100644 index 0000000..449d94d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/SpotColor.cs @@ -0,0 +1,95 @@ +using System; + +/* + * $Id: SpotColor.cs,v 1.4 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author psoares + */ + public class SpotColor : ExtendedColor { + + PdfSpotColor spot; + float tint; + + public SpotColor(PdfSpotColor spot, float tint) : + base(TYPE_SEPARATION, + ((float)spot.AlternativeCS.R / 255f - 1f) * tint + 1, + ((float)spot.AlternativeCS.G / 255f - 1f) * tint + 1, + ((float)spot.AlternativeCS.B / 255f - 1f) * tint + 1) { + this.spot = spot; + this.tint = tint; + } + + public SpotColor(PdfSpotColor spot) : this(spot, spot.Tint) {} + + public PdfSpotColor PdfSpotColor { + get { + return spot; + } + } + + public float Tint { + get { + return tint; + } + } + + public override bool Equals(Object obj) { + return this == obj; + } + + public override int GetHashCode() { + return spot.GetHashCode() ^ tint.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/StampContent.cs b/iTechSharp/iTextSharp/text/pdf/StampContent.cs new file mode 100644 index 0000000..b9efcca --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/StampContent.cs @@ -0,0 +1,86 @@ +using System; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class StampContent : PdfContentByte { + internal PdfStamperImp.PageStamp ps; + internal PageResources pageResources; + + /** Creates a new instance of StampContent */ + internal StampContent(PdfStamperImp stamper, PdfStamperImp.PageStamp ps) : base(stamper) { + this.ps = ps; + pageResources = ps.pageResources; + } + + public override void SetAction(PdfAction action, float llx, float lly, float urx, float ury) { + ((PdfStamperImp)writer).AddAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action), ps.pageN); + } + + /** + * Gets a duplicate of this PdfContentByte. All + * the members are copied by reference but the buffer stays different. + * + * @return a copy of this PdfContentByte + */ + public override PdfContentByte Duplicate { + get { + return new StampContent((PdfStamperImp)writer, ps); + } + } + + internal override PageResources PageResources { + get { + return pageResources; + } + } + + internal override void AddAnnotation(PdfAnnotation annot) { + ((PdfStamperImp)writer).AddAnnotation(annot, ps.pageN); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/StandardDecryption.cs b/iTechSharp/iTextSharp/text/pdf/StandardDecryption.cs new file mode 100644 index 0000000..0e4d27b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/StandardDecryption.cs @@ -0,0 +1,111 @@ +using System; +using iTextSharp.text.pdf.crypto; +/* + * $Id: StandardDecryption.cs,v 1.3 2007/04/29 13:57:12 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.crypto { + + public class StandardDecryption { + protected ARCFOUREncryption arcfour; + protected AESCipher cipher; + private byte[] key; + private const int AES_128 = 4; + private bool aes; + private bool initiated; + private byte[] iv = new byte[16]; + private int ivptr; + + /** Creates a new instance of StandardDecryption */ + public StandardDecryption(byte[] key, int off, int len, int revision) { + aes = revision == AES_128; + if (aes) { + this.key = new byte[len]; + System.Array.Copy(key, off, this.key, 0, len); + } + else { + arcfour = new ARCFOUREncryption(); + arcfour.PrepareARCFOURKey(key, off, len); + } + } + + public byte[] Update(byte[] b, int off, int len) { + if (aes) { + if (initiated) + return cipher.Update(b, off, len); + else { + int left = Math.Min(iv.Length - ivptr, len); + System.Array.Copy(b, off, iv, ivptr, left); + off += left; + len -= left; + ivptr += left; + if (ivptr == iv.Length) { + cipher = new AESCipher(false, key, iv); + initiated = true; + if (len > 0) + return cipher.Update(b, off, len); + } + return null; + } + } + else { + byte[] b2 = new byte[len]; + arcfour.EncryptARCFOUR(b, off, len, b2, 0); + return b2; + } + } + + public byte[] Finish() { + if (aes) { + return cipher.DoFinal(); + } + else + return null; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/TextField.cs b/iTechSharp/iTextSharp/text/pdf/TextField.cs new file mode 100644 index 0000000..587ccfe --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/TextField.cs @@ -0,0 +1,641 @@ +using System; +using System.Collections; +using System.Text; +/* + * Copyright 2003-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Supports text, combo and list fields generating the correct appearances. + * All the option in the Acrobat GUI are supported in an easy to use API. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class TextField : BaseField { + + /** Holds value of property defaultText. */ + private String defaultText; + + /** Holds value of property choices. */ + private String[] choices; + + /** Holds value of property choiceExports. */ + private String[] choiceExports; + + /** Holds value of property choiceSelection. */ + private int choiceSelection; + + private int topFirst; + + private float extraMarginLeft; + private float extraMarginTop; + + /** Creates a new TextField. + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public TextField(PdfWriter writer, Rectangle box, String fieldName) : base(writer, box, fieldName) { + } + + private static bool CheckRTL(String text) { + if (text == null || text.Length == 0) + return false; + char[] cc = text.ToCharArray(); + for (int k = 0; k < cc.Length; ++k) { + int c = (int)cc[k]; + if (c >= 0x590 && c < 0x0780) + return true; + } + return false; + } + + private static void ChangeFontSize(Phrase p, float size) { + foreach (Chunk ck in p) { + ck.Font.Size = size; + } + } + + private Phrase ComposePhrase(String text, BaseFont ufont, Color color, float fontSize) { + Phrase phrase = null; + if (extensionFont == null && (substitutionFonts == null || substitutionFonts.Count == 0)) + phrase = new Phrase(new Chunk(text, new Font(ufont, fontSize, 0, color))); + else { + FontSelector fs = new FontSelector(); + fs.AddFont(new Font(ufont, fontSize, 0, color)); + if (extensionFont != null) + fs.AddFont(new Font(extensionFont, fontSize, 0, color)); + if (substitutionFonts != null) { + foreach (BaseFont bf in substitutionFonts) { + fs.AddFont(new Font(bf, fontSize, 0, color)); + } + } + phrase = fs.Process(text); + } + return phrase; + } + + private static String RemoveCRLF(String text) { + if (text.IndexOf('\n') >= 0 || text.IndexOf('\r') >= 0) { + char[] p = text.ToCharArray(); + StringBuilder sb = new StringBuilder(p.Length); + for (int k = 0; k < p.Length; ++k) { + char c = p[k]; + if (c == '\n') + sb.Append(' '); + else if (c == '\r') { + sb.Append(' '); + if (k < p.Length - 1 && p[k + 1] == '\n') + ++k; + } + else + sb.Append(c); + } + return sb.ToString(); + } + return text; + } + + /** + * Gets the appearance for this TextField. + * @return the appearance object for this TextField + * @throws IOException + * @throws DocumentException + */ + public PdfAppearance GetAppearance() { + PdfAppearance app = GetBorderAppearance(); + app.BeginVariableText(); + if (text == null || text.Length == 0) { + app.EndVariableText(); + return app; + } + BaseFont ufont = RealFont; + bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; + float h = box.Height - borderWidth * 2; + float bw2 = borderWidth; + if (borderExtra) { + h -= borderWidth * 2; + bw2 *= 2; + } + h -= extraMarginTop; + float offsetX = (borderExtra ? 2 * borderWidth : borderWidth); + offsetX = Math.Max(offsetX, 1); + float offX = Math.Min(bw2, offsetX); + app.SaveState(); + app.Rectangle(offX, offX, box.Width - 2 * offX, box.Height - 2 * offX); + app.Clip(); + app.NewPath(); + Color fcolor = (textColor == null) ? GrayColor.GRAYBLACK : textColor; + String ptext = text; //fixed by Kazuya Ujihara (ujihara.jp) + if ((options & PASSWORD) != 0) { + ptext = new String('*', ptext.Length); + } + int rtl = CheckRTL(ptext) ? PdfWriter.RUN_DIRECTION_LTR : PdfWriter.RUN_DIRECTION_NO_BIDI; + if ((options & MULTILINE) == 0) { + ptext = RemoveCRLF(text); + } + Phrase phrase = ComposePhrase(ptext, ufont, fcolor, fontSize); + if ((options & MULTILINE) != 0) { + float usize = fontSize; + float width = box.Width - 4 * offsetX - extraMarginLeft; + float factor = ufont.GetFontDescriptor(BaseFont.BBOXURY, 1) - ufont.GetFontDescriptor(BaseFont.BBOXLLY, 1); + ColumnText ct = new ColumnText(null); + if (usize == 0) { + usize = h / factor; + if (usize > 4) { + if (usize > 12) + usize = 12; + float step = Math.Max((usize - 4) / 10, 0.2f); + ct.SetSimpleColumn(0, -h, width, 0); + ct.Alignment = alignment; + ct.RunDirection = rtl; + for (; usize > 4; usize -= step) { + ct.YLine = 0; + ChangeFontSize(phrase, usize); + ct.SetText(phrase); + ct.Leading = factor * usize; + int status = ct.Go(true); + if ((status & ColumnText.NO_MORE_COLUMN) == 0) + break; + } + } + if (usize < 4) { + usize = 4; + } + } + ChangeFontSize(phrase, usize); + ct.Canvas = app; + float leading = usize * factor; + float offsetY = offsetX + h - ufont.GetFontDescriptor(BaseFont.BBOXURY, usize); + ct.SetSimpleColumn(extraMarginLeft + 2 * offsetX, -20000, box.Width - 2 * offsetX, offsetY + leading); + ct.Leading = leading; + ct.Alignment = alignment; + ct.RunDirection = rtl; + ct.SetText(phrase); + ct.Go(); + } + else { + float usize = fontSize; + if (usize == 0) { + float maxCalculatedSize = h / (ufont.GetFontDescriptor(BaseFont.BBOXURX, 1) - ufont.GetFontDescriptor(BaseFont.BBOXLLY, 1)); + ChangeFontSize(phrase, 1); + float wd = ColumnText.GetWidth(phrase, rtl, 0); + if (wd == 0) + usize = maxCalculatedSize; + else + usize = (box.Width - extraMarginLeft - 4 * offsetX) / wd; + if (usize > maxCalculatedSize) + usize = maxCalculatedSize; + if (usize < 4) + usize = 4; + } + ChangeFontSize(phrase, usize); + float offsetY = offX + ((box.Height - 2*offX) - ufont.GetFontDescriptor(BaseFont.ASCENT, usize)) / 2; + if (offsetY < offX) + offsetY = offX; + if (offsetY - offX < -ufont.GetFontDescriptor(BaseFont.DESCENT, usize)) { + float ny = -ufont.GetFontDescriptor(BaseFont.DESCENT, usize) + offX; + float dy = box.Height - offX - ufont.GetFontDescriptor(BaseFont.ASCENT, usize); + offsetY = Math.Min(ny, Math.Max(offsetY, dy)); + } + if ((options & COMB) != 0 && maxCharacterLength > 0) { + int textLen = Math.Min(maxCharacterLength, ptext.Length); + int position = 0; + if (alignment == Element.ALIGN_RIGHT) { + position = maxCharacterLength - textLen; + } + else if (alignment == Element.ALIGN_CENTER) { + position = (maxCharacterLength - textLen) / 2; + } + float step = (box.Width - extraMarginLeft) / maxCharacterLength; + float start = step / 2 + position * step; + if (textColor == null) + app.SetGrayFill(0); + else + app.SetColorFill(textColor); + app.BeginText(); + foreach (Chunk ck in phrase) { + BaseFont bf = ck.Font.BaseFont; + app.SetFontAndSize(bf, usize); + StringBuilder sb = ck.Append(""); + for (int j = 0; j < sb.Length; ++j) { + String c = sb.ToString(j, 1); + float wd = bf.GetWidthPoint(c, usize); + app.SetTextMatrix(extraMarginLeft + start - wd / 2, offsetY - extraMarginTop); + app.ShowText(c); + start += step; + } + } + app.EndText(); + } + else { + if (alignment == Element.ALIGN_RIGHT) { + ColumnText.ShowTextAligned(app, Element.ALIGN_RIGHT, phrase, extraMarginLeft + box.Width - 2 * offsetX, offsetY - extraMarginTop, 0, rtl, 0); + } + else if (alignment == Element.ALIGN_CENTER) { + ColumnText.ShowTextAligned(app, Element.ALIGN_CENTER, phrase, extraMarginLeft + box.Width / 2, offsetY - extraMarginTop, 0, rtl, 0); + } + else + ColumnText.ShowTextAligned(app, Element.ALIGN_LEFT, phrase, extraMarginLeft + 2 * offsetX, offsetY - extraMarginTop, 0, rtl, 0); + } + } + app.RestoreState(); + app.EndVariableText(); + return app; + } + + internal PdfAppearance GetListAppearance() { + PdfAppearance app = GetBorderAppearance(); + app.BeginVariableText(); + if (choices == null || choices.Length == 0) { + app.EndVariableText(); + return app; + } + int topChoice = choiceSelection; + if (topChoice >= choices.Length) { + topChoice = choices.Length - 1; + } + if (topChoice < 0) + topChoice = 0; + BaseFont ufont = RealFont; + float usize = fontSize; + if (usize == 0) + usize = 12; + bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; + float h = box.Height - borderWidth * 2; + if (borderExtra) + h -= borderWidth * 2; + float offsetX = (borderExtra ? 2 * borderWidth : borderWidth); + float leading = ufont.GetFontDescriptor(BaseFont.BBOXURY, usize) - ufont.GetFontDescriptor(BaseFont.BBOXLLY, usize); + int maxFit = (int)(h / leading) + 1; + int first = 0; + int last = 0; + last = topChoice + maxFit / 2 + 1; + first = last - maxFit; + if (first < 0) { + last += first; + first = 0; + } + // first = topChoice; + last = first + maxFit; + if (last > choices.Length) + last = choices.Length; + topFirst = first; + app.SaveState(); + app.Rectangle(offsetX, offsetX, box.Width - 2 * offsetX, box.Height - 2 * offsetX); + app.Clip(); + app.NewPath(); + Color fcolor = (textColor == null) ? GrayColor.GRAYBLACK : textColor; + app.SetColorFill(new Color(10, 36, 106)); + app.Rectangle(offsetX, offsetX + h - (topChoice - first + 1) * leading, box.Width - 2 * offsetX, leading); + app.Fill(); + float xp = offsetX * 2; + float yp = offsetX + h - ufont.GetFontDescriptor(BaseFont.BBOXURY, usize); + for (int idx = first; idx < last; ++idx, yp -= leading) { + String ptext = choices[idx]; + int rtl = CheckRTL(ptext) ? PdfWriter.RUN_DIRECTION_LTR : PdfWriter.RUN_DIRECTION_NO_BIDI; + ptext = RemoveCRLF(ptext); + Phrase phrase = ComposePhrase(ptext, ufont, (idx == topChoice) ? GrayColor.GRAYWHITE : fcolor, usize); + ColumnText.ShowTextAligned(app, Element.ALIGN_LEFT, phrase, xp, yp, 0, rtl, 0); + } + app.RestoreState(); + app.EndVariableText(); + return app; + } + + /** Gets a new text field. + * @throws IOException on error + * @throws DocumentException on error + * @return a new text field + */ + public PdfFormField GetTextField() { + if (maxCharacterLength <= 0) + options &= ~COMB; + if ((options & COMB) != 0) + options &= ~MULTILINE; + PdfFormField field = PdfFormField.CreateTextField(writer, false, false, maxCharacterLength); + field.SetWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); + switch (alignment) { + case Element.ALIGN_CENTER: + field.Quadding = PdfFormField.Q_CENTER; + break; + case Element.ALIGN_RIGHT: + field.Quadding = PdfFormField.Q_RIGHT; + break; + } + if (rotation != 0) + field.MKRotation = rotation; + if (fieldName != null) { + field.FieldName = fieldName; + if ((options & REQUIRED) == 0 && !"".Equals(text)) + field.ValueAsString = text; + if (defaultText != null) + field.DefaultValueAsString = defaultText; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + if ((options & MULTILINE) != 0) + field.SetFieldFlags(PdfFormField.FF_MULTILINE); + if ((options & DO_NOT_SCROLL) != 0) + field.SetFieldFlags(PdfFormField.FF_DONOTSCROLL); + if ((options & PASSWORD) != 0) + field.SetFieldFlags(PdfFormField.FF_PASSWORD); + if ((options & FILE_SELECTION) != 0) + field.SetFieldFlags(PdfFormField.FF_FILESELECT); + if ((options & DO_NOT_SPELL_CHECK) != 0) + field.SetFieldFlags(PdfFormField.FF_DONOTSPELLCHECK); + if ((options & COMB) != 0) + field.SetFieldFlags(PdfFormField.FF_COMB); + } + field.BorderStyle = new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3)); + PdfAppearance tp = GetAppearance(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + PdfAppearance da = (PdfAppearance)tp.Duplicate; + da.SetFontAndSize(RealFont, fontSize); + if (textColor == null) + da.SetGrayFill(0); + else + da.SetColorFill(textColor); + field.DefaultAppearanceString = da; + if (borderColor != null) + field.MKBorderColor = borderColor; + if (backgroundColor != null) + field.MKBackgroundColor = backgroundColor; + switch (visibility) { + case HIDDEN: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN; + break; + case VISIBLE_BUT_DOES_NOT_PRINT: + break; + case HIDDEN_BUT_PRINTABLE: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW; + break; + default: + field.Flags = PdfAnnotation.FLAGS_PRINT; + break; + } + return field; + } + + /** Gets a new combo field. + * @throws IOException on error + * @throws DocumentException on error + * @return a new combo field + */ + public PdfFormField GetComboField() { + return GetChoiceField(false); + } + + /** Gets a new list field. + * @throws IOException on error + * @throws DocumentException on error + * @return a new list field + */ + public PdfFormField GetListField() { + return GetChoiceField(true); + } + + protected PdfFormField GetChoiceField(bool isList) { + options &= (~MULTILINE) & (~COMB); + String[] uchoices = choices; + if (uchoices == null) + uchoices = new String[0]; + int topChoice = choiceSelection; + if (topChoice >= uchoices.Length) + topChoice = uchoices.Length - 1; + if (text == null) text = ""; //fixed by Kazuya Ujihara (ujihara.jp) + if (topChoice >= 0) + text = uchoices[topChoice]; + if (topChoice < 0) + topChoice = 0; + PdfFormField field = null; + String[,] mix = null; + if (choiceExports == null) { + if (isList) + field = PdfFormField.CreateList(writer, uchoices, topChoice); + else + field = PdfFormField.CreateCombo(writer, (options & EDIT) != 0, uchoices, topChoice); + } + else { + mix = new String[uchoices.Length, 2]; + for (int k = 0; k < mix.GetLength(0); ++k) + mix[k, 0] = mix[k, 1] = uchoices[k]; + int top = Math.Min(uchoices.Length, choiceExports.Length); + for (int k = 0; k < top; ++k) { + if (choiceExports[k] != null) + mix[k, 0] = choiceExports[k]; + } + if (isList) + field = PdfFormField.CreateList(writer, mix, topChoice); + else + field = PdfFormField.CreateCombo(writer, (options & EDIT) != 0, mix, topChoice); + } + field.SetWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); + if (rotation != 0) + field.MKRotation = rotation; + if (fieldName != null) { + field.FieldName = fieldName; + if (uchoices.Length > 0) { + if (mix != null) { + field.ValueAsString = mix[topChoice, 0]; + field.DefaultValueAsString = mix[topChoice, 0]; + } + else { + field.ValueAsString = text; + field.DefaultValueAsString = text; + } + } + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + if ((options & DO_NOT_SPELL_CHECK) != 0) + field.SetFieldFlags(PdfFormField.FF_DONOTSPELLCHECK); + } + field.BorderStyle = new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3)); + PdfAppearance tp; + if (isList) { + tp = GetListAppearance(); + if (topFirst > 0) + field.Put(PdfName.TI, new PdfNumber(topFirst)); + } + else + tp = GetAppearance(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + PdfAppearance da = (PdfAppearance)tp.Duplicate; + da.SetFontAndSize(RealFont, fontSize); + if (textColor == null) + da.SetGrayFill(0); + else + da.SetColorFill(textColor); + field.DefaultAppearanceString = da; + if (borderColor != null) + field.MKBorderColor = borderColor; + if (backgroundColor != null) + field.MKBackgroundColor = backgroundColor; + switch (visibility) { + case HIDDEN: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN; + break; + case VISIBLE_BUT_DOES_NOT_PRINT: + break; + case HIDDEN_BUT_PRINTABLE: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW; + break; + default: + field.Flags = PdfAnnotation.FLAGS_PRINT; + break; + } + return field; + } + + /** Sets the default text. It is only meaningful for text fields. + * @param defaultText the default text + */ + public string DefaultText { + get { + return defaultText; + } + set { + defaultText = value; + } + } + + /** Sets the choices to be presented to the user in list/combo + * fields. + * @param choices the choices to be presented to the user + */ + public string[] Choices { + get { + return choices; + } + set { + choices = value; + } + } + + /** Sets the export values in list/combo fields. If this array + * is null then the choice values will also be used + * as the export values. + * @param choiceExports the export values in list/combo fields + */ + public string[] ChoiceExports { + get { + return choiceExports; + } + set { + choiceExports = value; + } + } + + /** Sets the zero based index of the selected item. + * @param choiceSelection the zero based index of the selected item + */ + public int ChoiceSelection { + get { + return choiceSelection; + } + set { + choiceSelection = value; + } + } + + internal int TopFirst { + get { + return topFirst; + } + } + + /** + * Sets extra margins in text fields to better mimic the Acrobat layout. + * @param extraMarginLeft the extra marging left + * @param extraMarginTop the extra margin top + */ + public void SetExtraMargin(float extraMarginLeft, float extraMarginTop) { + this.extraMarginLeft = extraMarginLeft; + this.extraMarginTop = extraMarginTop; + } + + /** + * Holds value of property substitutionFonts. + */ + private ArrayList substitutionFonts; + + /** + * Sets a list of substitution fonts. The list is composed of BaseFont and can also be null. The fonts in this list will be used if the original + * font doesn't contain the needed glyphs. + * @param substitutionFonts the list + */ + public ArrayList SubstitutionFonts { + set { + substitutionFonts = value; + } + get { + return substitutionFonts; + } + } + + /** + * Holds value of property extensionFont. + */ + private BaseFont extensionFont; + + /** + * Sets the extensionFont. This font will be searched before the + * substitution fonts. It may be null. + * @param extensionFont New value of property extensionFont. + */ + public BaseFont ExtensionFont { + set { + extensionFont = value; + } + get { + return extensionFont; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/TrueTypeFont.cs b/iTechSharp/iTextSharp/text/pdf/TrueTypeFont.cs new file mode 100644 index 0000000..23cb888 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/TrueTypeFont.cs @@ -0,0 +1,1517 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: TrueTypeFont.cs,v 1.12 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Reads a Truetype font + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class TrueTypeFont : BaseFont { + + /** The code pages possible for a True Type font. + */ + internal static string[] codePages = { + "1252 Latin 1", + "1250 Latin 2: Eastern Europe", + "1251 Cyrillic", + "1253 Greek", + "1254 Turkish", + "1255 Hebrew", + "1256 Arabic", + "1257 Windows Baltic", + "1258 Vietnamese", + null, + null, + null, + null, + null, + null, + null, + "874 Thai", + "932 JIS/Japan", + "936 Chinese: Simplified chars--PRC and Singapore", + "949 Korean Wansung", + "950 Chinese: Traditional chars--Taiwan and Hong Kong", + "1361 Korean Johab", + null, + null, + null, + null, + null, + null, + null, + "Macintosh Character Set (US Roman)", + "OEM Character Set", + "Symbol Character Set", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "869 IBM Greek", + "866 MS-DOS Russian", + "865 MS-DOS Nordic", + "864 Arabic", + "863 MS-DOS Canadian French", + "862 Hebrew", + "861 MS-DOS Icelandic", + "860 MS-DOS Portuguese", + "857 IBM Turkish", + "855 IBM Cyrillic; primarily Russian", + "852 Latin 2", + "775 MS-DOS Baltic", + "737 Greek; former 437 G", + "708 Arabic; ASMO 708", + "850 WE/Latin 1", + "437 US"}; + + protected bool justNames = false; + /** Contains the location of the several tables. The key is the name of + * the table and the value is an int[2] where position 0 + * is the offset from the start of the file and position 1 is the length + * of the table. + */ + protected Hashtable tables; + /** The file in use. + */ + protected RandomAccessFileOrArray rf; + /** The file name. + */ + protected string fileName; + + protected bool cff = false; + + protected int cffOffset; + + protected int cffLength; + + /** The offset from the start of the file to the table directory. + * It is 0 for TTF and may vary for TTC depending on the chosen font. + */ + protected int directoryOffset; + /** The index for the TTC font. It is an empty string for a + * TTF file. + */ + protected string ttcIndex; + /** The style modifier */ + protected string style = ""; + /** The content of table 'head'. + */ + protected FontHeader head = new FontHeader(); + /** The content of table 'hhea'. + */ + protected HorizontalHeader hhea = new HorizontalHeader(); + /** The content of table 'OS/2'. + */ + protected WindowsMetrics os_2 = new WindowsMetrics(); + /** The width of the glyphs. This is essentially the content of table + * 'hmtx' normalized to 1000 units. + */ + protected int[] GlyphWidths; + + protected int[][] bboxes; + + /** The map containing the code information for the table 'cmap', encoding 1.0. + * The key is the code and the value is an int[2] where position 0 + * is the glyph number and position 1 is the glyph width normalized to 1000 + * units. + */ + protected Hashtable cmap10; + /** The map containing the code information for the table 'cmap', encoding 3.1 + * in Unicode. + *

    + * The key is the code and the value is an int[2] where position 0 + * is the glyph number and position 1 is the glyph width normalized to 1000 + * units. + */ + protected Hashtable cmap31; + + + ///

    + /// By James for unicode Ext.B + /// + protected Hashtable cmapExt; + + + /** The map containing the kerning information. It represents the content of + * table 'kern'. The key is an Integer where the top 16 bits + * are the glyph number for the first character and the lower 16 bits are the + * glyph number for the second character. The value is the amount of kerning in + * normalized 1000 units as an Integer. This value is usually negative. + */ + protected IntHashtable kerning = new IntHashtable(); + /** + * The font name. + * This name is usually extracted from the table 'name' with + * the 'Name ID' 6. + */ + protected string fontName; + + /** The full name of the font + */ + protected string[][] fullName; + + /** All the names auf the Names-Table + */ + protected string[][] allNameEntries; + + /** The family name of the font + */ + protected string[][] familyName; + /** The italic angle. It is usually extracted from the 'post' table or in it's + * absence with the code: + *

    + *

    +         * -Math.Atan2(hhea.caretSlopeRun, hhea.caretSlopeRise) * 180 / Math.PI
    +         * 
    + */ + protected double italicAngle; + /** true if all the glyphs have the same width. + */ + protected bool isFixedPitch = false; + + protected int underlinePosition; + + protected int underlineThickness; + + /** The components of table 'head'. + */ + protected class FontHeader { + /** A variable. */ + internal int flags; + /** A variable. */ + internal int unitsPerEm; + /** A variable. */ + internal short xMin; + /** A variable. */ + internal short yMin; + /** A variable. */ + internal short xMax; + /** A variable. */ + internal short yMax; + /** A variable. */ + internal int macStyle; + } + + /** The components of table 'hhea'. + */ + protected class HorizontalHeader { + /** A variable. */ + internal short Ascender; + /** A variable. */ + internal short Descender; + /** A variable. */ + internal short LineGap; + /** A variable. */ + internal int advanceWidthMax; + /** A variable. */ + internal short minLeftSideBearing; + /** A variable. */ + internal short minRightSideBearing; + /** A variable. */ + internal short xMaxExtent; + /** A variable. */ + internal short caretSlopeRise; + /** A variable. */ + internal short caretSlopeRun; + /** A variable. */ + internal int numberOfHMetrics; + } + + /** The components of table 'OS/2'. + */ + protected class WindowsMetrics { + /** A variable. */ + internal short xAvgCharWidth; + /** A variable. */ + internal int usWeightClass; + /** A variable. */ + internal int usWidthClass; + /** A variable. */ + internal short fsType; + /** A variable. */ + internal short ySubscriptXSize; + /** A variable. */ + internal short ySubscriptYSize; + /** A variable. */ + internal short ySubscriptXOffset; + /** A variable. */ + internal short ySubscriptYOffset; + /** A variable. */ + internal short ySuperscriptXSize; + /** A variable. */ + internal short ySuperscriptYSize; + /** A variable. */ + internal short ySuperscriptXOffset; + /** A variable. */ + internal short ySuperscriptYOffset; + /** A variable. */ + internal short yStrikeoutSize; + /** A variable. */ + internal short yStrikeoutPosition; + /** A variable. */ + internal short sFamilyClass; + /** A variable. */ + internal byte[] panose = new byte[10]; + /** A variable. */ + internal byte[] achVendID = new byte[4]; + /** A variable. */ + internal int fsSelection; + /** A variable. */ + internal int usFirstCharIndex; + /** A variable. */ + internal int usLastCharIndex; + /** A variable. */ + internal short sTypoAscender; + /** A variable. */ + internal short sTypoDescender; + /** A variable. */ + internal short sTypoLineGap; + /** A variable. */ + internal int usWinAscent; + /** A variable. */ + internal int usWinDescent; + /** A variable. */ + internal int ulCodePageRange1; + /** A variable. */ + internal int ulCodePageRange2; + /** A variable. */ + internal int sCapHeight; + } + + /** This constructor is present to allow extending the class. + */ + protected TrueTypeFont() { + } + + internal TrueTypeFont(string ttFile, string enc, bool emb, byte[] ttfAfm) : this(ttFile, enc, emb, ttfAfm, false) {} + + /** Creates a new TrueType font. + * @param ttFile the location of the font on file. The file must end in '.ttf' or + * '.ttc' but can have modifiers after the name + * @param enc the encoding to be applied to this font + * @param emb true if the font is to be embedded in the PDF + * @param ttfAfm the font as a byte array + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + internal TrueTypeFont(string ttFile, string enc, bool emb, byte[] ttfAfm, bool justNames) { + this.justNames = justNames; + string nameBase = GetBaseName(ttFile); + string ttcName = GetTTCName(nameBase); + if (nameBase.Length < ttFile.Length) { + style = ttFile.Substring(nameBase.Length); + } + encoding = enc; + embedded = emb; + fileName = ttcName; + FontType = FONT_TYPE_TT; + ttcIndex = ""; + if (ttcName.Length < nameBase.Length) + ttcIndex = nameBase.Substring(ttcName.Length + 1); + if (fileName.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || fileName.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || fileName.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttc")) { + Process(ttfAfm); + if (!justNames && embedded && os_2.fsType == 2) + throw new DocumentException(fileName + style + " cannot be embedded due to licensing restrictions."); + } + else + throw new DocumentException(fileName + style + " is not a TTF, OTF or TTC font file."); + if (!encoding.StartsWith("#")) + PdfEncodings.ConvertToBytes(" ", enc); // check if the encoding exists + CreateEncoding(); + } + + /** Gets the name from a composed TTC file name. + * If I have for input "myfont.ttc,2" the return will + * be "myfont.ttc". + * @param name the full name + * @return the simple file name + */ + protected static string GetTTCName(string name) { + int idx = name.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,"); + if (idx < 0) + return name; + else + return name.Substring(0, idx + 4); + } + + + /** + * Reads the tables 'head', 'hhea', 'OS/2' and 'post' filling several variables. + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + internal void FillTables() { + int[] table_location; + table_location = (int[])tables["head"]; + if (table_location == null) + throw new DocumentException("Table 'head' does not exist in " + fileName + style); + rf.Seek(table_location[0] + 16); + head.flags = rf.ReadUnsignedShort(); + head.unitsPerEm = rf.ReadUnsignedShort(); + rf.SkipBytes(16); + head.xMin = rf.ReadShort(); + head.yMin = rf.ReadShort(); + head.xMax = rf.ReadShort(); + head.yMax = rf.ReadShort(); + head.macStyle = rf.ReadUnsignedShort(); + + table_location = (int[])tables["hhea"]; + if (table_location == null) + throw new DocumentException("Table 'hhea' does not exist " + fileName + style); + rf.Seek(table_location[0] + 4); + hhea.Ascender = rf.ReadShort(); + hhea.Descender = rf.ReadShort(); + hhea.LineGap = rf.ReadShort(); + hhea.advanceWidthMax = rf.ReadUnsignedShort(); + hhea.minLeftSideBearing = rf.ReadShort(); + hhea.minRightSideBearing = rf.ReadShort(); + hhea.xMaxExtent = rf.ReadShort(); + hhea.caretSlopeRise = rf.ReadShort(); + hhea.caretSlopeRun = rf.ReadShort(); + rf.SkipBytes(12); + hhea.numberOfHMetrics = rf.ReadUnsignedShort(); + + table_location = (int[])tables["OS/2"]; + if (table_location == null) + throw new DocumentException("Table 'OS/2' does not exist in " + fileName + style); + rf.Seek(table_location[0]); + int version = rf.ReadUnsignedShort(); + os_2.xAvgCharWidth = rf.ReadShort(); + os_2.usWeightClass = rf.ReadUnsignedShort(); + os_2.usWidthClass = rf.ReadUnsignedShort(); + os_2.fsType = rf.ReadShort(); + os_2.ySubscriptXSize = rf.ReadShort(); + os_2.ySubscriptYSize = rf.ReadShort(); + os_2.ySubscriptXOffset = rf.ReadShort(); + os_2.ySubscriptYOffset = rf.ReadShort(); + os_2.ySuperscriptXSize = rf.ReadShort(); + os_2.ySuperscriptYSize = rf.ReadShort(); + os_2.ySuperscriptXOffset = rf.ReadShort(); + os_2.ySuperscriptYOffset = rf.ReadShort(); + os_2.yStrikeoutSize = rf.ReadShort(); + os_2.yStrikeoutPosition = rf.ReadShort(); + os_2.sFamilyClass = rf.ReadShort(); + rf.ReadFully(os_2.panose); + rf.SkipBytes(16); + rf.ReadFully(os_2.achVendID); + os_2.fsSelection = rf.ReadUnsignedShort(); + os_2.usFirstCharIndex = rf.ReadUnsignedShort(); + os_2.usLastCharIndex = rf.ReadUnsignedShort(); + os_2.sTypoAscender = rf.ReadShort(); + os_2.sTypoDescender = rf.ReadShort(); + if (os_2.sTypoDescender > 0) + os_2.sTypoDescender = (short)(-os_2.sTypoDescender); + os_2.sTypoLineGap = rf.ReadShort(); + os_2.usWinAscent = rf.ReadUnsignedShort(); + os_2.usWinDescent = rf.ReadUnsignedShort(); + os_2.ulCodePageRange1 = 0; + os_2.ulCodePageRange2 = 0; + if (version > 0) { + os_2.ulCodePageRange1 = rf.ReadInt(); + os_2.ulCodePageRange2 = rf.ReadInt(); + } + if (version > 1) { + rf.SkipBytes(2); + os_2.sCapHeight = rf.ReadShort(); + } + else + os_2.sCapHeight = (int)(0.7 * head.unitsPerEm); + + table_location = (int[])tables["post"]; + if (table_location == null) { + italicAngle = -Math.Atan2(hhea.caretSlopeRun, hhea.caretSlopeRise) * 180 / Math.PI; + return; + } + rf.Seek(table_location[0] + 4); + short mantissa = rf.ReadShort(); + int fraction = rf.ReadUnsignedShort(); + italicAngle = (double)mantissa + (double)fraction / 16384.0; + underlinePosition = rf.ReadShort(); + underlineThickness = rf.ReadShort(); + isFixedPitch = rf.ReadInt() != 0; + } + + /** + * Gets the Postscript font name. + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + * @return the Postscript font name + */ + internal string BaseFont { + get { + int[] table_location; + table_location = (int[])tables["name"]; + if (table_location == null) + throw new DocumentException("Table 'name' does not exist in " + fileName + style); + rf.Seek(table_location[0] + 2); + int numRecords = rf.ReadUnsignedShort(); + int startOfStorage = rf.ReadUnsignedShort(); + for (int k = 0; k < numRecords; ++k) { + int platformID = rf.ReadUnsignedShort(); + int platformEncodingID = rf.ReadUnsignedShort(); + int languageID = rf.ReadUnsignedShort(); + int nameID = rf.ReadUnsignedShort(); + int length = rf.ReadUnsignedShort(); + int offset = rf.ReadUnsignedShort(); + if (nameID == 6) { + rf.Seek(table_location[0] + startOfStorage + offset); + if (platformID == 0 || platformID == 3) + return ReadUnicodeString(length); + else + return ReadStandardString(length); + } + } + FileInfo file = new FileInfo(fileName); + return file.Name.Replace(' ', '-'); + } + } + + /** Extracts the names of the font in all the languages available. + * @param id the name id to retrieve + * @throws DocumentException on error + * @throws IOException on error + */ + internal string[][] GetNames(int id) { + int[] table_location; + table_location = (int[])tables["name"]; + if (table_location == null) + throw new DocumentException("Table 'name' does not exist in " + fileName + style); + rf.Seek(table_location[0] + 2); + int numRecords = rf.ReadUnsignedShort(); + int startOfStorage = rf.ReadUnsignedShort(); + ArrayList names = new ArrayList(); + for (int k = 0; k < numRecords; ++k) { + int platformID = rf.ReadUnsignedShort(); + int platformEncodingID = rf.ReadUnsignedShort(); + int languageID = rf.ReadUnsignedShort(); + int nameID = rf.ReadUnsignedShort(); + int length = rf.ReadUnsignedShort(); + int offset = rf.ReadUnsignedShort(); + if (nameID == id) { + int pos = rf.FilePointer; + rf.Seek(table_location[0] + startOfStorage + offset); + string name; + if (platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1)){ + name = ReadUnicodeString(length); + } + else { + name = ReadStandardString(length); + } + names.Add(new string[]{platformID.ToString(), + platformEncodingID.ToString(), languageID.ToString(), name}); + rf.Seek(pos); + } + } + string[][] thisName = new string[names.Count][]; + for (int k = 0; k < names.Count; ++k) + thisName[k] = (string[])names[k]; + return thisName; + } + + /** Extracts all the names of the names-Table + * @param id the name id to retrieve + * @throws DocumentException on error + * @throws IOException on error + */ + internal string[][] GetAllNames() { + int[] table_location; + table_location = (int[])tables["name"]; + if (table_location == null) + throw new DocumentException("Table 'name' does not exist in " + fileName + style); + rf.Seek(table_location[0] + 2); + int numRecords = rf.ReadUnsignedShort(); + int startOfStorage = rf.ReadUnsignedShort(); + ArrayList names = new ArrayList(); + for (int k = 0; k < numRecords; ++k) { + int platformID = rf.ReadUnsignedShort(); + int platformEncodingID = rf.ReadUnsignedShort(); + int languageID = rf.ReadUnsignedShort(); + int nameID = rf.ReadUnsignedShort(); + int length = rf.ReadUnsignedShort(); + int offset = rf.ReadUnsignedShort(); + int pos = rf.FilePointer; + rf.Seek(table_location[0] + startOfStorage + offset); + String name; + if (platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1)){ + name = ReadUnicodeString(length); + } + else { + name = ReadStandardString(length); + } + names.Add(new String[]{nameID.ToString(), platformID.ToString(), + platformEncodingID.ToString(), languageID.ToString(), name}); + rf.Seek(pos); + } + string[][] thisName = new string[names.Count][]; + for (int k = 0; k < names.Count; ++k) + thisName[k] = (string[])names[k]; + return thisName; + } + + internal void CheckCff() { + int[] table_location; + table_location = (int[])tables["CFF "]; + if (table_location != null) { + cff = true; + cffOffset = table_location[0]; + cffLength = table_location[1]; + } + } + + /** Reads the font data. + * @param ttfAfm the font as a byte array, possibly null + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + internal void Process(byte[] ttfAfm) { + tables = new Hashtable(); + + try { + if (ttfAfm == null) + rf = new RandomAccessFileOrArray(fileName); + else + rf = new RandomAccessFileOrArray(ttfAfm); + if (ttcIndex.Length > 0) { + int dirIdx = int.Parse(ttcIndex); + if (dirIdx < 0) + throw new DocumentException("The font index for " + fileName + " must be positive."); + string mainTag = ReadStandardString(4); + if (!mainTag.Equals("ttcf")) + throw new DocumentException(fileName + " is not a valid TTC file."); + rf.SkipBytes(4); + int dirCount = rf.ReadInt(); + if (dirIdx >= dirCount) + throw new DocumentException("The font index for " + fileName + " must be between 0 and " + (dirCount - 1) + ". It was " + dirIdx + "."); + rf.SkipBytes(dirIdx * 4); + directoryOffset = rf.ReadInt(); + } + rf.Seek(directoryOffset); + int ttId = rf.ReadInt(); + if (ttId != 0x00010000 && ttId != 0x4F54544F) + throw new DocumentException(fileName + " is not a valid TTF or OTF file."); + int num_tables = rf.ReadUnsignedShort(); + rf.SkipBytes(6); + for (int k = 0; k < num_tables; ++k) { + string tag = ReadStandardString(4); + rf.SkipBytes(4); + int[] table_location = new int[2]; + table_location[0] = rf.ReadInt(); + table_location[1] = rf.ReadInt(); + tables[tag] = table_location; + } + CheckCff(); + fontName = BaseFont; + fullName = GetNames(4); //full name + familyName = GetNames(1); //family name + allNameEntries = GetAllNames(); + if (!justNames) { + FillTables(); + ReadGlyphWidths(); + ReadCMaps(); + ReadKerning(); + ReadBbox(); + GlyphWidths = null; + } + } + finally { + if (rf != null) { + rf.Close(); + if (!embedded) + rf = null; + } + } + } + + /** Reads a string from the font file as bytes using the Cp1252 + * encoding. + * @param length the length of bytes to read + * @return the string read + * @throws IOException the font file could not be read + */ + protected string ReadStandardString(int length) { + byte[] buf = new byte[length]; + rf.ReadFully(buf); + return System.Text.Encoding.GetEncoding(1252).GetString(buf); + } + + /** Reads a Unicode string from the font file. Each character is + * represented by two bytes. + * @param length the length of bytes to read. The string will have length/2 + * characters + * @return the string read + * @throws IOException the font file could not be read + */ + protected string ReadUnicodeString(int length) { + StringBuilder buf = new StringBuilder(); + length /= 2; + for (int k = 0; k < length; ++k) { + buf.Append(rf.ReadChar()); + } + return buf.ToString(); + } + + /** Reads the glyphs widths. The widths are extracted from the table 'hmtx'. + * The glyphs are normalized to 1000 units. + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + protected void ReadGlyphWidths() { + int[] table_location; + table_location = (int[])tables["hmtx"]; + if (table_location == null) + throw new DocumentException("Table 'hmtx' does not exist in " + fileName + style); + rf.Seek(table_location[0]); + GlyphWidths = new int[hhea.numberOfHMetrics]; + for (int k = 0; k < hhea.numberOfHMetrics; ++k) { + GlyphWidths[k] = (rf.ReadUnsignedShort() * 1000) / head.unitsPerEm; + rf.ReadUnsignedShort(); + } + } + + /** Gets a glyph width. + * @param glyph the glyph to get the width of + * @return the width of the glyph in normalized 1000 units + */ + protected int GetGlyphWidth(int glyph) { + if (glyph >= GlyphWidths.Length) + glyph = GlyphWidths.Length - 1; + return GlyphWidths[glyph]; + } + + private void ReadBbox() { + int[] tableLocation; + tableLocation = (int[])tables["head"]; + if (tableLocation == null) + throw new DocumentException("Table 'head' does not exist in " + fileName + style); + rf.Seek(tableLocation[0] + TrueTypeFontSubSet.HEAD_LOCA_FORMAT_OFFSET); + bool locaShortTable = (rf.ReadUnsignedShort() == 0); + tableLocation = (int[])tables["loca"]; + if (tableLocation == null) + return; + rf.Seek(tableLocation[0]); + int[] locaTable; + if (locaShortTable) { + int entries = tableLocation[1] / 2; + locaTable = new int[entries]; + for (int k = 0; k < entries; ++k) + locaTable[k] = rf.ReadUnsignedShort() * 2; + } + else { + int entries = tableLocation[1] / 4; + locaTable = new int[entries]; + for (int k = 0; k < entries; ++k) + locaTable[k] = rf.ReadInt(); + } + tableLocation = (int[])tables["glyf"]; + if (tableLocation == null) + throw new DocumentException("Table 'glyf' does not exist in " + fileName + style); + int tableGlyphOffset = tableLocation[0]; + bboxes = new int[locaTable.Length - 1][]; + for (int glyph = 0; glyph < locaTable.Length - 1; ++glyph) { + int start = locaTable[glyph]; + if (start != locaTable[glyph + 1]) { + rf.Seek(tableGlyphOffset + start + 2); + bboxes[glyph] = new int[]{ + (rf.ReadShort() * 1000) / head.unitsPerEm, + (rf.ReadShort() * 1000) / head.unitsPerEm, + (rf.ReadShort() * 1000) / head.unitsPerEm, + (rf.ReadShort() * 1000) / head.unitsPerEm}; + } + } + } + + /** Reads the several maps from the table 'cmap'. The maps of interest are 1.0 for symbolic + * fonts and 3.1 for all others. A symbolic font is defined as having the map 3.0. + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + internal void ReadCMaps() { + int[] table_location; + table_location = (int[])tables["cmap"]; + if (table_location == null) + throw new DocumentException("Table 'cmap' does not exist in " + fileName + style); + rf.Seek(table_location[0]); + rf.SkipBytes(2); + int num_tables = rf.ReadUnsignedShort(); + fontSpecific = false; + int map10 = 0; + int map31 = 0; + int map30 = 0; + + //add by james for cmap Ext.b + int mapExt = 0; + + for (int k = 0; k < num_tables; ++k) { + int platId = rf.ReadUnsignedShort(); + int platSpecId = rf.ReadUnsignedShort(); + int offset = rf.ReadInt(); + if (platId == 3 && platSpecId == 0) { + fontSpecific = true; + map30 = offset; + } + else if (platId == 3 && platSpecId == 1) { + map31 = offset; + } + else if (platId == 3 && platSpecId == 10) + { + mapExt = offset; + } + + if (platId == 1 && platSpecId == 0) { + map10 = offset; + } + + + } + if (map10 > 0) { + rf.Seek(table_location[0] + map10); + int format = rf.ReadUnsignedShort(); + switch (format) { + case 0: + cmap10 = ReadFormat0(); + break; + case 4: + cmap10 = ReadFormat4(); + break; + case 6: + cmap10 = ReadFormat6(); + break; + } + } + if (map31 > 0) { + rf.Seek(table_location[0] + map31); + int format = rf.ReadUnsignedShort(); + if (format == 4) { + cmap31 = ReadFormat4(); + } + } + if (map30 > 0) { + rf.Seek(table_location[0] + map30); + int format = rf.ReadUnsignedShort(); + if (format == 4) { + cmap10 = ReadFormat4(); + } + } + if (mapExt > 0) { + rf.Seek(table_location[0] + mapExt); + int format = rf.ReadUnsignedShort(); + switch (format) { + case 0: + cmapExt = ReadFormat0(); + break; + case 4: + cmapExt = ReadFormat4(); + break; + case 6: + cmapExt = ReadFormat6(); + break; + case 12: + cmapExt = ReadFormat12(); + break; + } + } + } + + internal Hashtable ReadFormat12() { + Hashtable h = new Hashtable(); + rf.SkipBytes(2); + int table_lenght = rf.ReadInt(); + rf.SkipBytes(4); + int nGroups = rf.ReadInt(); + for (int k = 0; k < nGroups; k++) { + int startCharCode = rf.ReadInt(); + int endCharCode = rf.ReadInt(); + int startGlyphID = rf.ReadInt(); + for (int i = startCharCode; i <= endCharCode; i++) { + int[] r = new int[2]; + r[0] = startGlyphID; + r[1] = GetGlyphWidth(r[0]); + h[i] = r; + startGlyphID++; + } + } + return h; + } + + /** The information in the maps of the table 'cmap' is coded in several formats. + * Format 0 is the Apple standard character to glyph index mapping table. + * @return a Hashtable representing this map + * @throws IOException the font file could not be read + */ + internal Hashtable ReadFormat0() { + Hashtable h = new Hashtable(); + rf.SkipBytes(4); + for (int k = 0; k < 256; ++k) { + int[] r = new int[2]; + r[0] = rf.ReadUnsignedByte(); + r[1] = GetGlyphWidth(r[0]); + h[k] = r; + } + return h; + } + + /** The information in the maps of the table 'cmap' is coded in several formats. + * Format 4 is the Microsoft standard character to glyph index mapping table. + * @return a Hashtable representing this map + * @throws IOException the font file could not be read + */ + internal Hashtable ReadFormat4() { + Hashtable h = new Hashtable(); + int table_lenght = rf.ReadUnsignedShort(); + rf.SkipBytes(2); + int segCount = rf.ReadUnsignedShort() / 2; + rf.SkipBytes(6); + int[] endCount = new int[segCount]; + for (int k = 0; k < segCount; ++k) { + endCount[k] = rf.ReadUnsignedShort(); + } + rf.SkipBytes(2); + int[] startCount = new int[segCount]; + for (int k = 0; k < segCount; ++k) { + startCount[k] = rf.ReadUnsignedShort(); + } + int[] idDelta = new int[segCount]; + for (int k = 0; k < segCount; ++k) { + idDelta[k] = rf.ReadUnsignedShort(); + } + int[] idRO = new int[segCount]; + for (int k = 0; k < segCount; ++k) { + idRO[k] = rf.ReadUnsignedShort(); + } + int[] glyphId = new int[table_lenght / 2 - 8 - segCount * 4]; + for (int k = 0; k < glyphId.Length; ++k) { + glyphId[k] = rf.ReadUnsignedShort(); + } + for (int k = 0; k < segCount; ++k) { + int glyph; + for (int j = startCount[k]; j <= endCount[k] && j != 0xFFFF; ++j) { + if (idRO[k] == 0) { + glyph = (j + idDelta[k]) & 0xFFFF; + } + else { + int idx = k + idRO[k] / 2 - segCount + j - startCount[k]; + if (idx >= glyphId.Length) + continue; + glyph = (glyphId[idx] + idDelta[k]) & 0xFFFF; + } + int[] r = new int[2]; + r[0] = glyph; + r[1] = GetGlyphWidth(r[0]); + h[fontSpecific ? ((j & 0xff00) == 0xf000 ? j & 0xff : j) : j] = r; + } + } + return h; + } + + /** The information in the maps of the table 'cmap' is coded in several formats. + * Format 6 is a trimmed table mapping. It is similar to format 0 but can have + * less than 256 entries. + * @return a Hashtable representing this map + * @throws IOException the font file could not be read + */ + internal Hashtable ReadFormat6() { + Hashtable h = new Hashtable(); + rf.SkipBytes(4); + int start_code = rf.ReadUnsignedShort(); + int code_count = rf.ReadUnsignedShort(); + for (int k = 0; k < code_count; ++k) { + int[] r = new int[2]; + r[0] = rf.ReadUnsignedShort(); + r[1] = GetGlyphWidth(r[0]); + h[k + start_code] = r; + } + return h; + } + + /** Reads the kerning information from the 'kern' table. + * @throws IOException the font file could not be read + */ + internal void ReadKerning() { + int[] table_location; + table_location = (int[])tables["kern"]; + if (table_location == null) + return; + rf.Seek(table_location[0] + 2); + int nTables = rf.ReadUnsignedShort(); + int checkpoint = table_location[0] + 4; + int length = 0; + for (int k = 0; k < nTables; ++k) { + checkpoint += length; + rf.Seek(checkpoint); + rf.SkipBytes(2); + length = rf.ReadUnsignedShort(); + int coverage = rf.ReadUnsignedShort(); + if ((coverage & 0xfff7) == 0x0001) { + int nPairs = rf.ReadUnsignedShort(); + rf.SkipBytes(6); + for (int j = 0; j < nPairs; ++j) { + int pair = rf.ReadInt(); + int value = ((int)rf.ReadShort() * 1000) / head.unitsPerEm; + kerning[pair] = value; + } + } + } + } + + /** Gets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @return the kerning to be applied + */ + public override int GetKerning(int char1, int char2) { + int[] metrics = GetMetricsTT(char1); + if (metrics == null) + return 0; + int c1 = metrics[0]; + metrics = GetMetricsTT(char2); + if (metrics == null) + return 0; + int c2 = metrics[0]; + return kerning[(c1 << 16) + c2]; + } + + /** Gets the width from the font according to the unicode char c. + * If the name is null it's a symbolic font. + * @param c the unicode char + * @param name the glyph name + * @return the width of the char + */ + internal override int GetRawWidth(int c, string name) { + int[] metric = GetMetricsTT(c); + if (metric == null) + return 0; + return metric[1]; + } + + /** Generates the font descriptor for this font. + * @return the PdfDictionary containing the font descriptor or null + * @param subsetPrefix the subset prefix + * @param fontStream the indirect reference to a PdfStream containing the font or null + * @throws DocumentException if there is an error + */ + protected PdfDictionary GetFontDescriptor(PdfIndirectReference fontStream, string subsetPrefix, PdfIndirectReference cidset) { + PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR); + dic.Put(PdfName.ASCENT, new PdfNumber((int)os_2.sTypoAscender * 1000 / head.unitsPerEm)); + dic.Put(PdfName.CAPHEIGHT, new PdfNumber((int)os_2.sCapHeight * 1000 / head.unitsPerEm)); + dic.Put(PdfName.DESCENT, new PdfNumber((int)os_2.sTypoDescender * 1000 / head.unitsPerEm)); + dic.Put(PdfName.FONTBBOX, new PdfRectangle( + (int)head.xMin * 1000 / head.unitsPerEm, + (int)head.yMin * 1000 / head.unitsPerEm, + (int)head.xMax * 1000 / head.unitsPerEm, + (int)head.yMax * 1000 / head.unitsPerEm)); + if (cidset != null) + dic.Put(PdfName.CIDSET, cidset); + if (cff) { + if (encoding.StartsWith("Identity-")) + dic.Put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName+"-"+encoding)); + else + dic.Put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName + style)); + } + else + dic.Put(PdfName.FONTNAME, new PdfName(subsetPrefix + fontName + style)); + dic.Put(PdfName.ITALICANGLE, new PdfNumber(italicAngle)); + dic.Put(PdfName.STEMV, new PdfNumber(80)); + if (fontStream != null) { + if (cff) + dic.Put(PdfName.FONTFILE3, fontStream); + else + dic.Put(PdfName.FONTFILE2, fontStream); + } + int flags = 0; + if (isFixedPitch) + flags |= 1; + flags |= fontSpecific ? 4 : 32; + if ((head.macStyle & 2) != 0) + flags |= 64; + if ((head.macStyle & 1) != 0) + flags |= 262144; + dic.Put(PdfName.FLAGS, new PdfNumber(flags)); + + return dic; + } + + /** Generates the font dictionary for this font. + * @return the PdfDictionary containing the font dictionary + * @param subsetPrefix the subset prefx + * @param firstChar the first valid character + * @param lastChar the last valid character + * @param shortTag a 256 bytes long byte array where each unused byte is represented by 0 + * @param fontDescriptor the indirect reference to a PdfDictionary containing the font descriptor or null + * @throws DocumentException if there is an error + */ + protected PdfDictionary GetFontBaseType(PdfIndirectReference fontDescriptor, string subsetPrefix, int firstChar, int lastChar, byte[] shortTag) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + if (cff) { + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + dic.Put(PdfName.BASEFONT, new PdfName(fontName + style)); + } + else { + dic.Put(PdfName.SUBTYPE, PdfName.TRUETYPE); + dic.Put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName + style)); + } + dic.Put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName + style)); + if (!fontSpecific) { + for (int k = firstChar; k <= lastChar; ++k) { + if (!differences[k].Equals(notdef)) { + firstChar = k; + break; + } + } + if (encoding.Equals(CP1252) || encoding.Equals(MACROMAN)) + dic.Put(PdfName.ENCODING, encoding.Equals(CP1252) ? PdfName.WIN_ANSI_ENCODING : PdfName.MAC_ROMAN_ENCODING); + else { + PdfDictionary enc = new PdfDictionary(PdfName.ENCODING); + PdfArray dif = new PdfArray(); + bool gap = true; + for (int k = firstChar; k <= lastChar; ++k) { + if (shortTag[k] != 0) { + if (gap) { + dif.Add(new PdfNumber(k)); + gap = false; + } + dif.Add(new PdfName(differences[k])); + } + else + gap = true; + } + enc.Put(PdfName.DIFFERENCES, dif); + dic.Put(PdfName.ENCODING, enc); + } + } + dic.Put(PdfName.FIRSTCHAR, new PdfNumber(firstChar)); + dic.Put(PdfName.LASTCHAR, new PdfNumber(lastChar)); + PdfArray wd = new PdfArray(); + for (int k = firstChar; k <= lastChar; ++k) { + if (shortTag[k] == 0) + wd.Add(new PdfNumber(0)); + else + wd.Add(new PdfNumber(widths[k])); + } + dic.Put(PdfName.WIDTHS, wd); + if (fontDescriptor != null) + dic.Put(PdfName.FONTDESCRIPTOR, fontDescriptor); + return dic; + } + + protected byte[] GetFullFont() { + RandomAccessFileOrArray rf2 = null; + try { + rf2 = new RandomAccessFileOrArray(rf); + rf2.ReOpen(); + byte[] b = new byte[rf2.Length]; + rf2.ReadFully(b); + return b; + } + finally { + try {if (rf2 != null) rf2.Close();} catch {} + } + } + + protected static int[] CompactRanges(ArrayList ranges) { + ArrayList simp = new ArrayList(); + for (int k = 0; k < ranges.Count; ++k) { + int[] r = (int[])ranges[k]; + for (int j = 0; j < r.Length; j += 2) { + simp.Add(new int[]{Math.Max(0, Math.Min(r[j], r[j + 1])), Math.Min(0xffff, Math.Max(r[j], r[j + 1]))}); + } + } + for (int k1 = 0; k1 < simp.Count - 1; ++k1) { + for (int k2 = k1 + 1; k2 < simp.Count; ++k2) { + int[] r1 = (int[])simp[k1]; + int[] r2 = (int[])simp[k2]; + if ((r1[0] >= r2[0] && r1[0] <= r2[1]) || (r1[1] >= r2[0] && r1[0] <= r2[1])) { + r1[0] = Math.Min(r1[0], r2[0]); + r1[1] = Math.Max(r1[1], r2[1]); + simp.RemoveAt(k2); + --k2; + } + } + } + int[] s = new int[simp.Count * 2]; + for (int k = 0; k < simp.Count; ++k) { + int[] r = (int[])simp[k]; + s[k * 2] = r[0]; + s[k * 2 + 1] = r[1]; + } + return s; + } + + protected void AddRangeUni(Hashtable longTag, bool includeMetrics, bool subsetp) { + if (!subsetp && (subsetRanges != null || directoryOffset > 0)) { + int[] rg = (subsetRanges == null && directoryOffset > 0) ? new int[]{0, 0xffff} : CompactRanges(subsetRanges); + Hashtable usemap; + if (!fontSpecific && cmap31 != null) + usemap = cmap31; + else if (fontSpecific && cmap10 != null) + usemap = cmap10; + else if (cmap31 != null) + usemap = cmap31; + else + usemap = cmap10; + foreach (DictionaryEntry e in usemap) { + int[] v = (int[])e.Value; + int gi = (int)v[0]; + if (longTag.ContainsKey(gi)) + continue; + int c = (int)e.Key; + bool skip = true; + for (int k = 0; k < rg.Length; k += 2) { + if (c >= rg[k] && c <= rg[k + 1]) { + skip = false; + break; + } + } + if (!skip) + longTag[gi] = includeMetrics ? new int[]{v[0], v[1], c} : null; + } + } + } + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param params several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + */ + internal override void WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) { + int firstChar = (int)parms[0]; + int lastChar = (int)parms[1]; + byte[] shortTag = (byte[])parms[2]; + bool subsetp = (bool)parms[3] && subset; + if (!subsetp) { + firstChar = 0; + lastChar = shortTag.Length - 1; + for (int k = 0; k < shortTag.Length; ++k) + shortTag[k] = 1; + } + PdfIndirectReference ind_font = null; + PdfObject pobj = null; + PdfIndirectObject obj = null; + string subsetPrefix = ""; + if (embedded) { + if (cff) { + RandomAccessFileOrArray rf2 = new RandomAccessFileOrArray(rf); + byte[] b = new byte[cffLength]; + try { + rf2.ReOpen(); + rf2.Seek(cffOffset); + rf2.ReadFully(b); + } + finally { + try { + rf2.Close(); + } + catch { + // empty on purpose + } + } + pobj = new StreamFont(b, "Type1C"); + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + else { + if (subsetp) + subsetPrefix = CreateSubsetPrefix(); + Hashtable glyphs = new Hashtable(); + for (int k = firstChar; k <= lastChar; ++k) { + if (shortTag[k] != 0) { + int[] metrics = null; + if (specialMap != null) { + int[] cd = GlyphList.NameToUnicode(differences[k]); + if (cd != null) + metrics = GetMetricsTT(cd[0]); + } + else { + if (fontSpecific) + metrics = GetMetricsTT(k); + else + metrics = GetMetricsTT(unicodeDifferences[k]); + } + if (metrics != null) + glyphs[metrics[0]] = null; + } + } + AddRangeUni(glyphs, false, subsetp); + byte[] b = null; + if (subsetp || directoryOffset != 0 || subsetRanges != null) { + TrueTypeFontSubSet sb = new TrueTypeFontSubSet(fileName, new RandomAccessFileOrArray(rf), glyphs, directoryOffset, true, !subsetp); + b = sb.Process(); + } + else { + b = GetFullFont(); + } + int[] lengths = new int[]{b.Length}; + pobj = new StreamFont(b, lengths); + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + } + pobj = GetFontDescriptor(ind_font, subsetPrefix, null); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetFontBaseType(ind_font, subsetPrefix, firstChar, lastChar, shortTag); + writer.AddToBody(pobj, piref); + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT + * and ITALICANGLE. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + */ + public override float GetFontDescriptor(int key, float fontSize) { + switch (key) { + case ASCENT: + return (float)os_2.sTypoAscender * fontSize / (float)head.unitsPerEm; + case CAPHEIGHT: + return (float)os_2.sCapHeight * fontSize / (float)head.unitsPerEm; + case DESCENT: + return (float)os_2.sTypoDescender * fontSize / (float)head.unitsPerEm; + case ITALICANGLE: + return (float)italicAngle; + case BBOXLLX: + return fontSize * (int)head.xMin / head.unitsPerEm; + case BBOXLLY: + return fontSize * (int)head.yMin / head.unitsPerEm; + case BBOXURX: + return fontSize * (int)head.xMax / head.unitsPerEm; + case BBOXURY: + return fontSize * (int)head.yMax / head.unitsPerEm; + case AWT_ASCENT: + return fontSize * (int)hhea.Ascender / head.unitsPerEm; + case AWT_DESCENT: + return fontSize * (int)hhea.Descender / head.unitsPerEm; + case AWT_LEADING: + return fontSize * (int)hhea.LineGap / head.unitsPerEm; + case AWT_MAXADVANCE: + return fontSize * (int)hhea.advanceWidthMax / head.unitsPerEm; + case UNDERLINE_POSITION: + return (underlinePosition - underlineThickness / 2) * fontSize / head.unitsPerEm; + case UNDERLINE_THICKNESS: + return underlineThickness * fontSize / head.unitsPerEm; + case STRIKETHROUGH_POSITION: + return os_2.yStrikeoutPosition * fontSize / head.unitsPerEm; + case STRIKETHROUGH_THICKNESS: + return os_2.yStrikeoutSize * fontSize / head.unitsPerEm; + case SUBSCRIPT_SIZE: + return os_2.ySubscriptYSize * fontSize / head.unitsPerEm; + case SUBSCRIPT_OFFSET: + return -os_2.ySubscriptYOffset * fontSize / head.unitsPerEm; + case SUPERSCRIPT_SIZE: + return os_2.ySuperscriptYSize * fontSize / head.unitsPerEm; + case SUPERSCRIPT_OFFSET: + return os_2.ySuperscriptYOffset * fontSize / head.unitsPerEm; + } + return 0; + } + + /** Gets the glyph index and metrics for a character. + * @param c the character + * @return an int array with {glyph index, width} + */ + public virtual int[] GetMetricsTT(int c) { + if (cmapExt != null) + return (int[])cmapExt[c]; + if (!fontSpecific && cmap31 != null) + return (int[])cmap31[c]; + if (fontSpecific && cmap10 != null) + return (int[])cmap10[c]; + if (cmap31 != null) + return (int[])cmap31[c]; + if (cmap10 != null) + return (int[])cmap10[c]; + return null; + } + + /** Gets the postscript font name. + * @return the postscript font name + */ + public override string PostscriptFontName { + get { + return fontName; + } + set { + fontName = value; + } + } + + /** Gets the code pages supported by the font. + * @return the code pages supported by the font + */ + public override string[] CodePagesSupported { + get { + long cp = (((long)os_2.ulCodePageRange2) << 32) + ((long)os_2.ulCodePageRange1 & 0xffffffffL); + int count = 0; + long bit = 1; + for (int k = 0; k < 64; ++k) { + if ((cp & bit) != 0 && codePages[k] != null) + ++count; + bit <<= 1; + } + string[] ret = new string[count]; + count = 0; + bit = 1; + for (int k = 0; k < 64; ++k) { + if ((cp & bit) != 0 && codePages[k] != null) + ret[count++] = codePages[k]; + bit <<= 1; + } + return ret; + } + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] FullFontName { + get { + return fullName; + } + } + + /** Gets all the entries of the Names-Table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] AllNameEntries { + get { + return allNameEntries; + } + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + */ + public override string[][] FamilyFontName { + get { + return familyName; + } + } + + /** Checks if the font has any kerning pairs. + * @return true if the font has any kerning pairs + */ + public override bool HasKernPairs() { + return kerning.Size > 0; + } + + /** + * Sets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @param kern the kerning to apply in normalized 1000 units + * @return true if the kerning was applied, false otherwise + */ + public override bool SetKerning(int char1, int char2, int kern) { + int[] metrics = GetMetricsTT(char1); + if (metrics == null) + return false; + int c1 = metrics[0]; + metrics = GetMetricsTT(char2); + if (metrics == null) + return false; + int c2 = metrics[0]; + kerning[(c1 << 16) + c2] = kern; + return true; + } + + protected override int[] GetRawCharBBox(int c, String name) { + Hashtable map = null; + if (name == null || cmap31 == null) + map = cmap10; + else + map = cmap31; + if (map == null) + return null; + int[] metric = (int[])map[c]; + if (metric == null || bboxes == null) + return null; + return bboxes[metric[0]]; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/TrueTypeFontSubSet.cs b/iTechSharp/iTextSharp/text/pdf/TrueTypeFontSubSet.cs new file mode 100644 index 0000000..e5f37fb --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/TrueTypeFontSubSet.cs @@ -0,0 +1,423 @@ +using System; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: TrueTypeFontSubSet.cs,v 1.4 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Subsets a True Type font by removing the unneeded glyphs from + * the font. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class TrueTypeFontSubSet { + internal static string[] tableNamesSimple = {"cvt ", "fpgm", "glyf", "head", + "hhea", "hmtx", "loca", "maxp", "prep"}; + internal static string[] tableNamesCmap = {"cmap", "cvt ", "fpgm", "glyf", "head", + "hhea", "hmtx", "loca", "maxp", "prep"}; + internal static string[] tableNamesExtra = {"OS/2", "cmap", "cvt ", "fpgm", "glyf", "head", + "hhea", "hmtx", "loca", "maxp", "name, prep"}; + internal static int[] entrySelectors = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4}; + internal static int TABLE_CHECKSUM = 0; + internal static int TABLE_OFFSET = 1; + internal static int TABLE_LENGTH = 2; + internal static int HEAD_LOCA_FORMAT_OFFSET = 51; + + internal static int ARG_1_AND_2_ARE_WORDS = 1; + internal static int WE_HAVE_A_SCALE = 8; + internal static int MORE_COMPONENTS = 32; + internal static int WE_HAVE_AN_X_AND_Y_SCALE = 64; + internal static int WE_HAVE_A_TWO_BY_TWO = 128; + + + /** Contains the location of the several tables. The key is the name of + * the table and the value is an int[3] where position 0 + * is the checksum, position 1 is the offset from the start of the file + * and position 2 is the length of the table. + */ + protected Hashtable tableDirectory; + /** The file in use. + */ + protected RandomAccessFileOrArray rf; + /** The file name. + */ + protected string fileName; + protected bool includeCmap; + protected bool includeExtras; + protected bool locaShortTable; + protected int[] locaTable; + protected Hashtable glyphsUsed; + protected ArrayList glyphsInList; + protected int tableGlyphOffset; + protected int[] newLocaTable; + protected byte[] newLocaTableOut; + protected byte[] newGlyfTable; + protected int glyfTableRealSize; + protected int locaTableRealSize; + protected byte[] outFont; + protected int fontPtr; + protected int directoryOffset; + + /** Creates a new TrueTypeFontSubSet + * @param directoryOffset The offset from the start of the file to the table directory + * @param fileName the file name of the font + * @param glyphsUsed the glyphs used + * @param includeCmap true if the table cmap is to be included in the generated font + */ + internal TrueTypeFontSubSet(string fileName, RandomAccessFileOrArray rf, Hashtable glyphsUsed, int directoryOffset, bool includeCmap, bool includeExtras) { + this.fileName = fileName; + this.rf = rf; + this.glyphsUsed = glyphsUsed; + this.includeCmap = includeCmap; + this.includeExtras = includeExtras; + this.directoryOffset = directoryOffset; + glyphsInList = new ArrayList(glyphsUsed.Keys); + } + + /** Does the actual work of subsetting the font. + * @throws IOException on error + * @throws DocumentException on error + * @return the subset font + */ + internal byte[] Process() { + try { + rf.ReOpen(); + CreateTableDirectory(); + ReadLoca(); + FlatGlyphs(); + CreateNewGlyphTables(); + LocaTobytes(); + AssembleFont(); + return outFont; + } + finally { + try { + rf.Close(); + } + catch { + // empty on purpose + } + } + } + + protected void AssembleFont() { + int[] tableLocation; + int fullFontSize = 0; + string[] tableNames; + if (includeExtras) + tableNames = tableNamesExtra; + else { + if (includeCmap) + tableNames = tableNamesCmap; + else + tableNames = tableNamesSimple; + } + int tablesUsed = 2; + int len = 0; + for (int k = 0; k < tableNames.Length; ++k) { + string name = tableNames[k]; + if (name.Equals("glyf") || name.Equals("loca")) + continue; + tableLocation = (int[])tableDirectory[name]; + if (tableLocation == null) + continue; + ++tablesUsed; + fullFontSize += (tableLocation[TABLE_LENGTH] + 3) & (~3); + } + fullFontSize += newLocaTableOut.Length; + fullFontSize += newGlyfTable.Length; + int iref = 16 * tablesUsed + 12; + fullFontSize += iref; + outFont = new byte[fullFontSize]; + fontPtr = 0; + WriteFontInt(0x00010000); + WriteFontShort(tablesUsed); + int selector = entrySelectors[tablesUsed]; + WriteFontShort((1 << selector) * 16); + WriteFontShort(selector); + WriteFontShort((tablesUsed - (1 << selector)) * 16); + for (int k = 0; k < tableNames.Length; ++k) { + string name = tableNames[k]; + tableLocation = (int[])tableDirectory[name]; + if (tableLocation == null) + continue; + WriteFontString(name); + if (name.Equals("glyf")) { + WriteFontInt(CalculateChecksum(newGlyfTable)); + len = glyfTableRealSize; + } + else if (name.Equals("loca")) { + WriteFontInt(CalculateChecksum(newLocaTableOut)); + len = locaTableRealSize; + } + else { + WriteFontInt(tableLocation[TABLE_CHECKSUM]); + len = tableLocation[TABLE_LENGTH]; + } + WriteFontInt(iref); + WriteFontInt(len); + iref += (len + 3) & (~3); + } + for (int k = 0; k < tableNames.Length; ++k) { + string name = tableNames[k]; + tableLocation = (int[])tableDirectory[name]; + if (tableLocation == null) + continue; + if (name.Equals("glyf")) { + Array.Copy(newGlyfTable, 0, outFont, fontPtr, newGlyfTable.Length); + fontPtr += newGlyfTable.Length; + newGlyfTable = null; + } + else if (name.Equals("loca")) { + Array.Copy(newLocaTableOut, 0, outFont, fontPtr, newLocaTableOut.Length); + fontPtr += newLocaTableOut.Length; + newLocaTableOut = null; + } + else { + rf.Seek(tableLocation[TABLE_OFFSET]); + rf.ReadFully(outFont, fontPtr, tableLocation[TABLE_LENGTH]); + fontPtr += (tableLocation[TABLE_LENGTH] + 3) & (~3); + } + } + } + + protected void CreateTableDirectory() { + tableDirectory = new Hashtable(); + rf.Seek(directoryOffset); + int id = rf.ReadInt(); + if (id != 0x00010000) + throw new DocumentException(fileName + " is not a true type file."); + int num_tables = rf.ReadUnsignedShort(); + rf.SkipBytes(6); + for (int k = 0; k < num_tables; ++k) { + string tag = ReadStandardString(4); + int[] tableLocation = new int[3]; + tableLocation[TABLE_CHECKSUM] = rf.ReadInt(); + tableLocation[TABLE_OFFSET] = rf.ReadInt(); + tableLocation[TABLE_LENGTH] = rf.ReadInt(); + tableDirectory[tag] = tableLocation; + } + } + + protected void ReadLoca() { + int[] tableLocation; + tableLocation = (int[])tableDirectory["head"]; + if (tableLocation == null) + throw new DocumentException("Table 'head' does not exist in " + fileName); + rf.Seek(tableLocation[TABLE_OFFSET] + HEAD_LOCA_FORMAT_OFFSET); + locaShortTable = (rf.ReadUnsignedShort() == 0); + tableLocation = (int[])tableDirectory["loca"]; + if (tableLocation == null) + throw new DocumentException("Table 'loca' does not exist in " + fileName); + rf.Seek(tableLocation[TABLE_OFFSET]); + if (locaShortTable) { + int entries = tableLocation[TABLE_LENGTH] / 2; + locaTable = new int[entries]; + for (int k = 0; k < entries; ++k) + locaTable[k] = rf.ReadUnsignedShort() * 2; + } + else { + int entries = tableLocation[TABLE_LENGTH] / 4; + locaTable = new int[entries]; + for (int k = 0; k < entries; ++k) + locaTable[k] = rf.ReadInt(); + } + } + + protected void CreateNewGlyphTables() { + newLocaTable = new int[locaTable.Length]; + int[] activeGlyphs = new int[glyphsInList.Count]; + for (int k = 0; k < activeGlyphs.Length; ++k) + activeGlyphs[k] = (int)glyphsInList[k]; + Array.Sort(activeGlyphs); + int glyfSize = 0; + for (int k = 0; k < activeGlyphs.Length; ++k) { + int glyph = activeGlyphs[k]; + glyfSize += locaTable[glyph + 1] - locaTable[glyph]; + } + glyfTableRealSize = glyfSize; + glyfSize = (glyfSize + 3) & (~3); + newGlyfTable = new byte[glyfSize]; + int glyfPtr = 0; + int listGlyf = 0; + for (int k = 0; k < newLocaTable.Length; ++k) { + newLocaTable[k] = glyfPtr; + if (listGlyf < activeGlyphs.Length && activeGlyphs[listGlyf] == k) { + ++listGlyf; + newLocaTable[k] = glyfPtr; + int start = locaTable[k]; + int len = locaTable[k + 1] - start; + if (len > 0) { + rf.Seek(tableGlyphOffset + start); + rf.ReadFully(newGlyfTable, glyfPtr, len); + glyfPtr += len; + } + } + } + } + + protected void LocaTobytes() { + if (locaShortTable) + locaTableRealSize = newLocaTable.Length * 2; + else + locaTableRealSize = newLocaTable.Length * 4; + newLocaTableOut = new byte[(locaTableRealSize + 3) & (~3)]; + outFont = newLocaTableOut; + fontPtr = 0; + for (int k = 0; k < newLocaTable.Length; ++k) { + if (locaShortTable) + WriteFontShort(newLocaTable[k] / 2); + else + WriteFontInt(newLocaTable[k]); + } + + } + + protected void FlatGlyphs() { + int[] tableLocation; + tableLocation = (int[])tableDirectory["glyf"]; + if (tableLocation == null) + throw new DocumentException("Table 'glyf' does not exist in " + fileName); + int glyph0 = 0; + if (!glyphsUsed.ContainsKey(glyph0)) { + glyphsUsed[glyph0] = null; + glyphsInList.Add(glyph0); + } + tableGlyphOffset = tableLocation[TABLE_OFFSET]; + for (int k = 0; k < glyphsInList.Count; ++k) { + int glyph = (int)glyphsInList[k]; + CheckGlyphComposite(glyph); + } + } + + protected void CheckGlyphComposite(int glyph) { + int start = locaTable[glyph]; + if (start == locaTable[glyph + 1]) // no contour + return; + rf.Seek(tableGlyphOffset + start); + int numContours = rf.ReadShort(); + if (numContours >= 0) + return; + rf.SkipBytes(8); + for(;;) { + int flags = rf.ReadUnsignedShort(); + int cGlyph = rf.ReadUnsignedShort(); + if (!glyphsUsed.ContainsKey(cGlyph)) { + glyphsUsed[cGlyph] = null; + glyphsInList.Add(cGlyph); + } + if ((flags & MORE_COMPONENTS) == 0) + return; + int skip; + if ((flags & ARG_1_AND_2_ARE_WORDS) != 0) + skip = 4; + else + skip = 2; + if ((flags & WE_HAVE_A_SCALE) != 0) + skip += 2; + else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) + skip += 4; + if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0) + skip += 8; + rf.SkipBytes(skip); + } + } + + /** Reads a string from the font file as bytes using the Cp1252 + * encoding. + * @param length the length of bytes to read + * @return the string read + * @throws IOException the font file could not be read + */ + protected string ReadStandardString(int length) { + byte[] buf = new byte[length]; + rf.ReadFully(buf); + return System.Text.Encoding.GetEncoding(1252).GetString(buf); + } + + protected void WriteFontShort(int n) { + outFont[fontPtr++] = (byte)(n >> 8); + outFont[fontPtr++] = (byte)(n); + } + + protected void WriteFontInt(int n) { + outFont[fontPtr++] = (byte)(n >> 24); + outFont[fontPtr++] = (byte)(n >> 16); + outFont[fontPtr++] = (byte)(n >> 8); + outFont[fontPtr++] = (byte)(n); + } + + protected void WriteFontString(string s) { + byte[] b = PdfEncodings.ConvertToBytes(s, BaseFont.WINANSI); + Array.Copy(b, 0, outFont, fontPtr, b.Length); + fontPtr += b.Length; + } + + protected int CalculateChecksum(byte[] b) { + int len = b.Length / 4; + int v0 = 0; + int v1 = 0; + int v2 = 0; + int v3 = 0; + int ptr = 0; + for (int k = 0; k < len; ++k) { + v3 += (int)b[ptr++] & 0xff; + v2 += (int)b[ptr++] & 0xff; + v1 += (int)b[ptr++] & 0xff; + v0 += (int)b[ptr++] & 0xff; + } + return v0 + (v1 << 8) + (v2 << 16) + (v3 << 24); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/TrueTypeFontUnicode.cs b/iTechSharp/iTextSharp/text/pdf/TrueTypeFontUnicode.cs new file mode 100644 index 0000000..1feb9f9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/TrueTypeFontUnicode.cs @@ -0,0 +1,487 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; + +/* + * $Id: TrueTypeFontUnicode.cs,v 1.12 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Represents a True Type font with Unicode encoding. All the character + * in the font can be used directly by using the encoding Identity-H or + * Identity-V. This is the only way to represent some character sets such + * as Thai. + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class TrueTypeFontUnicode : TrueTypeFont, IComparer { + + /** true if the encoding is vertical. + */ + bool vertical = false; + + /** Creates a new TrueType font addressed by Unicode characters. The font + * will always be embedded. + * @param ttFile the location of the font on file. The file must end in '.ttf'. + * The modifiers after the name are ignored. + * @param enc the encoding to be applied to this font + * @param emb true if the font is to be embedded in the PDF + * @param ttfAfm the font as a byte array + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + internal TrueTypeFontUnicode(string ttFile, string enc, bool emb, byte[] ttfAfm) { + string nameBase = GetBaseName(ttFile); + string ttcName = GetTTCName(nameBase); + if (nameBase.Length < ttFile.Length) { + style = ttFile.Substring(nameBase.Length); + } + encoding = enc; + embedded = emb; + fileName = ttcName; + ttcIndex = ""; + if (ttcName.Length < nameBase.Length) + ttcIndex = nameBase.Substring(ttcName.Length + 1); + FontType = FONT_TYPE_TTUNI; + if ((fileName.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || fileName.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || fileName.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttc")) && ((enc.Equals(IDENTITY_H) || enc.Equals(IDENTITY_V)) && emb)) { + Process(ttfAfm); + if (os_2.fsType == 2) + throw new DocumentException(fileName + style + " cannot be embedded due to licensing restrictions."); + // Sivan + if ((cmap31 == null && !fontSpecific) || (cmap10 == null && fontSpecific)) + directTextToByte=true; + //throw new DocumentException(fileName + " " + style + " does not contain an usable cmap."); + if (fontSpecific) { + fontSpecific = false; + String tempEncoding = encoding; + encoding = ""; + CreateEncoding(); + encoding = tempEncoding; + fontSpecific = true; + } + } + else + throw new DocumentException(fileName + " " + style + " is not a TTF font file."); + vertical = enc.EndsWith("V"); + } + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public override int GetWidth(int char1) { + if (vertical) + return 1000; + if (fontSpecific) { + if ((char1 & 0xff00) == 0 || (char1 & 0xff00) == 0xf000) + return GetRawWidth(char1 & 0xff, null); + else + return 0; + } + else { + return GetRawWidth(char1, encoding); + } + } + + /** + * Gets the width of a string in normalized 1000 units. + * @param text the string to get the witdth of + * @return the width in normalized 1000 units + */ + public override int GetWidth(string text) { + if (vertical) + return text.Length * 1000; + int total = 0; + if (fontSpecific) { + char[] cc = text.ToCharArray(); + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if ((c & 0xff00) == 0 || (c & 0xff00) == 0xf000) + total += GetRawWidth(c & 0xff, null); + } + } + else { + int len = text.Length; + for (int k = 0; k < len; ++k) { + if (Utilities.IsSurrogatePair(text, k)) { + total += GetRawWidth(Utilities.ConvertToUtf32(text, k), encoding); + ++k; + } + else + total += GetRawWidth(text[k], encoding); + } + } + return total; + } + + /** Creates a ToUnicode CMap to allow copy and paste from Acrobat. + * @param metrics metrics[0] contains the glyph index and metrics[2] + * contains the Unicode code + * @throws DocumentException on error + * @return the stream representing this CMap or null + */ + private PdfStream GetToUnicode(Object[] metrics) { + if (metrics.Length == 0) + return null; + StringBuilder buf = new StringBuilder( + "/CIDInit /ProcSet findresource begin\n" + + "12 dict begin\n" + + "begincmap\n" + + "/CIDSystemInfo\n" + + "<< /Registry (TTX+0)\n" + + "/Ordering (T42UV)\n" + + "/Supplement 0\n" + + ">> def\n" + + "/CMapName /TTX+0 def\n" + + "/CMapType 2 def\n" + + "1 begincodespacerange\n" + + "<0000>\n" + + "endcodespacerange\n"); + int size = 0; + for (int k = 0; k < metrics.Length; ++k) { + if (size == 0) { + if (k != 0) { + buf.Append("endbfrange\n"); + } + size = Math.Min(100, metrics.Length - k); + buf.Append(size).Append(" beginbfrange\n"); + } + --size; + int[] metric = (int[])metrics[k]; + string fromTo = ToHex(metric[0]); + buf.Append(fromTo).Append(fromTo).Append(ToHex(metric[2])).Append('\n'); + } + buf.Append( + "endbfrange\n" + + "endcmap\n" + + "CMapName currentdict /CMap defineresource pop\n" + + "end end\n"); + string s = buf.ToString(); + PdfStream stream = new PdfStream(PdfEncodings.ConvertToBytes(s, null)); + stream.FlateCompress(); + return stream; + } + + /** Gets an hex string in the format "<HHHH>". + * @param n the number + * @return the hex string + */ + internal static string ToHex(int n) { + if (n < 0x10000) + return "<" + System.Convert.ToString(n, 16).PadLeft(4, '0') + ">"; + n -= 0x10000; + int high = (n / 0x400) + 0xd800; + int low = (n % 0x400) + 0xdc00; + return "[<" + System.Convert.ToString(high, 16).PadLeft(4, '0') + System.Convert.ToString(low, 16).PadLeft(4, '0') + ">]"; + } + + /** Generates the CIDFontTyte2 dictionary. + * @param fontDescriptor the indirect reference to the font descriptor + * @param subsetPrefix the subset prefix + * @param metrics the horizontal width metrics + * @return a stream + */ + private PdfDictionary GetCIDFontType2(PdfIndirectReference fontDescriptor, string subsetPrefix, Object[] metrics) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + // sivan; cff + if (cff) { + dic.Put(PdfName.SUBTYPE, PdfName.CIDFONTTYPE0); + dic.Put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName+"-"+encoding)); + } + else { + dic.Put(PdfName.SUBTYPE, PdfName.CIDFONTTYPE2); + dic.Put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName)); + } + dic.Put(PdfName.FONTDESCRIPTOR, fontDescriptor); + if (!cff) + dic.Put(PdfName.CIDTOGIDMAP,PdfName.IDENTITY); + PdfDictionary cdic = new PdfDictionary(); + cdic.Put(PdfName.REGISTRY, new PdfString("Adobe")); + cdic.Put(PdfName.ORDERING, new PdfString("Identity")); + cdic.Put(PdfName.SUPPLEMENT, new PdfNumber(0)); + dic.Put(PdfName.CIDSYSTEMINFO, cdic); + if (!vertical) { + dic.Put(PdfName.DW, new PdfNumber(1000)); + StringBuilder buf = new StringBuilder("["); + int lastNumber = -10; + bool firstTime = true; + for (int k = 0; k < metrics.Length; ++k) { + int[] metric = (int[])metrics[k]; + if (metric[1] == 1000) + continue; + int m = metric[0]; + if (m == lastNumber + 1) { + buf.Append(' ').Append(metric[1]); + } + else { + if (!firstTime) { + buf.Append(']'); + } + firstTime = false; + buf.Append(m).Append('[').Append(metric[1]); + } + lastNumber = m; + } + if (buf.Length > 1) { + buf.Append("]]"); + dic.Put(PdfName.W, new PdfLiteral(buf.ToString())); + } + } + return dic; + } + + /** Generates the font dictionary. + * @param descendant the descendant dictionary + * @param subsetPrefix the subset prefix + * @param toUnicode the ToUnicode stream + * @return the stream + */ + private PdfDictionary GetFontBaseType(PdfIndirectReference descendant, string subsetPrefix, PdfIndirectReference toUnicode) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + + dic.Put(PdfName.SUBTYPE, PdfName.TYPE0); + // The PDF Reference manual advises to add -encoding to CID font names + if (cff) + dic.Put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName+"-"+encoding)); + else + dic.Put(PdfName.BASEFONT, new PdfName(subsetPrefix + fontName)); + dic.Put(PdfName.ENCODING, new PdfName(encoding)); + dic.Put(PdfName.DESCENDANTFONTS, new PdfArray(descendant)); + if (toUnicode != null) + dic.Put(PdfName.TOUNICODE, toUnicode); + return dic; + } + + /** The method used to sort the metrics array. + * @param o1 the first element + * @param o2 the second element + * @return the comparisation + */ + public int Compare(Object o1, Object o2) { + int m1 = ((int[])o1)[0]; + int m2 = ((int[])o2)[0]; + if (m1 < m2) + return -1; + if (m1 == m2) + return 0; + return 1; + } + + private static readonly byte[] rotbits = {(byte)0x80,(byte)0x40,(byte)0x20,(byte)0x10,(byte)0x08,(byte)0x04,(byte)0x02,(byte)0x01}; + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param parms several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + */ + internal override void WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) { + Hashtable longTag = (Hashtable)parms[0]; + AddRangeUni(longTag, true, subset); + ArrayList tmp = new ArrayList(); + foreach (object o in longTag.Values) { + tmp.Add(o); + } + Object[] metrics = tmp.ToArray(); + Array.Sort(metrics, this); + PdfIndirectReference ind_font = null; + PdfObject pobj = null; + PdfIndirectObject obj = null; + PdfIndirectReference cidset = null; + if (writer.PDFXConformance == PdfWriter.PDFA1A || writer.PDFXConformance == PdfWriter.PDFA1B) { + PdfStream stream; + if (metrics.Length == 0) { + stream = new PdfStream(new byte[]{(byte)0x80}); + } + else { + int top = ((int[])metrics[metrics.Length - 1])[0]; + byte[] bt = new byte[top / 8 + 1]; + for (int k = 0; k < metrics.Length; ++k) { + int v = ((int[])metrics[k])[0]; + bt[v / 8] |= rotbits[v % 8]; + } + stream = new PdfStream(bt); + stream.FlateCompress(); + } + cidset = writer.AddToBody(stream).IndirectReference; + } + // sivan: cff + if (cff) { + RandomAccessFileOrArray rf2 = new RandomAccessFileOrArray(rf); + byte[] b = new byte[cffLength]; + try { + rf2.ReOpen(); + rf2.Seek(cffOffset); + rf2.ReadFully(b); + } finally { + try { + rf2.Close(); + } catch { + // empty on purpose + } + } + if (subset || subsetRanges != null) { + CFFFontSubset cffs = new CFFFontSubset(new RandomAccessFileOrArray(b),longTag); + b = cffs.Process( (cffs.GetNames())[0] ); + } + + pobj = new StreamFont(b, "CIDFontType0C"); + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } else { + byte[] b; + if (subset || directoryOffset != 0) { + TrueTypeFontSubSet sb = new TrueTypeFontSubSet(fileName, new RandomAccessFileOrArray(rf), longTag, directoryOffset, false, false); + b = sb.Process(); + } + else { + b = GetFullFont(); + } + int[] lengths = new int[]{b.Length}; + pobj = new StreamFont(b, lengths); + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + String subsetPrefix = ""; + if (subset) + subsetPrefix = CreateSubsetPrefix(); + PdfDictionary dic = GetFontDescriptor(ind_font, subsetPrefix, cidset); + obj = writer.AddToBody(dic); + ind_font = obj.IndirectReference; + + pobj = GetCIDFontType2(ind_font, subsetPrefix, metrics); + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + + pobj = GetToUnicode(metrics); + PdfIndirectReference toUnicodeRef = null; + if (pobj != null) { + obj = writer.AddToBody(pobj); + toUnicodeRef = obj.IndirectReference; + } + + pobj = GetFontBaseType(ind_font, subsetPrefix, toUnicodeRef); + writer.AddToBody(pobj, piref); + } + + /** A forbidden operation. Will throw a null pointer exception. + * @param text the text + * @return always null + */ + internal override byte[] ConvertToBytes(string text) { + return null; + } + + internal override byte[] ConvertToBytes(int char1) { + return null; + } + + /** Gets the glyph index and metrics for a character. + * @param c the character + * @return an int array with {glyph index, width} + */ + public override int[] GetMetricsTT(int c) { + if (cmapExt != null) + return (int[])cmapExt[c]; + Hashtable map = null; + if (fontSpecific) + map = cmap10; + else + map = cmap31; + if (map == null) + return null; + if (fontSpecific) { + if ((c & 0xffffff00) == 0 || (c & 0xffffff00) == 0xf000) + return (int[])map[c & 0xff]; + else + return null; + } + else + return (int[])map[c]; + } + + /** + * Checks if a character exists in this font. + * @param c the character to check + * @return true if the character has a glyph, + * false otherwise + */ + public override bool CharExists(int c) { + return GetMetricsTT(c) != null; + } + + /** + * Sets the character advance. + * @param c the character + * @param advance the character advance normalized to 1000 units + * @return true if the advance was set, + * false otherwise + */ + public override bool SetCharAdvance(int c, int advance) { + int[] m = GetMetricsTT(c); + if (m == null) + return false; + m[1] = advance; + return true; + } + + public override int[] GetCharBBox(int c) { + if (bboxes == null) + return null; + int[] m = GetMetricsTT(c); + if (m == null) + return null; + return bboxes[m[0]]; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/Type1Font.cs b/iTechSharp/iTextSharp/text/pdf/Type1Font.cs new file mode 100644 index 0000000..dcd94fd --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Type1Font.cs @@ -0,0 +1,796 @@ +using System; +using System.IO; +using System.Collections; +using System.util; + +/* + * $Id: Type1Font.cs,v 1.13 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Reads a Type1 font + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class Type1Font : BaseFont { + /** The PFB file if the input was made with a byte array. + */ + protected byte[] pfb; + /** The Postscript font name. + */ + private string FontName; + /** The full name of the font. + */ + private string FullName; + /** The family name of the font. + */ + private string FamilyName; + /** The weight of the font: normal, bold, etc. + */ + private string Weight = ""; + /** The italic angle of the font, usually 0.0 or negative. + */ + private float ItalicAngle = 0.0f; + /** true if all the characters have the same + * width. + */ + private bool IsFixedPitch = false; + /** The character set of the font. + */ + private string CharacterSet; + /** The llx of the FontBox. + */ + private int llx = -50; + /** The lly of the FontBox. + */ + private int lly = -200; + /** The lurx of the FontBox. + */ + private int urx = 1000; + /** The ury of the FontBox. + */ + private int ury = 900; + /** The underline position. + */ + private int UnderlinePosition = -100; + /** The underline thickness. + */ + private int UnderlineThickness = 50; + /** The font's encoding name. This encoding is 'StandardEncoding' or + * 'AdobeStandardEncoding' for a font that can be totally encoded + * according to the characters names. For all other names the + * font is treated as symbolic. + */ + private string EncodingScheme = "FontSpecific"; + /** A variable. + */ + private int CapHeight = 700; + /** A variable. + */ + private int XHeight = 480; + /** A variable. + */ + private int Ascender = 800; + /** A variable. + */ + private int Descender = -200; + /** A variable. + */ + private int StdHW; + /** A variable. + */ + private int StdVW = 80; + + /** Represents the section CharMetrics in the AFM file. Each + * value of this array contains a Object[4] with an + * Integer, Integer, String and int[]. This is the code, width, name and char bbox. + * The key is the name of the char and also an Integer with the char number. + */ + private Hashtable CharMetrics = new Hashtable(); + /** Represents the section KernPairs in the AFM file. The key is + * the name of the first character and the value is a Object[] + * with 2 elements for each kern pair. Position 0 is the name of + * the second character and position 1 is the kerning distance. This is + * repeated for all the pairs. + */ + private Hashtable KernPairs = new Hashtable(); + /** The file in use. + */ + private string fileName; + /** true if this font is one of the 14 built in fonts. + */ + private bool builtinFont = false; + /** Types of records in a PFB file. ASCII is 1 and BINARY is 2. + * They have to appear in the PFB file in this sequence. + */ + private static readonly int[] PFB_TYPES = {1, 2, 1}; + + /** Creates a new Type1 font. + * @param ttfAfm the AFM file if the input is made with a byte array + * @param pfb the PFB file if the input is made with a byte array + * @param afmFile the name of one of the 14 built-in fonts or the location of an AFM file. The file must end in '.afm' + * @param enc the encoding to be applied to this font + * @param emb true if the font is to be embedded in the PDF + * @throws DocumentException the AFM file is invalid + * @throws IOException the AFM file could not be read + */ + internal Type1Font(string afmFile, string enc, bool emb, byte[] ttfAfm, byte[] pfb) { + if (emb && ttfAfm != null && pfb == null) + throw new DocumentException("Two byte arrays are needed if the Type1 font is embedded."); + if (emb && ttfAfm != null) + this.pfb = pfb; + encoding = enc; + embedded = emb; + fileName = afmFile; + FontType = FONT_TYPE_T1; + RandomAccessFileOrArray rf = null; + Stream istr = null; + if (BuiltinFonts14.ContainsKey(afmFile)) { + embedded = false; + builtinFont = true; + byte[] buf = new byte[1024]; + try { + istr = GetResourceStream(RESOURCE_PATH + afmFile + ".afm"); + if (istr == null) { + Console.Error.WriteLine(afmFile + " not found as resource."); + throw new DocumentException(afmFile + " not found as resource."); + } + MemoryStream ostr = new MemoryStream(); + while (true) { + int size = istr.Read(buf, 0, buf.Length); + if (size == 0) + break; + ostr.Write(buf, 0, size); + } + buf = ostr.ToArray(); + } + finally { + if (istr != null) { + try { + istr.Close(); + } + catch { + // empty on purpose + } + } + } + try { + rf = new RandomAccessFileOrArray(buf); + Process(rf); + } + finally { + if (rf != null) { + try { + rf.Close(); + } + catch { + // empty on purpose + } + } + } + } + else if (afmFile.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".afm")) { + try { + if (ttfAfm == null) + rf = new RandomAccessFileOrArray(afmFile); + else + rf = new RandomAccessFileOrArray(ttfAfm); + Process(rf); + } + finally { + if (rf != null) { + try { + rf.Close(); + } + catch { + // empty on purpose + } + } + } + } + else if (afmFile.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".pfm")) { + try { + MemoryStream ba = new MemoryStream(); + if (ttfAfm == null) + rf = new RandomAccessFileOrArray(afmFile); + else + rf = new RandomAccessFileOrArray(ttfAfm); + Pfm2afm.Convert(rf, ba); + rf.Close(); + rf = new RandomAccessFileOrArray(ba.ToArray()); + Process(rf); + } + finally { + if (rf != null) { + try { + rf.Close(); + } + catch { + // empty on purpose + } + } + } + } + else + throw new DocumentException(afmFile + " is not an AFM or PFM font file."); + EncodingScheme = EncodingScheme.Trim(); + if (EncodingScheme.Equals("AdobeStandardEncoding") || EncodingScheme.Equals("StandardEncoding")) { + fontSpecific = false; + } + if (!encoding.StartsWith("#")) + PdfEncodings.ConvertToBytes(" ", enc); // check if the encoding exists + CreateEncoding(); + } + + /** Gets the width from the font according to the name or, + * if the name is null, meaning it is a symbolic font, + * the char c. + * @param c the char if the font is symbolic + * @param name the glyph name + * @return the width of the char + */ + internal override int GetRawWidth(int c, string name) { + Object[] metrics; + if (name == null) { // font specific + metrics = (Object[])CharMetrics[c]; + } + else { + if (name.Equals(".notdef")) + return 0; + metrics = (Object[])CharMetrics[name]; + } + if (metrics != null) + return (int)metrics[1]; + return 0; + } + + /** Gets the kerning between two Unicode characters. The characters + * are converted to names and this names are used to find the kerning + * pairs in the Hashtable KernPairs. + * @param char1 the first char + * @param char2 the second char + * @return the kerning to be applied + */ + public override int GetKerning(int char1, int char2) { + string first = GlyphList.UnicodeToName((int)char1); + if (first == null) + return 0; + string second = GlyphList.UnicodeToName((int)char2); + if (second == null) + return 0; + Object[] obj = (Object[])KernPairs[first]; + if (obj == null) + return 0; + for (int k = 0; k < obj.Length; k += 2) { + if (second.Equals(obj[k])) + return (int)obj[k + 1]; + } + return 0; + } + + + /** Reads the font metrics + * @param rf the AFM file + * @throws DocumentException the AFM file is invalid + * @throws IOException the AFM file could not be read + */ + public void Process(RandomAccessFileOrArray rf) { + string line; + bool isMetrics = false; + while ((line = rf.ReadLine()) != null) { + StringTokenizer tok = new StringTokenizer(line, " ,\n\r\t\f"); + if (!tok.HasMoreTokens()) + continue; + string ident = tok.NextToken(); + if (ident.Equals("FontName")) + FontName = tok.NextToken("\u00ff").Substring(1); + else if (ident.Equals("FullName")) + FullName = tok.NextToken("\u00ff").Substring(1); + else if (ident.Equals("FamilyName")) + FamilyName = tok.NextToken("\u00ff").Substring(1); + else if (ident.Equals("Weight")) + Weight = tok.NextToken("\u00ff").Substring(1); + else if (ident.Equals("ItalicAngle")) + ItalicAngle = float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("IsFixedPitch")) + IsFixedPitch = tok.NextToken().Equals("true"); + else if (ident.Equals("CharacterSet")) + CharacterSet = tok.NextToken("\u00ff").Substring(1); + else if (ident.Equals("FontBBox")) { + llx = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + lly = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + urx = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + ury = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + } + else if (ident.Equals("UnderlinePosition")) + UnderlinePosition = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("UnderlineThickness")) + UnderlineThickness = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("EncodingScheme")) + EncodingScheme = tok.NextToken("\u00ff").Substring(1); + else if (ident.Equals("CapHeight")) + CapHeight = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("XHeight")) + XHeight = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("Ascender")) + Ascender = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("Descender")) + Descender = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("StdHW")) + StdHW = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("StdVW")) + StdVW = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("StartCharMetrics")) { + isMetrics = true; + break; + } + } + if (!isMetrics) + throw new DocumentException("Missing StartCharMetrics in " + fileName); + while ((line = rf.ReadLine()) != null) { + StringTokenizer tok = new StringTokenizer(line); + if (!tok.HasMoreTokens()) + continue; + string ident = tok.NextToken(); + if (ident.Equals("EndCharMetrics")) { + isMetrics = false; + break; + } + int C = -1; + int WX = 250; + string N = ""; + int[] B = null; + + tok = new StringTokenizer(line, ";"); + while (tok.HasMoreTokens()) + { + StringTokenizer tokc = new StringTokenizer(tok.NextToken()); + if (!tokc.HasMoreTokens()) + continue; + ident = tokc.NextToken(); + if (ident.Equals("C")) + C = int.Parse(tokc.NextToken()); + else if (ident.Equals("WX")) + WX = (int)float.Parse(tokc.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + else if (ident.Equals("N")) + N = tokc.NextToken(); + else if (ident.Equals("B")) { + B = new int[]{int.Parse(tokc.NextToken()), + int.Parse(tokc.NextToken()), + int.Parse(tokc.NextToken()), + int.Parse(tokc.NextToken())}; + } + } + Object[] metrics = new Object[]{C, WX, N, B}; + if (C >= 0) + CharMetrics[C] = metrics; + CharMetrics[N] = metrics; + } + if (isMetrics) + throw new DocumentException("Missing EndCharMetrics in " + fileName); + if (!CharMetrics.ContainsKey("nonbreakingspace")) { + Object[] space = (Object[])CharMetrics["space"]; + if (space != null) + CharMetrics["nonbreakingspace"] = space; + } + while ((line = rf.ReadLine()) != null) { + StringTokenizer tok = new StringTokenizer(line); + if (!tok.HasMoreTokens()) + continue; + string ident = tok.NextToken(); + if (ident.Equals("EndFontMetrics")) + return; + if (ident.Equals("StartKernPairs")) { + isMetrics = true; + break; + } + } + if (!isMetrics) + throw new DocumentException("Missing EndFontMetrics in " + fileName); + while ((line = rf.ReadLine()) != null) { + StringTokenizer tok = new StringTokenizer(line); + if (!tok.HasMoreTokens()) + continue; + string ident = tok.NextToken(); + if (ident.Equals("KPX")) { + string first = tok.NextToken(); + string second = tok.NextToken(); + int width = (int)float.Parse(tok.NextToken(), System.Globalization.NumberFormatInfo.InvariantInfo); + Object[] relates = (Object[])KernPairs[first]; + if (relates == null) + KernPairs[first] = new Object[]{second, width}; + else { + int n = relates.Length; + Object[] relates2 = new Object[n + 2]; + Array.Copy(relates, 0, relates2, 0, n); + relates2[n] = second; + relates2[n + 1] = width; + KernPairs[first] = relates2; + } + } + else if (ident.Equals("EndKernPairs")) { + isMetrics = false; + break; + } + } + if (isMetrics) + throw new DocumentException("Missing EndKernPairs in " + fileName); + rf.Close(); + } + + /** If the embedded flag is false or if the font is + * one of the 14 built in types, it returns null, + * otherwise the font is read and output in a PdfStream object. + * @return the PdfStream containing the font or null + * @throws DocumentException if there is an error reading the font + */ + private PdfStream GetFontStream() { + if (builtinFont || !embedded) + return null; + RandomAccessFileOrArray rf = null; + try { + string filePfb = fileName.Substring(0, fileName.Length - 3) + "pfb"; + if (pfb == null) + rf = new RandomAccessFileOrArray(filePfb); + else + rf = new RandomAccessFileOrArray(pfb); + int fileLength = rf.Length; + byte[] st = new byte[fileLength - 18]; + int[] lengths = new int[3]; + int bytePtr = 0; + for (int k = 0; k < 3; ++k) { + if (rf.Read() != 0x80) + throw new DocumentException("Start marker missing in " + filePfb); + if (rf.Read() != PFB_TYPES[k]) + throw new DocumentException("Incorrect segment type in " + filePfb); + int size = rf.Read(); + size += rf.Read() << 8; + size += rf.Read() << 16; + size += rf.Read() << 24; + lengths[k] = size; + while (size != 0) { + int got = rf.Read(st, bytePtr, size); + if (got < 0) + throw new DocumentException("Premature end in " + filePfb); + bytePtr += got; + size -= got; + } + } + return new StreamFont(st, lengths); + } + finally { + if (rf != null) { + try { + rf.Close(); + } + catch { + // empty on purpose + } + } + } + } + + /** Generates the font descriptor for this font or null if it is + * one of the 14 built in fonts. + * @param fontStream the indirect reference to a PdfStream containing the font or null + * @return the PdfDictionary containing the font descriptor or null + */ + public PdfDictionary GetFontDescriptor(PdfIndirectReference fontStream) { + if (builtinFont) + return null; + PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR); + dic.Put(PdfName.ASCENT, new PdfNumber(Ascender)); + dic.Put(PdfName.CAPHEIGHT, new PdfNumber(CapHeight)); + dic.Put(PdfName.DESCENT, new PdfNumber(Descender)); + dic.Put(PdfName.FONTBBOX, new PdfRectangle(llx, lly, urx, ury)); + dic.Put(PdfName.FONTNAME, new PdfName(FontName)); + dic.Put(PdfName.ITALICANGLE, new PdfNumber(ItalicAngle)); + dic.Put(PdfName.STEMV, new PdfNumber(StdVW)); + if (fontStream != null) + dic.Put(PdfName.FONTFILE, fontStream); + int flags = 0; + if (IsFixedPitch) + flags |= 1; + flags |= fontSpecific ? 4 : 32; + if (ItalicAngle < 0) + flags |= 64; + if (FontName.IndexOf("Caps") >= 0 || FontName.EndsWith("SC")) + flags |= 131072; + if (Weight.Equals("Bold")) + flags |= 262144; + dic.Put(PdfName.FLAGS, new PdfNumber(flags)); + + return dic; + } + + /** Generates the font dictionary for this font. + * @return the PdfDictionary containing the font dictionary + * @param firstChar the first valid character + * @param lastChar the last valid character + * @param shortTag a 256 bytes long byte array where each unused byte is represented by 0 + * @param fontDescriptor the indirect reference to a PdfDictionary containing the font descriptor or null + */ + private PdfDictionary GetFontBaseType(PdfIndirectReference fontDescriptor, int firstChar, int lastChar, byte[] shortTag) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + dic.Put(PdfName.BASEFONT, new PdfName(FontName)); + bool stdEncoding = encoding.Equals(CP1252) || encoding.Equals(MACROMAN); + if (!fontSpecific || specialMap != null) { + for (int k = firstChar; k <= lastChar; ++k) { + if (!differences[k].Equals(notdef)) { + firstChar = k; + break; + } + } + if (stdEncoding) + dic.Put(PdfName.ENCODING, encoding.Equals(CP1252) ? PdfName.WIN_ANSI_ENCODING : PdfName.MAC_ROMAN_ENCODING); + else { + PdfDictionary enc = new PdfDictionary(PdfName.ENCODING); + PdfArray dif = new PdfArray(); + bool gap = true; + for (int k = firstChar; k <= lastChar; ++k) { + if (shortTag[k] != 0) { + if (gap) { + dif.Add(new PdfNumber(k)); + gap = false; + } + dif.Add(new PdfName(differences[k])); + } + else + gap = true; + } + enc.Put(PdfName.DIFFERENCES, dif); + dic.Put(PdfName.ENCODING, enc); + } + } + if (specialMap != null || forceWidthsOutput || !(builtinFont && (fontSpecific || stdEncoding))) { + dic.Put(PdfName.FIRSTCHAR, new PdfNumber(firstChar)); + dic.Put(PdfName.LASTCHAR, new PdfNumber(lastChar)); + PdfArray wd = new PdfArray(); + for (int k = firstChar; k <= lastChar; ++k) { + if (shortTag[k] == 0) + wd.Add(new PdfNumber(0)); + else + wd.Add(new PdfNumber(widths[k])); + } + dic.Put(PdfName.WIDTHS, wd); + } + if (!builtinFont && fontDescriptor != null) + dic.Put(PdfName.FONTDESCRIPTOR, fontDescriptor); + return dic; + } + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param parms several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + */ + internal override void WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) { + int firstChar = (int)parms[0]; + int lastChar = (int)parms[1]; + byte[] shortTag = (byte[])parms[2]; + bool subsetp = (bool)parms[3] && subset; + if (!subsetp) { + firstChar = 0; + lastChar = shortTag.Length - 1; + for (int k = 0; k < shortTag.Length; ++k) + shortTag[k] = 1; + } + PdfIndirectReference ind_font = null; + PdfObject pobj = null; + PdfIndirectObject obj = null; + pobj = GetFontStream(); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetFontDescriptor(ind_font); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetFontBaseType(ind_font, firstChar, lastChar, shortTag); + writer.AddToBody(pobj, piref); + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT, + * ITALICANGLE, BBOXLLX, BBOXLLY, BBOXURX + * and BBOXURY. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + */ + public override float GetFontDescriptor(int key, float fontSize) { + switch (key) { + case AWT_ASCENT: + case ASCENT: + return Ascender * fontSize / 1000; + case CAPHEIGHT: + return CapHeight * fontSize / 1000; + case AWT_DESCENT: + case DESCENT: + return Descender * fontSize / 1000; + case ITALICANGLE: + return ItalicAngle; + case BBOXLLX: + return llx * fontSize / 1000; + case BBOXLLY: + return lly * fontSize / 1000; + case BBOXURX: + return urx * fontSize / 1000; + case BBOXURY: + return ury * fontSize / 1000; + case AWT_LEADING: + return 0; + case AWT_MAXADVANCE: + return (urx - llx) * fontSize / 1000; + case UNDERLINE_POSITION: + return UnderlinePosition * fontSize / 1000; + case UNDERLINE_THICKNESS: + return UnderlineThickness * fontSize / 1000; + } + return 0; + } + + /** Gets the postscript font name. + * @return the postscript font name + */ + public override string PostscriptFontName { + get { + return FontName; + } + set { + FontName = value; + } + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] FullFontName { + get { + return new string[][]{new string[] {"", "", "", FullName}}; + } + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] AllNameEntries { + get { + return new string[][]{new string[]{"4", "", "", "", FullName}}; + } + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + */ + public override string[][] FamilyFontName { + get { + return new string[][]{new string[] {"", "", "", FamilyName}}; + } + } + + /** Checks if the font has any kerning pairs. + * @return true if the font has any kerning pairs + */ + public override bool HasKernPairs() { + return KernPairs.Count > 0; + } + + /** + * Sets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @param kern the kerning to apply in normalized 1000 units + * @return true if the kerning was applied, false otherwise + */ + public override bool SetKerning(int char1, int char2, int kern) { + String first = GlyphList.UnicodeToName((int)char1); + if (first == null) + return false; + String second = GlyphList.UnicodeToName((int)char2); + if (second == null) + return false; + Object[] obj = (Object[])KernPairs[first]; + if (obj == null) { + obj = new Object[]{second, kern}; + KernPairs[first] = obj; + return true; + } + for (int k = 0; k < obj.Length; k += 2) { + if (second.Equals(obj[k])) { + obj[k + 1] = kern; + return true; + } + } + int size = obj.Length; + Object[] obj2 = new Object[size + 2]; + Array.Copy(obj, 0, obj2, 0, size); + obj2[size] = second; + obj2[size + 1] = kern; + KernPairs[first] = obj2; + return true; + } + + protected override int[] GetRawCharBBox(int c, String name) { + Object[] metrics; + if (name == null) { // font specific + metrics = (Object[])CharMetrics[c]; + } + else { + if (name.Equals(".notdef")) + return null; + metrics = (Object[])CharMetrics[name]; + } + if (metrics != null) + return ((int[])(metrics[3])); + return null; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/Type3Font.cs b/iTechSharp/iTextSharp/text/pdf/Type3Font.cs new file mode 100644 index 0000000..a707102 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Type3Font.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A class to support Type3 fonts. + */ + public class Type3Font : BaseFont { + + private bool[] usedSlot; + private IntHashtable widths3 = new IntHashtable(); + private Hashtable char2glyph = new Hashtable(); + private PdfWriter writer; + private float llx = float.NaN, lly, urx, ury; + private PageResources pageResources = new PageResources(); + private bool colorized; + + /** + * Creates a Type3 font. + * @param writer the writer + * @param chars an array of chars corresponding to the glyphs used (not used, prisent for compability only) + * @param colorized if true the font may specify color, if false no color commands are allowed + * and only images as masks can be used + */ + public Type3Font(PdfWriter writer, char[] chars, bool colorized) : this(writer, colorized) { + } + + /** + * Creates a Type3 font. This implementation assumes that the /FontMatrix is + * [0.001 0 0 0.001 0 0] or a 1000-unit glyph coordinate system. + *

    + * An example: + *

    + *

    +        * Document document = new Document(PageSize.A4);
    +        * PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("type3.pdf"));
    +        * document.open();
    +        * Type3Font t3 = new Type3Font(writer, false);
    +        * PdfContentByte g = t3.defineGlyph('a', 1000, 0, 0, 750, 750);
    +        * g.rectangle(0, 0, 750, 750);
    +        * g.fill();
    +        * g = t3.defineGlyph('b', 1000, 0, 0, 750, 750);
    +        * g.moveTo(0, 0);
    +        * g.lineTo(375, 750);
    +        * g.lineTo(750, 0);
    +        * g.fill();
    +        * Font f = new Font(t3, 12);
    +        * document.add(new Paragraph("ababab", f));
    +        * document.close();
    +        * 
    + * @param writer the writer + * @param colorized if true the font may specify color, if false no color commands are allowed + * and only images as masks can be used + */ + public Type3Font(PdfWriter writer, bool colorized) { + this.writer = writer; + this.colorized = colorized; + fontType = FONT_TYPE_T3; + usedSlot = new bool[256]; + } + + /** + * Defines a glyph. If the character was already defined it will return the same content + * @param c the character to match this glyph. + * @param wx the advance this character will have + * @param llx the X lower left corner of the glyph bounding box. If the colorize option is + * true the value is ignored + * @param lly the Y lower left corner of the glyph bounding box. If the colorize option is + * true the value is ignored + * @param urx the X upper right corner of the glyph bounding box. If the colorize option is + * true the value is ignored + * @param ury the Y upper right corner of the glyph bounding box. If the colorize option is + * true the value is ignored + * @return a content where the glyph can be defined + */ + public PdfContentByte DefineGlyph(char c, float wx, float llx, float lly, float urx, float ury) { + if (c == 0 || c > 255) + throw new ArgumentException("The char " + (int)c + " doesn't belong in this Type3 font"); + usedSlot[c] = true; + Type3Glyph glyph = (Type3Glyph)char2glyph[c]; + if (glyph != null) + return glyph; + widths3[c] = (int)wx; + if (!colorized) { + if (float.IsNaN(this.llx)) { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + else { + this.llx = Math.Min(this.llx, llx); + this.lly = Math.Min(this.lly, lly); + this.urx = Math.Max(this.urx, urx); + this.ury = Math.Max(this.ury, ury); + } + } + glyph = new Type3Glyph(writer, pageResources, wx, llx, lly, urx, ury, colorized); + char2glyph[c] = glyph; + return glyph; + } + + public override String[][] FamilyFontName { + get { + return FullFontName; + } + } + + public override float GetFontDescriptor(int key, float fontSize) { + return 0; + } + + public override String[][] FullFontName { + get { + return new string[][]{new string[]{"", "", "", ""}}; + } + } + + public override string[][] AllNameEntries { + get { + return new string[][]{new string[]{"4", "", "", "", ""}}; + } + } + + public override int GetKerning(int char1, int char2) { + return 0; + } + + public override string PostscriptFontName { + get { + return ""; + } + set { + } + } + + protected override int[] GetRawCharBBox(int c, String name) { + return null; + } + + internal override int GetRawWidth(int c, String name) { + return 0; + } + + public override bool HasKernPairs() { + return false; + } + + public override bool SetKerning(int char1, int char2, int kern) { + return false; + } + + internal override void WriteFont(PdfWriter writer, PdfIndirectReference piRef, Object[] oParams) { + if (this.writer != writer) + throw new ArgumentException("Type3 font used with the wrong PdfWriter"); + // Get first & lastchar ... + int firstChar = 0; + while( firstChar < usedSlot.Length && !usedSlot[firstChar] ) firstChar++; + + if ( firstChar == usedSlot.Length ) { + throw new DocumentException( "No glyphs defined for Type3 font" ); + } + int lastChar = usedSlot.Length - 1; + while( lastChar >= firstChar && !usedSlot[lastChar] ) lastChar--; + + int[] widths = new int[lastChar - firstChar + 1]; + int[] invOrd = new int[lastChar - firstChar + 1]; + + int invOrdIndx = 0, w = 0; + for( int u = firstChar; u<=lastChar; u++, w++ ) { + if ( usedSlot[u] ) { + invOrd[invOrdIndx++] = u; + widths[w] = widths3[u]; + } + } + PdfArray diffs = new PdfArray(); + PdfDictionary charprocs = new PdfDictionary(); + int last = -1; + for (int k = 0; k < invOrdIndx; ++k) { + int c = invOrd[k]; + if (c > last) { + last = c; + diffs.Add(new PdfNumber(last)); + } + ++last; + int c2 = invOrd[k]; + String s = GlyphList.UnicodeToName(c2); + if (s == null) + s = "a" + c2; + PdfName n = new PdfName(s); + diffs.Add(n); + Type3Glyph glyph = (Type3Glyph)char2glyph[(char)c2]; + PdfStream stream = new PdfStream(glyph.ToPdf(null)); + stream.FlateCompress(); + PdfIndirectReference refp = writer.AddToBody(stream).IndirectReference; + charprocs.Put(n, refp); + } + PdfDictionary font = new PdfDictionary(PdfName.FONT); + font.Put(PdfName.SUBTYPE, PdfName.TYPE3); + if (colorized) + font.Put(PdfName.FONTBBOX, new PdfRectangle(0, 0, 0, 0)); + else + font.Put(PdfName.FONTBBOX, new PdfRectangle(llx, lly, urx, ury)); + font.Put(PdfName.FONTMATRIX, new PdfArray(new float[]{0.001f, 0, 0, 0.001f, 0, 0})); + font.Put(PdfName.CHARPROCS, writer.AddToBody(charprocs).IndirectReference); + PdfDictionary encoding = new PdfDictionary(); + encoding.Put(PdfName.DIFFERENCES, diffs); + font.Put(PdfName.ENCODING, writer.AddToBody(encoding).IndirectReference); + font.Put(PdfName.FIRSTCHAR, new PdfNumber(firstChar)); + font.Put(PdfName.LASTCHAR, new PdfNumber(lastChar)); + font.Put(PdfName.WIDTHS, writer.AddToBody(new PdfArray(widths)).IndirectReference); + if (pageResources.HasResources()) + font.Put(PdfName.RESOURCES, writer.AddToBody(pageResources.Resources).IndirectReference); + writer.AddToBody(font, piRef); + } + + internal override byte[] ConvertToBytes(String text) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int p = 0; + for (int k = 0; k < cc.Length; ++k) { + char c = cc[k]; + if (CharExists(c)) + b[p++] = (byte)c; + } + if (b.Length == p) + return b; + byte[] b2 = new byte[p]; + Array.Copy(b, 0, b2, 0, p); + return b2; + } + + internal override byte[] ConvertToBytes(int char1) { + if (CharExists(char1)) + return new byte[]{(byte)char1}; + else return new byte[0]; + } + + public override int GetWidth(int char1) { + if (!widths3.ContainsKey(char1)) + throw new ArgumentException("The char " + (int)char1 + " is not defined in a Type3 font"); + return widths3[char1]; + } + + public override int GetWidth(String text) { + char[] c = text.ToCharArray(); + int total = 0; + for (int k = 0; k < c.Length; ++k) + total += GetWidth(c[k]); + return total; + } + + public override int[] GetCharBBox(int c) { + return null; + } + + public override bool CharExists(int c) { + if ( c > 0 && c < 256 ) { + return usedSlot[c]; + } else { + return false; + } + } + + public override bool SetCharAdvance(int c, int advance) { + return false; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/Type3Glyph.cs b/iTechSharp/iTextSharp/text/pdf/Type3Glyph.cs new file mode 100644 index 0000000..cce6c71 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Type3Glyph.cs @@ -0,0 +1,94 @@ +using System; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * The content where Type3 glyphs are written to. + */ + public sealed class Type3Glyph : PdfContentByte { + + private PageResources pageResources; + private bool colorized; + + private Type3Glyph() : base(null) { + } + + internal Type3Glyph(PdfWriter writer, PageResources pageResources, float wx, float llx, float lly, float urx, float ury, bool colorized) : base(writer) { + this.pageResources = pageResources; + this.colorized = colorized; + if (colorized) { + content.Append(wx).Append(" 0 d0\n"); + } + else { + content.Append(wx).Append(" 0 ").Append(llx).Append(' ').Append(lly).Append(' ').Append(urx).Append(' ').Append(ury).Append(" d1\n"); + } + } + + internal override PageResources PageResources { + get { + return pageResources; + } + } + + public override void AddImage(Image image, float a, float b, float c, float d, float e, float f, bool inlineImage) { + if (!colorized && (!image.IsMask() || !(image.Bpc == 1 || image.Bpc > 0xff))) + throw new DocumentException("Not colorized Typed3 fonts only accept mask images."); + base.AddImage(image, a, b, c, d, e, f, inlineImage); + } + + public PdfContentByte GetDuplicate() { + Type3Glyph dup = new Type3Glyph(); + dup.writer = writer; + dup.pdf = pdf; + dup.pageResources = pageResources; + dup.colorized = colorized; + return dup; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/VerticalText.cs b/iTechSharp/iTextSharp/text/pdf/VerticalText.cs new file mode 100644 index 0000000..05ce4c0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/VerticalText.cs @@ -0,0 +1,344 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Writes text vertically. Note that the naming is done according + * to horizontal text although it referrs to vertical text. + * A line with the alignment Element.LEFT_ALIGN will actually + * be top aligned. + */ + public class VerticalText { + + /** Signals that there are no more text available. */ + public static int NO_MORE_TEXT = 1; + + /** Signals that there is no more column. */ + public static int NO_MORE_COLUMN = 2; + + /** The chunks that form the text. */ + protected ArrayList chunks = new ArrayList(); + + /** The PdfContent where the text will be written to. */ + protected PdfContentByte text; + + /** The column Element. Default is left Element. */ + protected int alignment = Element.ALIGN_LEFT; + + /** Marks the chunks to be eliminated when the line is written. */ + protected int currentChunkMarker = -1; + + /** The chunk created by the splitting. */ + protected PdfChunk currentStandbyChunk; + + /** The chunk created by the splitting. */ + protected string splittedChunkText; + + /** The leading + */ + protected float leading; + + /** The X coordinate. + */ + protected float startX; + + /** The Y coordinate. + */ + protected float startY; + + /** The maximum number of vertical lines. + */ + protected int maxLines; + + /** The height of the text. + */ + protected float height; + + /** Creates new VerticalText + * @param text the place where the text will be written to. Can + * be a template. + */ + public VerticalText(PdfContentByte text) { + this.text = text; + } + + /** + * Adds a Phrase to the current text array. + * @param phrase the text + */ + public void AddText(Phrase phrase) { + foreach(Chunk c in phrase.Chunks) { + chunks.Add(new PdfChunk(c, null)); + } + } + + /** + * Adds a Chunk to the current text array. + * @param chunk the text + */ + public void AddText(Chunk chunk) { + chunks.Add(new PdfChunk(chunk, null)); + } + + /** Sets the layout. + * @param startX the top right X line position + * @param startY the top right Y line position + * @param height the height of the lines + * @param maxLines the maximum number of lines + * @param leading the separation between the lines + */ + public void SetVerticalLayout(float startX, float startY, float height, int maxLines, float leading) { + this.startX = startX; + this.startY = startY; + this.height = height; + this.maxLines = maxLines; + Leading = leading; + } + + /** Gets the separation between the vertical lines. + * @return the vertical line separation + */ + public float Leading { + get { + return leading; + } + + set { + this.leading = value; + } + } + + /** + * Creates a line from the chunk array. + * @param width the width of the line + * @return the line or null if no more chunks + */ + protected PdfLine CreateLine(float width) { + if (chunks.Count == 0) + return null; + splittedChunkText = null; + currentStandbyChunk = null; + PdfLine line = new PdfLine(0, width, alignment, 0); + string total; + for (currentChunkMarker = 0; currentChunkMarker < chunks.Count; ++currentChunkMarker) { + PdfChunk original = (PdfChunk)(chunks[currentChunkMarker]); + total = original.ToString(); + currentStandbyChunk = line.Add(original); + if (currentStandbyChunk != null) { + splittedChunkText = original.ToString(); + original.Value = total; + return line; + } + } + return line; + } + + /** + * Normalizes the list of chunks when the line is accepted. + */ + protected void ShortenChunkArray() { + if (currentChunkMarker < 0) + return; + if (currentChunkMarker >= chunks.Count) { + chunks.Clear(); + return; + } + PdfChunk split = (PdfChunk)(chunks[currentChunkMarker]); + split.Value = splittedChunkText; + chunks[currentChunkMarker] = currentStandbyChunk; + for (int j = currentChunkMarker - 1; j >= 0; --j) + chunks.RemoveAt(j); + } + + /** + * Outputs the lines to the document. It is equivalent to go(false). + * @return returns the result of the operation. It can be NO_MORE_TEXT + * and/or NO_MORE_COLUMN + * @throws DocumentException on error + */ + public int Go() { + return Go(false); + } + + /** + * Outputs the lines to the document. The output can be simulated. + * @param simulate true to simulate the writting to the document + * @return returns the result of the operation. It can be NO_MORE_TEXT + * and/or NO_MORE_COLUMN + * @throws DocumentException on error + */ + public int Go(bool simulate) { + bool dirty = false; + PdfContentByte graphics = null; + if (text != null) { + graphics = text.Duplicate; + } + else if (!simulate) + throw new Exception("VerticalText.go with simulate==false and text==null."); + int status = 0; + for (;;) { + if (maxLines <= 0) { + status = NO_MORE_COLUMN; + if (chunks.Count == 0) + status |= NO_MORE_TEXT; + break; + } + if (chunks.Count == 0) { + status = NO_MORE_TEXT; + break; + } + PdfLine line = CreateLine(height); + if (!simulate && !dirty) { + text.BeginText(); + dirty = true; + } + ShortenChunkArray(); + if (!simulate) { + text.SetTextMatrix(startX, startY - line.IndentLeft); + WriteLine(line, text, graphics); + } + --maxLines; + startX -= leading; + } + if (dirty) { + text.EndText(); + text.Add(graphics); + } + return status; + } + + internal void WriteLine(PdfLine line, PdfContentByte text, PdfContentByte graphics) { + PdfFont currentFont = null; + foreach(PdfChunk chunk in line) { + if (chunk.Font.CompareTo(currentFont) != 0) { + currentFont = chunk.Font; + text.SetFontAndSize(currentFont.Font, currentFont.Size); + } + Color color = chunk.Color; + if (color != null) + text.SetColorFill(color); + text.ShowText(chunk.ToString()); + if (color != null) + text.ResetRGBColorFill(); + } + } + + /** Sets the new text origin. + * @param startX the X coordinate + * @param startY the Y coordinate + */ + public void SetOrigin(float startX, float startY) { + this.startX = startX; + this.startY = startY; + } + + /** Gets the X coordinate where the next line will be writen. This value will change + * after each call to go(). + * @return the X coordinate + */ + public float OriginX { + get { + return startX; + } + } + + /** Gets the Y coordinate where the next line will be writen. + * @return the Y coordinate + */ + public float OriginY { + get { + return startY; + } + } + + /** Gets the maximum number of available lines. This value will change + * after each call to go(). + * @return Value of property maxLines. + */ + public int MaxLines { + get { + return maxLines; + } + + set { + this.maxLines = value; + } + } + + /** Gets the height of the line + * @return the height + */ + public float Height { + get { + return height; + } + + set { + this.height = value; + } + } + + /** + * Gets the Element. + * @return the alignment + */ + public int Alignment { + get { + return alignment; + } + + set { + this.alignment = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/XfaForm.cs b/iTechSharp/iTextSharp/text/pdf/XfaForm.cs new file mode 100644 index 0000000..d3b044b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/XfaForm.cs @@ -0,0 +1,995 @@ +using System; +using System.Collections; +using System.Text; +using System.IO; +using System.Xml; +/* + * $Id: XfaForm.cs,v 1.7 2007/05/21 10:55:28 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Processes XFA forms. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class XfaForm { + + private Xml2SomTemplate templateSom; + private Xml2SomDatasets datasetsSom; + private AcroFieldsSearch acroFieldsSom; + private PdfReader reader; + private bool xfaPresent; + private XmlDocument domDocument; + private bool changed; + private XmlNode datasetsNode; + public const String XFA_DATA_SCHEMA = "http://www.xfa.org/schema/xfa-data/1.0/"; + + /** + * An empty constructor to build on. + */ + public XfaForm() { + } + + /** + * A constructor from a PdfReader. It basically does everything + * from finding the XFA stream to the XML parsing. + * @param reader the reader + * @throws java.io.IOException on error + * @throws javax.xml.parsers.ParserConfigurationException on error + * @throws org.xml.sax.SAXException on error + */ + public XfaForm(PdfReader reader) { + this.reader = reader; + PdfDictionary af = (PdfDictionary)PdfReader.GetPdfObjectRelease(reader.Catalog.Get(PdfName.ACROFORM)); + if (af == null) { + xfaPresent = false; + return; + } + PdfObject xfa = PdfReader.GetPdfObjectRelease(af.Get(PdfName.XFA)); + if (xfa == null) { + xfaPresent = false; + return; + } + xfaPresent = true; + MemoryStream bout = new MemoryStream(); + if (xfa.IsArray()) { + ArrayList ar = ((PdfArray)xfa).ArrayList; + for (int k = 1; k < ar.Count; k += 2) { + PdfObject ob = PdfReader.GetPdfObject((PdfObject)ar[k]); + if (ob is PRStream) { + byte[] b = PdfReader.GetStreamBytes((PRStream)ob); + bout.Write(b, 0, b.Length); + } + } + } + else if (xfa is PRStream) { + byte[] b = PdfReader.GetStreamBytes((PRStream)xfa); + bout.Write(b, 0, b.Length); + } + bout.Seek(0, SeekOrigin.Begin); + XmlTextReader xtr = new XmlTextReader(bout); + domDocument = new XmlDocument(); + domDocument.Load(xtr); + XmlNode n = domDocument.FirstChild; + while (n.NodeType != XmlNodeType.Element) + n = n.NextSibling; + n = n.FirstChild; + while (n != null) { + if (n.NodeType == XmlNodeType.Element) { + String s = n.LocalName; + if (s.Equals("template")) { + templateSom = new Xml2SomTemplate(n); + } + else if (s.Equals("datasets")) { + datasetsNode = n; + datasetsSom = new Xml2SomDatasets(n.FirstChild); + } + } + n = n.NextSibling; + } + } + + /** + * Sets the XFA key from a byte array. The old XFA is erased. + * @param xfaData the data + * @param reader the reader + * @param writer the writer + * @throws java.io.IOException on error + */ + public static void SetXfa(byte[] xfaData, PdfReader reader, PdfWriter writer) { + PdfDictionary af = (PdfDictionary)PdfReader.GetPdfObjectRelease(reader.Catalog.Get(PdfName.ACROFORM)); + if (af == null) { + return; + } + reader.KillXref(af.Get(PdfName.XFA)); + PdfStream str = new PdfStream(xfaData); + str.FlateCompress(); + PdfIndirectReference refe = writer.AddToBody(str).IndirectReference; + af.Put(PdfName.XFA, refe); + } + + /** + * Sets the XFA key from the instance data. The old XFA is erased. + * @param writer the writer + * @throws java.io.IOException on error + */ + public void SetXfa(PdfWriter writer) { + SetXfa(SerializeDoc(domDocument), reader, writer); + } + + /** + * Serializes a XML document to a byte array. + * @param n the XML document + * @throws java.io.IOException on error + * @return the serialized XML document + */ + public static byte[] SerializeDoc(XmlNode n) { + MemoryStream fout = new MemoryStream(); + XmlTextWriter xw = new XmlTextWriter(fout, new UTF8Encoding(false)); + xw.WriteNode(new XmlNodeReader(n), true); + xw.Close(); + return fout.ToArray(); + } + + /** + * Returns true if it is a XFA form. + * @return true if it is a XFA form + */ + public bool XfaPresent { + get { + return xfaPresent; + } + set { + xfaPresent = value; + } + } + + /** + * Gets the top level DOM document. + * @return the top level DOM document + */ + public XmlDocument DomDocument { + get { + return domDocument; + } + set { + domDocument = value; + } + } + + + /** + * Finds the complete field name contained in the "classic" forms from a partial + * name. + * @param name the complete or partial name + * @param af the fields + * @return the complete name or null if not found + */ + public String FindFieldName(String name, AcroFields af) { + Hashtable items = af.Fields; + if (items.ContainsKey(name)) + return name; + if (acroFieldsSom == null) { + acroFieldsSom = new AcroFieldsSearch(items.Keys); + } + if (acroFieldsSom.AcroShort2LongName.ContainsKey(name)) + return (String)acroFieldsSom.AcroShort2LongName[name]; + return acroFieldsSom.InverseSearchGlobal(Xml2Som.SplitParts(name)); + } + + /** + * Finds the complete SOM name contained in the datasets section from a + * possibly partial name. + * @param name the complete or partial name + * @return the complete name or null if not found + */ + public String FindDatasetsName(String name) { + if (datasetsSom.Name2Node.ContainsKey(name)) + return name; + return datasetsSom.InverseSearchGlobal(Xml2Som.SplitParts(name)); + } + + /** + * Finds the Node contained in the datasets section from a + * possibly partial name. + * @param name the complete or partial name + * @return the Node or null if not found + */ + public XmlNode FindDatasetsNode(String name) { + if (name == null) + return null; + name = FindDatasetsName(name); + if (name == null) + return null; + return (XmlNode)datasetsSom.Name2Node[name]; + } + + /** + * Gets all the text contained in the child nodes of this node. + * @param n the Node + * @return the text found or "" if no text was found + */ + public static String GetNodeText(XmlNode n) { + if (n == null) + return ""; + return GetNodeText(n, ""); + + } + + private static String GetNodeText(XmlNode n, String name) { + XmlNode n2 = n.FirstChild; + while (n2 != null) { + if (n2.NodeType == XmlNodeType.Element) { + name = GetNodeText(n2, name); + } + else if (n2.NodeType == XmlNodeType.Text) { + name += n2.Value; + } + n2 = n2.NextSibling; + } + return name; + } + + /** + * Sets the text of this node. All the child's node are deleted and a new + * child text node is created. + * @param n the Node to add the text to + * @param text the text to add + */ + public void SetNodeText(XmlNode n, String text) { + if (n == null) + return; + XmlNode nc = null; + while ((nc = n.FirstChild) != null) { + n.RemoveChild(nc); + } + n.Attributes.RemoveNamedItem("dataNode", XFA_DATA_SCHEMA); + n.AppendChild(domDocument.CreateTextNode(text)); + changed = true; + } + + /** + * Sets the PdfReader to be used by this instance. + * @param reader the PdfReader to be used by this instance + */ + public PdfReader Reader { + set { + reader = value; + } + get { + return reader; + } + } + + /** + * Checks if this XFA form was changed. + * @return true if this XFA form was changed + */ + public bool Changed { + get { + return changed; + } + set { + changed = value; + } + } + + /** + * A structure to store each part of a SOM name and link it to the next part + * beginning from the lower hierarchie. + */ + public class InverseStore { + protected internal ArrayList part = new ArrayList(); + protected internal ArrayList follow = new ArrayList(); + + /** + * Gets the full name by traversing the hiearchie using only the + * index 0. + * @return the full name + */ + public String DefaultName { + get { + InverseStore store = this; + while (true) { + Object obj = store.follow[0]; + if (obj is String) + return (String)obj; + store = (InverseStore)obj; + } + } + } + + /** + * Search the current node for a similar name. A similar name starts + * with the same name but has a differnt index. For example, "detail[3]" + * is similar to "detail[9]". The main use is to discard names that + * correspond to out of bounds records. + * @param name the name to search + * @return true if a similitude was found + */ + public bool IsSimilar(String name) { + int idx = name.IndexOf('['); + name = name.Substring(0, idx + 1); + foreach (String n in part) { + if (n.StartsWith(name)) + return true; + } + return false; + } + } + + /** + * Another stack implementation. The main use is to facilitate + * the porting to other languages. + */ + public class Stack2 : ArrayList { + /** + * Looks at the object at the top of this stack without removing it from the stack. + * @return the object at the top of this stack + */ + public Object Peek() { + if (Count == 0) + throw new InvalidOperationException(); + return this[Count - 1]; + } + + /** + * Removes the object at the top of this stack and returns that object as the value of this function. + * @return the object at the top of this stack + */ + public Object Pop() { + if (Count == 0) + throw new InvalidOperationException(); + Object ret = this[Count - 1]; + RemoveAt(Count - 1); + return ret; + } + + /** + * Pushes an item onto the top of this stack. + * @param item the item to be pushed onto this stack + * @return the item argument + */ + public Object Push(Object item) { + Add(item); + return item; + } + + /** + * Tests if this stack is empty. + * @return true if and only if this stack contains no items; false otherwise + */ + public bool Empty() { + return Count == 0; + } + } + + /** + * A class for some basic SOM processing. + */ + public class Xml2Som { + /** + * The order the names appear in the XML, depth first. + */ + protected ArrayList order; + /** + * The mapping of full names to nodes. + */ + protected Hashtable name2Node; + /** + * The data to do a search from the bottom hierarchie. + */ + protected Hashtable inverseSearch; + /** + * A stack to be used when parsing. + */ + protected Stack2 stack; + /** + * A temporary store for the repetition count. + */ + protected int anform; + + /** + * Escapes a SOM string fragment replacing "." with "\.". + * @param s the unescaped string + * @return the escaped string + */ + public static String EscapeSom(String s) { + int idx = s.IndexOf('.'); + if (idx < 0) + return s; + StringBuilder sb = new StringBuilder(); + int last = 0; + while (idx >= 0) { + sb.Append(s.Substring(last, idx - last)); + sb.Append('\\'); + last = idx; + idx = s.IndexOf('.', idx + 1); + } + sb.Append(s.Substring(last)); + return sb.ToString(); + } + + /** + * Unescapes a SOM string fragment replacing "\." with ".". + * @param s the escaped string + * @return the unescaped string + */ + public static String UnescapeSom(String s) { + int idx = s.IndexOf('\\'); + if (idx < 0) + return s; + StringBuilder sb = new StringBuilder(); + int last = 0; + while (idx >= 0) { + sb.Append(s.Substring(last, idx - last)); + last = idx + 1; + idx = s.IndexOf('\\', idx + 1); + } + sb.Append(s.Substring(last)); + return sb.ToString(); + } + + /** + * Outputs the stack as the sequence of elements separated + * by '.'. + * @return the stack as the sequence of elements separated by '.' + */ + protected String PrintStack() { + if (stack.Empty()) + return ""; + StringBuilder s = new StringBuilder(); + foreach (String part in stack) + s.Append('.').Append(part); + return s.ToString(1, s.Length - 1); + } + + /** + * Gets the name with the #subform removed. + * @param s the long name + * @return the short name + */ + public static String GetShortName(String s) { + int idx = s.IndexOf(".#subform["); + if (idx < 0) + return s; + int last = 0; + StringBuilder sb = new StringBuilder(); + while (idx >= 0) { + sb.Append(s.Substring(last, idx - last)); + idx = s.IndexOf("]", idx + 10); + if (idx < 0) + return sb.ToString(); + last = idx + 1; + idx = s.IndexOf(".#subform[", last); + } + sb.Append(s.Substring(last)); + return sb.ToString(); + } + + /** + * Adds a SOM name to the search node chain. + * @param unstack the SOM name + */ + public void InverseSearchAdd(String unstack) { + InverseSearchAdd(inverseSearch, stack, unstack); + } + + /** + * Adds a SOM name to the search node chain. + * @param inverseSearch the start point + * @param stack the stack with the separeted SOM parts + * @param unstack the full name + */ + public static void InverseSearchAdd(Hashtable inverseSearch, Stack2 stack, String unstack) { + String last = (String)stack.Peek(); + InverseStore store = (InverseStore)inverseSearch[last]; + if (store == null) { + store = new InverseStore(); + inverseSearch[last] = store; + } + for (int k = stack.Count - 2; k >= 0; --k) { + last = (String)stack[k]; + InverseStore store2; + int idx = store.part.IndexOf(last); + if (idx < 0) { + store.part.Add(last); + store2 = new InverseStore(); + store.follow.Add(store2); + } + else + store2 = (InverseStore)store.follow[idx]; + store = store2; + } + store.part.Add(""); + store.follow.Add(unstack); + } + + /** + * Searchs the SOM hiearchie from the bottom. + * @param parts the SOM parts + * @return the full name or null if not found + */ + public String InverseSearchGlobal(ArrayList parts) { + if (parts.Count == 0) + return null; + InverseStore store = (InverseStore)inverseSearch[parts[parts.Count - 1]]; + if (store == null) + return null; + for (int k = parts.Count - 2; k >= 0; --k) { + String part = (String)parts[k]; + int idx = store.part.IndexOf(part); + if (idx < 0) { + if (store.IsSimilar(part)) + return null; + return store.DefaultName; + } + store = (InverseStore)store.follow[idx]; + } + return store.DefaultName; + } + + /** + * Splits a SOM name in the individual parts. + * @param name the full SOM name + * @return the split name + */ + public static Stack2 SplitParts(String name) { + while (name.StartsWith(".")) + name = name.Substring(1); + Stack2 parts = new Stack2(); + int last = 0; + int pos = 0; + String part; + while (true) { + pos = last; + while (true) { + pos = name.IndexOf('.', pos); + if (pos < 0) + break; + if (name[pos - 1] == '\\') + ++pos; + else + break; + } + if (pos < 0) + break; + part = name.Substring(last, pos - last); + if (!part.EndsWith("]")) + part += "[0]"; + parts.Add(part); + last = pos + 1; + } + part = name.Substring(last); + if (!part.EndsWith("]")) + part += "[0]"; + parts.Add(part); + return parts; + } + + /** + * Gets the order the names appear in the XML, depth first. + * @return the order the names appear in the XML, depth first + */ + public ArrayList Order { + get { + return order; + } + set { + order = value; + } + } + + /** + * Gets the mapping of full names to nodes. + * @return the mapping of full names to nodes + */ + public Hashtable Name2Node { + get { + return name2Node; + } + set { + name2Node = value; + } + } + + /** + * Gets the data to do a search from the bottom hierarchie. + * @return the data to do a search from the bottom hierarchie + */ + public Hashtable InverseSearch { + get { + return inverseSearch; + } + set { + inverseSearch = value; + } + } + } + + /** + * Processes the datasets section in the XFA form. + */ + public class Xml2SomDatasets : Xml2Som { + /** + * Creates a new instance from the datasets node. This expects + * not the datasets but the data node that comes below. + * @param n the datasets node + */ + public Xml2SomDatasets(XmlNode n) { + order = new ArrayList(); + name2Node = new Hashtable(); + stack = new Stack2(); + anform = 0; + inverseSearch = new Hashtable(); + ProcessDatasetsInternal(n); + } + + /** + * Inserts a new Node that will match the short name. + * @param n the datasets top Node + * @param shortName the short name + * @return the new Node of the inserted name + */ + public XmlNode InsertNode(XmlNode n, String shortName) { + Stack2 stack = SplitParts(shortName); + XmlDocument doc = n.OwnerDocument; + XmlNode n2 = null; + n = n.FirstChild; + for (int k = 0; k < stack.Count; ++k) { + String part = (String)stack[k]; + int idx = part.LastIndexOf('['); + String name = part.Substring(0, idx); + idx = int.Parse(part.Substring(idx + 1, part.Length - idx - 2)); + int found = -1; + for (n2 = n.FirstChild; n2 != null; n2 = n2.NextSibling) { + if (n2.NodeType == XmlNodeType.Element) { + String s = EscapeSom(n2.LocalName); + if (s.Equals(name)) { + ++found; + if (found == idx) + break; + } + } + } + for (; found < idx; ++found) { + n2 = doc.CreateElement(name); + n2 = n.AppendChild(n2); + XmlNode attr = doc.CreateNode(XmlNodeType.Attribute, "dataNode", XFA_DATA_SCHEMA); + attr.Value = "dataGroup"; + n2.Attributes.SetNamedItem(attr); + } + n = n2; + } + InverseSearchAdd(inverseSearch, stack, shortName); + name2Node[shortName] = n2; + order.Add(shortName); + return n2; + } + + private static bool HasChildren(XmlNode n) { + XmlNode dataNodeN = n.Attributes.GetNamedItem("dataNode", XFA_DATA_SCHEMA); + if (dataNodeN != null) { + String dataNode = dataNodeN.Value; + if ("dataGroup".Equals(dataNode)) + return true; + else if ("dataValue".Equals(dataNode)) + return false; + } + if (!n.HasChildNodes) + return false; + XmlNode n2 = n.FirstChild; + while (n2 != null) { + if (n2.NodeType == XmlNodeType.Element) { + return true; + } + n2 = n2.NextSibling; + } + return false; + } + + private void ProcessDatasetsInternal(XmlNode n) { + Hashtable ss = new Hashtable(); + XmlNode n2 = n.FirstChild; + while (n2 != null) { + if (n2.NodeType == XmlNodeType.Element) { + String s = EscapeSom(n2.LocalName); + int i; + if (ss[s] == null) + i = 0; + else + i = (int)ss[s] + 1; + ss[s] = i; + if (HasChildren(n2)) { + stack.Push(s + "[" + i.ToString() + "]"); + ProcessDatasetsInternal(n2); + stack.Pop(); + } + else { + stack.Push(s + "[" + i.ToString() + "]"); + String unstack = PrintStack(); + order.Add(unstack); + InverseSearchAdd(unstack); + name2Node[unstack] = n2; + stack.Pop(); + } + } + n2 = n2.NextSibling; + } + } + } + + /** + * A class to process "classic" fields. + */ + public class AcroFieldsSearch : Xml2Som { + private Hashtable acroShort2LongName; + + /** + * Creates a new instance from a Collection with the full names. + * @param items the Collection + */ + public AcroFieldsSearch(ICollection items) { + inverseSearch = new Hashtable(); + acroShort2LongName = new Hashtable(); + foreach (String itemName in items) { + String itemShort = GetShortName(itemName); + acroShort2LongName[itemShort] = itemName; + InverseSearchAdd(inverseSearch, SplitParts(itemShort), itemName); + } + } + + /** + * Gets the mapping from short names to long names. A long + * name may contain the #subform name part. + * @return the mapping from short names to long names + */ + public Hashtable AcroShort2LongName { + get { + return acroShort2LongName; + } + set { + acroShort2LongName = value; + } + } + } + + /** + * Processes the template section in the XFA form. + */ + public class Xml2SomTemplate : Xml2Som { + private bool dynamicForm; + private int templateLevel; + + /** + * Creates a new instance from the datasets node. + * @param n the template node + */ + public Xml2SomTemplate(XmlNode n) { + order = new ArrayList(); + name2Node = new Hashtable(); + stack = new Stack2(); + anform = 0; + templateLevel = 0; + inverseSearch = new Hashtable(); + ProcessTemplate(n, null); + } + + /** + * Gets the field type as described in the template section of the XFA. + * @param s the exact template name + * @return the field type or null if not found + */ + public String GetFieldType(String s) { + XmlNode n = (XmlNode)name2Node[s]; + if (n == null) + return null; + if (n.LocalName.Equals("exclGroup")) + return "exclGroup"; + XmlNode ui = n.FirstChild; + while (ui != null) { + if (ui.NodeType == XmlNodeType.Element && ui.LocalName.Equals("ui")) { + break; + } + ui = ui.NextSibling; + } + if (ui == null) + return null; + XmlNode type = ui.FirstChild; + while (type != null) { + if (type.NodeType == XmlNodeType.Element && !(type.LocalName.Equals("extras") && type.LocalName.Equals("picture"))) { + return type.LocalName; + } + type = type.NextSibling; + } + return null; + } + + private void ProcessTemplate(XmlNode n, Hashtable ff) { + if (ff == null) + ff = new Hashtable(); + Hashtable ss = new Hashtable(); + XmlNode n2 = n.FirstChild; + while (n2 != null) { + if (n2.NodeType == XmlNodeType.Element) { + String s = n2.LocalName; + if (s.Equals("subform")) { + XmlNode name = n2.Attributes.GetNamedItem("name"); + String nn = "#subform"; + bool annon = true; + if (name != null) { + nn = EscapeSom(name.Value); + annon = false; + } + int i; + if (annon) { + i = anform; + ++anform; + } + else { + if (ss[nn] == null) + i = 0; + else + i = (int)ss[nn] + 1; + ss[nn] = i; + } + stack.Push(nn + "[" + i.ToString() + "]"); + ++templateLevel; + if (annon) + ProcessTemplate(n2, ff); + else + ProcessTemplate(n2, null); + --templateLevel; + stack.Pop(); + } + else if (s.Equals("field") || s.Equals("exclGroup")) { + XmlNode name = n2.Attributes.GetNamedItem("name"); + if (name != null) { + String nn = EscapeSom(name.Value); + int i; + if (ff[nn] == null) + i = 0; + else + i = (int)ff[nn] + 1; + ff[nn] = i; + stack.Push(nn + "[" + i.ToString() + "]"); + String unstack = PrintStack(); + order.Add(unstack); + InverseSearchAdd(unstack); + name2Node[unstack] = n2; + stack.Pop(); + } + } + else if (!dynamicForm && templateLevel > 0 && s.Equals("occur")) { + int initial = 1; + int min = 1; + int max = 1; + XmlNode a = n2.Attributes.GetNamedItem("initial"); + if (a != null) + try{initial = int.Parse(a.Value.Trim());}catch{}; + a = n2.Attributes.GetNamedItem("min"); + if (a != null) + try{min = int.Parse(a.Value.Trim());}catch{}; + a = n2.Attributes.GetNamedItem("max"); + if (a != null) + try{max = int.Parse(a.Value.Trim());}catch{}; + if (initial != min || min != max) + dynamicForm = true; + } + } + n2 = n2.NextSibling; + } + } + + /** + * true if it's a dynamic form; false + * if it's a static form. + * @return true if it's a dynamic form; false + * if it's a static form + */ + public bool DynamicForm { + get { + return dynamicForm; + } + set { + dynamicForm = value; + } + } + } + + /** + * Gets the class that contains the template processing section of the XFA. + * @return the class that contains the template processing section of the XFA + */ + public Xml2SomTemplate TemplateSom { + get { + return templateSom; + } + set { + templateSom = value; + } + } + + /** + * Gets the class that contains the datasets processing section of the XFA. + * @return the class that contains the datasets processing section of the XFA + */ + public Xml2SomDatasets DatasetsSom { + get { + return datasetsSom; + } + set { + datasetsSom = value; + } + } + + /** + * Gets the class that contains the "classic" fields processing. + * @return the class that contains the "classic" fields processing + */ + public AcroFieldsSearch AcroFieldsSom { + get { + return acroFieldsSom; + } + set { + acroFieldsSom = value; + } + } + + /** + * Gets the Node that corresponds to the datasets part. + * @return the Node that corresponds to the datasets part + */ + public XmlNode DatasetsNode { + get { + return datasetsNode; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/XfdfReader.cs b/iTechSharp/iTextSharp/text/pdf/XfdfReader.cs new file mode 100644 index 0000000..69d95b1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/XfdfReader.cs @@ -0,0 +1,223 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.xml.simpleparser; +/* + * + * Copyright 2004 by Leonard Rosenthol. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Reads a XFDF. + * @author Leonard Rosenthol (leonardr@pdfsages.com) + */ + public class XfdfReader : ISimpleXMLDocHandler { + // stuff used during parsing to handle state + private bool foundRoot = false; + private Stackr fieldNames = new Stackr(); + private Stackr fieldValues = new Stackr(); + + // storage for the field list and their values + internal Hashtable fields; + + // storage for the path to referenced PDF, if any + internal String fileSpec; + + /** Reads an XFDF form. + * @param filename the file name of the form + * @throws IOException on error + */ + public XfdfReader(String filename) { + FileStream fin = null; + try { + fin = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + SimpleXMLParser.Parse(this, fin); + } + finally { + try{if (fin != null) fin.Close();}catch{} + } + } + + /** Reads an XFDF form. + * @param xfdfIn the byte array with the form + * @throws IOException on error + */ + public XfdfReader(byte[] xfdfIn) { + SimpleXMLParser.Parse( this, new MemoryStream(xfdfIn)); + } + + /** Gets all the fields. The map is keyed by the fully qualified + * field name and the value is a merged PdfDictionary + * with the field content. + * @return all the fields + */ + public Hashtable Fields { + get { + return fields; + } + } + + /** Gets the field value. + * @param name the fully qualified field name + * @return the field's value + */ + public String GetField(String name) { + return (String)fields[name]; + } + + /** Gets the field value or null if the field does not + * exist or has no value defined. + * @param name the fully qualified field name + * @return the field value or null + */ + public String GetFieldValue(String name) { + String field = (String)fields[name]; + if (field == null) + return null; + else + return field; + } + + /** Gets the PDF file specification contained in the FDF. + * @return the PDF file specification contained in the FDF + */ + public String FileSpec { + get { + return fileSpec; + } + } + + /** + * Called when a start tag is found. + * @param tag the tag name + * @param h the tag's attributes + */ + public void StartElement(String tag, Hashtable h) { + if ( !foundRoot ) { + if (!tag.Equals("xfdf")) + throw new Exception("Root element is not Bookmark."); + else + foundRoot = true; + } + + if ( tag.Equals("xfdf") ){ + + } else if ( tag.Equals("f") ) { + fileSpec = (String)h[ "href" ]; + } else if ( tag.Equals("fields") ) { + fields = new Hashtable(); // init it! + } else if ( tag.Equals("field") ) { + String fName = (String) h[ "name" ]; + fieldNames.Push( fName ); + } else if ( tag.Equals("value") ) { + fieldValues.Push(""); + } + } + /** + * Called when an end tag is found. + * @param tag the tag name + */ + public void EndElement(String tag) { + if ( tag.Equals("value") ) { + String fName = ""; + for (int k = 0; k < fieldNames.Count; ++k) { + fName += "." + (String)fieldNames[k]; + } + if (fName.StartsWith(".")) + fName = fName.Substring(1); + String fVal = (String) fieldValues.Pop(); + fields[fName] = fVal; + } + else if (tag.Equals("field") ) { + if (fieldNames.Count != 0) + fieldNames.Pop(); + } + } + + /** + * Called when the document starts to be parsed. + */ + public void StartDocument() + { + fileSpec = ""; // and this too... + } + /** + * Called after the document is parsed. + */ + public void EndDocument() + { + + } + /** + * Called when a text element is found. + * @param str the text element, probably a fragment. + */ + public void Text(String str) + { + if (fieldNames.Count == 0 || fieldValues.Count == 0) + return; + + String val = (String)fieldValues.Pop(); + val += str; + fieldValues.Push(val); + } + + internal class Stackr : ArrayList { + internal void Push(object obj) { + Add(obj); + } + + internal object Pop() { + if (Count == 0) + throw new InvalidOperationException("The stack is empty."); + object obj = this[Count - 1]; + RemoveAt(Count - 1); + return obj; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/codec/BmpImage.cs b/iTechSharp/iTextSharp/text/pdf/codec/BmpImage.cs new file mode 100644 index 0000000..0e1deb0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/BmpImage.cs @@ -0,0 +1,1278 @@ +using System; +using System.Collections; +using System.IO; +using System.Net; +using System.util; +using iTextSharp.text; +/* + * Copyright 2003-2008 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +namespace iTextSharp.text.pdf.codec { + /** Reads a BMP image. All types of BMP can be read. + *

    + * It is based in the JAI codec. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BmpImage { + + // BMP variables + private Stream inputStream; + private long bitmapFileSize; + private long bitmapOffset; + private long compression; + private long imageSize; + private byte[] palette; + private int imageType; + private int numBands; + private bool isBottomUp; + private int bitsPerPixel; + private int redMask, greenMask, blueMask, alphaMask; + public Hashtable properties = new Hashtable(); + private long xPelsPerMeter; + private long yPelsPerMeter; + // BMP Image types + private const int VERSION_2_1_BIT = 0; + private const int VERSION_2_4_BIT = 1; + private const int VERSION_2_8_BIT = 2; + private const int VERSION_2_24_BIT = 3; + + private const int VERSION_3_1_BIT = 4; + private const int VERSION_3_4_BIT = 5; + private const int VERSION_3_8_BIT = 6; + private const int VERSION_3_24_BIT = 7; + + private const int VERSION_3_NT_16_BIT = 8; + private const int VERSION_3_NT_32_BIT = 9; + + private const int VERSION_4_1_BIT = 10; + private const int VERSION_4_4_BIT = 11; + private const int VERSION_4_8_BIT = 12; + private const int VERSION_4_16_BIT = 13; + private const int VERSION_4_24_BIT = 14; + private const int VERSION_4_32_BIT = 15; + + // Color space types + private const int LCS_CALIBRATED_RGB = 0; + private const int LCS_sRGB = 1; + private const int LCS_CMYK = 2; + + // Compression Types + private const int BI_RGB = 0; + private const int BI_RLE8 = 1; + private const int BI_RLE4 = 2; + private const int BI_BITFIELDS = 3; + + int width; + int height; + + internal BmpImage(Stream isp, bool noHeader, int size) { + bitmapFileSize = size; + bitmapOffset = 0; + Process(isp, noHeader); + } + + /** Reads a BMP from an url. + * @param url the url + * @throws IOException on error + * @return the image + */ + public static Image GetImage(Uri url) { + Stream isp = null; + try { + isp = WebRequest.Create(url).GetResponse().GetResponseStream(); + Image img = GetImage(isp); + img.Url = url; + return img; + } + finally { + if (isp != null) { + isp.Close(); + } + } + } + + /** Reads a BMP from a stream. The stream is not closed. + * @param is the stream + * @throws IOException on error + * @return the image + */ + public static Image GetImage(Stream isp) { + return GetImage(isp, false, 0); + } + + /** Reads a BMP from a stream. The stream is not closed. + * The BMP may not have a header and be considered as a plain DIB. + * @param is the stream + * @param noHeader true to process a plain DIB + * @param size the size of the DIB. Not used for a BMP + * @throws IOException on error + * @return the image + */ + public static Image GetImage(Stream isp, bool noHeader, int size) { + BmpImage bmp = new BmpImage(isp, noHeader, size); + Image img = bmp.GetImage(); + img.SetDpi((int)((double)bmp.xPelsPerMeter * 0.0254 + 0.5), (int)((double)bmp.yPelsPerMeter * 0.0254 + 0.5)); + img.OriginalType = Image.ORIGINAL_BMP; + return img; + } + + /** Reads a BMP from a file. + * @param file the file + * @throws IOException on error + * @return the image + */ + public static Image GetImage(String file) { + return GetImage(Utilities.ToURL(file)); + } + + /** Reads a BMP from a byte array. + * @param data the byte array + * @throws IOException on error + * @return the image + */ + public static Image GetImage(byte[] data) { + Stream isp = new MemoryStream(data); + Image img = GetImage(isp); + img.OriginalData = data; + return img; + } + + + protected void Process(Stream stream, bool noHeader) { + if (noHeader || stream is BufferedStream) { + inputStream = stream; + } else { + inputStream = new BufferedStream(stream); + } + if (!noHeader) { + // Start File Header + if (!(ReadUnsignedByte(inputStream) == 'B' && + ReadUnsignedByte(inputStream) == 'M')) { + throw new Exception("Invalid magic value for BMP file."); + } + + // Read file size + bitmapFileSize = ReadDWord(inputStream); + + // Read the two reserved fields + ReadWord(inputStream); + ReadWord(inputStream); + + // Offset to the bitmap from the beginning + bitmapOffset = ReadDWord(inputStream); + + // End File Header + } + // Start BitmapCoreHeader + long size = ReadDWord(inputStream); + + if (size == 12) { + width = ReadWord(inputStream); + height = ReadWord(inputStream); + } else { + width = ReadLong(inputStream); + height = ReadLong(inputStream); + } + + int planes = ReadWord(inputStream); + bitsPerPixel = ReadWord(inputStream); + + properties["color_planes"] = planes; + properties["bits_per_pixel"] = bitsPerPixel; + + // As BMP always has 3 rgb bands, except for Version 5, + // which is bgra + numBands = 3; + if (bitmapOffset == 0) + bitmapOffset = size; + if (size == 12) { + // Windows 2.x and OS/2 1.x + properties["bmp_version"] = "BMP v. 2.x"; + + // Classify the image type + if (bitsPerPixel == 1) { + imageType = VERSION_2_1_BIT; + } else if (bitsPerPixel == 4) { + imageType = VERSION_2_4_BIT; + } else if (bitsPerPixel == 8) { + imageType = VERSION_2_8_BIT; + } else if (bitsPerPixel == 24) { + imageType = VERSION_2_24_BIT; + } + + // Read in the palette + int numberOfEntries = (int)((bitmapOffset-14-size) / 3); + int sizeOfPalette = numberOfEntries*3; + if (bitmapOffset == size) { + switch (imageType) { + case VERSION_2_1_BIT: + sizeOfPalette = 2 * 3; + break; + case VERSION_2_4_BIT: + sizeOfPalette = 16 * 3; + break; + case VERSION_2_8_BIT: + sizeOfPalette = 256 * 3; + break; + case VERSION_2_24_BIT: + sizeOfPalette = 0; + break; + } + bitmapOffset = size + sizeOfPalette; + } + ReadPalette(sizeOfPalette); + } else { + + compression = ReadDWord(inputStream); + imageSize = ReadDWord(inputStream); + xPelsPerMeter = ReadLong(inputStream); + yPelsPerMeter = ReadLong(inputStream); + long colorsUsed = ReadDWord(inputStream); + long colorsImportant = ReadDWord(inputStream); + + switch ((int)compression) { + case BI_RGB: + properties["compression"] = "BI_RGB"; + break; + + case BI_RLE8: + properties["compression"] = "BI_RLE8"; + break; + + case BI_RLE4: + properties["compression"] = "BI_RLE4"; + break; + + case BI_BITFIELDS: + properties["compression"] = "BI_BITFIELDS"; + break; + } + + properties["x_pixels_per_meter"] = xPelsPerMeter; + properties["y_pixels_per_meter"] = yPelsPerMeter; + properties["colors_used"] = colorsUsed; + properties["colors_important"] = colorsImportant; + + if (size == 40) { + // Windows 3.x and Windows NT + switch ((int)compression) { + + case BI_RGB: // No compression + case BI_RLE8: // 8-bit RLE compression + case BI_RLE4: // 4-bit RLE compression + + if (bitsPerPixel == 1) { + imageType = VERSION_3_1_BIT; + } else if (bitsPerPixel == 4) { + imageType = VERSION_3_4_BIT; + } else if (bitsPerPixel == 8) { + imageType = VERSION_3_8_BIT; + } else if (bitsPerPixel == 24) { + imageType = VERSION_3_24_BIT; + } else if (bitsPerPixel == 16) { + imageType = VERSION_3_NT_16_BIT; + redMask = 0x7C00; + greenMask = 0x3E0; + blueMask = 0x1F; + properties["red_mask"] = redMask; + properties["green_mask"] = greenMask; + properties["blue_mask"] = blueMask; + } else if (bitsPerPixel == 32) { + imageType = VERSION_3_NT_32_BIT; + redMask = 0x00FF0000; + greenMask = 0x0000FF00; + blueMask = 0x000000FF; + properties["red_mask"] = redMask; + properties["green_mask"] = greenMask; + properties["blue_mask"] = blueMask; + } + + // Read in the palette + int numberOfEntries = (int)((bitmapOffset-14-size) / 4); + int sizeOfPalette = numberOfEntries*4; + if (bitmapOffset == size) { + switch (imageType) { + case VERSION_3_1_BIT: + sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4; + break; + case VERSION_3_4_BIT: + sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4; + break; + case VERSION_3_8_BIT: + sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4; + break; + default: + sizeOfPalette = 0; + break; + } + bitmapOffset = size + sizeOfPalette; + } + ReadPalette(sizeOfPalette); + properties["bmp_version"] = "BMP v. 3.x"; + break; + + case BI_BITFIELDS: + + if (bitsPerPixel == 16) { + imageType = VERSION_3_NT_16_BIT; + } else if (bitsPerPixel == 32) { + imageType = VERSION_3_NT_32_BIT; + } + + // BitsField encoding + redMask = (int)ReadDWord(inputStream); + greenMask = (int)ReadDWord(inputStream); + blueMask = (int)ReadDWord(inputStream); + + properties["red_mask"] = redMask; + properties["green_mask"] = greenMask; + properties["blue_mask"] = blueMask; + + if (colorsUsed != 0) { + // there is a palette + sizeOfPalette = (int)colorsUsed*4; + ReadPalette(sizeOfPalette); + } + + properties["bmp_version"] = "BMP v. 3.x NT"; + break; + + default: + throw new + Exception("Invalid compression specified in BMP file."); + } + } else if (size == 108) { + // Windows 4.x BMP + + properties["bmp_version"] = "BMP v. 4.x"; + + // rgb masks, valid only if comp is BI_BITFIELDS + redMask = (int)ReadDWord(inputStream); + greenMask = (int)ReadDWord(inputStream); + blueMask = (int)ReadDWord(inputStream); + // Only supported for 32bpp BI_RGB argb + alphaMask = (int)ReadDWord(inputStream); + long csType = ReadDWord(inputStream); + int redX = ReadLong(inputStream); + int redY = ReadLong(inputStream); + int redZ = ReadLong(inputStream); + int greenX = ReadLong(inputStream); + int greenY = ReadLong(inputStream); + int greenZ = ReadLong(inputStream); + int blueX = ReadLong(inputStream); + int blueY = ReadLong(inputStream); + int blueZ = ReadLong(inputStream); + long gammaRed = ReadDWord(inputStream); + long gammaGreen = ReadDWord(inputStream); + long gammaBlue = ReadDWord(inputStream); + + if (bitsPerPixel == 1) { + imageType = VERSION_4_1_BIT; + } else if (bitsPerPixel == 4) { + imageType = VERSION_4_4_BIT; + } else if (bitsPerPixel == 8) { + imageType = VERSION_4_8_BIT; + } else if (bitsPerPixel == 16) { + imageType = VERSION_4_16_BIT; + if ((int)compression == BI_RGB) { + redMask = 0x7C00; + greenMask = 0x3E0; + blueMask = 0x1F; + } + } else if (bitsPerPixel == 24) { + imageType = VERSION_4_24_BIT; + } else if (bitsPerPixel == 32) { + imageType = VERSION_4_32_BIT; + if ((int)compression == BI_RGB) { + redMask = 0x00FF0000; + greenMask = 0x0000FF00; + blueMask = 0x000000FF; + } + } + + properties["red_mask"] = redMask; + properties["green_mask"] = greenMask; + properties["blue_mask"] = blueMask; + properties["alpha_mask"] = alphaMask; + + // Read in the palette + int numberOfEntries = (int)((bitmapOffset-14-size) / 4); + int sizeOfPalette = numberOfEntries*4; + if (bitmapOffset == size) { + switch (imageType) { + case VERSION_4_1_BIT: + sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4; + break; + case VERSION_4_4_BIT: + sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4; + break; + case VERSION_4_8_BIT: + sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4; + break; + default: + sizeOfPalette = 0; + break; + } + bitmapOffset = size + sizeOfPalette; + } + ReadPalette(sizeOfPalette); + + switch ((int)csType) { + case LCS_CALIBRATED_RGB: + // All the new fields are valid only for this case + properties["color_space"] = "LCS_CALIBRATED_RGB"; + properties["redX"] = redX; + properties["redY"] = redY; + properties["redZ"] = redZ; + properties["greenX"] = greenX; + properties["greenY"] = greenY; + properties["greenZ"] = greenZ; + properties["blueX"] = blueX; + properties["blueY"] = blueY; + properties["blueZ"] = blueZ; + properties["gamma_red"] = gammaRed; + properties["gamma_green"] = gammaGreen; + properties["gamma_blue"] = gammaBlue; + + // break; + throw new + Exception("Not implemented yet."); + + case LCS_sRGB: + // Default Windows color space + properties["color_space"] = "LCS_sRGB"; + break; + + case LCS_CMYK: + properties["color_space"] = "LCS_CMYK"; + // break; + throw new + Exception("Not implemented yet."); + } + + } else { + properties["bmp_version"] = "BMP v. 5.x"; + throw new + Exception("BMP version 5 not implemented yet."); + } + } + + if (height > 0) { + // bottom up image + isBottomUp = true; + } else { + // top down image + isBottomUp = false; + height = Math.Abs(height); + } + // When number of bitsPerPixel is <= 8, we use IndexColorModel. + if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) { + + numBands = 1; + + + // Create IndexColorModel from the palette. + byte[] r; + byte[] g; + byte[] b; + int sizep; + if (imageType == VERSION_2_1_BIT || + imageType == VERSION_2_4_BIT || + imageType == VERSION_2_8_BIT) { + + sizep = palette.Length/3; + + if (sizep > 256) { + sizep = 256; + } + + int off; + r = new byte[sizep]; + g = new byte[sizep]; + b = new byte[sizep]; + for (int i=0; i 256) { + sizep = 256; + } + + int off; + r = new byte[sizep]; + g = new byte[sizep]; + b = new byte[sizep]; + for (int i=0; i= 0; --i) { + l = width * 3 * i; + for (int j=0; j= 0; i--) { + index = i * width; + lineEnd = l + width; + while (l != lineEnd) { + val[l++] = inverted[index++]; + } + } + } + int stride = ((width + 1) / 2); + byte[] bdata = new byte[stride * height]; + int ptr = 0; + int sh = 0; + for (int h = 0; h < height; ++h) { + for (int w = 0; w < width; ++w) { + if ((w & 1) == 0) + bdata[sh + w / 2] = (byte)(val[ptr++] << 4); + else + bdata[sh + w / 2] |= (byte)(val[ptr++] & 0x0f); + } + sh += stride; + } + return IndexedModel(bdata, 4, 4); + } + + private byte[] DecodeRLE(bool is8, byte[] values) { + byte[] val = new byte[width * height]; + try { + int ptr = 0; + int x = 0; + int q = 0; + for (int y = 0; y < height && ptr < values.Length;) { + int count = values[ptr++] & 0xff; + if (count != 0) { + // encoded mode + int bt = values[ptr++] & 0xff; + if (is8) { + for (int i = count; i != 0; --i) { + val[q++] = (byte)bt; + } + } + else { + for (int i = 0; i < count; ++i) { + val[q++] = (byte)((i & 1) == 1 ? (bt & 0x0f) : ((bt >> 4) & 0x0f)); + } + } + x += count; + } + else { + // escape mode + count = values[ptr++] & 0xff; + if (count == 1) + break; + switch (count) { + case 0: + x = 0; + ++y; + q = y * width; + break; + case 2: + // delta mode + x += values[ptr++] & 0xff; + y += values[ptr++] & 0xff; + q = y * width + x; + break; + default: + // absolute mode + if (is8) { + for (int i = count; i != 0; --i) + val[q++] = (byte)(values[ptr++] & 0xff); + } + else { + int bt = 0; + for (int i = 0; i < count; ++i) { + if ((i & 1) == 0) + bt = values[ptr++] & 0xff; + val[q++] = (byte)((i & 1) == 1 ? (bt & 0x0f) : ((bt >> 4) & 0x0f)); + } + } + x += count; + // read pad byte + if (is8) { + if ((count & 1) == 1) + ++ptr; + } + else { + if ((count & 3) == 1 || (count & 3) == 2) + ++ptr; + } + break; + } + } + } + } + catch { + //empty on purpose + } + + return val; + } + + // Windows defined data type reading methods - everything is little endian + + // Unsigned 8 bits + private int ReadUnsignedByte(Stream stream) { + return (stream.ReadByte() & 0xff); + } + + // Unsigned 2 bytes + private int ReadUnsignedShort(Stream stream) { + int b1 = ReadUnsignedByte(stream); + int b2 = ReadUnsignedByte(stream); + return ((b2 << 8) | b1) & 0xffff; + } + + // Signed 16 bits + private int ReadShort(Stream stream) { + int b1 = ReadUnsignedByte(stream); + int b2 = ReadUnsignedByte(stream); + return (b2 << 8) | b1; + } + + // Unsigned 16 bits + private int ReadWord(Stream stream) { + return ReadUnsignedShort(stream); + } + + // Unsigned 4 bytes + private long ReadUnsignedInt(Stream stream) { + int b1 = ReadUnsignedByte(stream); + int b2 = ReadUnsignedByte(stream); + int b3 = ReadUnsignedByte(stream); + int b4 = ReadUnsignedByte(stream); + long l = (long)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1); + return l & 0xffffffff; + } + + // Signed 4 bytes + private int ReadInt(Stream stream) { + int b1 = ReadUnsignedByte(stream); + int b2 = ReadUnsignedByte(stream); + int b3 = ReadUnsignedByte(stream); + int b4 = ReadUnsignedByte(stream); + return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1; + } + + // Unsigned 4 bytes + private long ReadDWord(Stream stream) { + return ReadUnsignedInt(stream); + } + + // 32 bit signed value + private int ReadLong(Stream stream) { + return ReadInt(stream); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/CCITTG4Encoder.cs b/iTechSharp/iTextSharp/text/pdf/codec/CCITTG4Encoder.cs new file mode 100644 index 0000000..fca3702 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/CCITTG4Encoder.cs @@ -0,0 +1,601 @@ +using System; +using iTextSharp.text.pdf; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * This code is base in the libtiff encoder + */ + +namespace iTextSharp.text.pdf.codec { + /** + * Encodes data in the CCITT G4 FAX format. + */ + public class CCITTG4Encoder { + private int rowbytes; + private int rowpixels; + private int bit = 8; + private int data; + private byte[] refline; + private ByteBuffer outBuf = new ByteBuffer(1024); + private byte[] dataBp; + private int offsetData; + private int sizeData; + + /** + * Creates a new encoder. + * @param width the line width + */ + public CCITTG4Encoder(int width) { + rowpixels = width; + rowbytes = (rowpixels + 7) / 8; + refline = new byte[rowbytes]; + } + + /** + * Encodes a number of lines. + * @param data the data to be encoded + * @param offset the offset into the data + * @param size the size of the data to be encoded + */ + public void Fax4Encode(byte[] data, int offset, int size) { + dataBp = data; + offsetData = offset; + sizeData = size; + while (sizeData > 0) { + Fax3Encode2DRow(); + Array.Copy(dataBp, offsetData, refline, 0, rowbytes); + offsetData += rowbytes; + sizeData -= rowbytes; + } + } + + + /** + * Encodes a full image. + * @param data the data to encode + * @param width the image width + * @param height the image height + * @return the encoded image + */ + public static byte[] Compress(byte[] data, int width, int height) { + CCITTG4Encoder g4 = new CCITTG4Encoder(width); + g4.Fax4Encode(data, 0, g4.rowbytes * height); + return g4.Close(); + } + + /** + * Encodes a number of lines. + * @param data the data to be encoded + * @param height the number of lines to encode + */ + public void Fax4Encode(byte[] data, int height) { + Fax4Encode(data, 0, rowbytes * height); + } + + private void Putcode(int[] table) { + PutBits(table[CODE], table[LENGTH]); + } + + private void Putspan(int span, int[][] tab) { + int code, length; + + while (span >= 2624) { + int[] te = tab[63 + (2560>>6)]; + code = te[CODE]; + length = te[LENGTH]; + PutBits(code, length); + span -= te[RUNLEN]; + } + if (span >= 64) { + int[] te = tab[63 + (span>>6)]; + code = te[CODE]; + length = te[LENGTH]; + PutBits(code, length); + span -= te[RUNLEN]; + } + code = tab[span][CODE]; + length = tab[span][LENGTH]; + PutBits(code, length); + } + + private void PutBits(int bits, int length) { + while (length > bit) { + data |= bits >> (length - bit); + length -= bit; + outBuf.Append((byte)data); + data = 0; + bit = 8; + } + data |= (bits & msbmask[length]) << (bit - length); + bit -= length; + if (bit == 0) { + outBuf.Append((byte)data); + data = 0; + bit = 8; + } + } + + private void Fax3Encode2DRow() { + int a0 = 0; + int a1 = (Pixel(dataBp, offsetData, 0) != 0 ? 0 : Finddiff(dataBp, offsetData, 0, rowpixels, 0)); + int b1 = (Pixel(refline, 0, 0) != 0 ? 0 : Finddiff(refline, 0, 0, rowpixels, 0)); + int a2, b2; + + for (;;) { + b2 = Finddiff2(refline, 0, b1, rowpixels, Pixel(refline, 0,b1)); + if (b2 >= a1) { + int d = b1 - a1; + if (!(-3 <= d && d <= 3)) { /* horizontal mode */ + a2 = Finddiff2(dataBp, offsetData, a1, rowpixels, Pixel(dataBp, offsetData,a1)); + Putcode(horizcode); + if (a0+a1 == 0 || Pixel(dataBp, offsetData, a0) == 0) { + Putspan(a1-a0, TIFFFaxWhiteCodes); + Putspan(a2-a1, TIFFFaxBlackCodes); + } else { + Putspan(a1-a0, TIFFFaxBlackCodes); + Putspan(a2-a1, TIFFFaxWhiteCodes); + } + a0 = a2; + } else { /* vertical mode */ + Putcode(vcodes[d+3]); + a0 = a1; + } + } else { /* pass mode */ + Putcode(passcode); + a0 = b2; + } + if (a0 >= rowpixels) + break; + a1 = Finddiff(dataBp, offsetData, a0, rowpixels, Pixel(dataBp, offsetData,a0)); + b1 = Finddiff(refline, 0, a0, rowpixels, Pixel(dataBp, offsetData,a0) ^ 1); + b1 = Finddiff(refline, 0, b1, rowpixels, Pixel(dataBp, offsetData,a0)); + } + } + + private void Fax4PostEncode() { + PutBits(EOL, 12); + PutBits(EOL, 12); + if (bit != 8) { + outBuf.Append((byte)data); + data = 0; + bit = 8; + } + } + + /** + * Closes the encoder and returns the encoded data. + * @return the encoded data + */ + public byte[] Close() { + Fax4PostEncode(); + return outBuf.ToByteArray(); + } + + private int Pixel(byte[] data, int offset, int bit) { + if (bit >= rowpixels) + return 0; + return ((data[offset + (bit >> 3)] & 0xff) >> (7-((bit)&7))) & 1; + } + + private static int Find1span(byte[] bp, int offset, int bs, int be) { + int bits = be - bs; + int n, span; + + int pos = offset + (bs >> 3); + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7)) != 0) { + span = oneruns[((int)bp[pos] << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + pos++; + } else + span = 0; + /* + * Scan full bytes for all 1's. + */ + while (bits >= 8) { + if (bp[pos] != 0xff) /* end of run */ + return (span + oneruns[bp[pos] & 0xff]); + span += 8; + bits -= 8; + pos++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = oneruns[bp[pos] & 0xff]; + span += (n > bits ? bits : n); + } + return (span); + } + + private static int Find0span(byte[] bp, int offset, int bs, int be) { + int bits = be - bs; + int n, span; + + int pos = offset + (bs >> 3); + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7)) != 0) { + span = zeroruns[((int)bp[pos] << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + pos++; + } else + span = 0; + /* + * Scan full bytes for all 1's. + */ + while (bits >= 8) { + if (bp[pos] != 0) /* end of run */ + return (span + zeroruns[bp[pos] & 0xff]); + span += 8; + bits -= 8; + pos++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = zeroruns[bp[pos] & 0xff]; + span += (n > bits ? bits : n); + } + return (span); + } + + private static int Finddiff(byte[] bp, int offset, int bs, int be, int color) { + return bs + (color != 0 ? Find1span(bp, offset, bs, be) : Find0span(bp, offset, bs, be)); + } + + private static int Finddiff2(byte[] bp, int offset, int bs, int be, int color) { + return bs < be ? Finddiff(bp, offset, bs, be, color) : be; + } + + private static byte[] zeroruns = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0 - 0xff */ + }; + + private static byte[] oneruns = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8 /* 0xf0 - 0xff */ + }; + + private const int LENGTH = 0; /* bit length of g3 code */ + private const int CODE = 1; /* g3 code */ + private const int RUNLEN = 2; /* run length in bits */ + + private const int EOL = 0x001; /* EOL code value - 0000 0000 0000 1 */ + + /* status values returned instead of a run length */ + private const int G3CODE_EOL = -1; /* NB: ACT_EOL - ACT_WRUNT */ + private const int G3CODE_INVALID = -2; /* NB: ACT_INVALID - ACT_WRUNT */ + private const int G3CODE_EOF = -3; /* end of input data */ + private const int G3CODE_INCOMP = -4; /* incomplete run code */ + + private int[][] TIFFFaxWhiteCodes = { + new int[]{ 8, 0x35, 0 }, /* 0011 0101 */ + new int[]{ 6, 0x7, 1 }, /* 0001 11 */ + new int[]{ 4, 0x7, 2 }, /* 0111 */ + new int[]{ 4, 0x8, 3 }, /* 1000 */ + new int[]{ 4, 0xB, 4 }, /* 1011 */ + new int[]{ 4, 0xC, 5 }, /* 1100 */ + new int[]{ 4, 0xE, 6 }, /* 1110 */ + new int[]{ 4, 0xF, 7 }, /* 1111 */ + new int[]{ 5, 0x13, 8 }, /* 1001 1 */ + new int[]{ 5, 0x14, 9 }, /* 1010 0 */ + new int[]{ 5, 0x7, 10 }, /* 0011 1 */ + new int[]{ 5, 0x8, 11 }, /* 0100 0 */ + new int[]{ 6, 0x8, 12 }, /* 0010 00 */ + new int[]{ 6, 0x3, 13 }, /* 0000 11 */ + new int[]{ 6, 0x34, 14 }, /* 1101 00 */ + new int[]{ 6, 0x35, 15 }, /* 1101 01 */ + new int[]{ 6, 0x2A, 16 }, /* 1010 10 */ + new int[]{ 6, 0x2B, 17 }, /* 1010 11 */ + new int[]{ 7, 0x27, 18 }, /* 0100 111 */ + new int[]{ 7, 0xC, 19 }, /* 0001 100 */ + new int[]{ 7, 0x8, 20 }, /* 0001 000 */ + new int[]{ 7, 0x17, 21 }, /* 0010 111 */ + new int[]{ 7, 0x3, 22 }, /* 0000 011 */ + new int[]{ 7, 0x4, 23 }, /* 0000 100 */ + new int[]{ 7, 0x28, 24 }, /* 0101 000 */ + new int[]{ 7, 0x2B, 25 }, /* 0101 011 */ + new int[]{ 7, 0x13, 26 }, /* 0010 011 */ + new int[]{ 7, 0x24, 27 }, /* 0100 100 */ + new int[]{ 7, 0x18, 28 }, /* 0011 000 */ + new int[]{ 8, 0x2, 29 }, /* 0000 0010 */ + new int[]{ 8, 0x3, 30 }, /* 0000 0011 */ + new int[]{ 8, 0x1A, 31 }, /* 0001 1010 */ + new int[]{ 8, 0x1B, 32 }, /* 0001 1011 */ + new int[]{ 8, 0x12, 33 }, /* 0001 0010 */ + new int[]{ 8, 0x13, 34 }, /* 0001 0011 */ + new int[]{ 8, 0x14, 35 }, /* 0001 0100 */ + new int[]{ 8, 0x15, 36 }, /* 0001 0101 */ + new int[]{ 8, 0x16, 37 }, /* 0001 0110 */ + new int[]{ 8, 0x17, 38 }, /* 0001 0111 */ + new int[]{ 8, 0x28, 39 }, /* 0010 1000 */ + new int[]{ 8, 0x29, 40 }, /* 0010 1001 */ + new int[]{ 8, 0x2A, 41 }, /* 0010 1010 */ + new int[]{ 8, 0x2B, 42 }, /* 0010 1011 */ + new int[]{ 8, 0x2C, 43 }, /* 0010 1100 */ + new int[]{ 8, 0x2D, 44 }, /* 0010 1101 */ + new int[]{ 8, 0x4, 45 }, /* 0000 0100 */ + new int[]{ 8, 0x5, 46 }, /* 0000 0101 */ + new int[]{ 8, 0xA, 47 }, /* 0000 1010 */ + new int[]{ 8, 0xB, 48 }, /* 0000 1011 */ + new int[]{ 8, 0x52, 49 }, /* 0101 0010 */ + new int[]{ 8, 0x53, 50 }, /* 0101 0011 */ + new int[]{ 8, 0x54, 51 }, /* 0101 0100 */ + new int[]{ 8, 0x55, 52 }, /* 0101 0101 */ + new int[]{ 8, 0x24, 53 }, /* 0010 0100 */ + new int[]{ 8, 0x25, 54 }, /* 0010 0101 */ + new int[]{ 8, 0x58, 55 }, /* 0101 1000 */ + new int[]{ 8, 0x59, 56 }, /* 0101 1001 */ + new int[]{ 8, 0x5A, 57 }, /* 0101 1010 */ + new int[]{ 8, 0x5B, 58 }, /* 0101 1011 */ + new int[]{ 8, 0x4A, 59 }, /* 0100 1010 */ + new int[]{ 8, 0x4B, 60 }, /* 0100 1011 */ + new int[]{ 8, 0x32, 61 }, /* 0011 0010 */ + new int[]{ 8, 0x33, 62 }, /* 0011 0011 */ + new int[]{ 8, 0x34, 63 }, /* 0011 0100 */ + new int[]{ 5, 0x1B, 64 }, /* 1101 1 */ + new int[]{ 5, 0x12, 128 }, /* 1001 0 */ + new int[]{ 6, 0x17, 192 }, /* 0101 11 */ + new int[]{ 7, 0x37, 256 }, /* 0110 111 */ + new int[]{ 8, 0x36, 320 }, /* 0011 0110 */ + new int[]{ 8, 0x37, 384 }, /* 0011 0111 */ + new int[]{ 8, 0x64, 448 }, /* 0110 0100 */ + new int[]{ 8, 0x65, 512 }, /* 0110 0101 */ + new int[]{ 8, 0x68, 576 }, /* 0110 1000 */ + new int[]{ 8, 0x67, 640 }, /* 0110 0111 */ + new int[]{ 9, 0xCC, 704 }, /* 0110 0110 0 */ + new int[]{ 9, 0xCD, 768 }, /* 0110 0110 1 */ + new int[]{ 9, 0xD2, 832 }, /* 0110 1001 0 */ + new int[]{ 9, 0xD3, 896 }, /* 0110 1001 1 */ + new int[]{ 9, 0xD4, 960 }, /* 0110 1010 0 */ + new int[]{ 9, 0xD5, 1024 }, /* 0110 1010 1 */ + new int[]{ 9, 0xD6, 1088 }, /* 0110 1011 0 */ + new int[]{ 9, 0xD7, 1152 }, /* 0110 1011 1 */ + new int[]{ 9, 0xD8, 1216 }, /* 0110 1100 0 */ + new int[]{ 9, 0xD9, 1280 }, /* 0110 1100 1 */ + new int[]{ 9, 0xDA, 1344 }, /* 0110 1101 0 */ + new int[]{ 9, 0xDB, 1408 }, /* 0110 1101 1 */ + new int[]{ 9, 0x98, 1472 }, /* 0100 1100 0 */ + new int[]{ 9, 0x99, 1536 }, /* 0100 1100 1 */ + new int[]{ 9, 0x9A, 1600 }, /* 0100 1101 0 */ + new int[]{ 6, 0x18, 1664 }, /* 0110 00 */ + new int[]{ 9, 0x9B, 1728 }, /* 0100 1101 1 */ + new int[]{ 11, 0x8, 1792 }, /* 0000 0001 000 */ + new int[]{ 11, 0xC, 1856 }, /* 0000 0001 100 */ + new int[]{ 11, 0xD, 1920 }, /* 0000 0001 101 */ + new int[]{ 12, 0x12, 1984 }, /* 0000 0001 0010 */ + new int[]{ 12, 0x13, 2048 }, /* 0000 0001 0011 */ + new int[]{ 12, 0x14, 2112 }, /* 0000 0001 0100 */ + new int[]{ 12, 0x15, 2176 }, /* 0000 0001 0101 */ + new int[]{ 12, 0x16, 2240 }, /* 0000 0001 0110 */ + new int[]{ 12, 0x17, 2304 }, /* 0000 0001 0111 */ + new int[]{ 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + new int[]{ 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + new int[]{ 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + new int[]{ 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + new int[]{ 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + new int[]{ 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + new int[]{ 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + new int[]{ 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + new int[]{ 12, 0x0, G3CODE_INVALID } /* 0000 0000 0000 */ + }; + + private int[][] TIFFFaxBlackCodes = { + new int[]{ 10, 0x37, 0 }, /* 0000 1101 11 */ + new int[]{ 3, 0x2, 1 }, /* 010 */ + new int[]{ 2, 0x3, 2 }, /* 11 */ + new int[]{ 2, 0x2, 3 }, /* 10 */ + new int[]{ 3, 0x3, 4 }, /* 011 */ + new int[]{ 4, 0x3, 5 }, /* 0011 */ + new int[]{ 4, 0x2, 6 }, /* 0010 */ + new int[]{ 5, 0x3, 7 }, /* 0001 1 */ + new int[]{ 6, 0x5, 8 }, /* 0001 01 */ + new int[]{ 6, 0x4, 9 }, /* 0001 00 */ + new int[]{ 7, 0x4, 10 }, /* 0000 100 */ + new int[]{ 7, 0x5, 11 }, /* 0000 101 */ + new int[]{ 7, 0x7, 12 }, /* 0000 111 */ + new int[]{ 8, 0x4, 13 }, /* 0000 0100 */ + new int[]{ 8, 0x7, 14 }, /* 0000 0111 */ + new int[]{ 9, 0x18, 15 }, /* 0000 1100 0 */ + new int[]{ 10, 0x17, 16 }, /* 0000 0101 11 */ + new int[]{ 10, 0x18, 17 }, /* 0000 0110 00 */ + new int[]{ 10, 0x8, 18 }, /* 0000 0010 00 */ + new int[]{ 11, 0x67, 19 }, /* 0000 1100 111 */ + new int[]{ 11, 0x68, 20 }, /* 0000 1101 000 */ + new int[]{ 11, 0x6C, 21 }, /* 0000 1101 100 */ + new int[]{ 11, 0x37, 22 }, /* 0000 0110 111 */ + new int[]{ 11, 0x28, 23 }, /* 0000 0101 000 */ + new int[]{ 11, 0x17, 24 }, /* 0000 0010 111 */ + new int[]{ 11, 0x18, 25 }, /* 0000 0011 000 */ + new int[]{ 12, 0xCA, 26 }, /* 0000 1100 1010 */ + new int[]{ 12, 0xCB, 27 }, /* 0000 1100 1011 */ + new int[]{ 12, 0xCC, 28 }, /* 0000 1100 1100 */ + new int[]{ 12, 0xCD, 29 }, /* 0000 1100 1101 */ + new int[]{ 12, 0x68, 30 }, /* 0000 0110 1000 */ + new int[]{ 12, 0x69, 31 }, /* 0000 0110 1001 */ + new int[]{ 12, 0x6A, 32 }, /* 0000 0110 1010 */ + new int[]{ 12, 0x6B, 33 }, /* 0000 0110 1011 */ + new int[]{ 12, 0xD2, 34 }, /* 0000 1101 0010 */ + new int[]{ 12, 0xD3, 35 }, /* 0000 1101 0011 */ + new int[]{ 12, 0xD4, 36 }, /* 0000 1101 0100 */ + new int[]{ 12, 0xD5, 37 }, /* 0000 1101 0101 */ + new int[]{ 12, 0xD6, 38 }, /* 0000 1101 0110 */ + new int[]{ 12, 0xD7, 39 }, /* 0000 1101 0111 */ + new int[]{ 12, 0x6C, 40 }, /* 0000 0110 1100 */ + new int[]{ 12, 0x6D, 41 }, /* 0000 0110 1101 */ + new int[]{ 12, 0xDA, 42 }, /* 0000 1101 1010 */ + new int[]{ 12, 0xDB, 43 }, /* 0000 1101 1011 */ + new int[]{ 12, 0x54, 44 }, /* 0000 0101 0100 */ + new int[]{ 12, 0x55, 45 }, /* 0000 0101 0101 */ + new int[]{ 12, 0x56, 46 }, /* 0000 0101 0110 */ + new int[]{ 12, 0x57, 47 }, /* 0000 0101 0111 */ + new int[]{ 12, 0x64, 48 }, /* 0000 0110 0100 */ + new int[]{ 12, 0x65, 49 }, /* 0000 0110 0101 */ + new int[]{ 12, 0x52, 50 }, /* 0000 0101 0010 */ + new int[]{ 12, 0x53, 51 }, /* 0000 0101 0011 */ + new int[]{ 12, 0x24, 52 }, /* 0000 0010 0100 */ + new int[]{ 12, 0x37, 53 }, /* 0000 0011 0111 */ + new int[]{ 12, 0x38, 54 }, /* 0000 0011 1000 */ + new int[]{ 12, 0x27, 55 }, /* 0000 0010 0111 */ + new int[]{ 12, 0x28, 56 }, /* 0000 0010 1000 */ + new int[]{ 12, 0x58, 57 }, /* 0000 0101 1000 */ + new int[]{ 12, 0x59, 58 }, /* 0000 0101 1001 */ + new int[]{ 12, 0x2B, 59 }, /* 0000 0010 1011 */ + new int[]{ 12, 0x2C, 60 }, /* 0000 0010 1100 */ + new int[]{ 12, 0x5A, 61 }, /* 0000 0101 1010 */ + new int[]{ 12, 0x66, 62 }, /* 0000 0110 0110 */ + new int[]{ 12, 0x67, 63 }, /* 0000 0110 0111 */ + new int[]{ 10, 0xF, 64 }, /* 0000 0011 11 */ + new int[]{ 12, 0xC8, 128 }, /* 0000 1100 1000 */ + new int[]{ 12, 0xC9, 192 }, /* 0000 1100 1001 */ + new int[]{ 12, 0x5B, 256 }, /* 0000 0101 1011 */ + new int[]{ 12, 0x33, 320 }, /* 0000 0011 0011 */ + new int[]{ 12, 0x34, 384 }, /* 0000 0011 0100 */ + new int[]{ 12, 0x35, 448 }, /* 0000 0011 0101 */ + new int[]{ 13, 0x6C, 512 }, /* 0000 0011 0110 0 */ + new int[]{ 13, 0x6D, 576 }, /* 0000 0011 0110 1 */ + new int[]{ 13, 0x4A, 640 }, /* 0000 0010 0101 0 */ + new int[]{ 13, 0x4B, 704 }, /* 0000 0010 0101 1 */ + new int[]{ 13, 0x4C, 768 }, /* 0000 0010 0110 0 */ + new int[]{ 13, 0x4D, 832 }, /* 0000 0010 0110 1 */ + new int[]{ 13, 0x72, 896 }, /* 0000 0011 1001 0 */ + new int[]{ 13, 0x73, 960 }, /* 0000 0011 1001 1 */ + new int[]{ 13, 0x74, 1024 }, /* 0000 0011 1010 0 */ + new int[]{ 13, 0x75, 1088 }, /* 0000 0011 1010 1 */ + new int[]{ 13, 0x76, 1152 }, /* 0000 0011 1011 0 */ + new int[]{ 13, 0x77, 1216 }, /* 0000 0011 1011 1 */ + new int[]{ 13, 0x52, 1280 }, /* 0000 0010 1001 0 */ + new int[]{ 13, 0x53, 1344 }, /* 0000 0010 1001 1 */ + new int[]{ 13, 0x54, 1408 }, /* 0000 0010 1010 0 */ + new int[]{ 13, 0x55, 1472 }, /* 0000 0010 1010 1 */ + new int[]{ 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */ + new int[]{ 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */ + new int[]{ 13, 0x64, 1664 }, /* 0000 0011 0010 0 */ + new int[]{ 13, 0x65, 1728 }, /* 0000 0011 0010 1 */ + new int[]{ 11, 0x8, 1792 }, /* 0000 0001 000 */ + new int[]{ 11, 0xC, 1856 }, /* 0000 0001 100 */ + new int[]{ 11, 0xD, 1920 }, /* 0000 0001 101 */ + new int[]{ 12, 0x12, 1984 }, /* 0000 0001 0010 */ + new int[]{ 12, 0x13, 2048 }, /* 0000 0001 0011 */ + new int[]{ 12, 0x14, 2112 }, /* 0000 0001 0100 */ + new int[]{ 12, 0x15, 2176 }, /* 0000 0001 0101 */ + new int[]{ 12, 0x16, 2240 }, /* 0000 0001 0110 */ + new int[]{ 12, 0x17, 2304 }, /* 0000 0001 0111 */ + new int[]{ 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + new int[]{ 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + new int[]{ 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + new int[]{ 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + new int[]{ 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + new int[]{ 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + new int[]{ 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + new int[]{ 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + new int[]{ 12, 0x0, G3CODE_INVALID } /* 0000 0000 0000 */ + }; + + private int[] horizcode = + { 3, 0x1, 0 }; /* 001 */ + private int[] passcode = + { 4, 0x1, 0 }; /* 0001 */ + private int[][] vcodes = { + new int[]{ 7, 0x03, 0 }, /* 0000 011 */ + new int[]{ 6, 0x03, 0 }, /* 0000 11 */ + new int[]{ 3, 0x03, 0 }, /* 011 */ + new int[]{ 1, 0x1, 0 }, /* 1 */ + new int[]{ 3, 0x2, 0 }, /* 010 */ + new int[]{ 6, 0x02, 0 }, /* 0000 10 */ + new int[]{ 7, 0x02, 0 } /* 0000 010 */ + }; + private int[] msbmask = + { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/GifImage.cs b/iTechSharp/iTextSharp/text/pdf/codec/GifImage.cs new file mode 100644 index 0000000..025264d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/GifImage.cs @@ -0,0 +1,597 @@ +using System; +using System.Net; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec { + /** Reads gif images of all types. All the images in a gif are read in the constructors + * and can be retrieved with other methods. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class GifImage { + + protected Stream inp; + protected int width; // full image width + protected int height; // full image height + protected bool gctFlag; // global color table used + + protected int bgIndex; // background color index + protected int bgColor; // background color + protected int pixelAspect; // pixel aspect ratio + + protected bool lctFlag; // local color table flag + protected bool interlace; // interlace flag + protected int lctSize; // local color table size + + protected int ix, iy, iw, ih; // current image rectangle + + protected byte[] block = new byte[256]; // current data block + protected int blockSize = 0; // block size + + // last graphic control extension info + protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev + protected bool transparency = false; // use transparent color + protected int delay = 0; // delay in milliseconds + protected int transIndex; // transparent color index + + protected const int MaxStackSize = 4096; // max decoder pixel stack size + + // LZW decoder working arrays + protected short[] prefix; + protected byte[] suffix; + protected byte[] pixelStack; + protected byte[] pixels; + + protected byte[] m_out; + protected int m_bpc; + protected int m_gbpc; + protected byte[] m_global_table; + protected byte[] m_local_table; + protected byte[] m_curr_table; + protected int m_line_stride; + protected byte[] fromData; + protected Uri fromUrl; + + + protected ArrayList frames = new ArrayList(); // frames read from current file + + /** Reads gif images from an URL. + * @param url the URL + * @throws IOException on error + */ + public GifImage(Uri url) { + fromUrl = url; + Stream isp = null; + try { + isp = WebRequest.Create(url).GetResponse().GetResponseStream(); + Process(isp); + } + finally { + if (isp != null) { + isp.Close(); + } + } + } + + /** Reads gif images from a file. + * @param file the file + * @throws IOException on error + */ + public GifImage(String file) : this(Utilities.ToURL(file)) { + } + + /** Reads gif images from a byte array. + * @param data the byte array + * @throws IOException on error + */ + public GifImage(byte[] data) { + fromData = data; + Stream isp = null; + try { + isp = new MemoryStream(data); + Process(isp); + } + finally { + if (isp != null) { + isp.Close(); + } + } + } + + /** Reads gif images from a stream. The stream isp not closed. + * @param isp the stream + * @throws IOException on error + */ + public GifImage(Stream isp) { + Process(isp); + } + + /** Gets the number of frames the gif has. + * @return the number of frames the gif has + */ + public int GetFrameCount() { + return frames.Count; + } + + /** Gets the image from a frame. The first frame isp 1. + * @param frame the frame to get the image from + * @return the image + */ + public Image GetImage(int frame) { + GifFrame gf = (GifFrame)frames[frame - 1]; + return gf.image; + } + + /** Gets the [x,y] position of the frame in reference to the + * logical screen. + * @param frame the frame + * @return the [x,y] position of the frame + */ + public int[] GetFramePosition(int frame) { + GifFrame gf = (GifFrame)frames[frame - 1]; + return new int[]{gf.ix, gf.iy}; + + } + + /** Gets the logical screen. The images may be smaller and placed + * in some position in this screen to playback some animation. + * No image will be be bigger that this. + * @return the logical screen dimensions as [x,y] + */ + public int[] GetLogicalScreen() { + return new int[]{width, height}; + } + + internal void Process(Stream isp) { + inp = new BufferedStream(isp); + ReadHeader(); + ReadContents(); + if (frames.Count == 0) + throw new IOException("The file does not contain any valid image."); + } + + /** + * Reads GIF file header information. + */ + protected void ReadHeader() { + String id = ""; + for (int i = 0; i < 6; i++) + id += (char)inp.ReadByte(); + if (!id.StartsWith("GIF8")) { + throw new IOException("Gif signature nor found."); + } + + ReadLSD(); + if (gctFlag) { + m_global_table = ReadColorTable(m_gbpc); + } + } + + /** + * Reads Logical Screen Descriptor + */ + protected void ReadLSD() { + + // logical screen size + width = ReadShort(); + height = ReadShort(); + + // packed fields + int packed = inp.ReadByte(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + m_gbpc = (packed & 7) + 1; + bgIndex = inp.ReadByte(); // background color index + pixelAspect = inp.ReadByte(); // pixel aspect ratio + } + + /** + * Reads next 16-bit value, LSB first + */ + protected int ReadShort() { + // read 16-bit value, LSB first + return inp.ReadByte() | (inp.ReadByte() << 8); + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + protected int ReadBlock() { + blockSize = inp.ReadByte(); + if (blockSize <= 0) + return blockSize = 0; + for (int k = 0; k < blockSize; ++k) { + int v = inp.ReadByte(); + if (v < 0) { + return blockSize = k; + } + block[k] = (byte)v; + } + return blockSize; + } + + protected byte[] ReadColorTable(int bpc) { + int ncolors = 1 << bpc; + int nbytes = 3*ncolors; + bpc = NewBpc(bpc); + byte[] table = new byte[(1 << bpc) * 3]; + ReadFully(table, 0, nbytes); + return table; + } + + + static protected int NewBpc(int bpc) { + switch (bpc) { + case 1: + case 2: + case 4: + break; + case 3: + return 4; + default: + return 8; + } + return bpc; + } + + protected void ReadContents() { + // read GIF file content blocks + bool done = false; + while (!done) { + int code = inp.ReadByte(); + switch (code) { + + case 0x2C: // image separator + ReadImage(); + break; + + case 0x21: // extension + code = inp.ReadByte(); + switch (code) { + + case 0xf9: // graphics control extension + ReadGraphicControlExt(); + break; + + case 0xff: // application extension + ReadBlock(); + Skip(); // don't care + break; + + default: // uninteresting extension + Skip(); + break; + } + break; + + default: + done = true; + break; + } + } + } + + /** + * Reads next frame image + */ + protected void ReadImage() { + ix = ReadShort(); // (sub)image position & size + iy = ReadShort(); + iw = ReadShort(); + ih = ReadShort(); + + int packed = inp.ReadByte(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag + interlace = (packed & 0x40) != 0; // 2 - interlace flag + // 3 - sort flag + // 4-5 - reserved + lctSize = 2 << (packed & 7); // 6-8 - local color table size + m_bpc = NewBpc(m_gbpc); + if (lctFlag) { + m_curr_table = ReadColorTable((packed & 7) + 1); // read table + m_bpc = NewBpc((packed & 7) + 1); + } + else { + m_curr_table = m_global_table; + } + if (transparency && transIndex >= m_curr_table.Length / 3) + transparency = false; + if (transparency && m_bpc == 1) { // Acrobat 5.05 doesn't like this combination + byte[] tp = new byte[12]; + Array.Copy(m_curr_table, 0, tp, 0, 6); + m_curr_table = tp; + m_bpc = 2; + } + bool skipZero = DecodeImageData(); // decode pixel data + if (!skipZero) + Skip(); + + Image img = null; + img = new ImgRaw(iw, ih, 1, m_bpc, m_out); + PdfArray colorspace = new PdfArray(); + colorspace.Add(PdfName.INDEXED); + colorspace.Add(PdfName.DEVICERGB); + int len = m_curr_table.Length; + colorspace.Add(new PdfNumber(len / 3 - 1)); + colorspace.Add(new PdfString(m_curr_table)); + PdfDictionary ad = new PdfDictionary(); + ad.Put(PdfName.COLORSPACE, colorspace); + img.Additional = ad; + if (transparency) { + img.Transparency = new int[]{transIndex, transIndex}; + } + img.OriginalType = Image.ORIGINAL_GIF; + img.OriginalData = fromData; + img.Url = fromUrl; + GifFrame gf = new GifFrame(); + gf.image = img; + gf.ix = ix; + gf.iy = iy; + frames.Add(gf); // add image to frame list + + //ResetFrame(); + + } + + protected bool DecodeImageData() { + int NullCode = -1; + int npix = iw * ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, + bits, code, count, i, datum, data_size, first, top, bi; + bool skipZero = false; + + if (prefix == null) + prefix = new short[MaxStackSize]; + if (suffix == null) + suffix = new byte[MaxStackSize]; + if (pixelStack == null) + pixelStack = new byte[MaxStackSize+1]; + + m_line_stride = (iw * m_bpc + 7) / 8; + m_out = new byte[m_line_stride * ih]; + int pass = 1; + int inc = interlace ? 8 : 1; + int line = 0; + int xpos = 0; + + // Initialize GIF data stream decoder. + + data_size = inp.ReadByte(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = NullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + + datum = bits = count = first = top = bi = 0; + + for (i = 0; i < npix; ) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = ReadBlock(); + if (count <= 0) { + skipZero = true; + break; + } + bi = 0; + } + datum += (((int) block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + + // Get the next code. + + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + + // Interpret the code + + if ((code > available) || (code == end_of_information)) + break; + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = NullCode; + continue; + } + if (old_code == NullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = ((int) suffix[code]) & 0xff; + + // Add a new string to the string table, + + if (available >= MaxStackSize) + break; + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) && (available < MaxStackSize)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + + // Pop a pixel off the pixel stack. + + top--; + i++; + + SetPixel(xpos, line, pixelStack[top]); + ++xpos; + if (xpos >= iw) { + xpos = 0; + line += inc; + if (line >= ih) { + if (interlace) { + do { + pass++; + switch (pass) { + case 2: + line = 4; + break; + case 3: + line = 2; + inc = 4; + break; + case 4: + line = 1; + inc = 2; + break; + default: // this shouldn't happen + line = ih - 1; + inc = 0; + break; + } + } while (line >= ih); + } + else { + line = ih - 1; // this shouldn't happen + inc = 0; + } + } + } + } + return skipZero; + } + + + protected void SetPixel(int x, int y, int v) { + if (m_bpc == 8) { + int pos = x + iw * y; + m_out[pos] = (byte)v; + } + else { + int pos = m_line_stride * y + x / (8 / m_bpc); + int vout = v << (8 - m_bpc * (x % (8 / m_bpc))- m_bpc); + m_out[pos] |= (byte)vout; + } + } + + /** + * Resets frame state for reading next image. + */ + protected void ResetFrame() { + } + + /** + * Reads Graphics Control Extension values + */ + protected void ReadGraphicControlExt() { + inp.ReadByte(); // block size + int packed = inp.ReadByte(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) + dispose = 1; // elect to keep old image if discretionary + transparency = (packed & 1) != 0; + delay = ReadShort() * 10; // delay inp milliseconds + transIndex = inp.ReadByte(); // transparent color index + inp.ReadByte(); // block terminator + } + + /** + * Skips variable length blocks up to and including + * next zero length block. + */ + protected void Skip() { + do { + ReadBlock(); + } while (blockSize > 0); + } + + private void ReadFully(byte[] b, int offset, int count) { + while (count > 0) { + int n = inp.Read(b, offset, count); + if (n <= 0) + throw new IOException("Insufficient data."); + count -= n; + offset += n; + } + } + + internal class GifFrame { + internal Image image; + internal int ix; + internal int iy; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/PngImage.cs b/iTechSharp/iTextSharp/text/pdf/codec/PngImage.cs new file mode 100644 index 0000000..0e6473e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/PngImage.cs @@ -0,0 +1,971 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using System.util.zlib; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * Copyright 2003-2008 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * This code is based on a series of source files originally released + * by SUN in the context of the JAI project. The original code was released + * under the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +namespace iTextSharp.text.pdf.codec { + /** Reads a PNG image. All types of PNG can be read. + *

    + * It is based in part in the JAI codec. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PngImage { + /** Some PNG specific values. */ + public static int[] PNGID = {137, 80, 78, 71, 13, 10, 26, 10}; + + /** A PNG marker. */ + public const String IHDR = "IHDR"; + + /** A PNG marker. */ + public const String PLTE = "PLTE"; + + /** A PNG marker. */ + public const String IDAT = "IDAT"; + + /** A PNG marker. */ + public const String IEND = "IEND"; + + /** A PNG marker. */ + public const String tRNS = "tRNS"; + + /** A PNG marker. */ + public const String pHYs = "pHYs"; + + /** A PNG marker. */ + public const String gAMA = "gAMA"; + + /** A PNG marker. */ + public const String cHRM = "cHRM"; + + /** A PNG marker. */ + public const String sRGB = "sRGB"; + + /** A PNG marker. */ + public const String iCCP = "iCCP"; + + private const int TRANSFERSIZE = 4096; + private const int PNG_FILTER_NONE = 0; + private const int PNG_FILTER_SUB = 1; + private const int PNG_FILTER_UP = 2; + private const int PNG_FILTER_AVERAGE = 3; + private const int PNG_FILTER_PAETH = 4; + private static PdfName[] intents = {PdfName.PERCEPTUAL, + PdfName.RELATIVECALORIMETRIC,PdfName.SATURATION,PdfName.ABSOLUTECALORIMETRIC}; + + Stream isp; + Stream dataStream; + int width; + int height; + int bitDepth; + int colorType; + int compressionMethod; + int filterMethod; + int interlaceMethod; + PdfDictionary additional = new PdfDictionary(); + byte[] image; + byte[] smask; + byte[] trans; + MemoryStream idat = new MemoryStream(); + int dpiX; + int dpiY; + float XYRatio; + bool genBWMask; + bool palShades; + int transRedGray = -1; + int transGreen = -1; + int transBlue = -1; + int inputBands; + int bytesPerPixel; // number of bytes per input pixel + byte[] colorTable; + float gamma = 1f; + bool hasCHRM = false; + float xW, yW, xR, yR, xG, yG, xB, yB; + PdfName intent; + ICC_Profile icc_profile; + + + + /** Creates a new instance of PngImage */ + PngImage(Stream isp) { + this.isp = isp; + } + + /** Reads a PNG from an url. + * @param url the url + * @throws IOException on error + * @return the image + */ + public static Image GetImage(Uri url) { + Stream isp = null; + try { + isp = WebRequest.Create(url).GetResponse().GetResponseStream(); + Image img = GetImage(isp); + img.Url = url; + return img; + } + finally { + if (isp != null) { + isp.Close(); + } + } + } + + /** Reads a PNG from a stream. + * @param is the stream + * @throws IOException on error + * @return the image + */ + public static Image GetImage(Stream isp) { + PngImage png = new PngImage(isp); + return png.GetImage(); + } + + /** Reads a PNG from a file. + * @param file the file + * @throws IOException on error + * @return the image + */ + public static Image GetImage(String file) { + return GetImage(Utilities.ToURL(file)); + } + + /** Reads a PNG from a byte array. + * @param data the byte array + * @throws IOException on error + * @return the image + */ + public static Image GetImage(byte[] data) { + Stream isp = new MemoryStream(data); + Image img = GetImage(isp); + img.OriginalData = data; + return img; + } + + static bool CheckMarker(String s) { + if (s.Length != 4) + return false; + for (int k = 0; k < 4; ++k) { + char c = s[k]; + if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) + return false; + } + return true; + } + + void ReadPng() { + for (int i = 0; i < PNGID.Length; i++) { + if (PNGID[i] != isp.ReadByte()) { + throw new IOException("File is not a valid PNG."); + } + } + byte[] buffer = new byte[TRANSFERSIZE]; + while (true) { + int len = GetInt(isp); + String marker = GetString(isp); + if (len < 0 || !CheckMarker(marker)) + throw new IOException("Corrupted PNG file."); + if (IDAT.Equals(marker)) { + int size; + while (len != 0) { + size = isp.Read(buffer, 0, Math.Min(len, TRANSFERSIZE)); + if (size <= 0) + return; + idat.Write(buffer, 0, size); + len -= size; + } + } + else if (tRNS.Equals(marker)) { + switch (colorType) { + case 0: + if (len >= 2) { + len -= 2; + int gray = GetWord(isp); + if (bitDepth == 16) + transRedGray = gray; + else + additional.Put(PdfName.MASK, new PdfLiteral("["+gray+" "+gray+"]")); + } + break; + case 2: + if (len >= 6) { + len -= 6; + int red = GetWord(isp); + int green = GetWord(isp); + int blue = GetWord(isp); + if (bitDepth == 16) { + transRedGray = red; + transGreen = green; + transBlue = blue; + } + else + additional.Put(PdfName.MASK, new PdfLiteral("["+red+" "+red+" "+green+" "+green+" "+blue+" "+blue+"]")); + } + break; + case 3: + if (len > 0) { + trans = new byte[len]; + for (int k = 0; k < len; ++k) + trans[k] = (byte)isp.ReadByte(); + len = 0; + } + break; + } + Utilities.Skip(isp, len); + } + else if (IHDR.Equals(marker)) { + width = GetInt(isp); + height = GetInt(isp); + + bitDepth = isp.ReadByte(); + colorType = isp.ReadByte(); + compressionMethod = isp.ReadByte(); + filterMethod = isp.ReadByte(); + interlaceMethod = isp.ReadByte(); + } + else if (PLTE.Equals(marker)) { + if (colorType == 3) { + PdfArray colorspace = new PdfArray(); + colorspace.Add(PdfName.INDEXED); + colorspace.Add(GetColorspace()); + colorspace.Add(new PdfNumber(len / 3 - 1)); + ByteBuffer colortable = new ByteBuffer(); + while ((len--) > 0) { + colortable.Append_i(isp.ReadByte()); + } + colorspace.Add(new PdfString(colorTable = colortable.ToByteArray())); + additional.Put(PdfName.COLORSPACE, colorspace); + } + else { + Utilities.Skip(isp, len); + } + } + else if (pHYs.Equals(marker)) { + int dx = GetInt(isp); + int dy = GetInt(isp); + int unit = isp.ReadByte(); + if (unit == 1) { + dpiX = (int)((float)dx * 0.0254f + 0.5f); + dpiY = (int)((float)dy * 0.0254f + 0.5f); + } + else { + if (dy != 0) + XYRatio = (float)dx / (float)dy; + } + } + else if (cHRM.Equals(marker)) { + xW = (float)GetInt(isp) / 100000f; + yW = (float)GetInt(isp) / 100000f; + xR = (float)GetInt(isp) / 100000f; + yR = (float)GetInt(isp) / 100000f; + xG = (float)GetInt(isp) / 100000f; + yG = (float)GetInt(isp) / 100000f; + xB = (float)GetInt(isp) / 100000f; + yB = (float)GetInt(isp) / 100000f; + hasCHRM = !(Math.Abs(xW)<0.0001f||Math.Abs(yW)<0.0001f||Math.Abs(xR)<0.0001f||Math.Abs(yR)<0.0001f||Math.Abs(xG)<0.0001f||Math.Abs(yG)<0.0001f||Math.Abs(xB)<0.0001f||Math.Abs(yB)<0.0001f); + } + else if (sRGB.Equals(marker)) { + int ri = isp.ReadByte(); + intent = intents[ri]; + gamma = 2.2f; + xW = 0.3127f; + yW = 0.329f; + xR = 0.64f; + yR = 0.33f; + xG = 0.3f; + yG = 0.6f; + xB = 0.15f; + yB = 0.06f; + hasCHRM = true; + } + else if (gAMA.Equals(marker)) { + int gm = GetInt(isp); + if (gm != 0) { + gamma = 100000f / (float)gm; + if (!hasCHRM) { + xW = 0.3127f; + yW = 0.329f; + xR = 0.64f; + yR = 0.33f; + xG = 0.3f; + yG = 0.6f; + xB = 0.15f; + yB = 0.06f; + hasCHRM = true; + } + } + } + else if (iCCP.Equals(marker)) { + do { + --len; + } while (isp.ReadByte() != 0); + isp.ReadByte(); + --len; + byte[] icccom = new byte[len]; + int p = 0; + while (len > 0) { + int r = isp.Read(icccom, p, len); + if (r < 0) + throw new IOException("Premature end of file."); + p += r; + len -= r; + } + byte[] iccp = PdfReader.FlateDecode(icccom, true); + icccom = null; + try { + icc_profile = ICC_Profile.GetInstance(iccp); + } + catch { + icc_profile = null; + } + } + else if (IEND.Equals(marker)) { + break; + } + else { + Utilities.Skip(isp, len); + } + Utilities.Skip(isp, 4); + } + } + + PdfObject GetColorspace() { + if (icc_profile != null) { + if ((colorType & 2) == 0) + return PdfName.DEVICEGRAY; + else + return PdfName.DEVICERGB; + } + if (gamma == 1f && !hasCHRM) { + if ((colorType & 2) == 0) + return PdfName.DEVICEGRAY; + else + return PdfName.DEVICERGB; + } + else { + PdfArray array = new PdfArray(); + PdfDictionary dic = new PdfDictionary(); + if ((colorType & 2) == 0) { + if (gamma == 1f) + return PdfName.DEVICEGRAY; + array.Add(PdfName.CALGRAY); + dic.Put(PdfName.GAMMA, new PdfNumber(gamma)); + dic.Put(PdfName.WHITEPOINT, new PdfLiteral("[1 1 1]")); + array.Add(dic); + } + else { + PdfObject wp = new PdfLiteral("[1 1 1]"); + array.Add(PdfName.CALRGB); + if (gamma != 1f) { + PdfArray gm = new PdfArray(); + PdfNumber n = new PdfNumber(gamma); + gm.Add(n); + gm.Add(n); + gm.Add(n); + dic.Put(PdfName.GAMMA, gm); + } + if (hasCHRM) { + float z = yW*((xG-xB)*yR-(xR-xB)*yG+(xR-xG)*yB); + float YA = yR*((xG-xB)*yW-(xW-xB)*yG+(xW-xG)*yB)/z; + float XA = YA*xR/yR; + float ZA = YA*((1-xR)/yR-1); + float YB = -yG*((xR-xB)*yW-(xW-xB)*yR+(xW-xR)*yB)/z; + float XB = YB*xG/yG; + float ZB = YB*((1-xG)/yG-1); + float YC = yB*((xR-xG)*yW-(xW-xG)*yW+(xW-xR)*yG)/z; + float XC = YC*xB/yB; + float ZC = YC*((1-xB)/yB-1); + float XW = XA+XB+XC; + float YW = 1;//YA+YB+YC; + float ZW = ZA+ZB+ZC; + PdfArray wpa = new PdfArray(); + wpa.Add(new PdfNumber(XW)); + wpa.Add(new PdfNumber(YW)); + wpa.Add(new PdfNumber(ZW)); + wp = wpa; + PdfArray matrix = new PdfArray(); + matrix.Add(new PdfNumber(XA)); + matrix.Add(new PdfNumber(YA)); + matrix.Add(new PdfNumber(ZA)); + matrix.Add(new PdfNumber(XB)); + matrix.Add(new PdfNumber(YB)); + matrix.Add(new PdfNumber(ZB)); + matrix.Add(new PdfNumber(XC)); + matrix.Add(new PdfNumber(YC)); + matrix.Add(new PdfNumber(ZC)); + dic.Put(PdfName.MATRIX, matrix); + } + dic.Put(PdfName.WHITEPOINT, wp); + array.Add(dic); + } + return array; + } + } + + Image GetImage() { + ReadPng(); + int pal0 = 0; + int palIdx = 0; + palShades = false; + if (trans != null) { + for (int k = 0; k < trans.Length; ++k) { + int n = trans[k] & 0xff; + if (n == 0) { + ++pal0; + palIdx = k; + } + if (n != 0 && n != 255) { + palShades = true; + break; + } + } + } + if ((colorType & 4) != 0) + palShades = true; + genBWMask = (!palShades && (pal0 > 1 || transRedGray >= 0)); + if (!palShades && !genBWMask && pal0 == 1) { + additional.Put(PdfName.MASK, new PdfLiteral("["+palIdx+" "+palIdx+"]")); + } + bool needDecode = (interlaceMethod == 1) || (bitDepth == 16) || ((colorType & 4) != 0) || palShades || genBWMask; + switch (colorType) { + case 0: + inputBands = 1; + break; + case 2: + inputBands = 3; + break; + case 3: + inputBands = 1; + break; + case 4: + inputBands = 2; + break; + case 6: + inputBands = 4; + break; + } + if (needDecode) + DecodeIdat(); + int components = inputBands; + if ((colorType & 4) != 0) + --components; + int bpc = bitDepth; + if (bpc == 16) + bpc = 8; + Image img; + if (image != null) + img = Image.GetInstance(width, height, components, bpc, image); + else { + img = new ImgRaw(width, height, components, bpc, idat.ToArray()); + img.Deflated = true; + PdfDictionary decodeparms = new PdfDictionary(); + decodeparms.Put(PdfName.BITSPERCOMPONENT, new PdfNumber(bitDepth)); + decodeparms.Put(PdfName.PREDICTOR, new PdfNumber(15)); + decodeparms.Put(PdfName.COLUMNS, new PdfNumber(width)); + decodeparms.Put(PdfName.COLORS, new PdfNumber((colorType == 3 || (colorType & 2) == 0) ? 1 : 3)); + additional.Put(PdfName.DECODEPARMS, decodeparms); + } + if (additional.Get(PdfName.COLORSPACE) == null) + additional.Put(PdfName.COLORSPACE, GetColorspace()); + if (intent != null) + additional.Put(PdfName.INTENT, intent); + if (additional.Size > 0) + img.Additional = additional; + if (icc_profile != null) + img.TagICC = icc_profile; + if (palShades) { + Image im2 = Image.GetInstance(width, height, 1, 8, smask); + im2.MakeMask(); + img.ImageMask = im2; + } + if (genBWMask) { + Image im2 = Image.GetInstance(width, height, 1, 1, smask); + im2.MakeMask(); + img.ImageMask = im2; + } + img.SetDpi(dpiX, dpiY); + img.XYRatio = XYRatio; + img.OriginalType = Image.ORIGINAL_PNG; + return img; + } + + void DecodeIdat() { + int nbitDepth = bitDepth; + if (nbitDepth == 16) + nbitDepth = 8; + int size = -1; + bytesPerPixel = (bitDepth == 16) ? 2 : 1; + switch (colorType) { + case 0: + size = (nbitDepth * width + 7) / 8 * height; + break; + case 2: + size = width * 3 * height; + bytesPerPixel *= 3; + break; + case 3: + if (interlaceMethod == 1) + size = (nbitDepth * width + 7) / 8 * height; + bytesPerPixel = 1; + break; + case 4: + size = width * height; + bytesPerPixel *= 2; + break; + case 6: + size = width * 3 * height; + bytesPerPixel *= 4; + break; + } + if (size >= 0) + image = new byte[size]; + if (palShades) + smask = new byte[width * height]; + else if (genBWMask) + smask = new byte[(width + 7) / 8 * height]; + idat.Position = 0; + dataStream = new ZInflaterInputStream(idat); + + if (interlaceMethod != 1) { + DecodePass(0, 0, 1, 1, width, height); + } + else { + DecodePass(0, 0, 8, 8, (width + 7)/8, (height + 7)/8); + DecodePass(4, 0, 8, 8, (width + 3)/8, (height + 7)/8); + DecodePass(0, 4, 4, 8, (width + 3)/4, (height + 3)/8); + DecodePass(2, 0, 4, 4, (width + 1)/4, (height + 3)/4); + DecodePass(0, 2, 2, 4, (width + 1)/2, (height + 1)/4); + DecodePass(1, 0, 2, 2, width/2, (height + 1)/2); + DecodePass(0, 1, 1, 2, width, height/2); + } + + } + + void DecodePass( int xOffset, int yOffset, + int xStep, int yStep, + int passWidth, int passHeight) { + if ((passWidth == 0) || (passHeight == 0)) { + return; + } + + int bytesPerRow = (inputBands*passWidth*bitDepth + 7)/8; + byte[] curr = new byte[bytesPerRow]; + byte[] prior = new byte[bytesPerRow]; + + // Decode the (sub)image row-by-row + int srcY, dstY; + for (srcY = 0, dstY = yOffset; + srcY < passHeight; + srcY++, dstY += yStep) { + // Read the filter type byte and a row of data + int filter = 0; + try { + filter = dataStream.ReadByte(); + ReadFully(dataStream,curr, 0, bytesPerRow); + } catch { + // empty on purpose + } + + switch (filter) { + case PNG_FILTER_NONE: + break; + case PNG_FILTER_SUB: + DecodeSubFilter(curr, bytesPerRow, bytesPerPixel); + break; + case PNG_FILTER_UP: + DecodeUpFilter(curr, prior, bytesPerRow); + break; + case PNG_FILTER_AVERAGE: + DecodeAverageFilter(curr, prior, bytesPerRow, bytesPerPixel); + break; + case PNG_FILTER_PAETH: + DecodePaethFilter(curr, prior, bytesPerRow, bytesPerPixel); + break; + default: + // Error -- uknown filter type + throw new Exception("PNG filter unknown."); + } + + ProcessPixels(curr, xOffset, xStep, dstY, passWidth); + + // Swap curr and prior + byte[] tmp = prior; + prior = curr; + curr = tmp; + } + } + + void ProcessPixels(byte[] curr, int xOffset, int step, int y, int width) { + int srcX, dstX; + + int[] outp = GetPixel(curr); + int sizes = 0; + switch (colorType) { + case 0: + case 3: + case 4: + sizes = 1; + break; + case 2: + case 6: + sizes = 3; + break; + } + if (image != null) { + dstX = xOffset; + int yStride = (sizes*this.width*(bitDepth == 16 ? 8 : bitDepth)+ 7)/8; + for (srcX = 0; srcX < width; srcX++) { + SetPixel(image, outp, inputBands * srcX, sizes, dstX, y, bitDepth, yStride); + dstX += step; + } + } + if (palShades) { + if ((colorType & 4) != 0) { + if (bitDepth == 16) { + for (int k = 0; k < width; ++k) { + int t = k * inputBands + sizes; + outp[t] = Util.USR(outp[t], 8); + } + } + int yStride = this.width; + dstX = xOffset; + for (srcX = 0; srcX < width; srcX++) { + SetPixel(smask, outp, inputBands * srcX + sizes, 1, dstX, y, 8, yStride); + dstX += step; + } + } + else { //colorType 3 + int yStride = this.width; + int[] v = new int[1]; + dstX = xOffset; + for (srcX = 0; srcX < width; srcX++) { + int idx = outp[srcX]; + if (idx < trans.Length) + v[0] = trans[idx]; + SetPixel(smask, v, 0, 1, dstX, y, 8, yStride); + dstX += step; + } + } + } + else if (genBWMask) { + switch (colorType) { + case 3: { + int yStride = (this.width + 7) / 8; + int[] v = new int[1]; + dstX = xOffset; + for (srcX = 0; srcX < width; srcX++) { + int idx = outp[srcX]; + if (idx < trans.Length) + v[0] = (trans[idx] == 0 ? 1 : 0); + SetPixel(smask, v, 0, 1, dstX, y, 1, yStride); + dstX += step; + } + break; + } + case 0: { + int yStride = (this.width + 7) / 8; + int[] v = new int[1]; + dstX = xOffset; + for (srcX = 0; srcX < width; srcX++) { + int g = outp[srcX]; + v[0] = (g == transRedGray ? 1 : 0); + SetPixel(smask, v, 0, 1, dstX, y, 1, yStride); + dstX += step; + } + break; + } + case 2: { + int yStride = (this.width + 7) / 8; + int[] v = new int[1]; + dstX = xOffset; + for (srcX = 0; srcX < width; srcX++) { + int markRed = inputBands * srcX; + v[0] = (outp[markRed] == transRedGray && outp[markRed + 1] == transGreen + && outp[markRed + 2] == transBlue ? 1 : 0); + SetPixel(smask, v, 0, 1, dstX, y, 1, yStride); + dstX += step; + } + break; + } + } + } + } + + static int GetPixel(byte[] image, int x, int y, int bitDepth, int bytesPerRow) { + if (bitDepth == 8) { + int pos = bytesPerRow * y + x; + return image[pos] & 0xff; + } + else { + int pos = bytesPerRow * y + x / (8 / bitDepth); + int v = image[pos] >> (8 - bitDepth * (x % (8 / bitDepth))- bitDepth); + return v & ((1 << bitDepth) - 1); + } + } + + static void SetPixel(byte[] image, int[] data, int offset, int size, int x, int y, int bitDepth, int bytesPerRow) { + if (bitDepth == 8) { + int pos = bytesPerRow * y + size * x; + for (int k = 0; k < size; ++k) + image[pos + k] = (byte)data[k + offset]; + } + else if (bitDepth == 16) { + int pos = bytesPerRow * y + size * x; + for (int k = 0; k < size; ++k) + image[pos + k] = (byte)(data[k + offset] >> 8); + } + else { + int pos = bytesPerRow * y + x / (8 / bitDepth); + int v = data[offset] << (8 - bitDepth * (x % (8 / bitDepth))- bitDepth); + image[pos] |= (byte)v; + } + } + + int[] GetPixel(byte[] curr) { + switch (bitDepth) { + case 8: { + int[] outp = new int[curr.Length]; + for (int k = 0; k < outp.Length; ++k) + outp[k] = curr[k] & 0xff; + return outp; + } + case 16: { + int[] outp = new int[curr.Length / 2]; + for (int k = 0; k < outp.Length; ++k) + outp[k] = ((curr[k * 2] & 0xff) << 8) + (curr[k * 2 + 1] & 0xff); + return outp; + } + default: { + int[] outp = new int[curr.Length * 8 / bitDepth]; + int idx = 0; + int passes = 8 / bitDepth; + int mask = (1 << bitDepth) - 1; + for (int k = 0; k < curr.Length; ++k) { + for (int j = passes - 1; j >= 0; --j) { + outp[idx++] = Util.USR(curr[k], bitDepth * j) & mask; + } + } + return outp; + } + } + } + + private static void DecodeSubFilter(byte[] curr, int count, int bpp) { + for (int i = bpp; i < count; i++) { + int val; + + val = curr[i] & 0xff; + val += curr[i - bpp] & 0xff; + + curr[i] = (byte)val; + } + } + + private static void DecodeUpFilter(byte[] curr, byte[] prev, + int count) { + for (int i = 0; i < count; i++) { + int raw = curr[i] & 0xff; + int prior = prev[i] & 0xff; + + curr[i] = (byte)(raw + prior); + } + } + + private static void DecodeAverageFilter(byte[] curr, byte[] prev, + int count, int bpp) { + int raw, priorPixel, priorRow; + + for (int i = 0; i < bpp; i++) { + raw = curr[i] & 0xff; + priorRow = prev[i] & 0xff; + + curr[i] = (byte)(raw + priorRow/2); + } + + for (int i = bpp; i < count; i++) { + raw = curr[i] & 0xff; + priorPixel = curr[i - bpp] & 0xff; + priorRow = prev[i] & 0xff; + + curr[i] = (byte)(raw + (priorPixel + priorRow)/2); + } + } + + private static int PaethPredictor(int a, int b, int c) { + int p = a + b - c; + int pa = Math.Abs(p - a); + int pb = Math.Abs(p - b); + int pc = Math.Abs(p - c); + + if ((pa <= pb) && (pa <= pc)) { + return a; + } else if (pb <= pc) { + return b; + } else { + return c; + } + } + + private static void DecodePaethFilter(byte[] curr, byte[] prev, + int count, int bpp) { + int raw, priorPixel, priorRow, priorRowPixel; + + for (int i = 0; i < bpp; i++) { + raw = curr[i] & 0xff; + priorRow = prev[i] & 0xff; + + curr[i] = (byte)(raw + priorRow); + } + + for (int i = bpp; i < count; i++) { + raw = curr[i] & 0xff; + priorPixel = curr[i - bpp] & 0xff; + priorRow = prev[i] & 0xff; + priorRowPixel = prev[i - bpp] & 0xff; + + curr[i] = (byte)(raw + PaethPredictor(priorPixel, + priorRow, + priorRowPixel)); + } + } + + /** + * Gets an int from an Stream. + * + * @param is an Stream + * @return the value of an int + */ + + public static int GetInt(Stream isp) { + return (isp.ReadByte() << 24) + (isp.ReadByte() << 16) + (isp.ReadByte() << 8) + isp.ReadByte(); + } + + /** + * Gets a word from an Stream. + * + * @param is an Stream + * @return the value of an int + */ + + public static int GetWord(Stream isp) { + return (isp.ReadByte() << 8) + isp.ReadByte(); + } + + /** + * Gets a String from an Stream. + * + * @param is an Stream + * @return the value of an int + */ + + public static String GetString(Stream isp) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < 4; i++) { + buf.Append((char)isp.ReadByte()); + } + return buf.ToString(); + } + + private static void ReadFully(Stream inp, byte[] b, int offset, int count) { + while (count > 0) { + int n = inp.Read(b, offset, count); + if (n <= 0) + throw new IOException("Insufficient data."); + count -= n; + offset += n; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/TIFFConstants.cs b/iTechSharp/iTextSharp/text/pdf/codec/TIFFConstants.cs new file mode 100644 index 0000000..4b7ee46 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/TIFFConstants.cs @@ -0,0 +1,282 @@ +using System; +/* + * Copyright 2003-2005 by Paulo Soares. + * + * This list of constants was originally released with libtiff + * under the following license: + * + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +namespace iTextSharp.text.pdf.codec { +/** + * A list of constants used in class TIFFImage. + */ + public class TIFFConstants { + + /* + * TIFF Tag Definitions (from tifflib). + */ + public const int TIFFTAG_SUBFILETYPE = 254; /* subfile data descriptor */ + public const int FILETYPE_REDUCEDIMAGE = 0x1; /* reduced resolution version */ + public const int FILETYPE_PAGE = 0x2; /* one page of many */ + public const int FILETYPE_MASK = 0x4; /* transparency mask */ + public const int TIFFTAG_OSUBFILETYPE = 255; /* +kind of data in subfile */ + public const int OFILETYPE_IMAGE = 1; /* full resolution image data */ + public const int OFILETYPE_REDUCEDIMAGE = 2; /* reduced size image data */ + public const int OFILETYPE_PAGE = 3; /* one page of many */ + public const int TIFFTAG_IMAGEWIDTH = 256; /* image width in pixels */ + public const int TIFFTAG_IMAGELENGTH = 257; /* image height in pixels */ + public const int TIFFTAG_BITSPERSAMPLE = 258; /* bits per channel (sample) */ + public const int TIFFTAG_COMPRESSION = 259; /* data compression technique */ + public const int COMPRESSION_NONE = 1; /* dump mode */ + public const int COMPRESSION_CCITTRLE = 2; /* CCITT modified Huffman RLE */ + public const int COMPRESSION_CCITTFAX3 = 3; /* CCITT Group 3 fax encoding */ + public const int COMPRESSION_CCITTFAX4 = 4; /* CCITT Group 4 fax encoding */ + public const int COMPRESSION_LZW = 5; /* Lempel-Ziv & Welch */ + public const int COMPRESSION_OJPEG = 6; /* !6.0 JPEG */ + public const int COMPRESSION_JPEG = 7; /* %JPEG DCT compression */ + public const int COMPRESSION_NEXT = 32766; /* NeXT 2-bit RLE */ + public const int COMPRESSION_CCITTRLEW = 32771; /* #1 w/ word alignment */ + public const int COMPRESSION_PACKBITS = 32773; /* Macintosh RLE */ + public const int COMPRESSION_THUNDERSCAN = 32809; /* ThunderScan RLE */ + /* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ + public const int COMPRESSION_DCS = 32947; /* Kodak DCS encoding */ + public const int COMPRESSION_JBIG = 34661; /* ISO JBIG */ + public const int COMPRESSION_SGILOG = 34676; /* SGI Log Luminance RLE */ + public const int COMPRESSION_SGILOG24 = 34677; /* SGI Log 24-bit packed */ + public const int TIFFTAG_PHOTOMETRIC = 262; /* photometric interpretation */ + public const int PHOTOMETRIC_MINISWHITE = 0; /* min value is white */ + public const int PHOTOMETRIC_MINISBLACK = 1; /* min value is black */ + public const int PHOTOMETRIC_RGB = 2; /* RGB color model */ + public const int PHOTOMETRIC_PALETTE = 3; /* color map indexed */ + public const int PHOTOMETRIC_MASK = 4; /* $holdout mask */ + public const int PHOTOMETRIC_SEPARATED = 5; /* !color separations */ + public const int PHOTOMETRIC_YCBCR = 6; /* !CCIR 601 */ + public const int PHOTOMETRIC_CIELAB = 8; /* !1976 CIE L*a*b* */ + public const int PHOTOMETRIC_LOGL = 32844; /* CIE Log2(L) */ + public const int PHOTOMETRIC_LOGLUV = 32845; /* CIE Log2(L) (u',v') */ + public const int TIFFTAG_THRESHHOLDING = 263; /* +thresholding used on data */ + public const int THRESHHOLD_BILEVEL = 1; /* b&w art scan */ + public const int THRESHHOLD_HALFTONE = 2; /* or dithered scan */ + public const int THRESHHOLD_ERRORDIFFUSE = 3; /* usually floyd-steinberg */ + public const int TIFFTAG_CELLWIDTH = 264; /* +dithering matrix width */ + public const int TIFFTAG_CELLLENGTH = 265; /* +dithering matrix height */ + public const int TIFFTAG_FILLORDER = 266; /* data order within a byte */ + public const int FILLORDER_MSB2LSB = 1; /* most significant -> least */ + public const int FILLORDER_LSB2MSB = 2; /* least significant -> most */ + public const int TIFFTAG_DOCUMENTNAME = 269; /* name of doc. image is from */ + public const int TIFFTAG_IMAGEDESCRIPTION = 270; /* info about image */ + public const int TIFFTAG_MAKE = 271; /* scanner manufacturer name */ + public const int TIFFTAG_MODEL = 272; /* scanner model name/number */ + public const int TIFFTAG_STRIPOFFSETS = 273; /* offsets to data strips */ + public const int TIFFTAG_ORIENTATION = 274; /* +image orientation */ + public const int ORIENTATION_TOPLEFT = 1; /* row 0 top, col 0 lhs */ + public const int ORIENTATION_TOPRIGHT = 2; /* row 0 top, col 0 rhs */ + public const int ORIENTATION_BOTRIGHT = 3; /* row 0 bottom, col 0 rhs */ + public const int ORIENTATION_BOTLEFT = 4; /* row 0 bottom, col 0 lhs */ + public const int ORIENTATION_LEFTTOP = 5; /* row 0 lhs, col 0 top */ + public const int ORIENTATION_RIGHTTOP = 6; /* row 0 rhs, col 0 top */ + public const int ORIENTATION_RIGHTBOT = 7; /* row 0 rhs, col 0 bottom */ + public const int ORIENTATION_LEFTBOT = 8; /* row 0 lhs, col 0 bottom */ + public const int TIFFTAG_SAMPLESPERPIXEL = 277; /* samples per pixel */ + public const int TIFFTAG_ROWSPERSTRIP = 278; /* rows per strip of data */ + public const int TIFFTAG_STRIPBYTECOUNTS = 279; /* bytes counts for strips */ + public const int TIFFTAG_MINSAMPLEVALUE = 280; /* +minimum sample value */ + public const int TIFFTAG_MAXSAMPLEVALUE = 281; /* +maximum sample value */ + public const int TIFFTAG_XRESOLUTION = 282; /* pixels/resolution in x */ + public const int TIFFTAG_YRESOLUTION = 283; /* pixels/resolution in y */ + public const int TIFFTAG_PLANARCONFIG = 284; /* storage organization */ + public const int PLANARCONFIG_CONTIG = 1; /* single image plane */ + public const int PLANARCONFIG_SEPARATE = 2; /* separate planes of data */ + public const int TIFFTAG_PAGENAME = 285; /* page name image is from */ + public const int TIFFTAG_XPOSITION = 286; /* x page offset of image lhs */ + public const int TIFFTAG_YPOSITION = 287; /* y page offset of image lhs */ + public const int TIFFTAG_FREEOFFSETS = 288; /* +byte offset to free block */ + public const int TIFFTAG_FREEBYTECOUNTS = 289; /* +sizes of free blocks */ + public const int TIFFTAG_GRAYRESPONSEUNIT = 290; /* $gray scale curve accuracy */ + public const int GRAYRESPONSEUNIT_10S = 1; /* tenths of a unit */ + public const int GRAYRESPONSEUNIT_100S = 2; /* hundredths of a unit */ + public const int GRAYRESPONSEUNIT_1000S = 3; /* thousandths of a unit */ + public const int GRAYRESPONSEUNIT_10000S = 4; /* ten-thousandths of a unit */ + public const int GRAYRESPONSEUNIT_100000S = 5; /* hundred-thousandths */ + public const int TIFFTAG_GRAYRESPONSECURVE = 291; /* $gray scale response curve */ + public const int TIFFTAG_GROUP3OPTIONS = 292; /* 32 flag bits */ + public const int GROUP3OPT_2DENCODING = 0x1; /* 2-dimensional coding */ + public const int GROUP3OPT_UNCOMPRESSED = 0x2; /* data not compressed */ + public const int GROUP3OPT_FILLBITS = 0x4; /* fill to byte boundary */ + public const int TIFFTAG_GROUP4OPTIONS = 293; /* 32 flag bits */ + public const int GROUP4OPT_UNCOMPRESSED = 0x2; /* data not compressed */ + public const int TIFFTAG_RESOLUTIONUNIT = 296; /* units of resolutions */ + public const int RESUNIT_NONE = 1; /* no meaningful units */ + public const int RESUNIT_INCH = 2; /* english */ + public const int RESUNIT_CENTIMETER = 3; /* metric */ + public const int TIFFTAG_PAGENUMBER = 297; /* page numbers of multi-page */ + public const int TIFFTAG_COLORRESPONSEUNIT = 300; /* $color curve accuracy */ + public const int COLORRESPONSEUNIT_10S = 1; /* tenths of a unit */ + public const int COLORRESPONSEUNIT_100S = 2; /* hundredths of a unit */ + public const int COLORRESPONSEUNIT_1000S = 3; /* thousandths of a unit */ + public const int COLORRESPONSEUNIT_10000S = 4; /* ten-thousandths of a unit */ + public const int COLORRESPONSEUNIT_100000S = 5; /* hundred-thousandths */ + public const int TIFFTAG_TRANSFERFUNCTION = 301; /* !colorimetry info */ + public const int TIFFTAG_SOFTWARE = 305; /* name & release */ + public const int TIFFTAG_DATETIME = 306; /* creation date and time */ + public const int TIFFTAG_ARTIST = 315; /* creator of image */ + public const int TIFFTAG_HOSTCOMPUTER = 316; /* machine where created */ + public const int TIFFTAG_PREDICTOR = 317; /* prediction scheme w/ LZW */ + public const int TIFFTAG_WHITEPOINT = 318; /* image white point */ + public const int TIFFTAG_PRIMARYCHROMATICITIES = 319; /* !primary chromaticities */ + public const int TIFFTAG_COLORMAP = 320; /* RGB map for pallette image */ + public const int TIFFTAG_HALFTONEHINTS = 321; /* !highlight+shadow info */ + public const int TIFFTAG_TILEWIDTH = 322; /* !rows/data tile */ + public const int TIFFTAG_TILELENGTH = 323; /* !cols/data tile */ + public const int TIFFTAG_TILEOFFSETS = 324; /* !offsets to data tiles */ + public const int TIFFTAG_TILEBYTECOUNTS = 325; /* !byte counts for tiles */ + public const int TIFFTAG_BADFAXLINES = 326; /* lines w/ wrong pixel count */ + public const int TIFFTAG_CLEANFAXDATA = 327; /* regenerated line info */ + public const int CLEANFAXDATA_CLEAN = 0; /* no errors detected */ + public const int CLEANFAXDATA_REGENERATED = 1; /* receiver regenerated lines */ + public const int CLEANFAXDATA_UNCLEAN = 2; /* uncorrected errors exist */ + public const int TIFFTAG_CONSECUTIVEBADFAXLINES = 328; /* max consecutive bad lines */ + public const int TIFFTAG_SUBIFD = 330; /* subimage descriptors */ + public const int TIFFTAG_INKSET = 332; /* !inks in separated image */ + public const int INKSET_CMYK = 1; /* !cyan-magenta-yellow-black */ + public const int TIFFTAG_INKNAMES = 333; /* !ascii names of inks */ + public const int TIFFTAG_NUMBEROFINKS = 334; /* !number of inks */ + public const int TIFFTAG_DOTRANGE = 336; /* !0% and 100% dot codes */ + public const int TIFFTAG_TARGETPRINTER = 337; /* !separation target */ + public const int TIFFTAG_EXTRASAMPLES = 338; /* !info about extra samples */ + public const int EXTRASAMPLE_UNSPECIFIED = 0; /* !unspecified data */ + public const int EXTRASAMPLE_ASSOCALPHA = 1; /* !associated alpha data */ + public const int EXTRASAMPLE_UNASSALPHA = 2; /* !unassociated alpha data */ + public const int TIFFTAG_SAMPLEFORMAT = 339; /* !data sample format */ + public const int SAMPLEFORMAT_UINT = 1; /* !unsigned integer data */ + public const int SAMPLEFORMAT_INT = 2; /* !signed integer data */ + public const int SAMPLEFORMAT_IEEEFP = 3; /* !IEEE floating point data */ + public const int SAMPLEFORMAT_VOID = 4; /* !untyped data */ + public const int SAMPLEFORMAT_COMPLEXINT = 5; /* !complex signed int */ + public const int SAMPLEFORMAT_COMPLEXIEEEFP = 6; /* !complex ieee floating */ + public const int TIFFTAG_SMINSAMPLEVALUE = 340; /* !variable MinSampleValue */ + public const int TIFFTAG_SMAXSAMPLEVALUE = 341; /* !variable MaxSampleValue */ + public const int TIFFTAG_JPEGTABLES = 347; /* %JPEG table stream */ + /* + * Tags 512-521 are obsoleted by Technical Note #2 + * which specifies a revised JPEG-in-TIFF scheme. + */ + public const int TIFFTAG_JPEGPROC = 512; /* !JPEG processing algorithm */ + public const int JPEGPROC_BASELINE = 1; /* !baseline sequential */ + public const int JPEGPROC_LOSSLESS = 14; /* !Huffman coded lossless */ + public const int TIFFTAG_JPEGIFOFFSET = 513; /* !pointer to SOI marker */ + public const int TIFFTAG_JPEGIFBYTECOUNT = 514; /* !JFIF stream length */ + public const int TIFFTAG_JPEGRESTARTINTERVAL = 515; /* !restart interval length */ + public const int TIFFTAG_JPEGLOSSLESSPREDICTORS = 517; /* !lossless proc predictor */ + public const int TIFFTAG_JPEGPOINTTRANSFORM = 518; /* !lossless point transform */ + public const int TIFFTAG_JPEGQTABLES = 519; /* !Q matrice offsets */ + public const int TIFFTAG_JPEGDCTABLES = 520; /* !DCT table offsets */ + public const int TIFFTAG_JPEGACTABLES = 521; /* !AC coefficient offsets */ + public const int TIFFTAG_YCBCRCOEFFICIENTS = 529; /* !RGB -> YCbCr transform */ + public const int TIFFTAG_YCBCRSUBSAMPLING = 530; /* !YCbCr subsampling factors */ + public const int TIFFTAG_YCBCRPOSITIONING = 531; /* !subsample positioning */ + public const int YCBCRPOSITION_CENTERED = 1; /* !as in PostScript Level 2 */ + public const int YCBCRPOSITION_COSITED = 2; /* !as in CCIR 601-1 */ + public const int TIFFTAG_REFERENCEBLACKWHITE = 532; /* !colorimetry info */ + /* tags 32952-32956 are private tags registered to Island Graphics */ + public const int TIFFTAG_REFPTS = 32953; /* image reference points */ + public const int TIFFTAG_REGIONTACKPOINT = 32954; /* region-xform tack point */ + public const int TIFFTAG_REGIONWARPCORNERS = 32955; /* warp quadrilateral */ + public const int TIFFTAG_REGIONAFFINE = 32956; /* affine transformation mat */ + /* tags 32995-32999 are private tags registered to SGI */ + public const int TIFFTAG_MATTEING = 32995; /* $use ExtraSamples */ + public const int TIFFTAG_DATATYPE = 32996; /* $use SampleFormat */ + public const int TIFFTAG_IMAGEDEPTH = 32997; /* z depth of image */ + public const int TIFFTAG_TILEDEPTH = 32998; /* z depth/data tile */ + /* tags 33300-33309 are private tags registered to Pixar */ + /* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ + public const int TIFFTAG_PIXAR_IMAGEFULLWIDTH = 33300; /* full image size in x */ + public const int TIFFTAG_PIXAR_IMAGEFULLLENGTH = 33301; /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ + public const int TIFFTAG_PIXAR_TEXTUREFORMAT = 33302; /* texture map format */ + public const int TIFFTAG_PIXAR_WRAPMODES = 33303; /* s & t wrap modes */ + public const int TIFFTAG_PIXAR_FOVCOT = 33304; /* cotan(fov) for env. maps */ + public const int TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN = 33305; + public const int TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA = 33306; + /* tag 33405 is a private tag registered to Eastman Kodak */ + public const int TIFFTAG_WRITERSERIALNUMBER = 33405; /* device serial number */ + /* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ + public const int TIFFTAG_COPYRIGHT = 33432; /* copyright string */ + /* IPTC TAG from RichTIFF specifications */ + public const int TIFFTAG_RICHTIFFIPTC = 33723; + /* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ + public const int TIFFTAG_STONITS = 37439; /* Sample value to Nits */ + /* tag 34929 is a private tag registered to FedEx */ + public const int TIFFTAG_FEDEX_EDR = 34929; /* unknown use */ + /* tag 65535 is an undefined tag used by Eastman Kodak */ + public const int TIFFTAG_DCSHUESHIFTVALUES = 65535; /* hue shift correction data */ + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/TIFFDirectory.cs b/iTechSharp/iTextSharp/text/pdf/codec/TIFFDirectory.cs new file mode 100644 index 0000000..cdc2175 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/TIFFDirectory.cs @@ -0,0 +1,669 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; +using iTextSharp.text.pdf; +/* + * Copyright 2003-2008 by Paulo Soares. + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageio.plugins.tiff.TIFFDirectory.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +namespace iTextSharp.text.pdf.codec { + /** + * A class representing an Image File Directory (IFD) from a TIFF 6.0 + * stream. The TIFF file format is described in more detail in the + * comments for the TIFFDescriptor class. + * + *

    A TIFF IFD consists of a set of TIFFField tags. Methods are + * provided to query the set of tags and to obtain the raw field + * array. In addition, convenience methods are provided for acquiring + * the values of tags that contain a single value that fits into a + * byte, int, long, float, or double. + * + *

    Every TIFF file is made up of one or more public IFDs that are + * joined in a linked list, rooted in the file header. A file may + * also contain so-called private IFDs that are referenced from + * tag data and do not appear in the main list. + * + *

    This class is not a committed part of the JAI API. It may + * be removed or changed in future releases of JAI. + * + * @see TIFFField + */ + public class TIFFDirectory { + + /** A bool storing the endianness of the stream. */ + bool isBigEndian; + + /** The number of entries in the IFD. */ + int numEntries; + + /** An array of TIFFFields. */ + TIFFField[] fields; + + /** A Hashtable indexing the fields by tag number. */ + Hashtable fieldIndex = new Hashtable(); + + /** The offset of this IFD. */ + long IFDOffset = 8; + + /** The offset of the next IFD. */ + long nextIFDOffset = 0; + + /** The default constructor. */ + TIFFDirectory() {} + + private static bool IsValidEndianTag(int endian) { + return ((endian == 0x4949) || (endian == 0x4d4d)); + } + + /** + * Constructs a TIFFDirectory from a SeekableStream. + * The directory parameter specifies which directory to read from + * the linked list present in the stream; directory 0 is normally + * read but it is possible to store multiple images in a single + * TIFF file by maintaing multiple directories. + * + * @param stream a SeekableStream to read from. + * @param directory the index of the directory to read. + */ + public TIFFDirectory(RandomAccessFileOrArray stream, int directory) + { + + long global_save_offset = stream.FilePointer; + long ifd_offset; + + // Read the TIFF header + stream.Seek(0L); + int endian = stream.ReadUnsignedShort(); + if (!IsValidEndianTag(endian)) { + throw new + ArgumentException("Bad endianness tag (not 0x4949 or 0x4d4d)."); + } + isBigEndian = (endian == 0x4d4d); + + int magic = ReadUnsignedShort(stream); + if (magic != 42) { + throw new + ArgumentException("Bad magic number, should be 42."); + } + + // Get the initial ifd offset as an unsigned int (using a long) + ifd_offset = ReadUnsignedInt(stream); + + for (int i = 0; i < directory; i++) { + if (ifd_offset == 0L) { + throw new + ArgumentException("Directory number too large."); + } + + stream.Seek(ifd_offset); + int entries = ReadUnsignedShort(stream); + stream.Skip(12*entries); + + ifd_offset = ReadUnsignedInt(stream); + } + + stream.Seek(ifd_offset); + Initialize(stream); + stream.Seek(global_save_offset); + } + + /** + * Constructs a TIFFDirectory by reading a SeekableStream. + * The ifd_offset parameter specifies the stream offset from which + * to begin reading; this mechanism is sometimes used to store + * private IFDs within a TIFF file that are not part of the normal + * sequence of IFDs. + * + * @param stream a SeekableStream to read from. + * @param ifd_offset the long byte offset of the directory. + * @param directory the index of the directory to read beyond the + * one at the current stream offset; zero indicates the IFD + * at the current offset. + */ + public TIFFDirectory(RandomAccessFileOrArray stream, long ifd_offset, int directory) + { + + long global_save_offset = stream.FilePointer; + stream.Seek(0L); + int endian = stream.ReadUnsignedShort(); + if (!IsValidEndianTag(endian)) { + throw new + ArgumentException("Bad endianness tag (not 0x4949 or 0x4d4d)."); + } + isBigEndian = (endian == 0x4d4d); + + // Seek to the first IFD. + stream.Seek(ifd_offset); + + // Seek to desired IFD if necessary. + int dirNum = 0; + while (dirNum < directory) { + // Get the number of fields in the current IFD. + int numEntries = ReadUnsignedShort(stream); + + // Skip to the next IFD offset value field. + stream.Seek(ifd_offset + 12*numEntries); + + // Read the offset to the next IFD beyond this one. + ifd_offset = ReadUnsignedInt(stream); + + // Seek to the next IFD. + stream.Seek(ifd_offset); + + // Increment the directory. + dirNum++; + } + + Initialize(stream); + stream.Seek(global_save_offset); + } + + private static int[] sizeOfType = { + 0, // 0 = n/a + 1, // 1 = byte + 1, // 2 = ascii + 2, // 3 = short + 4, // 4 = long + 8, // 5 = rational + 1, // 6 = sbyte + 1, // 7 = undefined + 2, // 8 = sshort + 4, // 9 = slong + 8, // 10 = srational + 4, // 11 = float + 8 // 12 = double + }; + + private void Initialize(RandomAccessFileOrArray stream) { + long nextTagOffset = 0L; + long maxOffset = (long) stream.Length; + int i, j; + + IFDOffset = stream.FilePointer; + + numEntries = ReadUnsignedShort(stream); + fields = new TIFFField[numEntries]; + + for (i = 0; (i < numEntries) && (nextTagOffset < maxOffset); i++) { + int tag = ReadUnsignedShort(stream); + int type = ReadUnsignedShort(stream); + int count = (int)(ReadUnsignedInt(stream)); + bool processTag = true; + + // The place to return to to read the next tag + nextTagOffset = stream.FilePointer + 4; + + try { + // If the tag data can't fit in 4 bytes, the next 4 bytes + // contain the starting offset of the data + if (count*sizeOfType[type] > 4) { + long valueOffset = ReadUnsignedInt(stream); + + // bounds check offset for EOF + if (valueOffset < maxOffset) { + stream.Seek(valueOffset); + } + else { + // bad offset pointer .. skip tag + processTag = false; + } + } + } catch (ArgumentOutOfRangeException) { + // if the data type is unknown we should skip this TIFF Field + processTag = false; + } + + if (processTag) { + fieldIndex[tag] = i; + Object obj = null; + + switch (type) { + case TIFFField.TIFF_BYTE: + case TIFFField.TIFF_SBYTE: + case TIFFField.TIFF_UNDEFINED: + case TIFFField.TIFF_ASCII: + byte[] bvalues = new byte[count]; + stream.ReadFully(bvalues, 0, count); + + if (type == TIFFField.TIFF_ASCII) { + + // Can be multiple strings + int index = 0, prevIndex = 0; + ArrayList v = new ArrayList(); + + while (index < count) { + + while ((index < count) && (bvalues[index++] != 0)); + + // When we encountered zero, means one string has ended + char[] cht = new char[index - prevIndex]; + Array.Copy(bvalues, prevIndex, cht, 0, index - prevIndex); + v.Add(new String(cht)); + prevIndex = index; + } + + count = v.Count; + String[] strings = new String[count]; + for (int c = 0 ; c < count; c++) { + strings[c] = (String)v[c]; + } + + obj = strings; + } else { + obj = bvalues; + } + + break; + + case TIFFField.TIFF_SHORT: + char[] cvalues = new char[count]; + for (j = 0; j < count; j++) { + cvalues[j] = (char)(ReadUnsignedShort(stream)); + } + obj = cvalues; + break; + + case TIFFField.TIFF_LONG: + long[] lvalues = new long[count]; + for (j = 0; j < count; j++) { + lvalues[j] = ReadUnsignedInt(stream); + } + obj = lvalues; + break; + + case TIFFField.TIFF_RATIONAL: + long[][] llvalues = new long[count][]; + for (j = 0; j < count; j++) { + long v0 = ReadUnsignedInt(stream); + long v1 = ReadUnsignedInt(stream); + llvalues[j] = new long[]{v0, v1}; + } + obj = llvalues; + break; + + case TIFFField.TIFF_SSHORT: + short[] svalues = new short[count]; + for (j = 0; j < count; j++) { + svalues[j] = ReadShort(stream); + } + obj = svalues; + break; + + case TIFFField.TIFF_SLONG: + int[] ivalues = new int[count]; + for (j = 0; j < count; j++) { + ivalues[j] = ReadInt(stream); + } + obj = ivalues; + break; + + case TIFFField.TIFF_SRATIONAL: + int[,] iivalues = new int[count,2]; + for (j = 0; j < count; j++) { + iivalues[j,0] = ReadInt(stream); + iivalues[j,1] = ReadInt(stream); + } + obj = iivalues; + break; + + case TIFFField.TIFF_FLOAT: + float[] fvalues = new float[count]; + for (j = 0; j < count; j++) { + fvalues[j] = ReadFloat(stream); + } + obj = fvalues; + break; + + case TIFFField.TIFF_DOUBLE: + double[] dvalues = new double[count]; + for (j = 0; j < count; j++) { + dvalues[j] = ReadDouble(stream); + } + obj = dvalues; + break; + + default: + break; + } + + fields[i] = new TIFFField(tag, type, count, obj); + } + + stream.Seek(nextTagOffset); + } + + // Read the offset of the next IFD. + try { + nextIFDOffset = ReadUnsignedInt(stream); + } + catch { + // broken tiffs may not have this pointer + nextIFDOffset = 0; + } + } + + /** Returns the number of directory entries. */ + public int GetNumEntries() { + return numEntries; + } + + /** + * Returns the value of a given tag as a TIFFField, + * or null if the tag is not present. + */ + public TIFFField GetField(int tag) { + object i = fieldIndex[tag]; + if (i == null) { + return null; + } else { + return fields[(int)i]; + } + } + + /** + * Returns true if a tag appears in the directory. + */ + public bool IsTagPresent(int tag) { + return fieldIndex.ContainsKey(tag); + } + + /** + * Returns an ordered array of ints indicating the tag + * values. + */ + public int[] GetTags() { + int[] tags = new int[fieldIndex.Count]; + fieldIndex.Keys.CopyTo(tags, 0); + return tags; + } + + /** + * Returns an array of TIFFFields containing all the fields + * in this directory. + */ + public TIFFField[] GetFields() { + return fields; + } + + /** + * Returns the value of a particular index of a given tag as a + * byte. The caller is responsible for ensuring that the tag is + * present and has type TIFFField.TIFF_SBYTE, TIFF_BYTE, or + * TIFF_UNDEFINED. + */ + public byte GetFieldAsByte(int tag, int index) { + int i = (int)fieldIndex[tag]; + byte [] b = (fields[(int)i]).GetAsBytes(); + return b[index]; + } + + /** + * Returns the value of index 0 of a given tag as a + * byte. The caller is responsible for ensuring that the tag is + * present and has type TIFFField.TIFF_SBYTE, TIFF_BYTE, or + * TIFF_UNDEFINED. + */ + public byte GetFieldAsByte(int tag) { + return GetFieldAsByte(tag, 0); + } + + /** + * Returns the value of a particular index of a given tag as a + * long. The caller is responsible for ensuring that the tag is + * present and has type TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED, + * TIFF_SHORT, TIFF_SSHORT, TIFF_SLONG or TIFF_LONG. + */ + public long GetFieldAsLong(int tag, int index) { + int i = (int)fieldIndex[tag]; + return (fields[i]).GetAsLong(index); + } + + /** + * Returns the value of index 0 of a given tag as a + * long. The caller is responsible for ensuring that the tag is + * present and has type TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED, + * TIFF_SHORT, TIFF_SSHORT, TIFF_SLONG or TIFF_LONG. + */ + public long GetFieldAsLong(int tag) { + return GetFieldAsLong(tag, 0); + } + + /** + * Returns the value of a particular index of a given tag as a + * float. The caller is responsible for ensuring that the tag is + * present and has numeric type (all but TIFF_UNDEFINED and + * TIFF_ASCII). + */ + public float GetFieldAsFloat(int tag, int index) { + int i = (int)fieldIndex[tag]; + return fields[i].GetAsFloat(index); + } + + /** + * Returns the value of index 0 of a given tag as a float. The + * caller is responsible for ensuring that the tag is present and + * has numeric type (all but TIFF_UNDEFINED and TIFF_ASCII). + */ + public float GetFieldAsFloat(int tag) { + return GetFieldAsFloat(tag, 0); + } + + /** + * Returns the value of a particular index of a given tag as a + * double. The caller is responsible for ensuring that the tag is + * present and has numeric type (all but TIFF_UNDEFINED and + * TIFF_ASCII). + */ + public double GetFieldAsDouble(int tag, int index) { + int i = (int)fieldIndex[tag]; + return fields[i].GetAsDouble(index); + } + + /** + * Returns the value of index 0 of a given tag as a double. The + * caller is responsible for ensuring that the tag is present and + * has numeric type (all but TIFF_UNDEFINED and TIFF_ASCII). + */ + public double GetFieldAsDouble(int tag) { + return GetFieldAsDouble(tag, 0); + } + + // Methods to read primitive data types from the stream + + private short ReadShort(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadShort(); + } else { + return stream.ReadShortLE(); + } + } + + private int ReadUnsignedShort(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadUnsignedShort(); + } else { + return stream.ReadUnsignedShortLE(); + } + } + + private int ReadInt(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadInt(); + } else { + return stream.ReadIntLE(); + } + } + + private long ReadUnsignedInt(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadUnsignedInt(); + } else { + return stream.ReadUnsignedIntLE(); + } + } + + private long ReadLong(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadLong(); + } else { + return stream.ReadLongLE(); + } + } + + private float ReadFloat(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadFloat(); + } else { + return stream.ReadFloatLE(); + } + } + + private double ReadDouble(RandomAccessFileOrArray stream) + { + if (isBigEndian) { + return stream.ReadDouble(); + } else { + return stream.ReadDoubleLE(); + } + } + + private static int ReadUnsignedShort(RandomAccessFileOrArray stream, + bool isBigEndian) + { + if (isBigEndian) { + return stream.ReadUnsignedShort(); + } else { + return stream.ReadUnsignedShortLE(); + } + } + + private static long ReadUnsignedInt(RandomAccessFileOrArray stream, + bool isBigEndian) + { + if (isBigEndian) { + return stream.ReadUnsignedInt(); + } else { + return stream.ReadUnsignedIntLE(); + } + } + + // Utilities + + /** + * Returns the number of image directories (subimages) stored in a + * given TIFF file, represented by a SeekableStream. + */ + public static int GetNumDirectories(RandomAccessFileOrArray stream) + { + long pointer = stream.FilePointer; // Save stream pointer + + stream.Seek(0L); + int endian = stream.ReadUnsignedShort(); + if (!IsValidEndianTag(endian)) { + throw new ArgumentException("Bad endianness tag (not 0x4949 or 0x4d4d)."); + } + bool isBigEndian = (endian == 0x4d4d); + int magic = ReadUnsignedShort(stream, isBigEndian); + if (magic != 42) { + throw new + ArgumentException("Bad magic number, should be 42."); + } + + stream.Seek(4L); + long offset = ReadUnsignedInt(stream, isBigEndian); + + int numDirectories = 0; + while (offset != 0L) { + ++numDirectories; + + // EOFException means IFD was probably not properly terminated. + try { + stream.Seek(offset); + int entries = ReadUnsignedShort(stream, isBigEndian); + stream.Skip(12*entries); + offset = ReadUnsignedInt(stream, isBigEndian); + } catch (EndOfStreamException) { + //numDirectories--; + break; + } + } + + stream.Seek(pointer); // Reset stream pointer + return numDirectories; + } + + /** + * Returns a bool indicating whether the byte order used in the + * the TIFF file is big-endian (i.e. whether the byte order is from + * the most significant to the least significant) + */ + public bool IsBigEndian() { + return isBigEndian; + } + + /** + * Returns the offset of the IFD corresponding to this + * TIFFDirectory. + */ + public long GetIFDOffset() { + return IFDOffset; + } + + /** + * Returns the offset of the next IFD after the IFD corresponding to this + * TIFFDirectory. + */ + public long GetNextIFDOffset() { + return nextIFDOffset; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/codec/TIFFFaxDecoder.cs b/iTechSharp/iTextSharp/text/pdf/codec/TIFFFaxDecoder.cs new file mode 100644 index 0000000..434a208 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/TIFFFaxDecoder.cs @@ -0,0 +1,1502 @@ +using System; +/* + * Copyright 2003-2008 by Paulo Soares. + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageioimpl.plugins.tiff.TIFFFaxDecompressor.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +namespace iTextSharp.text.pdf.codec { + public class TIFFFaxDecoder { + + private int bitPointer, bytePointer; + private byte[] data; + private int w, h; + private int fillOrder; + + // Data structures needed to store changing elements for the previous + // and the current scanline + private int changingElemSize = 0; + private int[] prevChangingElems; + private int[] currChangingElems; + + // Element at which to start search in getNextChangingElement + private int lastChangingElement = 0; + + private int compression = 2; + + // Variables set by T4Options + private int uncompressedMode = 0; + private int fillBits = 0; + private int oneD; + + static int[] table1 = { + 0x00, // 0 bits are left in first byte - SHOULD NOT HAPPEN + 0x01, // 1 bits are left in first byte + 0x03, // 2 bits are left in first byte + 0x07, // 3 bits are left in first byte + 0x0f, // 4 bits are left in first byte + 0x1f, // 5 bits are left in first byte + 0x3f, // 6 bits are left in first byte + 0x7f, // 7 bits are left in first byte + 0xff // 8 bits are left in first byte + }; + + static int[] table2 = { + 0x00, // 0 + 0x80, // 1 + 0xc0, // 2 + 0xe0, // 3 + 0xf0, // 4 + 0xf8, // 5 + 0xfc, // 6 + 0xfe, // 7 + 0xff // 8 + }; + + // Table to be used when fillOrder = 2, for flipping bytes. + internal static byte[] flipTable = { + 0, 256-128, 64, 256-64, 32, 256-96, 96, 256-32, + 16, 256-112, 80, 256-48, 48, 256-80, 112, 256-16, + 8, 256-120, 72, 256-56, 40, 256-88, 104, 256-24, + 24, 256-104, 88, 256-40, 56, 256-72, 120, 256-8, + 4, 256-124, 68, 256-60, 36, 256-92, 100, 256-28, + 20, 256-108, 84, 256-44, 52, 256-76, 116, 256-12, + 12, 256-116, 76, 256-52, 44, 256-84, 108, 256-20, + 28, 256-100, 92, 256-36, 60, 256-68, 124, 256-4, + 2, 256-126, 66, 256-62, 34, 256-94, 98, 256-30, + 18, 256-110, 82, 256-46, 50, 256-78, 114, 256-14, + 10, 256-118, 74, 256-54, 42, 256-86, 106, 256-22, + 26, 256-102, 90, 256-38, 58, 256-70, 122, 256-6, + 6, 256-122, 70, 256-58, 38, 256-90, 102, 256-26, + 22, 256-106, 86, 256-42, 54, 256-74, 118, 256-10, + 14, 256-114, 78, 256-50, 46, 256-82, 110, 256-18, + 30, 256-98, 94, 256-34, 62, 256-66, 126, 256-2, + 1, 256-127, 65, 256-63, 33, 256-95, 97, 256-31, + 17, 256-111, 81, 256-47, 49, 256-79, 113, 256-15, + 9, 256-119, 73, 256-55, 41, 256-87, 105, 256-23, + 25, 256-103, 89, 256-39, 57, 256-71, 121, 256-7, + 5, 256-123, 69, 256-59, 37, 256-91, 101, 256-27, + 21, 256-107, 85, 256-43, 53, 256-75, 117, 256-11, + 13, 256-115, 77, 256-51, 45, 256-83, 109, 256-19, + 29, 256-99, 93, 256-35, 61, 256-67, 125, 256-3, + 3, 256-125, 67, 256-61, 35, 256-93, 99, 256-29, + 19, 256-109, 83, 256-45, 51, 256-77, 115, 256-13, + 11, 256-117, 75, 256-53, 43, 256-85, 107, 256-21, + 27, 256-101, 91, 256-37, 59, 256-69, 123, 256-5, + 7, 256-121, 71, 256-57, 39, 256-89, 103, 256-25, + 23, 256-105, 87, 256-41, 55, 256-73, 119, 256-9, + 15, 256-113, 79, 256-49, 47, 256-81, 111, 256-17, + 31, 256-97, 95, 256-33, 63, 256-65, 127, 256-1, + }; + + // The main 10 bit white runs lookup table + static short[] white = { + // 0 - 7 + 6430, 6400, 6400, 6400, 3225, 3225, 3225, 3225, + // 8 - 15 + 944, 944, 944, 944, 976, 976, 976, 976, + // 16 - 23 + 1456, 1456, 1456, 1456, 1488, 1488, 1488, 1488, + // 24 - 31 + 718, 718, 718, 718, 718, 718, 718, 718, + // 32 - 39 + 750, 750, 750, 750, 750, 750, 750, 750, + // 40 - 47 + 1520, 1520, 1520, 1520, 1552, 1552, 1552, 1552, + // 48 - 55 + 428, 428, 428, 428, 428, 428, 428, 428, + // 56 - 63 + 428, 428, 428, 428, 428, 428, 428, 428, + // 64 - 71 + 654, 654, 654, 654, 654, 654, 654, 654, + // 72 - 79 + 1072, 1072, 1072, 1072, 1104, 1104, 1104, 1104, + // 80 - 87 + 1136, 1136, 1136, 1136, 1168, 1168, 1168, 1168, + // 88 - 95 + 1200, 1200, 1200, 1200, 1232, 1232, 1232, 1232, + // 96 - 103 + 622, 622, 622, 622, 622, 622, 622, 622, + // 104 - 111 + 1008, 1008, 1008, 1008, 1040, 1040, 1040, 1040, + // 112 - 119 + 44, 44, 44, 44, 44, 44, 44, 44, + // 120 - 127 + 44, 44, 44, 44, 44, 44, 44, 44, + // 128 - 135 + 396, 396, 396, 396, 396, 396, 396, 396, + // 136 - 143 + 396, 396, 396, 396, 396, 396, 396, 396, + // 144 - 151 + 1712, 1712, 1712, 1712, 1744, 1744, 1744, 1744, + // 152 - 159 + 846, 846, 846, 846, 846, 846, 846, 846, + // 160 - 167 + 1264, 1264, 1264, 1264, 1296, 1296, 1296, 1296, + // 168 - 175 + 1328, 1328, 1328, 1328, 1360, 1360, 1360, 1360, + // 176 - 183 + 1392, 1392, 1392, 1392, 1424, 1424, 1424, 1424, + // 184 - 191 + 686, 686, 686, 686, 686, 686, 686, 686, + // 192 - 199 + 910, 910, 910, 910, 910, 910, 910, 910, + // 200 - 207 + 1968, 1968, 1968, 1968, 2000, 2000, 2000, 2000, + // 208 - 215 + 2032, 2032, 2032, 2032, 16, 16, 16, 16, + // 216 - 223 + 10257, 10257, 10257, 10257, 12305, 12305, 12305, 12305, + // 224 - 231 + 330, 330, 330, 330, 330, 330, 330, 330, + // 232 - 239 + 330, 330, 330, 330, 330, 330, 330, 330, + // 240 - 247 + 330, 330, 330, 330, 330, 330, 330, 330, + // 248 - 255 + 330, 330, 330, 330, 330, 330, 330, 330, + // 256 - 263 + 362, 362, 362, 362, 362, 362, 362, 362, + // 264 - 271 + 362, 362, 362, 362, 362, 362, 362, 362, + // 272 - 279 + 362, 362, 362, 362, 362, 362, 362, 362, + // 280 - 287 + 362, 362, 362, 362, 362, 362, 362, 362, + // 288 - 295 + 878, 878, 878, 878, 878, 878, 878, 878, + // 296 - 303 + 1904, 1904, 1904, 1904, 1936, 1936, 1936, 1936, + // 304 - 311 + -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, + // 312 - 319 + 590, 590, 590, 590, 590, 590, 590, 590, + // 320 - 327 + 782, 782, 782, 782, 782, 782, 782, 782, + // 328 - 335 + 1584, 1584, 1584, 1584, 1616, 1616, 1616, 1616, + // 336 - 343 + 1648, 1648, 1648, 1648, 1680, 1680, 1680, 1680, + // 344 - 351 + 814, 814, 814, 814, 814, 814, 814, 814, + // 352 - 359 + 1776, 1776, 1776, 1776, 1808, 1808, 1808, 1808, + // 360 - 367 + 1840, 1840, 1840, 1840, 1872, 1872, 1872, 1872, + // 368 - 375 + 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, + // 376 - 383 + 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, + // 384 - 391 + -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, + // 392 - 399 + -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, + // 400 - 407 + 14353, 14353, 14353, 14353, 16401, 16401, 16401, 16401, + // 408 - 415 + 22547, 22547, 24595, 24595, 20497, 20497, 20497, 20497, + // 416 - 423 + 18449, 18449, 18449, 18449, 26643, 26643, 28691, 28691, + // 424 - 431 + 30739, 30739, -32749, -32749, -30701, -30701, -28653, -28653, + // 432 - 439 + -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, + // 440 - 447 + 8207, 8207, 8207, 8207, 8207, 8207, 8207, 8207, + // 448 - 455 + 72, 72, 72, 72, 72, 72, 72, 72, + // 456 - 463 + 72, 72, 72, 72, 72, 72, 72, 72, + // 464 - 471 + 72, 72, 72, 72, 72, 72, 72, 72, + // 472 - 479 + 72, 72, 72, 72, 72, 72, 72, 72, + // 480 - 487 + 72, 72, 72, 72, 72, 72, 72, 72, + // 488 - 495 + 72, 72, 72, 72, 72, 72, 72, 72, + // 496 - 503 + 72, 72, 72, 72, 72, 72, 72, 72, + // 504 - 511 + 72, 72, 72, 72, 72, 72, 72, 72, + // 512 - 519 + 104, 104, 104, 104, 104, 104, 104, 104, + // 520 - 527 + 104, 104, 104, 104, 104, 104, 104, 104, + // 528 - 535 + 104, 104, 104, 104, 104, 104, 104, 104, + // 536 - 543 + 104, 104, 104, 104, 104, 104, 104, 104, + // 544 - 551 + 104, 104, 104, 104, 104, 104, 104, 104, + // 552 - 559 + 104, 104, 104, 104, 104, 104, 104, 104, + // 560 - 567 + 104, 104, 104, 104, 104, 104, 104, 104, + // 568 - 575 + 104, 104, 104, 104, 104, 104, 104, 104, + // 576 - 583 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 584 - 591 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 592 - 599 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 600 - 607 + 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, + // 608 - 615 + 266, 266, 266, 266, 266, 266, 266, 266, + // 616 - 623 + 266, 266, 266, 266, 266, 266, 266, 266, + // 624 - 631 + 266, 266, 266, 266, 266, 266, 266, 266, + // 632 - 639 + 266, 266, 266, 266, 266, 266, 266, 266, + // 640 - 647 + 298, 298, 298, 298, 298, 298, 298, 298, + // 648 - 655 + 298, 298, 298, 298, 298, 298, 298, 298, + // 656 - 663 + 298, 298, 298, 298, 298, 298, 298, 298, + // 664 - 671 + 298, 298, 298, 298, 298, 298, 298, 298, + // 672 - 679 + 524, 524, 524, 524, 524, 524, 524, 524, + // 680 - 687 + 524, 524, 524, 524, 524, 524, 524, 524, + // 688 - 695 + 556, 556, 556, 556, 556, 556, 556, 556, + // 696 - 703 + 556, 556, 556, 556, 556, 556, 556, 556, + // 704 - 711 + 136, 136, 136, 136, 136, 136, 136, 136, + // 712 - 719 + 136, 136, 136, 136, 136, 136, 136, 136, + // 720 - 727 + 136, 136, 136, 136, 136, 136, 136, 136, + // 728 - 735 + 136, 136, 136, 136, 136, 136, 136, 136, + // 736 - 743 + 136, 136, 136, 136, 136, 136, 136, 136, + // 744 - 751 + 136, 136, 136, 136, 136, 136, 136, 136, + // 752 - 759 + 136, 136, 136, 136, 136, 136, 136, 136, + // 760 - 767 + 136, 136, 136, 136, 136, 136, 136, 136, + // 768 - 775 + 168, 168, 168, 168, 168, 168, 168, 168, + // 776 - 783 + 168, 168, 168, 168, 168, 168, 168, 168, + // 784 - 791 + 168, 168, 168, 168, 168, 168, 168, 168, + // 792 - 799 + 168, 168, 168, 168, 168, 168, 168, 168, + // 800 - 807 + 168, 168, 168, 168, 168, 168, 168, 168, + // 808 - 815 + 168, 168, 168, 168, 168, 168, 168, 168, + // 816 - 823 + 168, 168, 168, 168, 168, 168, 168, 168, + // 824 - 831 + 168, 168, 168, 168, 168, 168, 168, 168, + // 832 - 839 + 460, 460, 460, 460, 460, 460, 460, 460, + // 840 - 847 + 460, 460, 460, 460, 460, 460, 460, 460, + // 848 - 855 + 492, 492, 492, 492, 492, 492, 492, 492, + // 856 - 863 + 492, 492, 492, 492, 492, 492, 492, 492, + // 864 - 871 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 872 - 879 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 880 - 887 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 888 - 895 + 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, + // 896 - 903 + 200, 200, 200, 200, 200, 200, 200, 200, + // 904 - 911 + 200, 200, 200, 200, 200, 200, 200, 200, + // 912 - 919 + 200, 200, 200, 200, 200, 200, 200, 200, + // 920 - 927 + 200, 200, 200, 200, 200, 200, 200, 200, + // 928 - 935 + 200, 200, 200, 200, 200, 200, 200, 200, + // 936 - 943 + 200, 200, 200, 200, 200, 200, 200, 200, + // 944 - 951 + 200, 200, 200, 200, 200, 200, 200, 200, + // 952 - 959 + 200, 200, 200, 200, 200, 200, 200, 200, + // 960 - 967 + 232, 232, 232, 232, 232, 232, 232, 232, + // 968 - 975 + 232, 232, 232, 232, 232, 232, 232, 232, + // 976 - 983 + 232, 232, 232, 232, 232, 232, 232, 232, + // 984 - 991 + 232, 232, 232, 232, 232, 232, 232, 232, + // 992 - 999 + 232, 232, 232, 232, 232, 232, 232, 232, + // 1000 - 1007 + 232, 232, 232, 232, 232, 232, 232, 232, + // 1008 - 1015 + 232, 232, 232, 232, 232, 232, 232, 232, + // 1016 - 1023 + 232, 232, 232, 232, 232, 232, 232, 232, + }; + + // Additional make up codes for both White and Black runs + static short[] additionalMakeup = { + 28679, 28679, 31752, unchecked((short)32777), + unchecked((short)33801), unchecked((short)34825), unchecked((short)35849), unchecked((short)36873), + unchecked((short)29703), unchecked((short)29703), unchecked((short)30727), unchecked((short)30727), + unchecked((short)37897), unchecked((short)38921), unchecked((short)39945), unchecked((short)40969) + }; + + // Initial black run look up table, uses the first 4 bits of a code + static short[] initBlack = { + // 0 - 7 + 3226, 6412, 200, 168, 38, 38, 134, 134, + // 8 - 15 + 100, 100, 100, 100, 68, 68, 68, 68 + }; + + // + static short[] twoBitBlack = {292, 260, 226, 226}; // 0 - 3 + + // Main black run table, using the last 9 bits of possible 13 bit code + static short[] black = { + // 0 - 7 + 62, 62, 30, 30, 0, 0, 0, 0, + // 8 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, + // 16 - 23 + 0, 0, 0, 0, 0, 0, 0, 0, + // 24 - 31 + 0, 0, 0, 0, 0, 0, 0, 0, + // 32 - 39 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 40 - 47 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 48 - 55 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 56 - 63 + 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, + // 64 - 71 + 588, 588, 588, 588, 588, 588, 588, 588, + // 72 - 79 + 1680, 1680, 20499, 22547, 24595, 26643, 1776, 1776, + // 80 - 87 + 1808, 1808, -24557, -22509, -20461, -18413, 1904, 1904, + // 88 - 95 + 1936, 1936, -16365, -14317, 782, 782, 782, 782, + // 96 - 103 + 814, 814, 814, 814, -12269, -10221, 10257, 10257, + // 104 - 111 + 12305, 12305, 14353, 14353, 16403, 18451, 1712, 1712, + // 112 - 119 + 1744, 1744, 28691, 30739, -32749, -30701, -28653, -26605, + // 120 - 127 + 2061, 2061, 2061, 2061, 2061, 2061, 2061, 2061, + // 128 - 135 + 424, 424, 424, 424, 424, 424, 424, 424, + // 136 - 143 + 424, 424, 424, 424, 424, 424, 424, 424, + // 144 - 151 + 424, 424, 424, 424, 424, 424, 424, 424, + // 152 - 159 + 424, 424, 424, 424, 424, 424, 424, 424, + // 160 - 167 + 750, 750, 750, 750, 1616, 1616, 1648, 1648, + // 168 - 175 + 1424, 1424, 1456, 1456, 1488, 1488, 1520, 1520, + // 176 - 183 + 1840, 1840, 1872, 1872, 1968, 1968, 8209, 8209, + // 184 - 191 + 524, 524, 524, 524, 524, 524, 524, 524, + // 192 - 199 + 556, 556, 556, 556, 556, 556, 556, 556, + // 200 - 207 + 1552, 1552, 1584, 1584, 2000, 2000, 2032, 2032, + // 208 - 215 + 976, 976, 1008, 1008, 1040, 1040, 1072, 1072, + // 216 - 223 + 1296, 1296, 1328, 1328, 718, 718, 718, 718, + // 224 - 231 + 456, 456, 456, 456, 456, 456, 456, 456, + // 232 - 239 + 456, 456, 456, 456, 456, 456, 456, 456, + // 240 - 247 + 456, 456, 456, 456, 456, 456, 456, 456, + // 248 - 255 + 456, 456, 456, 456, 456, 456, 456, 456, + // 256 - 263 + 326, 326, 326, 326, 326, 326, 326, 326, + // 264 - 271 + 326, 326, 326, 326, 326, 326, 326, 326, + // 272 - 279 + 326, 326, 326, 326, 326, 326, 326, 326, + // 280 - 287 + 326, 326, 326, 326, 326, 326, 326, 326, + // 288 - 295 + 326, 326, 326, 326, 326, 326, 326, 326, + // 296 - 303 + 326, 326, 326, 326, 326, 326, 326, 326, + // 304 - 311 + 326, 326, 326, 326, 326, 326, 326, 326, + // 312 - 319 + 326, 326, 326, 326, 326, 326, 326, 326, + // 320 - 327 + 358, 358, 358, 358, 358, 358, 358, 358, + // 328 - 335 + 358, 358, 358, 358, 358, 358, 358, 358, + // 336 - 343 + 358, 358, 358, 358, 358, 358, 358, 358, + // 344 - 351 + 358, 358, 358, 358, 358, 358, 358, 358, + // 352 - 359 + 358, 358, 358, 358, 358, 358, 358, 358, + // 360 - 367 + 358, 358, 358, 358, 358, 358, 358, 358, + // 368 - 375 + 358, 358, 358, 358, 358, 358, 358, 358, + // 376 - 383 + 358, 358, 358, 358, 358, 358, 358, 358, + // 384 - 391 + 490, 490, 490, 490, 490, 490, 490, 490, + // 392 - 399 + 490, 490, 490, 490, 490, 490, 490, 490, + // 400 - 407 + 4113, 4113, 6161, 6161, 848, 848, 880, 880, + // 408 - 415 + 912, 912, 944, 944, 622, 622, 622, 622, + // 416 - 423 + 654, 654, 654, 654, 1104, 1104, 1136, 1136, + // 424 - 431 + 1168, 1168, 1200, 1200, 1232, 1232, 1264, 1264, + // 432 - 439 + 686, 686, 686, 686, 1360, 1360, 1392, 1392, + // 440 - 447 + 12, 12, 12, 12, 12, 12, 12, 12, + // 448 - 455 + 390, 390, 390, 390, 390, 390, 390, 390, + // 456 - 463 + 390, 390, 390, 390, 390, 390, 390, 390, + // 464 - 471 + 390, 390, 390, 390, 390, 390, 390, 390, + // 472 - 479 + 390, 390, 390, 390, 390, 390, 390, 390, + // 480 - 487 + 390, 390, 390, 390, 390, 390, 390, 390, + // 488 - 495 + 390, 390, 390, 390, 390, 390, 390, 390, + // 496 - 503 + 390, 390, 390, 390, 390, 390, 390, 390, + // 504 - 511 + 390, 390, 390, 390, 390, 390, 390, 390, + }; + + static byte[] twoDCodes = { + // 0 - 7 + 80, 88, 23, 71, 30, 30, 62, 62, + // 8 - 15 + 4, 4, 4, 4, 4, 4, 4, 4, + // 16 - 23 + 11, 11, 11, 11, 11, 11, 11, 11, + // 24 - 31 + 11, 11, 11, 11, 11, 11, 11, 11, + // 32 - 39 + 35, 35, 35, 35, 35, 35, 35, 35, + // 40 - 47 + 35, 35, 35, 35, 35, 35, 35, 35, + // 48 - 55 + 51, 51, 51, 51, 51, 51, 51, 51, + // 56 - 63 + 51, 51, 51, 51, 51, 51, 51, 51, + // 64 - 71 + 41, 41, 41, 41, 41, 41, 41, 41, + // 72 - 79 + 41, 41, 41, 41, 41, 41, 41, 41, + // 80 - 87 + 41, 41, 41, 41, 41, 41, 41, 41, + // 88 - 95 + 41, 41, 41, 41, 41, 41, 41, 41, + // 96 - 103 + 41, 41, 41, 41, 41, 41, 41, 41, + // 104 - 111 + 41, 41, 41, 41, 41, 41, 41, 41, + // 112 - 119 + 41, 41, 41, 41, 41, 41, 41, 41, + // 120 - 127 + 41, 41, 41, 41, 41, 41, 41, 41, + }; + + /** + * @param fillOrder The fill order of the compressed data bytes. + * @param w + * @param h + */ + public TIFFFaxDecoder(int fillOrder, int w, int h) { + this.fillOrder = fillOrder; + this.w = w; + this.h = h; + + this.bitPointer = 0; + this.bytePointer = 0; + this.prevChangingElems = new int[w]; + this.currChangingElems = new int[w]; + } + + public static void ReverseBits(byte[] b) { + for (int k = 0; k < b.Length; ++k) + b[k] = flipTable[b[k] & 0xff]; + } + + + // One-dimensional decoding methods + + public void Decode1D(byte[] buffer, byte[] compData, + int startX, int height) { + this.data = compData; + + int lineOffset = 0; + int scanlineStride = (w + 7)/8; + + bitPointer = 0; + bytePointer = 0; + + for (int i = 0; i < height; i++) { + DecodeNextScanline(buffer, lineOffset, startX); + lineOffset += scanlineStride; + } + } + + public void DecodeNextScanline(byte[] buffer, + int lineOffset, int bitOffset) { + int bits = 0, code = 0, isT = 0; + int current, entry, twoBits; + bool isWhite = true; + + // Initialize starting of the changing elements array + changingElemSize = 0; + + // While scanline not complete + while (bitOffset < w) { + while (isWhite) { + // White run + current = NextNBits(10); + entry = white[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >> 1) & 0x0f; + + if (bits == 12) { // Additional Make up code + // Get the next 2 bits + twoBits = NextLesserThan8Bits(2); + // Consolidate the 2 new bits and last 2 bits into 4 bits + current = ((current << 2) & 0x000c) | twoBits; + entry = additionalMakeup[current]; + bits = (entry >> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >> 4) & 0x0fff; // 12 bits + bitOffset += code; // Skip white run + + UpdatePointer(4 - bits); + } else if (bits == 0) { // ERROR + throw new Exception("Invalid code encountered."); + } else if (bits == 15) { // EOL + throw new Exception("EOL code word encountered in White run."); + } else { + // 11 bits - 0000 0111 1111 1111 = 0x07ff + code = (entry >> 5) & 0x07ff; + bitOffset += code; + + UpdatePointer(10 - bits); + if (isT == 0) { + isWhite = false; + currChangingElems[changingElemSize++] = bitOffset; + } + } + } + + // Check whether this run completed one width, if so + // advance to next byte boundary for compression = 2. + if (bitOffset == w) { + if (compression == 2) { + AdvancePointer(); + } + break; + } + + while (isWhite == false) { + // Black run + current = NextLesserThan8Bits(4); + entry = initBlack[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >> 1) & 0x000f; + code = (entry >> 5) & 0x07ff; + + if (code == 100) { + current = NextNBits(9); + entry = black[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >> 1) & 0x000f; + code = (entry >> 5) & 0x07ff; + + if (bits == 12) { + // Additional makeup codes + UpdatePointer(5); + current = NextLesserThan8Bits(4); + entry = additionalMakeup[current]; + bits = (entry >> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >> 4) & 0x0fff; // 12 bits + + SetToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + UpdatePointer(4 - bits); + } else if (bits == 15) { + // EOL code + throw new Exception("EOL code word encountered in Black run."); + } else { + SetToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + UpdatePointer(9 - bits); + if (isT == 0) { + isWhite = true; + currChangingElems[changingElemSize++] = bitOffset; + } + } + } else if (code == 200) { + // Is a Terminating code + current = NextLesserThan8Bits(2); + entry = twoBitBlack[current]; + code = (entry >> 5) & 0x07ff; + bits = (entry >> 1) & 0x0f; + + SetToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + UpdatePointer(2 - bits); + isWhite = true; + currChangingElems[changingElemSize++] = bitOffset; + } else { + // Is a Terminating code + SetToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + UpdatePointer(4 - bits); + isWhite = true; + currChangingElems[changingElemSize++] = bitOffset; + } + } + + // Check whether this run completed one width + if (bitOffset == w) { + if (compression == 2) { + AdvancePointer(); + } + break; + } + } + + currChangingElems[changingElemSize++] = bitOffset; + } + + // Two-dimensional decoding methods + + public void Decode2D(byte[] buffer, + byte[] compData, + int startX, + int height, + long tiffT4Options) { + this.data = compData; + compression = 3; + + bitPointer = 0; + bytePointer = 0; + + int scanlineStride = (w + 7)/8; + + int a0, a1, b1, b2; + int[] b = new int[2]; + int entry, code, bits; + bool isWhite; + int currIndex = 0; + int[] temp; + + // fillBits - dealt with this in readEOL + // 1D/2D encoding - dealt with this in readEOL + + // uncompressedMode - haven't dealt with this yet. + + + oneD = (int)(tiffT4Options & 0x01); + uncompressedMode = (int)((tiffT4Options & 0x02) >> 1); + fillBits = (int)((tiffT4Options & 0x04) >> 2); + + // The data must start with an EOL code + if (ReadEOL(true) != 1) { + throw new Exception("First scanline must be 1D encoded."); + } + + int lineOffset = 0; + int bitOffset; + + // Then the 1D encoded scanline data will occur, changing elements + // array gets set. + DecodeNextScanline(buffer, lineOffset, startX); + lineOffset += scanlineStride; + + for (int lines = 1; lines < height; lines++) { + + // Every line must begin with an EOL followed by a bit which + // indicates whether the following scanline is 1D or 2D encoded. + if (ReadEOL(false) == 0) { + // 2D encoded scanline follows + + // Initialize previous scanlines changing elements, and + // initialize current scanline's changing elements array + temp = prevChangingElems; + prevChangingElems = currChangingElems; + currChangingElems = temp; + currIndex = 0; + + // a0 has to be set just before the start of this scanline. + a0 = -1; + isWhite = true; + bitOffset = startX; + + lastChangingElement = 0; + + while (bitOffset < w) { + // Get the next changing element + GetNextChangingElement(a0, isWhite, b); + + b1 = b[0]; + b2 = b[1]; + + // Get the next seven bits + entry = NextLesserThan8Bits(7); + + // Run these through the 2DCodes table + entry = (int)(twoDCodes[entry] & 0xff); + + // Get the code and the number of bits used up + code = (entry & 0x78) >> 3; + bits = entry & 0x07; + + if (code == 0) { + if (!isWhite) { + SetToBlack(buffer, lineOffset, bitOffset, + b2 - bitOffset); + } + bitOffset = a0 = b2; + + // Set pointer to consume the correct number of bits. + UpdatePointer(7 - bits); + } else if (code == 1) { + // Horizontal + UpdatePointer(7 - bits); + + // identify the next 2 codes. + int number; + if (isWhite) { + number = DecodeWhiteCodeWord(); + bitOffset += number; + currChangingElems[currIndex++] = bitOffset; + + number = DecodeBlackCodeWord(); + SetToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + currChangingElems[currIndex++] = bitOffset; + } else { + number = DecodeBlackCodeWord(); + SetToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + currChangingElems[currIndex++] = bitOffset; + + number = DecodeWhiteCodeWord(); + bitOffset += number; + currChangingElems[currIndex++] = bitOffset; + } + + a0 = bitOffset; + } else if (code <= 8) { + // Vertical + a1 = b1 + (code - 5); + + currChangingElems[currIndex++] = a1; + + // We write the current color till a1 - 1 pos, + // since a1 is where the next color starts + if (!isWhite) { + SetToBlack(buffer, lineOffset, bitOffset, + a1 - bitOffset); + } + bitOffset = a0 = a1; + isWhite = !isWhite; + + UpdatePointer(7 - bits); + } else { + throw new Exception("Invalid code encountered while decoding 2D group 3 compressed data."); + } + } + + // Add the changing element beyond the current scanline for the + // other color too + currChangingElems[currIndex++] = bitOffset; + changingElemSize = currIndex; + } else { + // 1D encoded scanline follows + DecodeNextScanline(buffer, lineOffset, startX); + } + + lineOffset += scanlineStride; + } + } + + public void DecodeT6(byte[] buffer, + byte[] compData, + int startX, + int height, + long tiffT6Options) { + this.data = compData; + compression = 4; + + bitPointer = 0; + bytePointer = 0; + + int scanlineStride = (w + 7)/8; + + int a0, a1, b1, b2; + int entry, code, bits; + bool isWhite; + int currIndex; + int[] temp; + + // Return values from getNextChangingElement + int[] b = new int[2]; + + // uncompressedMode - have written some code for this, but this + // has not been tested due to lack of test images using this optional + + uncompressedMode = (int)((tiffT6Options & 0x02) >> 1); + + // Local cached reference + int[] cce = currChangingElems; + + // Assume invisible preceding row of all white pixels and insert + // both black and white changing elements beyond the end of this + // imaginary scanline. + changingElemSize = 0; + cce[changingElemSize++] = w; + cce[changingElemSize++] = w; + + int lineOffset = 0; + int bitOffset; + + for (int lines = 0; lines < height; lines++) { + // a0 has to be set just before the start of the scanline. + a0 = -1; + isWhite = true; + + // Assign the changing elements of the previous scanline to + // prevChangingElems and start putting this new scanline's + // changing elements into the currChangingElems. + temp = prevChangingElems; + prevChangingElems = currChangingElems; + cce = currChangingElems = temp; + currIndex = 0; + + // Start decoding the scanline at startX in the raster + bitOffset = startX; + + // Reset search start position for getNextChangingElement + lastChangingElement = 0; + + // Till one whole scanline is decoded + while (bitOffset < w) { + // Get the next changing element + GetNextChangingElement(a0, isWhite, b); + b1 = b[0]; + b2 = b[1]; + + // Get the next seven bits + entry = NextLesserThan8Bits(7); + // Run these through the 2DCodes table + entry = (int)(twoDCodes[entry] & 0xff); + + // Get the code and the number of bits used up + code = (entry & 0x78) >> 3; + bits = entry & 0x07; + + if (code == 0) { // Pass + // We always assume WhiteIsZero format for fax. + if (!isWhite) { + SetToBlack(buffer, lineOffset, bitOffset, + b2 - bitOffset); + } + bitOffset = a0 = b2; + + // Set pointer to only consume the correct number of bits. + UpdatePointer(7 - bits); + } else if (code == 1) { // Horizontal + // Set pointer to only consume the correct number of bits. + UpdatePointer(7 - bits); + + // identify the next 2 alternating color codes. + int number; + if (isWhite) { + // Following are white and black runs + number = DecodeWhiteCodeWord(); + bitOffset += number; + cce[currIndex++] = bitOffset; + + number = DecodeBlackCodeWord(); + SetToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + cce[currIndex++] = bitOffset; + } else { + // First a black run and then a white run follows + number = DecodeBlackCodeWord(); + SetToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + cce[currIndex++] = bitOffset; + + number = DecodeWhiteCodeWord(); + bitOffset += number; + cce[currIndex++] = bitOffset; + } + + a0 = bitOffset; + } else if (code <= 8) { // Vertical + a1 = b1 + (code - 5); + cce[currIndex++] = a1; + + // We write the current color till a1 - 1 pos, + // since a1 is where the next color starts + if (!isWhite) { + SetToBlack(buffer, lineOffset, bitOffset, + a1 - bitOffset); + } + bitOffset = a0 = a1; + isWhite = !isWhite; + + UpdatePointer(7 - bits); + } else if (code == 11) { + if (NextLesserThan8Bits(3) != 7) { + throw new Exception("Invalid code encountered while decoding 2D group 4 compressed data."); + } + + int zeros = 0; + bool exit = false; + + while (!exit) { + while (NextLesserThan8Bits(1) != 1) { + zeros++; + } + + if (zeros > 5) { + // Exit code + + // Zeros before exit code + zeros = zeros - 6; + + if (!isWhite && (zeros > 0)) { + cce[currIndex++] = bitOffset; + } + + // Zeros before the exit code + bitOffset += zeros; + if (zeros > 0) { + // Some zeros have been written + isWhite = true; + } + + // Read in the bit which specifies the color of + // the following run + if (NextLesserThan8Bits(1) == 0) { + if (!isWhite) { + cce[currIndex++] = bitOffset; + } + isWhite = true; + } else { + if (isWhite) { + cce[currIndex++] = bitOffset; + } + isWhite = false; + } + + exit = true; + } + + if (zeros == 5) { + if (!isWhite) { + cce[currIndex++] = bitOffset; + } + bitOffset += zeros; + + // Last thing written was white + isWhite = true; + } else { + bitOffset += zeros; + + cce[currIndex++] = bitOffset; + SetToBlack(buffer, lineOffset, bitOffset, 1); + ++bitOffset; + + // Last thing written was black + isWhite = false; + } + + } + } else { + //micah_tessler@yahoo.com + //Microsoft TIFF renderers seem to treat unknown codes as line-breaks + //That is, they give up on the current line and move on to the next one + //set bitOffset to w to move on to the next scan line. + bitOffset = w; + UpdatePointer(7 - bits); + } + } + + // Add the changing element beyond the current scanline for the + // other color too + //make sure that the index does not exceed the bounds of the array + if (currIndex < cce.Length) + cce[currIndex++] = bitOffset; + + // Number of changing elements in this scanline. + changingElemSize = currIndex; + + lineOffset += scanlineStride; + } + } + + private void SetToBlack(byte[] buffer, + int lineOffset, int bitOffset, + int numBits) { + int bitNum = 8*lineOffset + bitOffset; + int lastBit = bitNum + numBits; + + int byteNum = bitNum >> 3; + + // Handle bits in first byte + int shift = bitNum & 0x7; + if (shift > 0) { + int maskVal = 1 << (7 - shift); + byte val = buffer[byteNum]; + while (maskVal > 0 && bitNum < lastBit) { + val |= (byte)maskVal; + maskVal >>= 1; + ++bitNum; + } + buffer[byteNum] = val; + } + + // Fill in 8 bits at a time + byteNum = bitNum >> 3; + while (bitNum < lastBit - 7) { + buffer[byteNum++] = (byte)255; + bitNum += 8; + } + + // Fill in remaining bits + while (bitNum < lastBit) { + byteNum = bitNum >> 3; + buffer[byteNum] |= (byte)(1 << (7 - (bitNum & 0x7))); + ++bitNum; + } + } + + // Returns run length + private int DecodeWhiteCodeWord() { + int current, entry, bits, isT, twoBits, code = -1; + int runLength = 0; + bool isWhite = true; + + while (isWhite) { + current = NextNBits(10); + entry = white[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >> 1) & 0x0f; + + if (bits == 12) { // Additional Make up code + // Get the next 2 bits + twoBits = NextLesserThan8Bits(2); + // Consolidate the 2 new bits and last 2 bits into 4 bits + current = ((current << 2) & 0x000c) | twoBits; + entry = additionalMakeup[current]; + bits = (entry >> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >> 4) & 0x0fff; // 12 bits + runLength += code; + UpdatePointer(4 - bits); + } else if (bits == 0) { // ERROR + throw new Exception("Invalid code encountered."); + } else if (bits == 15) { // EOL + throw new Exception("EOL code word encountered in White run."); + } else { + // 11 bits - 0000 0111 1111 1111 = 0x07ff + code = (entry >> 5) & 0x07ff; + runLength += code; + UpdatePointer(10 - bits); + if (isT == 0) { + isWhite = false; + } + } + } + + return runLength; + } + + // Returns run length + private int DecodeBlackCodeWord() { + int current, entry, bits, isT, code = -1; + int runLength = 0; + bool isWhite = false; + + while (!isWhite) { + current = NextLesserThan8Bits(4); + entry = initBlack[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >> 1) & 0x000f; + code = (entry >> 5) & 0x07ff; + + if (code == 100) { + current = NextNBits(9); + entry = black[current]; + + // Get the 3 fields from the entry + isT = entry & 0x0001; + bits = (entry >> 1) & 0x000f; + code = (entry >> 5) & 0x07ff; + + if (bits == 12) { + // Additional makeup codes + UpdatePointer(5); + current = NextLesserThan8Bits(4); + entry = additionalMakeup[current]; + bits = (entry >> 1) & 0x07; // 3 bits 0000 0111 + code = (entry >> 4) & 0x0fff; // 12 bits + runLength += code; + + UpdatePointer(4 - bits); + } else if (bits == 15) { + // EOL code + throw new Exception("EOL code word encountered in Black run."); + } else { + runLength += code; + UpdatePointer(9 - bits); + if (isT == 0) { + isWhite = true; + } + } + } else if (code == 200) { + // Is a Terminating code + current = NextLesserThan8Bits(2); + entry = twoBitBlack[current]; + code = (entry >> 5) & 0x07ff; + runLength += code; + bits = (entry >> 1) & 0x0f; + UpdatePointer(2 - bits); + isWhite = true; + } else { + // Is a Terminating code + runLength += code; + UpdatePointer(4 - bits); + isWhite = true; + } + } + + return runLength; + } + + private int ReadEOL(bool isFirstEOL) { + if (fillBits == 0) { + int next12Bits = NextNBits(12); + if (isFirstEOL && next12Bits == 0) { + + // Might have the case of EOL padding being used even + // though it was not flagged in the T4Options field. + // This was observed to be the case in TIFFs produced + // by a well known vendor who shall remain nameless. + + if (NextNBits(4) == 1) { + + // EOL must be padded: reset the fillBits flag. + + fillBits = 1; + return 1; + } + } + if (next12Bits != 1) { + throw new Exception("Scanline must begin with EOL code word."); + } + } else if (fillBits == 1) { + + // First EOL code word xxxx 0000 0000 0001 will occur + // As many fill bits will be present as required to make + // the EOL code of 12 bits end on a byte boundary. + + int bitsLeft = 8 - bitPointer; + + if (NextNBits(bitsLeft) != 0) { + throw new Exception("All fill bits preceding EOL code must be 0."); + } + + // If the number of bitsLeft is less than 8, then to have a 12 + // bit EOL sequence, two more bytes are certainly going to be + // required. The first of them has to be all zeros, so ensure + // that. + if (bitsLeft < 4) { + if (NextNBits(8) != 0) { + throw new Exception("All fill bits preceding EOL code must be 0."); + } + } + + // There might be a random number of fill bytes with 0s, so + // loop till the EOL of 0000 0001 is found, as long as all + // the bytes preceding it are 0's. + int n; + while ((n = NextNBits(8)) != 1) { + + // If not all zeros + if (n != 0) { + throw new Exception("All fill bits preceding EOL code must be 0."); + } + } + } + + // If one dimensional encoding mode, then always return 1 + if (oneD == 0) { + return 1; + } else { + // Otherwise for 2D encoding mode, + // The next one bit signifies 1D/2D encoding of next line. + return NextLesserThan8Bits(1); + } + } + + private void GetNextChangingElement(int a0, bool isWhite, int[] ret) { + // Local copies of instance variables + int[] pce = this.prevChangingElems; + int ces = this.changingElemSize; + + // If the previous match was at an odd element, we still + // have to search the preceeding element. + // int start = lastChangingElement & ~0x1; + int start = lastChangingElement > 0 ? lastChangingElement - 1 : 0; + if (isWhite) { + start &= ~0x1; // Search even numbered elements + } else { + start |= 0x1; // Search odd numbered elements + } + + int i = start; + for (; i < ces; i += 2) { + int temp = pce[i]; + if (temp > a0) { + lastChangingElement = i; + ret[0] = temp; + break; + } + } + + if (i + 1 < ces) { + ret[1] = pce[i + 1]; + } + } + + private int NextNBits(int bitsToGet) { + byte b, next, next2next; + int l = data.Length - 1; + int bp = this.bytePointer; + + if (fillOrder == 1) { + b = data[bp]; + + if (bp == l) { + next = 0x00; + next2next = 0x00; + } else if ((bp + 1) == l) { + next = data[bp + 1]; + next2next = 0x00; + } else { + next = data[bp + 1]; + next2next = data[bp + 2]; + } + } else if (fillOrder == 2) { + b = flipTable[data[bp] & 0xff]; + + if (bp == l) { + next = 0x00; + next2next = 0x00; + } else if ((bp + 1) == l) { + next = flipTable[data[bp + 1] & 0xff]; + next2next = 0x00; + } else { + next = flipTable[data[bp + 1] & 0xff]; + next2next = flipTable[data[bp + 2] & 0xff]; + } + } else { + throw new Exception("TIFF_FILL_ORDER tag must be either 1 or 2."); + } + + int bitsLeft = 8 - bitPointer; + int bitsFromNextByte = bitsToGet - bitsLeft; + int bitsFromNext2NextByte = 0; + if (bitsFromNextByte > 8) { + bitsFromNext2NextByte = bitsFromNextByte - 8; + bitsFromNextByte = 8; + } + + bytePointer++; + + int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft); + int i2 = (next & table2[bitsFromNextByte]) >> (8 - bitsFromNextByte); + + int i3 = 0; + if (bitsFromNext2NextByte != 0) { + i2 <<= bitsFromNext2NextByte; + i3 = (next2next & table2[bitsFromNext2NextByte]) >> + (8 - bitsFromNext2NextByte); + i2 |= i3; + bytePointer++; + bitPointer = bitsFromNext2NextByte; + } else { + if (bitsFromNextByte == 8) { + bitPointer = 0; + bytePointer++; + } else { + bitPointer = bitsFromNextByte; + } + } + + int i = i1 | i2; + return i; + } + + private int NextLesserThan8Bits(int bitsToGet) { + byte b, next; + int l = data.Length - 1; + int bp = this.bytePointer; + + if (fillOrder == 1) { + b = data[bp]; + if (bp == l) { + next = 0x00; + } else { + next = data[bp + 1]; + } + } else if (fillOrder == 2) { + b = flipTable[data[bp] & 0xff]; + if (bp == l) { + next = 0x00; + } else { + next = flipTable[data[bp + 1] & 0xff]; + } + } else { + throw new Exception("TIFF_FILL_ORDER tag must be either 1 or 2."); + } + + int bitsLeft = 8 - bitPointer; + int bitsFromNextByte = bitsToGet - bitsLeft; + + int shift = bitsLeft - bitsToGet; + int i1, i2; + if (shift >= 0) { + i1 = (b & table1[bitsLeft]) >> shift; + bitPointer += bitsToGet; + if (bitPointer == 8) { + bitPointer = 0; + bytePointer++; + } + } else { + i1 = (b & table1[bitsLeft]) << (-shift); + i2 = (next & table2[bitsFromNextByte]) >> (8 - bitsFromNextByte); + + i1 |= i2; + bytePointer++; + bitPointer = bitsFromNextByte; + } + + return i1; + } + + // Move pointer backwards by given amount of bits + private void UpdatePointer(int bitsToMoveBack) { + int i = bitPointer - bitsToMoveBack; + + if (i < 0) { + bytePointer--; + bitPointer = 8 + i; + } else { + bitPointer = i; + } + } + + // Move to the next byte boundary + private bool AdvancePointer() { + if (bitPointer != 0) { + bytePointer++; + bitPointer = 0; + } + + return true; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/TIFFField.cs b/iTechSharp/iTextSharp/text/pdf/codec/TIFFField.cs new file mode 100644 index 0000000..22aa0b6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/TIFFField.cs @@ -0,0 +1,487 @@ +using System; +/* + * Copyright 2003-2008 by Paulo Soares. + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageio.plugins.tiff.TIFFField.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +namespace iTextSharp.text.pdf.codec { + /** + * A class representing a field in a TIFF 6.0 Image File Directory. + * + *

    The TIFF file format is described in more detail in the + * comments for the TIFFDescriptor class. + * + *

    A field in a TIFF Image File Directory (IFD). A field is defined + * as a sequence of values of identical data type. TIFF 6.0 defines + * 12 data types, which are mapped internally onto the Java datatypes + * byte, int, long, float, and double. + * + *

    This class is not a committed part of the JAI API. It may + * be removed or changed in future releases of JAI. + * + * @see TIFFDirectory + */ + public class TIFFField : IComparable { + + /** Flag for 8 bit unsigned integers. */ + public const int TIFF_BYTE = 1; + + /** Flag for null-terminated ASCII strings. */ + public const int TIFF_ASCII = 2; + + /** Flag for 16 bit unsigned integers. */ + public const int TIFF_SHORT = 3; + + /** Flag for 32 bit unsigned integers. */ + public const int TIFF_LONG = 4; + + /** Flag for pairs of 32 bit unsigned integers. */ + public const int TIFF_RATIONAL = 5; + + /** Flag for 8 bit signed integers. */ + public const int TIFF_SBYTE = 6; + + /** Flag for 8 bit uninterpreted bytes. */ + public const int TIFF_UNDEFINED = 7; + + /** Flag for 16 bit signed integers. */ + public const int TIFF_SSHORT = 8; + + /** Flag for 32 bit signed integers. */ + public const int TIFF_SLONG = 9; + + /** Flag for pairs of 32 bit signed integers. */ + public const int TIFF_SRATIONAL = 10; + + /** Flag for 32 bit IEEE floats. */ + public const int TIFF_FLOAT = 11; + + /** Flag for 64 bit IEEE doubles. */ + public const int TIFF_DOUBLE = 12; + + /** The tag number. */ + int tag; + + /** The tag type. */ + int type; + + /** The number of data items present in the field. */ + int count; + + /** The field data. */ + Object data; + + /** The default constructor. */ + internal TIFFField() {} + + /** + * Constructs a TIFFField with arbitrary data. The data + * parameter must be an array of a Java type appropriate for the + * type of the TIFF field. Since there is no available 32-bit + * unsigned datatype, long is used. The mapping between types is + * as follows: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    TIFF type Java type
    TIFF_BYTE byte
    TIFF_ASCII String
    TIFF_SHORT char
    TIFF_LONG long
    TIFF_RATIONAL long[2]
    TIFF_SBYTE byte
    TIFF_UNDEFINED byte
    TIFF_SSHORT short
    TIFF_SLONG int
    TIFF_SRATIONAL int[2]
    TIFF_FLOAT float
    TIFF_DOUBLE double
    + */ + public TIFFField(int tag, int type, int count, Object data) { + this.tag = tag; + this.type = type; + this.count = count; + this.data = data; + } + + /** + * Returns the tag number, between 0 and 65535. + */ + public int GetTag() { + return tag; + } + + /** + * Returns the type of the data stored in the IFD. + * For a TIFF6.0 file, the value will equal one of the + * TIFF_ constants defined in this class. For future + * revisions of TIFF, higher values are possible. + * + */ + public new int GetType() { + return type; + } + + /** + * Returns the number of elements in the IFD. + */ + public int GetCount() { + return count; + } + + /** + * Returns the data as an uninterpreted array of bytes. + * The type of the field must be one of TIFF_BYTE, TIFF_SBYTE, + * or TIFF_UNDEFINED; + * + *

    For data in TIFF_BYTE format, the application must take + * care when promoting the data to longer integral types + * to avoid sign extension. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_BYTE, TIFF_SBYTE, or TIFF_UNDEFINED. + */ + public byte[] GetAsBytes() { + return (byte[])data; + } + + /** + * Returns TIFF_SHORT data as an array of chars (unsigned 16-bit + * integers). + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_SHORT. + */ + public char[] GetAsChars() { + return (char[])data; + } + + /** + * Returns TIFF_SSHORT data as an array of shorts (signed 16-bit + * integers). + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_SSHORT. + */ + public short[] GetAsShorts() { + return (short[])data; + } + + /** + * Returns TIFF_SLONG data as an array of ints (signed 32-bit + * integers). + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_SLONG. + */ + public int[] GetAsInts() { + return (int[])data; + } + + /** + * Returns TIFF_LONG data as an array of longs (signed 64-bit + * integers). + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_LONG. + */ + public long[] GetAsLongs() { + return (long[])data; + } + + /** + * Returns TIFF_FLOAT data as an array of floats. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_FLOAT. + */ + public float[] GetAsFloats() { + return (float[])data; + } + + /** + * Returns TIFF_DOUBLE data as an array of doubles. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_DOUBLE. + */ + public double[] GetAsDoubles() { + return (double[])data; + } + + /** + * Returns TIFF_SRATIONAL data as an array of 2-element arrays of ints. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_SRATIONAL. + */ + public int[][] GetAsSRationals() { + return (int[][])data; + } + + /** + * Returns TIFF_RATIONAL data as an array of 2-element arrays of longs. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_RATTIONAL. + */ + public long[][] GetAsRationals() { + return (long[][])data; + } + + /** + * Returns data in TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED, TIFF_SHORT, + * TIFF_SSHORT, or TIFF_SLONG format as an int. + * + *

    TIFF_BYTE and TIFF_UNDEFINED data are treated as unsigned; + * that is, no sign extension will take place and the returned + * value will be in the range [0, 255]. TIFF_SBYTE data will + * be returned in the range [-128, 127]. + * + *

    A ClassCastException will be thrown if the field is not of + * type TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED, TIFF_SHORT, + * TIFF_SSHORT, or TIFF_SLONG. + */ + public int GetAsInt(int index) { + switch (type) { + case TIFF_BYTE: case TIFF_UNDEFINED: + return ((byte[])data)[index] & 0xff; + case TIFF_SBYTE: + return ((byte[])data)[index]; + case TIFF_SHORT: + return ((char[])data)[index] & 0xffff; + case TIFF_SSHORT: + return ((short[])data)[index]; + case TIFF_SLONG: + return ((int[])data)[index]; + default: + throw new InvalidCastException(); + } + } + + /** + * Returns data in TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED, TIFF_SHORT, + * TIFF_SSHORT, TIFF_SLONG, or TIFF_LONG format as a long. + * + *

    TIFF_BYTE and TIFF_UNDEFINED data are treated as unsigned; + * that is, no sign extension will take place and the returned + * value will be in the range [0, 255]. TIFF_SBYTE data will + * be returned in the range [-128, 127]. + * + *

    A ClassCastException will be thrown if the field is not of + * type TIFF_BYTE, TIFF_SBYTE, TIFF_UNDEFINED, TIFF_SHORT, + * TIFF_SSHORT, TIFF_SLONG, or TIFF_LONG. + */ + public long GetAsLong(int index) { + switch (type) { + case TIFF_BYTE: case TIFF_UNDEFINED: + return ((byte[])data)[index] & 0xff; + case TIFF_SBYTE: + return ((byte[])data)[index]; + case TIFF_SHORT: + return ((char[])data)[index] & 0xffff; + case TIFF_SSHORT: + return ((short[])data)[index]; + case TIFF_SLONG: + return ((int[])data)[index]; + case TIFF_LONG: + return ((long[])data)[index]; + default: + throw new InvalidCastException(); + } + } + + /** + * Returns data in any numerical format as a float. Data in + * TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated by + * dividing the numerator into the denominator using + * double-precision arithmetic and then truncating to single + * precision. Data in TIFF_SLONG, TIFF_LONG, or TIFF_DOUBLE + * format may suffer from truncation. + * + *

    A ClassCastException will be thrown if the field is + * of type TIFF_UNDEFINED or TIFF_ASCII. + */ + public float GetAsFloat(int index) { + switch (type) { + case TIFF_BYTE: + return ((byte[])data)[index] & 0xff; + case TIFF_SBYTE: + return ((byte[])data)[index]; + case TIFF_SHORT: + return ((char[])data)[index] & 0xffff; + case TIFF_SSHORT: + return ((short[])data)[index]; + case TIFF_SLONG: + return ((int[])data)[index]; + case TIFF_LONG: + return ((long[])data)[index]; + case TIFF_FLOAT: + return ((float[])data)[index]; + case TIFF_DOUBLE: + return (float)((double[])data)[index]; + case TIFF_SRATIONAL: + int[] ivalue = GetAsSRational(index); + return (float)((double)ivalue[0]/ivalue[1]); + case TIFF_RATIONAL: + long[] lvalue = GetAsRational(index); + return (float)((double)lvalue[0]/lvalue[1]); + default: + throw new InvalidCastException(); + } + } + + /** + * Returns data in any numerical format as a float. Data in + * TIFF_SRATIONAL or TIFF_RATIONAL format are evaluated by + * dividing the numerator into the denominator using + * double-precision arithmetic. + * + *

    A ClassCastException will be thrown if the field is of + * type TIFF_UNDEFINED or TIFF_ASCII. + */ + public double GetAsDouble(int index) { + switch (type) { + case TIFF_BYTE: + return ((byte[])data)[index] & 0xff; + case TIFF_SBYTE: + return ((byte[])data)[index]; + case TIFF_SHORT: + return ((char[])data)[index] & 0xffff; + case TIFF_SSHORT: + return ((short[])data)[index]; + case TIFF_SLONG: + return ((int[])data)[index]; + case TIFF_LONG: + return ((long[])data)[index]; + case TIFF_FLOAT: + return ((float[])data)[index]; + case TIFF_DOUBLE: + return ((double[])data)[index]; + case TIFF_SRATIONAL: + int[] ivalue = GetAsSRational(index); + return (double)ivalue[0]/ivalue[1]; + case TIFF_RATIONAL: + long[] lvalue = GetAsRational(index); + return (double)lvalue[0]/lvalue[1]; + default: + throw new InvalidCastException(); + } + } + + /** + * Returns a TIFF_ASCII data item as a String. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_ASCII. + */ + public String GetAsString(int index) { + return ((String[])data)[index]; + } + + /** + * Returns a TIFF_SRATIONAL data item as a two-element array + * of ints. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_SRATIONAL. + */ + public int[] GetAsSRational(int index) { + return ((int[][])data)[index]; + } + + /** + * Returns a TIFF_RATIONAL data item as a two-element array + * of ints. + * + *

    A ClassCastException will be thrown if the field is not + * of type TIFF_RATIONAL. + */ + public long[] GetAsRational(int index) { + if (type == TIFF_LONG) + return GetAsLongs(); + return ((long[][])data)[index]; + } + + /** + * Compares this TIFFField with another + * TIFFField by comparing the tags. + * + *

    Note: this class has a natural ordering that is inconsistent + * with equals(). + * + * @throws IllegalArgumentException if the parameter is null. + * @throws ClassCastException if the parameter is not a + * TIFFField. + */ + public int CompareTo(Object o) { + if (o == null) { + throw new ArgumentException(); + } + + int oTag = ((TIFFField)o).GetTag(); + + if (tag < oTag) { + return -1; + } else if (tag > oTag) { + return 1; + } else { + return 0; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/TIFFLZWDecoder.cs b/iTechSharp/iTextSharp/text/pdf/codec/TIFFLZWDecoder.cs new file mode 100644 index 0000000..b192dd0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/TIFFLZWDecoder.cs @@ -0,0 +1,272 @@ +using System; +/* + * Copyright 2003-2008 by Paulo Soares. + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageioimpl.plugins.tiff.TIFFLZWDecompressor.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +namespace iTextSharp.text.pdf.codec { + /** + * A class for performing LZW decoding. + * + * + */ + public class TIFFLZWDecoder { + + byte[][] stringTable; + byte[] data = null; + byte[] uncompData; + int tableIndex, bitsToGet = 9; + int bytePointer; + int dstIndex; + int w, h; + int predictor, samplesPerPixel; + int nextData = 0; + int nextBits = 0; + + int[] andTable = { + 511, + 1023, + 2047, + 4095 + }; + + public TIFFLZWDecoder(int w, int predictor, int samplesPerPixel) { + this.w = w; + this.predictor = predictor; + this.samplesPerPixel = samplesPerPixel; + } + + /** + * Method to decode LZW compressed data. + * + * @param data The compressed data. + * @param uncompData Array to return the uncompressed data in. + * @param h The number of rows the compressed data contains. + */ + public byte[] Decode(byte[] data, byte[] uncompData, int h) { + + if (data[0] == (byte)0x00 && data[1] == (byte)0x01) { + throw new InvalidOperationException("TIFF 5.0-style LZW codes are not supported."); + } + + InitializeStringTable(); + + this.data = data; + this.h = h; + this.uncompData = uncompData; + + // Initialize pointers + bytePointer = 0; + dstIndex = 0; + + + nextData = 0; + nextBits = 0; + + int code, oldCode = 0; + byte[] strn; + + while ( ((code = GetNextCode()) != 257) && + dstIndex < uncompData.Length) { + + if (code == 256) { + + InitializeStringTable(); + code = GetNextCode(); + + if (code == 257) { + break; + } + + WriteString(stringTable[code]); + oldCode = code; + + } else { + + if (code < tableIndex) { + + strn = stringTable[code]; + + WriteString(strn); + AddStringToTable(stringTable[oldCode], strn[0]); + oldCode = code; + + } else { + + strn = stringTable[oldCode]; + strn = ComposeString(strn, strn[0]); + WriteString(strn); + AddStringToTable(strn); + oldCode = code; + } + + } + + } + + // Horizontal Differencing Predictor + if (predictor == 2) { + + int count; + for (int j = 0; j < h; j++) { + + count = samplesPerPixel * (j * w + 1); + + for (int i = samplesPerPixel; i < w * samplesPerPixel; i++) { + + uncompData[count] += uncompData[count - samplesPerPixel]; + count++; + } + } + } + + return uncompData; + } + + + /** + * Initialize the string table. + */ + public void InitializeStringTable() { + + stringTable = new byte[4096][]; + + for (int i=0; i<256; i++) { + stringTable[i] = new byte[1]; + stringTable[i][0] = (byte)i; + } + + tableIndex = 258; + bitsToGet = 9; + } + + /** + * Write out the string just uncompressed. + */ + public void WriteString(byte[] strn) { + // Fix for broken tiff files + int max = uncompData.Length - dstIndex; + if (strn.Length < max) + max = strn.Length; + System.Array.Copy(strn, 0, uncompData, dstIndex, max); + dstIndex += max; + } + + /** + * Add a new string to the string table. + */ + public void AddStringToTable(byte[] oldString, byte newString) { + int length = oldString.Length; + byte[] strn = new byte[length + 1]; + Array.Copy(oldString, 0, strn, 0, length); + strn[length] = newString; + + // Add this new String to the table + stringTable[tableIndex++] = strn; + + if (tableIndex == 511) { + bitsToGet = 10; + } else if (tableIndex == 1023) { + bitsToGet = 11; + } else if (tableIndex == 2047) { + bitsToGet = 12; + } + } + + /** + * Add a new string to the string table. + */ + public void AddStringToTable(byte[] strn) { + + // Add this new String to the table + stringTable[tableIndex++] = strn; + + if (tableIndex == 511) { + bitsToGet = 10; + } else if (tableIndex == 1023) { + bitsToGet = 11; + } else if (tableIndex == 2047) { + bitsToGet = 12; + } + } + + /** + * Append newString to the end of oldString. + */ + public byte[] ComposeString(byte[] oldString, byte newString) { + int length = oldString.Length; + byte[] strn = new byte[length + 1]; + Array.Copy(oldString, 0, strn, 0, length); + strn[length] = newString; + + return strn; + } + + // Returns the next 9, 10, 11 or 12 bits + public int GetNextCode() { + // Attempt to get the next code. The exception is caught to make + // this robust to cases wherein the EndOfInformation code has been + // omitted from a strip. Examples of such cases have been observed + // in practice. + try { + nextData = (nextData << 8) | (data[bytePointer++] & 0xff); + nextBits += 8; + + if (nextBits < bitsToGet) { + nextData = (nextData << 8) | (data[bytePointer++] & 0xff); + nextBits += 8; + } + + int code = + (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet-9]; + nextBits -= bitsToGet; + + return code; + } catch (IndexOutOfRangeException) { + // Strip not terminated as expected: return EndOfInformation code. + return 257; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/TiffImage.cs b/iTechSharp/iTextSharp/text/pdf/codec/TiffImage.cs new file mode 100644 index 0000000..f178d8c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/TiffImage.cs @@ -0,0 +1,546 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.pdf; +using System.util.zlib; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec { + /** Reads TIFF images + * @author Paulo Soares (psoares@consiste.pt) + */ + public class TiffImage { + + /** Gets the number of pages the TIFF document has. + * @param s the file source + * @return the number of pages + */ + public static int GetNumberOfPages(RandomAccessFileOrArray s) { + return TIFFDirectory.GetNumDirectories(s); + } + + static int GetDpi(TIFFField fd, int resolutionUnit) { + if (fd == null) + return 0; + long[] res = fd.GetAsRational(0); + float frac = (float)res[0] / (float)res[1]; + int dpi = 0; + switch (resolutionUnit) { + case TIFFConstants.RESUNIT_INCH: + case TIFFConstants.RESUNIT_NONE: + dpi = (int)(frac + 0.5); + break; + case TIFFConstants.RESUNIT_CENTIMETER: + dpi = (int)(frac * 2.54 + 0.5); + break; + } + return dpi; + } + + /** Reads a page from a TIFF image. Direct mode is not used. + * @param s the file source + * @param page the page to get. The first page is 1 + * @return the Image + */ + public static Image GetTiffImage(RandomAccessFileOrArray s, int page) { + return GetTiffImage(s, page, false); + } + + /** Reads a page from a TIFF image. + * @param s the file source + * @param page the page to get. The first page is 1 + * @param direct for single strip, CCITT images, generate the image + * by direct byte copying. It's faster but may not work + * every time + * @return the Image + */ + public static Image GetTiffImage(RandomAccessFileOrArray s, int page, bool direct) { + if (page < 1) + throw new ArgumentException("The page number must be >= 1."); + TIFFDirectory dir = new TIFFDirectory(s, page - 1); + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_TILEWIDTH)) + throw new ArgumentException("Tiles are not supported."); + int compression = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION); + switch (compression) { + case TIFFConstants.COMPRESSION_CCITTRLEW: + case TIFFConstants.COMPRESSION_CCITTRLE: + case TIFFConstants.COMPRESSION_CCITTFAX3: + case TIFFConstants.COMPRESSION_CCITTFAX4: + break; + default: + return GetTiffImageColor(dir, s); + } + float rotation = 0; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) { + int rot = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION); + if (rot == TIFFConstants.ORIENTATION_BOTRIGHT || rot == TIFFConstants.ORIENTATION_BOTLEFT) + rotation = (float)Math.PI; + else if (rot == TIFFConstants.ORIENTATION_LEFTTOP || rot == TIFFConstants.ORIENTATION_LEFTBOT) + rotation = (float)(Math.PI / 2.0); + else if (rot == TIFFConstants.ORIENTATION_RIGHTTOP || rot == TIFFConstants.ORIENTATION_RIGHTBOT) + rotation = -(float)(Math.PI / 2.0); + } + + Image img = null; + long tiffT4Options = 0; + long tiffT6Options = 0; + int fillOrder = 1; + int h = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH); + int w = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH); + int dpiX = 0; + int dpiY = 0; + float XYRatio = 0; + int resolutionUnit = TIFFConstants.RESUNIT_INCH; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT)) + resolutionUnit = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT); + dpiX = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_XRESOLUTION), resolutionUnit); + dpiY = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_YRESOLUTION), resolutionUnit); + if (resolutionUnit == TIFFConstants.RESUNIT_NONE) { + if (dpiY != 0) + XYRatio = (float)dpiX / (float)dpiY; + dpiX = 0; + dpiY = 0; + } + int rowsStrip = h; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP)) + rowsStrip = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP); + if (rowsStrip <= 0 || rowsStrip > h) + rowsStrip = h; + long[] offset = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPOFFSETS); + long[] size = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPBYTECOUNTS); + if ((size == null || (size.Length == 1 && (size[0] == 0 || size[0] + offset[0] > s.Length))) && h == rowsStrip) { // some TIFF producers are really lousy, so... + size = new long[]{s.Length - (int)offset[0]}; + } + bool reverse = false; + TIFFField fillOrderField = dir.GetField(TIFFConstants.TIFFTAG_FILLORDER); + if (fillOrderField != null) + fillOrder = fillOrderField.GetAsInt(0); + reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB); + int paramsn = 0; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_PHOTOMETRIC)) { + long photo = dir.GetFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC); + if (photo == TIFFConstants.PHOTOMETRIC_MINISBLACK) + paramsn |= Image.CCITT_BLACKIS1; + } + int imagecomp = 0; + switch (compression) { + case TIFFConstants.COMPRESSION_CCITTRLEW: + case TIFFConstants.COMPRESSION_CCITTRLE: + imagecomp = Image.CCITTG3_1D; + paramsn |= Image.CCITT_ENCODEDBYTEALIGN | Image.CCITT_ENDOFBLOCK; + break; + case TIFFConstants.COMPRESSION_CCITTFAX3: + imagecomp = Image.CCITTG3_1D; + paramsn |= Image.CCITT_ENDOFLINE | Image.CCITT_ENDOFBLOCK; + TIFFField t4OptionsField = dir.GetField(TIFFConstants.TIFFTAG_GROUP3OPTIONS); + if (t4OptionsField != null) { + tiffT4Options = t4OptionsField.GetAsLong(0); + if ((tiffT4Options & TIFFConstants.GROUP3OPT_2DENCODING) != 0) + imagecomp = Image.CCITTG3_2D; + if ((tiffT4Options & TIFFConstants.GROUP3OPT_FILLBITS) != 0) + paramsn |= Image.CCITT_ENCODEDBYTEALIGN; + } + break; + case TIFFConstants.COMPRESSION_CCITTFAX4: + imagecomp = Image.CCITTG4; + TIFFField t6OptionsField = dir.GetField(TIFFConstants.TIFFTAG_GROUP4OPTIONS); + if (t6OptionsField != null) + tiffT6Options = t6OptionsField.GetAsLong(0); + break; + } + if (direct && rowsStrip == h) { //single strip, direct + byte[] im = new byte[(int)size[0]]; + s.Seek(offset[0]); + s.ReadFully(im); + img = Image.GetInstance(w, h, false, imagecomp, paramsn, im); + img.Inverted = true; + } + else { + int rowsLeft = h; + CCITTG4Encoder g4 = new CCITTG4Encoder(w); + for (int k = 0; k < offset.Length; ++k) { + byte[] im = new byte[(int)size[k]]; + s.Seek(offset[k]); + s.ReadFully(im); + int height = Math.Min(rowsStrip, rowsLeft); + TIFFFaxDecoder decoder = new TIFFFaxDecoder(fillOrder, w, height); + byte[] outBuf = new byte[(w + 7) / 8 * height]; + switch (compression) { + case TIFFConstants.COMPRESSION_CCITTRLEW: + case TIFFConstants.COMPRESSION_CCITTRLE: + decoder.Decode1D(outBuf, im, 0, height); + g4.Fax4Encode(outBuf, height); + break; + case TIFFConstants.COMPRESSION_CCITTFAX3: + try { + decoder.Decode2D(outBuf, im, 0, height, tiffT4Options); + } + catch (Exception e) { + // let's flip the fill bits and try again... + tiffT4Options ^= TIFFConstants.GROUP3OPT_FILLBITS; + try { + decoder.Decode2D(outBuf, im, 0, height, tiffT4Options); + } + catch { + throw e; + } + } + g4.Fax4Encode(outBuf, height); + break; + case TIFFConstants.COMPRESSION_CCITTFAX4: + decoder.DecodeT6(outBuf, im, 0, height, tiffT6Options); + g4.Fax4Encode(outBuf, height); + break; + } + rowsLeft -= rowsStrip; + } + byte[] g4pic = g4.Close(); + img = Image.GetInstance(w, h, false, Image.CCITTG4, paramsn & Image.CCITT_BLACKIS1, g4pic); + } + img.SetDpi(dpiX, dpiY); + img.XYRatio = XYRatio; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) { + try { + TIFFField fd = dir.GetField(TIFFConstants.TIFFTAG_ICCPROFILE); + ICC_Profile icc_prof = ICC_Profile.GetInstance(fd.GetAsBytes()); + if (icc_prof.NumComponents == 1) + img.TagICC = icc_prof; + } + catch { + //empty + } + } + img.OriginalType = Image.ORIGINAL_TIFF; + if (rotation != 0) + img.InitialRotation = rotation; + return img; + } + + protected static Image GetTiffImageColor(TIFFDirectory dir, RandomAccessFileOrArray s) { + int predictor = 1; + TIFFLZWDecoder lzwDecoder = null; + int compression = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION); + switch (compression) { + case TIFFConstants.COMPRESSION_NONE: + case TIFFConstants.COMPRESSION_LZW: + case TIFFConstants.COMPRESSION_PACKBITS: + case TIFFConstants.COMPRESSION_DEFLATE: + case TIFFConstants.COMPRESSION_ADOBE_DEFLATE: + case TIFFConstants.COMPRESSION_OJPEG: + case TIFFConstants.COMPRESSION_JPEG: + break; + default: + throw new ArgumentException("The compression " + compression + " is not supported."); + } + int photometric = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC); + switch (photometric) { + case TIFFConstants.PHOTOMETRIC_MINISWHITE: + case TIFFConstants.PHOTOMETRIC_MINISBLACK: + case TIFFConstants.PHOTOMETRIC_RGB: + case TIFFConstants.PHOTOMETRIC_SEPARATED: + case TIFFConstants.PHOTOMETRIC_PALETTE: + break; + default: + if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) + throw new ArgumentException("The photometric " + photometric + " is not supported."); + break; + } + float rotation = 0; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) { + int rot = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION); + if (rot == TIFFConstants.ORIENTATION_BOTRIGHT || rot == TIFFConstants.ORIENTATION_BOTLEFT) + rotation = (float)Math.PI; + else if (rot == TIFFConstants.ORIENTATION_LEFTTOP || rot == TIFFConstants.ORIENTATION_LEFTBOT) + rotation = (float)(Math.PI / 2.0); + else if (rot == TIFFConstants.ORIENTATION_RIGHTTOP || rot == TIFFConstants.ORIENTATION_RIGHTBOT) + rotation = -(float)(Math.PI / 2.0); + } + + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_PLANARCONFIG) + && dir.GetFieldAsLong(TIFFConstants.TIFFTAG_PLANARCONFIG) == TIFFConstants.PLANARCONFIG_SEPARATE) + throw new ArgumentException("Planar images are not supported."); + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_EXTRASAMPLES)) + throw new ArgumentException("Extra samples are not supported."); + int samplePerPixel = 1; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL)) // 1,3,4 + samplePerPixel = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL); + int bitsPerSample = 1; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_BITSPERSAMPLE)) + bitsPerSample = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_BITSPERSAMPLE); + switch (bitsPerSample) { + case 1: + case 2: + case 4: + case 8: + break; + default: + throw new ArgumentException("Bits per sample " + bitsPerSample + " is not supported."); + } + Image img = null; + + int h = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH); + int w = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH); + int dpiX = 0; + int dpiY = 0; + int resolutionUnit = TIFFConstants.RESUNIT_INCH; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT)) + resolutionUnit = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT); + dpiX = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_XRESOLUTION), resolutionUnit); + dpiY = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_YRESOLUTION), resolutionUnit); + int fillOrder = 1; + bool reverse = false; + TIFFField fillOrderField = dir.GetField(TIFFConstants.TIFFTAG_FILLORDER); + if (fillOrderField != null) + fillOrder = fillOrderField.GetAsInt(0); + reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB); + int rowsStrip = h; + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP)) //another hack for broken tiffs + rowsStrip = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP); + if (rowsStrip <= 0 || rowsStrip > h) + rowsStrip = h; + long[] offset = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPOFFSETS); + long[] size = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPBYTECOUNTS); + if ((size == null || (size.Length == 1 && (size[0] == 0 || size[0] + offset[0] > s.Length))) && h == rowsStrip) { // some TIFF producers are really lousy, so... + size = new long[]{s.Length - (int)offset[0]}; + } + if (compression == TIFFConstants.COMPRESSION_LZW) { + TIFFField predictorField = dir.GetField(TIFFConstants.TIFFTAG_PREDICTOR); + if (predictorField != null) { + predictor = predictorField.GetAsInt(0); + if (predictor != 1 && predictor != 2) { + throw new Exception("Illegal value for Predictor in TIFF file."); + } + if (predictor == 2 && bitsPerSample != 8) { + throw new Exception(bitsPerSample + "-bit samples are not supported for Horizontal differencing Predictor."); + } + } + lzwDecoder = new TIFFLZWDecoder(w, predictor, + samplePerPixel); + } + int rowsLeft = h; + MemoryStream stream = null; + ZDeflaterOutputStream zip = null; + CCITTG4Encoder g4 = null; + if (bitsPerSample == 1 && samplePerPixel == 1) { + g4 = new CCITTG4Encoder(w); + } + else { + stream = new MemoryStream(); + if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) + zip = new ZDeflaterOutputStream(stream); + } + if (compression == TIFFConstants.COMPRESSION_OJPEG) { + + // Assume that the TIFFTAG_JPEGIFBYTECOUNT tag is optional, since it's obsolete and + // is often missing + + if ((!dir.IsTagPresent(TIFFConstants.TIFFTAG_JPEGIFOFFSET))) { + throw new IOException("Missing tag(s) for OJPEG compression."); + } + int jpegOffset = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFOFFSET); + int jpegLength = s.Length - jpegOffset; + + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT)) { + jpegLength = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT) + + (int)size[0]; + } + + byte[] jpeg = new byte[Math.Min(jpegLength, s.Length - jpegOffset)]; + + int posFilePointer = s.FilePointer; + posFilePointer += jpegOffset; + s.Seek(posFilePointer); + s.ReadFully(jpeg); + img = new Jpeg(jpeg); + } + else if (compression == TIFFConstants.COMPRESSION_JPEG) { + if (size.Length > 1) + throw new IOException("Compression JPEG is only supported with a single strip. This image has " + size.Length + " strips."); + byte[] jpeg = new byte[(int)size[0]]; + s.Seek(offset[0]); + s.ReadFully(jpeg); + img = new Jpeg(jpeg); + } + else { + for (int k = 0; k < offset.Length; ++k) { + byte[] im = new byte[(int)size[k]]; + s.Seek(offset[k]); + s.ReadFully(im); + int height = Math.Min(rowsStrip, rowsLeft); + byte[] outBuf = null; + if (compression != TIFFConstants.COMPRESSION_NONE) + outBuf = new byte[(w * bitsPerSample * samplePerPixel + 7) / 8 * height]; + if (reverse) + TIFFFaxDecoder.ReverseBits(im); + switch (compression) { + case TIFFConstants.COMPRESSION_DEFLATE: + case TIFFConstants.COMPRESSION_ADOBE_DEFLATE: + Inflate(im, outBuf); + break; + case TIFFConstants.COMPRESSION_NONE: + outBuf = im; + break; + case TIFFConstants.COMPRESSION_PACKBITS: + DecodePackbits(im, outBuf); + break; + case TIFFConstants.COMPRESSION_LZW: + lzwDecoder.Decode(im, outBuf, height); + break; + } + if (bitsPerSample == 1 && samplePerPixel == 1) { + g4.Fax4Encode(outBuf, height); + } + else { + zip.Write(outBuf, 0, outBuf.Length); + } + rowsLeft -= rowsStrip; + } + if (bitsPerSample == 1 && samplePerPixel == 1) { + img = Image.GetInstance(w, h, false, Image.CCITTG4, + photometric == TIFFConstants.PHOTOMETRIC_MINISBLACK ? Image.CCITT_BLACKIS1 : 0, g4.Close()); + } + else { + zip.Close(); + img = Image.GetInstance(w, h, samplePerPixel, bitsPerSample, stream.ToArray()); + img.Deflated = true; + } + } + img.SetDpi(dpiX, dpiY); + if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) { + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) { + try { + TIFFField fd = dir.GetField(TIFFConstants.TIFFTAG_ICCPROFILE); + ICC_Profile icc_prof = ICC_Profile.GetInstance(fd.GetAsBytes()); + if (samplePerPixel == icc_prof.NumComponents) + img.TagICC = icc_prof; + } + catch { + //empty + } + } + if (dir.IsTagPresent(TIFFConstants.TIFFTAG_COLORMAP)) { + TIFFField fd = dir.GetField(TIFFConstants.TIFFTAG_COLORMAP); + char[] rgb = fd.GetAsChars(); + byte[] palette = new byte[rgb.Length]; + int gColor = rgb.Length / 3; + int bColor = gColor * 2; + for (int k = 0; k < gColor; ++k) { + palette[k * 3] = (byte)(rgb[k] >> 8); + palette[k * 3 + 1] = (byte)(rgb[k + gColor] >> 8); + palette[k * 3 + 2] = (byte)(rgb[k + bColor] >> 8); + } + PdfArray indexed = new PdfArray(); + indexed.Add(PdfName.INDEXED); + indexed.Add(PdfName.DEVICERGB); + indexed.Add(new PdfNumber(gColor - 1)); + indexed.Add(new PdfString(palette)); + PdfDictionary additional = new PdfDictionary(); + additional.Put(PdfName.COLORSPACE, indexed); + img.Additional = additional; + } + img.OriginalType = Image.ORIGINAL_TIFF; + } + if (photometric == TIFFConstants.PHOTOMETRIC_MINISWHITE) + img.Inverted = true; + if (rotation != 0) + img.InitialRotation = rotation; + return img; + } + + static long[] GetArrayLongShort(TIFFDirectory dir, int tag) { + TIFFField field = dir.GetField(tag); + if (field == null) + return null; + long[] offset; + if (field.GetType() == TIFFField.TIFF_LONG) + offset = field.GetAsLongs(); + else { // must be short + char[] temp = field.GetAsChars(); + offset = new long[temp.Length]; + for (int k = 0; k < temp.Length; ++k) + offset[k] = temp[k]; + } + return offset; + } + + // Uncompress packbits compressed image data. + public static void DecodePackbits(byte[] data, byte[] dst) { + int srcCount = 0, dstCount = 0; + sbyte repeat, b; + + try { + while (dstCount < dst.Length) { + b = (sbyte)data[srcCount++]; + if (b >= 0 && b <= 127) { + // literal run packet + for (int i=0; i<(b + 1); i++) { + dst[dstCount++] = data[srcCount++]; + } + + } else if (b <= -1 && b >= -127) { + // 2 byte encoded run packet + repeat = (sbyte)data[srcCount++]; + for (int i=0; i<(-b + 1); i++) { + dst[dstCount++] = (byte)repeat; + } + } else { + // no-op packet. Do nothing + srcCount++; + } + } + } + catch { + } + } + + public static void Inflate(byte[] deflated, byte[] inflated) { + byte[] outp = PdfReader.FlateDecode(deflated); + System.Array.Copy(outp, 0, inflated, 0, Math.Min(outp.Length, inflated.Length)); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/InputMeta.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/InputMeta.cs new file mode 100644 index 0000000..55faf1b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/InputMeta.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; +using iTextSharp.text; + +/* + * $Id: InputMeta.cs,v 1.4 2008/05/13 11:25:36 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf { + ///

    + /// Summary description for InputMeta. + /// + public class InputMeta { + + Stream sr; + int length; + + public InputMeta(Stream istr) { + this.sr = istr; + } + + public int ReadWord() { + length += 2; + int k1 = sr.ReadByte(); + if (k1 < 0) + return 0; + return (k1 + (sr.ReadByte() << 8)) & 0xffff; + } + + public int ReadShort() { + int k = ReadWord(); + if (k > 0x7fff) + k -= 0x10000; + return k; + } + + public Int32 ReadInt() { + length += 4; + int k1 = sr.ReadByte(); + if (k1 < 0) + return 0; + int k2 = sr.ReadByte() << 8; + int k3 = sr.ReadByte() << 16; + return k1 + k2 + k3 + (sr.ReadByte() << 24); + } + + public int ReadByte() { + ++length; + return sr.ReadByte() & 0xff; + } + + public void Skip(int len) { + length += len; + Utilities.Skip(sr, len); + } + + public int Length { + get { + return length; + } + } + + public Color ReadColor() { + int red = ReadByte(); + int green = ReadByte(); + int blue = ReadByte(); + ReadByte(); + return new Color(red, green, blue); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaBrush.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaBrush.cs new file mode 100644 index 0000000..8f475d4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaBrush.cs @@ -0,0 +1,101 @@ +using System; +using iTextSharp.text; + +/* + * $Id: MetaBrush.cs,v 1.3 2008/05/13 11:25:36 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf { + public class MetaBrush : MetaObject { + + public const int BS_SOLID = 0; + public const int BS_NULL = 1; + public const int BS_HATCHED = 2; + public const int BS_PATTERN = 3; + public const int BS_DIBPATTERN = 5; + public const int HS_HORIZONTAL = 0; + public const int HS_VERTICAL = 1; + public const int HS_FDIAGONAL = 2; + public const int HS_BDIAGONAL = 3; + public const int HS_CROSS = 4; + public const int HS_DIAGCROSS = 5; + + int style = BS_SOLID; + int hatch; + Color color = Color.WHITE; + + public MetaBrush() { + type = META_BRUSH; + } + + public void Init(InputMeta meta) { + style = meta.ReadWord(); + color = meta.ReadColor(); + hatch = meta.ReadWord(); + } + + public int Style { + get { + return style; + } + } + + public int Hatch { + get { + return hatch; + } + } + + public Color Color { + get { + return color; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaDo.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaDo.cs new file mode 100644 index 0000000..39ae47a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaDo.cs @@ -0,0 +1,764 @@ +using System; +using System.IO; +using System.Net; +using iTextSharp.text; +using System.Collections; + +/* + * $Id: MetaDo.cs,v 1.4 2008/05/13 11:25:36 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf +{ + /// + /// Summary description for MetaDo. + /// + public class MetaDo + { + + public const int META_SETBKCOLOR = 0x0201; + public const int META_SETBKMODE = 0x0102; + public const int META_SETMAPMODE = 0x0103; + public const int META_SETROP2 = 0x0104; + public const int META_SETRELABS = 0x0105; + public const int META_SETPOLYFILLMODE = 0x0106; + public const int META_SETSTRETCHBLTMODE = 0x0107; + public const int META_SETTEXTCHAREXTRA = 0x0108; + public const int META_SETTEXTCOLOR = 0x0209; + public const int META_SETTEXTJUSTIFICATION = 0x020A; + public const int META_SETWINDOWORG = 0x020B; + public const int META_SETWINDOWEXT = 0x020C; + public const int META_SETVIEWPORTORG = 0x020D; + public const int META_SETVIEWPORTEXT = 0x020E; + public const int META_OFFSETWINDOWORG = 0x020F; + public const int META_SCALEWINDOWEXT = 0x0410; + public const int META_OFFSETVIEWPORTORG = 0x0211; + public const int META_SCALEVIEWPORTEXT = 0x0412; + public const int META_LINETO = 0x0213; + public const int META_MOVETO = 0x0214; + public const int META_EXCLUDECLIPRECT = 0x0415; + public const int META_INTERSECTCLIPRECT = 0x0416; + public const int META_ARC = 0x0817; + public const int META_ELLIPSE = 0x0418; + public const int META_FLOODFILL = 0x0419; + public const int META_PIE = 0x081A; + public const int META_RECTANGLE = 0x041B; + public const int META_ROUNDRECT = 0x061C; + public const int META_PATBLT = 0x061D; + public const int META_SAVEDC = 0x001E; + public const int META_SETPIXEL = 0x041F; + public const int META_OFFSETCLIPRGN = 0x0220; + public const int META_TEXTOUT = 0x0521; + public const int META_BITBLT = 0x0922; + public const int META_STRETCHBLT = 0x0B23; + public const int META_POLYGON = 0x0324; + public const int META_POLYLINE = 0x0325; + public const int META_ESCAPE = 0x0626; + public const int META_RESTOREDC = 0x0127; + public const int META_FILLREGION = 0x0228; + public const int META_FRAMEREGION = 0x0429; + public const int META_INVERTREGION = 0x012A; + public const int META_PAINTREGION = 0x012B; + public const int META_SELECTCLIPREGION = 0x012C; + public const int META_SELECTOBJECT = 0x012D; + public const int META_SETTEXTALIGN = 0x012E; + public const int META_CHORD = 0x0830; + public const int META_SETMAPPERFLAGS = 0x0231; + public const int META_EXTTEXTOUT = 0x0a32; + public const int META_SETDIBTODEV = 0x0d33; + public const int META_SELECTPALETTE = 0x0234; + public const int META_REALIZEPALETTE = 0x0035; + public const int META_ANIMATEPALETTE = 0x0436; + public const int META_SETPALENTRIES = 0x0037; + public const int META_POLYPOLYGON = 0x0538; + public const int META_RESIZEPALETTE = 0x0139; + public const int META_DIBBITBLT = 0x0940; + public const int META_DIBSTRETCHBLT = 0x0b41; + public const int META_DIBCREATEPATTERNBRUSH = 0x0142; + public const int META_STRETCHDIB = 0x0f43; + public const int META_EXTFLOODFILL = 0x0548; + public const int META_DELETEOBJECT = 0x01f0; + public const int META_CREATEPALETTE = 0x00f7; + public const int META_CREATEPATTERNBRUSH = 0x01F9; + public const int META_CREATEPENINDIRECT = 0x02FA; + public const int META_CREATEFONTINDIRECT = 0x02FB; + public const int META_CREATEBRUSHINDIRECT = 0x02FC; + public const int META_CREATEREGION = 0x06FF; + + public PdfContentByte cb; + public InputMeta meta; + int left; + int top; + int right; + int bottom; + int inch; + MetaState state = new MetaState(); + + public MetaDo(Stream meta, PdfContentByte cb) { + this.cb = cb; + this.meta = new InputMeta(meta); + } + + public void ReadAll() { + if (meta.ReadInt() != unchecked((int)0x9AC6CDD7)) { + throw new DocumentException("Not a placeable windows metafile"); + } + meta.ReadWord(); + left = meta.ReadShort(); + top = meta.ReadShort(); + right = meta.ReadShort(); + bottom = meta.ReadShort(); + inch = meta.ReadWord(); + state.ScalingX = (float)(right - left) / (float)inch * 72f; + state.ScalingY = (float)(bottom - top) / (float)inch * 72f; + state.OffsetWx = left; + state.OffsetWy = top; + state.ExtentWx = right - left; + state.ExtentWy = bottom - top; + meta.ReadInt(); + meta.ReadWord(); + meta.Skip(18); + + int tsize; + int function; + cb.SetLineCap(1); + cb.SetLineJoin(1); + for (;;) { + int lenMarker = meta.Length; + tsize = meta.ReadInt(); + if (tsize < 3) + break; + function = meta.ReadWord(); + switch (function) { + case 0: + break; + case META_CREATEPALETTE: + case META_CREATEREGION: + case META_DIBCREATEPATTERNBRUSH: + state.AddMetaObject(new MetaObject()); + break; + case META_CREATEPENINDIRECT: + { + MetaPen pen = new MetaPen(); + pen.Init(meta); + state.AddMetaObject(pen); + break; + } + case META_CREATEBRUSHINDIRECT: + { + MetaBrush brush = new MetaBrush(); + brush.Init(meta); + state.AddMetaObject(brush); + break; + } + case META_CREATEFONTINDIRECT: + { + MetaFont font = new MetaFont(); + font.Init(meta); + state.AddMetaObject(font); + break; + } + case META_SELECTOBJECT: + { + int idx = meta.ReadWord(); + state.SelectMetaObject(idx, cb); + break; + } + case META_DELETEOBJECT: + { + int idx = meta.ReadWord(); + state.DeleteMetaObject(idx); + break; + } + case META_SAVEDC: + state.SaveState(cb); + break; + case META_RESTOREDC: + { + int idx = meta.ReadShort(); + state.RestoreState(idx, cb); + break; + } + case META_SETWINDOWORG: + state.OffsetWy = meta.ReadShort(); + state.OffsetWx = meta.ReadShort(); + break; + case META_SETWINDOWEXT: + state.ExtentWy = meta.ReadShort(); + state.ExtentWx = meta.ReadShort(); + break; + case META_MOVETO: + { + int y = meta.ReadShort(); + System.Drawing.Point p = new System.Drawing.Point(meta.ReadShort(), y); + state.CurrentPoint = p; + break; + } + case META_LINETO: + { + int y = meta.ReadShort(); + int x = meta.ReadShort(); + System.Drawing.Point p = state.CurrentPoint; + cb.MoveTo(state.TransformX(p.X), state.TransformY(p.Y)); + cb.LineTo(state.TransformX(x), state.TransformY(y)); + cb.Stroke(); + state.CurrentPoint = new System.Drawing.Point(x, y); + break; + } + case META_POLYLINE: + { + state.LineJoinPolygon = cb; + int len = meta.ReadWord(); + int x = meta.ReadShort(); + int y = meta.ReadShort(); + cb.MoveTo(state.TransformX(x), state.TransformY(y)); + for (int k = 1; k < len; ++k) { + x = meta.ReadShort(); + y = meta.ReadShort(); + cb.LineTo(state.TransformX(x), state.TransformY(y)); + } + cb.Stroke(); + break; + } + case META_POLYGON: + { + if (IsNullStrokeFill(false)) + break; + int len = meta.ReadWord(); + int sx = meta.ReadShort(); + int sy = meta.ReadShort(); + cb.MoveTo(state.TransformX(sx), state.TransformY(sy)); + for (int k = 1; k < len; ++k) { + int x = meta.ReadShort(); + int y = meta.ReadShort(); + cb.LineTo(state.TransformX(x), state.TransformY(y)); + } + cb.LineTo(state.TransformX(sx), state.TransformY(sy)); + StrokeAndFill(); + break; + } + case META_POLYPOLYGON: + { + if (IsNullStrokeFill(false)) + break; + int numPoly = meta.ReadWord(); + int[] lens = new int[numPoly]; + for (int k = 0; k < lens.Length; ++k) + lens[k] = meta.ReadWord(); + for (int j = 0; j < lens.Length; ++j) { + int len = lens[j]; + int sx = meta.ReadShort(); + int sy = meta.ReadShort(); + cb.MoveTo(state.TransformX(sx), state.TransformY(sy)); + for (int k = 1; k < len; ++k) { + int x = meta.ReadShort(); + int y = meta.ReadShort(); + cb.LineTo(state.TransformX(x), state.TransformY(y)); + } + cb.LineTo(state.TransformX(sx), state.TransformY(sy)); + } + StrokeAndFill(); + break; + } + case META_ELLIPSE: + { + if (IsNullStrokeFill(state.LineNeutral)) + break; + int b = meta.ReadShort(); + int r = meta.ReadShort(); + int t = meta.ReadShort(); + int l = meta.ReadShort(); + cb.Arc(state.TransformX(l), state.TransformY(b), state.TransformX(r), state.TransformY(t), 0, 360); + StrokeAndFill(); + break; + } + case META_ARC: + { + if (IsNullStrokeFill(state.LineNeutral)) + break; + float yend = state.TransformY(meta.ReadShort()); + float xend = state.TransformX(meta.ReadShort()); + float ystart = state.TransformY(meta.ReadShort()); + float xstart = state.TransformX(meta.ReadShort()); + float b = state.TransformY(meta.ReadShort()); + float r = state.TransformX(meta.ReadShort()); + float t = state.TransformY(meta.ReadShort()); + float l = state.TransformX(meta.ReadShort()); + float cx = (r + l) / 2; + float cy = (t + b) / 2; + float arc1 = GetArc(cx, cy, xstart, ystart); + float arc2 = GetArc(cx, cy, xend, yend); + arc2 -= arc1; + if (arc2 <= 0) + arc2 += 360; + cb.Arc(l, b, r, t, arc1, arc2); + cb.Stroke(); + break; + } + case META_PIE: + { + if (IsNullStrokeFill(state.LineNeutral)) + break; + float yend = state.TransformY(meta.ReadShort()); + float xend = state.TransformX(meta.ReadShort()); + float ystart = state.TransformY(meta.ReadShort()); + float xstart = state.TransformX(meta.ReadShort()); + float b = state.TransformY(meta.ReadShort()); + float r = state.TransformX(meta.ReadShort()); + float t = state.TransformY(meta.ReadShort()); + float l = state.TransformX(meta.ReadShort()); + float cx = (r + l) / 2; + float cy = (t + b) / 2; + float arc1 = GetArc(cx, cy, xstart, ystart); + float arc2 = GetArc(cx, cy, xend, yend); + arc2 -= arc1; + if (arc2 <= 0) + arc2 += 360; + ArrayList ar = PdfContentByte.BezierArc(l, b, r, t, arc1, arc2); + if (ar.Count == 0) + break; + float[] pt = (float [])ar[0]; + cb.MoveTo(cx, cy); + cb.LineTo(pt[0], pt[1]); + for (int k = 0; k < ar.Count; ++k) { + pt = (float [])ar[k]; + cb.CurveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]); + } + cb.LineTo(cx, cy); + StrokeAndFill(); + break; + } + case META_CHORD: + { + if (IsNullStrokeFill(state.LineNeutral)) + break; + float yend = state.TransformY(meta.ReadShort()); + float xend = state.TransformX(meta.ReadShort()); + float ystart = state.TransformY(meta.ReadShort()); + float xstart = state.TransformX(meta.ReadShort()); + float b = state.TransformY(meta.ReadShort()); + float r = state.TransformX(meta.ReadShort()); + float t = state.TransformY(meta.ReadShort()); + float l = state.TransformX(meta.ReadShort()); + float cx = (r + l) / 2; + float cy = (t + b) / 2; + float arc1 = GetArc(cx, cy, xstart, ystart); + float arc2 = GetArc(cx, cy, xend, yend); + arc2 -= arc1; + if (arc2 <= 0) + arc2 += 360; + ArrayList ar = PdfContentByte.BezierArc(l, b, r, t, arc1, arc2); + if (ar.Count == 0) + break; + float[] pt = (float [])ar[0]; + cx = pt[0]; + cy = pt[1]; + cb.MoveTo(cx, cy); + for (int k = 0; k < ar.Count; ++k) { + pt = (float [])ar[k]; + cb.CurveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]); + } + cb.LineTo(cx, cy); + StrokeAndFill(); + break; + } + case META_RECTANGLE: + { + if (IsNullStrokeFill(true)) + break; + float b = state.TransformY(meta.ReadShort()); + float r = state.TransformX(meta.ReadShort()); + float t = state.TransformY(meta.ReadShort()); + float l = state.TransformX(meta.ReadShort()); + cb.Rectangle(l, b, r - l, t - b); + StrokeAndFill(); + break; + } + case META_ROUNDRECT: + { + if (IsNullStrokeFill(true)) + break; + float h = state.TransformY(0) - state.TransformY(meta.ReadShort()); + float w = state.TransformX(meta.ReadShort()) - state.TransformX(0); + float b = state.TransformY(meta.ReadShort()); + float r = state.TransformX(meta.ReadShort()); + float t = state.TransformY(meta.ReadShort()); + float l = state.TransformX(meta.ReadShort()); + cb.RoundRectangle(l, b, r - l, t - b, (h + w) / 4); + StrokeAndFill(); + break; + } + case META_INTERSECTCLIPRECT: + { + float b = state.TransformY(meta.ReadShort()); + float r = state.TransformX(meta.ReadShort()); + float t = state.TransformY(meta.ReadShort()); + float l = state.TransformX(meta.ReadShort()); + cb.Rectangle(l, b, r - l, t - b); + cb.EoClip(); + cb.NewPath(); + break; + } + case META_EXTTEXTOUT: + { + int y = meta.ReadShort(); + int x = meta.ReadShort(); + int count = meta.ReadWord(); + int flag = meta.ReadWord(); + int x1 = 0; + int y1 = 0; + int x2 = 0; + int y2 = 0; + if ((flag & (MetaFont.ETO_CLIPPED | MetaFont.ETO_OPAQUE)) != 0) { + x1 = meta.ReadShort(); + y1 = meta.ReadShort(); + x2 = meta.ReadShort(); + y2 = meta.ReadShort(); + } + byte[] text = new byte[count]; + int k; + for (k = 0; k < count; ++k) { + byte c = (byte)meta.ReadByte(); + if (c == 0) + break; + text[k] = c; + } + string s; + try { + s = System.Text.Encoding.GetEncoding(1252).GetString(text, 0, k); + } + catch { + s = System.Text.ASCIIEncoding.ASCII.GetString(text, 0, k); + } + OutputText(x, y, flag, x1, y1, x2, y2, s); + break; + } + case META_TEXTOUT: + { + int count = meta.ReadWord(); + byte[] text = new byte[count]; + int k; + for (k = 0; k < count; ++k) { + byte c = (byte)meta.ReadByte(); + if (c == 0) + break; + text[k] = c; + } + string s; + try { + s = System.Text.Encoding.GetEncoding(1252).GetString(text, 0, k); + } + catch { + s = System.Text.ASCIIEncoding.ASCII.GetString(text, 0, k); + } + count = (count + 1) & 0xfffe; + meta.Skip(count - k); + int y = meta.ReadShort(); + int x = meta.ReadShort(); + OutputText(x, y, 0, 0, 0, 0, 0, s); + break; + } + case META_SETBKCOLOR: + state.CurrentBackgroundColor = meta.ReadColor(); + break; + case META_SETTEXTCOLOR: + state.CurrentTextColor = meta.ReadColor(); + break; + case META_SETTEXTALIGN: + state.TextAlign = meta.ReadWord(); + break; + case META_SETBKMODE: + state.BackgroundMode = meta.ReadWord(); + break; + case META_SETPOLYFILLMODE: + state.PolyFillMode = meta.ReadWord(); + break; + case META_SETPIXEL: + { + Color color = meta.ReadColor(); + int y = meta.ReadShort(); + int x = meta.ReadShort(); + cb.SaveState(); + cb.SetColorFill(color); + cb.Rectangle(state.TransformX(x), state.TransformY(y), .2f, .2f); + cb.Fill(); + cb.RestoreState(); + break; + } + case META_DIBSTRETCHBLT: + case META_STRETCHDIB: { + int rop = meta.ReadInt(); + if (function == META_STRETCHDIB) { + /*int usage = */ meta.ReadWord(); + } + int srcHeight = meta.ReadShort(); + int srcWidth = meta.ReadShort(); + int ySrc = meta.ReadShort(); + int xSrc = meta.ReadShort(); + float destHeight = state.TransformY(meta.ReadShort()) - state.TransformY(0); + float destWidth = state.TransformX(meta.ReadShort()) - state.TransformX(0); + float yDest = state.TransformY(meta.ReadShort()); + float xDest = state.TransformX(meta.ReadShort()); + byte[] b = new byte[(tsize * 2) - (meta.Length - lenMarker)]; + for (int k = 0; k < b.Length; ++k) + b[k] = (byte)meta.ReadByte(); + try { + MemoryStream inb = new MemoryStream(b); + Image bmp = BmpImage.GetImage(inb, true, b.Length); + cb.SaveState(); + cb.Rectangle(xDest, yDest, destWidth, destHeight); + cb.Clip(); + cb.NewPath(); + bmp.ScaleAbsolute(destWidth * bmp.Width / srcWidth, -destHeight * bmp.Height / srcHeight); + bmp.SetAbsolutePosition(xDest - destWidth * xSrc / srcWidth, yDest + destHeight * ySrc / srcHeight - bmp.ScaledHeight); + cb.AddImage(bmp); + cb.RestoreState(); + } + catch { + // empty on purpose + } + break; + } + } + meta.Skip((tsize * 2) - (meta.Length - lenMarker)); + } + state.Cleanup(cb); + } + + public void OutputText(int x, int y, int flag, int x1, int y1, int x2, int y2, string text) { + MetaFont font = state.CurrentFont; + float refX = state.TransformX(x); + float refY = state.TransformY(y); + float angle = state.TransformAngle(font.Angle); + float sin = (float)Math.Sin(angle); + float cos = (float)Math.Cos(angle); + float fontSize = font.GetFontSize(state); + BaseFont bf = font.Font; + int align = state.TextAlign; + float textWidth = bf.GetWidthPoint(text, fontSize); + float tx = 0; + float ty = 0; + float descender = bf.GetFontDescriptor(BaseFont.DESCENT, fontSize); + float ury = bf.GetFontDescriptor(BaseFont.BBOXURY, fontSize); + cb.SaveState(); + cb.ConcatCTM(cos, sin, -sin, cos, refX, refY); + if ((align & MetaState.TA_CENTER) == MetaState.TA_CENTER) + tx = -textWidth / 2; + else if ((align & MetaState.TA_RIGHT) == MetaState.TA_RIGHT) + tx = -textWidth; + if ((align & MetaState.TA_BASELINE) == MetaState.TA_BASELINE) + ty = 0; + else if ((align & MetaState.TA_BOTTOM) == MetaState.TA_BOTTOM) + ty = -descender; + else + ty = -ury; + Color textColor; + if (state.BackgroundMode == MetaState.OPAQUE) { + textColor = state.CurrentBackgroundColor; + cb.SetColorFill(textColor); + cb.Rectangle(tx, ty + descender, textWidth, ury - descender); + cb.Fill(); + } + textColor = state.CurrentTextColor; + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(bf, fontSize); + cb.SetTextMatrix(tx, ty); + cb.ShowText(text); + cb.EndText(); + if (font.IsUnderline()) { + cb.Rectangle(tx, ty - fontSize / 4, textWidth, fontSize / 15); + cb.Fill(); + } + if (font.IsStrikeout()) { + cb.Rectangle(tx, ty + fontSize / 3, textWidth, fontSize / 15); + cb.Fill(); + } + cb.RestoreState(); + } + + public bool IsNullStrokeFill(bool isRectangle) { + MetaPen pen = state.CurrentPen; + MetaBrush brush = state.CurrentBrush; + bool noPen = (pen.Style == MetaPen.PS_NULL); + int style = brush.Style; + bool isBrush = (style == MetaBrush.BS_SOLID || (style == MetaBrush.BS_HATCHED && state.BackgroundMode == MetaState.OPAQUE)); + bool result = noPen && !isBrush; + if (!noPen) { + if (isRectangle) + state.LineJoinRectangle = cb; + else + state.LineJoinPolygon = cb; + } + return result; + } + + public void StrokeAndFill(){ + MetaPen pen = state.CurrentPen; + MetaBrush brush = state.CurrentBrush; + int penStyle = pen.Style; + int brushStyle = brush.Style; + if (penStyle == MetaPen.PS_NULL) { + cb.ClosePath(); + if (state.PolyFillMode == MetaState.ALTERNATE) { + cb.EoFill(); + } + else { + cb.Fill(); + } + } + else { + bool isBrush = (brushStyle == MetaBrush.BS_SOLID || (brushStyle == MetaBrush.BS_HATCHED && state.BackgroundMode == MetaState.OPAQUE)); + if (isBrush) { + if (state.PolyFillMode == MetaState.ALTERNATE) + cb.ClosePathEoFillStroke(); + else + cb.ClosePathFillStroke(); + } + else { + cb.ClosePathStroke(); + } + } + } + + internal static float GetArc(float xCenter, float yCenter, float xDot, float yDot) { + double s = Math.Atan2(yDot - yCenter, xDot - xCenter); + if (s < 0) + s += Math.PI * 2; + return (float)(s / Math.PI * 180); + } + + public static byte[] WrapBMP(Image image) { + if (image.OriginalType != Image.ORIGINAL_BMP) + throw new IOException("Only BMP can be wrapped in WMF."); + Stream imgIn; + byte[] data = null; + if (image.OriginalData == null) { + imgIn = WebRequest.Create(image.Url).GetResponse().GetResponseStream(); + MemoryStream outp = new MemoryStream(); + int b = 0; + while ((b = imgIn.ReadByte()) != -1) + outp.WriteByte((byte)b); + imgIn.Close(); + data = outp.ToArray(); + } + else + data = image.OriginalData; + int sizeBmpWords = (data.Length - 14 + 1) >> 1; + MemoryStream os = new MemoryStream(); + // write metafile header + WriteWord(os, 1); + WriteWord(os, 9); + WriteWord(os, 0x0300); + WriteDWord(os, 9 + 4 + 5 + 5 + (13 + sizeBmpWords) + 3); // total metafile size + WriteWord(os, 1); + WriteDWord(os, 14 + sizeBmpWords); // max record size + WriteWord(os, 0); + // write records + WriteDWord(os, 4); + WriteWord(os, META_SETMAPMODE); + WriteWord(os, 8); + + WriteDWord(os, 5); + WriteWord(os, META_SETWINDOWORG); + WriteWord(os, 0); + WriteWord(os, 0); + + WriteDWord(os, 5); + WriteWord(os, META_SETWINDOWEXT); + WriteWord(os, (int)image.Height); + WriteWord(os, (int)image.Width); + + WriteDWord(os, 13 + sizeBmpWords); + WriteWord(os, META_DIBSTRETCHBLT); + WriteDWord(os, 0x00cc0020); + WriteWord(os, (int)image.Height); + WriteWord(os, (int)image.Width); + WriteWord(os, 0); + WriteWord(os, 0); + WriteWord(os, (int)image.Height); + WriteWord(os, (int)image.Width); + WriteWord(os, 0); + WriteWord(os, 0); + os.Write(data, 14, data.Length - 14); + if ((data.Length & 1) == 1) + os.WriteByte(0); +// WriteDWord(os, 14 + sizeBmpWords); +// WriteWord(os, META_STRETCHDIB); +// WriteDWord(os, 0x00cc0020); +// WriteWord(os, 0); +// WriteWord(os, (int)image.Height); +// WriteWord(os, (int)image.Width); +// WriteWord(os, 0); +// WriteWord(os, 0); +// WriteWord(os, (int)image.Height); +// WriteWord(os, (int)image.Width); +// WriteWord(os, 0); +// WriteWord(os, 0); +// os.Write(data, 14, data.length - 14); +// if ((data.length & 1) == 1) +// os.Write(0); + + WriteDWord(os, 3); + WriteWord(os, 0); + os.Close(); + return os.ToArray(); + } + + public static void WriteWord(Stream os, int v) { + os.WriteByte((byte)(v & 0xff)); + os.WriteByte((byte)((v >> 8) & 0xff)); + } + + public static void WriteDWord(Stream os, int v) { + WriteWord(os, v & 0xffff); + WriteWord(os, (v >> 16) & 0xffff); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaFont.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaFont.cs new file mode 100644 index 0000000..44c61af --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaFont.cs @@ -0,0 +1,206 @@ +using System; + +/* + * $Id: MetaFont.cs,v 1.7 2008/05/13 11:25:37 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf { + public class MetaFont : MetaObject { + static string[] fontNames = { + "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", + "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", + "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", + "Symbol", "ZapfDingbats"}; + + internal const int MARKER_BOLD = 1; + internal const int MARKER_ITALIC = 2; + internal const int MARKER_COURIER = 0; + internal const int MARKER_HELVETICA = 4; + internal const int MARKER_TIMES = 8; + internal const int MARKER_SYMBOL = 12; + + internal const int DEFAULT_PITCH = 0; + internal const int FIXED_PITCH = 1; + internal const int VARIABLE_PITCH = 2; + internal const int FF_DONTCARE = 0; + internal const int FF_ROMAN = 1; + internal const int FF_SWISS = 2; + internal const int FF_MODERN = 3; + internal const int FF_SCRIPT = 4; + internal const int FF_DECORATIVE = 5; + internal const int BOLDTHRESHOLD = 600; + internal const int nameSize = 32; + internal const int ETO_OPAQUE = 2; + internal const int ETO_CLIPPED = 4; + + int height; + float angle; + int bold; + int italic; + bool underline; + bool strikeout; + int charset; + int pitchAndFamily; + string faceName = "arial"; + BaseFont font = null; + + public MetaFont() { + type = META_FONT; + } + + public void Init(InputMeta meta) { + height = Math.Abs(meta.ReadShort()); + meta.Skip(2); + angle = (float)(meta.ReadShort() / 1800.0 * Math.PI); + meta.Skip(2); + bold = (meta.ReadShort() >= BOLDTHRESHOLD ? MARKER_BOLD : 0); + italic = (meta.ReadByte() != 0 ? MARKER_ITALIC : 0); + underline = (meta.ReadByte() != 0); + strikeout = (meta.ReadByte() != 0); + charset = meta.ReadByte(); + meta.Skip(3); + pitchAndFamily = meta.ReadByte(); + byte[] name = new byte[nameSize]; + int k; + for (k = 0; k < nameSize; ++k) { + int c = meta.ReadByte(); + if (c == 0) { + break; + } + name[k] = (byte)c; + } + try { + faceName = System.Text.Encoding.GetEncoding(1252).GetString(name, 0, k); + } + catch { + faceName = System.Text.ASCIIEncoding.ASCII.GetString(name, 0, k); + } + faceName = faceName.ToLower(System.Globalization.CultureInfo.InvariantCulture); + } + + public BaseFont Font { + get { + if (font != null) + return font; + iTextSharp.text.Font ff2 = FontFactory.GetFont(faceName, BaseFont.CP1252, true, 10, ((italic != 0) ? iTextSharp.text.Font.ITALIC : 0) | ((bold != 0) ? iTextSharp.text.Font.BOLD : 0)); + font = ff2.BaseFont; + if (font != null) + return font; + string fontName; + if (faceName.IndexOf("courier") != -1 || faceName.IndexOf("terminal") != -1 + || faceName.IndexOf("fixedsys") != -1) { + fontName = fontNames[MARKER_COURIER + italic + bold]; + } + else if (faceName.IndexOf("ms sans serif") != -1 || faceName.IndexOf("arial") != -1 + || faceName.IndexOf("system") != -1) { + fontName = fontNames[MARKER_HELVETICA + italic + bold]; + } + else if (faceName.IndexOf("arial black") != -1) { + fontName = fontNames[MARKER_HELVETICA + italic + MARKER_BOLD]; + } + else if (faceName.IndexOf("times") != -1 || faceName.IndexOf("ms serif") != -1 + || faceName.IndexOf("roman") != -1) { + fontName = fontNames[MARKER_TIMES + italic + bold]; + } + else if (faceName.IndexOf("symbol") != -1) { + fontName = fontNames[MARKER_SYMBOL]; + } + else { + int pitch = pitchAndFamily & 3; + int family = (pitchAndFamily >> 4) & 7; + switch (family) { + case FF_MODERN: + fontName = fontNames[MARKER_COURIER + italic + bold]; + break; + case FF_ROMAN: + fontName = fontNames[MARKER_TIMES + italic + bold]; + break; + case FF_SWISS: + case FF_SCRIPT: + case FF_DECORATIVE: + fontName = fontNames[MARKER_HELVETICA + italic + bold]; + break; + default: { + switch (pitch) { + case FIXED_PITCH: + fontName = fontNames[MARKER_COURIER + italic + bold]; + break; + default: + fontName = fontNames[MARKER_HELVETICA + italic + bold]; + break; + } + break; + } + } + } + font = BaseFont.CreateFont(fontName, BaseFont.CP1252, false); + + return font; + } + } + + public float Angle { + get { + return angle; + } + } + + public bool IsUnderline() { + return underline; + } + + public bool IsStrikeout() { + return strikeout; + } + + public float GetFontSize(MetaState state) { + return Math.Abs(state.TransformY(height) - state.TransformY(0)) * Document.WmfFontCorrection; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaObject.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaObject.cs new file mode 100644 index 0000000..cc0e54c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaObject.cs @@ -0,0 +1,76 @@ +using System; + +/* + * $Id: MetaObject.cs,v 1.3 2008/05/13 11:25:37 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf +{ + public class MetaObject + { + public const int META_NOT_SUPPORTED = 0; + public const int META_PEN = 1; + public const int META_BRUSH = 2; + public const int META_FONT = 3; + public int type = META_NOT_SUPPORTED; + + public MetaObject() { + } + + public MetaObject(int type) { + this.type = type; + } + + public int Type { + get { + return type; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaPen.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaPen.cs new file mode 100644 index 0000000..ffcfcc4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaPen.cs @@ -0,0 +1,98 @@ +using System; +using iTextSharp.text; + +/* + * $Id: MetaPen.cs,v 1.3 2008/05/13 11:25:37 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf { + public class MetaPen : MetaObject { + + public const int PS_SOLID = 0; + public const int PS_DASH = 1; + public const int PS_DOT = 2; + public const int PS_DASHDOT = 3; + public const int PS_DASHDOTDOT = 4; + public const int PS_NULL = 5; + public const int PS_INSIDEFRAME = 6; + + int style = PS_SOLID; + int penWidth = 1; + Color color = Color.BLACK; + + public MetaPen() { + type = META_PEN; + } + + public void Init(InputMeta meta) { + style = meta.ReadWord(); + penWidth = meta.ReadShort(); + meta.ReadWord(); + color = meta.ReadColor(); + } + + public int Style { + get { + return style; + } + } + + public int PenWidth { + get { + return penWidth; + } + } + + public Color Color { + get { + return color; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaState.cs b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaState.cs new file mode 100644 index 0000000..9966994 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaState.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections; +using iTextSharp.text; + +/* + * $Id: MetaState.cs,v 1.6 2008/05/13 11:25:37 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.codec.wmf { + public class MetaState { + + public static int TA_NOUPDATECP = 0; + public static int TA_UPDATECP = 1; + public static int TA_LEFT = 0; + public static int TA_RIGHT = 2; + public static int TA_CENTER = 6; + public static int TA_TOP = 0; + public static int TA_BOTTOM = 8; + public static int TA_BASELINE = 24; + + public static int TRANSPARENT = 1; + public static int OPAQUE = 2; + + public static int ALTERNATE = 1; + public static int WINDING = 2; + + public Stack savedStates; + public ArrayList MetaObjects; + public System.Drawing.Point currentPoint; + public MetaPen currentPen; + public MetaBrush currentBrush; + public MetaFont currentFont; + public Color currentBackgroundColor = Color.WHITE; + public Color currentTextColor = Color.BLACK; + public int backgroundMode = OPAQUE; + public int polyFillMode = ALTERNATE; + public int lineJoin = 1; + public int textAlign; + public int offsetWx; + public int offsetWy; + public int extentWx; + public int extentWy; + public float scalingX; + public float scalingY; + + + /** Creates new MetaState */ + public MetaState() { + savedStates = new Stack(); + MetaObjects = new ArrayList(); + currentPoint = new System.Drawing.Point(0, 0); + currentPen = new MetaPen(); + currentBrush = new MetaBrush(); + currentFont = new MetaFont(); + } + + public MetaState(MetaState state) { + metaState = state; + } + + public MetaState metaState { + set { + savedStates = value.savedStates; + MetaObjects = value.MetaObjects; + currentPoint = value.currentPoint; + currentPen = value.currentPen; + currentBrush = value.currentBrush; + currentFont = value.currentFont; + currentBackgroundColor = value.currentBackgroundColor; + currentTextColor = value.currentTextColor; + backgroundMode = value.backgroundMode; + polyFillMode = value.polyFillMode; + textAlign = value.textAlign; + lineJoin = value.lineJoin; + offsetWx = value.offsetWx; + offsetWy = value.offsetWy; + extentWx = value.extentWx; + extentWy = value.extentWy; + scalingX = value.scalingX; + scalingY = value.scalingY; + } + } + + public void AddMetaObject(MetaObject obj) { + for (int k = 0; k < MetaObjects.Count; ++k) { + if (MetaObjects[k] == null) { + MetaObjects[k] = obj; + return; + } + } + MetaObjects.Add(obj); + } + + public void SelectMetaObject(int index, PdfContentByte cb) { + MetaObject obj = (MetaObject)MetaObjects[index]; + if (obj == null) + return; + int style; + switch (obj.Type) { + case MetaObject.META_BRUSH: + currentBrush = (MetaBrush)obj; + style = currentBrush.Style; + if (style == MetaBrush.BS_SOLID) { + Color color = currentBrush.Color; + cb.SetColorFill(color); + } + else if (style == MetaBrush.BS_HATCHED) { + Color color = currentBackgroundColor; + cb.SetColorFill(color); + } + break; + case MetaObject.META_PEN: { + currentPen = (MetaPen)obj; + style = currentPen.Style; + if (style != MetaPen.PS_NULL) { + Color color = currentPen.Color; + cb.SetColorStroke(color); + cb.SetLineWidth(Math.Abs((float)currentPen.PenWidth * scalingX / extentWx)); + switch (style) { + case MetaPen.PS_DASH: + cb.SetLineDash(18, 6, 0); + break; + case MetaPen.PS_DASHDOT: + cb.SetLiteral("[9 6 3 6]0 d\n"); + break; + case MetaPen.PS_DASHDOTDOT: + cb.SetLiteral("[9 3 3 3 3 3]0 d\n"); + break; + case MetaPen.PS_DOT: + cb.SetLineDash(3, 0); + break; + default: + cb.SetLineDash(0); + break; + } + } + break; + } + case MetaObject.META_FONT: { + currentFont = (MetaFont)obj; + break; + } + } + } + + public void DeleteMetaObject(int index) { + MetaObjects[index] = null; + } + + public void SaveState(PdfContentByte cb) { + cb.SaveState(); + MetaState state = new MetaState(this); + savedStates.Push(state); + } + + public void RestoreState(int index, PdfContentByte cb) { + int pops; + if (index < 0) + pops = Math.Min(-index, savedStates.Count); + else + pops = Math.Max(savedStates.Count - index, 0); + if (pops == 0) + return; + MetaState state = null; + while (pops-- != 0) { + cb.RestoreState(); + state = (MetaState)savedStates.Pop(); + } + metaState = state; + } + + public void Cleanup(PdfContentByte cb) { + int k = savedStates.Count; + while (k-- > 0) + cb.RestoreState(); + } + + public float TransformX(int x) { + return ((float)x - offsetWx) * scalingX / extentWx; + } + + public float TransformY(int y) { + return (1f - ((float)y - offsetWy) / extentWy) * scalingY; + } + + public float ScalingX { + set { + this.scalingX = value; + } + } + + public float ScalingY { + set { + this.scalingY = value; + } + } + + public int OffsetWx { + set { + this.offsetWx = value; + } + } + + public int OffsetWy { + set { + this.offsetWy = value; + } + } + + public int ExtentWx { + set { + this.extentWx = value; + } + } + + public int ExtentWy { + set { + this.extentWy = value; + } + } + + public float TransformAngle(float angle) { + float ta = scalingY < 0 ? -angle : angle; + return (float)(scalingX < 0 ? Math.PI - ta : ta); + } + + public System.Drawing.Point CurrentPoint { + get { + return currentPoint; + } + + set { + currentPoint = value; + } + } + + public MetaBrush CurrentBrush { + get { + return currentBrush; + } + } + + public MetaPen CurrentPen { + get { + return currentPen; + } + } + + public MetaFont CurrentFont { + get { + return currentFont; + } + } + + /** Getter for property currentBackgroundColor. + * @return Value of property currentBackgroundColor. + */ + public Color CurrentBackgroundColor { + get { + return currentBackgroundColor; + } + + set { + this.currentBackgroundColor = value; + } + } + + /** Getter for property currentTextColor. + * @return Value of property currentTextColor. + */ + public Color CurrentTextColor { + get { + return currentTextColor; + } + + set { + this.currentTextColor = value; + } + } + + /** Getter for property backgroundMode. + * @return Value of property backgroundMode. + */ + public int BackgroundMode { + get { + return backgroundMode; + } + + set { + this.backgroundMode = value; + } + } + + /** Getter for property textAlign. + * @return Value of property textAlign. + */ + public int TextAlign { + get { + return textAlign; + } + + set { + this.textAlign = value; + } + } + + /** Getter for property polyFillMode. + * @return Value of property polyFillMode. + */ + public int PolyFillMode { + get { + return polyFillMode; + } + + set { + this.polyFillMode = value; + } + } + + public PdfContentByte LineJoinRectangle { + set { + if (lineJoin != 0) { + lineJoin = 0; + value.SetLineJoin(0); + } + } + } + + public PdfContentByte LineJoinPolygon { + set { + if (lineJoin == 0) { + lineJoin = 1; + value.SetLineJoin(1); + } + } + } + + public bool LineNeutral { + get { + return (lineJoin == 0); + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/collection/PdfCollection.cs b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollection.cs new file mode 100644 index 0000000..47c0f1c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollection.cs @@ -0,0 +1,67 @@ +using System; +using iTextSharp.text.pdf; + +namespace iTextSharp.text.pdf.collection { + + public class PdfCollection : PdfDictionary { + + /** A type of PDF Collection */ + public const int DETAILS = 0; + /** A type of PDF Collection */ + public const int TILE = 1; + /** A type of PDF Collection */ + public const int HIDDEN = 2; + + /** + * Constructs a PDF Collection. + * @param type the type of PDF collection. + */ + public PdfCollection(int type) : base(PdfName.COLLECTION) { + switch(type) { + case TILE: + Put(PdfName.VIEW, PdfName.T); + break; + case HIDDEN: + Put(PdfName.VIEW, PdfName.H); + break; + default: + Put(PdfName.VIEW, PdfName.D); + break; + } + } + + /** + * Identifies the document that will be initially presented + * in the user interface. + * @param description the description that was used when attaching the file to the document + */ + public String InitialDocument { + set { + Put(PdfName.D, new PdfString(value, null)); + } + } + + /** + * Sets the Collection schema dictionary. + * @param schema an overview of the collection fields + */ + public PdfCollectionSchema Schema { + set { + Put(PdfName.SCHEMA, value); + } + get { + return (PdfCollectionSchema)Get(PdfName.SCHEMA); + } + } + + /** + * Sets the Collection sort dictionary. + * @param sort a collection sort dictionary + */ + public PdfCollectionSort Sort { + set { + Put(PdfName.SORT, value); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionField.cs b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionField.cs new file mode 100644 index 0000000..871ca60 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionField.cs @@ -0,0 +1,127 @@ +using System; +using iTextSharp.text.pdf; + +namespace iTextSharp.text.pdf.collection { + + /** + * @author blowagie + * + */ + public class PdfCollectionField : PdfDictionary { + /** A possible type of collection field. */ + public const int TEXT = 0; + /** A possible type of collection field. */ + public const int DATE = 1; + /** A possible type of collection field. */ + public new const int NUMBER = 2; + /** A possible type of collection field. */ + public const int FILENAME = 3; + /** A possible type of collection field. */ + public const int DESC = 4; + /** A possible type of collection field. */ + public const int MODDATE = 5; + /** A possible type of collection field. */ + public const int CREATIONDATE = 6; + /** A possible type of collection field. */ + public const int SIZE = 7; + + /** The type of the PDF collection field. */ + protected internal int fieldType; + + /** + * Creates a PdfCollectionField. + * @param name the field name + * @param type the field type + */ + public PdfCollectionField(String name, int type) : base(PdfName.COLLECTIONFIELD) { + Put(PdfName.N, new PdfString(name, PdfObject.TEXT_UNICODE)); + this.fieldType = type; + switch (type) { + default: + Put(PdfName.SUBTYPE, PdfName.S); + break; + case DATE: + Put(PdfName.SUBTYPE, PdfName.D); + break; + case NUMBER: + Put(PdfName.SUBTYPE, PdfName.N); + break; + case FILENAME: + Put(PdfName.SUBTYPE, PdfName.F); + break; + case DESC: + Put(PdfName.SUBTYPE, PdfName.DESC); + break; + case MODDATE: + Put(PdfName.SUBTYPE, PdfName.MODDATE); + break; + case CREATIONDATE: + Put(PdfName.SUBTYPE, PdfName.CREATIONDATE); + break; + case SIZE: + Put(PdfName.SUBTYPE, PdfName.SIZE); + break; + } + } + + /** + * The relative order of the field name. Fields are sorted in ascending order. + * @param i a number indicating the order of the field + */ + public int Order { + set { + Put(PdfName.O, new PdfNumber(value)); + } + } + + /** + * Sets the initial visibility of the field. + * @param visible the default is true (visible) + */ + public bool Visible { + set { + Put(PdfName.V, new PdfBoolean(value)); + } + } + + /** + * Indication if the field value should be editable in the viewer. + * @param editable the default is false (not editable) + */ + public bool Editable { + set { + Put(PdfName.E, new PdfBoolean(value)); + } + } + + /** + * Checks if the type of the field is suitable for a Collection Item. + */ + public bool IsCollectionItem() { + switch (fieldType) { + case TEXT: + case DATE: + case NUMBER: + return true; + default: + return false; + } + } + + /** + * Returns a PdfObject that can be used as the value of a Collection Item. + * @param String value the value that has to be changed into a PdfObject (PdfString, PdfDate or PdfNumber) + */ + public PdfObject GetValue(String v) { + switch (fieldType) { + case TEXT: + return new PdfString(v, PdfObject.TEXT_UNICODE); + case DATE: + return new PdfDate(PdfDate.Decode(v)); + case NUMBER: + return new PdfNumber(v); + } + throw new InvalidOperationException(v + " is not an acceptable value for the field " + Get(PdfName.N).ToString()); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionItem.cs b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionItem.cs new file mode 100644 index 0000000..3501f54 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionItem.cs @@ -0,0 +1,112 @@ +using System; +using iTextSharp.text.pdf; + +namespace iTextSharp.text.pdf.collection { + + public class PdfCollectionItem : PdfDictionary { + + /** The PdfCollectionSchema with the names and types of the items. */ + internal PdfCollectionSchema schema; + + /** + * Constructs a Collection Item that can be added to a PdfFileSpecification. + */ + public PdfCollectionItem(PdfCollectionSchema schema) : base(PdfName.COLLECTIONITEM) { + this.schema = schema; + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, String value) { + PdfName fieldname = new PdfName(key); + PdfCollectionField field = (PdfCollectionField)schema.Get(fieldname); + Put(fieldname, field.GetValue(value)); + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, PdfString value) { + PdfName fieldname = new PdfName(key); + PdfCollectionField field = (PdfCollectionField)schema.Get(fieldname); + if (field.fieldType == PdfCollectionField.TEXT) { + Put(fieldname, value); + } + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, PdfDate d) { + PdfName fieldname = new PdfName(key); + PdfCollectionField field = (PdfCollectionField)schema.Get(fieldname); + if (field.fieldType == PdfCollectionField.DATE) { + Put(fieldname, d); + } + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, PdfNumber n) { + PdfName fieldname = new PdfName(key); + PdfCollectionField field = (PdfCollectionField)schema.Get(fieldname); + if (field.fieldType == PdfCollectionField.NUMBER) { + Put(fieldname, n); + } + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, DateTime c) { + AddItem(key, new PdfDate(c)); + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, int i) { + AddItem(key, new PdfNumber(i)); + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, float f) { + AddItem(key, new PdfNumber(f)); + } + + /** + * Sets the value of the collection item. + * @param value + */ + public void AddItem(String key, double d) { + AddItem(key, new PdfNumber(d)); + } + + /** + * Adds a prefix for the Collection item. + * You can only use this method after you have set the value of the item. + * @param prefix a prefix + */ + public void SetPrefix(String key, String prefix) { + PdfName fieldname = new PdfName(key); + PdfObject o = Get(fieldname); + if (o == null) + throw new InvalidOperationException("You must set a value before adding a prefix."); + PdfDictionary dict = new PdfDictionary(PdfName.COLLECTIONSUBITEM); + dict.Put(PdfName.D, o); + dict.Put(PdfName.P, new PdfString(prefix, PdfObject.TEXT_UNICODE)); + Put(fieldname, dict); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSchema.cs b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSchema.cs new file mode 100644 index 0000000..c229d5d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSchema.cs @@ -0,0 +1,22 @@ +using System; +using iTextSharp.text.pdf; + +namespace iTextSharp.text.pdf.collection { + + public class PdfCollectionSchema : PdfDictionary { + /** + * Creates a Collection Schema dictionary. + */ + public PdfCollectionSchema() : base(PdfName.COLLECTIONSCHEMA) { + } + + /** + * Adds a Collection field to the Schema. + * @param name the name of the collection field + * @param field a Collection Field + */ + public void AddField(String name, PdfCollectionField field) { + Put(new PdfName(name), field); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSort.cs b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSort.cs new file mode 100644 index 0000000..b7f6bde --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSort.cs @@ -0,0 +1,63 @@ +using System; +using iTextSharp.text.pdf; + +namespace iTextSharp.text.pdf.collection { + + public class PdfCollectionSort : PdfDictionary { + + /** + * Constructs a PDF Collection Sort Dictionary. + * @param key the key of the field that will be used to sort entries + */ + public PdfCollectionSort(String key) : base(PdfName.COLLECTIONSORT) { + Put(PdfName.S, new PdfName(key)); + } + + /** + * Constructs a PDF Collection Sort Dictionary. + * @param keys the keys of the fields that will be used to sort entries + */ + public PdfCollectionSort(String[] keys) : base(PdfName.COLLECTIONSORT) { + PdfArray array = new PdfArray(); + for (int i = 0; i < keys.Length; i++) { + array.Add(new PdfName(keys[i])); + } + Put(PdfName.S, array); + } + + /** + * Defines the sort order of the field (ascending or descending). + * @param ascending true is the default, use false for descending order + */ + public void SetSortOrder(bool ascending) { + PdfObject o = (PdfObject)Get(PdfName.S); + if (o is PdfName) { + Put(PdfName.A, new PdfBoolean(ascending)); + } + else { + throw new InvalidOperationException("You have to define a bool array for this collection sort dictionary."); + } + } + + /** + * Defines the sort order of the field (ascending or descending). + * @param ascending an array with every element corresponding with a name of a field. + */ + public void SetSortOrder(bool[] ascending) { + PdfObject o = (PdfObject)Get(PdfName.S); + if (o is PdfArray) { + if (((PdfArray)o).Size != ascending.Length) { + throw new InvalidOperationException("The number of booleans in this array doesn't correspond with the number of fields."); + } + PdfArray array = new PdfArray(); + for (int i = 0; i < ascending.Length; i++) { + array.Add(new PdfBoolean(ascending[i])); + } + Put(PdfName.A, array); + } + else { + throw new InvalidOperationException("You need a single bool for this collection sort dictionary."); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/collection/PdfTargetDictionary.cs b/iTechSharp/iTextSharp/text/pdf/collection/PdfTargetDictionary.cs new file mode 100644 index 0000000..85d33fd --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/collection/PdfTargetDictionary.cs @@ -0,0 +1,101 @@ +using System; +using iTextSharp.text.pdf; + +namespace iTextSharp.text.pdf.collection { + + public class PdfTargetDictionary : PdfDictionary { + + /** + * Creates dictionary referring to a target document that is the parent of the current document. + * @param nested null if this is the actual target, another target if this is only an intermediate target. + */ + public PdfTargetDictionary(PdfTargetDictionary nested) : base() { + Put(PdfName.R, PdfName.P); + if (nested != null) + AdditionalPath = nested; + } + + /** + * Creates a dictionary referring to a target document. + * @param child if false, this refers to the parent document; if true, this refers to a child document, and you'll have to specify where to find the child using the other methods of this class + */ + public PdfTargetDictionary(bool child) : base() { + if (child) { + Put(PdfName.R, PdfName.C); + } + else { + Put(PdfName.R, PdfName.P); + } + } + + /** + * If this dictionary refers to a child that is a document level attachment, + * you need to specify the name that was used to attach the document. + * @param name the name in the EmbeddedFiles name tree + */ + public String EmbeddedFileName { + set { + Put(PdfName.N, new PdfString(value, null)); + } + } + + /** + * If this dictionary refers to a child that is a file attachment added to a page, + * you need to specify the name of the page (or use setFileAttachmentPage to specify the page number). + * Once you have specified the page, you still need to specify the attachment using another method. + * @param name the named destination referring to the page with the file attachment. + */ + public String FileAttachmentPagename { + set { + Put(PdfName.P, new PdfString(value, null)); + } + } + + /** + * If this dictionary refers to a child that is a file attachment added to a page, + * you need to specify the page number (or use setFileAttachmentPagename to specify a named destination). + * Once you have specified the page, you still need to specify the attachment using another method. + * @param page the page number of the page with the file attachment. + */ + public int FileAttachmentPage { + set { + Put(PdfName.P, new PdfNumber(value)); + } + } + + /** + * If this dictionary refers to a child that is a file attachment added to a page, + * you need to specify the page with setFileAttachmentPage or setFileAttachmentPageName, + * and then specify the name of the attachment added to this page (or use setFileAttachmentIndex). + * @param name the name of the attachment + */ + public String FileAttachmentName { + set { + Put(PdfName.A, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** + * If this dictionary refers to a child that is a file attachment added to a page, + * you need to specify the page with setFileAttachmentPage or setFileAttachmentPageName, + * and then specify the index of the attachment added to this page (or use setFileAttachmentName). + * @param name the name of the attachment + */ + public int FileAttachmentIndex { + set { + Put(PdfName.A, new PdfNumber(value)); + } + } + + /** + * If this dictionary refers to an intermediate target, you can + * add the next target in the sequence. + * @param nested the next target in the sequence + */ + public PdfTargetDictionary AdditionalPath { + set { + Put(PdfName.T, value); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/crypto/AESCipher.cs b/iTechSharp/iTextSharp/text/pdf/crypto/AESCipher.cs new file mode 100644 index 0000000..f4a7b7a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/crypto/AESCipher.cs @@ -0,0 +1,105 @@ +using System; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +/* + * $Id: AESCipher.cs,v 1.4 2007/03/06 12:29:31 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf.crypto { + +/** + * Creates an AES Cipher with CBC and padding PKCS5/7. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class AESCipher { + private PaddedBufferedBlockCipher bp; + + /** Creates a new instance of AESCipher */ + public AESCipher(bool forEncryption, byte[] key, byte[] iv) { + IBlockCipher aes = new AesFastEngine(); + IBlockCipher cbc = new CbcBlockCipher(aes); + bp = new PaddedBufferedBlockCipher(cbc); + KeyParameter kp = new KeyParameter(key); + ParametersWithIV piv = new ParametersWithIV(kp, iv); + bp.Init(forEncryption, piv); + } + + public byte[] Update(byte[] inp, int inpOff, int inpLen) { + int neededLen = bp.GetUpdateOutputSize(inpLen); + byte[] outp = null; + if (neededLen > 0) + outp = new byte[neededLen]; + else + neededLen = 0; + bp.ProcessBytes(inp, inpOff, inpLen, outp, 0); + return outp; + } + + public byte[] DoFinal() { + int neededLen = bp.GetOutputSize(0); + byte[] outp = new byte[neededLen]; + int n = 0; + try { + n = bp.DoFinal(outp, 0); + } + catch { + return outp; + } + if (n != outp.Length) { + byte[] outp2 = new byte[n]; + System.Array.Copy(outp, 0, outp2, 0, n); + return outp2; + } + else + return outp; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/crypto/ARCFOUREncryption.cs b/iTechSharp/iTextSharp/text/pdf/crypto/ARCFOUREncryption.cs new file mode 100644 index 0000000..740762e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/crypto/ARCFOUREncryption.cs @@ -0,0 +1,108 @@ +using System; +/* + * $Id: ARCFOUREncryption.cs,v 1.1 2007/04/19 16:41:32 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf.crypto { + + public class ARCFOUREncryption { + + private byte[] state = new byte[256]; + private int x; + private int y; + + /** Creates a new instance of ARCFOUREncryption */ + public ARCFOUREncryption() { + } + + public void PrepareARCFOURKey(byte[] key) { + PrepareARCFOURKey(key, 0, key.Length); + } + + public void PrepareARCFOURKey(byte[] key, int off, int len) { + int index1 = 0; + int index2 = 0; + for (int k = 0; k < 256; ++k) + state[k] = (byte)k; + x = 0; + y = 0; + byte tmp; + for (int k = 0; k < 256; ++k) { + index2 = (key[index1 + off] + state[k] + index2) & 255; + tmp = state[k]; + state[k] = state[index2]; + state[index2] = tmp; + index1 = (index1 + 1) % len; + } + } + + public void EncryptARCFOUR(byte[] dataIn, int off, int len, byte[] dataOut, int offOut) { + int length = len + off; + byte tmp; + for (int k = off; k < length; ++k) { + x = (x + 1) & 255; + y = (state[x] + y) & 255; + tmp = state[x]; + state[x] = state[y]; + state[y] = tmp; + dataOut[k - off + offOut] = (byte)(dataIn[k] ^ state[(state[x] + state[y]) & 255]); + } + } + + public void EncryptARCFOUR(byte[] data, int off, int len) { + EncryptARCFOUR(data, off, len, data, off); + } + + public void EncryptARCFOUR(byte[] dataIn, byte[] dataOut) { + EncryptARCFOUR(dataIn, 0, dataIn.Length, dataOut, 0); + } + + public void EncryptARCFOUR(byte[] data) { + EncryptARCFOUR(data, 0, data.Length, data, 0); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/crypto/IVGenerator.cs b/iTechSharp/iTextSharp/text/pdf/crypto/IVGenerator.cs new file mode 100644 index 0000000..a403ac7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/crypto/IVGenerator.cs @@ -0,0 +1,97 @@ +using System; + +/* + * $Id: IVGenerator.cs,v 1.5 2008/04/17 15:37:19 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf.crypto { + +/** + * An initialization vector generator for a CBC block encryption. It's a random generator based on RC4. + * @author Paulo Soares (psoares@consiste.pt) + */ + public sealed class IVGenerator { + + private static ARCFOUREncryption rc4; + + static IVGenerator(){ + rc4 = new ARCFOUREncryption(); + byte[] longBytes = new byte[8]; + long val = DateTime.Now.Ticks; + for (int i = 0; i != 8; i++) { + longBytes[i] = (byte)val; + val = (long)((ulong)val >> 8); + } + rc4.PrepareARCFOURKey(longBytes); + } + + /** Creates a new instance of IVGenerator */ + private IVGenerator() { + } + + /** + * Gets a 16 byte random initialization vector. + * @return a 16 byte random initialization vector + */ + public static byte[] GetIV() { + return GetIV(16); + } + + /** + * Gets a random initialization vector. + * @param len the length of the initialization vector + * @return a random initialization vector + */ + public static byte[] GetIV(int len) { + byte[] b = new byte[len]; + lock (rc4) { + rc4.EncryptARCFOUR(b); + } + return b; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/draw/DottedLineSeparator.cs b/iTechSharp/iTextSharp/text/pdf/draw/DottedLineSeparator.cs new file mode 100644 index 0000000..d14fedb --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/draw/DottedLineSeparator.cs @@ -0,0 +1,91 @@ +using System; +using iTextSharp.text.pdf; +/* + * + * $Id: DottedLineSeparator.cs,v 1.2 2008/05/13 11:25:38 psoares33 Exp $ + * + * Copyright 2008 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.draw { + + /** + * Element that draws a dotted line from left to right. + * Can be added directly to a document or column. + * Can also be used to create a separator chunk. + * @since 2.1.2 + */ + public class DottedLineSeparator : LineSeparator { + + /** the gap between the dots. */ + protected float gap = 5; + + /** + * @see com.lowagie.text.pdf.draw.DrawInterface#draw(com.lowagie.text.pdf.PdfContentByte, float, float, float, float, float) + */ + public override void Draw(PdfContentByte canvas, float llx, float lly, float urx, float ury, float y) { + canvas.SaveState(); + canvas.SetLineWidth(lineWidth); + canvas.SetLineCap(PdfContentByte.LINE_CAP_ROUND); + canvas.SetLineDash(0, gap, gap / 2); + DrawLine(canvas, llx, urx, y); + canvas.RestoreState(); + } + + /** + * Setter for the gap between the center of the dots of the dotted line. + * @param gap the gap between the center of the dots + */ + public float Gap { + get { + return gap; + } + set { + gap = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/draw/IDrawInterface.cs b/iTechSharp/iTextSharp/text/pdf/draw/IDrawInterface.cs new file mode 100644 index 0000000..f35b527 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/draw/IDrawInterface.cs @@ -0,0 +1,74 @@ +using System; +using iTextSharp.text.pdf; + +/* + * + * $Id: IDrawInterface.cs,v 1.2 2008/05/13 11:25:38 psoares33 Exp $ + * + * Copyright 2008 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.draw { + /** + * Interface for an Element that allows you to draw something at the current + * vertical position. Trivial implementations are LineSeparator and VerticalPositionMark. + * It is also used to define what has to be drawn by a separator chunk. + * @since 2.1.2 + */ + public interface IDrawInterface { + /** + * Implement this method if you want to draw something at the current Y position + * (for instance a line). + * @param canvas the canvas on which you can draw + * @param llx the x coordinate of the left page margin + * @param lly the y coordinate of the bottom page margin + * @param urx the x coordinate of the right page margin + * @param ury the y coordinate of the top page margin + * @param y the current y position on the page + */ + void Draw(PdfContentByte canvas, float llx, float lly, float urx, float ury, float y); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/draw/LineSeparator.cs b/iTechSharp/iTextSharp/text/pdf/draw/LineSeparator.cs new file mode 100644 index 0000000..b5706cc --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/draw/LineSeparator.cs @@ -0,0 +1,192 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * + * $Id: LineSeparator.cs,v 1.2 2008/05/13 11:25:38 psoares33 Exp $ + * + * Copyright 2008 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.draw { + + /** + * Element that draws a solid line from left to right. + * Can be added directly to a document or column. + * Can also be used to create a separator chunk. + * @author Paulo Soares + * @since 2.1.2 + */ + public class LineSeparator : VerticalPositionMark { + + /** The thickness of the line. */ + protected float lineWidth = 1; + /** The width of the line as a percentage of the available page width. */ + protected float percentage = 100; + /** The color of the line. */ + protected Color lineColor; + /** The alignment of the line. */ + protected int alignment = Element.ALIGN_CENTER; + + /** + * Creates a new instance of the LineSeparator class. + * @param lineWidth the thickness of the line + * @param percentage the width of the line as a percentage of the available page width + * @param color the color of the line + * @param align the alignment + * @param offset the offset of the line relative to the current baseline (negative = under the baseline) + */ + public LineSeparator(float lineWidth, float percentage, Color lineColor, int align, float offset) { + this.lineWidth = lineWidth; + this.percentage = percentage; + this.lineColor = lineColor; + this.alignment = align; + this.offset = offset; + } + + /** + * Creates a new instance of the LineSeparator class with + * default values: lineWidth 1 user unit, width 100%, centered with offset 0. + */ + public LineSeparator() { + } + + /** + * @see com.lowagie.text.pdf.draw.DrawInterface#draw(com.lowagie.text.pdf.PdfContentByte, float, float, float, float, float) + */ + public override void Draw(PdfContentByte canvas, float llx, float lly, float urx, float ury, float y) { + canvas.SaveState(); + DrawLine(canvas, llx, urx, y); + canvas.RestoreState(); + } + + /** + * Draws a horizontal line. + * @param canvas the canvas to draw on + * @param leftX the left x coordinate + * @param rightX the right x coordindate + * @param y the y coordinate + */ + public void DrawLine(PdfContentByte canvas, float leftX, float rightX, float y) { + float w; + if (Percentage < 0) + w = -Percentage; + else + w = (rightX - leftX) * Percentage / 100.0f; + float s; + switch (Alignment) { + case Element.ALIGN_LEFT: + s = 0; + break; + case Element.ALIGN_RIGHT: + s = rightX - leftX - w; + break; + default: + s = (rightX - leftX - w) / 2; + break; + } + canvas.SetLineWidth(LineWidth); + if (LineColor != null) + canvas.SetColorStroke(LineColor); + canvas.MoveTo(s + leftX, y + offset); + canvas.LineTo(s + w + leftX, y + offset); + canvas.Stroke(); + } + + /** + * Setter for the line width. + * @param lineWidth the thickness of the line that will be drawn. + */ + public float LineWidth { + get { + return lineWidth; + } + set { + lineWidth = value; + } + } + + /** + * Setter for the width as a percentage of the available width. + * @return a width percentage + */ + public float Percentage { + get { + return percentage; + } + set { + percentage = value; + } + } + + /** + * Setter for the color of the line that will be drawn. + * @param color a color + */ + + public Color LineColor { + get { + return lineColor; + } + set { + lineColor = value; + } + } + + /** + * Setter for the alignment of the line. + * @param align an alignment value + */ + public int Alignment { + get { + return alignment; + } + set { + alignment = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/draw/VerticalPositionMark.cs b/iTechSharp/iTextSharp/text/pdf/draw/VerticalPositionMark.cs new file mode 100644 index 0000000..3675c60 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/draw/VerticalPositionMark.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; + +/* + * + * $Id: VerticalPositionMark.cs,v 1.2 2008/05/13 11:25:38 psoares33 Exp $ + * + * Copyright 2008 by Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.draw { + + /** + * Helper class implementing the DrawInterface. Can be used to add + * horizontal or vertical separators. Won't draw anything unless + * you implement the draw method. + * @since 2.1.2 + */ + + public class VerticalPositionMark : IDrawInterface, IElement { + + /** Another implementation of the DrawInterface; its draw method will overrule LineSeparator.Draw(). */ + protected IDrawInterface drawInterface = null; + + /** The offset for the line. */ + protected float offset = 0; + + /** + * Creates a vertical position mark that won't draw anything unless + * you define a DrawInterface. + */ + public VerticalPositionMark() { + } + + /** + * Creates a vertical position mark that won't draw anything unless + * you define a DrawInterface. + * @param drawInterface the drawInterface for this vertical position mark. + * @param offset the offset for this vertical position mark. + */ + public VerticalPositionMark(IDrawInterface drawInterface, float offset) { + this.drawInterface = drawInterface; + this.offset = offset; + } + + /** + * @see com.lowagie.text.pdf.draw.DrawInterface#draw(com.lowagie.text.pdf.PdfContentByte, float, float, float, float, float) + */ + public virtual void Draw(PdfContentByte canvas, float llx, float lly, float urx, float ury, float y) { + if (drawInterface != null) { + drawInterface.Draw(canvas, llx, lly, urx, ury, y + offset); + } + } + + /** + * @see com.lowagie.text.Element#process(com.lowagie.text.ElementListener) + */ + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } catch (DocumentException) { + return false; + } + } + + /** + * @see com.lowagie.text.Element#type() + */ + public int Type { + get { + return Element.YMARK; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + */ + public bool IsNestable() { + return false; + } + + /** + * @see com.lowagie.text.Element#getChunks() + */ + public ArrayList Chunks { + get { + ArrayList list = new ArrayList(); + list.Add(new Chunk(this, true)); + return list; + } + } + + /** + * Setter for the interface with the overruling Draw() method. + * @param drawInterface a DrawInterface implementation + */ + public virtual IDrawInterface DrawInterface { + set { + drawInterface = value; + } + get { + return drawInterface; + } + } + + /** + * Setter for the offset. The offset is relative to the current + * Y position. If you want to underline something, you have to + * choose a negative offset. + * @param offset an offset + */ + public virtual float Offset { + set { + offset = value; + } + get { + return offset; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/events/FieldPositioningEvents.cs b/iTechSharp/iTextSharp/text/pdf/events/FieldPositioningEvents.cs new file mode 100644 index 0000000..f127587 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/events/FieldPositioningEvents.cs @@ -0,0 +1,183 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; + +/* + * Copyright 2005 by Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf.events { + + /** + * Class for an index. + * + * @author Michael Niedermair + */ + public class FieldPositioningEvents : PdfPageEventHelper, IPdfPCellEvent { + + /** + * Keeps a map with fields that are to be positioned in inGenericTag. + */ + protected Hashtable genericChunkFields = new Hashtable(); + + /** + * Keeps the form field that is to be positioned in a cellLayout event. + */ + protected PdfFormField cellField = null; + + /** + * The PdfWriter to use when a field has to added in a cell event. + */ + protected PdfWriter fieldWriter = null; + /** + * The PdfFormField that is the parent of the field added in a cell event. + */ + protected PdfFormField parent = null; + + /** Creates a new event. This constructor will be used if you need to position fields with Chunk objects. */ + public FieldPositioningEvents() {} + + /** Some extra padding that will be taken into account when defining the widget. */ + public float padding; + + /** + * Add a PdfFormField that has to be tied to a generic Chunk. + */ + public void AddField(String text, PdfFormField field) { + genericChunkFields[text] = field; + } + + /** Creates a new event. This constructor will be used if you need to position fields with a Cell Event. */ + public FieldPositioningEvents(PdfWriter writer, PdfFormField field) { + this.cellField = field; + this.fieldWriter = writer; + } + + /** Creates a new event. This constructor will be used if you need to position fields with a Cell Event. */ + public FieldPositioningEvents(PdfFormField parent, PdfFormField field) { + this.cellField = field; + this.parent = parent; + } + + /** Creates a new event. This constructor will be used if you need to position fields with a Cell Event. + * @throws DocumentException + * @throws IOException*/ + public FieldPositioningEvents(PdfWriter writer, String text) { + this.fieldWriter = writer; + TextField tf = new TextField(writer, new Rectangle(0, 0), text); + tf.FontSize = 14; + cellField = tf.GetTextField(); + } + + /** Creates a new event. This constructor will be used if you need to position fields with a Cell Event. + * @throws DocumentException + * @throws IOException*/ + public FieldPositioningEvents(PdfWriter writer, PdfFormField parent, String text) { + this.parent = parent; + TextField tf = new TextField(writer, new Rectangle(0, 0), text); + tf.FontSize = 14; + cellField = tf.GetTextField(); + } + + /** + * @param padding The padding to set. + */ + public float Padding { + set { + padding = value; + } + get { + return padding; + } + } + + /** + * @param parent The parent to set. + */ + public PdfFormField Parent { + set { + parent = value; + } + get { + return parent; + } + } + + /** + * @see com.lowagie.text.pdf.PdfPageEvent#onGenericTag(com.lowagie.text.pdf.PdfWriter, com.lowagie.text.Document, com.lowagie.text.Rectangle, java.lang.String) + */ + public override void OnGenericTag(PdfWriter writer, Document document, + Rectangle rect, String text) { + rect.Bottom = rect.Bottom - 3; + PdfFormField field = (PdfFormField) genericChunkFields[text]; + if (field == null) { + TextField tf = new TextField(writer, new Rectangle(rect.GetLeft(padding), rect.GetBottom(padding), rect.GetRight(padding), rect.GetTop(padding)), text); + tf.FontSize = 14; + field = tf.GetTextField(); + } + else { + field.Put(PdfName.RECT, new PdfRectangle(rect.GetLeft(padding), rect.GetBottom(padding), rect.GetRight(padding), rect.GetTop(padding))); + } + if (parent == null) + writer.AddAnnotation(field); + else + parent.AddKid(field); + } + + /** + * @see com.lowagie.text.pdf.PdfPCellEvent#cellLayout(com.lowagie.text.pdf.PdfPCell, com.lowagie.text.Rectangle, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void CellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvases) { + if (cellField == null || (fieldWriter == null && parent == null)) throw new ArgumentException("You have used the wrong constructor for this FieldPositioningEvents class."); + cellField.Put(PdfName.RECT, new PdfRectangle(rect.GetLeft(padding), rect.GetBottom(padding), rect.GetRight(padding), rect.GetTop(padding))); + if (parent == null) + fieldWriter.AddAnnotation(cellField); + else + parent.AddKid(cellField); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/events/IndexEvents.cs b/iTechSharp/iTextSharp/text/pdf/events/IndexEvents.cs new file mode 100644 index 0000000..e8a693c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/events/IndexEvents.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text; + +/* + * Copyright 2005 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf.events { + + /** + * Class for an index. + * + * @author Michael Niedermair + */ + public class IndexEvents : PdfPageEventHelper { + + /** + * keeps the indextag with the pagenumber + */ + private Hashtable indextag = new Hashtable(); + + /** + * All the text that is passed to this event, gets registered in the indexentry. + * + * @see com.lowagie.text.pdf.PdfPageEventHelper#onGenericTag( + * com.lowagie.text.pdf.PdfWriter, com.lowagie.text.Document, + * com.lowagie.text.Rectangle, java.lang.String) + */ + public override void OnGenericTag(PdfWriter writer, Document document, + Rectangle rect, String text) { + indextag[text] = writer.PageNumber; + } + + // -------------------------------------------------------------------- + /** + * indexcounter + */ + private long indexcounter = 0; + + /** + * the list for the index entry + */ + private ArrayList indexentry = new ArrayList(); + + /** + * Create an index entry. + * + * @param text The text for the Chunk. + * @param in1 The first level. + * @param in2 The second level. + * @param in3 The third level. + * @return Returns the Chunk. + */ + public Chunk Create(String text, String in1, String in2, + String in3) { + + Chunk chunk = new Chunk(text); + String tag = "idx_" + (indexcounter++); + chunk.SetGenericTag(tag); + chunk.SetLocalDestination(tag); + Entry entry = new Entry(in1, in2, in3, tag, this); + indexentry.Add(entry); + return chunk; + } + + /** + * Create an index entry. + * + * @param text The text for the Chunk. + * @param in1 The first level. + * @return Returns the Chunk. + */ + public Chunk Create(String text, String in1) { + return Create(text, in1, "", ""); + } + + /** + * Create an index entry. + * + * @param text The text for the Chunk. + * @param in1 The first level. + * @param in2 The second level. + * @return Returns the Chunk. + */ + public Chunk Create(String text, String in1, String in2) { + return Create(text, in1, in2, ""); + } + + /** + * Create an index entry. + * + * @param text The text. + * @param in1 The first level. + * @param in2 The second level. + * @param in3 The third level. + */ + public void Create(Chunk text, String in1, String in2, + String in3) { + + String tag = "idx_" + (indexcounter++); + text.SetGenericTag(tag); + text.SetLocalDestination(tag); + Entry entry = new Entry(in1, in2, in3, tag, this); + indexentry.Add(entry); + } + + /** + * Create an index entry. + * + * @param text The text. + * @param in1 The first level. + */ + public void Create(Chunk text, String in1) { + Create(text, in1, "", ""); + } + + /** + * Create an index entry. + * + * @param text The text. + * @param in1 The first level. + * @param in2 The second level. + */ + public void Create(Chunk text, String in1, String in2) { + Create(text, in1, in2, ""); + } + + private class ISortIndex : IComparer { + + public int Compare(object arg0, object arg1) { + Entry en1 = (Entry) arg0; + Entry en2 = (Entry) arg1; + + int rt = 0; + if (en1.GetIn1() != null && en2.GetIn1() != null) { + if ((rt = Util.CompareToIgnoreCase(en1.GetIn1(),en2.GetIn1())) == 0) { + // in1 equals + if (en1.GetIn2() != null && en2.GetIn2() != null) { + if ((rt = Util.CompareToIgnoreCase(en1.GetIn2(), en2.GetIn2())) == 0) { + // in2 equals + if (en1.GetIn3() != null && en2.GetIn3() != null) { + rt = Util.CompareToIgnoreCase(en1.GetIn3(), en2.GetIn3()); + } + } + } + } + } + return rt; + } + } + + /** + * Comparator for sorting the index + */ + private IComparer comparator = new ISortIndex(); + + /** + * Set the comparator. + * @param aComparator The comparator to set. + */ + public void SetComparator(IComparer aComparator) { + comparator = aComparator; + } + + /** + * Returns the sorted list with the entries and the collected page numbers. + * @return Returns the sorted list with the entries and teh collected page numbers. + */ + public ArrayList GetSortedEntries() { + + Hashtable grouped = new Hashtable(); + + for (int i = 0; i < indexentry.Count; i++) { + Entry e = (Entry) indexentry[i]; + String key = e.GetKey(); + + Entry master = (Entry) grouped[key]; + if (master != null) { + master.AddPageNumberAndTag(e.GetPageNumber(), e.GetTag()); + } else { + e.AddPageNumberAndTag(e.GetPageNumber(), e.GetTag()); + grouped[key] = e; + } + } + + // copy to a list and sort it + ArrayList sorted = new ArrayList(grouped.Values); + sorted.Sort(0, sorted.Count, comparator); + return sorted; + } + + // -------------------------------------------------------------------- + /** + * Class for an index entry. + *

    + * In the first step, only in1, in2,in3 and tag are used. + * After the collections of the index entries, pagenumbers are used. + *

    + */ + public class Entry { + + /** + * first level + */ + private String in1; + + /** + * second level + */ + private String in2; + + /** + * third level + */ + private String in3; + + /** + * the tag + */ + private String tag; + + /** + * the lsit of all page numbers. + */ + private ArrayList pagenumbers = new ArrayList(); + + /** + * the lsit of all tags. + */ + private ArrayList tags = new ArrayList(); + private IndexEvents parent; + + /** + * Create a new object. + * @param aIn1 The first level. + * @param aIn2 The second level. + * @param aIn3 The third level. + * @param aTag The tag. + */ + public Entry(String aIn1, String aIn2, String aIn3, + String aTag, IndexEvents parent) { + in1 = aIn1; + in2 = aIn2; + in3 = aIn3; + tag = aTag; + this.parent = parent; + } + + /** + * Returns the in1. + * @return Returns the in1. + */ + public String GetIn1() { + return in1; + } + + /** + * Returns the in2. + * @return Returns the in2. + */ + public String GetIn2() { + return in2; + } + + /** + * Returns the in3. + * @return Returns the in3. + */ + public String GetIn3() { + return in3; + } + + /** + * Returns the tag. + * @return Returns the tag. + */ + public String GetTag() { + return tag; + } + + /** + * Returns the pagenumer for this entry. + * @return Returns the pagenumer for this entry. + */ + public int GetPageNumber() { + int rt = -1; + object i = parent.indextag[tag]; + if (i != null) { + rt = (int)i; + } + return rt; + } + + /** + * Add a pagenumber. + * @param number The page number. + * @param tag + */ + public void AddPageNumberAndTag(int number, String tag) { + pagenumbers.Add(number); + tags.Add(tag); + } + + /** + * Returns the key for the map-entry. + * @return Returns the key for the map-entry. + */ + public String GetKey() { + return in1 + "!" + in2 + "!" + in3; + } + + /** + * Returns the pagenumbers. + * @return Returns the pagenumbers. + */ + public ArrayList GetPagenumbers() { + return pagenumbers; + } + + /** + * Returns the tags. + * @return Returns the tags. + */ + public ArrayList GetTags() { + return tags; + } + + /** + * print the entry (only for test) + * @return the toString implementation of the entry + */ + public override String ToString() { + StringBuilder buf = new StringBuilder(); + buf.Append(in1).Append(' '); + buf.Append(in2).Append(' '); + buf.Append(in3).Append(' '); + for (int i = 0; i < pagenumbers.Count; i++) { + buf.Append(pagenumbers[i]).Append(' '); + } + return buf.ToString(); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/events/PdfPCellEventForwarder.cs b/iTechSharp/iTextSharp/text/pdf/events/PdfPCellEventForwarder.cs new file mode 100644 index 0000000..d019e31 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/events/PdfPCellEventForwarder.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * $Id: PdfPCellEventForwarder.cs,v 1.2 2008/05/13 11:25:40 psoares33 Exp $ + * + * + * Copyright 2005 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.events { + + /** + * If you want to add more than one event to a cell, + * you have to construct a PdfPCellEventForwarder, add the + * different events to this object and add the forwarder to + * the PdfPCell. + */ + + public class PdfPCellEventForwarder : IPdfPCellEvent { + + /** ArrayList containing all the PageEvents that have to be executed. */ + protected ArrayList events = new ArrayList(); + + /** + * Add a page event to the forwarder. + * @param event an event that has to be added to the forwarder. + */ + public void AddCellEvent(IPdfPCellEvent eventa) { + events.Add(eventa); + } + + /** + * @see com.lowagie.text.pdf.PdfPCellEvent#cellLayout(com.lowagie.text.pdf.PdfPCell, com.lowagie.text.Rectangle, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) { + foreach (IPdfPCellEvent eventa in events) { + eventa.CellLayout(cell, position, canvases); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/events/PdfPTableEventForwarder.cs b/iTechSharp/iTextSharp/text/pdf/events/PdfPTableEventForwarder.cs new file mode 100644 index 0000000..f598df8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/events/PdfPTableEventForwarder.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; +/* + * $Id: PdfPTableEventForwarder.cs,v 1.2 2008/05/13 11:25:40 psoares33 Exp $ + * + * + * Copyright 2005 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.events { + + /** + * If you want to add more than one page event to a PdfPTable, + * you have to construct a PdfPTableEventForwarder, add the + * different events to this object and add the forwarder to + * the PdfWriter. + */ + + public class PdfPTableEventForwarder : IPdfPTableEvent { + + /** ArrayList containing all the PageEvents that have to be executed. */ + protected ArrayList events = new ArrayList(); + + /** + * Add a page event to the forwarder. + * @param event an event that has to be added to the forwarder. + */ + public void AddTableEvent(IPdfPTableEvent eventa) { + events.Add(eventa); + } + + /** + * @see com.lowagie.text.pdf.PdfPTableEvent#tableLayout(com.lowagie.text.pdf.PdfPTable, float[][], float[], int, int, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void TableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases) { + foreach (IPdfPTableEvent eventa in events) { + eventa.TableLayout(table, widths, heights, headerRows, rowStart, canvases); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/events/PdfPageEventForwarder.cs b/iTechSharp/iTextSharp/text/pdf/events/PdfPageEventForwarder.cs new file mode 100644 index 0000000..c7b101d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/events/PdfPageEventForwarder.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * $Id: PdfPageEventForwarder.cs,v 1.2 2008/05/13 11:25:40 psoares33 Exp $ + * + * + * Copyright 2005 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.events { + + /** + * If you want to add more than one page eventa to a PdfWriter, + * you have to construct a PdfPageEventForwarder, add the + * different events to this object and add the forwarder to + * the PdfWriter. + */ + + public class PdfPageEventForwarder : IPdfPageEvent { + + /** ArrayList containing all the PageEvents that have to be executed. */ + protected ArrayList events = new ArrayList(); + + /** + * Add a page eventa to the forwarder. + * @param eventa an eventa that has to be added to the forwarder. + */ + public void AddPageEvent(IPdfPageEvent eventa) { + events.Add(eventa); + } + + /** + * Called when the document is opened. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + */ + public virtual void OnOpenDocument(PdfWriter writer, Document document) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnOpenDocument(writer, document); + } + } + + /** + * Called when a page is initialized. + *

    + * Note that if even if a page is not written this method is still called. + * It is preferable to use onEndPage to avoid infinite loops. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + */ + public virtual void OnStartPage(PdfWriter writer, Document document) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnStartPage(writer, document); + } + } + + /** + * Called when a page is finished, just before being written to the + * document. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + */ + public virtual void OnEndPage(PdfWriter writer, Document document) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnEndPage(writer, document); + } + } + + /** + * Called when the document is closed. + *

    + * Note that this method is called with the page number equal to the last + * page plus one. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + */ + public virtual void OnCloseDocument(PdfWriter writer, Document document) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnCloseDocument(writer, document); + } + } + + /** + * Called when a Paragraph is written. + *

    + * paragraphPosition will hold the height at which the + * paragraph will be written to. This is useful to insert bookmarks with + * more control. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param paragraphPosition + * the position the paragraph will be written to + */ + public virtual void OnParagraph(PdfWriter writer, Document document, + float paragraphPosition) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnParagraph(writer, document, paragraphPosition); + } + } + + /** + * Called when a Paragraph is written. + *

    + * paragraphPosition will hold the height of the end of the + * paragraph. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param paragraphPosition + * the position of the end of the paragraph + */ + public virtual void OnParagraphEnd(PdfWriter writer, Document document, + float paragraphPosition) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnParagraphEnd(writer, document, paragraphPosition); + } + } + + /** + * Called when a Chapter is written. + *

    + * position will hold the height at which the chapter will be + * written to. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param paragraphPosition + * the position the chapter will be written to + * @param title + * the title of the Chapter + */ + public virtual void OnChapter(PdfWriter writer, Document document, + float paragraphPosition, Paragraph title) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnChapter(writer, document, paragraphPosition, title); + } + } + + /** + * Called when the end of a Chapter is reached. + *

    + * position will hold the height of the end of the chapter. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param position + * the position of the end of the chapter. + */ + public virtual void OnChapterEnd(PdfWriter writer, Document document, float position) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnChapterEnd(writer, document, position); + } + } + + /** + * Called when a Section is written. + *

    + * position will hold the height at which the section will be + * written to. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param paragraphPosition + * the position the section will be written to + * @param depth + * the number depth of the Section + * @param title + * the title of the section + */ + public virtual void OnSection(PdfWriter writer, Document document, + float paragraphPosition, int depth, Paragraph title) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnSection(writer, document, paragraphPosition, depth, title); + } + } + + /** + * Called when the end of a Section is reached. + *

    + * position will hold the height of the section end. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param position + * the position of the end of the section + */ + public virtual void OnSectionEnd(PdfWriter writer, Document document, float position) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnSectionEnd(writer, document, position); + } + } + + /** + * Called when a Chunk with a generic tag is written. + *

    + * It is usefull to pinpoint the Chunk location to generate + * bookmarks, for example. + * + * @param writer + * the PdfWriter for this document + * @param document + * the document + * @param rect + * the Rectangle containing the Chunk + * + * @param text + * the text of the tag + */ + public virtual void OnGenericTag(PdfWriter writer, Document document, + Rectangle rect, String text) { + foreach (IPdfPageEvent eventa in events) { + eventa.OnGenericTag(writer, document, rect, text); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Courier-Bold.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Courier-Bold.afm new file mode 100644 index 0000000..352ace5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Courier-Bold.afm @@ -0,0 +1,342 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Mon Jun 23 16:28:00 1997 +Comment UniqueID 43048 +Comment VMusage 41139 52164 +FontName Courier-Bold +FullName Courier Bold +FamilyName Courier +Weight Bold +ItalicAngle 0 +IsFixedPitch true +CharacterSet ExtendedRoman +FontBBox -113 -250 749 801 +UnderlinePosition -100 +UnderlineThickness 50 +Version 003.000 +Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +EncodingScheme AdobeStandardEncoding +CapHeight 562 +XHeight 439 +Ascender 629 +Descender -157 +StdHW 84 +StdVW 106 +StartCharMetrics 315 +C 32 ; WX 600 ; N space ; B 0 0 0 0 ; +C 33 ; WX 600 ; N exclam ; B 202 -15 398 572 ; +C 34 ; WX 600 ; N quotedbl ; B 135 277 465 562 ; +C 35 ; WX 600 ; N numbersign ; B 56 -45 544 651 ; +C 36 ; WX 600 ; N dollar ; B 82 -126 519 666 ; +C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ; +C 38 ; WX 600 ; N ampersand ; B 36 -15 546 543 ; +C 39 ; WX 600 ; N quoteright ; B 171 277 423 562 ; +C 40 ; WX 600 ; N parenleft ; B 219 -102 461 616 ; +C 41 ; WX 600 ; N parenright ; B 139 -102 381 616 ; +C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ; +C 43 ; WX 600 ; N plus ; B 71 39 529 478 ; +C 44 ; WX 600 ; N comma ; B 123 -111 393 174 ; +C 45 ; WX 600 ; N hyphen ; B 100 203 500 313 ; +C 46 ; WX 600 ; N period ; B 192 -15 408 171 ; +C 47 ; WX 600 ; N slash ; B 98 -77 502 626 ; +C 48 ; WX 600 ; N zero ; B 87 -15 513 616 ; +C 49 ; WX 600 ; N one ; B 81 0 539 616 ; +C 50 ; WX 600 ; N two ; B 61 0 499 616 ; +C 51 ; WX 600 ; N three ; B 63 -15 501 616 ; +C 52 ; WX 600 ; N four ; B 53 0 507 616 ; +C 53 ; WX 600 ; N five ; B 70 -15 521 601 ; +C 54 ; WX 600 ; N six ; B 90 -15 521 616 ; +C 55 ; WX 600 ; N seven ; B 55 0 494 601 ; +C 56 ; WX 600 ; N eight ; B 83 -15 517 616 ; +C 57 ; WX 600 ; N nine ; B 79 -15 510 616 ; +C 58 ; WX 600 ; N colon ; B 191 -15 407 425 ; +C 59 ; WX 600 ; N semicolon ; B 123 -111 408 425 ; +C 60 ; WX 600 ; N less ; B 66 15 523 501 ; +C 61 ; WX 600 ; N equal ; B 71 118 529 398 ; +C 62 ; WX 600 ; N greater ; B 77 15 534 501 ; +C 63 ; WX 600 ; N question ; B 98 -14 501 580 ; +C 64 ; WX 600 ; N at ; B 16 -15 584 616 ; +C 65 ; WX 600 ; N A ; B -9 0 609 562 ; +C 66 ; WX 600 ; N B ; B 30 0 573 562 ; +C 67 ; WX 600 ; N C ; B 22 -18 560 580 ; +C 68 ; WX 600 ; N D ; B 30 0 594 562 ; +C 69 ; WX 600 ; N E ; B 25 0 560 562 ; +C 70 ; WX 600 ; N F ; B 39 0 570 562 ; +C 71 ; WX 600 ; N G ; B 22 -18 594 580 ; +C 72 ; WX 600 ; N H ; B 20 0 580 562 ; +C 73 ; WX 600 ; N I ; B 77 0 523 562 ; +C 74 ; WX 600 ; N J ; B 37 -18 601 562 ; +C 75 ; WX 600 ; N K ; B 21 0 599 562 ; +C 76 ; WX 600 ; N L ; B 39 0 578 562 ; +C 77 ; WX 600 ; N M ; B -2 0 602 562 ; +C 78 ; WX 600 ; N N ; B 8 -12 610 562 ; +C 79 ; WX 600 ; N O ; B 22 -18 578 580 ; +C 80 ; WX 600 ; N P ; B 48 0 559 562 ; +C 81 ; WX 600 ; N Q ; B 32 -138 578 580 ; +C 82 ; WX 600 ; N R ; B 24 0 599 562 ; +C 83 ; WX 600 ; N S ; B 47 -22 553 582 ; +C 84 ; WX 600 ; N T ; B 21 0 579 562 ; +C 85 ; WX 600 ; N U ; B 4 -18 596 562 ; +C 86 ; WX 600 ; N V ; B -13 0 613 562 ; +C 87 ; WX 600 ; N W ; B -18 0 618 562 ; +C 88 ; WX 600 ; N X ; B 12 0 588 562 ; +C 89 ; WX 600 ; N Y ; B 12 0 589 562 ; +C 90 ; WX 600 ; N Z ; B 62 0 539 562 ; +C 91 ; WX 600 ; N bracketleft ; B 245 -102 475 616 ; +C 92 ; WX 600 ; N backslash ; B 99 -77 503 626 ; +C 93 ; WX 600 ; N bracketright ; B 125 -102 355 616 ; +C 94 ; WX 600 ; N asciicircum ; B 108 250 492 616 ; +C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ; +C 96 ; WX 600 ; N quoteleft ; B 178 277 428 562 ; +C 97 ; WX 600 ; N a ; B 35 -15 570 454 ; +C 98 ; WX 600 ; N b ; B 0 -15 584 626 ; +C 99 ; WX 600 ; N c ; B 40 -15 545 459 ; +C 100 ; WX 600 ; N d ; B 20 -15 591 626 ; +C 101 ; WX 600 ; N e ; B 40 -15 563 454 ; +C 102 ; WX 600 ; N f ; B 83 0 547 626 ; L i fi ; L l fl ; +C 103 ; WX 600 ; N g ; B 30 -146 580 454 ; +C 104 ; WX 600 ; N h ; B 5 0 592 626 ; +C 105 ; WX 600 ; N i ; B 77 0 523 658 ; +C 106 ; WX 600 ; N j ; B 63 -146 440 658 ; +C 107 ; WX 600 ; N k ; B 20 0 585 626 ; +C 108 ; WX 600 ; N l ; B 77 0 523 626 ; +C 109 ; WX 600 ; N m ; B -22 0 626 454 ; +C 110 ; WX 600 ; N n ; B 18 0 592 454 ; +C 111 ; WX 600 ; N o ; B 30 -15 570 454 ; +C 112 ; WX 600 ; N p ; B -1 -142 570 454 ; +C 113 ; WX 600 ; N q ; B 20 -142 591 454 ; +C 114 ; WX 600 ; N r ; B 47 0 580 454 ; +C 115 ; WX 600 ; N s ; B 68 -17 535 459 ; +C 116 ; WX 600 ; N t ; B 47 -15 532 562 ; +C 117 ; WX 600 ; N u ; B -1 -15 569 439 ; +C 118 ; WX 600 ; N v ; B -1 0 601 439 ; +C 119 ; WX 600 ; N w ; B -18 0 618 439 ; +C 120 ; WX 600 ; N x ; B 6 0 594 439 ; +C 121 ; WX 600 ; N y ; B -4 -142 601 439 ; +C 122 ; WX 600 ; N z ; B 81 0 520 439 ; +C 123 ; WX 600 ; N braceleft ; B 160 -102 464 616 ; +C 124 ; WX 600 ; N bar ; B 255 -250 345 750 ; +C 125 ; WX 600 ; N braceright ; B 136 -102 440 616 ; +C 126 ; WX 600 ; N asciitilde ; B 71 153 530 356 ; +C 161 ; WX 600 ; N exclamdown ; B 202 -146 398 449 ; +C 162 ; WX 600 ; N cent ; B 66 -49 518 614 ; +C 163 ; WX 600 ; N sterling ; B 72 -28 558 611 ; +C 164 ; WX 600 ; N fraction ; B 25 -60 576 661 ; +C 165 ; WX 600 ; N yen ; B 10 0 590 562 ; +C 166 ; WX 600 ; N florin ; B -30 -131 572 616 ; +C 167 ; WX 600 ; N section ; B 83 -70 517 580 ; +C 168 ; WX 600 ; N currency ; B 54 49 546 517 ; +C 169 ; WX 600 ; N quotesingle ; B 227 277 373 562 ; +C 170 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ; +C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ; +C 172 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ; +C 173 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ; +C 174 ; WX 600 ; N fi ; B 12 0 593 626 ; +C 175 ; WX 600 ; N fl ; B 12 0 593 626 ; +C 177 ; WX 600 ; N endash ; B 65 203 535 313 ; +C 178 ; WX 600 ; N dagger ; B 106 -70 494 580 ; +C 179 ; WX 600 ; N daggerdbl ; B 106 -70 494 580 ; +C 180 ; WX 600 ; N periodcentered ; B 196 165 404 351 ; +C 182 ; WX 600 ; N paragraph ; B 6 -70 576 580 ; +C 183 ; WX 600 ; N bullet ; B 140 132 460 430 ; +C 184 ; WX 600 ; N quotesinglbase ; B 175 -142 427 143 ; +C 185 ; WX 600 ; N quotedblbase ; B 65 -142 529 143 ; +C 186 ; WX 600 ; N quotedblright ; B 61 277 525 562 ; +C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ; +C 188 ; WX 600 ; N ellipsis ; B 26 -15 574 116 ; +C 189 ; WX 600 ; N perthousand ; B -113 -15 713 616 ; +C 191 ; WX 600 ; N questiondown ; B 99 -146 502 449 ; +C 193 ; WX 600 ; N grave ; B 132 508 395 661 ; +C 194 ; WX 600 ; N acute ; B 205 508 468 661 ; +C 195 ; WX 600 ; N circumflex ; B 103 483 497 657 ; +C 196 ; WX 600 ; N tilde ; B 89 493 512 636 ; +C 197 ; WX 600 ; N macron ; B 88 505 512 585 ; +C 198 ; WX 600 ; N breve ; B 83 468 517 631 ; +C 199 ; WX 600 ; N dotaccent ; B 230 498 370 638 ; +C 200 ; WX 600 ; N dieresis ; B 128 498 472 638 ; +C 202 ; WX 600 ; N ring ; B 198 481 402 678 ; +C 203 ; WX 600 ; N cedilla ; B 205 -206 387 0 ; +C 205 ; WX 600 ; N hungarumlaut ; B 68 488 588 661 ; +C 206 ; WX 600 ; N ogonek ; B 169 -199 400 0 ; +C 207 ; WX 600 ; N caron ; B 103 493 497 667 ; +C 208 ; WX 600 ; N emdash ; B -10 203 610 313 ; +C 225 ; WX 600 ; N AE ; B -29 0 602 562 ; +C 227 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ; +C 232 ; WX 600 ; N Lslash ; B 39 0 578 562 ; +C 233 ; WX 600 ; N Oslash ; B 22 -22 578 584 ; +C 234 ; WX 600 ; N OE ; B -25 0 595 562 ; +C 235 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ; +C 241 ; WX 600 ; N ae ; B -4 -15 601 454 ; +C 245 ; WX 600 ; N dotlessi ; B 77 0 523 439 ; +C 248 ; WX 600 ; N lslash ; B 77 0 523 626 ; +C 249 ; WX 600 ; N oslash ; B 30 -24 570 463 ; +C 250 ; WX 600 ; N oe ; B -18 -15 611 454 ; +C 251 ; WX 600 ; N germandbls ; B 22 -15 596 626 ; +C -1 ; WX 600 ; N Idieresis ; B 77 0 523 761 ; +C -1 ; WX 600 ; N eacute ; B 40 -15 563 661 ; +C -1 ; WX 600 ; N abreve ; B 35 -15 570 661 ; +C -1 ; WX 600 ; N uhungarumlaut ; B -1 -15 628 661 ; +C -1 ; WX 600 ; N ecaron ; B 40 -15 563 667 ; +C -1 ; WX 600 ; N Ydieresis ; B 12 0 589 761 ; +C -1 ; WX 600 ; N divide ; B 71 16 529 500 ; +C -1 ; WX 600 ; N Yacute ; B 12 0 589 784 ; +C -1 ; WX 600 ; N Acircumflex ; B -9 0 609 780 ; +C -1 ; WX 600 ; N aacute ; B 35 -15 570 661 ; +C -1 ; WX 600 ; N Ucircumflex ; B 4 -18 596 780 ; +C -1 ; WX 600 ; N yacute ; B -4 -142 601 661 ; +C -1 ; WX 600 ; N scommaaccent ; B 68 -250 535 459 ; +C -1 ; WX 600 ; N ecircumflex ; B 40 -15 563 657 ; +C -1 ; WX 600 ; N Uring ; B 4 -18 596 801 ; +C -1 ; WX 600 ; N Udieresis ; B 4 -18 596 761 ; +C -1 ; WX 600 ; N aogonek ; B 35 -199 586 454 ; +C -1 ; WX 600 ; N Uacute ; B 4 -18 596 784 ; +C -1 ; WX 600 ; N uogonek ; B -1 -199 585 439 ; +C -1 ; WX 600 ; N Edieresis ; B 25 0 560 761 ; +C -1 ; WX 600 ; N Dcroat ; B 30 0 594 562 ; +C -1 ; WX 600 ; N commaaccent ; B 205 -250 397 -57 ; +C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ; +C -1 ; WX 600 ; N Emacron ; B 25 0 560 708 ; +C -1 ; WX 600 ; N ccaron ; B 40 -15 545 667 ; +C -1 ; WX 600 ; N aring ; B 35 -15 570 678 ; +C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 610 562 ; +C -1 ; WX 600 ; N lacute ; B 77 0 523 801 ; +C -1 ; WX 600 ; N agrave ; B 35 -15 570 661 ; +C -1 ; WX 600 ; N Tcommaaccent ; B 21 -250 579 562 ; +C -1 ; WX 600 ; N Cacute ; B 22 -18 560 784 ; +C -1 ; WX 600 ; N atilde ; B 35 -15 570 636 ; +C -1 ; WX 600 ; N Edotaccent ; B 25 0 560 761 ; +C -1 ; WX 600 ; N scaron ; B 68 -17 535 667 ; +C -1 ; WX 600 ; N scedilla ; B 68 -206 535 459 ; +C -1 ; WX 600 ; N iacute ; B 77 0 523 661 ; +C -1 ; WX 600 ; N lozenge ; B 66 0 534 740 ; +C -1 ; WX 600 ; N Rcaron ; B 24 0 599 790 ; +C -1 ; WX 600 ; N Gcommaaccent ; B 22 -250 594 580 ; +C -1 ; WX 600 ; N ucircumflex ; B -1 -15 569 657 ; +C -1 ; WX 600 ; N acircumflex ; B 35 -15 570 657 ; +C -1 ; WX 600 ; N Amacron ; B -9 0 609 708 ; +C -1 ; WX 600 ; N rcaron ; B 47 0 580 667 ; +C -1 ; WX 600 ; N ccedilla ; B 40 -206 545 459 ; +C -1 ; WX 600 ; N Zdotaccent ; B 62 0 539 761 ; +C -1 ; WX 600 ; N Thorn ; B 48 0 557 562 ; +C -1 ; WX 600 ; N Omacron ; B 22 -18 578 708 ; +C -1 ; WX 600 ; N Racute ; B 24 0 599 784 ; +C -1 ; WX 600 ; N Sacute ; B 47 -22 553 784 ; +C -1 ; WX 600 ; N dcaron ; B 20 -15 727 626 ; +C -1 ; WX 600 ; N Umacron ; B 4 -18 596 708 ; +C -1 ; WX 600 ; N uring ; B -1 -15 569 678 ; +C -1 ; WX 600 ; N threebaseior ; B 138 222 433 616 ; +C -1 ; WX 600 ; N Ograve ; B 22 -18 578 784 ; +C -1 ; WX 600 ; N Agrave ; B -9 0 609 784 ; +C -1 ; WX 600 ; N Abreve ; B -9 0 609 784 ; +C -1 ; WX 600 ; N multiply ; B 81 39 520 478 ; +C -1 ; WX 600 ; N uacute ; B -1 -15 569 661 ; +C -1 ; WX 600 ; N Tcaron ; B 21 0 579 790 ; +C -1 ; WX 600 ; N partialdiff ; B 63 -38 537 728 ; +C -1 ; WX 600 ; N ydieresis ; B -4 -142 601 638 ; +C -1 ; WX 600 ; N Nacute ; B 8 -12 610 784 ; +C -1 ; WX 600 ; N icircumflex ; B 73 0 523 657 ; +C -1 ; WX 600 ; N Ecircumflex ; B 25 0 560 780 ; +C -1 ; WX 600 ; N adieresis ; B 35 -15 570 638 ; +C -1 ; WX 600 ; N edieresis ; B 40 -15 563 638 ; +C -1 ; WX 600 ; N cacute ; B 40 -15 545 661 ; +C -1 ; WX 600 ; N nacute ; B 18 0 592 661 ; +C -1 ; WX 600 ; N umacron ; B -1 -15 569 585 ; +C -1 ; WX 600 ; N Ncaron ; B 8 -12 610 790 ; +C -1 ; WX 600 ; N Iacute ; B 77 0 523 784 ; +C -1 ; WX 600 ; N plusminus ; B 71 24 529 515 ; +C -1 ; WX 600 ; N brokenbar ; B 255 -175 345 675 ; +C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ; +C -1 ; WX 600 ; N Gbreve ; B 22 -18 594 784 ; +C -1 ; WX 600 ; N Idotaccent ; B 77 0 523 761 ; +C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ; +C -1 ; WX 600 ; N Egrave ; B 25 0 560 784 ; +C -1 ; WX 600 ; N racute ; B 47 0 580 661 ; +C -1 ; WX 600 ; N omacron ; B 30 -15 570 585 ; +C -1 ; WX 600 ; N Zacute ; B 62 0 539 784 ; +C -1 ; WX 600 ; N Zcaron ; B 62 0 539 790 ; +C -1 ; WX 600 ; N greaterequal ; B 26 0 523 696 ; +C -1 ; WX 600 ; N Eth ; B 30 0 594 562 ; +C -1 ; WX 600 ; N Ccedilla ; B 22 -206 560 580 ; +C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 523 626 ; +C -1 ; WX 600 ; N tcaron ; B 47 -15 532 703 ; +C -1 ; WX 600 ; N eogonek ; B 40 -199 563 454 ; +C -1 ; WX 600 ; N Uogonek ; B 4 -199 596 562 ; +C -1 ; WX 600 ; N Aacute ; B -9 0 609 784 ; +C -1 ; WX 600 ; N Adieresis ; B -9 0 609 761 ; +C -1 ; WX 600 ; N egrave ; B 40 -15 563 661 ; +C -1 ; WX 600 ; N zacute ; B 81 0 520 661 ; +C -1 ; WX 600 ; N iogonek ; B 77 -199 523 658 ; +C -1 ; WX 600 ; N Oacute ; B 22 -18 578 784 ; +C -1 ; WX 600 ; N oacute ; B 30 -15 570 661 ; +C -1 ; WX 600 ; N amacron ; B 35 -15 570 585 ; +C -1 ; WX 600 ; N sacute ; B 68 -17 535 661 ; +C -1 ; WX 600 ; N idieresis ; B 77 0 523 618 ; +C -1 ; WX 600 ; N Ocircumflex ; B 22 -18 578 780 ; +C -1 ; WX 600 ; N Ugrave ; B 4 -18 596 784 ; +C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ; +C -1 ; WX 600 ; N thorn ; B -14 -142 570 626 ; +C -1 ; WX 600 ; N twobaseior ; B 143 230 436 616 ; +C -1 ; WX 600 ; N Odieresis ; B 22 -18 578 761 ; +C -1 ; WX 600 ; N mu ; B -1 -142 569 439 ; +C -1 ; WX 600 ; N igrave ; B 77 0 523 661 ; +C -1 ; WX 600 ; N ohungarumlaut ; B 30 -15 668 661 ; +C -1 ; WX 600 ; N Eogonek ; B 25 -199 576 562 ; +C -1 ; WX 600 ; N dcroat ; B 20 -15 591 626 ; +C -1 ; WX 600 ; N threequarters ; B -47 -60 648 661 ; +C -1 ; WX 600 ; N Scedilla ; B 47 -206 553 582 ; +C -1 ; WX 600 ; N lcaron ; B 77 0 597 626 ; +C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 599 562 ; +C -1 ; WX 600 ; N Lacute ; B 39 0 578 784 ; +C -1 ; WX 600 ; N trademark ; B -9 230 749 562 ; +C -1 ; WX 600 ; N edotaccent ; B 40 -15 563 638 ; +C -1 ; WX 600 ; N Igrave ; B 77 0 523 784 ; +C -1 ; WX 600 ; N Imacron ; B 77 0 523 708 ; +C -1 ; WX 600 ; N Lcaron ; B 39 0 637 562 ; +C -1 ; WX 600 ; N onehalf ; B -47 -60 648 661 ; +C -1 ; WX 600 ; N lessequal ; B 26 0 523 696 ; +C -1 ; WX 600 ; N ocircumflex ; B 30 -15 570 657 ; +C -1 ; WX 600 ; N ntilde ; B 18 0 592 636 ; +C -1 ; WX 600 ; N Uhungarumlaut ; B 4 -18 638 784 ; +C -1 ; WX 600 ; N Eacute ; B 25 0 560 784 ; +C -1 ; WX 600 ; N emacron ; B 40 -15 563 585 ; +C -1 ; WX 600 ; N gbreve ; B 30 -146 580 661 ; +C -1 ; WX 600 ; N onequarter ; B -56 -60 656 661 ; +C -1 ; WX 600 ; N Scaron ; B 47 -22 553 790 ; +C -1 ; WX 600 ; N Scommaaccent ; B 47 -250 553 582 ; +C -1 ; WX 600 ; N Ohungarumlaut ; B 22 -18 628 784 ; +C -1 ; WX 600 ; N degree ; B 86 243 474 616 ; +C -1 ; WX 600 ; N ograve ; B 30 -15 570 661 ; +C -1 ; WX 600 ; N Ccaron ; B 22 -18 560 790 ; +C -1 ; WX 600 ; N ugrave ; B -1 -15 569 661 ; +C -1 ; WX 600 ; N radical ; B -19 -104 473 778 ; +C -1 ; WX 600 ; N Dcaron ; B 30 0 594 790 ; +C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 580 454 ; +C -1 ; WX 600 ; N Ntilde ; B 8 -12 610 759 ; +C -1 ; WX 600 ; N otilde ; B 30 -15 570 636 ; +C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 599 562 ; +C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 578 562 ; +C -1 ; WX 600 ; N Atilde ; B -9 0 609 759 ; +C -1 ; WX 600 ; N Aogonek ; B -9 -199 625 562 ; +C -1 ; WX 600 ; N Aring ; B -9 0 609 801 ; +C -1 ; WX 600 ; N Otilde ; B 22 -18 578 759 ; +C -1 ; WX 600 ; N zdotaccent ; B 81 0 520 638 ; +C -1 ; WX 600 ; N Ecaron ; B 25 0 560 790 ; +C -1 ; WX 600 ; N Iogonek ; B 77 -199 523 562 ; +C -1 ; WX 600 ; N kcommaaccent ; B 20 -250 585 626 ; +C -1 ; WX 600 ; N minus ; B 71 203 529 313 ; +C -1 ; WX 600 ; N Icircumflex ; B 77 0 523 780 ; +C -1 ; WX 600 ; N ncaron ; B 18 0 592 667 ; +C -1 ; WX 600 ; N tcommaaccent ; B 47 -250 532 562 ; +C -1 ; WX 600 ; N logicalnot ; B 71 103 529 413 ; +C -1 ; WX 600 ; N odieresis ; B 30 -15 570 638 ; +C -1 ; WX 600 ; N udieresis ; B -1 -15 569 638 ; +C -1 ; WX 600 ; N notequal ; B 12 -47 537 563 ; +C -1 ; WX 600 ; N gcommaaccent ; B 30 -146 580 714 ; +C -1 ; WX 600 ; N eth ; B 58 -27 543 626 ; +C -1 ; WX 600 ; N zcaron ; B 81 0 520 667 ; +C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 592 454 ; +C -1 ; WX 600 ; N onebaseior ; B 153 230 447 616 ; +C -1 ; WX 600 ; N imacron ; B 77 0 523 585 ; +C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Courier-BoldOblique.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Courier-BoldOblique.afm new file mode 100644 index 0000000..33738a8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Courier-BoldOblique.afm @@ -0,0 +1,342 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Mon Jun 23 16:28:46 1997 +Comment UniqueID 43049 +Comment VMusage 17529 79244 +FontName Courier-BoldOblique +FullName Courier Bold Oblique +FamilyName Courier +Weight Bold +ItalicAngle -12 +IsFixedPitch true +CharacterSet ExtendedRoman +FontBBox -57 -250 869 801 +UnderlinePosition -100 +UnderlineThickness 50 +Version 003.000 +Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +EncodingScheme AdobeStandardEncoding +CapHeight 562 +XHeight 439 +Ascender 629 +Descender -157 +StdHW 84 +StdVW 106 +StartCharMetrics 315 +C 32 ; WX 600 ; N space ; B 0 0 0 0 ; +C 33 ; WX 600 ; N exclam ; B 215 -15 495 572 ; +C 34 ; WX 600 ; N quotedbl ; B 211 277 585 562 ; +C 35 ; WX 600 ; N numbersign ; B 88 -45 641 651 ; +C 36 ; WX 600 ; N dollar ; B 87 -126 630 666 ; +C 37 ; WX 600 ; N percent ; B 101 -15 625 616 ; +C 38 ; WX 600 ; N ampersand ; B 61 -15 595 543 ; +C 39 ; WX 600 ; N quoteright ; B 229 277 543 562 ; +C 40 ; WX 600 ; N parenleft ; B 265 -102 592 616 ; +C 41 ; WX 600 ; N parenright ; B 117 -102 444 616 ; +C 42 ; WX 600 ; N asterisk ; B 179 219 598 601 ; +C 43 ; WX 600 ; N plus ; B 114 39 596 478 ; +C 44 ; WX 600 ; N comma ; B 99 -111 430 174 ; +C 45 ; WX 600 ; N hyphen ; B 143 203 567 313 ; +C 46 ; WX 600 ; N period ; B 206 -15 427 171 ; +C 47 ; WX 600 ; N slash ; B 90 -77 626 626 ; +C 48 ; WX 600 ; N zero ; B 135 -15 593 616 ; +C 49 ; WX 600 ; N one ; B 93 0 562 616 ; +C 50 ; WX 600 ; N two ; B 61 0 594 616 ; +C 51 ; WX 600 ; N three ; B 71 -15 571 616 ; +C 52 ; WX 600 ; N four ; B 81 0 559 616 ; +C 53 ; WX 600 ; N five ; B 77 -15 621 601 ; +C 54 ; WX 600 ; N six ; B 135 -15 652 616 ; +C 55 ; WX 600 ; N seven ; B 147 0 622 601 ; +C 56 ; WX 600 ; N eight ; B 115 -15 604 616 ; +C 57 ; WX 600 ; N nine ; B 75 -15 592 616 ; +C 58 ; WX 600 ; N colon ; B 205 -15 480 425 ; +C 59 ; WX 600 ; N semicolon ; B 99 -111 481 425 ; +C 60 ; WX 600 ; N less ; B 120 15 613 501 ; +C 61 ; WX 600 ; N equal ; B 96 118 614 398 ; +C 62 ; WX 600 ; N greater ; B 97 15 589 501 ; +C 63 ; WX 600 ; N question ; B 183 -14 592 580 ; +C 64 ; WX 600 ; N at ; B 65 -15 642 616 ; +C 65 ; WX 600 ; N A ; B -9 0 632 562 ; +C 66 ; WX 600 ; N B ; B 30 0 630 562 ; +C 67 ; WX 600 ; N C ; B 74 -18 675 580 ; +C 68 ; WX 600 ; N D ; B 30 0 664 562 ; +C 69 ; WX 600 ; N E ; B 25 0 670 562 ; +C 70 ; WX 600 ; N F ; B 39 0 684 562 ; +C 71 ; WX 600 ; N G ; B 74 -18 675 580 ; +C 72 ; WX 600 ; N H ; B 20 0 700 562 ; +C 73 ; WX 600 ; N I ; B 77 0 643 562 ; +C 74 ; WX 600 ; N J ; B 58 -18 721 562 ; +C 75 ; WX 600 ; N K ; B 21 0 692 562 ; +C 76 ; WX 600 ; N L ; B 39 0 636 562 ; +C 77 ; WX 600 ; N M ; B -2 0 722 562 ; +C 78 ; WX 600 ; N N ; B 8 -12 730 562 ; +C 79 ; WX 600 ; N O ; B 74 -18 645 580 ; +C 80 ; WX 600 ; N P ; B 48 0 643 562 ; +C 81 ; WX 600 ; N Q ; B 83 -138 636 580 ; +C 82 ; WX 600 ; N R ; B 24 0 617 562 ; +C 83 ; WX 600 ; N S ; B 54 -22 673 582 ; +C 84 ; WX 600 ; N T ; B 86 0 679 562 ; +C 85 ; WX 600 ; N U ; B 101 -18 716 562 ; +C 86 ; WX 600 ; N V ; B 84 0 733 562 ; +C 87 ; WX 600 ; N W ; B 79 0 738 562 ; +C 88 ; WX 600 ; N X ; B 12 0 690 562 ; +C 89 ; WX 600 ; N Y ; B 109 0 709 562 ; +C 90 ; WX 600 ; N Z ; B 62 0 637 562 ; +C 91 ; WX 600 ; N bracketleft ; B 223 -102 606 616 ; +C 92 ; WX 600 ; N backslash ; B 222 -77 496 626 ; +C 93 ; WX 600 ; N bracketright ; B 103 -102 486 616 ; +C 94 ; WX 600 ; N asciicircum ; B 171 250 556 616 ; +C 95 ; WX 600 ; N underscore ; B -27 -125 585 -75 ; +C 96 ; WX 600 ; N quoteleft ; B 297 277 487 562 ; +C 97 ; WX 600 ; N a ; B 61 -15 593 454 ; +C 98 ; WX 600 ; N b ; B 13 -15 636 626 ; +C 99 ; WX 600 ; N c ; B 81 -15 631 459 ; +C 100 ; WX 600 ; N d ; B 60 -15 645 626 ; +C 101 ; WX 600 ; N e ; B 81 -15 605 454 ; +C 102 ; WX 600 ; N f ; B 83 0 677 626 ; L i fi ; L l fl ; +C 103 ; WX 600 ; N g ; B 40 -146 674 454 ; +C 104 ; WX 600 ; N h ; B 18 0 615 626 ; +C 105 ; WX 600 ; N i ; B 77 0 546 658 ; +C 106 ; WX 600 ; N j ; B 36 -146 580 658 ; +C 107 ; WX 600 ; N k ; B 33 0 643 626 ; +C 108 ; WX 600 ; N l ; B 77 0 546 626 ; +C 109 ; WX 600 ; N m ; B -22 0 649 454 ; +C 110 ; WX 600 ; N n ; B 18 0 615 454 ; +C 111 ; WX 600 ; N o ; B 71 -15 622 454 ; +C 112 ; WX 600 ; N p ; B -32 -142 622 454 ; +C 113 ; WX 600 ; N q ; B 60 -142 685 454 ; +C 114 ; WX 600 ; N r ; B 47 0 655 454 ; +C 115 ; WX 600 ; N s ; B 66 -17 608 459 ; +C 116 ; WX 600 ; N t ; B 118 -15 567 562 ; +C 117 ; WX 600 ; N u ; B 70 -15 592 439 ; +C 118 ; WX 600 ; N v ; B 70 0 695 439 ; +C 119 ; WX 600 ; N w ; B 53 0 712 439 ; +C 120 ; WX 600 ; N x ; B 6 0 671 439 ; +C 121 ; WX 600 ; N y ; B -21 -142 695 439 ; +C 122 ; WX 600 ; N z ; B 81 0 614 439 ; +C 123 ; WX 600 ; N braceleft ; B 203 -102 595 616 ; +C 124 ; WX 600 ; N bar ; B 201 -250 505 750 ; +C 125 ; WX 600 ; N braceright ; B 114 -102 506 616 ; +C 126 ; WX 600 ; N asciitilde ; B 120 153 590 356 ; +C 161 ; WX 600 ; N exclamdown ; B 196 -146 477 449 ; +C 162 ; WX 600 ; N cent ; B 121 -49 605 614 ; +C 163 ; WX 600 ; N sterling ; B 106 -28 650 611 ; +C 164 ; WX 600 ; N fraction ; B 22 -60 708 661 ; +C 165 ; WX 600 ; N yen ; B 98 0 710 562 ; +C 166 ; WX 600 ; N florin ; B -57 -131 702 616 ; +C 167 ; WX 600 ; N section ; B 74 -70 620 580 ; +C 168 ; WX 600 ; N currency ; B 77 49 644 517 ; +C 169 ; WX 600 ; N quotesingle ; B 303 277 493 562 ; +C 170 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ; +C 171 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ; +C 172 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ; +C 173 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ; +C 174 ; WX 600 ; N fi ; B 12 0 644 626 ; +C 175 ; WX 600 ; N fl ; B 12 0 644 626 ; +C 177 ; WX 600 ; N endash ; B 108 203 602 313 ; +C 178 ; WX 600 ; N dagger ; B 175 -70 586 580 ; +C 179 ; WX 600 ; N daggerdbl ; B 121 -70 587 580 ; +C 180 ; WX 600 ; N periodcentered ; B 248 165 461 351 ; +C 182 ; WX 600 ; N paragraph ; B 61 -70 700 580 ; +C 183 ; WX 600 ; N bullet ; B 196 132 523 430 ; +C 184 ; WX 600 ; N quotesinglbase ; B 144 -142 458 143 ; +C 185 ; WX 600 ; N quotedblbase ; B 34 -142 560 143 ; +C 186 ; WX 600 ; N quotedblright ; B 119 277 645 562 ; +C 187 ; WX 600 ; N guillemotright ; B 71 70 647 446 ; +C 188 ; WX 600 ; N ellipsis ; B 35 -15 587 116 ; +C 189 ; WX 600 ; N perthousand ; B -45 -15 743 616 ; +C 191 ; WX 600 ; N questiondown ; B 100 -146 509 449 ; +C 193 ; WX 600 ; N grave ; B 272 508 503 661 ; +C 194 ; WX 600 ; N acute ; B 312 508 609 661 ; +C 195 ; WX 600 ; N circumflex ; B 212 483 607 657 ; +C 196 ; WX 600 ; N tilde ; B 199 493 643 636 ; +C 197 ; WX 600 ; N macron ; B 195 505 637 585 ; +C 198 ; WX 600 ; N breve ; B 217 468 652 631 ; +C 199 ; WX 600 ; N dotaccent ; B 348 498 493 638 ; +C 200 ; WX 600 ; N dieresis ; B 246 498 595 638 ; +C 202 ; WX 600 ; N ring ; B 319 481 528 678 ; +C 203 ; WX 600 ; N cedilla ; B 168 -206 368 0 ; +C 205 ; WX 600 ; N hungarumlaut ; B 171 488 729 661 ; +C 206 ; WX 600 ; N ogonek ; B 143 -199 367 0 ; +C 207 ; WX 600 ; N caron ; B 238 493 633 667 ; +C 208 ; WX 600 ; N emdash ; B 33 203 677 313 ; +C 225 ; WX 600 ; N AE ; B -29 0 708 562 ; +C 227 ; WX 600 ; N ordfeminine ; B 188 196 526 580 ; +C 232 ; WX 600 ; N Lslash ; B 39 0 636 562 ; +C 233 ; WX 600 ; N Oslash ; B 48 -22 673 584 ; +C 234 ; WX 600 ; N OE ; B 26 0 701 562 ; +C 235 ; WX 600 ; N ordmasculine ; B 188 196 543 580 ; +C 241 ; WX 600 ; N ae ; B 21 -15 652 454 ; +C 245 ; WX 600 ; N dotlessi ; B 77 0 546 439 ; +C 248 ; WX 600 ; N lslash ; B 77 0 587 626 ; +C 249 ; WX 600 ; N oslash ; B 54 -24 638 463 ; +C 250 ; WX 600 ; N oe ; B 18 -15 662 454 ; +C 251 ; WX 600 ; N germandbls ; B 22 -15 629 626 ; +C -1 ; WX 600 ; N Idieresis ; B 77 0 643 761 ; +C -1 ; WX 600 ; N eacute ; B 81 -15 609 661 ; +C -1 ; WX 600 ; N abreve ; B 61 -15 658 661 ; +C -1 ; WX 600 ; N uhungarumlaut ; B 70 -15 769 661 ; +C -1 ; WX 600 ; N ecaron ; B 81 -15 633 667 ; +C -1 ; WX 600 ; N Ydieresis ; B 109 0 709 761 ; +C -1 ; WX 600 ; N divide ; B 114 16 596 500 ; +C -1 ; WX 600 ; N Yacute ; B 109 0 709 784 ; +C -1 ; WX 600 ; N Acircumflex ; B -9 0 632 780 ; +C -1 ; WX 600 ; N aacute ; B 61 -15 609 661 ; +C -1 ; WX 600 ; N Ucircumflex ; B 101 -18 716 780 ; +C -1 ; WX 600 ; N yacute ; B -21 -142 695 661 ; +C -1 ; WX 600 ; N scommaaccent ; B 66 -250 608 459 ; +C -1 ; WX 600 ; N ecircumflex ; B 81 -15 607 657 ; +C -1 ; WX 600 ; N Uring ; B 101 -18 716 801 ; +C -1 ; WX 600 ; N Udieresis ; B 101 -18 716 761 ; +C -1 ; WX 600 ; N aogonek ; B 61 -199 593 454 ; +C -1 ; WX 600 ; N Uacute ; B 101 -18 716 784 ; +C -1 ; WX 600 ; N uogonek ; B 70 -199 592 439 ; +C -1 ; WX 600 ; N Edieresis ; B 25 0 670 761 ; +C -1 ; WX 600 ; N Dcroat ; B 30 0 664 562 ; +C -1 ; WX 600 ; N commaaccent ; B 151 -250 385 -57 ; +C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ; +C -1 ; WX 600 ; N Emacron ; B 25 0 670 708 ; +C -1 ; WX 600 ; N ccaron ; B 81 -15 633 667 ; +C -1 ; WX 600 ; N aring ; B 61 -15 593 678 ; +C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 730 562 ; +C -1 ; WX 600 ; N lacute ; B 77 0 639 801 ; +C -1 ; WX 600 ; N agrave ; B 61 -15 593 661 ; +C -1 ; WX 600 ; N Tcommaaccent ; B 86 -250 679 562 ; +C -1 ; WX 600 ; N Cacute ; B 74 -18 675 784 ; +C -1 ; WX 600 ; N atilde ; B 61 -15 643 636 ; +C -1 ; WX 600 ; N Edotaccent ; B 25 0 670 761 ; +C -1 ; WX 600 ; N scaron ; B 66 -17 633 667 ; +C -1 ; WX 600 ; N scedilla ; B 66 -206 608 459 ; +C -1 ; WX 600 ; N iacute ; B 77 0 609 661 ; +C -1 ; WX 600 ; N lozenge ; B 145 0 614 740 ; +C -1 ; WX 600 ; N Rcaron ; B 24 0 659 790 ; +C -1 ; WX 600 ; N Gcommaaccent ; B 74 -250 675 580 ; +C -1 ; WX 600 ; N ucircumflex ; B 70 -15 597 657 ; +C -1 ; WX 600 ; N acircumflex ; B 61 -15 607 657 ; +C -1 ; WX 600 ; N Amacron ; B -9 0 633 708 ; +C -1 ; WX 600 ; N rcaron ; B 47 0 655 667 ; +C -1 ; WX 600 ; N ccedilla ; B 81 -206 631 459 ; +C -1 ; WX 600 ; N Zdotaccent ; B 62 0 637 761 ; +C -1 ; WX 600 ; N Thorn ; B 48 0 620 562 ; +C -1 ; WX 600 ; N Omacron ; B 74 -18 663 708 ; +C -1 ; WX 600 ; N Racute ; B 24 0 665 784 ; +C -1 ; WX 600 ; N Sacute ; B 54 -22 673 784 ; +C -1 ; WX 600 ; N dcaron ; B 60 -15 861 626 ; +C -1 ; WX 600 ; N Umacron ; B 101 -18 716 708 ; +C -1 ; WX 600 ; N uring ; B 70 -15 592 678 ; +C -1 ; WX 600 ; N threebaseior ; B 193 222 526 616 ; +C -1 ; WX 600 ; N Ograve ; B 74 -18 645 784 ; +C -1 ; WX 600 ; N Agrave ; B -9 0 632 784 ; +C -1 ; WX 600 ; N Abreve ; B -9 0 684 784 ; +C -1 ; WX 600 ; N multiply ; B 104 39 606 478 ; +C -1 ; WX 600 ; N uacute ; B 70 -15 599 661 ; +C -1 ; WX 600 ; N Tcaron ; B 86 0 679 790 ; +C -1 ; WX 600 ; N partialdiff ; B 91 -38 627 728 ; +C -1 ; WX 600 ; N ydieresis ; B -21 -142 695 638 ; +C -1 ; WX 600 ; N Nacute ; B 8 -12 730 784 ; +C -1 ; WX 600 ; N icircumflex ; B 77 0 577 657 ; +C -1 ; WX 600 ; N Ecircumflex ; B 25 0 670 780 ; +C -1 ; WX 600 ; N adieresis ; B 61 -15 595 638 ; +C -1 ; WX 600 ; N edieresis ; B 81 -15 605 638 ; +C -1 ; WX 600 ; N cacute ; B 81 -15 649 661 ; +C -1 ; WX 600 ; N nacute ; B 18 0 639 661 ; +C -1 ; WX 600 ; N umacron ; B 70 -15 637 585 ; +C -1 ; WX 600 ; N Ncaron ; B 8 -12 730 790 ; +C -1 ; WX 600 ; N Iacute ; B 77 0 643 784 ; +C -1 ; WX 600 ; N plusminus ; B 76 24 614 515 ; +C -1 ; WX 600 ; N brokenbar ; B 217 -175 489 675 ; +C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ; +C -1 ; WX 600 ; N Gbreve ; B 74 -18 684 784 ; +C -1 ; WX 600 ; N Idotaccent ; B 77 0 643 761 ; +C -1 ; WX 600 ; N summation ; B 15 -10 672 706 ; +C -1 ; WX 600 ; N Egrave ; B 25 0 670 784 ; +C -1 ; WX 600 ; N racute ; B 47 0 655 661 ; +C -1 ; WX 600 ; N omacron ; B 71 -15 637 585 ; +C -1 ; WX 600 ; N Zacute ; B 62 0 665 784 ; +C -1 ; WX 600 ; N Zcaron ; B 62 0 659 790 ; +C -1 ; WX 600 ; N greaterequal ; B 26 0 627 696 ; +C -1 ; WX 600 ; N Eth ; B 30 0 664 562 ; +C -1 ; WX 600 ; N Ccedilla ; B 74 -206 675 580 ; +C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 546 626 ; +C -1 ; WX 600 ; N tcaron ; B 118 -15 627 703 ; +C -1 ; WX 600 ; N eogonek ; B 81 -199 605 454 ; +C -1 ; WX 600 ; N Uogonek ; B 101 -199 716 562 ; +C -1 ; WX 600 ; N Aacute ; B -9 0 655 784 ; +C -1 ; WX 600 ; N Adieresis ; B -9 0 632 761 ; +C -1 ; WX 600 ; N egrave ; B 81 -15 605 661 ; +C -1 ; WX 600 ; N zacute ; B 81 0 614 661 ; +C -1 ; WX 600 ; N iogonek ; B 77 -199 546 658 ; +C -1 ; WX 600 ; N Oacute ; B 74 -18 645 784 ; +C -1 ; WX 600 ; N oacute ; B 71 -15 649 661 ; +C -1 ; WX 600 ; N amacron ; B 61 -15 637 585 ; +C -1 ; WX 600 ; N sacute ; B 66 -17 609 661 ; +C -1 ; WX 600 ; N idieresis ; B 77 0 561 618 ; +C -1 ; WX 600 ; N Ocircumflex ; B 74 -18 645 780 ; +C -1 ; WX 600 ; N Ugrave ; B 101 -18 716 784 ; +C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ; +C -1 ; WX 600 ; N thorn ; B -32 -142 622 626 ; +C -1 ; WX 600 ; N twobaseior ; B 191 230 542 616 ; +C -1 ; WX 600 ; N Odieresis ; B 74 -18 645 761 ; +C -1 ; WX 600 ; N mu ; B 49 -142 592 439 ; +C -1 ; WX 600 ; N igrave ; B 77 0 546 661 ; +C -1 ; WX 600 ; N ohungarumlaut ; B 71 -15 809 661 ; +C -1 ; WX 600 ; N Eogonek ; B 25 -199 670 562 ; +C -1 ; WX 600 ; N dcroat ; B 60 -15 712 626 ; +C -1 ; WX 600 ; N threequarters ; B 8 -60 699 661 ; +C -1 ; WX 600 ; N Scedilla ; B 54 -206 673 582 ; +C -1 ; WX 600 ; N lcaron ; B 77 0 731 626 ; +C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 692 562 ; +C -1 ; WX 600 ; N Lacute ; B 39 0 636 784 ; +C -1 ; WX 600 ; N trademark ; B 86 230 869 562 ; +C -1 ; WX 600 ; N edotaccent ; B 81 -15 605 638 ; +C -1 ; WX 600 ; N Igrave ; B 77 0 643 784 ; +C -1 ; WX 600 ; N Imacron ; B 77 0 663 708 ; +C -1 ; WX 600 ; N Lcaron ; B 39 0 757 562 ; +C -1 ; WX 600 ; N onehalf ; B 22 -60 716 661 ; +C -1 ; WX 600 ; N lessequal ; B 26 0 671 696 ; +C -1 ; WX 600 ; N ocircumflex ; B 71 -15 622 657 ; +C -1 ; WX 600 ; N ntilde ; B 18 0 643 636 ; +C -1 ; WX 600 ; N Uhungarumlaut ; B 101 -18 805 784 ; +C -1 ; WX 600 ; N Eacute ; B 25 0 670 784 ; +C -1 ; WX 600 ; N emacron ; B 81 -15 637 585 ; +C -1 ; WX 600 ; N gbreve ; B 40 -146 674 661 ; +C -1 ; WX 600 ; N onequarter ; B 13 -60 707 661 ; +C -1 ; WX 600 ; N Scaron ; B 54 -22 689 790 ; +C -1 ; WX 600 ; N Scommaaccent ; B 54 -250 673 582 ; +C -1 ; WX 600 ; N Ohungarumlaut ; B 74 -18 795 784 ; +C -1 ; WX 600 ; N degree ; B 173 243 570 616 ; +C -1 ; WX 600 ; N ograve ; B 71 -15 622 661 ; +C -1 ; WX 600 ; N Ccaron ; B 74 -18 689 790 ; +C -1 ; WX 600 ; N ugrave ; B 70 -15 592 661 ; +C -1 ; WX 600 ; N radical ; B 67 -104 635 778 ; +C -1 ; WX 600 ; N Dcaron ; B 30 0 664 790 ; +C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 655 454 ; +C -1 ; WX 600 ; N Ntilde ; B 8 -12 730 759 ; +C -1 ; WX 600 ; N otilde ; B 71 -15 643 636 ; +C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 617 562 ; +C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 636 562 ; +C -1 ; WX 600 ; N Atilde ; B -9 0 669 759 ; +C -1 ; WX 600 ; N Aogonek ; B -9 -199 632 562 ; +C -1 ; WX 600 ; N Aring ; B -9 0 632 801 ; +C -1 ; WX 600 ; N Otilde ; B 74 -18 669 759 ; +C -1 ; WX 600 ; N zdotaccent ; B 81 0 614 638 ; +C -1 ; WX 600 ; N Ecaron ; B 25 0 670 790 ; +C -1 ; WX 600 ; N Iogonek ; B 77 -199 643 562 ; +C -1 ; WX 600 ; N kcommaaccent ; B 33 -250 643 626 ; +C -1 ; WX 600 ; N minus ; B 114 203 596 313 ; +C -1 ; WX 600 ; N Icircumflex ; B 77 0 643 780 ; +C -1 ; WX 600 ; N ncaron ; B 18 0 633 667 ; +C -1 ; WX 600 ; N tcommaaccent ; B 118 -250 567 562 ; +C -1 ; WX 600 ; N logicalnot ; B 135 103 617 413 ; +C -1 ; WX 600 ; N odieresis ; B 71 -15 622 638 ; +C -1 ; WX 600 ; N udieresis ; B 70 -15 595 638 ; +C -1 ; WX 600 ; N notequal ; B 30 -47 626 563 ; +C -1 ; WX 600 ; N gcommaaccent ; B 40 -146 674 714 ; +C -1 ; WX 600 ; N eth ; B 93 -27 661 626 ; +C -1 ; WX 600 ; N zcaron ; B 81 0 643 667 ; +C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 615 454 ; +C -1 ; WX 600 ; N onebaseior ; B 212 230 514 616 ; +C -1 ; WX 600 ; N imacron ; B 77 0 575 585 ; +C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Courier-Oblique.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Courier-Oblique.afm new file mode 100644 index 0000000..def637d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Courier-Oblique.afm @@ -0,0 +1,342 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 17:37:52 1997 +Comment UniqueID 43051 +Comment VMusage 16248 75829 +FontName Courier-Oblique +FullName Courier Oblique +FamilyName Courier +Weight Medium +ItalicAngle -12 +IsFixedPitch true +CharacterSet ExtendedRoman +FontBBox -27 -250 849 805 +UnderlinePosition -100 +UnderlineThickness 50 +Version 003.000 +Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +EncodingScheme AdobeStandardEncoding +CapHeight 562 +XHeight 426 +Ascender 629 +Descender -157 +StdHW 51 +StdVW 51 +StartCharMetrics 315 +C 32 ; WX 600 ; N space ; B 0 0 0 0 ; +C 33 ; WX 600 ; N exclam ; B 243 -15 464 572 ; +C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ; +C 35 ; WX 600 ; N numbersign ; B 133 -32 596 639 ; +C 36 ; WX 600 ; N dollar ; B 108 -126 596 662 ; +C 37 ; WX 600 ; N percent ; B 134 -15 599 622 ; +C 38 ; WX 600 ; N ampersand ; B 87 -15 580 543 ; +C 39 ; WX 600 ; N quoteright ; B 283 328 495 562 ; +C 40 ; WX 600 ; N parenleft ; B 313 -108 572 622 ; +C 41 ; WX 600 ; N parenright ; B 137 -108 396 622 ; +C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ; +C 43 ; WX 600 ; N plus ; B 129 44 580 470 ; +C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ; +C 45 ; WX 600 ; N hyphen ; B 152 231 558 285 ; +C 46 ; WX 600 ; N period ; B 238 -15 382 109 ; +C 47 ; WX 600 ; N slash ; B 112 -80 604 629 ; +C 48 ; WX 600 ; N zero ; B 154 -15 575 622 ; +C 49 ; WX 600 ; N one ; B 98 0 515 622 ; +C 50 ; WX 600 ; N two ; B 70 0 568 622 ; +C 51 ; WX 600 ; N three ; B 82 -15 538 622 ; +C 52 ; WX 600 ; N four ; B 108 0 541 622 ; +C 53 ; WX 600 ; N five ; B 99 -15 589 607 ; +C 54 ; WX 600 ; N six ; B 155 -15 629 622 ; +C 55 ; WX 600 ; N seven ; B 182 0 612 607 ; +C 56 ; WX 600 ; N eight ; B 132 -15 588 622 ; +C 57 ; WX 600 ; N nine ; B 93 -15 574 622 ; +C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ; +C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ; +C 60 ; WX 600 ; N less ; B 96 42 610 472 ; +C 61 ; WX 600 ; N equal ; B 109 138 600 376 ; +C 62 ; WX 600 ; N greater ; B 85 42 599 472 ; +C 63 ; WX 600 ; N question ; B 222 -15 583 572 ; +C 64 ; WX 600 ; N at ; B 127 -15 582 622 ; +C 65 ; WX 600 ; N A ; B 3 0 607 562 ; +C 66 ; WX 600 ; N B ; B 43 0 616 562 ; +C 67 ; WX 600 ; N C ; B 93 -18 655 580 ; +C 68 ; WX 600 ; N D ; B 43 0 645 562 ; +C 69 ; WX 600 ; N E ; B 53 0 660 562 ; +C 70 ; WX 600 ; N F ; B 53 0 660 562 ; +C 71 ; WX 600 ; N G ; B 83 -18 645 580 ; +C 72 ; WX 600 ; N H ; B 32 0 687 562 ; +C 73 ; WX 600 ; N I ; B 96 0 623 562 ; +C 74 ; WX 600 ; N J ; B 52 -18 685 562 ; +C 75 ; WX 600 ; N K ; B 38 0 671 562 ; +C 76 ; WX 600 ; N L ; B 47 0 607 562 ; +C 77 ; WX 600 ; N M ; B 4 0 715 562 ; +C 78 ; WX 600 ; N N ; B 7 -13 712 562 ; +C 79 ; WX 600 ; N O ; B 94 -18 625 580 ; +C 80 ; WX 600 ; N P ; B 79 0 644 562 ; +C 81 ; WX 600 ; N Q ; B 95 -138 625 580 ; +C 82 ; WX 600 ; N R ; B 38 0 598 562 ; +C 83 ; WX 600 ; N S ; B 76 -20 650 580 ; +C 84 ; WX 600 ; N T ; B 108 0 665 562 ; +C 85 ; WX 600 ; N U ; B 125 -18 702 562 ; +C 86 ; WX 600 ; N V ; B 105 -13 723 562 ; +C 87 ; WX 600 ; N W ; B 106 -13 722 562 ; +C 88 ; WX 600 ; N X ; B 23 0 675 562 ; +C 89 ; WX 600 ; N Y ; B 133 0 695 562 ; +C 90 ; WX 600 ; N Z ; B 86 0 610 562 ; +C 91 ; WX 600 ; N bracketleft ; B 246 -108 574 622 ; +C 92 ; WX 600 ; N backslash ; B 249 -80 468 629 ; +C 93 ; WX 600 ; N bracketright ; B 135 -108 463 622 ; +C 94 ; WX 600 ; N asciicircum ; B 175 354 587 622 ; +C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ; +C 96 ; WX 600 ; N quoteleft ; B 343 328 457 562 ; +C 97 ; WX 600 ; N a ; B 76 -15 569 441 ; +C 98 ; WX 600 ; N b ; B 29 -15 625 629 ; +C 99 ; WX 600 ; N c ; B 106 -15 608 441 ; +C 100 ; WX 600 ; N d ; B 85 -15 640 629 ; +C 101 ; WX 600 ; N e ; B 106 -15 598 441 ; +C 102 ; WX 600 ; N f ; B 114 0 662 629 ; L i fi ; L l fl ; +C 103 ; WX 600 ; N g ; B 61 -157 657 441 ; +C 104 ; WX 600 ; N h ; B 33 0 592 629 ; +C 105 ; WX 600 ; N i ; B 95 0 515 657 ; +C 106 ; WX 600 ; N j ; B 52 -157 550 657 ; +C 107 ; WX 600 ; N k ; B 58 0 633 629 ; +C 108 ; WX 600 ; N l ; B 95 0 515 629 ; +C 109 ; WX 600 ; N m ; B -5 0 615 441 ; +C 110 ; WX 600 ; N n ; B 26 0 585 441 ; +C 111 ; WX 600 ; N o ; B 102 -15 588 441 ; +C 112 ; WX 600 ; N p ; B -24 -157 605 441 ; +C 113 ; WX 600 ; N q ; B 85 -157 682 441 ; +C 114 ; WX 600 ; N r ; B 60 0 636 441 ; +C 115 ; WX 600 ; N s ; B 78 -15 584 441 ; +C 116 ; WX 600 ; N t ; B 167 -15 561 561 ; +C 117 ; WX 600 ; N u ; B 101 -15 572 426 ; +C 118 ; WX 600 ; N v ; B 90 -10 681 426 ; +C 119 ; WX 600 ; N w ; B 76 -10 695 426 ; +C 120 ; WX 600 ; N x ; B 20 0 655 426 ; +C 121 ; WX 600 ; N y ; B -4 -157 683 426 ; +C 122 ; WX 600 ; N z ; B 99 0 593 426 ; +C 123 ; WX 600 ; N braceleft ; B 233 -108 569 622 ; +C 124 ; WX 600 ; N bar ; B 222 -250 485 750 ; +C 125 ; WX 600 ; N braceright ; B 140 -108 477 622 ; +C 126 ; WX 600 ; N asciitilde ; B 116 197 600 320 ; +C 161 ; WX 600 ; N exclamdown ; B 225 -157 445 430 ; +C 162 ; WX 600 ; N cent ; B 151 -49 588 614 ; +C 163 ; WX 600 ; N sterling ; B 124 -21 621 611 ; +C 164 ; WX 600 ; N fraction ; B 84 -57 646 665 ; +C 165 ; WX 600 ; N yen ; B 120 0 693 562 ; +C 166 ; WX 600 ; N florin ; B -26 -143 671 622 ; +C 167 ; WX 600 ; N section ; B 104 -78 590 580 ; +C 168 ; WX 600 ; N currency ; B 94 58 628 506 ; +C 169 ; WX 600 ; N quotesingle ; B 345 328 460 562 ; +C 170 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ; +C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ; +C 172 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ; +C 173 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ; +C 174 ; WX 600 ; N fi ; B 3 0 619 629 ; +C 175 ; WX 600 ; N fl ; B 3 0 619 629 ; +C 177 ; WX 600 ; N endash ; B 124 231 586 285 ; +C 178 ; WX 600 ; N dagger ; B 217 -78 546 580 ; +C 179 ; WX 600 ; N daggerdbl ; B 163 -78 546 580 ; +C 180 ; WX 600 ; N periodcentered ; B 275 189 434 327 ; +C 182 ; WX 600 ; N paragraph ; B 100 -78 630 562 ; +C 183 ; WX 600 ; N bullet ; B 224 130 485 383 ; +C 184 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ; +C 185 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ; +C 186 ; WX 600 ; N quotedblright ; B 213 328 576 562 ; +C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ; +C 188 ; WX 600 ; N ellipsis ; B 46 -15 575 111 ; +C 189 ; WX 600 ; N perthousand ; B 59 -15 627 622 ; +C 191 ; WX 600 ; N questiondown ; B 105 -157 466 430 ; +C 193 ; WX 600 ; N grave ; B 294 497 484 672 ; +C 194 ; WX 600 ; N acute ; B 348 497 612 672 ; +C 195 ; WX 600 ; N circumflex ; B 229 477 581 654 ; +C 196 ; WX 600 ; N tilde ; B 212 489 629 606 ; +C 197 ; WX 600 ; N macron ; B 232 525 600 565 ; +C 198 ; WX 600 ; N breve ; B 279 501 576 609 ; +C 199 ; WX 600 ; N dotaccent ; B 373 537 478 640 ; +C 200 ; WX 600 ; N dieresis ; B 272 537 579 640 ; +C 202 ; WX 600 ; N ring ; B 332 463 500 627 ; +C 203 ; WX 600 ; N cedilla ; B 197 -151 344 10 ; +C 205 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ; +C 206 ; WX 600 ; N ogonek ; B 189 -172 377 4 ; +C 207 ; WX 600 ; N caron ; B 262 492 614 669 ; +C 208 ; WX 600 ; N emdash ; B 49 231 661 285 ; +C 225 ; WX 600 ; N AE ; B 3 0 655 562 ; +C 227 ; WX 600 ; N ordfeminine ; B 209 249 512 580 ; +C 232 ; WX 600 ; N Lslash ; B 47 0 607 562 ; +C 233 ; WX 600 ; N Oslash ; B 94 -80 625 629 ; +C 234 ; WX 600 ; N OE ; B 59 0 672 562 ; +C 235 ; WX 600 ; N ordmasculine ; B 210 249 535 580 ; +C 241 ; WX 600 ; N ae ; B 41 -15 626 441 ; +C 245 ; WX 600 ; N dotlessi ; B 95 0 515 426 ; +C 248 ; WX 600 ; N lslash ; B 95 0 587 629 ; +C 249 ; WX 600 ; N oslash ; B 102 -80 588 506 ; +C 250 ; WX 600 ; N oe ; B 54 -15 615 441 ; +C 251 ; WX 600 ; N germandbls ; B 48 -15 617 629 ; +C -1 ; WX 600 ; N Idieresis ; B 96 0 623 753 ; +C -1 ; WX 600 ; N eacute ; B 106 -15 612 672 ; +C -1 ; WX 600 ; N abreve ; B 76 -15 576 609 ; +C -1 ; WX 600 ; N uhungarumlaut ; B 101 -15 723 672 ; +C -1 ; WX 600 ; N ecaron ; B 106 -15 614 669 ; +C -1 ; WX 600 ; N Ydieresis ; B 133 0 695 753 ; +C -1 ; WX 600 ; N divide ; B 136 48 573 467 ; +C -1 ; WX 600 ; N Yacute ; B 133 0 695 805 ; +C -1 ; WX 600 ; N Acircumflex ; B 3 0 607 787 ; +C -1 ; WX 600 ; N aacute ; B 76 -15 612 672 ; +C -1 ; WX 600 ; N Ucircumflex ; B 125 -18 702 787 ; +C -1 ; WX 600 ; N yacute ; B -4 -157 683 672 ; +C -1 ; WX 600 ; N scommaaccent ; B 78 -250 584 441 ; +C -1 ; WX 600 ; N ecircumflex ; B 106 -15 598 654 ; +C -1 ; WX 600 ; N Uring ; B 125 -18 702 760 ; +C -1 ; WX 600 ; N Udieresis ; B 125 -18 702 753 ; +C -1 ; WX 600 ; N aogonek ; B 76 -172 569 441 ; +C -1 ; WX 600 ; N Uacute ; B 125 -18 702 805 ; +C -1 ; WX 600 ; N uogonek ; B 101 -172 572 426 ; +C -1 ; WX 600 ; N Edieresis ; B 53 0 660 753 ; +C -1 ; WX 600 ; N Dcroat ; B 43 0 645 562 ; +C -1 ; WX 600 ; N commaaccent ; B 145 -250 323 -58 ; +C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ; +C -1 ; WX 600 ; N Emacron ; B 53 0 660 698 ; +C -1 ; WX 600 ; N ccaron ; B 106 -15 614 669 ; +C -1 ; WX 600 ; N aring ; B 76 -15 569 627 ; +C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 712 562 ; +C -1 ; WX 600 ; N lacute ; B 95 0 640 805 ; +C -1 ; WX 600 ; N agrave ; B 76 -15 569 672 ; +C -1 ; WX 600 ; N Tcommaaccent ; B 108 -250 665 562 ; +C -1 ; WX 600 ; N Cacute ; B 93 -18 655 805 ; +C -1 ; WX 600 ; N atilde ; B 76 -15 629 606 ; +C -1 ; WX 600 ; N Edotaccent ; B 53 0 660 753 ; +C -1 ; WX 600 ; N scaron ; B 78 -15 614 669 ; +C -1 ; WX 600 ; N scedilla ; B 78 -151 584 441 ; +C -1 ; WX 600 ; N iacute ; B 95 0 612 672 ; +C -1 ; WX 600 ; N lozenge ; B 94 0 519 706 ; +C -1 ; WX 600 ; N Rcaron ; B 38 0 642 802 ; +C -1 ; WX 600 ; N Gcommaaccent ; B 83 -250 645 580 ; +C -1 ; WX 600 ; N ucircumflex ; B 101 -15 572 654 ; +C -1 ; WX 600 ; N acircumflex ; B 76 -15 581 654 ; +C -1 ; WX 600 ; N Amacron ; B 3 0 607 698 ; +C -1 ; WX 600 ; N rcaron ; B 60 0 636 669 ; +C -1 ; WX 600 ; N ccedilla ; B 106 -151 614 441 ; +C -1 ; WX 600 ; N Zdotaccent ; B 86 0 610 753 ; +C -1 ; WX 600 ; N Thorn ; B 79 0 606 562 ; +C -1 ; WX 600 ; N Omacron ; B 94 -18 628 698 ; +C -1 ; WX 600 ; N Racute ; B 38 0 670 805 ; +C -1 ; WX 600 ; N Sacute ; B 76 -20 650 805 ; +C -1 ; WX 600 ; N dcaron ; B 85 -15 849 629 ; +C -1 ; WX 600 ; N Umacron ; B 125 -18 702 698 ; +C -1 ; WX 600 ; N uring ; B 101 -15 572 627 ; +C -1 ; WX 600 ; N threebaseior ; B 213 240 501 622 ; +C -1 ; WX 600 ; N Ograve ; B 94 -18 625 805 ; +C -1 ; WX 600 ; N Agrave ; B 3 0 607 805 ; +C -1 ; WX 600 ; N Abreve ; B 3 0 607 732 ; +C -1 ; WX 600 ; N multiply ; B 103 43 607 470 ; +C -1 ; WX 600 ; N uacute ; B 101 -15 602 672 ; +C -1 ; WX 600 ; N Tcaron ; B 108 0 665 802 ; +C -1 ; WX 600 ; N partialdiff ; B 45 -38 546 710 ; +C -1 ; WX 600 ; N ydieresis ; B -4 -157 683 620 ; +C -1 ; WX 600 ; N Nacute ; B 7 -13 712 805 ; +C -1 ; WX 600 ; N icircumflex ; B 95 0 551 654 ; +C -1 ; WX 600 ; N Ecircumflex ; B 53 0 660 787 ; +C -1 ; WX 600 ; N adieresis ; B 76 -15 575 620 ; +C -1 ; WX 600 ; N edieresis ; B 106 -15 598 620 ; +C -1 ; WX 600 ; N cacute ; B 106 -15 612 672 ; +C -1 ; WX 600 ; N nacute ; B 26 0 602 672 ; +C -1 ; WX 600 ; N umacron ; B 101 -15 600 565 ; +C -1 ; WX 600 ; N Ncaron ; B 7 -13 712 802 ; +C -1 ; WX 600 ; N Iacute ; B 96 0 640 805 ; +C -1 ; WX 600 ; N plusminus ; B 96 44 594 558 ; +C -1 ; WX 600 ; N brokenbar ; B 238 -175 469 675 ; +C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ; +C -1 ; WX 600 ; N Gbreve ; B 83 -18 645 732 ; +C -1 ; WX 600 ; N Idotaccent ; B 96 0 623 753 ; +C -1 ; WX 600 ; N summation ; B 15 -10 670 706 ; +C -1 ; WX 600 ; N Egrave ; B 53 0 660 805 ; +C -1 ; WX 600 ; N racute ; B 60 0 636 672 ; +C -1 ; WX 600 ; N omacron ; B 102 -15 600 565 ; +C -1 ; WX 600 ; N Zacute ; B 86 0 670 805 ; +C -1 ; WX 600 ; N Zcaron ; B 86 0 642 802 ; +C -1 ; WX 600 ; N greaterequal ; B 98 0 594 710 ; +C -1 ; WX 600 ; N Eth ; B 43 0 645 562 ; +C -1 ; WX 600 ; N Ccedilla ; B 93 -151 658 580 ; +C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 515 629 ; +C -1 ; WX 600 ; N tcaron ; B 167 -15 587 717 ; +C -1 ; WX 600 ; N eogonek ; B 106 -172 598 441 ; +C -1 ; WX 600 ; N Uogonek ; B 124 -172 702 562 ; +C -1 ; WX 600 ; N Aacute ; B 3 0 660 805 ; +C -1 ; WX 600 ; N Adieresis ; B 3 0 607 753 ; +C -1 ; WX 600 ; N egrave ; B 106 -15 598 672 ; +C -1 ; WX 600 ; N zacute ; B 99 0 612 672 ; +C -1 ; WX 600 ; N iogonek ; B 95 -172 515 657 ; +C -1 ; WX 600 ; N Oacute ; B 94 -18 640 805 ; +C -1 ; WX 600 ; N oacute ; B 102 -15 612 672 ; +C -1 ; WX 600 ; N amacron ; B 76 -15 600 565 ; +C -1 ; WX 600 ; N sacute ; B 78 -15 612 672 ; +C -1 ; WX 600 ; N idieresis ; B 95 0 545 620 ; +C -1 ; WX 600 ; N Ocircumflex ; B 94 -18 625 787 ; +C -1 ; WX 600 ; N Ugrave ; B 125 -18 702 805 ; +C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ; +C -1 ; WX 600 ; N thorn ; B -24 -157 605 629 ; +C -1 ; WX 600 ; N twobaseior ; B 230 249 535 622 ; +C -1 ; WX 600 ; N Odieresis ; B 94 -18 625 753 ; +C -1 ; WX 600 ; N mu ; B 72 -157 572 426 ; +C -1 ; WX 600 ; N igrave ; B 95 0 515 672 ; +C -1 ; WX 600 ; N ohungarumlaut ; B 102 -15 723 672 ; +C -1 ; WX 600 ; N Eogonek ; B 53 -172 660 562 ; +C -1 ; WX 600 ; N dcroat ; B 85 -15 704 629 ; +C -1 ; WX 600 ; N threequarters ; B 73 -56 659 666 ; +C -1 ; WX 600 ; N Scedilla ; B 76 -151 650 580 ; +C -1 ; WX 600 ; N lcaron ; B 95 0 667 629 ; +C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 671 562 ; +C -1 ; WX 600 ; N Lacute ; B 47 0 607 805 ; +C -1 ; WX 600 ; N trademark ; B 75 263 742 562 ; +C -1 ; WX 600 ; N edotaccent ; B 106 -15 598 620 ; +C -1 ; WX 600 ; N Igrave ; B 96 0 623 805 ; +C -1 ; WX 600 ; N Imacron ; B 96 0 628 698 ; +C -1 ; WX 600 ; N Lcaron ; B 47 0 632 562 ; +C -1 ; WX 600 ; N onehalf ; B 65 -57 669 665 ; +C -1 ; WX 600 ; N lessequal ; B 98 0 645 710 ; +C -1 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ; +C -1 ; WX 600 ; N ntilde ; B 26 0 629 606 ; +C -1 ; WX 600 ; N Uhungarumlaut ; B 125 -18 761 805 ; +C -1 ; WX 600 ; N Eacute ; B 53 0 670 805 ; +C -1 ; WX 600 ; N emacron ; B 106 -15 600 565 ; +C -1 ; WX 600 ; N gbreve ; B 61 -157 657 609 ; +C -1 ; WX 600 ; N onequarter ; B 65 -57 674 665 ; +C -1 ; WX 600 ; N Scaron ; B 76 -20 672 802 ; +C -1 ; WX 600 ; N Scommaaccent ; B 76 -250 650 580 ; +C -1 ; WX 600 ; N Ohungarumlaut ; B 94 -18 751 805 ; +C -1 ; WX 600 ; N degree ; B 214 269 576 622 ; +C -1 ; WX 600 ; N ograve ; B 102 -15 588 672 ; +C -1 ; WX 600 ; N Ccaron ; B 93 -18 672 802 ; +C -1 ; WX 600 ; N ugrave ; B 101 -15 572 672 ; +C -1 ; WX 600 ; N radical ; B 85 -15 765 792 ; +C -1 ; WX 600 ; N Dcaron ; B 43 0 645 802 ; +C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 636 441 ; +C -1 ; WX 600 ; N Ntilde ; B 7 -13 712 729 ; +C -1 ; WX 600 ; N otilde ; B 102 -15 629 606 ; +C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 598 562 ; +C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 607 562 ; +C -1 ; WX 600 ; N Atilde ; B 3 0 655 729 ; +C -1 ; WX 600 ; N Aogonek ; B 3 -172 607 562 ; +C -1 ; WX 600 ; N Aring ; B 3 0 607 750 ; +C -1 ; WX 600 ; N Otilde ; B 94 -18 655 729 ; +C -1 ; WX 600 ; N zdotaccent ; B 99 0 593 620 ; +C -1 ; WX 600 ; N Ecaron ; B 53 0 660 802 ; +C -1 ; WX 600 ; N Iogonek ; B 96 -172 623 562 ; +C -1 ; WX 600 ; N kcommaaccent ; B 58 -250 633 629 ; +C -1 ; WX 600 ; N minus ; B 129 232 580 283 ; +C -1 ; WX 600 ; N Icircumflex ; B 96 0 623 787 ; +C -1 ; WX 600 ; N ncaron ; B 26 0 614 669 ; +C -1 ; WX 600 ; N tcommaaccent ; B 165 -250 561 561 ; +C -1 ; WX 600 ; N logicalnot ; B 155 108 591 369 ; +C -1 ; WX 600 ; N odieresis ; B 102 -15 588 620 ; +C -1 ; WX 600 ; N udieresis ; B 101 -15 575 620 ; +C -1 ; WX 600 ; N notequal ; B 43 -16 621 529 ; +C -1 ; WX 600 ; N gcommaaccent ; B 61 -157 657 708 ; +C -1 ; WX 600 ; N eth ; B 102 -15 639 629 ; +C -1 ; WX 600 ; N zcaron ; B 99 0 624 669 ; +C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 585 441 ; +C -1 ; WX 600 ; N onebaseior ; B 231 249 491 622 ; +C -1 ; WX 600 ; N imacron ; B 95 0 543 565 ; +C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Courier.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Courier.afm new file mode 100644 index 0000000..1d23d2e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Courier.afm @@ -0,0 +1,342 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 17:27:09 1997 +Comment UniqueID 43050 +Comment VMusage 39754 50779 +FontName Courier +FullName Courier +FamilyName Courier +Weight Medium +ItalicAngle 0 +IsFixedPitch true +CharacterSet ExtendedRoman +FontBBox -23 -250 715 805 +UnderlinePosition -100 +UnderlineThickness 50 +Version 003.000 +Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +EncodingScheme AdobeStandardEncoding +CapHeight 562 +XHeight 426 +Ascender 629 +Descender -157 +StdHW 51 +StdVW 51 +StartCharMetrics 315 +C 32 ; WX 600 ; N space ; B 0 0 0 0 ; +C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ; +C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ; +C 35 ; WX 600 ; N numbersign ; B 93 -32 507 639 ; +C 36 ; WX 600 ; N dollar ; B 105 -126 496 662 ; +C 37 ; WX 600 ; N percent ; B 81 -15 518 622 ; +C 38 ; WX 600 ; N ampersand ; B 63 -15 538 543 ; +C 39 ; WX 600 ; N quoteright ; B 213 328 376 562 ; +C 40 ; WX 600 ; N parenleft ; B 269 -108 440 622 ; +C 41 ; WX 600 ; N parenright ; B 160 -108 331 622 ; +C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ; +C 43 ; WX 600 ; N plus ; B 80 44 520 470 ; +C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ; +C 45 ; WX 600 ; N hyphen ; B 103 231 497 285 ; +C 46 ; WX 600 ; N period ; B 229 -15 371 109 ; +C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ; +C 48 ; WX 600 ; N zero ; B 106 -15 494 622 ; +C 49 ; WX 600 ; N one ; B 96 0 505 622 ; +C 50 ; WX 600 ; N two ; B 70 0 471 622 ; +C 51 ; WX 600 ; N three ; B 75 -15 466 622 ; +C 52 ; WX 600 ; N four ; B 78 0 500 622 ; +C 53 ; WX 600 ; N five ; B 92 -15 497 607 ; +C 54 ; WX 600 ; N six ; B 111 -15 497 622 ; +C 55 ; WX 600 ; N seven ; B 82 0 483 607 ; +C 56 ; WX 600 ; N eight ; B 102 -15 498 622 ; +C 57 ; WX 600 ; N nine ; B 96 -15 489 622 ; +C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ; +C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ; +C 60 ; WX 600 ; N less ; B 41 42 519 472 ; +C 61 ; WX 600 ; N equal ; B 80 138 520 376 ; +C 62 ; WX 600 ; N greater ; B 66 42 544 472 ; +C 63 ; WX 600 ; N question ; B 129 -15 492 572 ; +C 64 ; WX 600 ; N at ; B 77 -15 533 622 ; +C 65 ; WX 600 ; N A ; B 3 0 597 562 ; +C 66 ; WX 600 ; N B ; B 43 0 559 562 ; +C 67 ; WX 600 ; N C ; B 41 -18 540 580 ; +C 68 ; WX 600 ; N D ; B 43 0 574 562 ; +C 69 ; WX 600 ; N E ; B 53 0 550 562 ; +C 70 ; WX 600 ; N F ; B 53 0 545 562 ; +C 71 ; WX 600 ; N G ; B 31 -18 575 580 ; +C 72 ; WX 600 ; N H ; B 32 0 568 562 ; +C 73 ; WX 600 ; N I ; B 96 0 504 562 ; +C 74 ; WX 600 ; N J ; B 34 -18 566 562 ; +C 75 ; WX 600 ; N K ; B 38 0 582 562 ; +C 76 ; WX 600 ; N L ; B 47 0 554 562 ; +C 77 ; WX 600 ; N M ; B 4 0 596 562 ; +C 78 ; WX 600 ; N N ; B 7 -13 593 562 ; +C 79 ; WX 600 ; N O ; B 43 -18 557 580 ; +C 80 ; WX 600 ; N P ; B 79 0 558 562 ; +C 81 ; WX 600 ; N Q ; B 43 -138 557 580 ; +C 82 ; WX 600 ; N R ; B 38 0 588 562 ; +C 83 ; WX 600 ; N S ; B 72 -20 529 580 ; +C 84 ; WX 600 ; N T ; B 38 0 563 562 ; +C 85 ; WX 600 ; N U ; B 17 -18 583 562 ; +C 86 ; WX 600 ; N V ; B -4 -13 604 562 ; +C 87 ; WX 600 ; N W ; B -3 -13 603 562 ; +C 88 ; WX 600 ; N X ; B 23 0 577 562 ; +C 89 ; WX 600 ; N Y ; B 24 0 576 562 ; +C 90 ; WX 600 ; N Z ; B 86 0 514 562 ; +C 91 ; WX 600 ; N bracketleft ; B 269 -108 442 622 ; +C 92 ; WX 600 ; N backslash ; B 118 -80 482 629 ; +C 93 ; WX 600 ; N bracketright ; B 158 -108 331 622 ; +C 94 ; WX 600 ; N asciicircum ; B 94 354 506 622 ; +C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ; +C 96 ; WX 600 ; N quoteleft ; B 224 328 387 562 ; +C 97 ; WX 600 ; N a ; B 53 -15 559 441 ; +C 98 ; WX 600 ; N b ; B 14 -15 575 629 ; +C 99 ; WX 600 ; N c ; B 66 -15 529 441 ; +C 100 ; WX 600 ; N d ; B 45 -15 591 629 ; +C 101 ; WX 600 ; N e ; B 66 -15 548 441 ; +C 102 ; WX 600 ; N f ; B 114 0 531 629 ; L i fi ; L l fl ; +C 103 ; WX 600 ; N g ; B 45 -157 566 441 ; +C 104 ; WX 600 ; N h ; B 18 0 582 629 ; +C 105 ; WX 600 ; N i ; B 95 0 505 657 ; +C 106 ; WX 600 ; N j ; B 82 -157 410 657 ; +C 107 ; WX 600 ; N k ; B 43 0 580 629 ; +C 108 ; WX 600 ; N l ; B 95 0 505 629 ; +C 109 ; WX 600 ; N m ; B -5 0 605 441 ; +C 110 ; WX 600 ; N n ; B 26 0 575 441 ; +C 111 ; WX 600 ; N o ; B 62 -15 538 441 ; +C 112 ; WX 600 ; N p ; B 9 -157 555 441 ; +C 113 ; WX 600 ; N q ; B 45 -157 591 441 ; +C 114 ; WX 600 ; N r ; B 60 0 559 441 ; +C 115 ; WX 600 ; N s ; B 80 -15 513 441 ; +C 116 ; WX 600 ; N t ; B 87 -15 530 561 ; +C 117 ; WX 600 ; N u ; B 21 -15 562 426 ; +C 118 ; WX 600 ; N v ; B 10 -10 590 426 ; +C 119 ; WX 600 ; N w ; B -4 -10 604 426 ; +C 120 ; WX 600 ; N x ; B 20 0 580 426 ; +C 121 ; WX 600 ; N y ; B 7 -157 592 426 ; +C 122 ; WX 600 ; N z ; B 99 0 502 426 ; +C 123 ; WX 600 ; N braceleft ; B 182 -108 437 622 ; +C 124 ; WX 600 ; N bar ; B 275 -250 326 750 ; +C 125 ; WX 600 ; N braceright ; B 163 -108 418 622 ; +C 126 ; WX 600 ; N asciitilde ; B 63 197 540 320 ; +C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ; +C 162 ; WX 600 ; N cent ; B 96 -49 500 614 ; +C 163 ; WX 600 ; N sterling ; B 84 -21 521 611 ; +C 164 ; WX 600 ; N fraction ; B 92 -57 509 665 ; +C 165 ; WX 600 ; N yen ; B 26 0 574 562 ; +C 166 ; WX 600 ; N florin ; B 4 -143 539 622 ; +C 167 ; WX 600 ; N section ; B 113 -78 488 580 ; +C 168 ; WX 600 ; N currency ; B 73 58 527 506 ; +C 169 ; WX 600 ; N quotesingle ; B 259 328 341 562 ; +C 170 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ; +C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ; +C 172 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ; +C 173 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ; +C 174 ; WX 600 ; N fi ; B 3 0 597 629 ; +C 175 ; WX 600 ; N fl ; B 3 0 597 629 ; +C 177 ; WX 600 ; N endash ; B 75 231 525 285 ; +C 178 ; WX 600 ; N dagger ; B 141 -78 459 580 ; +C 179 ; WX 600 ; N daggerdbl ; B 141 -78 459 580 ; +C 180 ; WX 600 ; N periodcentered ; B 222 189 378 327 ; +C 182 ; WX 600 ; N paragraph ; B 50 -78 511 562 ; +C 183 ; WX 600 ; N bullet ; B 172 130 428 383 ; +C 184 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ; +C 185 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ; +C 186 ; WX 600 ; N quotedblright ; B 143 328 457 562 ; +C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ; +C 188 ; WX 600 ; N ellipsis ; B 37 -15 563 111 ; +C 189 ; WX 600 ; N perthousand ; B 3 -15 600 622 ; +C 191 ; WX 600 ; N questiondown ; B 108 -157 471 430 ; +C 193 ; WX 600 ; N grave ; B 151 497 378 672 ; +C 194 ; WX 600 ; N acute ; B 242 497 469 672 ; +C 195 ; WX 600 ; N circumflex ; B 124 477 476 654 ; +C 196 ; WX 600 ; N tilde ; B 105 489 503 606 ; +C 197 ; WX 600 ; N macron ; B 120 525 480 565 ; +C 198 ; WX 600 ; N breve ; B 153 501 447 609 ; +C 199 ; WX 600 ; N dotaccent ; B 249 537 352 640 ; +C 200 ; WX 600 ; N dieresis ; B 148 537 453 640 ; +C 202 ; WX 600 ; N ring ; B 218 463 382 627 ; +C 203 ; WX 600 ; N cedilla ; B 224 -151 362 10 ; +C 205 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ; +C 206 ; WX 600 ; N ogonek ; B 211 -172 407 4 ; +C 207 ; WX 600 ; N caron ; B 124 492 476 669 ; +C 208 ; WX 600 ; N emdash ; B 0 231 600 285 ; +C 225 ; WX 600 ; N AE ; B 3 0 550 562 ; +C 227 ; WX 600 ; N ordfeminine ; B 156 249 442 580 ; +C 232 ; WX 600 ; N Lslash ; B 47 0 554 562 ; +C 233 ; WX 600 ; N Oslash ; B 43 -80 557 629 ; +C 234 ; WX 600 ; N OE ; B 7 0 567 562 ; +C 235 ; WX 600 ; N ordmasculine ; B 157 249 443 580 ; +C 241 ; WX 600 ; N ae ; B 19 -15 570 441 ; +C 245 ; WX 600 ; N dotlessi ; B 95 0 505 426 ; +C 248 ; WX 600 ; N lslash ; B 95 0 505 629 ; +C 249 ; WX 600 ; N oslash ; B 62 -80 538 506 ; +C 250 ; WX 600 ; N oe ; B 19 -15 559 441 ; +C 251 ; WX 600 ; N germandbls ; B 48 -15 588 629 ; +C -1 ; WX 600 ; N Idieresis ; B 96 0 504 753 ; +C -1 ; WX 600 ; N eacute ; B 66 -15 548 672 ; +C -1 ; WX 600 ; N abreve ; B 53 -15 559 609 ; +C -1 ; WX 600 ; N uhungarumlaut ; B 21 -15 580 672 ; +C -1 ; WX 600 ; N ecaron ; B 66 -15 548 669 ; +C -1 ; WX 600 ; N Ydieresis ; B 24 0 576 753 ; +C -1 ; WX 600 ; N divide ; B 87 48 513 467 ; +C -1 ; WX 600 ; N Yacute ; B 24 0 576 805 ; +C -1 ; WX 600 ; N Acircumflex ; B 3 0 597 787 ; +C -1 ; WX 600 ; N aacute ; B 53 -15 559 672 ; +C -1 ; WX 600 ; N Ucircumflex ; B 17 -18 583 787 ; +C -1 ; WX 600 ; N yacute ; B 7 -157 592 672 ; +C -1 ; WX 600 ; N scommaaccent ; B 80 -250 513 441 ; +C -1 ; WX 600 ; N ecircumflex ; B 66 -15 548 654 ; +C -1 ; WX 600 ; N Uring ; B 17 -18 583 760 ; +C -1 ; WX 600 ; N Udieresis ; B 17 -18 583 753 ; +C -1 ; WX 600 ; N aogonek ; B 53 -172 587 441 ; +C -1 ; WX 600 ; N Uacute ; B 17 -18 583 805 ; +C -1 ; WX 600 ; N uogonek ; B 21 -172 590 426 ; +C -1 ; WX 600 ; N Edieresis ; B 53 0 550 753 ; +C -1 ; WX 600 ; N Dcroat ; B 30 0 574 562 ; +C -1 ; WX 600 ; N commaaccent ; B 198 -250 335 -58 ; +C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ; +C -1 ; WX 600 ; N Emacron ; B 53 0 550 698 ; +C -1 ; WX 600 ; N ccaron ; B 66 -15 529 669 ; +C -1 ; WX 600 ; N aring ; B 53 -15 559 627 ; +C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 593 562 ; +C -1 ; WX 600 ; N lacute ; B 95 0 505 805 ; +C -1 ; WX 600 ; N agrave ; B 53 -15 559 672 ; +C -1 ; WX 600 ; N Tcommaaccent ; B 38 -250 563 562 ; +C -1 ; WX 600 ; N Cacute ; B 41 -18 540 805 ; +C -1 ; WX 600 ; N atilde ; B 53 -15 559 606 ; +C -1 ; WX 600 ; N Edotaccent ; B 53 0 550 753 ; +C -1 ; WX 600 ; N scaron ; B 80 -15 513 669 ; +C -1 ; WX 600 ; N scedilla ; B 80 -151 513 441 ; +C -1 ; WX 600 ; N iacute ; B 95 0 505 672 ; +C -1 ; WX 600 ; N lozenge ; B 18 0 443 706 ; +C -1 ; WX 600 ; N Rcaron ; B 38 0 588 802 ; +C -1 ; WX 600 ; N Gcommaaccent ; B 31 -250 575 580 ; +C -1 ; WX 600 ; N ucircumflex ; B 21 -15 562 654 ; +C -1 ; WX 600 ; N acircumflex ; B 53 -15 559 654 ; +C -1 ; WX 600 ; N Amacron ; B 3 0 597 698 ; +C -1 ; WX 600 ; N rcaron ; B 60 0 559 669 ; +C -1 ; WX 600 ; N ccedilla ; B 66 -151 529 441 ; +C -1 ; WX 600 ; N Zdotaccent ; B 86 0 514 753 ; +C -1 ; WX 600 ; N Thorn ; B 79 0 538 562 ; +C -1 ; WX 600 ; N Omacron ; B 43 -18 557 698 ; +C -1 ; WX 600 ; N Racute ; B 38 0 588 805 ; +C -1 ; WX 600 ; N Sacute ; B 72 -20 529 805 ; +C -1 ; WX 600 ; N dcaron ; B 45 -15 715 629 ; +C -1 ; WX 600 ; N Umacron ; B 17 -18 583 698 ; +C -1 ; WX 600 ; N uring ; B 21 -15 562 627 ; +C -1 ; WX 600 ; N threebaseior ; B 155 240 406 622 ; +C -1 ; WX 600 ; N Ograve ; B 43 -18 557 805 ; +C -1 ; WX 600 ; N Agrave ; B 3 0 597 805 ; +C -1 ; WX 600 ; N Abreve ; B 3 0 597 732 ; +C -1 ; WX 600 ; N multiply ; B 87 43 515 470 ; +C -1 ; WX 600 ; N uacute ; B 21 -15 562 672 ; +C -1 ; WX 600 ; N Tcaron ; B 38 0 563 802 ; +C -1 ; WX 600 ; N partialdiff ; B 17 -38 459 710 ; +C -1 ; WX 600 ; N ydieresis ; B 7 -157 592 620 ; +C -1 ; WX 600 ; N Nacute ; B 7 -13 593 805 ; +C -1 ; WX 600 ; N icircumflex ; B 94 0 505 654 ; +C -1 ; WX 600 ; N Ecircumflex ; B 53 0 550 787 ; +C -1 ; WX 600 ; N adieresis ; B 53 -15 559 620 ; +C -1 ; WX 600 ; N edieresis ; B 66 -15 548 620 ; +C -1 ; WX 600 ; N cacute ; B 66 -15 529 672 ; +C -1 ; WX 600 ; N nacute ; B 26 0 575 672 ; +C -1 ; WX 600 ; N umacron ; B 21 -15 562 565 ; +C -1 ; WX 600 ; N Ncaron ; B 7 -13 593 802 ; +C -1 ; WX 600 ; N Iacute ; B 96 0 504 805 ; +C -1 ; WX 600 ; N plusminus ; B 87 44 513 558 ; +C -1 ; WX 600 ; N brokenbar ; B 275 -175 326 675 ; +C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ; +C -1 ; WX 600 ; N Gbreve ; B 31 -18 575 732 ; +C -1 ; WX 600 ; N Idotaccent ; B 96 0 504 753 ; +C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ; +C -1 ; WX 600 ; N Egrave ; B 53 0 550 805 ; +C -1 ; WX 600 ; N racute ; B 60 0 559 672 ; +C -1 ; WX 600 ; N omacron ; B 62 -15 538 565 ; +C -1 ; WX 600 ; N Zacute ; B 86 0 514 805 ; +C -1 ; WX 600 ; N Zcaron ; B 86 0 514 802 ; +C -1 ; WX 600 ; N greaterequal ; B 98 0 502 710 ; +C -1 ; WX 600 ; N Eth ; B 30 0 574 562 ; +C -1 ; WX 600 ; N Ccedilla ; B 41 -151 540 580 ; +C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 505 629 ; +C -1 ; WX 600 ; N tcaron ; B 87 -15 530 717 ; +C -1 ; WX 600 ; N eogonek ; B 66 -172 548 441 ; +C -1 ; WX 600 ; N Uogonek ; B 17 -172 583 562 ; +C -1 ; WX 600 ; N Aacute ; B 3 0 597 805 ; +C -1 ; WX 600 ; N Adieresis ; B 3 0 597 753 ; +C -1 ; WX 600 ; N egrave ; B 66 -15 548 672 ; +C -1 ; WX 600 ; N zacute ; B 99 0 502 672 ; +C -1 ; WX 600 ; N iogonek ; B 95 -172 505 657 ; +C -1 ; WX 600 ; N Oacute ; B 43 -18 557 805 ; +C -1 ; WX 600 ; N oacute ; B 62 -15 538 672 ; +C -1 ; WX 600 ; N amacron ; B 53 -15 559 565 ; +C -1 ; WX 600 ; N sacute ; B 80 -15 513 672 ; +C -1 ; WX 600 ; N idieresis ; B 95 0 505 620 ; +C -1 ; WX 600 ; N Ocircumflex ; B 43 -18 557 787 ; +C -1 ; WX 600 ; N Ugrave ; B 17 -18 583 805 ; +C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ; +C -1 ; WX 600 ; N thorn ; B -6 -157 555 629 ; +C -1 ; WX 600 ; N twobaseior ; B 177 249 424 622 ; +C -1 ; WX 600 ; N Odieresis ; B 43 -18 557 753 ; +C -1 ; WX 600 ; N mu ; B 21 -157 562 426 ; +C -1 ; WX 600 ; N igrave ; B 95 0 505 672 ; +C -1 ; WX 600 ; N ohungarumlaut ; B 62 -15 580 672 ; +C -1 ; WX 600 ; N Eogonek ; B 53 -172 561 562 ; +C -1 ; WX 600 ; N dcroat ; B 45 -15 591 629 ; +C -1 ; WX 600 ; N threequarters ; B 8 -56 593 666 ; +C -1 ; WX 600 ; N Scedilla ; B 72 -151 529 580 ; +C -1 ; WX 600 ; N lcaron ; B 95 0 533 629 ; +C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 582 562 ; +C -1 ; WX 600 ; N Lacute ; B 47 0 554 805 ; +C -1 ; WX 600 ; N trademark ; B -23 263 623 562 ; +C -1 ; WX 600 ; N edotaccent ; B 66 -15 548 620 ; +C -1 ; WX 600 ; N Igrave ; B 96 0 504 805 ; +C -1 ; WX 600 ; N Imacron ; B 96 0 504 698 ; +C -1 ; WX 600 ; N Lcaron ; B 47 0 554 562 ; +C -1 ; WX 600 ; N onehalf ; B 0 -57 611 665 ; +C -1 ; WX 600 ; N lessequal ; B 98 0 502 710 ; +C -1 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ; +C -1 ; WX 600 ; N ntilde ; B 26 0 575 606 ; +C -1 ; WX 600 ; N Uhungarumlaut ; B 17 -18 590 805 ; +C -1 ; WX 600 ; N Eacute ; B 53 0 550 805 ; +C -1 ; WX 600 ; N emacron ; B 66 -15 548 565 ; +C -1 ; WX 600 ; N gbreve ; B 45 -157 566 609 ; +C -1 ; WX 600 ; N onequarter ; B 0 -57 600 665 ; +C -1 ; WX 600 ; N Scaron ; B 72 -20 529 802 ; +C -1 ; WX 600 ; N Scommaaccent ; B 72 -250 529 580 ; +C -1 ; WX 600 ; N Ohungarumlaut ; B 43 -18 580 805 ; +C -1 ; WX 600 ; N degree ; B 123 269 477 622 ; +C -1 ; WX 600 ; N ograve ; B 62 -15 538 672 ; +C -1 ; WX 600 ; N Ccaron ; B 41 -18 540 802 ; +C -1 ; WX 600 ; N ugrave ; B 21 -15 562 672 ; +C -1 ; WX 600 ; N radical ; B 3 -15 597 792 ; +C -1 ; WX 600 ; N Dcaron ; B 43 0 574 802 ; +C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 559 441 ; +C -1 ; WX 600 ; N Ntilde ; B 7 -13 593 729 ; +C -1 ; WX 600 ; N otilde ; B 62 -15 538 606 ; +C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 588 562 ; +C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 554 562 ; +C -1 ; WX 600 ; N Atilde ; B 3 0 597 729 ; +C -1 ; WX 600 ; N Aogonek ; B 3 -172 608 562 ; +C -1 ; WX 600 ; N Aring ; B 3 0 597 750 ; +C -1 ; WX 600 ; N Otilde ; B 43 -18 557 729 ; +C -1 ; WX 600 ; N zdotaccent ; B 99 0 502 620 ; +C -1 ; WX 600 ; N Ecaron ; B 53 0 550 802 ; +C -1 ; WX 600 ; N Iogonek ; B 96 -172 504 562 ; +C -1 ; WX 600 ; N kcommaaccent ; B 43 -250 580 629 ; +C -1 ; WX 600 ; N minus ; B 80 232 520 283 ; +C -1 ; WX 600 ; N Icircumflex ; B 96 0 504 787 ; +C -1 ; WX 600 ; N ncaron ; B 26 0 575 669 ; +C -1 ; WX 600 ; N tcommaaccent ; B 87 -250 530 561 ; +C -1 ; WX 600 ; N logicalnot ; B 87 108 513 369 ; +C -1 ; WX 600 ; N odieresis ; B 62 -15 538 620 ; +C -1 ; WX 600 ; N udieresis ; B 21 -15 562 620 ; +C -1 ; WX 600 ; N notequal ; B 15 -16 540 529 ; +C -1 ; WX 600 ; N gcommaaccent ; B 45 -157 566 708 ; +C -1 ; WX 600 ; N eth ; B 62 -15 538 629 ; +C -1 ; WX 600 ; N zcaron ; B 99 0 502 669 ; +C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 575 441 ; +C -1 ; WX 600 ; N onebaseior ; B 172 249 428 622 ; +C -1 ; WX 600 ; N imacron ; B 95 0 505 565 ; +C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Bold.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Bold.afm new file mode 100644 index 0000000..276cc8f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Bold.afm @@ -0,0 +1,2827 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:43:52 1997 +Comment UniqueID 43052 +Comment VMusage 37169 48194 +FontName Helvetica-Bold +FullName Helvetica Bold +FamilyName Helvetica +Weight Bold +ItalicAngle 0 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -170 -228 1003 962 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 718 +XHeight 532 +Ascender 718 +Descender -207 +StdHW 118 +StdVW 140 +StartCharMetrics 315 +C 32 ; WX 278 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 90 0 244 718 ; +C 34 ; WX 474 ; N quotedbl ; B 98 447 376 718 ; +C 35 ; WX 556 ; N numbersign ; B 18 0 538 698 ; +C 36 ; WX 556 ; N dollar ; B 30 -115 523 775 ; +C 37 ; WX 889 ; N percent ; B 28 -19 861 710 ; +C 38 ; WX 722 ; N ampersand ; B 54 -19 701 718 ; +C 39 ; WX 278 ; N quoteright ; B 69 445 209 718 ; +C 40 ; WX 333 ; N parenleft ; B 35 -208 314 734 ; +C 41 ; WX 333 ; N parenright ; B 19 -208 298 734 ; +C 42 ; WX 389 ; N asterisk ; B 27 387 362 718 ; +C 43 ; WX 584 ; N plus ; B 40 0 544 506 ; +C 44 ; WX 278 ; N comma ; B 64 -168 214 146 ; +C 45 ; WX 333 ; N hyphen ; B 27 215 306 345 ; +C 46 ; WX 278 ; N period ; B 64 0 214 146 ; +C 47 ; WX 278 ; N slash ; B -33 -19 311 737 ; +C 48 ; WX 556 ; N zero ; B 32 -19 524 710 ; +C 49 ; WX 556 ; N one ; B 69 0 378 710 ; +C 50 ; WX 556 ; N two ; B 26 0 511 710 ; +C 51 ; WX 556 ; N three ; B 27 -19 516 710 ; +C 52 ; WX 556 ; N four ; B 27 0 526 710 ; +C 53 ; WX 556 ; N five ; B 27 -19 516 698 ; +C 54 ; WX 556 ; N six ; B 31 -19 520 710 ; +C 55 ; WX 556 ; N seven ; B 25 0 528 698 ; +C 56 ; WX 556 ; N eight ; B 32 -19 524 710 ; +C 57 ; WX 556 ; N nine ; B 30 -19 522 710 ; +C 58 ; WX 333 ; N colon ; B 92 0 242 512 ; +C 59 ; WX 333 ; N semicolon ; B 92 -168 242 512 ; +C 60 ; WX 584 ; N less ; B 38 -8 546 514 ; +C 61 ; WX 584 ; N equal ; B 40 87 544 419 ; +C 62 ; WX 584 ; N greater ; B 38 -8 546 514 ; +C 63 ; WX 611 ; N question ; B 60 0 556 727 ; +C 64 ; WX 975 ; N at ; B 118 -19 856 737 ; +C 65 ; WX 722 ; N A ; B 20 0 702 718 ; +C 66 ; WX 722 ; N B ; B 76 0 669 718 ; +C 67 ; WX 722 ; N C ; B 44 -19 684 737 ; +C 68 ; WX 722 ; N D ; B 76 0 685 718 ; +C 69 ; WX 667 ; N E ; B 76 0 621 718 ; +C 70 ; WX 611 ; N F ; B 76 0 587 718 ; +C 71 ; WX 778 ; N G ; B 44 -19 713 737 ; +C 72 ; WX 722 ; N H ; B 71 0 651 718 ; +C 73 ; WX 278 ; N I ; B 64 0 214 718 ; +C 74 ; WX 556 ; N J ; B 22 -18 484 718 ; +C 75 ; WX 722 ; N K ; B 87 0 722 718 ; +C 76 ; WX 611 ; N L ; B 76 0 583 718 ; +C 77 ; WX 833 ; N M ; B 69 0 765 718 ; +C 78 ; WX 722 ; N N ; B 69 0 654 718 ; +C 79 ; WX 778 ; N O ; B 44 -19 734 737 ; +C 80 ; WX 667 ; N P ; B 76 0 627 718 ; +C 81 ; WX 778 ; N Q ; B 44 -52 737 737 ; +C 82 ; WX 722 ; N R ; B 76 0 677 718 ; +C 83 ; WX 667 ; N S ; B 39 -19 629 737 ; +C 84 ; WX 611 ; N T ; B 14 0 598 718 ; +C 85 ; WX 722 ; N U ; B 72 -19 651 718 ; +C 86 ; WX 667 ; N V ; B 19 0 648 718 ; +C 87 ; WX 944 ; N W ; B 16 0 929 718 ; +C 88 ; WX 667 ; N X ; B 14 0 653 718 ; +C 89 ; WX 667 ; N Y ; B 15 0 653 718 ; +C 90 ; WX 611 ; N Z ; B 25 0 586 718 ; +C 91 ; WX 333 ; N bracketleft ; B 63 -196 309 722 ; +C 92 ; WX 278 ; N backslash ; B -33 -19 311 737 ; +C 93 ; WX 333 ; N bracketright ; B 24 -196 270 722 ; +C 94 ; WX 584 ; N asciicircum ; B 62 323 522 698 ; +C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ; +C 96 ; WX 278 ; N quoteleft ; B 69 454 209 727 ; +C 97 ; WX 556 ; N a ; B 29 -14 527 546 ; +C 98 ; WX 611 ; N b ; B 61 -14 578 718 ; +C 99 ; WX 556 ; N c ; B 34 -14 524 546 ; +C 100 ; WX 611 ; N d ; B 34 -14 551 718 ; +C 101 ; WX 556 ; N e ; B 23 -14 528 546 ; +C 102 ; WX 333 ; N f ; B 10 0 318 727 ; L i fi ; L l fl ; +C 103 ; WX 611 ; N g ; B 40 -217 553 546 ; +C 104 ; WX 611 ; N h ; B 65 0 546 718 ; +C 105 ; WX 278 ; N i ; B 69 0 209 725 ; +C 106 ; WX 278 ; N j ; B 3 -214 209 725 ; +C 107 ; WX 556 ; N k ; B 69 0 562 718 ; +C 108 ; WX 278 ; N l ; B 69 0 209 718 ; +C 109 ; WX 889 ; N m ; B 64 0 826 546 ; +C 110 ; WX 611 ; N n ; B 65 0 546 546 ; +C 111 ; WX 611 ; N o ; B 34 -14 578 546 ; +C 112 ; WX 611 ; N p ; B 62 -207 578 546 ; +C 113 ; WX 611 ; N q ; B 34 -207 552 546 ; +C 114 ; WX 389 ; N r ; B 64 0 373 546 ; +C 115 ; WX 556 ; N s ; B 30 -14 519 546 ; +C 116 ; WX 333 ; N t ; B 10 -6 309 676 ; +C 117 ; WX 611 ; N u ; B 66 -14 545 532 ; +C 118 ; WX 556 ; N v ; B 13 0 543 532 ; +C 119 ; WX 778 ; N w ; B 10 0 769 532 ; +C 120 ; WX 556 ; N x ; B 15 0 541 532 ; +C 121 ; WX 556 ; N y ; B 10 -214 539 532 ; +C 122 ; WX 500 ; N z ; B 20 0 480 532 ; +C 123 ; WX 389 ; N braceleft ; B 48 -196 365 722 ; +C 124 ; WX 280 ; N bar ; B 84 -225 196 775 ; +C 125 ; WX 389 ; N braceright ; B 24 -196 341 722 ; +C 126 ; WX 584 ; N asciitilde ; B 61 163 523 343 ; +C 161 ; WX 333 ; N exclamdown ; B 90 -186 244 532 ; +C 162 ; WX 556 ; N cent ; B 34 -118 524 628 ; +C 163 ; WX 556 ; N sterling ; B 28 -16 541 718 ; +C 164 ; WX 167 ; N fraction ; B -170 -19 336 710 ; +C 165 ; WX 556 ; N yen ; B -9 0 565 698 ; +C 166 ; WX 556 ; N florin ; B -10 -210 516 737 ; +C 167 ; WX 556 ; N section ; B 34 -184 522 727 ; +C 168 ; WX 556 ; N currency ; B -3 76 559 636 ; +C 169 ; WX 238 ; N quotesingle ; B 70 447 168 718 ; +C 170 ; WX 500 ; N quotedblleft ; B 64 454 436 727 ; +C 171 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ; +C 172 ; WX 333 ; N guilsinglleft ; B 83 76 250 484 ; +C 173 ; WX 333 ; N guilsinglright ; B 83 76 250 484 ; +C 174 ; WX 611 ; N fi ; B 10 0 542 727 ; +C 175 ; WX 611 ; N fl ; B 10 0 542 727 ; +C 177 ; WX 556 ; N endash ; B 0 227 556 333 ; +C 178 ; WX 556 ; N dagger ; B 36 -171 520 718 ; +C 179 ; WX 556 ; N daggerdbl ; B 36 -171 520 718 ; +C 180 ; WX 278 ; N periodcentered ; B 58 172 220 334 ; +C 182 ; WX 556 ; N paragraph ; B -8 -191 539 700 ; +C 183 ; WX 350 ; N bullet ; B 10 194 340 524 ; +C 184 ; WX 278 ; N quotesinglbase ; B 69 -146 209 127 ; +C 185 ; WX 500 ; N quotedblbase ; B 64 -146 436 127 ; +C 186 ; WX 500 ; N quotedblright ; B 64 445 436 718 ; +C 187 ; WX 556 ; N guillemotright ; B 88 76 468 484 ; +C 188 ; WX 1000 ; N ellipsis ; B 92 0 908 146 ; +C 189 ; WX 1000 ; N perthousand ; B -3 -19 1003 710 ; +C 191 ; WX 611 ; N questiondown ; B 55 -195 551 532 ; +C 193 ; WX 333 ; N grave ; B -23 604 225 750 ; +C 194 ; WX 333 ; N acute ; B 108 604 356 750 ; +C 195 ; WX 333 ; N circumflex ; B -10 604 343 750 ; +C 196 ; WX 333 ; N tilde ; B -17 610 350 737 ; +C 197 ; WX 333 ; N macron ; B -6 604 339 678 ; +C 198 ; WX 333 ; N breve ; B -2 604 335 750 ; +C 199 ; WX 333 ; N dotaccent ; B 104 614 230 729 ; +C 200 ; WX 333 ; N dieresis ; B 6 614 327 729 ; +C 202 ; WX 333 ; N ring ; B 59 568 275 776 ; +C 203 ; WX 333 ; N cedilla ; B 6 -228 245 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B 9 604 486 750 ; +C 206 ; WX 333 ; N ogonek ; B 71 -228 304 0 ; +C 207 ; WX 333 ; N caron ; B -10 604 343 750 ; +C 208 ; WX 1000 ; N emdash ; B 0 227 1000 333 ; +C 225 ; WX 1000 ; N AE ; B 5 0 954 718 ; +C 227 ; WX 370 ; N ordfeminine ; B 22 401 347 737 ; +C 232 ; WX 611 ; N Lslash ; B -20 0 583 718 ; +C 233 ; WX 778 ; N Oslash ; B 33 -27 744 745 ; +C 234 ; WX 1000 ; N OE ; B 37 -19 961 737 ; +C 235 ; WX 365 ; N ordmasculine ; B 6 401 360 737 ; +C 241 ; WX 889 ; N ae ; B 29 -14 858 546 ; +C 245 ; WX 278 ; N dotlessi ; B 69 0 209 532 ; +C 248 ; WX 278 ; N lslash ; B -18 0 296 718 ; +C 249 ; WX 611 ; N oslash ; B 22 -29 589 560 ; +C 250 ; WX 944 ; N oe ; B 34 -14 912 546 ; +C 251 ; WX 611 ; N germandbls ; B 69 -14 579 731 ; +C -1 ; WX 278 ; N Idieresis ; B -21 0 300 915 ; +C -1 ; WX 556 ; N eacute ; B 23 -14 528 750 ; +C -1 ; WX 556 ; N abreve ; B 29 -14 527 750 ; +C -1 ; WX 611 ; N uhungarumlaut ; B 66 -14 625 750 ; +C -1 ; WX 556 ; N ecaron ; B 23 -14 528 750 ; +C -1 ; WX 667 ; N Ydieresis ; B 15 0 653 915 ; +C -1 ; WX 584 ; N divide ; B 40 -42 544 548 ; +C -1 ; WX 667 ; N Yacute ; B 15 0 653 936 ; +C -1 ; WX 722 ; N Acircumflex ; B 20 0 702 936 ; +C -1 ; WX 556 ; N aacute ; B 29 -14 527 750 ; +C -1 ; WX 722 ; N Ucircumflex ; B 72 -19 651 936 ; +C -1 ; WX 556 ; N yacute ; B 10 -214 539 750 ; +C -1 ; WX 556 ; N scommaaccent ; B 30 -228 519 546 ; +C -1 ; WX 556 ; N ecircumflex ; B 23 -14 528 750 ; +C -1 ; WX 722 ; N Uring ; B 72 -19 651 962 ; +C -1 ; WX 722 ; N Udieresis ; B 72 -19 651 915 ; +C -1 ; WX 556 ; N aogonek ; B 29 -224 545 546 ; +C -1 ; WX 722 ; N Uacute ; B 72 -19 651 936 ; +C -1 ; WX 611 ; N uogonek ; B 66 -228 545 532 ; +C -1 ; WX 667 ; N Edieresis ; B 76 0 621 915 ; +C -1 ; WX 722 ; N Dcroat ; B -5 0 685 718 ; +C -1 ; WX 250 ; N commaaccent ; B 64 -228 199 -50 ; +C -1 ; WX 737 ; N copyright ; B -11 -19 749 737 ; +C -1 ; WX 667 ; N Emacron ; B 76 0 621 864 ; +C -1 ; WX 556 ; N ccaron ; B 34 -14 524 750 ; +C -1 ; WX 556 ; N aring ; B 29 -14 527 776 ; +C -1 ; WX 722 ; N Ncommaaccent ; B 69 -228 654 718 ; +C -1 ; WX 278 ; N lacute ; B 69 0 329 936 ; +C -1 ; WX 556 ; N agrave ; B 29 -14 527 750 ; +C -1 ; WX 611 ; N Tcommaaccent ; B 14 -228 598 718 ; +C -1 ; WX 722 ; N Cacute ; B 44 -19 684 936 ; +C -1 ; WX 556 ; N atilde ; B 29 -14 527 737 ; +C -1 ; WX 667 ; N Edotaccent ; B 76 0 621 915 ; +C -1 ; WX 556 ; N scaron ; B 30 -14 519 750 ; +C -1 ; WX 556 ; N scedilla ; B 30 -228 519 546 ; +C -1 ; WX 278 ; N iacute ; B 69 0 329 750 ; +C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ; +C -1 ; WX 722 ; N Rcaron ; B 76 0 677 936 ; +C -1 ; WX 778 ; N Gcommaaccent ; B 44 -228 713 737 ; +C -1 ; WX 611 ; N ucircumflex ; B 66 -14 545 750 ; +C -1 ; WX 556 ; N acircumflex ; B 29 -14 527 750 ; +C -1 ; WX 722 ; N Amacron ; B 20 0 702 864 ; +C -1 ; WX 389 ; N rcaron ; B 18 0 373 750 ; +C -1 ; WX 556 ; N ccedilla ; B 34 -228 524 546 ; +C -1 ; WX 611 ; N Zdotaccent ; B 25 0 586 915 ; +C -1 ; WX 667 ; N Thorn ; B 76 0 627 718 ; +C -1 ; WX 778 ; N Omacron ; B 44 -19 734 864 ; +C -1 ; WX 722 ; N Racute ; B 76 0 677 936 ; +C -1 ; WX 667 ; N Sacute ; B 39 -19 629 936 ; +C -1 ; WX 743 ; N dcaron ; B 34 -14 750 718 ; +C -1 ; WX 722 ; N Umacron ; B 72 -19 651 864 ; +C -1 ; WX 611 ; N uring ; B 66 -14 545 776 ; +C -1 ; WX 333 ; N threebaseior ; B 8 271 326 710 ; +C -1 ; WX 778 ; N Ograve ; B 44 -19 734 936 ; +C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ; +C -1 ; WX 722 ; N Abreve ; B 20 0 702 936 ; +C -1 ; WX 584 ; N multiply ; B 40 1 545 505 ; +C -1 ; WX 611 ; N uacute ; B 66 -14 545 750 ; +C -1 ; WX 611 ; N Tcaron ; B 14 0 598 936 ; +C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ; +C -1 ; WX 556 ; N ydieresis ; B 10 -214 539 729 ; +C -1 ; WX 722 ; N Nacute ; B 69 0 654 936 ; +C -1 ; WX 278 ; N icircumflex ; B -37 0 316 750 ; +C -1 ; WX 667 ; N Ecircumflex ; B 76 0 621 936 ; +C -1 ; WX 556 ; N adieresis ; B 29 -14 527 729 ; +C -1 ; WX 556 ; N edieresis ; B 23 -14 528 729 ; +C -1 ; WX 556 ; N cacute ; B 34 -14 524 750 ; +C -1 ; WX 611 ; N nacute ; B 65 0 546 750 ; +C -1 ; WX 611 ; N umacron ; B 66 -14 545 678 ; +C -1 ; WX 722 ; N Ncaron ; B 69 0 654 936 ; +C -1 ; WX 278 ; N Iacute ; B 64 0 329 936 ; +C -1 ; WX 584 ; N plusminus ; B 40 0 544 506 ; +C -1 ; WX 280 ; N brokenbar ; B 84 -150 196 700 ; +C -1 ; WX 737 ; N registered ; B -11 -19 748 737 ; +C -1 ; WX 778 ; N Gbreve ; B 44 -19 713 936 ; +C -1 ; WX 278 ; N Idotaccent ; B 64 0 214 915 ; +C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ; +C -1 ; WX 667 ; N Egrave ; B 76 0 621 936 ; +C -1 ; WX 389 ; N racute ; B 64 0 384 750 ; +C -1 ; WX 611 ; N omacron ; B 34 -14 578 678 ; +C -1 ; WX 611 ; N Zacute ; B 25 0 586 936 ; +C -1 ; WX 611 ; N Zcaron ; B 25 0 586 936 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ; +C -1 ; WX 722 ; N Eth ; B -5 0 685 718 ; +C -1 ; WX 722 ; N Ccedilla ; B 44 -228 684 737 ; +C -1 ; WX 278 ; N lcommaaccent ; B 69 -228 213 718 ; +C -1 ; WX 389 ; N tcaron ; B 10 -6 421 878 ; +C -1 ; WX 556 ; N eogonek ; B 23 -228 528 546 ; +C -1 ; WX 722 ; N Uogonek ; B 72 -228 651 718 ; +C -1 ; WX 722 ; N Aacute ; B 20 0 702 936 ; +C -1 ; WX 722 ; N Adieresis ; B 20 0 702 915 ; +C -1 ; WX 556 ; N egrave ; B 23 -14 528 750 ; +C -1 ; WX 500 ; N zacute ; B 20 0 480 750 ; +C -1 ; WX 278 ; N iogonek ; B 16 -224 249 725 ; +C -1 ; WX 778 ; N Oacute ; B 44 -19 734 936 ; +C -1 ; WX 611 ; N oacute ; B 34 -14 578 750 ; +C -1 ; WX 556 ; N amacron ; B 29 -14 527 678 ; +C -1 ; WX 556 ; N sacute ; B 30 -14 519 750 ; +C -1 ; WX 278 ; N idieresis ; B -21 0 300 729 ; +C -1 ; WX 778 ; N Ocircumflex ; B 44 -19 734 936 ; +C -1 ; WX 722 ; N Ugrave ; B 72 -19 651 936 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 611 ; N thorn ; B 62 -208 578 718 ; +C -1 ; WX 333 ; N twobaseior ; B 9 283 324 710 ; +C -1 ; WX 778 ; N Odieresis ; B 44 -19 734 915 ; +C -1 ; WX 611 ; N mu ; B 66 -207 545 532 ; +C -1 ; WX 278 ; N igrave ; B -50 0 209 750 ; +C -1 ; WX 611 ; N ohungarumlaut ; B 34 -14 625 750 ; +C -1 ; WX 667 ; N Eogonek ; B 76 -224 639 718 ; +C -1 ; WX 611 ; N dcroat ; B 34 -14 650 718 ; +C -1 ; WX 834 ; N threequarters ; B 16 -19 799 710 ; +C -1 ; WX 667 ; N Scedilla ; B 39 -228 629 737 ; +C -1 ; WX 400 ; N lcaron ; B 69 0 408 718 ; +C -1 ; WX 722 ; N Kcommaaccent ; B 87 -228 722 718 ; +C -1 ; WX 611 ; N Lacute ; B 76 0 583 936 ; +C -1 ; WX 1000 ; N trademark ; B 44 306 956 718 ; +C -1 ; WX 556 ; N edotaccent ; B 23 -14 528 729 ; +C -1 ; WX 278 ; N Igrave ; B -50 0 214 936 ; +C -1 ; WX 278 ; N Imacron ; B -33 0 312 864 ; +C -1 ; WX 611 ; N Lcaron ; B 76 0 583 718 ; +C -1 ; WX 834 ; N onehalf ; B 26 -19 794 710 ; +C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ; +C -1 ; WX 611 ; N ocircumflex ; B 34 -14 578 750 ; +C -1 ; WX 611 ; N ntilde ; B 65 0 546 737 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 72 -19 681 936 ; +C -1 ; WX 667 ; N Eacute ; B 76 0 621 936 ; +C -1 ; WX 556 ; N emacron ; B 23 -14 528 678 ; +C -1 ; WX 611 ; N gbreve ; B 40 -217 553 750 ; +C -1 ; WX 834 ; N onequarter ; B 26 -19 766 710 ; +C -1 ; WX 667 ; N Scaron ; B 39 -19 629 936 ; +C -1 ; WX 667 ; N Scommaaccent ; B 39 -228 629 737 ; +C -1 ; WX 778 ; N Ohungarumlaut ; B 44 -19 734 936 ; +C -1 ; WX 400 ; N degree ; B 57 426 343 712 ; +C -1 ; WX 611 ; N ograve ; B 34 -14 578 750 ; +C -1 ; WX 722 ; N Ccaron ; B 44 -19 684 936 ; +C -1 ; WX 611 ; N ugrave ; B 66 -14 545 750 ; +C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ; +C -1 ; WX 722 ; N Dcaron ; B 76 0 685 936 ; +C -1 ; WX 389 ; N rcommaaccent ; B 64 -228 373 546 ; +C -1 ; WX 722 ; N Ntilde ; B 69 0 654 923 ; +C -1 ; WX 611 ; N otilde ; B 34 -14 578 737 ; +C -1 ; WX 722 ; N Rcommaaccent ; B 76 -228 677 718 ; +C -1 ; WX 611 ; N Lcommaaccent ; B 76 -228 583 718 ; +C -1 ; WX 722 ; N Atilde ; B 20 0 702 923 ; +C -1 ; WX 722 ; N Aogonek ; B 20 -224 742 718 ; +C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ; +C -1 ; WX 778 ; N Otilde ; B 44 -19 734 923 ; +C -1 ; WX 500 ; N zdotaccent ; B 20 0 480 729 ; +C -1 ; WX 667 ; N Ecaron ; B 76 0 621 936 ; +C -1 ; WX 278 ; N Iogonek ; B -11 -228 222 718 ; +C -1 ; WX 556 ; N kcommaaccent ; B 69 -228 562 718 ; +C -1 ; WX 584 ; N minus ; B 40 197 544 309 ; +C -1 ; WX 278 ; N Icircumflex ; B -37 0 316 936 ; +C -1 ; WX 611 ; N ncaron ; B 65 0 546 750 ; +C -1 ; WX 333 ; N tcommaaccent ; B 10 -228 309 676 ; +C -1 ; WX 584 ; N logicalnot ; B 40 108 544 419 ; +C -1 ; WX 611 ; N odieresis ; B 34 -14 578 729 ; +C -1 ; WX 611 ; N udieresis ; B 66 -14 545 729 ; +C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ; +C -1 ; WX 611 ; N gcommaaccent ; B 40 -217 553 850 ; +C -1 ; WX 611 ; N eth ; B 34 -14 578 737 ; +C -1 ; WX 500 ; N zcaron ; B 20 0 480 750 ; +C -1 ; WX 611 ; N ncommaaccent ; B 65 -228 546 546 ; +C -1 ; WX 333 ; N onebaseior ; B 26 283 237 710 ; +C -1 ; WX 278 ; N imacron ; B -8 0 285 678 ; +C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2481 +KPX A C -40 +KPX A Cacute -40 +KPX A Ccaron -40 +KPX A Ccedilla -40 +KPX A G -50 +KPX A Gbreve -50 +KPX A Gcommaaccent -50 +KPX A O -40 +KPX A Oacute -40 +KPX A Ocircumflex -40 +KPX A Odieresis -40 +KPX A Ograve -40 +KPX A Ohungarumlaut -40 +KPX A Omacron -40 +KPX A Oslash -40 +KPX A Otilde -40 +KPX A Q -40 +KPX A T -90 +KPX A Tcaron -90 +KPX A Tcommaaccent -90 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -80 +KPX A W -60 +KPX A Y -110 +KPX A Yacute -110 +KPX A Ydieresis -110 +KPX A u -30 +KPX A uacute -30 +KPX A ucircumflex -30 +KPX A udieresis -30 +KPX A ugrave -30 +KPX A uhungarumlaut -30 +KPX A umacron -30 +KPX A uogonek -30 +KPX A uring -30 +KPX A v -40 +KPX A w -30 +KPX A y -30 +KPX A yacute -30 +KPX A ydieresis -30 +KPX Aacute C -40 +KPX Aacute Cacute -40 +KPX Aacute Ccaron -40 +KPX Aacute Ccedilla -40 +KPX Aacute G -50 +KPX Aacute Gbreve -50 +KPX Aacute Gcommaaccent -50 +KPX Aacute O -40 +KPX Aacute Oacute -40 +KPX Aacute Ocircumflex -40 +KPX Aacute Odieresis -40 +KPX Aacute Ograve -40 +KPX Aacute Ohungarumlaut -40 +KPX Aacute Omacron -40 +KPX Aacute Oslash -40 +KPX Aacute Otilde -40 +KPX Aacute Q -40 +KPX Aacute T -90 +KPX Aacute Tcaron -90 +KPX Aacute Tcommaaccent -90 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -80 +KPX Aacute W -60 +KPX Aacute Y -110 +KPX Aacute Yacute -110 +KPX Aacute Ydieresis -110 +KPX Aacute u -30 +KPX Aacute uacute -30 +KPX Aacute ucircumflex -30 +KPX Aacute udieresis -30 +KPX Aacute ugrave -30 +KPX Aacute uhungarumlaut -30 +KPX Aacute umacron -30 +KPX Aacute uogonek -30 +KPX Aacute uring -30 +KPX Aacute v -40 +KPX Aacute w -30 +KPX Aacute y -30 +KPX Aacute yacute -30 +KPX Aacute ydieresis -30 +KPX Abreve C -40 +KPX Abreve Cacute -40 +KPX Abreve Ccaron -40 +KPX Abreve Ccedilla -40 +KPX Abreve G -50 +KPX Abreve Gbreve -50 +KPX Abreve Gcommaaccent -50 +KPX Abreve O -40 +KPX Abreve Oacute -40 +KPX Abreve Ocircumflex -40 +KPX Abreve Odieresis -40 +KPX Abreve Ograve -40 +KPX Abreve Ohungarumlaut -40 +KPX Abreve Omacron -40 +KPX Abreve Oslash -40 +KPX Abreve Otilde -40 +KPX Abreve Q -40 +KPX Abreve T -90 +KPX Abreve Tcaron -90 +KPX Abreve Tcommaaccent -90 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -80 +KPX Abreve W -60 +KPX Abreve Y -110 +KPX Abreve Yacute -110 +KPX Abreve Ydieresis -110 +KPX Abreve u -30 +KPX Abreve uacute -30 +KPX Abreve ucircumflex -30 +KPX Abreve udieresis -30 +KPX Abreve ugrave -30 +KPX Abreve uhungarumlaut -30 +KPX Abreve umacron -30 +KPX Abreve uogonek -30 +KPX Abreve uring -30 +KPX Abreve v -40 +KPX Abreve w -30 +KPX Abreve y -30 +KPX Abreve yacute -30 +KPX Abreve ydieresis -30 +KPX Acircumflex C -40 +KPX Acircumflex Cacute -40 +KPX Acircumflex Ccaron -40 +KPX Acircumflex Ccedilla -40 +KPX Acircumflex G -50 +KPX Acircumflex Gbreve -50 +KPX Acircumflex Gcommaaccent -50 +KPX Acircumflex O -40 +KPX Acircumflex Oacute -40 +KPX Acircumflex Ocircumflex -40 +KPX Acircumflex Odieresis -40 +KPX Acircumflex Ograve -40 +KPX Acircumflex Ohungarumlaut -40 +KPX Acircumflex Omacron -40 +KPX Acircumflex Oslash -40 +KPX Acircumflex Otilde -40 +KPX Acircumflex Q -40 +KPX Acircumflex T -90 +KPX Acircumflex Tcaron -90 +KPX Acircumflex Tcommaaccent -90 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -80 +KPX Acircumflex W -60 +KPX Acircumflex Y -110 +KPX Acircumflex Yacute -110 +KPX Acircumflex Ydieresis -110 +KPX Acircumflex u -30 +KPX Acircumflex uacute -30 +KPX Acircumflex ucircumflex -30 +KPX Acircumflex udieresis -30 +KPX Acircumflex ugrave -30 +KPX Acircumflex uhungarumlaut -30 +KPX Acircumflex umacron -30 +KPX Acircumflex uogonek -30 +KPX Acircumflex uring -30 +KPX Acircumflex v -40 +KPX Acircumflex w -30 +KPX Acircumflex y -30 +KPX Acircumflex yacute -30 +KPX Acircumflex ydieresis -30 +KPX Adieresis C -40 +KPX Adieresis Cacute -40 +KPX Adieresis Ccaron -40 +KPX Adieresis Ccedilla -40 +KPX Adieresis G -50 +KPX Adieresis Gbreve -50 +KPX Adieresis Gcommaaccent -50 +KPX Adieresis O -40 +KPX Adieresis Oacute -40 +KPX Adieresis Ocircumflex -40 +KPX Adieresis Odieresis -40 +KPX Adieresis Ograve -40 +KPX Adieresis Ohungarumlaut -40 +KPX Adieresis Omacron -40 +KPX Adieresis Oslash -40 +KPX Adieresis Otilde -40 +KPX Adieresis Q -40 +KPX Adieresis T -90 +KPX Adieresis Tcaron -90 +KPX Adieresis Tcommaaccent -90 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -80 +KPX Adieresis W -60 +KPX Adieresis Y -110 +KPX Adieresis Yacute -110 +KPX Adieresis Ydieresis -110 +KPX Adieresis u -30 +KPX Adieresis uacute -30 +KPX Adieresis ucircumflex -30 +KPX Adieresis udieresis -30 +KPX Adieresis ugrave -30 +KPX Adieresis uhungarumlaut -30 +KPX Adieresis umacron -30 +KPX Adieresis uogonek -30 +KPX Adieresis uring -30 +KPX Adieresis v -40 +KPX Adieresis w -30 +KPX Adieresis y -30 +KPX Adieresis yacute -30 +KPX Adieresis ydieresis -30 +KPX Agrave C -40 +KPX Agrave Cacute -40 +KPX Agrave Ccaron -40 +KPX Agrave Ccedilla -40 +KPX Agrave G -50 +KPX Agrave Gbreve -50 +KPX Agrave Gcommaaccent -50 +KPX Agrave O -40 +KPX Agrave Oacute -40 +KPX Agrave Ocircumflex -40 +KPX Agrave Odieresis -40 +KPX Agrave Ograve -40 +KPX Agrave Ohungarumlaut -40 +KPX Agrave Omacron -40 +KPX Agrave Oslash -40 +KPX Agrave Otilde -40 +KPX Agrave Q -40 +KPX Agrave T -90 +KPX Agrave Tcaron -90 +KPX Agrave Tcommaaccent -90 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -80 +KPX Agrave W -60 +KPX Agrave Y -110 +KPX Agrave Yacute -110 +KPX Agrave Ydieresis -110 +KPX Agrave u -30 +KPX Agrave uacute -30 +KPX Agrave ucircumflex -30 +KPX Agrave udieresis -30 +KPX Agrave ugrave -30 +KPX Agrave uhungarumlaut -30 +KPX Agrave umacron -30 +KPX Agrave uogonek -30 +KPX Agrave uring -30 +KPX Agrave v -40 +KPX Agrave w -30 +KPX Agrave y -30 +KPX Agrave yacute -30 +KPX Agrave ydieresis -30 +KPX Amacron C -40 +KPX Amacron Cacute -40 +KPX Amacron Ccaron -40 +KPX Amacron Ccedilla -40 +KPX Amacron G -50 +KPX Amacron Gbreve -50 +KPX Amacron Gcommaaccent -50 +KPX Amacron O -40 +KPX Amacron Oacute -40 +KPX Amacron Ocircumflex -40 +KPX Amacron Odieresis -40 +KPX Amacron Ograve -40 +KPX Amacron Ohungarumlaut -40 +KPX Amacron Omacron -40 +KPX Amacron Oslash -40 +KPX Amacron Otilde -40 +KPX Amacron Q -40 +KPX Amacron T -90 +KPX Amacron Tcaron -90 +KPX Amacron Tcommaaccent -90 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -80 +KPX Amacron W -60 +KPX Amacron Y -110 +KPX Amacron Yacute -110 +KPX Amacron Ydieresis -110 +KPX Amacron u -30 +KPX Amacron uacute -30 +KPX Amacron ucircumflex -30 +KPX Amacron udieresis -30 +KPX Amacron ugrave -30 +KPX Amacron uhungarumlaut -30 +KPX Amacron umacron -30 +KPX Amacron uogonek -30 +KPX Amacron uring -30 +KPX Amacron v -40 +KPX Amacron w -30 +KPX Amacron y -30 +KPX Amacron yacute -30 +KPX Amacron ydieresis -30 +KPX Aogonek C -40 +KPX Aogonek Cacute -40 +KPX Aogonek Ccaron -40 +KPX Aogonek Ccedilla -40 +KPX Aogonek G -50 +KPX Aogonek Gbreve -50 +KPX Aogonek Gcommaaccent -50 +KPX Aogonek O -40 +KPX Aogonek Oacute -40 +KPX Aogonek Ocircumflex -40 +KPX Aogonek Odieresis -40 +KPX Aogonek Ograve -40 +KPX Aogonek Ohungarumlaut -40 +KPX Aogonek Omacron -40 +KPX Aogonek Oslash -40 +KPX Aogonek Otilde -40 +KPX Aogonek Q -40 +KPX Aogonek T -90 +KPX Aogonek Tcaron -90 +KPX Aogonek Tcommaaccent -90 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -80 +KPX Aogonek W -60 +KPX Aogonek Y -110 +KPX Aogonek Yacute -110 +KPX Aogonek Ydieresis -110 +KPX Aogonek u -30 +KPX Aogonek uacute -30 +KPX Aogonek ucircumflex -30 +KPX Aogonek udieresis -30 +KPX Aogonek ugrave -30 +KPX Aogonek uhungarumlaut -30 +KPX Aogonek umacron -30 +KPX Aogonek uogonek -30 +KPX Aogonek uring -30 +KPX Aogonek v -40 +KPX Aogonek w -30 +KPX Aogonek y -30 +KPX Aogonek yacute -30 +KPX Aogonek ydieresis -30 +KPX Aring C -40 +KPX Aring Cacute -40 +KPX Aring Ccaron -40 +KPX Aring Ccedilla -40 +KPX Aring G -50 +KPX Aring Gbreve -50 +KPX Aring Gcommaaccent -50 +KPX Aring O -40 +KPX Aring Oacute -40 +KPX Aring Ocircumflex -40 +KPX Aring Odieresis -40 +KPX Aring Ograve -40 +KPX Aring Ohungarumlaut -40 +KPX Aring Omacron -40 +KPX Aring Oslash -40 +KPX Aring Otilde -40 +KPX Aring Q -40 +KPX Aring T -90 +KPX Aring Tcaron -90 +KPX Aring Tcommaaccent -90 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -80 +KPX Aring W -60 +KPX Aring Y -110 +KPX Aring Yacute -110 +KPX Aring Ydieresis -110 +KPX Aring u -30 +KPX Aring uacute -30 +KPX Aring ucircumflex -30 +KPX Aring udieresis -30 +KPX Aring ugrave -30 +KPX Aring uhungarumlaut -30 +KPX Aring umacron -30 +KPX Aring uogonek -30 +KPX Aring uring -30 +KPX Aring v -40 +KPX Aring w -30 +KPX Aring y -30 +KPX Aring yacute -30 +KPX Aring ydieresis -30 +KPX Atilde C -40 +KPX Atilde Cacute -40 +KPX Atilde Ccaron -40 +KPX Atilde Ccedilla -40 +KPX Atilde G -50 +KPX Atilde Gbreve -50 +KPX Atilde Gcommaaccent -50 +KPX Atilde O -40 +KPX Atilde Oacute -40 +KPX Atilde Ocircumflex -40 +KPX Atilde Odieresis -40 +KPX Atilde Ograve -40 +KPX Atilde Ohungarumlaut -40 +KPX Atilde Omacron -40 +KPX Atilde Oslash -40 +KPX Atilde Otilde -40 +KPX Atilde Q -40 +KPX Atilde T -90 +KPX Atilde Tcaron -90 +KPX Atilde Tcommaaccent -90 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -80 +KPX Atilde W -60 +KPX Atilde Y -110 +KPX Atilde Yacute -110 +KPX Atilde Ydieresis -110 +KPX Atilde u -30 +KPX Atilde uacute -30 +KPX Atilde ucircumflex -30 +KPX Atilde udieresis -30 +KPX Atilde ugrave -30 +KPX Atilde uhungarumlaut -30 +KPX Atilde umacron -30 +KPX Atilde uogonek -30 +KPX Atilde uring -30 +KPX Atilde v -40 +KPX Atilde w -30 +KPX Atilde y -30 +KPX Atilde yacute -30 +KPX Atilde ydieresis -30 +KPX B A -30 +KPX B Aacute -30 +KPX B Abreve -30 +KPX B Acircumflex -30 +KPX B Adieresis -30 +KPX B Agrave -30 +KPX B Amacron -30 +KPX B Aogonek -30 +KPX B Aring -30 +KPX B Atilde -30 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX D A -40 +KPX D Aacute -40 +KPX D Abreve -40 +KPX D Acircumflex -40 +KPX D Adieresis -40 +KPX D Agrave -40 +KPX D Amacron -40 +KPX D Aogonek -40 +KPX D Aring -40 +KPX D Atilde -40 +KPX D V -40 +KPX D W -40 +KPX D Y -70 +KPX D Yacute -70 +KPX D Ydieresis -70 +KPX D comma -30 +KPX D period -30 +KPX Dcaron A -40 +KPX Dcaron Aacute -40 +KPX Dcaron Abreve -40 +KPX Dcaron Acircumflex -40 +KPX Dcaron Adieresis -40 +KPX Dcaron Agrave -40 +KPX Dcaron Amacron -40 +KPX Dcaron Aogonek -40 +KPX Dcaron Aring -40 +KPX Dcaron Atilde -40 +KPX Dcaron V -40 +KPX Dcaron W -40 +KPX Dcaron Y -70 +KPX Dcaron Yacute -70 +KPX Dcaron Ydieresis -70 +KPX Dcaron comma -30 +KPX Dcaron period -30 +KPX Dcroat A -40 +KPX Dcroat Aacute -40 +KPX Dcroat Abreve -40 +KPX Dcroat Acircumflex -40 +KPX Dcroat Adieresis -40 +KPX Dcroat Agrave -40 +KPX Dcroat Amacron -40 +KPX Dcroat Aogonek -40 +KPX Dcroat Aring -40 +KPX Dcroat Atilde -40 +KPX Dcroat V -40 +KPX Dcroat W -40 +KPX Dcroat Y -70 +KPX Dcroat Yacute -70 +KPX Dcroat Ydieresis -70 +KPX Dcroat comma -30 +KPX Dcroat period -30 +KPX F A -80 +KPX F Aacute -80 +KPX F Abreve -80 +KPX F Acircumflex -80 +KPX F Adieresis -80 +KPX F Agrave -80 +KPX F Amacron -80 +KPX F Aogonek -80 +KPX F Aring -80 +KPX F Atilde -80 +KPX F a -20 +KPX F aacute -20 +KPX F abreve -20 +KPX F acircumflex -20 +KPX F adieresis -20 +KPX F agrave -20 +KPX F amacron -20 +KPX F aogonek -20 +KPX F aring -20 +KPX F atilde -20 +KPX F comma -100 +KPX F period -100 +KPX J A -20 +KPX J Aacute -20 +KPX J Abreve -20 +KPX J Acircumflex -20 +KPX J Adieresis -20 +KPX J Agrave -20 +KPX J Amacron -20 +KPX J Aogonek -20 +KPX J Aring -20 +KPX J Atilde -20 +KPX J comma -20 +KPX J period -20 +KPX J u -20 +KPX J uacute -20 +KPX J ucircumflex -20 +KPX J udieresis -20 +KPX J ugrave -20 +KPX J uhungarumlaut -20 +KPX J umacron -20 +KPX J uogonek -20 +KPX J uring -20 +KPX K O -30 +KPX K Oacute -30 +KPX K Ocircumflex -30 +KPX K Odieresis -30 +KPX K Ograve -30 +KPX K Ohungarumlaut -30 +KPX K Omacron -30 +KPX K Oslash -30 +KPX K Otilde -30 +KPX K e -15 +KPX K eacute -15 +KPX K ecaron -15 +KPX K ecircumflex -15 +KPX K edieresis -15 +KPX K edotaccent -15 +KPX K egrave -15 +KPX K emacron -15 +KPX K eogonek -15 +KPX K o -35 +KPX K oacute -35 +KPX K ocircumflex -35 +KPX K odieresis -35 +KPX K ograve -35 +KPX K ohungarumlaut -35 +KPX K omacron -35 +KPX K oslash -35 +KPX K otilde -35 +KPX K u -30 +KPX K uacute -30 +KPX K ucircumflex -30 +KPX K udieresis -30 +KPX K ugrave -30 +KPX K uhungarumlaut -30 +KPX K umacron -30 +KPX K uogonek -30 +KPX K uring -30 +KPX K y -40 +KPX K yacute -40 +KPX K ydieresis -40 +KPX Kcommaaccent O -30 +KPX Kcommaaccent Oacute -30 +KPX Kcommaaccent Ocircumflex -30 +KPX Kcommaaccent Odieresis -30 +KPX Kcommaaccent Ograve -30 +KPX Kcommaaccent Ohungarumlaut -30 +KPX Kcommaaccent Omacron -30 +KPX Kcommaaccent Oslash -30 +KPX Kcommaaccent Otilde -30 +KPX Kcommaaccent e -15 +KPX Kcommaaccent eacute -15 +KPX Kcommaaccent ecaron -15 +KPX Kcommaaccent ecircumflex -15 +KPX Kcommaaccent edieresis -15 +KPX Kcommaaccent edotaccent -15 +KPX Kcommaaccent egrave -15 +KPX Kcommaaccent emacron -15 +KPX Kcommaaccent eogonek -15 +KPX Kcommaaccent o -35 +KPX Kcommaaccent oacute -35 +KPX Kcommaaccent ocircumflex -35 +KPX Kcommaaccent odieresis -35 +KPX Kcommaaccent ograve -35 +KPX Kcommaaccent ohungarumlaut -35 +KPX Kcommaaccent omacron -35 +KPX Kcommaaccent oslash -35 +KPX Kcommaaccent otilde -35 +KPX Kcommaaccent u -30 +KPX Kcommaaccent uacute -30 +KPX Kcommaaccent ucircumflex -30 +KPX Kcommaaccent udieresis -30 +KPX Kcommaaccent ugrave -30 +KPX Kcommaaccent uhungarumlaut -30 +KPX Kcommaaccent umacron -30 +KPX Kcommaaccent uogonek -30 +KPX Kcommaaccent uring -30 +KPX Kcommaaccent y -40 +KPX Kcommaaccent yacute -40 +KPX Kcommaaccent ydieresis -40 +KPX L T -90 +KPX L Tcaron -90 +KPX L Tcommaaccent -90 +KPX L V -110 +KPX L W -80 +KPX L Y -120 +KPX L Yacute -120 +KPX L Ydieresis -120 +KPX L quotedblright -140 +KPX L quoteright -140 +KPX L y -30 +KPX L yacute -30 +KPX L ydieresis -30 +KPX Lacute T -90 +KPX Lacute Tcaron -90 +KPX Lacute Tcommaaccent -90 +KPX Lacute V -110 +KPX Lacute W -80 +KPX Lacute Y -120 +KPX Lacute Yacute -120 +KPX Lacute Ydieresis -120 +KPX Lacute quotedblright -140 +KPX Lacute quoteright -140 +KPX Lacute y -30 +KPX Lacute yacute -30 +KPX Lacute ydieresis -30 +KPX Lcommaaccent T -90 +KPX Lcommaaccent Tcaron -90 +KPX Lcommaaccent Tcommaaccent -90 +KPX Lcommaaccent V -110 +KPX Lcommaaccent W -80 +KPX Lcommaaccent Y -120 +KPX Lcommaaccent Yacute -120 +KPX Lcommaaccent Ydieresis -120 +KPX Lcommaaccent quotedblright -140 +KPX Lcommaaccent quoteright -140 +KPX Lcommaaccent y -30 +KPX Lcommaaccent yacute -30 +KPX Lcommaaccent ydieresis -30 +KPX Lslash T -90 +KPX Lslash Tcaron -90 +KPX Lslash Tcommaaccent -90 +KPX Lslash V -110 +KPX Lslash W -80 +KPX Lslash Y -120 +KPX Lslash Yacute -120 +KPX Lslash Ydieresis -120 +KPX Lslash quotedblright -140 +KPX Lslash quoteright -140 +KPX Lslash y -30 +KPX Lslash yacute -30 +KPX Lslash ydieresis -30 +KPX O A -50 +KPX O Aacute -50 +KPX O Abreve -50 +KPX O Acircumflex -50 +KPX O Adieresis -50 +KPX O Agrave -50 +KPX O Amacron -50 +KPX O Aogonek -50 +KPX O Aring -50 +KPX O Atilde -50 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -50 +KPX O X -50 +KPX O Y -70 +KPX O Yacute -70 +KPX O Ydieresis -70 +KPX O comma -40 +KPX O period -40 +KPX Oacute A -50 +KPX Oacute Aacute -50 +KPX Oacute Abreve -50 +KPX Oacute Acircumflex -50 +KPX Oacute Adieresis -50 +KPX Oacute Agrave -50 +KPX Oacute Amacron -50 +KPX Oacute Aogonek -50 +KPX Oacute Aring -50 +KPX Oacute Atilde -50 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -50 +KPX Oacute X -50 +KPX Oacute Y -70 +KPX Oacute Yacute -70 +KPX Oacute Ydieresis -70 +KPX Oacute comma -40 +KPX Oacute period -40 +KPX Ocircumflex A -50 +KPX Ocircumflex Aacute -50 +KPX Ocircumflex Abreve -50 +KPX Ocircumflex Acircumflex -50 +KPX Ocircumflex Adieresis -50 +KPX Ocircumflex Agrave -50 +KPX Ocircumflex Amacron -50 +KPX Ocircumflex Aogonek -50 +KPX Ocircumflex Aring -50 +KPX Ocircumflex Atilde -50 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -50 +KPX Ocircumflex X -50 +KPX Ocircumflex Y -70 +KPX Ocircumflex Yacute -70 +KPX Ocircumflex Ydieresis -70 +KPX Ocircumflex comma -40 +KPX Ocircumflex period -40 +KPX Odieresis A -50 +KPX Odieresis Aacute -50 +KPX Odieresis Abreve -50 +KPX Odieresis Acircumflex -50 +KPX Odieresis Adieresis -50 +KPX Odieresis Agrave -50 +KPX Odieresis Amacron -50 +KPX Odieresis Aogonek -50 +KPX Odieresis Aring -50 +KPX Odieresis Atilde -50 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -50 +KPX Odieresis X -50 +KPX Odieresis Y -70 +KPX Odieresis Yacute -70 +KPX Odieresis Ydieresis -70 +KPX Odieresis comma -40 +KPX Odieresis period -40 +KPX Ograve A -50 +KPX Ograve Aacute -50 +KPX Ograve Abreve -50 +KPX Ograve Acircumflex -50 +KPX Ograve Adieresis -50 +KPX Ograve Agrave -50 +KPX Ograve Amacron -50 +KPX Ograve Aogonek -50 +KPX Ograve Aring -50 +KPX Ograve Atilde -50 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -50 +KPX Ograve X -50 +KPX Ograve Y -70 +KPX Ograve Yacute -70 +KPX Ograve Ydieresis -70 +KPX Ograve comma -40 +KPX Ograve period -40 +KPX Ohungarumlaut A -50 +KPX Ohungarumlaut Aacute -50 +KPX Ohungarumlaut Abreve -50 +KPX Ohungarumlaut Acircumflex -50 +KPX Ohungarumlaut Adieresis -50 +KPX Ohungarumlaut Agrave -50 +KPX Ohungarumlaut Amacron -50 +KPX Ohungarumlaut Aogonek -50 +KPX Ohungarumlaut Aring -50 +KPX Ohungarumlaut Atilde -50 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -50 +KPX Ohungarumlaut X -50 +KPX Ohungarumlaut Y -70 +KPX Ohungarumlaut Yacute -70 +KPX Ohungarumlaut Ydieresis -70 +KPX Ohungarumlaut comma -40 +KPX Ohungarumlaut period -40 +KPX Omacron A -50 +KPX Omacron Aacute -50 +KPX Omacron Abreve -50 +KPX Omacron Acircumflex -50 +KPX Omacron Adieresis -50 +KPX Omacron Agrave -50 +KPX Omacron Amacron -50 +KPX Omacron Aogonek -50 +KPX Omacron Aring -50 +KPX Omacron Atilde -50 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -50 +KPX Omacron X -50 +KPX Omacron Y -70 +KPX Omacron Yacute -70 +KPX Omacron Ydieresis -70 +KPX Omacron comma -40 +KPX Omacron period -40 +KPX Oslash A -50 +KPX Oslash Aacute -50 +KPX Oslash Abreve -50 +KPX Oslash Acircumflex -50 +KPX Oslash Adieresis -50 +KPX Oslash Agrave -50 +KPX Oslash Amacron -50 +KPX Oslash Aogonek -50 +KPX Oslash Aring -50 +KPX Oslash Atilde -50 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -50 +KPX Oslash X -50 +KPX Oslash Y -70 +KPX Oslash Yacute -70 +KPX Oslash Ydieresis -70 +KPX Oslash comma -40 +KPX Oslash period -40 +KPX Otilde A -50 +KPX Otilde Aacute -50 +KPX Otilde Abreve -50 +KPX Otilde Acircumflex -50 +KPX Otilde Adieresis -50 +KPX Otilde Agrave -50 +KPX Otilde Amacron -50 +KPX Otilde Aogonek -50 +KPX Otilde Aring -50 +KPX Otilde Atilde -50 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -50 +KPX Otilde X -50 +KPX Otilde Y -70 +KPX Otilde Yacute -70 +KPX Otilde Ydieresis -70 +KPX Otilde comma -40 +KPX Otilde period -40 +KPX P A -100 +KPX P Aacute -100 +KPX P Abreve -100 +KPX P Acircumflex -100 +KPX P Adieresis -100 +KPX P Agrave -100 +KPX P Amacron -100 +KPX P Aogonek -100 +KPX P Aring -100 +KPX P Atilde -100 +KPX P a -30 +KPX P aacute -30 +KPX P abreve -30 +KPX P acircumflex -30 +KPX P adieresis -30 +KPX P agrave -30 +KPX P amacron -30 +KPX P aogonek -30 +KPX P aring -30 +KPX P atilde -30 +KPX P comma -120 +KPX P e -30 +KPX P eacute -30 +KPX P ecaron -30 +KPX P ecircumflex -30 +KPX P edieresis -30 +KPX P edotaccent -30 +KPX P egrave -30 +KPX P emacron -30 +KPX P eogonek -30 +KPX P o -40 +KPX P oacute -40 +KPX P ocircumflex -40 +KPX P odieresis -40 +KPX P ograve -40 +KPX P ohungarumlaut -40 +KPX P omacron -40 +KPX P oslash -40 +KPX P otilde -40 +KPX P period -120 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX Q comma 20 +KPX Q period 20 +KPX R O -20 +KPX R Oacute -20 +KPX R Ocircumflex -20 +KPX R Odieresis -20 +KPX R Ograve -20 +KPX R Ohungarumlaut -20 +KPX R Omacron -20 +KPX R Oslash -20 +KPX R Otilde -20 +KPX R T -20 +KPX R Tcaron -20 +KPX R Tcommaaccent -20 +KPX R U -20 +KPX R Uacute -20 +KPX R Ucircumflex -20 +KPX R Udieresis -20 +KPX R Ugrave -20 +KPX R Uhungarumlaut -20 +KPX R Umacron -20 +KPX R Uogonek -20 +KPX R Uring -20 +KPX R V -50 +KPX R W -40 +KPX R Y -50 +KPX R Yacute -50 +KPX R Ydieresis -50 +KPX Racute O -20 +KPX Racute Oacute -20 +KPX Racute Ocircumflex -20 +KPX Racute Odieresis -20 +KPX Racute Ograve -20 +KPX Racute Ohungarumlaut -20 +KPX Racute Omacron -20 +KPX Racute Oslash -20 +KPX Racute Otilde -20 +KPX Racute T -20 +KPX Racute Tcaron -20 +KPX Racute Tcommaaccent -20 +KPX Racute U -20 +KPX Racute Uacute -20 +KPX Racute Ucircumflex -20 +KPX Racute Udieresis -20 +KPX Racute Ugrave -20 +KPX Racute Uhungarumlaut -20 +KPX Racute Umacron -20 +KPX Racute Uogonek -20 +KPX Racute Uring -20 +KPX Racute V -50 +KPX Racute W -40 +KPX Racute Y -50 +KPX Racute Yacute -50 +KPX Racute Ydieresis -50 +KPX Rcaron O -20 +KPX Rcaron Oacute -20 +KPX Rcaron Ocircumflex -20 +KPX Rcaron Odieresis -20 +KPX Rcaron Ograve -20 +KPX Rcaron Ohungarumlaut -20 +KPX Rcaron Omacron -20 +KPX Rcaron Oslash -20 +KPX Rcaron Otilde -20 +KPX Rcaron T -20 +KPX Rcaron Tcaron -20 +KPX Rcaron Tcommaaccent -20 +KPX Rcaron U -20 +KPX Rcaron Uacute -20 +KPX Rcaron Ucircumflex -20 +KPX Rcaron Udieresis -20 +KPX Rcaron Ugrave -20 +KPX Rcaron Uhungarumlaut -20 +KPX Rcaron Umacron -20 +KPX Rcaron Uogonek -20 +KPX Rcaron Uring -20 +KPX Rcaron V -50 +KPX Rcaron W -40 +KPX Rcaron Y -50 +KPX Rcaron Yacute -50 +KPX Rcaron Ydieresis -50 +KPX Rcommaaccent O -20 +KPX Rcommaaccent Oacute -20 +KPX Rcommaaccent Ocircumflex -20 +KPX Rcommaaccent Odieresis -20 +KPX Rcommaaccent Ograve -20 +KPX Rcommaaccent Ohungarumlaut -20 +KPX Rcommaaccent Omacron -20 +KPX Rcommaaccent Oslash -20 +KPX Rcommaaccent Otilde -20 +KPX Rcommaaccent T -20 +KPX Rcommaaccent Tcaron -20 +KPX Rcommaaccent Tcommaaccent -20 +KPX Rcommaaccent U -20 +KPX Rcommaaccent Uacute -20 +KPX Rcommaaccent Ucircumflex -20 +KPX Rcommaaccent Udieresis -20 +KPX Rcommaaccent Ugrave -20 +KPX Rcommaaccent Uhungarumlaut -20 +KPX Rcommaaccent Umacron -20 +KPX Rcommaaccent Uogonek -20 +KPX Rcommaaccent Uring -20 +KPX Rcommaaccent V -50 +KPX Rcommaaccent W -40 +KPX Rcommaaccent Y -50 +KPX Rcommaaccent Yacute -50 +KPX Rcommaaccent Ydieresis -50 +KPX T A -90 +KPX T Aacute -90 +KPX T Abreve -90 +KPX T Acircumflex -90 +KPX T Adieresis -90 +KPX T Agrave -90 +KPX T Amacron -90 +KPX T Aogonek -90 +KPX T Aring -90 +KPX T Atilde -90 +KPX T O -40 +KPX T Oacute -40 +KPX T Ocircumflex -40 +KPX T Odieresis -40 +KPX T Ograve -40 +KPX T Ohungarumlaut -40 +KPX T Omacron -40 +KPX T Oslash -40 +KPX T Otilde -40 +KPX T a -80 +KPX T aacute -80 +KPX T abreve -80 +KPX T acircumflex -80 +KPX T adieresis -80 +KPX T agrave -80 +KPX T amacron -80 +KPX T aogonek -80 +KPX T aring -80 +KPX T atilde -80 +KPX T colon -40 +KPX T comma -80 +KPX T e -60 +KPX T eacute -60 +KPX T ecaron -60 +KPX T ecircumflex -60 +KPX T edieresis -60 +KPX T edotaccent -60 +KPX T egrave -60 +KPX T emacron -60 +KPX T eogonek -60 +KPX T hyphen -120 +KPX T o -80 +KPX T oacute -80 +KPX T ocircumflex -80 +KPX T odieresis -80 +KPX T ograve -80 +KPX T ohungarumlaut -80 +KPX T omacron -80 +KPX T oslash -80 +KPX T otilde -80 +KPX T period -80 +KPX T r -80 +KPX T racute -80 +KPX T rcommaaccent -80 +KPX T semicolon -40 +KPX T u -90 +KPX T uacute -90 +KPX T ucircumflex -90 +KPX T udieresis -90 +KPX T ugrave -90 +KPX T uhungarumlaut -90 +KPX T umacron -90 +KPX T uogonek -90 +KPX T uring -90 +KPX T w -60 +KPX T y -60 +KPX T yacute -60 +KPX T ydieresis -60 +KPX Tcaron A -90 +KPX Tcaron Aacute -90 +KPX Tcaron Abreve -90 +KPX Tcaron Acircumflex -90 +KPX Tcaron Adieresis -90 +KPX Tcaron Agrave -90 +KPX Tcaron Amacron -90 +KPX Tcaron Aogonek -90 +KPX Tcaron Aring -90 +KPX Tcaron Atilde -90 +KPX Tcaron O -40 +KPX Tcaron Oacute -40 +KPX Tcaron Ocircumflex -40 +KPX Tcaron Odieresis -40 +KPX Tcaron Ograve -40 +KPX Tcaron Ohungarumlaut -40 +KPX Tcaron Omacron -40 +KPX Tcaron Oslash -40 +KPX Tcaron Otilde -40 +KPX Tcaron a -80 +KPX Tcaron aacute -80 +KPX Tcaron abreve -80 +KPX Tcaron acircumflex -80 +KPX Tcaron adieresis -80 +KPX Tcaron agrave -80 +KPX Tcaron amacron -80 +KPX Tcaron aogonek -80 +KPX Tcaron aring -80 +KPX Tcaron atilde -80 +KPX Tcaron colon -40 +KPX Tcaron comma -80 +KPX Tcaron e -60 +KPX Tcaron eacute -60 +KPX Tcaron ecaron -60 +KPX Tcaron ecircumflex -60 +KPX Tcaron edieresis -60 +KPX Tcaron edotaccent -60 +KPX Tcaron egrave -60 +KPX Tcaron emacron -60 +KPX Tcaron eogonek -60 +KPX Tcaron hyphen -120 +KPX Tcaron o -80 +KPX Tcaron oacute -80 +KPX Tcaron ocircumflex -80 +KPX Tcaron odieresis -80 +KPX Tcaron ograve -80 +KPX Tcaron ohungarumlaut -80 +KPX Tcaron omacron -80 +KPX Tcaron oslash -80 +KPX Tcaron otilde -80 +KPX Tcaron period -80 +KPX Tcaron r -80 +KPX Tcaron racute -80 +KPX Tcaron rcommaaccent -80 +KPX Tcaron semicolon -40 +KPX Tcaron u -90 +KPX Tcaron uacute -90 +KPX Tcaron ucircumflex -90 +KPX Tcaron udieresis -90 +KPX Tcaron ugrave -90 +KPX Tcaron uhungarumlaut -90 +KPX Tcaron umacron -90 +KPX Tcaron uogonek -90 +KPX Tcaron uring -90 +KPX Tcaron w -60 +KPX Tcaron y -60 +KPX Tcaron yacute -60 +KPX Tcaron ydieresis -60 +KPX Tcommaaccent A -90 +KPX Tcommaaccent Aacute -90 +KPX Tcommaaccent Abreve -90 +KPX Tcommaaccent Acircumflex -90 +KPX Tcommaaccent Adieresis -90 +KPX Tcommaaccent Agrave -90 +KPX Tcommaaccent Amacron -90 +KPX Tcommaaccent Aogonek -90 +KPX Tcommaaccent Aring -90 +KPX Tcommaaccent Atilde -90 +KPX Tcommaaccent O -40 +KPX Tcommaaccent Oacute -40 +KPX Tcommaaccent Ocircumflex -40 +KPX Tcommaaccent Odieresis -40 +KPX Tcommaaccent Ograve -40 +KPX Tcommaaccent Ohungarumlaut -40 +KPX Tcommaaccent Omacron -40 +KPX Tcommaaccent Oslash -40 +KPX Tcommaaccent Otilde -40 +KPX Tcommaaccent a -80 +KPX Tcommaaccent aacute -80 +KPX Tcommaaccent abreve -80 +KPX Tcommaaccent acircumflex -80 +KPX Tcommaaccent adieresis -80 +KPX Tcommaaccent agrave -80 +KPX Tcommaaccent amacron -80 +KPX Tcommaaccent aogonek -80 +KPX Tcommaaccent aring -80 +KPX Tcommaaccent atilde -80 +KPX Tcommaaccent colon -40 +KPX Tcommaaccent comma -80 +KPX Tcommaaccent e -60 +KPX Tcommaaccent eacute -60 +KPX Tcommaaccent ecaron -60 +KPX Tcommaaccent ecircumflex -60 +KPX Tcommaaccent edieresis -60 +KPX Tcommaaccent edotaccent -60 +KPX Tcommaaccent egrave -60 +KPX Tcommaaccent emacron -60 +KPX Tcommaaccent eogonek -60 +KPX Tcommaaccent hyphen -120 +KPX Tcommaaccent o -80 +KPX Tcommaaccent oacute -80 +KPX Tcommaaccent ocircumflex -80 +KPX Tcommaaccent odieresis -80 +KPX Tcommaaccent ograve -80 +KPX Tcommaaccent ohungarumlaut -80 +KPX Tcommaaccent omacron -80 +KPX Tcommaaccent oslash -80 +KPX Tcommaaccent otilde -80 +KPX Tcommaaccent period -80 +KPX Tcommaaccent r -80 +KPX Tcommaaccent racute -80 +KPX Tcommaaccent rcommaaccent -80 +KPX Tcommaaccent semicolon -40 +KPX Tcommaaccent u -90 +KPX Tcommaaccent uacute -90 +KPX Tcommaaccent ucircumflex -90 +KPX Tcommaaccent udieresis -90 +KPX Tcommaaccent ugrave -90 +KPX Tcommaaccent uhungarumlaut -90 +KPX Tcommaaccent umacron -90 +KPX Tcommaaccent uogonek -90 +KPX Tcommaaccent uring -90 +KPX Tcommaaccent w -60 +KPX Tcommaaccent y -60 +KPX Tcommaaccent yacute -60 +KPX Tcommaaccent ydieresis -60 +KPX U A -50 +KPX U Aacute -50 +KPX U Abreve -50 +KPX U Acircumflex -50 +KPX U Adieresis -50 +KPX U Agrave -50 +KPX U Amacron -50 +KPX U Aogonek -50 +KPX U Aring -50 +KPX U Atilde -50 +KPX U comma -30 +KPX U period -30 +KPX Uacute A -50 +KPX Uacute Aacute -50 +KPX Uacute Abreve -50 +KPX Uacute Acircumflex -50 +KPX Uacute Adieresis -50 +KPX Uacute Agrave -50 +KPX Uacute Amacron -50 +KPX Uacute Aogonek -50 +KPX Uacute Aring -50 +KPX Uacute Atilde -50 +KPX Uacute comma -30 +KPX Uacute period -30 +KPX Ucircumflex A -50 +KPX Ucircumflex Aacute -50 +KPX Ucircumflex Abreve -50 +KPX Ucircumflex Acircumflex -50 +KPX Ucircumflex Adieresis -50 +KPX Ucircumflex Agrave -50 +KPX Ucircumflex Amacron -50 +KPX Ucircumflex Aogonek -50 +KPX Ucircumflex Aring -50 +KPX Ucircumflex Atilde -50 +KPX Ucircumflex comma -30 +KPX Ucircumflex period -30 +KPX Udieresis A -50 +KPX Udieresis Aacute -50 +KPX Udieresis Abreve -50 +KPX Udieresis Acircumflex -50 +KPX Udieresis Adieresis -50 +KPX Udieresis Agrave -50 +KPX Udieresis Amacron -50 +KPX Udieresis Aogonek -50 +KPX Udieresis Aring -50 +KPX Udieresis Atilde -50 +KPX Udieresis comma -30 +KPX Udieresis period -30 +KPX Ugrave A -50 +KPX Ugrave Aacute -50 +KPX Ugrave Abreve -50 +KPX Ugrave Acircumflex -50 +KPX Ugrave Adieresis -50 +KPX Ugrave Agrave -50 +KPX Ugrave Amacron -50 +KPX Ugrave Aogonek -50 +KPX Ugrave Aring -50 +KPX Ugrave Atilde -50 +KPX Ugrave comma -30 +KPX Ugrave period -30 +KPX Uhungarumlaut A -50 +KPX Uhungarumlaut Aacute -50 +KPX Uhungarumlaut Abreve -50 +KPX Uhungarumlaut Acircumflex -50 +KPX Uhungarumlaut Adieresis -50 +KPX Uhungarumlaut Agrave -50 +KPX Uhungarumlaut Amacron -50 +KPX Uhungarumlaut Aogonek -50 +KPX Uhungarumlaut Aring -50 +KPX Uhungarumlaut Atilde -50 +KPX Uhungarumlaut comma -30 +KPX Uhungarumlaut period -30 +KPX Umacron A -50 +KPX Umacron Aacute -50 +KPX Umacron Abreve -50 +KPX Umacron Acircumflex -50 +KPX Umacron Adieresis -50 +KPX Umacron Agrave -50 +KPX Umacron Amacron -50 +KPX Umacron Aogonek -50 +KPX Umacron Aring -50 +KPX Umacron Atilde -50 +KPX Umacron comma -30 +KPX Umacron period -30 +KPX Uogonek A -50 +KPX Uogonek Aacute -50 +KPX Uogonek Abreve -50 +KPX Uogonek Acircumflex -50 +KPX Uogonek Adieresis -50 +KPX Uogonek Agrave -50 +KPX Uogonek Amacron -50 +KPX Uogonek Aogonek -50 +KPX Uogonek Aring -50 +KPX Uogonek Atilde -50 +KPX Uogonek comma -30 +KPX Uogonek period -30 +KPX Uring A -50 +KPX Uring Aacute -50 +KPX Uring Abreve -50 +KPX Uring Acircumflex -50 +KPX Uring Adieresis -50 +KPX Uring Agrave -50 +KPX Uring Amacron -50 +KPX Uring Aogonek -50 +KPX Uring Aring -50 +KPX Uring Atilde -50 +KPX Uring comma -30 +KPX Uring period -30 +KPX V A -80 +KPX V Aacute -80 +KPX V Abreve -80 +KPX V Acircumflex -80 +KPX V Adieresis -80 +KPX V Agrave -80 +KPX V Amacron -80 +KPX V Aogonek -80 +KPX V Aring -80 +KPX V Atilde -80 +KPX V G -50 +KPX V Gbreve -50 +KPX V Gcommaaccent -50 +KPX V O -50 +KPX V Oacute -50 +KPX V Ocircumflex -50 +KPX V Odieresis -50 +KPX V Ograve -50 +KPX V Ohungarumlaut -50 +KPX V Omacron -50 +KPX V Oslash -50 +KPX V Otilde -50 +KPX V a -60 +KPX V aacute -60 +KPX V abreve -60 +KPX V acircumflex -60 +KPX V adieresis -60 +KPX V agrave -60 +KPX V amacron -60 +KPX V aogonek -60 +KPX V aring -60 +KPX V atilde -60 +KPX V colon -40 +KPX V comma -120 +KPX V e -50 +KPX V eacute -50 +KPX V ecaron -50 +KPX V ecircumflex -50 +KPX V edieresis -50 +KPX V edotaccent -50 +KPX V egrave -50 +KPX V emacron -50 +KPX V eogonek -50 +KPX V hyphen -80 +KPX V o -90 +KPX V oacute -90 +KPX V ocircumflex -90 +KPX V odieresis -90 +KPX V ograve -90 +KPX V ohungarumlaut -90 +KPX V omacron -90 +KPX V oslash -90 +KPX V otilde -90 +KPX V period -120 +KPX V semicolon -40 +KPX V u -60 +KPX V uacute -60 +KPX V ucircumflex -60 +KPX V udieresis -60 +KPX V ugrave -60 +KPX V uhungarumlaut -60 +KPX V umacron -60 +KPX V uogonek -60 +KPX V uring -60 +KPX W A -60 +KPX W Aacute -60 +KPX W Abreve -60 +KPX W Acircumflex -60 +KPX W Adieresis -60 +KPX W Agrave -60 +KPX W Amacron -60 +KPX W Aogonek -60 +KPX W Aring -60 +KPX W Atilde -60 +KPX W O -20 +KPX W Oacute -20 +KPX W Ocircumflex -20 +KPX W Odieresis -20 +KPX W Ograve -20 +KPX W Ohungarumlaut -20 +KPX W Omacron -20 +KPX W Oslash -20 +KPX W Otilde -20 +KPX W a -40 +KPX W aacute -40 +KPX W abreve -40 +KPX W acircumflex -40 +KPX W adieresis -40 +KPX W agrave -40 +KPX W amacron -40 +KPX W aogonek -40 +KPX W aring -40 +KPX W atilde -40 +KPX W colon -10 +KPX W comma -80 +KPX W e -35 +KPX W eacute -35 +KPX W ecaron -35 +KPX W ecircumflex -35 +KPX W edieresis -35 +KPX W edotaccent -35 +KPX W egrave -35 +KPX W emacron -35 +KPX W eogonek -35 +KPX W hyphen -40 +KPX W o -60 +KPX W oacute -60 +KPX W ocircumflex -60 +KPX W odieresis -60 +KPX W ograve -60 +KPX W ohungarumlaut -60 +KPX W omacron -60 +KPX W oslash -60 +KPX W otilde -60 +KPX W period -80 +KPX W semicolon -10 +KPX W u -45 +KPX W uacute -45 +KPX W ucircumflex -45 +KPX W udieresis -45 +KPX W ugrave -45 +KPX W uhungarumlaut -45 +KPX W umacron -45 +KPX W uogonek -45 +KPX W uring -45 +KPX W y -20 +KPX W yacute -20 +KPX W ydieresis -20 +KPX Y A -110 +KPX Y Aacute -110 +KPX Y Abreve -110 +KPX Y Acircumflex -110 +KPX Y Adieresis -110 +KPX Y Agrave -110 +KPX Y Amacron -110 +KPX Y Aogonek -110 +KPX Y Aring -110 +KPX Y Atilde -110 +KPX Y O -70 +KPX Y Oacute -70 +KPX Y Ocircumflex -70 +KPX Y Odieresis -70 +KPX Y Ograve -70 +KPX Y Ohungarumlaut -70 +KPX Y Omacron -70 +KPX Y Oslash -70 +KPX Y Otilde -70 +KPX Y a -90 +KPX Y aacute -90 +KPX Y abreve -90 +KPX Y acircumflex -90 +KPX Y adieresis -90 +KPX Y agrave -90 +KPX Y amacron -90 +KPX Y aogonek -90 +KPX Y aring -90 +KPX Y atilde -90 +KPX Y colon -50 +KPX Y comma -100 +KPX Y e -80 +KPX Y eacute -80 +KPX Y ecaron -80 +KPX Y ecircumflex -80 +KPX Y edieresis -80 +KPX Y edotaccent -80 +KPX Y egrave -80 +KPX Y emacron -80 +KPX Y eogonek -80 +KPX Y o -100 +KPX Y oacute -100 +KPX Y ocircumflex -100 +KPX Y odieresis -100 +KPX Y ograve -100 +KPX Y ohungarumlaut -100 +KPX Y omacron -100 +KPX Y oslash -100 +KPX Y otilde -100 +KPX Y period -100 +KPX Y semicolon -50 +KPX Y u -100 +KPX Y uacute -100 +KPX Y ucircumflex -100 +KPX Y udieresis -100 +KPX Y ugrave -100 +KPX Y uhungarumlaut -100 +KPX Y umacron -100 +KPX Y uogonek -100 +KPX Y uring -100 +KPX Yacute A -110 +KPX Yacute Aacute -110 +KPX Yacute Abreve -110 +KPX Yacute Acircumflex -110 +KPX Yacute Adieresis -110 +KPX Yacute Agrave -110 +KPX Yacute Amacron -110 +KPX Yacute Aogonek -110 +KPX Yacute Aring -110 +KPX Yacute Atilde -110 +KPX Yacute O -70 +KPX Yacute Oacute -70 +KPX Yacute Ocircumflex -70 +KPX Yacute Odieresis -70 +KPX Yacute Ograve -70 +KPX Yacute Ohungarumlaut -70 +KPX Yacute Omacron -70 +KPX Yacute Oslash -70 +KPX Yacute Otilde -70 +KPX Yacute a -90 +KPX Yacute aacute -90 +KPX Yacute abreve -90 +KPX Yacute acircumflex -90 +KPX Yacute adieresis -90 +KPX Yacute agrave -90 +KPX Yacute amacron -90 +KPX Yacute aogonek -90 +KPX Yacute aring -90 +KPX Yacute atilde -90 +KPX Yacute colon -50 +KPX Yacute comma -100 +KPX Yacute e -80 +KPX Yacute eacute -80 +KPX Yacute ecaron -80 +KPX Yacute ecircumflex -80 +KPX Yacute edieresis -80 +KPX Yacute edotaccent -80 +KPX Yacute egrave -80 +KPX Yacute emacron -80 +KPX Yacute eogonek -80 +KPX Yacute o -100 +KPX Yacute oacute -100 +KPX Yacute ocircumflex -100 +KPX Yacute odieresis -100 +KPX Yacute ograve -100 +KPX Yacute ohungarumlaut -100 +KPX Yacute omacron -100 +KPX Yacute oslash -100 +KPX Yacute otilde -100 +KPX Yacute period -100 +KPX Yacute semicolon -50 +KPX Yacute u -100 +KPX Yacute uacute -100 +KPX Yacute ucircumflex -100 +KPX Yacute udieresis -100 +KPX Yacute ugrave -100 +KPX Yacute uhungarumlaut -100 +KPX Yacute umacron -100 +KPX Yacute uogonek -100 +KPX Yacute uring -100 +KPX Ydieresis A -110 +KPX Ydieresis Aacute -110 +KPX Ydieresis Abreve -110 +KPX Ydieresis Acircumflex -110 +KPX Ydieresis Adieresis -110 +KPX Ydieresis Agrave -110 +KPX Ydieresis Amacron -110 +KPX Ydieresis Aogonek -110 +KPX Ydieresis Aring -110 +KPX Ydieresis Atilde -110 +KPX Ydieresis O -70 +KPX Ydieresis Oacute -70 +KPX Ydieresis Ocircumflex -70 +KPX Ydieresis Odieresis -70 +KPX Ydieresis Ograve -70 +KPX Ydieresis Ohungarumlaut -70 +KPX Ydieresis Omacron -70 +KPX Ydieresis Oslash -70 +KPX Ydieresis Otilde -70 +KPX Ydieresis a -90 +KPX Ydieresis aacute -90 +KPX Ydieresis abreve -90 +KPX Ydieresis acircumflex -90 +KPX Ydieresis adieresis -90 +KPX Ydieresis agrave -90 +KPX Ydieresis amacron -90 +KPX Ydieresis aogonek -90 +KPX Ydieresis aring -90 +KPX Ydieresis atilde -90 +KPX Ydieresis colon -50 +KPX Ydieresis comma -100 +KPX Ydieresis e -80 +KPX Ydieresis eacute -80 +KPX Ydieresis ecaron -80 +KPX Ydieresis ecircumflex -80 +KPX Ydieresis edieresis -80 +KPX Ydieresis edotaccent -80 +KPX Ydieresis egrave -80 +KPX Ydieresis emacron -80 +KPX Ydieresis eogonek -80 +KPX Ydieresis o -100 +KPX Ydieresis oacute -100 +KPX Ydieresis ocircumflex -100 +KPX Ydieresis odieresis -100 +KPX Ydieresis ograve -100 +KPX Ydieresis ohungarumlaut -100 +KPX Ydieresis omacron -100 +KPX Ydieresis oslash -100 +KPX Ydieresis otilde -100 +KPX Ydieresis period -100 +KPX Ydieresis semicolon -50 +KPX Ydieresis u -100 +KPX Ydieresis uacute -100 +KPX Ydieresis ucircumflex -100 +KPX Ydieresis udieresis -100 +KPX Ydieresis ugrave -100 +KPX Ydieresis uhungarumlaut -100 +KPX Ydieresis umacron -100 +KPX Ydieresis uogonek -100 +KPX Ydieresis uring -100 +KPX a g -10 +KPX a gbreve -10 +KPX a gcommaaccent -10 +KPX a v -15 +KPX a w -15 +KPX a y -20 +KPX a yacute -20 +KPX a ydieresis -20 +KPX aacute g -10 +KPX aacute gbreve -10 +KPX aacute gcommaaccent -10 +KPX aacute v -15 +KPX aacute w -15 +KPX aacute y -20 +KPX aacute yacute -20 +KPX aacute ydieresis -20 +KPX abreve g -10 +KPX abreve gbreve -10 +KPX abreve gcommaaccent -10 +KPX abreve v -15 +KPX abreve w -15 +KPX abreve y -20 +KPX abreve yacute -20 +KPX abreve ydieresis -20 +KPX acircumflex g -10 +KPX acircumflex gbreve -10 +KPX acircumflex gcommaaccent -10 +KPX acircumflex v -15 +KPX acircumflex w -15 +KPX acircumflex y -20 +KPX acircumflex yacute -20 +KPX acircumflex ydieresis -20 +KPX adieresis g -10 +KPX adieresis gbreve -10 +KPX adieresis gcommaaccent -10 +KPX adieresis v -15 +KPX adieresis w -15 +KPX adieresis y -20 +KPX adieresis yacute -20 +KPX adieresis ydieresis -20 +KPX agrave g -10 +KPX agrave gbreve -10 +KPX agrave gcommaaccent -10 +KPX agrave v -15 +KPX agrave w -15 +KPX agrave y -20 +KPX agrave yacute -20 +KPX agrave ydieresis -20 +KPX amacron g -10 +KPX amacron gbreve -10 +KPX amacron gcommaaccent -10 +KPX amacron v -15 +KPX amacron w -15 +KPX amacron y -20 +KPX amacron yacute -20 +KPX amacron ydieresis -20 +KPX aogonek g -10 +KPX aogonek gbreve -10 +KPX aogonek gcommaaccent -10 +KPX aogonek v -15 +KPX aogonek w -15 +KPX aogonek y -20 +KPX aogonek yacute -20 +KPX aogonek ydieresis -20 +KPX aring g -10 +KPX aring gbreve -10 +KPX aring gcommaaccent -10 +KPX aring v -15 +KPX aring w -15 +KPX aring y -20 +KPX aring yacute -20 +KPX aring ydieresis -20 +KPX atilde g -10 +KPX atilde gbreve -10 +KPX atilde gcommaaccent -10 +KPX atilde v -15 +KPX atilde w -15 +KPX atilde y -20 +KPX atilde yacute -20 +KPX atilde ydieresis -20 +KPX b l -10 +KPX b lacute -10 +KPX b lcommaaccent -10 +KPX b lslash -10 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX b v -20 +KPX b y -20 +KPX b yacute -20 +KPX b ydieresis -20 +KPX c h -10 +KPX c k -20 +KPX c kcommaaccent -20 +KPX c l -20 +KPX c lacute -20 +KPX c lcommaaccent -20 +KPX c lslash -20 +KPX c y -10 +KPX c yacute -10 +KPX c ydieresis -10 +KPX cacute h -10 +KPX cacute k -20 +KPX cacute kcommaaccent -20 +KPX cacute l -20 +KPX cacute lacute -20 +KPX cacute lcommaaccent -20 +KPX cacute lslash -20 +KPX cacute y -10 +KPX cacute yacute -10 +KPX cacute ydieresis -10 +KPX ccaron h -10 +KPX ccaron k -20 +KPX ccaron kcommaaccent -20 +KPX ccaron l -20 +KPX ccaron lacute -20 +KPX ccaron lcommaaccent -20 +KPX ccaron lslash -20 +KPX ccaron y -10 +KPX ccaron yacute -10 +KPX ccaron ydieresis -10 +KPX ccedilla h -10 +KPX ccedilla k -20 +KPX ccedilla kcommaaccent -20 +KPX ccedilla l -20 +KPX ccedilla lacute -20 +KPX ccedilla lcommaaccent -20 +KPX ccedilla lslash -20 +KPX ccedilla y -10 +KPX ccedilla yacute -10 +KPX ccedilla ydieresis -10 +KPX colon space -40 +KPX comma quotedblright -120 +KPX comma quoteright -120 +KPX comma space -40 +KPX d d -10 +KPX d dcroat -10 +KPX d v -15 +KPX d w -15 +KPX d y -15 +KPX d yacute -15 +KPX d ydieresis -15 +KPX dcroat d -10 +KPX dcroat dcroat -10 +KPX dcroat v -15 +KPX dcroat w -15 +KPX dcroat y -15 +KPX dcroat yacute -15 +KPX dcroat ydieresis -15 +KPX e comma 10 +KPX e period 20 +KPX e v -15 +KPX e w -15 +KPX e x -15 +KPX e y -15 +KPX e yacute -15 +KPX e ydieresis -15 +KPX eacute comma 10 +KPX eacute period 20 +KPX eacute v -15 +KPX eacute w -15 +KPX eacute x -15 +KPX eacute y -15 +KPX eacute yacute -15 +KPX eacute ydieresis -15 +KPX ecaron comma 10 +KPX ecaron period 20 +KPX ecaron v -15 +KPX ecaron w -15 +KPX ecaron x -15 +KPX ecaron y -15 +KPX ecaron yacute -15 +KPX ecaron ydieresis -15 +KPX ecircumflex comma 10 +KPX ecircumflex period 20 +KPX ecircumflex v -15 +KPX ecircumflex w -15 +KPX ecircumflex x -15 +KPX ecircumflex y -15 +KPX ecircumflex yacute -15 +KPX ecircumflex ydieresis -15 +KPX edieresis comma 10 +KPX edieresis period 20 +KPX edieresis v -15 +KPX edieresis w -15 +KPX edieresis x -15 +KPX edieresis y -15 +KPX edieresis yacute -15 +KPX edieresis ydieresis -15 +KPX edotaccent comma 10 +KPX edotaccent period 20 +KPX edotaccent v -15 +KPX edotaccent w -15 +KPX edotaccent x -15 +KPX edotaccent y -15 +KPX edotaccent yacute -15 +KPX edotaccent ydieresis -15 +KPX egrave comma 10 +KPX egrave period 20 +KPX egrave v -15 +KPX egrave w -15 +KPX egrave x -15 +KPX egrave y -15 +KPX egrave yacute -15 +KPX egrave ydieresis -15 +KPX emacron comma 10 +KPX emacron period 20 +KPX emacron v -15 +KPX emacron w -15 +KPX emacron x -15 +KPX emacron y -15 +KPX emacron yacute -15 +KPX emacron ydieresis -15 +KPX eogonek comma 10 +KPX eogonek period 20 +KPX eogonek v -15 +KPX eogonek w -15 +KPX eogonek x -15 +KPX eogonek y -15 +KPX eogonek yacute -15 +KPX eogonek ydieresis -15 +KPX f comma -10 +KPX f e -10 +KPX f eacute -10 +KPX f ecaron -10 +KPX f ecircumflex -10 +KPX f edieresis -10 +KPX f edotaccent -10 +KPX f egrave -10 +KPX f emacron -10 +KPX f eogonek -10 +KPX f o -20 +KPX f oacute -20 +KPX f ocircumflex -20 +KPX f odieresis -20 +KPX f ograve -20 +KPX f ohungarumlaut -20 +KPX f omacron -20 +KPX f oslash -20 +KPX f otilde -20 +KPX f period -10 +KPX f quotedblright 30 +KPX f quoteright 30 +KPX g e 10 +KPX g eacute 10 +KPX g ecaron 10 +KPX g ecircumflex 10 +KPX g edieresis 10 +KPX g edotaccent 10 +KPX g egrave 10 +KPX g emacron 10 +KPX g eogonek 10 +KPX g g -10 +KPX g gbreve -10 +KPX g gcommaaccent -10 +KPX gbreve e 10 +KPX gbreve eacute 10 +KPX gbreve ecaron 10 +KPX gbreve ecircumflex 10 +KPX gbreve edieresis 10 +KPX gbreve edotaccent 10 +KPX gbreve egrave 10 +KPX gbreve emacron 10 +KPX gbreve eogonek 10 +KPX gbreve g -10 +KPX gbreve gbreve -10 +KPX gbreve gcommaaccent -10 +KPX gcommaaccent e 10 +KPX gcommaaccent eacute 10 +KPX gcommaaccent ecaron 10 +KPX gcommaaccent ecircumflex 10 +KPX gcommaaccent edieresis 10 +KPX gcommaaccent edotaccent 10 +KPX gcommaaccent egrave 10 +KPX gcommaaccent emacron 10 +KPX gcommaaccent eogonek 10 +KPX gcommaaccent g -10 +KPX gcommaaccent gbreve -10 +KPX gcommaaccent gcommaaccent -10 +KPX h y -20 +KPX h yacute -20 +KPX h ydieresis -20 +KPX k o -15 +KPX k oacute -15 +KPX k ocircumflex -15 +KPX k odieresis -15 +KPX k ograve -15 +KPX k ohungarumlaut -15 +KPX k omacron -15 +KPX k oslash -15 +KPX k otilde -15 +KPX kcommaaccent o -15 +KPX kcommaaccent oacute -15 +KPX kcommaaccent ocircumflex -15 +KPX kcommaaccent odieresis -15 +KPX kcommaaccent ograve -15 +KPX kcommaaccent ohungarumlaut -15 +KPX kcommaaccent omacron -15 +KPX kcommaaccent oslash -15 +KPX kcommaaccent otilde -15 +KPX l w -15 +KPX l y -15 +KPX l yacute -15 +KPX l ydieresis -15 +KPX lacute w -15 +KPX lacute y -15 +KPX lacute yacute -15 +KPX lacute ydieresis -15 +KPX lcommaaccent w -15 +KPX lcommaaccent y -15 +KPX lcommaaccent yacute -15 +KPX lcommaaccent ydieresis -15 +KPX lslash w -15 +KPX lslash y -15 +KPX lslash yacute -15 +KPX lslash ydieresis -15 +KPX m u -20 +KPX m uacute -20 +KPX m ucircumflex -20 +KPX m udieresis -20 +KPX m ugrave -20 +KPX m uhungarumlaut -20 +KPX m umacron -20 +KPX m uogonek -20 +KPX m uring -20 +KPX m y -30 +KPX m yacute -30 +KPX m ydieresis -30 +KPX n u -10 +KPX n uacute -10 +KPX n ucircumflex -10 +KPX n udieresis -10 +KPX n ugrave -10 +KPX n uhungarumlaut -10 +KPX n umacron -10 +KPX n uogonek -10 +KPX n uring -10 +KPX n v -40 +KPX n y -20 +KPX n yacute -20 +KPX n ydieresis -20 +KPX nacute u -10 +KPX nacute uacute -10 +KPX nacute ucircumflex -10 +KPX nacute udieresis -10 +KPX nacute ugrave -10 +KPX nacute uhungarumlaut -10 +KPX nacute umacron -10 +KPX nacute uogonek -10 +KPX nacute uring -10 +KPX nacute v -40 +KPX nacute y -20 +KPX nacute yacute -20 +KPX nacute ydieresis -20 +KPX ncaron u -10 +KPX ncaron uacute -10 +KPX ncaron ucircumflex -10 +KPX ncaron udieresis -10 +KPX ncaron ugrave -10 +KPX ncaron uhungarumlaut -10 +KPX ncaron umacron -10 +KPX ncaron uogonek -10 +KPX ncaron uring -10 +KPX ncaron v -40 +KPX ncaron y -20 +KPX ncaron yacute -20 +KPX ncaron ydieresis -20 +KPX ncommaaccent u -10 +KPX ncommaaccent uacute -10 +KPX ncommaaccent ucircumflex -10 +KPX ncommaaccent udieresis -10 +KPX ncommaaccent ugrave -10 +KPX ncommaaccent uhungarumlaut -10 +KPX ncommaaccent umacron -10 +KPX ncommaaccent uogonek -10 +KPX ncommaaccent uring -10 +KPX ncommaaccent v -40 +KPX ncommaaccent y -20 +KPX ncommaaccent yacute -20 +KPX ncommaaccent ydieresis -20 +KPX ntilde u -10 +KPX ntilde uacute -10 +KPX ntilde ucircumflex -10 +KPX ntilde udieresis -10 +KPX ntilde ugrave -10 +KPX ntilde uhungarumlaut -10 +KPX ntilde umacron -10 +KPX ntilde uogonek -10 +KPX ntilde uring -10 +KPX ntilde v -40 +KPX ntilde y -20 +KPX ntilde yacute -20 +KPX ntilde ydieresis -20 +KPX o v -20 +KPX o w -15 +KPX o x -30 +KPX o y -20 +KPX o yacute -20 +KPX o ydieresis -20 +KPX oacute v -20 +KPX oacute w -15 +KPX oacute x -30 +KPX oacute y -20 +KPX oacute yacute -20 +KPX oacute ydieresis -20 +KPX ocircumflex v -20 +KPX ocircumflex w -15 +KPX ocircumflex x -30 +KPX ocircumflex y -20 +KPX ocircumflex yacute -20 +KPX ocircumflex ydieresis -20 +KPX odieresis v -20 +KPX odieresis w -15 +KPX odieresis x -30 +KPX odieresis y -20 +KPX odieresis yacute -20 +KPX odieresis ydieresis -20 +KPX ograve v -20 +KPX ograve w -15 +KPX ograve x -30 +KPX ograve y -20 +KPX ograve yacute -20 +KPX ograve ydieresis -20 +KPX ohungarumlaut v -20 +KPX ohungarumlaut w -15 +KPX ohungarumlaut x -30 +KPX ohungarumlaut y -20 +KPX ohungarumlaut yacute -20 +KPX ohungarumlaut ydieresis -20 +KPX omacron v -20 +KPX omacron w -15 +KPX omacron x -30 +KPX omacron y -20 +KPX omacron yacute -20 +KPX omacron ydieresis -20 +KPX oslash v -20 +KPX oslash w -15 +KPX oslash x -30 +KPX oslash y -20 +KPX oslash yacute -20 +KPX oslash ydieresis -20 +KPX otilde v -20 +KPX otilde w -15 +KPX otilde x -30 +KPX otilde y -20 +KPX otilde yacute -20 +KPX otilde ydieresis -20 +KPX p y -15 +KPX p yacute -15 +KPX p ydieresis -15 +KPX period quotedblright -120 +KPX period quoteright -120 +KPX period space -40 +KPX quotedblright space -80 +KPX quoteleft quoteleft -46 +KPX quoteright d -80 +KPX quoteright dcroat -80 +KPX quoteright l -20 +KPX quoteright lacute -20 +KPX quoteright lcommaaccent -20 +KPX quoteright lslash -20 +KPX quoteright quoteright -46 +KPX quoteright r -40 +KPX quoteright racute -40 +KPX quoteright rcaron -40 +KPX quoteright rcommaaccent -40 +KPX quoteright s -60 +KPX quoteright sacute -60 +KPX quoteright scaron -60 +KPX quoteright scedilla -60 +KPX quoteright scommaaccent -60 +KPX quoteright space -80 +KPX quoteright v -20 +KPX r c -20 +KPX r cacute -20 +KPX r ccaron -20 +KPX r ccedilla -20 +KPX r comma -60 +KPX r d -20 +KPX r dcroat -20 +KPX r g -15 +KPX r gbreve -15 +KPX r gcommaaccent -15 +KPX r hyphen -20 +KPX r o -20 +KPX r oacute -20 +KPX r ocircumflex -20 +KPX r odieresis -20 +KPX r ograve -20 +KPX r ohungarumlaut -20 +KPX r omacron -20 +KPX r oslash -20 +KPX r otilde -20 +KPX r period -60 +KPX r q -20 +KPX r s -15 +KPX r sacute -15 +KPX r scaron -15 +KPX r scedilla -15 +KPX r scommaaccent -15 +KPX r t 20 +KPX r tcommaaccent 20 +KPX r v 10 +KPX r y 10 +KPX r yacute 10 +KPX r ydieresis 10 +KPX racute c -20 +KPX racute cacute -20 +KPX racute ccaron -20 +KPX racute ccedilla -20 +KPX racute comma -60 +KPX racute d -20 +KPX racute dcroat -20 +KPX racute g -15 +KPX racute gbreve -15 +KPX racute gcommaaccent -15 +KPX racute hyphen -20 +KPX racute o -20 +KPX racute oacute -20 +KPX racute ocircumflex -20 +KPX racute odieresis -20 +KPX racute ograve -20 +KPX racute ohungarumlaut -20 +KPX racute omacron -20 +KPX racute oslash -20 +KPX racute otilde -20 +KPX racute period -60 +KPX racute q -20 +KPX racute s -15 +KPX racute sacute -15 +KPX racute scaron -15 +KPX racute scedilla -15 +KPX racute scommaaccent -15 +KPX racute t 20 +KPX racute tcommaaccent 20 +KPX racute v 10 +KPX racute y 10 +KPX racute yacute 10 +KPX racute ydieresis 10 +KPX rcaron c -20 +KPX rcaron cacute -20 +KPX rcaron ccaron -20 +KPX rcaron ccedilla -20 +KPX rcaron comma -60 +KPX rcaron d -20 +KPX rcaron dcroat -20 +KPX rcaron g -15 +KPX rcaron gbreve -15 +KPX rcaron gcommaaccent -15 +KPX rcaron hyphen -20 +KPX rcaron o -20 +KPX rcaron oacute -20 +KPX rcaron ocircumflex -20 +KPX rcaron odieresis -20 +KPX rcaron ograve -20 +KPX rcaron ohungarumlaut -20 +KPX rcaron omacron -20 +KPX rcaron oslash -20 +KPX rcaron otilde -20 +KPX rcaron period -60 +KPX rcaron q -20 +KPX rcaron s -15 +KPX rcaron sacute -15 +KPX rcaron scaron -15 +KPX rcaron scedilla -15 +KPX rcaron scommaaccent -15 +KPX rcaron t 20 +KPX rcaron tcommaaccent 20 +KPX rcaron v 10 +KPX rcaron y 10 +KPX rcaron yacute 10 +KPX rcaron ydieresis 10 +KPX rcommaaccent c -20 +KPX rcommaaccent cacute -20 +KPX rcommaaccent ccaron -20 +KPX rcommaaccent ccedilla -20 +KPX rcommaaccent comma -60 +KPX rcommaaccent d -20 +KPX rcommaaccent dcroat -20 +KPX rcommaaccent g -15 +KPX rcommaaccent gbreve -15 +KPX rcommaaccent gcommaaccent -15 +KPX rcommaaccent hyphen -20 +KPX rcommaaccent o -20 +KPX rcommaaccent oacute -20 +KPX rcommaaccent ocircumflex -20 +KPX rcommaaccent odieresis -20 +KPX rcommaaccent ograve -20 +KPX rcommaaccent ohungarumlaut -20 +KPX rcommaaccent omacron -20 +KPX rcommaaccent oslash -20 +KPX rcommaaccent otilde -20 +KPX rcommaaccent period -60 +KPX rcommaaccent q -20 +KPX rcommaaccent s -15 +KPX rcommaaccent sacute -15 +KPX rcommaaccent scaron -15 +KPX rcommaaccent scedilla -15 +KPX rcommaaccent scommaaccent -15 +KPX rcommaaccent t 20 +KPX rcommaaccent tcommaaccent 20 +KPX rcommaaccent v 10 +KPX rcommaaccent y 10 +KPX rcommaaccent yacute 10 +KPX rcommaaccent ydieresis 10 +KPX s w -15 +KPX sacute w -15 +KPX scaron w -15 +KPX scedilla w -15 +KPX scommaaccent w -15 +KPX semicolon space -40 +KPX space T -100 +KPX space Tcaron -100 +KPX space Tcommaaccent -100 +KPX space V -80 +KPX space W -80 +KPX space Y -120 +KPX space Yacute -120 +KPX space Ydieresis -120 +KPX space quotedblleft -80 +KPX space quoteleft -60 +KPX v a -20 +KPX v aacute -20 +KPX v abreve -20 +KPX v acircumflex -20 +KPX v adieresis -20 +KPX v agrave -20 +KPX v amacron -20 +KPX v aogonek -20 +KPX v aring -20 +KPX v atilde -20 +KPX v comma -80 +KPX v o -30 +KPX v oacute -30 +KPX v ocircumflex -30 +KPX v odieresis -30 +KPX v ograve -30 +KPX v ohungarumlaut -30 +KPX v omacron -30 +KPX v oslash -30 +KPX v otilde -30 +KPX v period -80 +KPX w comma -40 +KPX w o -20 +KPX w oacute -20 +KPX w ocircumflex -20 +KPX w odieresis -20 +KPX w ograve -20 +KPX w ohungarumlaut -20 +KPX w omacron -20 +KPX w oslash -20 +KPX w otilde -20 +KPX w period -40 +KPX x e -10 +KPX x eacute -10 +KPX x ecaron -10 +KPX x ecircumflex -10 +KPX x edieresis -10 +KPX x edotaccent -10 +KPX x egrave -10 +KPX x emacron -10 +KPX x eogonek -10 +KPX y a -30 +KPX y aacute -30 +KPX y abreve -30 +KPX y acircumflex -30 +KPX y adieresis -30 +KPX y agrave -30 +KPX y amacron -30 +KPX y aogonek -30 +KPX y aring -30 +KPX y atilde -30 +KPX y comma -80 +KPX y e -10 +KPX y eacute -10 +KPX y ecaron -10 +KPX y ecircumflex -10 +KPX y edieresis -10 +KPX y edotaccent -10 +KPX y egrave -10 +KPX y emacron -10 +KPX y eogonek -10 +KPX y o -25 +KPX y oacute -25 +KPX y ocircumflex -25 +KPX y odieresis -25 +KPX y ograve -25 +KPX y ohungarumlaut -25 +KPX y omacron -25 +KPX y oslash -25 +KPX y otilde -25 +KPX y period -80 +KPX yacute a -30 +KPX yacute aacute -30 +KPX yacute abreve -30 +KPX yacute acircumflex -30 +KPX yacute adieresis -30 +KPX yacute agrave -30 +KPX yacute amacron -30 +KPX yacute aogonek -30 +KPX yacute aring -30 +KPX yacute atilde -30 +KPX yacute comma -80 +KPX yacute e -10 +KPX yacute eacute -10 +KPX yacute ecaron -10 +KPX yacute ecircumflex -10 +KPX yacute edieresis -10 +KPX yacute edotaccent -10 +KPX yacute egrave -10 +KPX yacute emacron -10 +KPX yacute eogonek -10 +KPX yacute o -25 +KPX yacute oacute -25 +KPX yacute ocircumflex -25 +KPX yacute odieresis -25 +KPX yacute ograve -25 +KPX yacute ohungarumlaut -25 +KPX yacute omacron -25 +KPX yacute oslash -25 +KPX yacute otilde -25 +KPX yacute period -80 +KPX ydieresis a -30 +KPX ydieresis aacute -30 +KPX ydieresis abreve -30 +KPX ydieresis acircumflex -30 +KPX ydieresis adieresis -30 +KPX ydieresis agrave -30 +KPX ydieresis amacron -30 +KPX ydieresis aogonek -30 +KPX ydieresis aring -30 +KPX ydieresis atilde -30 +KPX ydieresis comma -80 +KPX ydieresis e -10 +KPX ydieresis eacute -10 +KPX ydieresis ecaron -10 +KPX ydieresis ecircumflex -10 +KPX ydieresis edieresis -10 +KPX ydieresis edotaccent -10 +KPX ydieresis egrave -10 +KPX ydieresis emacron -10 +KPX ydieresis eogonek -10 +KPX ydieresis o -25 +KPX ydieresis oacute -25 +KPX ydieresis ocircumflex -25 +KPX ydieresis odieresis -25 +KPX ydieresis ograve -25 +KPX ydieresis ohungarumlaut -25 +KPX ydieresis omacron -25 +KPX ydieresis oslash -25 +KPX ydieresis otilde -25 +KPX ydieresis period -80 +KPX z e 10 +KPX z eacute 10 +KPX z ecaron 10 +KPX z ecircumflex 10 +KPX z edieresis 10 +KPX z edotaccent 10 +KPX z egrave 10 +KPX z emacron 10 +KPX z eogonek 10 +KPX zacute e 10 +KPX zacute eacute 10 +KPX zacute ecaron 10 +KPX zacute ecircumflex 10 +KPX zacute edieresis 10 +KPX zacute edotaccent 10 +KPX zacute egrave 10 +KPX zacute emacron 10 +KPX zacute eogonek 10 +KPX zcaron e 10 +KPX zcaron eacute 10 +KPX zcaron ecaron 10 +KPX zcaron ecircumflex 10 +KPX zcaron edieresis 10 +KPX zcaron edotaccent 10 +KPX zcaron egrave 10 +KPX zcaron emacron 10 +KPX zcaron eogonek 10 +KPX zdotaccent e 10 +KPX zdotaccent eacute 10 +KPX zdotaccent ecaron 10 +KPX zdotaccent ecircumflex 10 +KPX zdotaccent edieresis 10 +KPX zdotaccent edotaccent 10 +KPX zdotaccent egrave 10 +KPX zdotaccent emacron 10 +KPX zdotaccent eogonek 10 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-BoldOblique.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-BoldOblique.afm new file mode 100644 index 0000000..0bb1bfb --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-BoldOblique.afm @@ -0,0 +1,2827 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:45:12 1997 +Comment UniqueID 43053 +Comment VMusage 14482 68586 +FontName Helvetica-BoldOblique +FullName Helvetica Bold Oblique +FamilyName Helvetica +Weight Bold +ItalicAngle -12 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -174 -228 1114 962 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 718 +XHeight 532 +Ascender 718 +Descender -207 +StdHW 118 +StdVW 140 +StartCharMetrics 315 +C 32 ; WX 278 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 94 0 397 718 ; +C 34 ; WX 474 ; N quotedbl ; B 193 447 529 718 ; +C 35 ; WX 556 ; N numbersign ; B 60 0 644 698 ; +C 36 ; WX 556 ; N dollar ; B 67 -115 622 775 ; +C 37 ; WX 889 ; N percent ; B 136 -19 901 710 ; +C 38 ; WX 722 ; N ampersand ; B 89 -19 732 718 ; +C 39 ; WX 278 ; N quoteright ; B 167 445 362 718 ; +C 40 ; WX 333 ; N parenleft ; B 76 -208 470 734 ; +C 41 ; WX 333 ; N parenright ; B -25 -208 369 734 ; +C 42 ; WX 389 ; N asterisk ; B 146 387 481 718 ; +C 43 ; WX 584 ; N plus ; B 82 0 610 506 ; +C 44 ; WX 278 ; N comma ; B 28 -168 245 146 ; +C 45 ; WX 333 ; N hyphen ; B 73 215 379 345 ; +C 46 ; WX 278 ; N period ; B 64 0 245 146 ; +C 47 ; WX 278 ; N slash ; B -37 -19 468 737 ; +C 48 ; WX 556 ; N zero ; B 86 -19 617 710 ; +C 49 ; WX 556 ; N one ; B 173 0 529 710 ; +C 50 ; WX 556 ; N two ; B 26 0 619 710 ; +C 51 ; WX 556 ; N three ; B 65 -19 608 710 ; +C 52 ; WX 556 ; N four ; B 60 0 598 710 ; +C 53 ; WX 556 ; N five ; B 64 -19 636 698 ; +C 54 ; WX 556 ; N six ; B 85 -19 619 710 ; +C 55 ; WX 556 ; N seven ; B 125 0 676 698 ; +C 56 ; WX 556 ; N eight ; B 69 -19 616 710 ; +C 57 ; WX 556 ; N nine ; B 78 -19 615 710 ; +C 58 ; WX 333 ; N colon ; B 92 0 351 512 ; +C 59 ; WX 333 ; N semicolon ; B 56 -168 351 512 ; +C 60 ; WX 584 ; N less ; B 82 -8 655 514 ; +C 61 ; WX 584 ; N equal ; B 58 87 633 419 ; +C 62 ; WX 584 ; N greater ; B 36 -8 609 514 ; +C 63 ; WX 611 ; N question ; B 165 0 671 727 ; +C 64 ; WX 975 ; N at ; B 186 -19 954 737 ; +C 65 ; WX 722 ; N A ; B 20 0 702 718 ; +C 66 ; WX 722 ; N B ; B 76 0 764 718 ; +C 67 ; WX 722 ; N C ; B 107 -19 789 737 ; +C 68 ; WX 722 ; N D ; B 76 0 777 718 ; +C 69 ; WX 667 ; N E ; B 76 0 757 718 ; +C 70 ; WX 611 ; N F ; B 76 0 740 718 ; +C 71 ; WX 778 ; N G ; B 108 -19 817 737 ; +C 72 ; WX 722 ; N H ; B 71 0 804 718 ; +C 73 ; WX 278 ; N I ; B 64 0 367 718 ; +C 74 ; WX 556 ; N J ; B 60 -18 637 718 ; +C 75 ; WX 722 ; N K ; B 87 0 858 718 ; +C 76 ; WX 611 ; N L ; B 76 0 611 718 ; +C 77 ; WX 833 ; N M ; B 69 0 918 718 ; +C 78 ; WX 722 ; N N ; B 69 0 807 718 ; +C 79 ; WX 778 ; N O ; B 107 -19 823 737 ; +C 80 ; WX 667 ; N P ; B 76 0 738 718 ; +C 81 ; WX 778 ; N Q ; B 107 -52 823 737 ; +C 82 ; WX 722 ; N R ; B 76 0 778 718 ; +C 83 ; WX 667 ; N S ; B 81 -19 718 737 ; +C 84 ; WX 611 ; N T ; B 140 0 751 718 ; +C 85 ; WX 722 ; N U ; B 116 -19 804 718 ; +C 86 ; WX 667 ; N V ; B 172 0 801 718 ; +C 87 ; WX 944 ; N W ; B 169 0 1082 718 ; +C 88 ; WX 667 ; N X ; B 14 0 791 718 ; +C 89 ; WX 667 ; N Y ; B 168 0 806 718 ; +C 90 ; WX 611 ; N Z ; B 25 0 737 718 ; +C 91 ; WX 333 ; N bracketleft ; B 21 -196 462 722 ; +C 92 ; WX 278 ; N backslash ; B 124 -19 307 737 ; +C 93 ; WX 333 ; N bracketright ; B -18 -196 423 722 ; +C 94 ; WX 584 ; N asciicircum ; B 131 323 591 698 ; +C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ; +C 96 ; WX 278 ; N quoteleft ; B 165 454 361 727 ; +C 97 ; WX 556 ; N a ; B 55 -14 583 546 ; +C 98 ; WX 611 ; N b ; B 61 -14 645 718 ; +C 99 ; WX 556 ; N c ; B 79 -14 599 546 ; +C 100 ; WX 611 ; N d ; B 82 -14 704 718 ; +C 101 ; WX 556 ; N e ; B 70 -14 593 546 ; +C 102 ; WX 333 ; N f ; B 87 0 469 727 ; L i fi ; L l fl ; +C 103 ; WX 611 ; N g ; B 38 -217 666 546 ; +C 104 ; WX 611 ; N h ; B 65 0 629 718 ; +C 105 ; WX 278 ; N i ; B 69 0 363 725 ; +C 106 ; WX 278 ; N j ; B -42 -214 363 725 ; +C 107 ; WX 556 ; N k ; B 69 0 670 718 ; +C 108 ; WX 278 ; N l ; B 69 0 362 718 ; +C 109 ; WX 889 ; N m ; B 64 0 909 546 ; +C 110 ; WX 611 ; N n ; B 65 0 629 546 ; +C 111 ; WX 611 ; N o ; B 82 -14 643 546 ; +C 112 ; WX 611 ; N p ; B 18 -207 645 546 ; +C 113 ; WX 611 ; N q ; B 80 -207 665 546 ; +C 114 ; WX 389 ; N r ; B 64 0 489 546 ; +C 115 ; WX 556 ; N s ; B 63 -14 584 546 ; +C 116 ; WX 333 ; N t ; B 100 -6 422 676 ; +C 117 ; WX 611 ; N u ; B 98 -14 658 532 ; +C 118 ; WX 556 ; N v ; B 126 0 656 532 ; +C 119 ; WX 778 ; N w ; B 123 0 882 532 ; +C 120 ; WX 556 ; N x ; B 15 0 648 532 ; +C 121 ; WX 556 ; N y ; B 42 -214 652 532 ; +C 122 ; WX 500 ; N z ; B 20 0 583 532 ; +C 123 ; WX 389 ; N braceleft ; B 94 -196 518 722 ; +C 124 ; WX 280 ; N bar ; B 36 -225 361 775 ; +C 125 ; WX 389 ; N braceright ; B -18 -196 407 722 ; +C 126 ; WX 584 ; N asciitilde ; B 115 163 577 343 ; +C 161 ; WX 333 ; N exclamdown ; B 50 -186 353 532 ; +C 162 ; WX 556 ; N cent ; B 79 -118 599 628 ; +C 163 ; WX 556 ; N sterling ; B 50 -16 635 718 ; +C 164 ; WX 167 ; N fraction ; B -174 -19 487 710 ; +C 165 ; WX 556 ; N yen ; B 60 0 713 698 ; +C 166 ; WX 556 ; N florin ; B -50 -210 669 737 ; +C 167 ; WX 556 ; N section ; B 61 -184 598 727 ; +C 168 ; WX 556 ; N currency ; B 27 76 680 636 ; +C 169 ; WX 238 ; N quotesingle ; B 165 447 321 718 ; +C 170 ; WX 500 ; N quotedblleft ; B 160 454 588 727 ; +C 171 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ; +C 172 ; WX 333 ; N guilsinglleft ; B 130 76 353 484 ; +C 173 ; WX 333 ; N guilsinglright ; B 99 76 322 484 ; +C 174 ; WX 611 ; N fi ; B 87 0 696 727 ; +C 175 ; WX 611 ; N fl ; B 87 0 695 727 ; +C 177 ; WX 556 ; N endash ; B 48 227 627 333 ; +C 178 ; WX 556 ; N dagger ; B 118 -171 626 718 ; +C 179 ; WX 556 ; N daggerdbl ; B 46 -171 628 718 ; +C 180 ; WX 278 ; N periodcentered ; B 110 172 276 334 ; +C 182 ; WX 556 ; N paragraph ; B 98 -191 688 700 ; +C 183 ; WX 350 ; N bullet ; B 83 194 420 524 ; +C 184 ; WX 278 ; N quotesinglbase ; B 41 -146 236 127 ; +C 185 ; WX 500 ; N quotedblbase ; B 36 -146 463 127 ; +C 186 ; WX 500 ; N quotedblright ; B 162 445 589 718 ; +C 187 ; WX 556 ; N guillemotright ; B 104 76 540 484 ; +C 188 ; WX 1000 ; N ellipsis ; B 92 0 939 146 ; +C 189 ; WX 1000 ; N perthousand ; B 76 -19 1038 710 ; +C 191 ; WX 611 ; N questiondown ; B 53 -195 559 532 ; +C 193 ; WX 333 ; N grave ; B 136 604 353 750 ; +C 194 ; WX 333 ; N acute ; B 236 604 515 750 ; +C 195 ; WX 333 ; N circumflex ; B 118 604 471 750 ; +C 196 ; WX 333 ; N tilde ; B 113 610 507 737 ; +C 197 ; WX 333 ; N macron ; B 122 604 483 678 ; +C 198 ; WX 333 ; N breve ; B 156 604 494 750 ; +C 199 ; WX 333 ; N dotaccent ; B 235 614 385 729 ; +C 200 ; WX 333 ; N dieresis ; B 137 614 482 729 ; +C 202 ; WX 333 ; N ring ; B 200 568 420 776 ; +C 203 ; WX 333 ; N cedilla ; B -37 -228 220 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B 137 604 645 750 ; +C 206 ; WX 333 ; N ogonek ; B 41 -228 264 0 ; +C 207 ; WX 333 ; N caron ; B 149 604 502 750 ; +C 208 ; WX 1000 ; N emdash ; B 48 227 1071 333 ; +C 225 ; WX 1000 ; N AE ; B 5 0 1100 718 ; +C 227 ; WX 370 ; N ordfeminine ; B 125 401 465 737 ; +C 232 ; WX 611 ; N Lslash ; B 34 0 611 718 ; +C 233 ; WX 778 ; N Oslash ; B 35 -27 894 745 ; +C 234 ; WX 1000 ; N OE ; B 99 -19 1114 737 ; +C 235 ; WX 365 ; N ordmasculine ; B 123 401 485 737 ; +C 241 ; WX 889 ; N ae ; B 56 -14 923 546 ; +C 245 ; WX 278 ; N dotlessi ; B 69 0 322 532 ; +C 248 ; WX 278 ; N lslash ; B 40 0 407 718 ; +C 249 ; WX 611 ; N oslash ; B 22 -29 701 560 ; +C 250 ; WX 944 ; N oe ; B 82 -14 977 546 ; +C 251 ; WX 611 ; N germandbls ; B 69 -14 657 731 ; +C -1 ; WX 278 ; N Idieresis ; B 64 0 494 915 ; +C -1 ; WX 556 ; N eacute ; B 70 -14 627 750 ; +C -1 ; WX 556 ; N abreve ; B 55 -14 606 750 ; +C -1 ; WX 611 ; N uhungarumlaut ; B 98 -14 784 750 ; +C -1 ; WX 556 ; N ecaron ; B 70 -14 614 750 ; +C -1 ; WX 667 ; N Ydieresis ; B 168 0 806 915 ; +C -1 ; WX 584 ; N divide ; B 82 -42 610 548 ; +C -1 ; WX 667 ; N Yacute ; B 168 0 806 936 ; +C -1 ; WX 722 ; N Acircumflex ; B 20 0 706 936 ; +C -1 ; WX 556 ; N aacute ; B 55 -14 627 750 ; +C -1 ; WX 722 ; N Ucircumflex ; B 116 -19 804 936 ; +C -1 ; WX 556 ; N yacute ; B 42 -214 652 750 ; +C -1 ; WX 556 ; N scommaaccent ; B 63 -228 584 546 ; +C -1 ; WX 556 ; N ecircumflex ; B 70 -14 593 750 ; +C -1 ; WX 722 ; N Uring ; B 116 -19 804 962 ; +C -1 ; WX 722 ; N Udieresis ; B 116 -19 804 915 ; +C -1 ; WX 556 ; N aogonek ; B 55 -224 583 546 ; +C -1 ; WX 722 ; N Uacute ; B 116 -19 804 936 ; +C -1 ; WX 611 ; N uogonek ; B 98 -228 658 532 ; +C -1 ; WX 667 ; N Edieresis ; B 76 0 757 915 ; +C -1 ; WX 722 ; N Dcroat ; B 62 0 777 718 ; +C -1 ; WX 250 ; N commaaccent ; B 16 -228 188 -50 ; +C -1 ; WX 737 ; N copyright ; B 56 -19 835 737 ; +C -1 ; WX 667 ; N Emacron ; B 76 0 757 864 ; +C -1 ; WX 556 ; N ccaron ; B 79 -14 614 750 ; +C -1 ; WX 556 ; N aring ; B 55 -14 583 776 ; +C -1 ; WX 722 ; N Ncommaaccent ; B 69 -228 807 718 ; +C -1 ; WX 278 ; N lacute ; B 69 0 528 936 ; +C -1 ; WX 556 ; N agrave ; B 55 -14 583 750 ; +C -1 ; WX 611 ; N Tcommaaccent ; B 140 -228 751 718 ; +C -1 ; WX 722 ; N Cacute ; B 107 -19 789 936 ; +C -1 ; WX 556 ; N atilde ; B 55 -14 619 737 ; +C -1 ; WX 667 ; N Edotaccent ; B 76 0 757 915 ; +C -1 ; WX 556 ; N scaron ; B 63 -14 614 750 ; +C -1 ; WX 556 ; N scedilla ; B 63 -228 584 546 ; +C -1 ; WX 278 ; N iacute ; B 69 0 488 750 ; +C -1 ; WX 494 ; N lozenge ; B 90 0 564 745 ; +C -1 ; WX 722 ; N Rcaron ; B 76 0 778 936 ; +C -1 ; WX 778 ; N Gcommaaccent ; B 108 -228 817 737 ; +C -1 ; WX 611 ; N ucircumflex ; B 98 -14 658 750 ; +C -1 ; WX 556 ; N acircumflex ; B 55 -14 583 750 ; +C -1 ; WX 722 ; N Amacron ; B 20 0 718 864 ; +C -1 ; WX 389 ; N rcaron ; B 64 0 530 750 ; +C -1 ; WX 556 ; N ccedilla ; B 79 -228 599 546 ; +C -1 ; WX 611 ; N Zdotaccent ; B 25 0 737 915 ; +C -1 ; WX 667 ; N Thorn ; B 76 0 716 718 ; +C -1 ; WX 778 ; N Omacron ; B 107 -19 823 864 ; +C -1 ; WX 722 ; N Racute ; B 76 0 778 936 ; +C -1 ; WX 667 ; N Sacute ; B 81 -19 722 936 ; +C -1 ; WX 743 ; N dcaron ; B 82 -14 903 718 ; +C -1 ; WX 722 ; N Umacron ; B 116 -19 804 864 ; +C -1 ; WX 611 ; N uring ; B 98 -14 658 776 ; +C -1 ; WX 333 ; N threebaseior ; B 91 271 441 710 ; +C -1 ; WX 778 ; N Ograve ; B 107 -19 823 936 ; +C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ; +C -1 ; WX 722 ; N Abreve ; B 20 0 729 936 ; +C -1 ; WX 584 ; N multiply ; B 57 1 635 505 ; +C -1 ; WX 611 ; N uacute ; B 98 -14 658 750 ; +C -1 ; WX 611 ; N Tcaron ; B 140 0 751 936 ; +C -1 ; WX 494 ; N partialdiff ; B 43 -21 585 750 ; +C -1 ; WX 556 ; N ydieresis ; B 42 -214 652 729 ; +C -1 ; WX 722 ; N Nacute ; B 69 0 807 936 ; +C -1 ; WX 278 ; N icircumflex ; B 69 0 444 750 ; +C -1 ; WX 667 ; N Ecircumflex ; B 76 0 757 936 ; +C -1 ; WX 556 ; N adieresis ; B 55 -14 594 729 ; +C -1 ; WX 556 ; N edieresis ; B 70 -14 594 729 ; +C -1 ; WX 556 ; N cacute ; B 79 -14 627 750 ; +C -1 ; WX 611 ; N nacute ; B 65 0 654 750 ; +C -1 ; WX 611 ; N umacron ; B 98 -14 658 678 ; +C -1 ; WX 722 ; N Ncaron ; B 69 0 807 936 ; +C -1 ; WX 278 ; N Iacute ; B 64 0 528 936 ; +C -1 ; WX 584 ; N plusminus ; B 40 0 625 506 ; +C -1 ; WX 280 ; N brokenbar ; B 52 -150 345 700 ; +C -1 ; WX 737 ; N registered ; B 55 -19 834 737 ; +C -1 ; WX 778 ; N Gbreve ; B 108 -19 817 936 ; +C -1 ; WX 278 ; N Idotaccent ; B 64 0 397 915 ; +C -1 ; WX 600 ; N summation ; B 14 -10 670 706 ; +C -1 ; WX 667 ; N Egrave ; B 76 0 757 936 ; +C -1 ; WX 389 ; N racute ; B 64 0 543 750 ; +C -1 ; WX 611 ; N omacron ; B 82 -14 643 678 ; +C -1 ; WX 611 ; N Zacute ; B 25 0 737 936 ; +C -1 ; WX 611 ; N Zcaron ; B 25 0 737 936 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 629 704 ; +C -1 ; WX 722 ; N Eth ; B 62 0 777 718 ; +C -1 ; WX 722 ; N Ccedilla ; B 107 -228 789 737 ; +C -1 ; WX 278 ; N lcommaaccent ; B 30 -228 362 718 ; +C -1 ; WX 389 ; N tcaron ; B 100 -6 608 878 ; +C -1 ; WX 556 ; N eogonek ; B 70 -228 593 546 ; +C -1 ; WX 722 ; N Uogonek ; B 116 -228 804 718 ; +C -1 ; WX 722 ; N Aacute ; B 20 0 750 936 ; +C -1 ; WX 722 ; N Adieresis ; B 20 0 716 915 ; +C -1 ; WX 556 ; N egrave ; B 70 -14 593 750 ; +C -1 ; WX 500 ; N zacute ; B 20 0 599 750 ; +C -1 ; WX 278 ; N iogonek ; B -14 -224 363 725 ; +C -1 ; WX 778 ; N Oacute ; B 107 -19 823 936 ; +C -1 ; WX 611 ; N oacute ; B 82 -14 654 750 ; +C -1 ; WX 556 ; N amacron ; B 55 -14 595 678 ; +C -1 ; WX 556 ; N sacute ; B 63 -14 627 750 ; +C -1 ; WX 278 ; N idieresis ; B 69 0 455 729 ; +C -1 ; WX 778 ; N Ocircumflex ; B 107 -19 823 936 ; +C -1 ; WX 722 ; N Ugrave ; B 116 -19 804 936 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 611 ; N thorn ; B 18 -208 645 718 ; +C -1 ; WX 333 ; N twobaseior ; B 69 283 449 710 ; +C -1 ; WX 778 ; N Odieresis ; B 107 -19 823 915 ; +C -1 ; WX 611 ; N mu ; B 22 -207 658 532 ; +C -1 ; WX 278 ; N igrave ; B 69 0 326 750 ; +C -1 ; WX 611 ; N ohungarumlaut ; B 82 -14 784 750 ; +C -1 ; WX 667 ; N Eogonek ; B 76 -224 757 718 ; +C -1 ; WX 611 ; N dcroat ; B 82 -14 789 718 ; +C -1 ; WX 834 ; N threequarters ; B 99 -19 839 710 ; +C -1 ; WX 667 ; N Scedilla ; B 81 -228 718 737 ; +C -1 ; WX 400 ; N lcaron ; B 69 0 561 718 ; +C -1 ; WX 722 ; N Kcommaaccent ; B 87 -228 858 718 ; +C -1 ; WX 611 ; N Lacute ; B 76 0 611 936 ; +C -1 ; WX 1000 ; N trademark ; B 179 306 1109 718 ; +C -1 ; WX 556 ; N edotaccent ; B 70 -14 593 729 ; +C -1 ; WX 278 ; N Igrave ; B 64 0 367 936 ; +C -1 ; WX 278 ; N Imacron ; B 64 0 496 864 ; +C -1 ; WX 611 ; N Lcaron ; B 76 0 643 718 ; +C -1 ; WX 834 ; N onehalf ; B 132 -19 858 710 ; +C -1 ; WX 549 ; N lessequal ; B 29 0 676 704 ; +C -1 ; WX 611 ; N ocircumflex ; B 82 -14 643 750 ; +C -1 ; WX 611 ; N ntilde ; B 65 0 646 737 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 116 -19 880 936 ; +C -1 ; WX 667 ; N Eacute ; B 76 0 757 936 ; +C -1 ; WX 556 ; N emacron ; B 70 -14 595 678 ; +C -1 ; WX 611 ; N gbreve ; B 38 -217 666 750 ; +C -1 ; WX 834 ; N onequarter ; B 132 -19 806 710 ; +C -1 ; WX 667 ; N Scaron ; B 81 -19 718 936 ; +C -1 ; WX 667 ; N Scommaaccent ; B 81 -228 718 737 ; +C -1 ; WX 778 ; N Ohungarumlaut ; B 107 -19 908 936 ; +C -1 ; WX 400 ; N degree ; B 175 426 467 712 ; +C -1 ; WX 611 ; N ograve ; B 82 -14 643 750 ; +C -1 ; WX 722 ; N Ccaron ; B 107 -19 789 936 ; +C -1 ; WX 611 ; N ugrave ; B 98 -14 658 750 ; +C -1 ; WX 549 ; N radical ; B 112 -46 689 850 ; +C -1 ; WX 722 ; N Dcaron ; B 76 0 777 936 ; +C -1 ; WX 389 ; N rcommaaccent ; B 26 -228 489 546 ; +C -1 ; WX 722 ; N Ntilde ; B 69 0 807 923 ; +C -1 ; WX 611 ; N otilde ; B 82 -14 646 737 ; +C -1 ; WX 722 ; N Rcommaaccent ; B 76 -228 778 718 ; +C -1 ; WX 611 ; N Lcommaaccent ; B 76 -228 611 718 ; +C -1 ; WX 722 ; N Atilde ; B 20 0 741 923 ; +C -1 ; WX 722 ; N Aogonek ; B 20 -224 702 718 ; +C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ; +C -1 ; WX 778 ; N Otilde ; B 107 -19 823 923 ; +C -1 ; WX 500 ; N zdotaccent ; B 20 0 583 729 ; +C -1 ; WX 667 ; N Ecaron ; B 76 0 757 936 ; +C -1 ; WX 278 ; N Iogonek ; B -41 -228 367 718 ; +C -1 ; WX 556 ; N kcommaaccent ; B 69 -228 670 718 ; +C -1 ; WX 584 ; N minus ; B 82 197 610 309 ; +C -1 ; WX 278 ; N Icircumflex ; B 64 0 484 936 ; +C -1 ; WX 611 ; N ncaron ; B 65 0 641 750 ; +C -1 ; WX 333 ; N tcommaaccent ; B 58 -228 422 676 ; +C -1 ; WX 584 ; N logicalnot ; B 105 108 633 419 ; +C -1 ; WX 611 ; N odieresis ; B 82 -14 643 729 ; +C -1 ; WX 611 ; N udieresis ; B 98 -14 658 729 ; +C -1 ; WX 549 ; N notequal ; B 32 -49 630 570 ; +C -1 ; WX 611 ; N gcommaaccent ; B 38 -217 666 850 ; +C -1 ; WX 611 ; N eth ; B 82 -14 670 737 ; +C -1 ; WX 500 ; N zcaron ; B 20 0 586 750 ; +C -1 ; WX 611 ; N ncommaaccent ; B 65 -228 629 546 ; +C -1 ; WX 333 ; N onebaseior ; B 148 283 388 710 ; +C -1 ; WX 278 ; N imacron ; B 69 0 429 678 ; +C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2481 +KPX A C -40 +KPX A Cacute -40 +KPX A Ccaron -40 +KPX A Ccedilla -40 +KPX A G -50 +KPX A Gbreve -50 +KPX A Gcommaaccent -50 +KPX A O -40 +KPX A Oacute -40 +KPX A Ocircumflex -40 +KPX A Odieresis -40 +KPX A Ograve -40 +KPX A Ohungarumlaut -40 +KPX A Omacron -40 +KPX A Oslash -40 +KPX A Otilde -40 +KPX A Q -40 +KPX A T -90 +KPX A Tcaron -90 +KPX A Tcommaaccent -90 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -80 +KPX A W -60 +KPX A Y -110 +KPX A Yacute -110 +KPX A Ydieresis -110 +KPX A u -30 +KPX A uacute -30 +KPX A ucircumflex -30 +KPX A udieresis -30 +KPX A ugrave -30 +KPX A uhungarumlaut -30 +KPX A umacron -30 +KPX A uogonek -30 +KPX A uring -30 +KPX A v -40 +KPX A w -30 +KPX A y -30 +KPX A yacute -30 +KPX A ydieresis -30 +KPX Aacute C -40 +KPX Aacute Cacute -40 +KPX Aacute Ccaron -40 +KPX Aacute Ccedilla -40 +KPX Aacute G -50 +KPX Aacute Gbreve -50 +KPX Aacute Gcommaaccent -50 +KPX Aacute O -40 +KPX Aacute Oacute -40 +KPX Aacute Ocircumflex -40 +KPX Aacute Odieresis -40 +KPX Aacute Ograve -40 +KPX Aacute Ohungarumlaut -40 +KPX Aacute Omacron -40 +KPX Aacute Oslash -40 +KPX Aacute Otilde -40 +KPX Aacute Q -40 +KPX Aacute T -90 +KPX Aacute Tcaron -90 +KPX Aacute Tcommaaccent -90 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -80 +KPX Aacute W -60 +KPX Aacute Y -110 +KPX Aacute Yacute -110 +KPX Aacute Ydieresis -110 +KPX Aacute u -30 +KPX Aacute uacute -30 +KPX Aacute ucircumflex -30 +KPX Aacute udieresis -30 +KPX Aacute ugrave -30 +KPX Aacute uhungarumlaut -30 +KPX Aacute umacron -30 +KPX Aacute uogonek -30 +KPX Aacute uring -30 +KPX Aacute v -40 +KPX Aacute w -30 +KPX Aacute y -30 +KPX Aacute yacute -30 +KPX Aacute ydieresis -30 +KPX Abreve C -40 +KPX Abreve Cacute -40 +KPX Abreve Ccaron -40 +KPX Abreve Ccedilla -40 +KPX Abreve G -50 +KPX Abreve Gbreve -50 +KPX Abreve Gcommaaccent -50 +KPX Abreve O -40 +KPX Abreve Oacute -40 +KPX Abreve Ocircumflex -40 +KPX Abreve Odieresis -40 +KPX Abreve Ograve -40 +KPX Abreve Ohungarumlaut -40 +KPX Abreve Omacron -40 +KPX Abreve Oslash -40 +KPX Abreve Otilde -40 +KPX Abreve Q -40 +KPX Abreve T -90 +KPX Abreve Tcaron -90 +KPX Abreve Tcommaaccent -90 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -80 +KPX Abreve W -60 +KPX Abreve Y -110 +KPX Abreve Yacute -110 +KPX Abreve Ydieresis -110 +KPX Abreve u -30 +KPX Abreve uacute -30 +KPX Abreve ucircumflex -30 +KPX Abreve udieresis -30 +KPX Abreve ugrave -30 +KPX Abreve uhungarumlaut -30 +KPX Abreve umacron -30 +KPX Abreve uogonek -30 +KPX Abreve uring -30 +KPX Abreve v -40 +KPX Abreve w -30 +KPX Abreve y -30 +KPX Abreve yacute -30 +KPX Abreve ydieresis -30 +KPX Acircumflex C -40 +KPX Acircumflex Cacute -40 +KPX Acircumflex Ccaron -40 +KPX Acircumflex Ccedilla -40 +KPX Acircumflex G -50 +KPX Acircumflex Gbreve -50 +KPX Acircumflex Gcommaaccent -50 +KPX Acircumflex O -40 +KPX Acircumflex Oacute -40 +KPX Acircumflex Ocircumflex -40 +KPX Acircumflex Odieresis -40 +KPX Acircumflex Ograve -40 +KPX Acircumflex Ohungarumlaut -40 +KPX Acircumflex Omacron -40 +KPX Acircumflex Oslash -40 +KPX Acircumflex Otilde -40 +KPX Acircumflex Q -40 +KPX Acircumflex T -90 +KPX Acircumflex Tcaron -90 +KPX Acircumflex Tcommaaccent -90 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -80 +KPX Acircumflex W -60 +KPX Acircumflex Y -110 +KPX Acircumflex Yacute -110 +KPX Acircumflex Ydieresis -110 +KPX Acircumflex u -30 +KPX Acircumflex uacute -30 +KPX Acircumflex ucircumflex -30 +KPX Acircumflex udieresis -30 +KPX Acircumflex ugrave -30 +KPX Acircumflex uhungarumlaut -30 +KPX Acircumflex umacron -30 +KPX Acircumflex uogonek -30 +KPX Acircumflex uring -30 +KPX Acircumflex v -40 +KPX Acircumflex w -30 +KPX Acircumflex y -30 +KPX Acircumflex yacute -30 +KPX Acircumflex ydieresis -30 +KPX Adieresis C -40 +KPX Adieresis Cacute -40 +KPX Adieresis Ccaron -40 +KPX Adieresis Ccedilla -40 +KPX Adieresis G -50 +KPX Adieresis Gbreve -50 +KPX Adieresis Gcommaaccent -50 +KPX Adieresis O -40 +KPX Adieresis Oacute -40 +KPX Adieresis Ocircumflex -40 +KPX Adieresis Odieresis -40 +KPX Adieresis Ograve -40 +KPX Adieresis Ohungarumlaut -40 +KPX Adieresis Omacron -40 +KPX Adieresis Oslash -40 +KPX Adieresis Otilde -40 +KPX Adieresis Q -40 +KPX Adieresis T -90 +KPX Adieresis Tcaron -90 +KPX Adieresis Tcommaaccent -90 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -80 +KPX Adieresis W -60 +KPX Adieresis Y -110 +KPX Adieresis Yacute -110 +KPX Adieresis Ydieresis -110 +KPX Adieresis u -30 +KPX Adieresis uacute -30 +KPX Adieresis ucircumflex -30 +KPX Adieresis udieresis -30 +KPX Adieresis ugrave -30 +KPX Adieresis uhungarumlaut -30 +KPX Adieresis umacron -30 +KPX Adieresis uogonek -30 +KPX Adieresis uring -30 +KPX Adieresis v -40 +KPX Adieresis w -30 +KPX Adieresis y -30 +KPX Adieresis yacute -30 +KPX Adieresis ydieresis -30 +KPX Agrave C -40 +KPX Agrave Cacute -40 +KPX Agrave Ccaron -40 +KPX Agrave Ccedilla -40 +KPX Agrave G -50 +KPX Agrave Gbreve -50 +KPX Agrave Gcommaaccent -50 +KPX Agrave O -40 +KPX Agrave Oacute -40 +KPX Agrave Ocircumflex -40 +KPX Agrave Odieresis -40 +KPX Agrave Ograve -40 +KPX Agrave Ohungarumlaut -40 +KPX Agrave Omacron -40 +KPX Agrave Oslash -40 +KPX Agrave Otilde -40 +KPX Agrave Q -40 +KPX Agrave T -90 +KPX Agrave Tcaron -90 +KPX Agrave Tcommaaccent -90 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -80 +KPX Agrave W -60 +KPX Agrave Y -110 +KPX Agrave Yacute -110 +KPX Agrave Ydieresis -110 +KPX Agrave u -30 +KPX Agrave uacute -30 +KPX Agrave ucircumflex -30 +KPX Agrave udieresis -30 +KPX Agrave ugrave -30 +KPX Agrave uhungarumlaut -30 +KPX Agrave umacron -30 +KPX Agrave uogonek -30 +KPX Agrave uring -30 +KPX Agrave v -40 +KPX Agrave w -30 +KPX Agrave y -30 +KPX Agrave yacute -30 +KPX Agrave ydieresis -30 +KPX Amacron C -40 +KPX Amacron Cacute -40 +KPX Amacron Ccaron -40 +KPX Amacron Ccedilla -40 +KPX Amacron G -50 +KPX Amacron Gbreve -50 +KPX Amacron Gcommaaccent -50 +KPX Amacron O -40 +KPX Amacron Oacute -40 +KPX Amacron Ocircumflex -40 +KPX Amacron Odieresis -40 +KPX Amacron Ograve -40 +KPX Amacron Ohungarumlaut -40 +KPX Amacron Omacron -40 +KPX Amacron Oslash -40 +KPX Amacron Otilde -40 +KPX Amacron Q -40 +KPX Amacron T -90 +KPX Amacron Tcaron -90 +KPX Amacron Tcommaaccent -90 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -80 +KPX Amacron W -60 +KPX Amacron Y -110 +KPX Amacron Yacute -110 +KPX Amacron Ydieresis -110 +KPX Amacron u -30 +KPX Amacron uacute -30 +KPX Amacron ucircumflex -30 +KPX Amacron udieresis -30 +KPX Amacron ugrave -30 +KPX Amacron uhungarumlaut -30 +KPX Amacron umacron -30 +KPX Amacron uogonek -30 +KPX Amacron uring -30 +KPX Amacron v -40 +KPX Amacron w -30 +KPX Amacron y -30 +KPX Amacron yacute -30 +KPX Amacron ydieresis -30 +KPX Aogonek C -40 +KPX Aogonek Cacute -40 +KPX Aogonek Ccaron -40 +KPX Aogonek Ccedilla -40 +KPX Aogonek G -50 +KPX Aogonek Gbreve -50 +KPX Aogonek Gcommaaccent -50 +KPX Aogonek O -40 +KPX Aogonek Oacute -40 +KPX Aogonek Ocircumflex -40 +KPX Aogonek Odieresis -40 +KPX Aogonek Ograve -40 +KPX Aogonek Ohungarumlaut -40 +KPX Aogonek Omacron -40 +KPX Aogonek Oslash -40 +KPX Aogonek Otilde -40 +KPX Aogonek Q -40 +KPX Aogonek T -90 +KPX Aogonek Tcaron -90 +KPX Aogonek Tcommaaccent -90 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -80 +KPX Aogonek W -60 +KPX Aogonek Y -110 +KPX Aogonek Yacute -110 +KPX Aogonek Ydieresis -110 +KPX Aogonek u -30 +KPX Aogonek uacute -30 +KPX Aogonek ucircumflex -30 +KPX Aogonek udieresis -30 +KPX Aogonek ugrave -30 +KPX Aogonek uhungarumlaut -30 +KPX Aogonek umacron -30 +KPX Aogonek uogonek -30 +KPX Aogonek uring -30 +KPX Aogonek v -40 +KPX Aogonek w -30 +KPX Aogonek y -30 +KPX Aogonek yacute -30 +KPX Aogonek ydieresis -30 +KPX Aring C -40 +KPX Aring Cacute -40 +KPX Aring Ccaron -40 +KPX Aring Ccedilla -40 +KPX Aring G -50 +KPX Aring Gbreve -50 +KPX Aring Gcommaaccent -50 +KPX Aring O -40 +KPX Aring Oacute -40 +KPX Aring Ocircumflex -40 +KPX Aring Odieresis -40 +KPX Aring Ograve -40 +KPX Aring Ohungarumlaut -40 +KPX Aring Omacron -40 +KPX Aring Oslash -40 +KPX Aring Otilde -40 +KPX Aring Q -40 +KPX Aring T -90 +KPX Aring Tcaron -90 +KPX Aring Tcommaaccent -90 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -80 +KPX Aring W -60 +KPX Aring Y -110 +KPX Aring Yacute -110 +KPX Aring Ydieresis -110 +KPX Aring u -30 +KPX Aring uacute -30 +KPX Aring ucircumflex -30 +KPX Aring udieresis -30 +KPX Aring ugrave -30 +KPX Aring uhungarumlaut -30 +KPX Aring umacron -30 +KPX Aring uogonek -30 +KPX Aring uring -30 +KPX Aring v -40 +KPX Aring w -30 +KPX Aring y -30 +KPX Aring yacute -30 +KPX Aring ydieresis -30 +KPX Atilde C -40 +KPX Atilde Cacute -40 +KPX Atilde Ccaron -40 +KPX Atilde Ccedilla -40 +KPX Atilde G -50 +KPX Atilde Gbreve -50 +KPX Atilde Gcommaaccent -50 +KPX Atilde O -40 +KPX Atilde Oacute -40 +KPX Atilde Ocircumflex -40 +KPX Atilde Odieresis -40 +KPX Atilde Ograve -40 +KPX Atilde Ohungarumlaut -40 +KPX Atilde Omacron -40 +KPX Atilde Oslash -40 +KPX Atilde Otilde -40 +KPX Atilde Q -40 +KPX Atilde T -90 +KPX Atilde Tcaron -90 +KPX Atilde Tcommaaccent -90 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -80 +KPX Atilde W -60 +KPX Atilde Y -110 +KPX Atilde Yacute -110 +KPX Atilde Ydieresis -110 +KPX Atilde u -30 +KPX Atilde uacute -30 +KPX Atilde ucircumflex -30 +KPX Atilde udieresis -30 +KPX Atilde ugrave -30 +KPX Atilde uhungarumlaut -30 +KPX Atilde umacron -30 +KPX Atilde uogonek -30 +KPX Atilde uring -30 +KPX Atilde v -40 +KPX Atilde w -30 +KPX Atilde y -30 +KPX Atilde yacute -30 +KPX Atilde ydieresis -30 +KPX B A -30 +KPX B Aacute -30 +KPX B Abreve -30 +KPX B Acircumflex -30 +KPX B Adieresis -30 +KPX B Agrave -30 +KPX B Amacron -30 +KPX B Aogonek -30 +KPX B Aring -30 +KPX B Atilde -30 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX D A -40 +KPX D Aacute -40 +KPX D Abreve -40 +KPX D Acircumflex -40 +KPX D Adieresis -40 +KPX D Agrave -40 +KPX D Amacron -40 +KPX D Aogonek -40 +KPX D Aring -40 +KPX D Atilde -40 +KPX D V -40 +KPX D W -40 +KPX D Y -70 +KPX D Yacute -70 +KPX D Ydieresis -70 +KPX D comma -30 +KPX D period -30 +KPX Dcaron A -40 +KPX Dcaron Aacute -40 +KPX Dcaron Abreve -40 +KPX Dcaron Acircumflex -40 +KPX Dcaron Adieresis -40 +KPX Dcaron Agrave -40 +KPX Dcaron Amacron -40 +KPX Dcaron Aogonek -40 +KPX Dcaron Aring -40 +KPX Dcaron Atilde -40 +KPX Dcaron V -40 +KPX Dcaron W -40 +KPX Dcaron Y -70 +KPX Dcaron Yacute -70 +KPX Dcaron Ydieresis -70 +KPX Dcaron comma -30 +KPX Dcaron period -30 +KPX Dcroat A -40 +KPX Dcroat Aacute -40 +KPX Dcroat Abreve -40 +KPX Dcroat Acircumflex -40 +KPX Dcroat Adieresis -40 +KPX Dcroat Agrave -40 +KPX Dcroat Amacron -40 +KPX Dcroat Aogonek -40 +KPX Dcroat Aring -40 +KPX Dcroat Atilde -40 +KPX Dcroat V -40 +KPX Dcroat W -40 +KPX Dcroat Y -70 +KPX Dcroat Yacute -70 +KPX Dcroat Ydieresis -70 +KPX Dcroat comma -30 +KPX Dcroat period -30 +KPX F A -80 +KPX F Aacute -80 +KPX F Abreve -80 +KPX F Acircumflex -80 +KPX F Adieresis -80 +KPX F Agrave -80 +KPX F Amacron -80 +KPX F Aogonek -80 +KPX F Aring -80 +KPX F Atilde -80 +KPX F a -20 +KPX F aacute -20 +KPX F abreve -20 +KPX F acircumflex -20 +KPX F adieresis -20 +KPX F agrave -20 +KPX F amacron -20 +KPX F aogonek -20 +KPX F aring -20 +KPX F atilde -20 +KPX F comma -100 +KPX F period -100 +KPX J A -20 +KPX J Aacute -20 +KPX J Abreve -20 +KPX J Acircumflex -20 +KPX J Adieresis -20 +KPX J Agrave -20 +KPX J Amacron -20 +KPX J Aogonek -20 +KPX J Aring -20 +KPX J Atilde -20 +KPX J comma -20 +KPX J period -20 +KPX J u -20 +KPX J uacute -20 +KPX J ucircumflex -20 +KPX J udieresis -20 +KPX J ugrave -20 +KPX J uhungarumlaut -20 +KPX J umacron -20 +KPX J uogonek -20 +KPX J uring -20 +KPX K O -30 +KPX K Oacute -30 +KPX K Ocircumflex -30 +KPX K Odieresis -30 +KPX K Ograve -30 +KPX K Ohungarumlaut -30 +KPX K Omacron -30 +KPX K Oslash -30 +KPX K Otilde -30 +KPX K e -15 +KPX K eacute -15 +KPX K ecaron -15 +KPX K ecircumflex -15 +KPX K edieresis -15 +KPX K edotaccent -15 +KPX K egrave -15 +KPX K emacron -15 +KPX K eogonek -15 +KPX K o -35 +KPX K oacute -35 +KPX K ocircumflex -35 +KPX K odieresis -35 +KPX K ograve -35 +KPX K ohungarumlaut -35 +KPX K omacron -35 +KPX K oslash -35 +KPX K otilde -35 +KPX K u -30 +KPX K uacute -30 +KPX K ucircumflex -30 +KPX K udieresis -30 +KPX K ugrave -30 +KPX K uhungarumlaut -30 +KPX K umacron -30 +KPX K uogonek -30 +KPX K uring -30 +KPX K y -40 +KPX K yacute -40 +KPX K ydieresis -40 +KPX Kcommaaccent O -30 +KPX Kcommaaccent Oacute -30 +KPX Kcommaaccent Ocircumflex -30 +KPX Kcommaaccent Odieresis -30 +KPX Kcommaaccent Ograve -30 +KPX Kcommaaccent Ohungarumlaut -30 +KPX Kcommaaccent Omacron -30 +KPX Kcommaaccent Oslash -30 +KPX Kcommaaccent Otilde -30 +KPX Kcommaaccent e -15 +KPX Kcommaaccent eacute -15 +KPX Kcommaaccent ecaron -15 +KPX Kcommaaccent ecircumflex -15 +KPX Kcommaaccent edieresis -15 +KPX Kcommaaccent edotaccent -15 +KPX Kcommaaccent egrave -15 +KPX Kcommaaccent emacron -15 +KPX Kcommaaccent eogonek -15 +KPX Kcommaaccent o -35 +KPX Kcommaaccent oacute -35 +KPX Kcommaaccent ocircumflex -35 +KPX Kcommaaccent odieresis -35 +KPX Kcommaaccent ograve -35 +KPX Kcommaaccent ohungarumlaut -35 +KPX Kcommaaccent omacron -35 +KPX Kcommaaccent oslash -35 +KPX Kcommaaccent otilde -35 +KPX Kcommaaccent u -30 +KPX Kcommaaccent uacute -30 +KPX Kcommaaccent ucircumflex -30 +KPX Kcommaaccent udieresis -30 +KPX Kcommaaccent ugrave -30 +KPX Kcommaaccent uhungarumlaut -30 +KPX Kcommaaccent umacron -30 +KPX Kcommaaccent uogonek -30 +KPX Kcommaaccent uring -30 +KPX Kcommaaccent y -40 +KPX Kcommaaccent yacute -40 +KPX Kcommaaccent ydieresis -40 +KPX L T -90 +KPX L Tcaron -90 +KPX L Tcommaaccent -90 +KPX L V -110 +KPX L W -80 +KPX L Y -120 +KPX L Yacute -120 +KPX L Ydieresis -120 +KPX L quotedblright -140 +KPX L quoteright -140 +KPX L y -30 +KPX L yacute -30 +KPX L ydieresis -30 +KPX Lacute T -90 +KPX Lacute Tcaron -90 +KPX Lacute Tcommaaccent -90 +KPX Lacute V -110 +KPX Lacute W -80 +KPX Lacute Y -120 +KPX Lacute Yacute -120 +KPX Lacute Ydieresis -120 +KPX Lacute quotedblright -140 +KPX Lacute quoteright -140 +KPX Lacute y -30 +KPX Lacute yacute -30 +KPX Lacute ydieresis -30 +KPX Lcommaaccent T -90 +KPX Lcommaaccent Tcaron -90 +KPX Lcommaaccent Tcommaaccent -90 +KPX Lcommaaccent V -110 +KPX Lcommaaccent W -80 +KPX Lcommaaccent Y -120 +KPX Lcommaaccent Yacute -120 +KPX Lcommaaccent Ydieresis -120 +KPX Lcommaaccent quotedblright -140 +KPX Lcommaaccent quoteright -140 +KPX Lcommaaccent y -30 +KPX Lcommaaccent yacute -30 +KPX Lcommaaccent ydieresis -30 +KPX Lslash T -90 +KPX Lslash Tcaron -90 +KPX Lslash Tcommaaccent -90 +KPX Lslash V -110 +KPX Lslash W -80 +KPX Lslash Y -120 +KPX Lslash Yacute -120 +KPX Lslash Ydieresis -120 +KPX Lslash quotedblright -140 +KPX Lslash quoteright -140 +KPX Lslash y -30 +KPX Lslash yacute -30 +KPX Lslash ydieresis -30 +KPX O A -50 +KPX O Aacute -50 +KPX O Abreve -50 +KPX O Acircumflex -50 +KPX O Adieresis -50 +KPX O Agrave -50 +KPX O Amacron -50 +KPX O Aogonek -50 +KPX O Aring -50 +KPX O Atilde -50 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -50 +KPX O X -50 +KPX O Y -70 +KPX O Yacute -70 +KPX O Ydieresis -70 +KPX O comma -40 +KPX O period -40 +KPX Oacute A -50 +KPX Oacute Aacute -50 +KPX Oacute Abreve -50 +KPX Oacute Acircumflex -50 +KPX Oacute Adieresis -50 +KPX Oacute Agrave -50 +KPX Oacute Amacron -50 +KPX Oacute Aogonek -50 +KPX Oacute Aring -50 +KPX Oacute Atilde -50 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -50 +KPX Oacute X -50 +KPX Oacute Y -70 +KPX Oacute Yacute -70 +KPX Oacute Ydieresis -70 +KPX Oacute comma -40 +KPX Oacute period -40 +KPX Ocircumflex A -50 +KPX Ocircumflex Aacute -50 +KPX Ocircumflex Abreve -50 +KPX Ocircumflex Acircumflex -50 +KPX Ocircumflex Adieresis -50 +KPX Ocircumflex Agrave -50 +KPX Ocircumflex Amacron -50 +KPX Ocircumflex Aogonek -50 +KPX Ocircumflex Aring -50 +KPX Ocircumflex Atilde -50 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -50 +KPX Ocircumflex X -50 +KPX Ocircumflex Y -70 +KPX Ocircumflex Yacute -70 +KPX Ocircumflex Ydieresis -70 +KPX Ocircumflex comma -40 +KPX Ocircumflex period -40 +KPX Odieresis A -50 +KPX Odieresis Aacute -50 +KPX Odieresis Abreve -50 +KPX Odieresis Acircumflex -50 +KPX Odieresis Adieresis -50 +KPX Odieresis Agrave -50 +KPX Odieresis Amacron -50 +KPX Odieresis Aogonek -50 +KPX Odieresis Aring -50 +KPX Odieresis Atilde -50 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -50 +KPX Odieresis X -50 +KPX Odieresis Y -70 +KPX Odieresis Yacute -70 +KPX Odieresis Ydieresis -70 +KPX Odieresis comma -40 +KPX Odieresis period -40 +KPX Ograve A -50 +KPX Ograve Aacute -50 +KPX Ograve Abreve -50 +KPX Ograve Acircumflex -50 +KPX Ograve Adieresis -50 +KPX Ograve Agrave -50 +KPX Ograve Amacron -50 +KPX Ograve Aogonek -50 +KPX Ograve Aring -50 +KPX Ograve Atilde -50 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -50 +KPX Ograve X -50 +KPX Ograve Y -70 +KPX Ograve Yacute -70 +KPX Ograve Ydieresis -70 +KPX Ograve comma -40 +KPX Ograve period -40 +KPX Ohungarumlaut A -50 +KPX Ohungarumlaut Aacute -50 +KPX Ohungarumlaut Abreve -50 +KPX Ohungarumlaut Acircumflex -50 +KPX Ohungarumlaut Adieresis -50 +KPX Ohungarumlaut Agrave -50 +KPX Ohungarumlaut Amacron -50 +KPX Ohungarumlaut Aogonek -50 +KPX Ohungarumlaut Aring -50 +KPX Ohungarumlaut Atilde -50 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -50 +KPX Ohungarumlaut X -50 +KPX Ohungarumlaut Y -70 +KPX Ohungarumlaut Yacute -70 +KPX Ohungarumlaut Ydieresis -70 +KPX Ohungarumlaut comma -40 +KPX Ohungarumlaut period -40 +KPX Omacron A -50 +KPX Omacron Aacute -50 +KPX Omacron Abreve -50 +KPX Omacron Acircumflex -50 +KPX Omacron Adieresis -50 +KPX Omacron Agrave -50 +KPX Omacron Amacron -50 +KPX Omacron Aogonek -50 +KPX Omacron Aring -50 +KPX Omacron Atilde -50 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -50 +KPX Omacron X -50 +KPX Omacron Y -70 +KPX Omacron Yacute -70 +KPX Omacron Ydieresis -70 +KPX Omacron comma -40 +KPX Omacron period -40 +KPX Oslash A -50 +KPX Oslash Aacute -50 +KPX Oslash Abreve -50 +KPX Oslash Acircumflex -50 +KPX Oslash Adieresis -50 +KPX Oslash Agrave -50 +KPX Oslash Amacron -50 +KPX Oslash Aogonek -50 +KPX Oslash Aring -50 +KPX Oslash Atilde -50 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -50 +KPX Oslash X -50 +KPX Oslash Y -70 +KPX Oslash Yacute -70 +KPX Oslash Ydieresis -70 +KPX Oslash comma -40 +KPX Oslash period -40 +KPX Otilde A -50 +KPX Otilde Aacute -50 +KPX Otilde Abreve -50 +KPX Otilde Acircumflex -50 +KPX Otilde Adieresis -50 +KPX Otilde Agrave -50 +KPX Otilde Amacron -50 +KPX Otilde Aogonek -50 +KPX Otilde Aring -50 +KPX Otilde Atilde -50 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -50 +KPX Otilde X -50 +KPX Otilde Y -70 +KPX Otilde Yacute -70 +KPX Otilde Ydieresis -70 +KPX Otilde comma -40 +KPX Otilde period -40 +KPX P A -100 +KPX P Aacute -100 +KPX P Abreve -100 +KPX P Acircumflex -100 +KPX P Adieresis -100 +KPX P Agrave -100 +KPX P Amacron -100 +KPX P Aogonek -100 +KPX P Aring -100 +KPX P Atilde -100 +KPX P a -30 +KPX P aacute -30 +KPX P abreve -30 +KPX P acircumflex -30 +KPX P adieresis -30 +KPX P agrave -30 +KPX P amacron -30 +KPX P aogonek -30 +KPX P aring -30 +KPX P atilde -30 +KPX P comma -120 +KPX P e -30 +KPX P eacute -30 +KPX P ecaron -30 +KPX P ecircumflex -30 +KPX P edieresis -30 +KPX P edotaccent -30 +KPX P egrave -30 +KPX P emacron -30 +KPX P eogonek -30 +KPX P o -40 +KPX P oacute -40 +KPX P ocircumflex -40 +KPX P odieresis -40 +KPX P ograve -40 +KPX P ohungarumlaut -40 +KPX P omacron -40 +KPX P oslash -40 +KPX P otilde -40 +KPX P period -120 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX Q comma 20 +KPX Q period 20 +KPX R O -20 +KPX R Oacute -20 +KPX R Ocircumflex -20 +KPX R Odieresis -20 +KPX R Ograve -20 +KPX R Ohungarumlaut -20 +KPX R Omacron -20 +KPX R Oslash -20 +KPX R Otilde -20 +KPX R T -20 +KPX R Tcaron -20 +KPX R Tcommaaccent -20 +KPX R U -20 +KPX R Uacute -20 +KPX R Ucircumflex -20 +KPX R Udieresis -20 +KPX R Ugrave -20 +KPX R Uhungarumlaut -20 +KPX R Umacron -20 +KPX R Uogonek -20 +KPX R Uring -20 +KPX R V -50 +KPX R W -40 +KPX R Y -50 +KPX R Yacute -50 +KPX R Ydieresis -50 +KPX Racute O -20 +KPX Racute Oacute -20 +KPX Racute Ocircumflex -20 +KPX Racute Odieresis -20 +KPX Racute Ograve -20 +KPX Racute Ohungarumlaut -20 +KPX Racute Omacron -20 +KPX Racute Oslash -20 +KPX Racute Otilde -20 +KPX Racute T -20 +KPX Racute Tcaron -20 +KPX Racute Tcommaaccent -20 +KPX Racute U -20 +KPX Racute Uacute -20 +KPX Racute Ucircumflex -20 +KPX Racute Udieresis -20 +KPX Racute Ugrave -20 +KPX Racute Uhungarumlaut -20 +KPX Racute Umacron -20 +KPX Racute Uogonek -20 +KPX Racute Uring -20 +KPX Racute V -50 +KPX Racute W -40 +KPX Racute Y -50 +KPX Racute Yacute -50 +KPX Racute Ydieresis -50 +KPX Rcaron O -20 +KPX Rcaron Oacute -20 +KPX Rcaron Ocircumflex -20 +KPX Rcaron Odieresis -20 +KPX Rcaron Ograve -20 +KPX Rcaron Ohungarumlaut -20 +KPX Rcaron Omacron -20 +KPX Rcaron Oslash -20 +KPX Rcaron Otilde -20 +KPX Rcaron T -20 +KPX Rcaron Tcaron -20 +KPX Rcaron Tcommaaccent -20 +KPX Rcaron U -20 +KPX Rcaron Uacute -20 +KPX Rcaron Ucircumflex -20 +KPX Rcaron Udieresis -20 +KPX Rcaron Ugrave -20 +KPX Rcaron Uhungarumlaut -20 +KPX Rcaron Umacron -20 +KPX Rcaron Uogonek -20 +KPX Rcaron Uring -20 +KPX Rcaron V -50 +KPX Rcaron W -40 +KPX Rcaron Y -50 +KPX Rcaron Yacute -50 +KPX Rcaron Ydieresis -50 +KPX Rcommaaccent O -20 +KPX Rcommaaccent Oacute -20 +KPX Rcommaaccent Ocircumflex -20 +KPX Rcommaaccent Odieresis -20 +KPX Rcommaaccent Ograve -20 +KPX Rcommaaccent Ohungarumlaut -20 +KPX Rcommaaccent Omacron -20 +KPX Rcommaaccent Oslash -20 +KPX Rcommaaccent Otilde -20 +KPX Rcommaaccent T -20 +KPX Rcommaaccent Tcaron -20 +KPX Rcommaaccent Tcommaaccent -20 +KPX Rcommaaccent U -20 +KPX Rcommaaccent Uacute -20 +KPX Rcommaaccent Ucircumflex -20 +KPX Rcommaaccent Udieresis -20 +KPX Rcommaaccent Ugrave -20 +KPX Rcommaaccent Uhungarumlaut -20 +KPX Rcommaaccent Umacron -20 +KPX Rcommaaccent Uogonek -20 +KPX Rcommaaccent Uring -20 +KPX Rcommaaccent V -50 +KPX Rcommaaccent W -40 +KPX Rcommaaccent Y -50 +KPX Rcommaaccent Yacute -50 +KPX Rcommaaccent Ydieresis -50 +KPX T A -90 +KPX T Aacute -90 +KPX T Abreve -90 +KPX T Acircumflex -90 +KPX T Adieresis -90 +KPX T Agrave -90 +KPX T Amacron -90 +KPX T Aogonek -90 +KPX T Aring -90 +KPX T Atilde -90 +KPX T O -40 +KPX T Oacute -40 +KPX T Ocircumflex -40 +KPX T Odieresis -40 +KPX T Ograve -40 +KPX T Ohungarumlaut -40 +KPX T Omacron -40 +KPX T Oslash -40 +KPX T Otilde -40 +KPX T a -80 +KPX T aacute -80 +KPX T abreve -80 +KPX T acircumflex -80 +KPX T adieresis -80 +KPX T agrave -80 +KPX T amacron -80 +KPX T aogonek -80 +KPX T aring -80 +KPX T atilde -80 +KPX T colon -40 +KPX T comma -80 +KPX T e -60 +KPX T eacute -60 +KPX T ecaron -60 +KPX T ecircumflex -60 +KPX T edieresis -60 +KPX T edotaccent -60 +KPX T egrave -60 +KPX T emacron -60 +KPX T eogonek -60 +KPX T hyphen -120 +KPX T o -80 +KPX T oacute -80 +KPX T ocircumflex -80 +KPX T odieresis -80 +KPX T ograve -80 +KPX T ohungarumlaut -80 +KPX T omacron -80 +KPX T oslash -80 +KPX T otilde -80 +KPX T period -80 +KPX T r -80 +KPX T racute -80 +KPX T rcommaaccent -80 +KPX T semicolon -40 +KPX T u -90 +KPX T uacute -90 +KPX T ucircumflex -90 +KPX T udieresis -90 +KPX T ugrave -90 +KPX T uhungarumlaut -90 +KPX T umacron -90 +KPX T uogonek -90 +KPX T uring -90 +KPX T w -60 +KPX T y -60 +KPX T yacute -60 +KPX T ydieresis -60 +KPX Tcaron A -90 +KPX Tcaron Aacute -90 +KPX Tcaron Abreve -90 +KPX Tcaron Acircumflex -90 +KPX Tcaron Adieresis -90 +KPX Tcaron Agrave -90 +KPX Tcaron Amacron -90 +KPX Tcaron Aogonek -90 +KPX Tcaron Aring -90 +KPX Tcaron Atilde -90 +KPX Tcaron O -40 +KPX Tcaron Oacute -40 +KPX Tcaron Ocircumflex -40 +KPX Tcaron Odieresis -40 +KPX Tcaron Ograve -40 +KPX Tcaron Ohungarumlaut -40 +KPX Tcaron Omacron -40 +KPX Tcaron Oslash -40 +KPX Tcaron Otilde -40 +KPX Tcaron a -80 +KPX Tcaron aacute -80 +KPX Tcaron abreve -80 +KPX Tcaron acircumflex -80 +KPX Tcaron adieresis -80 +KPX Tcaron agrave -80 +KPX Tcaron amacron -80 +KPX Tcaron aogonek -80 +KPX Tcaron aring -80 +KPX Tcaron atilde -80 +KPX Tcaron colon -40 +KPX Tcaron comma -80 +KPX Tcaron e -60 +KPX Tcaron eacute -60 +KPX Tcaron ecaron -60 +KPX Tcaron ecircumflex -60 +KPX Tcaron edieresis -60 +KPX Tcaron edotaccent -60 +KPX Tcaron egrave -60 +KPX Tcaron emacron -60 +KPX Tcaron eogonek -60 +KPX Tcaron hyphen -120 +KPX Tcaron o -80 +KPX Tcaron oacute -80 +KPX Tcaron ocircumflex -80 +KPX Tcaron odieresis -80 +KPX Tcaron ograve -80 +KPX Tcaron ohungarumlaut -80 +KPX Tcaron omacron -80 +KPX Tcaron oslash -80 +KPX Tcaron otilde -80 +KPX Tcaron period -80 +KPX Tcaron r -80 +KPX Tcaron racute -80 +KPX Tcaron rcommaaccent -80 +KPX Tcaron semicolon -40 +KPX Tcaron u -90 +KPX Tcaron uacute -90 +KPX Tcaron ucircumflex -90 +KPX Tcaron udieresis -90 +KPX Tcaron ugrave -90 +KPX Tcaron uhungarumlaut -90 +KPX Tcaron umacron -90 +KPX Tcaron uogonek -90 +KPX Tcaron uring -90 +KPX Tcaron w -60 +KPX Tcaron y -60 +KPX Tcaron yacute -60 +KPX Tcaron ydieresis -60 +KPX Tcommaaccent A -90 +KPX Tcommaaccent Aacute -90 +KPX Tcommaaccent Abreve -90 +KPX Tcommaaccent Acircumflex -90 +KPX Tcommaaccent Adieresis -90 +KPX Tcommaaccent Agrave -90 +KPX Tcommaaccent Amacron -90 +KPX Tcommaaccent Aogonek -90 +KPX Tcommaaccent Aring -90 +KPX Tcommaaccent Atilde -90 +KPX Tcommaaccent O -40 +KPX Tcommaaccent Oacute -40 +KPX Tcommaaccent Ocircumflex -40 +KPX Tcommaaccent Odieresis -40 +KPX Tcommaaccent Ograve -40 +KPX Tcommaaccent Ohungarumlaut -40 +KPX Tcommaaccent Omacron -40 +KPX Tcommaaccent Oslash -40 +KPX Tcommaaccent Otilde -40 +KPX Tcommaaccent a -80 +KPX Tcommaaccent aacute -80 +KPX Tcommaaccent abreve -80 +KPX Tcommaaccent acircumflex -80 +KPX Tcommaaccent adieresis -80 +KPX Tcommaaccent agrave -80 +KPX Tcommaaccent amacron -80 +KPX Tcommaaccent aogonek -80 +KPX Tcommaaccent aring -80 +KPX Tcommaaccent atilde -80 +KPX Tcommaaccent colon -40 +KPX Tcommaaccent comma -80 +KPX Tcommaaccent e -60 +KPX Tcommaaccent eacute -60 +KPX Tcommaaccent ecaron -60 +KPX Tcommaaccent ecircumflex -60 +KPX Tcommaaccent edieresis -60 +KPX Tcommaaccent edotaccent -60 +KPX Tcommaaccent egrave -60 +KPX Tcommaaccent emacron -60 +KPX Tcommaaccent eogonek -60 +KPX Tcommaaccent hyphen -120 +KPX Tcommaaccent o -80 +KPX Tcommaaccent oacute -80 +KPX Tcommaaccent ocircumflex -80 +KPX Tcommaaccent odieresis -80 +KPX Tcommaaccent ograve -80 +KPX Tcommaaccent ohungarumlaut -80 +KPX Tcommaaccent omacron -80 +KPX Tcommaaccent oslash -80 +KPX Tcommaaccent otilde -80 +KPX Tcommaaccent period -80 +KPX Tcommaaccent r -80 +KPX Tcommaaccent racute -80 +KPX Tcommaaccent rcommaaccent -80 +KPX Tcommaaccent semicolon -40 +KPX Tcommaaccent u -90 +KPX Tcommaaccent uacute -90 +KPX Tcommaaccent ucircumflex -90 +KPX Tcommaaccent udieresis -90 +KPX Tcommaaccent ugrave -90 +KPX Tcommaaccent uhungarumlaut -90 +KPX Tcommaaccent umacron -90 +KPX Tcommaaccent uogonek -90 +KPX Tcommaaccent uring -90 +KPX Tcommaaccent w -60 +KPX Tcommaaccent y -60 +KPX Tcommaaccent yacute -60 +KPX Tcommaaccent ydieresis -60 +KPX U A -50 +KPX U Aacute -50 +KPX U Abreve -50 +KPX U Acircumflex -50 +KPX U Adieresis -50 +KPX U Agrave -50 +KPX U Amacron -50 +KPX U Aogonek -50 +KPX U Aring -50 +KPX U Atilde -50 +KPX U comma -30 +KPX U period -30 +KPX Uacute A -50 +KPX Uacute Aacute -50 +KPX Uacute Abreve -50 +KPX Uacute Acircumflex -50 +KPX Uacute Adieresis -50 +KPX Uacute Agrave -50 +KPX Uacute Amacron -50 +KPX Uacute Aogonek -50 +KPX Uacute Aring -50 +KPX Uacute Atilde -50 +KPX Uacute comma -30 +KPX Uacute period -30 +KPX Ucircumflex A -50 +KPX Ucircumflex Aacute -50 +KPX Ucircumflex Abreve -50 +KPX Ucircumflex Acircumflex -50 +KPX Ucircumflex Adieresis -50 +KPX Ucircumflex Agrave -50 +KPX Ucircumflex Amacron -50 +KPX Ucircumflex Aogonek -50 +KPX Ucircumflex Aring -50 +KPX Ucircumflex Atilde -50 +KPX Ucircumflex comma -30 +KPX Ucircumflex period -30 +KPX Udieresis A -50 +KPX Udieresis Aacute -50 +KPX Udieresis Abreve -50 +KPX Udieresis Acircumflex -50 +KPX Udieresis Adieresis -50 +KPX Udieresis Agrave -50 +KPX Udieresis Amacron -50 +KPX Udieresis Aogonek -50 +KPX Udieresis Aring -50 +KPX Udieresis Atilde -50 +KPX Udieresis comma -30 +KPX Udieresis period -30 +KPX Ugrave A -50 +KPX Ugrave Aacute -50 +KPX Ugrave Abreve -50 +KPX Ugrave Acircumflex -50 +KPX Ugrave Adieresis -50 +KPX Ugrave Agrave -50 +KPX Ugrave Amacron -50 +KPX Ugrave Aogonek -50 +KPX Ugrave Aring -50 +KPX Ugrave Atilde -50 +KPX Ugrave comma -30 +KPX Ugrave period -30 +KPX Uhungarumlaut A -50 +KPX Uhungarumlaut Aacute -50 +KPX Uhungarumlaut Abreve -50 +KPX Uhungarumlaut Acircumflex -50 +KPX Uhungarumlaut Adieresis -50 +KPX Uhungarumlaut Agrave -50 +KPX Uhungarumlaut Amacron -50 +KPX Uhungarumlaut Aogonek -50 +KPX Uhungarumlaut Aring -50 +KPX Uhungarumlaut Atilde -50 +KPX Uhungarumlaut comma -30 +KPX Uhungarumlaut period -30 +KPX Umacron A -50 +KPX Umacron Aacute -50 +KPX Umacron Abreve -50 +KPX Umacron Acircumflex -50 +KPX Umacron Adieresis -50 +KPX Umacron Agrave -50 +KPX Umacron Amacron -50 +KPX Umacron Aogonek -50 +KPX Umacron Aring -50 +KPX Umacron Atilde -50 +KPX Umacron comma -30 +KPX Umacron period -30 +KPX Uogonek A -50 +KPX Uogonek Aacute -50 +KPX Uogonek Abreve -50 +KPX Uogonek Acircumflex -50 +KPX Uogonek Adieresis -50 +KPX Uogonek Agrave -50 +KPX Uogonek Amacron -50 +KPX Uogonek Aogonek -50 +KPX Uogonek Aring -50 +KPX Uogonek Atilde -50 +KPX Uogonek comma -30 +KPX Uogonek period -30 +KPX Uring A -50 +KPX Uring Aacute -50 +KPX Uring Abreve -50 +KPX Uring Acircumflex -50 +KPX Uring Adieresis -50 +KPX Uring Agrave -50 +KPX Uring Amacron -50 +KPX Uring Aogonek -50 +KPX Uring Aring -50 +KPX Uring Atilde -50 +KPX Uring comma -30 +KPX Uring period -30 +KPX V A -80 +KPX V Aacute -80 +KPX V Abreve -80 +KPX V Acircumflex -80 +KPX V Adieresis -80 +KPX V Agrave -80 +KPX V Amacron -80 +KPX V Aogonek -80 +KPX V Aring -80 +KPX V Atilde -80 +KPX V G -50 +KPX V Gbreve -50 +KPX V Gcommaaccent -50 +KPX V O -50 +KPX V Oacute -50 +KPX V Ocircumflex -50 +KPX V Odieresis -50 +KPX V Ograve -50 +KPX V Ohungarumlaut -50 +KPX V Omacron -50 +KPX V Oslash -50 +KPX V Otilde -50 +KPX V a -60 +KPX V aacute -60 +KPX V abreve -60 +KPX V acircumflex -60 +KPX V adieresis -60 +KPX V agrave -60 +KPX V amacron -60 +KPX V aogonek -60 +KPX V aring -60 +KPX V atilde -60 +KPX V colon -40 +KPX V comma -120 +KPX V e -50 +KPX V eacute -50 +KPX V ecaron -50 +KPX V ecircumflex -50 +KPX V edieresis -50 +KPX V edotaccent -50 +KPX V egrave -50 +KPX V emacron -50 +KPX V eogonek -50 +KPX V hyphen -80 +KPX V o -90 +KPX V oacute -90 +KPX V ocircumflex -90 +KPX V odieresis -90 +KPX V ograve -90 +KPX V ohungarumlaut -90 +KPX V omacron -90 +KPX V oslash -90 +KPX V otilde -90 +KPX V period -120 +KPX V semicolon -40 +KPX V u -60 +KPX V uacute -60 +KPX V ucircumflex -60 +KPX V udieresis -60 +KPX V ugrave -60 +KPX V uhungarumlaut -60 +KPX V umacron -60 +KPX V uogonek -60 +KPX V uring -60 +KPX W A -60 +KPX W Aacute -60 +KPX W Abreve -60 +KPX W Acircumflex -60 +KPX W Adieresis -60 +KPX W Agrave -60 +KPX W Amacron -60 +KPX W Aogonek -60 +KPX W Aring -60 +KPX W Atilde -60 +KPX W O -20 +KPX W Oacute -20 +KPX W Ocircumflex -20 +KPX W Odieresis -20 +KPX W Ograve -20 +KPX W Ohungarumlaut -20 +KPX W Omacron -20 +KPX W Oslash -20 +KPX W Otilde -20 +KPX W a -40 +KPX W aacute -40 +KPX W abreve -40 +KPX W acircumflex -40 +KPX W adieresis -40 +KPX W agrave -40 +KPX W amacron -40 +KPX W aogonek -40 +KPX W aring -40 +KPX W atilde -40 +KPX W colon -10 +KPX W comma -80 +KPX W e -35 +KPX W eacute -35 +KPX W ecaron -35 +KPX W ecircumflex -35 +KPX W edieresis -35 +KPX W edotaccent -35 +KPX W egrave -35 +KPX W emacron -35 +KPX W eogonek -35 +KPX W hyphen -40 +KPX W o -60 +KPX W oacute -60 +KPX W ocircumflex -60 +KPX W odieresis -60 +KPX W ograve -60 +KPX W ohungarumlaut -60 +KPX W omacron -60 +KPX W oslash -60 +KPX W otilde -60 +KPX W period -80 +KPX W semicolon -10 +KPX W u -45 +KPX W uacute -45 +KPX W ucircumflex -45 +KPX W udieresis -45 +KPX W ugrave -45 +KPX W uhungarumlaut -45 +KPX W umacron -45 +KPX W uogonek -45 +KPX W uring -45 +KPX W y -20 +KPX W yacute -20 +KPX W ydieresis -20 +KPX Y A -110 +KPX Y Aacute -110 +KPX Y Abreve -110 +KPX Y Acircumflex -110 +KPX Y Adieresis -110 +KPX Y Agrave -110 +KPX Y Amacron -110 +KPX Y Aogonek -110 +KPX Y Aring -110 +KPX Y Atilde -110 +KPX Y O -70 +KPX Y Oacute -70 +KPX Y Ocircumflex -70 +KPX Y Odieresis -70 +KPX Y Ograve -70 +KPX Y Ohungarumlaut -70 +KPX Y Omacron -70 +KPX Y Oslash -70 +KPX Y Otilde -70 +KPX Y a -90 +KPX Y aacute -90 +KPX Y abreve -90 +KPX Y acircumflex -90 +KPX Y adieresis -90 +KPX Y agrave -90 +KPX Y amacron -90 +KPX Y aogonek -90 +KPX Y aring -90 +KPX Y atilde -90 +KPX Y colon -50 +KPX Y comma -100 +KPX Y e -80 +KPX Y eacute -80 +KPX Y ecaron -80 +KPX Y ecircumflex -80 +KPX Y edieresis -80 +KPX Y edotaccent -80 +KPX Y egrave -80 +KPX Y emacron -80 +KPX Y eogonek -80 +KPX Y o -100 +KPX Y oacute -100 +KPX Y ocircumflex -100 +KPX Y odieresis -100 +KPX Y ograve -100 +KPX Y ohungarumlaut -100 +KPX Y omacron -100 +KPX Y oslash -100 +KPX Y otilde -100 +KPX Y period -100 +KPX Y semicolon -50 +KPX Y u -100 +KPX Y uacute -100 +KPX Y ucircumflex -100 +KPX Y udieresis -100 +KPX Y ugrave -100 +KPX Y uhungarumlaut -100 +KPX Y umacron -100 +KPX Y uogonek -100 +KPX Y uring -100 +KPX Yacute A -110 +KPX Yacute Aacute -110 +KPX Yacute Abreve -110 +KPX Yacute Acircumflex -110 +KPX Yacute Adieresis -110 +KPX Yacute Agrave -110 +KPX Yacute Amacron -110 +KPX Yacute Aogonek -110 +KPX Yacute Aring -110 +KPX Yacute Atilde -110 +KPX Yacute O -70 +KPX Yacute Oacute -70 +KPX Yacute Ocircumflex -70 +KPX Yacute Odieresis -70 +KPX Yacute Ograve -70 +KPX Yacute Ohungarumlaut -70 +KPX Yacute Omacron -70 +KPX Yacute Oslash -70 +KPX Yacute Otilde -70 +KPX Yacute a -90 +KPX Yacute aacute -90 +KPX Yacute abreve -90 +KPX Yacute acircumflex -90 +KPX Yacute adieresis -90 +KPX Yacute agrave -90 +KPX Yacute amacron -90 +KPX Yacute aogonek -90 +KPX Yacute aring -90 +KPX Yacute atilde -90 +KPX Yacute colon -50 +KPX Yacute comma -100 +KPX Yacute e -80 +KPX Yacute eacute -80 +KPX Yacute ecaron -80 +KPX Yacute ecircumflex -80 +KPX Yacute edieresis -80 +KPX Yacute edotaccent -80 +KPX Yacute egrave -80 +KPX Yacute emacron -80 +KPX Yacute eogonek -80 +KPX Yacute o -100 +KPX Yacute oacute -100 +KPX Yacute ocircumflex -100 +KPX Yacute odieresis -100 +KPX Yacute ograve -100 +KPX Yacute ohungarumlaut -100 +KPX Yacute omacron -100 +KPX Yacute oslash -100 +KPX Yacute otilde -100 +KPX Yacute period -100 +KPX Yacute semicolon -50 +KPX Yacute u -100 +KPX Yacute uacute -100 +KPX Yacute ucircumflex -100 +KPX Yacute udieresis -100 +KPX Yacute ugrave -100 +KPX Yacute uhungarumlaut -100 +KPX Yacute umacron -100 +KPX Yacute uogonek -100 +KPX Yacute uring -100 +KPX Ydieresis A -110 +KPX Ydieresis Aacute -110 +KPX Ydieresis Abreve -110 +KPX Ydieresis Acircumflex -110 +KPX Ydieresis Adieresis -110 +KPX Ydieresis Agrave -110 +KPX Ydieresis Amacron -110 +KPX Ydieresis Aogonek -110 +KPX Ydieresis Aring -110 +KPX Ydieresis Atilde -110 +KPX Ydieresis O -70 +KPX Ydieresis Oacute -70 +KPX Ydieresis Ocircumflex -70 +KPX Ydieresis Odieresis -70 +KPX Ydieresis Ograve -70 +KPX Ydieresis Ohungarumlaut -70 +KPX Ydieresis Omacron -70 +KPX Ydieresis Oslash -70 +KPX Ydieresis Otilde -70 +KPX Ydieresis a -90 +KPX Ydieresis aacute -90 +KPX Ydieresis abreve -90 +KPX Ydieresis acircumflex -90 +KPX Ydieresis adieresis -90 +KPX Ydieresis agrave -90 +KPX Ydieresis amacron -90 +KPX Ydieresis aogonek -90 +KPX Ydieresis aring -90 +KPX Ydieresis atilde -90 +KPX Ydieresis colon -50 +KPX Ydieresis comma -100 +KPX Ydieresis e -80 +KPX Ydieresis eacute -80 +KPX Ydieresis ecaron -80 +KPX Ydieresis ecircumflex -80 +KPX Ydieresis edieresis -80 +KPX Ydieresis edotaccent -80 +KPX Ydieresis egrave -80 +KPX Ydieresis emacron -80 +KPX Ydieresis eogonek -80 +KPX Ydieresis o -100 +KPX Ydieresis oacute -100 +KPX Ydieresis ocircumflex -100 +KPX Ydieresis odieresis -100 +KPX Ydieresis ograve -100 +KPX Ydieresis ohungarumlaut -100 +KPX Ydieresis omacron -100 +KPX Ydieresis oslash -100 +KPX Ydieresis otilde -100 +KPX Ydieresis period -100 +KPX Ydieresis semicolon -50 +KPX Ydieresis u -100 +KPX Ydieresis uacute -100 +KPX Ydieresis ucircumflex -100 +KPX Ydieresis udieresis -100 +KPX Ydieresis ugrave -100 +KPX Ydieresis uhungarumlaut -100 +KPX Ydieresis umacron -100 +KPX Ydieresis uogonek -100 +KPX Ydieresis uring -100 +KPX a g -10 +KPX a gbreve -10 +KPX a gcommaaccent -10 +KPX a v -15 +KPX a w -15 +KPX a y -20 +KPX a yacute -20 +KPX a ydieresis -20 +KPX aacute g -10 +KPX aacute gbreve -10 +KPX aacute gcommaaccent -10 +KPX aacute v -15 +KPX aacute w -15 +KPX aacute y -20 +KPX aacute yacute -20 +KPX aacute ydieresis -20 +KPX abreve g -10 +KPX abreve gbreve -10 +KPX abreve gcommaaccent -10 +KPX abreve v -15 +KPX abreve w -15 +KPX abreve y -20 +KPX abreve yacute -20 +KPX abreve ydieresis -20 +KPX acircumflex g -10 +KPX acircumflex gbreve -10 +KPX acircumflex gcommaaccent -10 +KPX acircumflex v -15 +KPX acircumflex w -15 +KPX acircumflex y -20 +KPX acircumflex yacute -20 +KPX acircumflex ydieresis -20 +KPX adieresis g -10 +KPX adieresis gbreve -10 +KPX adieresis gcommaaccent -10 +KPX adieresis v -15 +KPX adieresis w -15 +KPX adieresis y -20 +KPX adieresis yacute -20 +KPX adieresis ydieresis -20 +KPX agrave g -10 +KPX agrave gbreve -10 +KPX agrave gcommaaccent -10 +KPX agrave v -15 +KPX agrave w -15 +KPX agrave y -20 +KPX agrave yacute -20 +KPX agrave ydieresis -20 +KPX amacron g -10 +KPX amacron gbreve -10 +KPX amacron gcommaaccent -10 +KPX amacron v -15 +KPX amacron w -15 +KPX amacron y -20 +KPX amacron yacute -20 +KPX amacron ydieresis -20 +KPX aogonek g -10 +KPX aogonek gbreve -10 +KPX aogonek gcommaaccent -10 +KPX aogonek v -15 +KPX aogonek w -15 +KPX aogonek y -20 +KPX aogonek yacute -20 +KPX aogonek ydieresis -20 +KPX aring g -10 +KPX aring gbreve -10 +KPX aring gcommaaccent -10 +KPX aring v -15 +KPX aring w -15 +KPX aring y -20 +KPX aring yacute -20 +KPX aring ydieresis -20 +KPX atilde g -10 +KPX atilde gbreve -10 +KPX atilde gcommaaccent -10 +KPX atilde v -15 +KPX atilde w -15 +KPX atilde y -20 +KPX atilde yacute -20 +KPX atilde ydieresis -20 +KPX b l -10 +KPX b lacute -10 +KPX b lcommaaccent -10 +KPX b lslash -10 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX b v -20 +KPX b y -20 +KPX b yacute -20 +KPX b ydieresis -20 +KPX c h -10 +KPX c k -20 +KPX c kcommaaccent -20 +KPX c l -20 +KPX c lacute -20 +KPX c lcommaaccent -20 +KPX c lslash -20 +KPX c y -10 +KPX c yacute -10 +KPX c ydieresis -10 +KPX cacute h -10 +KPX cacute k -20 +KPX cacute kcommaaccent -20 +KPX cacute l -20 +KPX cacute lacute -20 +KPX cacute lcommaaccent -20 +KPX cacute lslash -20 +KPX cacute y -10 +KPX cacute yacute -10 +KPX cacute ydieresis -10 +KPX ccaron h -10 +KPX ccaron k -20 +KPX ccaron kcommaaccent -20 +KPX ccaron l -20 +KPX ccaron lacute -20 +KPX ccaron lcommaaccent -20 +KPX ccaron lslash -20 +KPX ccaron y -10 +KPX ccaron yacute -10 +KPX ccaron ydieresis -10 +KPX ccedilla h -10 +KPX ccedilla k -20 +KPX ccedilla kcommaaccent -20 +KPX ccedilla l -20 +KPX ccedilla lacute -20 +KPX ccedilla lcommaaccent -20 +KPX ccedilla lslash -20 +KPX ccedilla y -10 +KPX ccedilla yacute -10 +KPX ccedilla ydieresis -10 +KPX colon space -40 +KPX comma quotedblright -120 +KPX comma quoteright -120 +KPX comma space -40 +KPX d d -10 +KPX d dcroat -10 +KPX d v -15 +KPX d w -15 +KPX d y -15 +KPX d yacute -15 +KPX d ydieresis -15 +KPX dcroat d -10 +KPX dcroat dcroat -10 +KPX dcroat v -15 +KPX dcroat w -15 +KPX dcroat y -15 +KPX dcroat yacute -15 +KPX dcroat ydieresis -15 +KPX e comma 10 +KPX e period 20 +KPX e v -15 +KPX e w -15 +KPX e x -15 +KPX e y -15 +KPX e yacute -15 +KPX e ydieresis -15 +KPX eacute comma 10 +KPX eacute period 20 +KPX eacute v -15 +KPX eacute w -15 +KPX eacute x -15 +KPX eacute y -15 +KPX eacute yacute -15 +KPX eacute ydieresis -15 +KPX ecaron comma 10 +KPX ecaron period 20 +KPX ecaron v -15 +KPX ecaron w -15 +KPX ecaron x -15 +KPX ecaron y -15 +KPX ecaron yacute -15 +KPX ecaron ydieresis -15 +KPX ecircumflex comma 10 +KPX ecircumflex period 20 +KPX ecircumflex v -15 +KPX ecircumflex w -15 +KPX ecircumflex x -15 +KPX ecircumflex y -15 +KPX ecircumflex yacute -15 +KPX ecircumflex ydieresis -15 +KPX edieresis comma 10 +KPX edieresis period 20 +KPX edieresis v -15 +KPX edieresis w -15 +KPX edieresis x -15 +KPX edieresis y -15 +KPX edieresis yacute -15 +KPX edieresis ydieresis -15 +KPX edotaccent comma 10 +KPX edotaccent period 20 +KPX edotaccent v -15 +KPX edotaccent w -15 +KPX edotaccent x -15 +KPX edotaccent y -15 +KPX edotaccent yacute -15 +KPX edotaccent ydieresis -15 +KPX egrave comma 10 +KPX egrave period 20 +KPX egrave v -15 +KPX egrave w -15 +KPX egrave x -15 +KPX egrave y -15 +KPX egrave yacute -15 +KPX egrave ydieresis -15 +KPX emacron comma 10 +KPX emacron period 20 +KPX emacron v -15 +KPX emacron w -15 +KPX emacron x -15 +KPX emacron y -15 +KPX emacron yacute -15 +KPX emacron ydieresis -15 +KPX eogonek comma 10 +KPX eogonek period 20 +KPX eogonek v -15 +KPX eogonek w -15 +KPX eogonek x -15 +KPX eogonek y -15 +KPX eogonek yacute -15 +KPX eogonek ydieresis -15 +KPX f comma -10 +KPX f e -10 +KPX f eacute -10 +KPX f ecaron -10 +KPX f ecircumflex -10 +KPX f edieresis -10 +KPX f edotaccent -10 +KPX f egrave -10 +KPX f emacron -10 +KPX f eogonek -10 +KPX f o -20 +KPX f oacute -20 +KPX f ocircumflex -20 +KPX f odieresis -20 +KPX f ograve -20 +KPX f ohungarumlaut -20 +KPX f omacron -20 +KPX f oslash -20 +KPX f otilde -20 +KPX f period -10 +KPX f quotedblright 30 +KPX f quoteright 30 +KPX g e 10 +KPX g eacute 10 +KPX g ecaron 10 +KPX g ecircumflex 10 +KPX g edieresis 10 +KPX g edotaccent 10 +KPX g egrave 10 +KPX g emacron 10 +KPX g eogonek 10 +KPX g g -10 +KPX g gbreve -10 +KPX g gcommaaccent -10 +KPX gbreve e 10 +KPX gbreve eacute 10 +KPX gbreve ecaron 10 +KPX gbreve ecircumflex 10 +KPX gbreve edieresis 10 +KPX gbreve edotaccent 10 +KPX gbreve egrave 10 +KPX gbreve emacron 10 +KPX gbreve eogonek 10 +KPX gbreve g -10 +KPX gbreve gbreve -10 +KPX gbreve gcommaaccent -10 +KPX gcommaaccent e 10 +KPX gcommaaccent eacute 10 +KPX gcommaaccent ecaron 10 +KPX gcommaaccent ecircumflex 10 +KPX gcommaaccent edieresis 10 +KPX gcommaaccent edotaccent 10 +KPX gcommaaccent egrave 10 +KPX gcommaaccent emacron 10 +KPX gcommaaccent eogonek 10 +KPX gcommaaccent g -10 +KPX gcommaaccent gbreve -10 +KPX gcommaaccent gcommaaccent -10 +KPX h y -20 +KPX h yacute -20 +KPX h ydieresis -20 +KPX k o -15 +KPX k oacute -15 +KPX k ocircumflex -15 +KPX k odieresis -15 +KPX k ograve -15 +KPX k ohungarumlaut -15 +KPX k omacron -15 +KPX k oslash -15 +KPX k otilde -15 +KPX kcommaaccent o -15 +KPX kcommaaccent oacute -15 +KPX kcommaaccent ocircumflex -15 +KPX kcommaaccent odieresis -15 +KPX kcommaaccent ograve -15 +KPX kcommaaccent ohungarumlaut -15 +KPX kcommaaccent omacron -15 +KPX kcommaaccent oslash -15 +KPX kcommaaccent otilde -15 +KPX l w -15 +KPX l y -15 +KPX l yacute -15 +KPX l ydieresis -15 +KPX lacute w -15 +KPX lacute y -15 +KPX lacute yacute -15 +KPX lacute ydieresis -15 +KPX lcommaaccent w -15 +KPX lcommaaccent y -15 +KPX lcommaaccent yacute -15 +KPX lcommaaccent ydieresis -15 +KPX lslash w -15 +KPX lslash y -15 +KPX lslash yacute -15 +KPX lslash ydieresis -15 +KPX m u -20 +KPX m uacute -20 +KPX m ucircumflex -20 +KPX m udieresis -20 +KPX m ugrave -20 +KPX m uhungarumlaut -20 +KPX m umacron -20 +KPX m uogonek -20 +KPX m uring -20 +KPX m y -30 +KPX m yacute -30 +KPX m ydieresis -30 +KPX n u -10 +KPX n uacute -10 +KPX n ucircumflex -10 +KPX n udieresis -10 +KPX n ugrave -10 +KPX n uhungarumlaut -10 +KPX n umacron -10 +KPX n uogonek -10 +KPX n uring -10 +KPX n v -40 +KPX n y -20 +KPX n yacute -20 +KPX n ydieresis -20 +KPX nacute u -10 +KPX nacute uacute -10 +KPX nacute ucircumflex -10 +KPX nacute udieresis -10 +KPX nacute ugrave -10 +KPX nacute uhungarumlaut -10 +KPX nacute umacron -10 +KPX nacute uogonek -10 +KPX nacute uring -10 +KPX nacute v -40 +KPX nacute y -20 +KPX nacute yacute -20 +KPX nacute ydieresis -20 +KPX ncaron u -10 +KPX ncaron uacute -10 +KPX ncaron ucircumflex -10 +KPX ncaron udieresis -10 +KPX ncaron ugrave -10 +KPX ncaron uhungarumlaut -10 +KPX ncaron umacron -10 +KPX ncaron uogonek -10 +KPX ncaron uring -10 +KPX ncaron v -40 +KPX ncaron y -20 +KPX ncaron yacute -20 +KPX ncaron ydieresis -20 +KPX ncommaaccent u -10 +KPX ncommaaccent uacute -10 +KPX ncommaaccent ucircumflex -10 +KPX ncommaaccent udieresis -10 +KPX ncommaaccent ugrave -10 +KPX ncommaaccent uhungarumlaut -10 +KPX ncommaaccent umacron -10 +KPX ncommaaccent uogonek -10 +KPX ncommaaccent uring -10 +KPX ncommaaccent v -40 +KPX ncommaaccent y -20 +KPX ncommaaccent yacute -20 +KPX ncommaaccent ydieresis -20 +KPX ntilde u -10 +KPX ntilde uacute -10 +KPX ntilde ucircumflex -10 +KPX ntilde udieresis -10 +KPX ntilde ugrave -10 +KPX ntilde uhungarumlaut -10 +KPX ntilde umacron -10 +KPX ntilde uogonek -10 +KPX ntilde uring -10 +KPX ntilde v -40 +KPX ntilde y -20 +KPX ntilde yacute -20 +KPX ntilde ydieresis -20 +KPX o v -20 +KPX o w -15 +KPX o x -30 +KPX o y -20 +KPX o yacute -20 +KPX o ydieresis -20 +KPX oacute v -20 +KPX oacute w -15 +KPX oacute x -30 +KPX oacute y -20 +KPX oacute yacute -20 +KPX oacute ydieresis -20 +KPX ocircumflex v -20 +KPX ocircumflex w -15 +KPX ocircumflex x -30 +KPX ocircumflex y -20 +KPX ocircumflex yacute -20 +KPX ocircumflex ydieresis -20 +KPX odieresis v -20 +KPX odieresis w -15 +KPX odieresis x -30 +KPX odieresis y -20 +KPX odieresis yacute -20 +KPX odieresis ydieresis -20 +KPX ograve v -20 +KPX ograve w -15 +KPX ograve x -30 +KPX ograve y -20 +KPX ograve yacute -20 +KPX ograve ydieresis -20 +KPX ohungarumlaut v -20 +KPX ohungarumlaut w -15 +KPX ohungarumlaut x -30 +KPX ohungarumlaut y -20 +KPX ohungarumlaut yacute -20 +KPX ohungarumlaut ydieresis -20 +KPX omacron v -20 +KPX omacron w -15 +KPX omacron x -30 +KPX omacron y -20 +KPX omacron yacute -20 +KPX omacron ydieresis -20 +KPX oslash v -20 +KPX oslash w -15 +KPX oslash x -30 +KPX oslash y -20 +KPX oslash yacute -20 +KPX oslash ydieresis -20 +KPX otilde v -20 +KPX otilde w -15 +KPX otilde x -30 +KPX otilde y -20 +KPX otilde yacute -20 +KPX otilde ydieresis -20 +KPX p y -15 +KPX p yacute -15 +KPX p ydieresis -15 +KPX period quotedblright -120 +KPX period quoteright -120 +KPX period space -40 +KPX quotedblright space -80 +KPX quoteleft quoteleft -46 +KPX quoteright d -80 +KPX quoteright dcroat -80 +KPX quoteright l -20 +KPX quoteright lacute -20 +KPX quoteright lcommaaccent -20 +KPX quoteright lslash -20 +KPX quoteright quoteright -46 +KPX quoteright r -40 +KPX quoteright racute -40 +KPX quoteright rcaron -40 +KPX quoteright rcommaaccent -40 +KPX quoteright s -60 +KPX quoteright sacute -60 +KPX quoteright scaron -60 +KPX quoteright scedilla -60 +KPX quoteright scommaaccent -60 +KPX quoteright space -80 +KPX quoteright v -20 +KPX r c -20 +KPX r cacute -20 +KPX r ccaron -20 +KPX r ccedilla -20 +KPX r comma -60 +KPX r d -20 +KPX r dcroat -20 +KPX r g -15 +KPX r gbreve -15 +KPX r gcommaaccent -15 +KPX r hyphen -20 +KPX r o -20 +KPX r oacute -20 +KPX r ocircumflex -20 +KPX r odieresis -20 +KPX r ograve -20 +KPX r ohungarumlaut -20 +KPX r omacron -20 +KPX r oslash -20 +KPX r otilde -20 +KPX r period -60 +KPX r q -20 +KPX r s -15 +KPX r sacute -15 +KPX r scaron -15 +KPX r scedilla -15 +KPX r scommaaccent -15 +KPX r t 20 +KPX r tcommaaccent 20 +KPX r v 10 +KPX r y 10 +KPX r yacute 10 +KPX r ydieresis 10 +KPX racute c -20 +KPX racute cacute -20 +KPX racute ccaron -20 +KPX racute ccedilla -20 +KPX racute comma -60 +KPX racute d -20 +KPX racute dcroat -20 +KPX racute g -15 +KPX racute gbreve -15 +KPX racute gcommaaccent -15 +KPX racute hyphen -20 +KPX racute o -20 +KPX racute oacute -20 +KPX racute ocircumflex -20 +KPX racute odieresis -20 +KPX racute ograve -20 +KPX racute ohungarumlaut -20 +KPX racute omacron -20 +KPX racute oslash -20 +KPX racute otilde -20 +KPX racute period -60 +KPX racute q -20 +KPX racute s -15 +KPX racute sacute -15 +KPX racute scaron -15 +KPX racute scedilla -15 +KPX racute scommaaccent -15 +KPX racute t 20 +KPX racute tcommaaccent 20 +KPX racute v 10 +KPX racute y 10 +KPX racute yacute 10 +KPX racute ydieresis 10 +KPX rcaron c -20 +KPX rcaron cacute -20 +KPX rcaron ccaron -20 +KPX rcaron ccedilla -20 +KPX rcaron comma -60 +KPX rcaron d -20 +KPX rcaron dcroat -20 +KPX rcaron g -15 +KPX rcaron gbreve -15 +KPX rcaron gcommaaccent -15 +KPX rcaron hyphen -20 +KPX rcaron o -20 +KPX rcaron oacute -20 +KPX rcaron ocircumflex -20 +KPX rcaron odieresis -20 +KPX rcaron ograve -20 +KPX rcaron ohungarumlaut -20 +KPX rcaron omacron -20 +KPX rcaron oslash -20 +KPX rcaron otilde -20 +KPX rcaron period -60 +KPX rcaron q -20 +KPX rcaron s -15 +KPX rcaron sacute -15 +KPX rcaron scaron -15 +KPX rcaron scedilla -15 +KPX rcaron scommaaccent -15 +KPX rcaron t 20 +KPX rcaron tcommaaccent 20 +KPX rcaron v 10 +KPX rcaron y 10 +KPX rcaron yacute 10 +KPX rcaron ydieresis 10 +KPX rcommaaccent c -20 +KPX rcommaaccent cacute -20 +KPX rcommaaccent ccaron -20 +KPX rcommaaccent ccedilla -20 +KPX rcommaaccent comma -60 +KPX rcommaaccent d -20 +KPX rcommaaccent dcroat -20 +KPX rcommaaccent g -15 +KPX rcommaaccent gbreve -15 +KPX rcommaaccent gcommaaccent -15 +KPX rcommaaccent hyphen -20 +KPX rcommaaccent o -20 +KPX rcommaaccent oacute -20 +KPX rcommaaccent ocircumflex -20 +KPX rcommaaccent odieresis -20 +KPX rcommaaccent ograve -20 +KPX rcommaaccent ohungarumlaut -20 +KPX rcommaaccent omacron -20 +KPX rcommaaccent oslash -20 +KPX rcommaaccent otilde -20 +KPX rcommaaccent period -60 +KPX rcommaaccent q -20 +KPX rcommaaccent s -15 +KPX rcommaaccent sacute -15 +KPX rcommaaccent scaron -15 +KPX rcommaaccent scedilla -15 +KPX rcommaaccent scommaaccent -15 +KPX rcommaaccent t 20 +KPX rcommaaccent tcommaaccent 20 +KPX rcommaaccent v 10 +KPX rcommaaccent y 10 +KPX rcommaaccent yacute 10 +KPX rcommaaccent ydieresis 10 +KPX s w -15 +KPX sacute w -15 +KPX scaron w -15 +KPX scedilla w -15 +KPX scommaaccent w -15 +KPX semicolon space -40 +KPX space T -100 +KPX space Tcaron -100 +KPX space Tcommaaccent -100 +KPX space V -80 +KPX space W -80 +KPX space Y -120 +KPX space Yacute -120 +KPX space Ydieresis -120 +KPX space quotedblleft -80 +KPX space quoteleft -60 +KPX v a -20 +KPX v aacute -20 +KPX v abreve -20 +KPX v acircumflex -20 +KPX v adieresis -20 +KPX v agrave -20 +KPX v amacron -20 +KPX v aogonek -20 +KPX v aring -20 +KPX v atilde -20 +KPX v comma -80 +KPX v o -30 +KPX v oacute -30 +KPX v ocircumflex -30 +KPX v odieresis -30 +KPX v ograve -30 +KPX v ohungarumlaut -30 +KPX v omacron -30 +KPX v oslash -30 +KPX v otilde -30 +KPX v period -80 +KPX w comma -40 +KPX w o -20 +KPX w oacute -20 +KPX w ocircumflex -20 +KPX w odieresis -20 +KPX w ograve -20 +KPX w ohungarumlaut -20 +KPX w omacron -20 +KPX w oslash -20 +KPX w otilde -20 +KPX w period -40 +KPX x e -10 +KPX x eacute -10 +KPX x ecaron -10 +KPX x ecircumflex -10 +KPX x edieresis -10 +KPX x edotaccent -10 +KPX x egrave -10 +KPX x emacron -10 +KPX x eogonek -10 +KPX y a -30 +KPX y aacute -30 +KPX y abreve -30 +KPX y acircumflex -30 +KPX y adieresis -30 +KPX y agrave -30 +KPX y amacron -30 +KPX y aogonek -30 +KPX y aring -30 +KPX y atilde -30 +KPX y comma -80 +KPX y e -10 +KPX y eacute -10 +KPX y ecaron -10 +KPX y ecircumflex -10 +KPX y edieresis -10 +KPX y edotaccent -10 +KPX y egrave -10 +KPX y emacron -10 +KPX y eogonek -10 +KPX y o -25 +KPX y oacute -25 +KPX y ocircumflex -25 +KPX y odieresis -25 +KPX y ograve -25 +KPX y ohungarumlaut -25 +KPX y omacron -25 +KPX y oslash -25 +KPX y otilde -25 +KPX y period -80 +KPX yacute a -30 +KPX yacute aacute -30 +KPX yacute abreve -30 +KPX yacute acircumflex -30 +KPX yacute adieresis -30 +KPX yacute agrave -30 +KPX yacute amacron -30 +KPX yacute aogonek -30 +KPX yacute aring -30 +KPX yacute atilde -30 +KPX yacute comma -80 +KPX yacute e -10 +KPX yacute eacute -10 +KPX yacute ecaron -10 +KPX yacute ecircumflex -10 +KPX yacute edieresis -10 +KPX yacute edotaccent -10 +KPX yacute egrave -10 +KPX yacute emacron -10 +KPX yacute eogonek -10 +KPX yacute o -25 +KPX yacute oacute -25 +KPX yacute ocircumflex -25 +KPX yacute odieresis -25 +KPX yacute ograve -25 +KPX yacute ohungarumlaut -25 +KPX yacute omacron -25 +KPX yacute oslash -25 +KPX yacute otilde -25 +KPX yacute period -80 +KPX ydieresis a -30 +KPX ydieresis aacute -30 +KPX ydieresis abreve -30 +KPX ydieresis acircumflex -30 +KPX ydieresis adieresis -30 +KPX ydieresis agrave -30 +KPX ydieresis amacron -30 +KPX ydieresis aogonek -30 +KPX ydieresis aring -30 +KPX ydieresis atilde -30 +KPX ydieresis comma -80 +KPX ydieresis e -10 +KPX ydieresis eacute -10 +KPX ydieresis ecaron -10 +KPX ydieresis ecircumflex -10 +KPX ydieresis edieresis -10 +KPX ydieresis edotaccent -10 +KPX ydieresis egrave -10 +KPX ydieresis emacron -10 +KPX ydieresis eogonek -10 +KPX ydieresis o -25 +KPX ydieresis oacute -25 +KPX ydieresis ocircumflex -25 +KPX ydieresis odieresis -25 +KPX ydieresis ograve -25 +KPX ydieresis ohungarumlaut -25 +KPX ydieresis omacron -25 +KPX ydieresis oslash -25 +KPX ydieresis otilde -25 +KPX ydieresis period -80 +KPX z e 10 +KPX z eacute 10 +KPX z ecaron 10 +KPX z ecircumflex 10 +KPX z edieresis 10 +KPX z edotaccent 10 +KPX z egrave 10 +KPX z emacron 10 +KPX z eogonek 10 +KPX zacute e 10 +KPX zacute eacute 10 +KPX zacute ecaron 10 +KPX zacute ecircumflex 10 +KPX zacute edieresis 10 +KPX zacute edotaccent 10 +KPX zacute egrave 10 +KPX zacute emacron 10 +KPX zacute eogonek 10 +KPX zcaron e 10 +KPX zcaron eacute 10 +KPX zcaron ecaron 10 +KPX zcaron ecircumflex 10 +KPX zcaron edieresis 10 +KPX zcaron edotaccent 10 +KPX zcaron egrave 10 +KPX zcaron emacron 10 +KPX zcaron eogonek 10 +KPX zdotaccent e 10 +KPX zdotaccent eacute 10 +KPX zdotaccent ecaron 10 +KPX zdotaccent ecircumflex 10 +KPX zdotaccent edieresis 10 +KPX zdotaccent edotaccent 10 +KPX zdotaccent egrave 10 +KPX zdotaccent emacron 10 +KPX zdotaccent eogonek 10 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Oblique.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Oblique.afm new file mode 100644 index 0000000..a1494fb --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Oblique.afm @@ -0,0 +1,3051 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:44:31 1997 +Comment UniqueID 43055 +Comment VMusage 14960 69346 +FontName Helvetica-Oblique +FullName Helvetica Oblique +FamilyName Helvetica +Weight Medium +ItalicAngle -12 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -170 -225 1116 931 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 718 +XHeight 523 +Ascender 718 +Descender -207 +StdHW 76 +StdVW 88 +StartCharMetrics 315 +C 32 ; WX 278 ; N space ; B 0 0 0 0 ; +C 33 ; WX 278 ; N exclam ; B 90 0 340 718 ; +C 34 ; WX 355 ; N quotedbl ; B 168 463 438 718 ; +C 35 ; WX 556 ; N numbersign ; B 73 0 631 688 ; +C 36 ; WX 556 ; N dollar ; B 69 -115 617 775 ; +C 37 ; WX 889 ; N percent ; B 147 -19 889 703 ; +C 38 ; WX 667 ; N ampersand ; B 77 -15 647 718 ; +C 39 ; WX 222 ; N quoteright ; B 151 463 310 718 ; +C 40 ; WX 333 ; N parenleft ; B 108 -207 454 733 ; +C 41 ; WX 333 ; N parenright ; B -9 -207 337 733 ; +C 42 ; WX 389 ; N asterisk ; B 165 431 475 718 ; +C 43 ; WX 584 ; N plus ; B 85 0 606 505 ; +C 44 ; WX 278 ; N comma ; B 56 -147 214 106 ; +C 45 ; WX 333 ; N hyphen ; B 93 232 357 322 ; +C 46 ; WX 278 ; N period ; B 87 0 214 106 ; +C 47 ; WX 278 ; N slash ; B -21 -19 452 737 ; +C 48 ; WX 556 ; N zero ; B 93 -19 608 703 ; +C 49 ; WX 556 ; N one ; B 207 0 508 703 ; +C 50 ; WX 556 ; N two ; B 26 0 617 703 ; +C 51 ; WX 556 ; N three ; B 75 -19 610 703 ; +C 52 ; WX 556 ; N four ; B 61 0 576 703 ; +C 53 ; WX 556 ; N five ; B 68 -19 621 688 ; +C 54 ; WX 556 ; N six ; B 91 -19 615 703 ; +C 55 ; WX 556 ; N seven ; B 137 0 669 688 ; +C 56 ; WX 556 ; N eight ; B 74 -19 607 703 ; +C 57 ; WX 556 ; N nine ; B 82 -19 609 703 ; +C 58 ; WX 278 ; N colon ; B 87 0 301 516 ; +C 59 ; WX 278 ; N semicolon ; B 56 -147 301 516 ; +C 60 ; WX 584 ; N less ; B 94 11 641 495 ; +C 61 ; WX 584 ; N equal ; B 63 115 628 390 ; +C 62 ; WX 584 ; N greater ; B 50 11 597 495 ; +C 63 ; WX 556 ; N question ; B 161 0 610 727 ; +C 64 ; WX 1015 ; N at ; B 215 -19 965 737 ; +C 65 ; WX 667 ; N A ; B 14 0 654 718 ; +C 66 ; WX 667 ; N B ; B 74 0 712 718 ; +C 67 ; WX 722 ; N C ; B 108 -19 782 737 ; +C 68 ; WX 722 ; N D ; B 81 0 764 718 ; +C 69 ; WX 667 ; N E ; B 86 0 762 718 ; +C 70 ; WX 611 ; N F ; B 86 0 736 718 ; +C 71 ; WX 778 ; N G ; B 111 -19 799 737 ; +C 72 ; WX 722 ; N H ; B 77 0 799 718 ; +C 73 ; WX 278 ; N I ; B 91 0 341 718 ; +C 74 ; WX 500 ; N J ; B 47 -19 581 718 ; +C 75 ; WX 667 ; N K ; B 76 0 808 718 ; +C 76 ; WX 556 ; N L ; B 76 0 555 718 ; +C 77 ; WX 833 ; N M ; B 73 0 914 718 ; +C 78 ; WX 722 ; N N ; B 76 0 799 718 ; +C 79 ; WX 778 ; N O ; B 105 -19 826 737 ; +C 80 ; WX 667 ; N P ; B 86 0 737 718 ; +C 81 ; WX 778 ; N Q ; B 105 -56 826 737 ; +C 82 ; WX 722 ; N R ; B 88 0 773 718 ; +C 83 ; WX 667 ; N S ; B 90 -19 713 737 ; +C 84 ; WX 611 ; N T ; B 148 0 750 718 ; +C 85 ; WX 722 ; N U ; B 123 -19 797 718 ; +C 86 ; WX 667 ; N V ; B 173 0 800 718 ; +C 87 ; WX 944 ; N W ; B 169 0 1081 718 ; +C 88 ; WX 667 ; N X ; B 19 0 790 718 ; +C 89 ; WX 667 ; N Y ; B 167 0 806 718 ; +C 90 ; WX 611 ; N Z ; B 23 0 741 718 ; +C 91 ; WX 278 ; N bracketleft ; B 21 -196 403 722 ; +C 92 ; WX 278 ; N backslash ; B 140 -19 291 737 ; +C 93 ; WX 278 ; N bracketright ; B -14 -196 368 722 ; +C 94 ; WX 469 ; N asciicircum ; B 42 264 539 688 ; +C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ; +C 96 ; WX 222 ; N quoteleft ; B 165 470 323 725 ; +C 97 ; WX 556 ; N a ; B 61 -15 559 538 ; +C 98 ; WX 556 ; N b ; B 58 -15 584 718 ; +C 99 ; WX 500 ; N c ; B 74 -15 553 538 ; +C 100 ; WX 556 ; N d ; B 84 -15 652 718 ; +C 101 ; WX 556 ; N e ; B 84 -15 578 538 ; +C 102 ; WX 278 ; N f ; B 86 0 416 728 ; L i fi ; L l fl ; +C 103 ; WX 556 ; N g ; B 42 -220 610 538 ; +C 104 ; WX 556 ; N h ; B 65 0 573 718 ; +C 105 ; WX 222 ; N i ; B 67 0 308 718 ; +C 106 ; WX 222 ; N j ; B -60 -210 308 718 ; +C 107 ; WX 500 ; N k ; B 67 0 600 718 ; +C 108 ; WX 222 ; N l ; B 67 0 308 718 ; +C 109 ; WX 833 ; N m ; B 65 0 852 538 ; +C 110 ; WX 556 ; N n ; B 65 0 573 538 ; +C 111 ; WX 556 ; N o ; B 83 -14 585 538 ; +C 112 ; WX 556 ; N p ; B 14 -207 584 538 ; +C 113 ; WX 556 ; N q ; B 84 -207 605 538 ; +C 114 ; WX 333 ; N r ; B 77 0 446 538 ; +C 115 ; WX 500 ; N s ; B 63 -15 529 538 ; +C 116 ; WX 278 ; N t ; B 102 -7 368 669 ; +C 117 ; WX 556 ; N u ; B 94 -15 600 523 ; +C 118 ; WX 500 ; N v ; B 119 0 603 523 ; +C 119 ; WX 722 ; N w ; B 125 0 820 523 ; +C 120 ; WX 500 ; N x ; B 11 0 594 523 ; +C 121 ; WX 500 ; N y ; B 15 -214 600 523 ; +C 122 ; WX 500 ; N z ; B 31 0 571 523 ; +C 123 ; WX 334 ; N braceleft ; B 92 -196 445 722 ; +C 124 ; WX 260 ; N bar ; B 46 -225 332 775 ; +C 125 ; WX 334 ; N braceright ; B 0 -196 354 722 ; +C 126 ; WX 584 ; N asciitilde ; B 111 180 580 326 ; +C 161 ; WX 333 ; N exclamdown ; B 77 -195 326 523 ; +C 162 ; WX 556 ; N cent ; B 95 -115 584 623 ; +C 163 ; WX 556 ; N sterling ; B 49 -16 634 718 ; +C 164 ; WX 167 ; N fraction ; B -170 -19 482 703 ; +C 165 ; WX 556 ; N yen ; B 81 0 699 688 ; +C 166 ; WX 556 ; N florin ; B -52 -207 654 737 ; +C 167 ; WX 556 ; N section ; B 76 -191 584 737 ; +C 168 ; WX 556 ; N currency ; B 60 99 646 603 ; +C 169 ; WX 191 ; N quotesingle ; B 157 463 285 718 ; +C 170 ; WX 333 ; N quotedblleft ; B 138 470 461 725 ; +C 171 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ; +C 172 ; WX 333 ; N guilsinglleft ; B 137 108 340 446 ; +C 173 ; WX 333 ; N guilsinglright ; B 111 108 314 446 ; +C 174 ; WX 500 ; N fi ; B 86 0 587 728 ; +C 175 ; WX 500 ; N fl ; B 86 0 585 728 ; +C 177 ; WX 556 ; N endash ; B 51 240 623 313 ; +C 178 ; WX 556 ; N dagger ; B 135 -159 622 718 ; +C 179 ; WX 556 ; N daggerdbl ; B 52 -159 623 718 ; +C 180 ; WX 278 ; N periodcentered ; B 129 190 257 315 ; +C 182 ; WX 537 ; N paragraph ; B 126 -173 650 718 ; +C 183 ; WX 350 ; N bullet ; B 91 202 413 517 ; +C 184 ; WX 222 ; N quotesinglbase ; B 21 -149 180 106 ; +C 185 ; WX 333 ; N quotedblbase ; B -6 -149 318 106 ; +C 186 ; WX 333 ; N quotedblright ; B 124 463 448 718 ; +C 187 ; WX 556 ; N guillemotright ; B 120 108 528 446 ; +C 188 ; WX 1000 ; N ellipsis ; B 115 0 908 106 ; +C 189 ; WX 1000 ; N perthousand ; B 88 -19 1029 703 ; +C 191 ; WX 611 ; N questiondown ; B 85 -201 534 525 ; +C 193 ; WX 333 ; N grave ; B 170 593 337 734 ; +C 194 ; WX 333 ; N acute ; B 248 593 475 734 ; +C 195 ; WX 333 ; N circumflex ; B 147 593 438 734 ; +C 196 ; WX 333 ; N tilde ; B 125 606 490 722 ; +C 197 ; WX 333 ; N macron ; B 143 627 468 684 ; +C 198 ; WX 333 ; N breve ; B 167 595 476 731 ; +C 199 ; WX 333 ; N dotaccent ; B 249 604 362 706 ; +C 200 ; WX 333 ; N dieresis ; B 168 604 443 706 ; +C 202 ; WX 333 ; N ring ; B 214 572 402 756 ; +C 203 ; WX 333 ; N cedilla ; B 2 -225 232 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B 157 593 565 734 ; +C 206 ; WX 333 ; N ogonek ; B 43 -225 249 0 ; +C 207 ; WX 333 ; N caron ; B 177 593 468 734 ; +C 208 ; WX 1000 ; N emdash ; B 51 240 1067 313 ; +C 225 ; WX 1000 ; N AE ; B 8 0 1097 718 ; +C 227 ; WX 370 ; N ordfeminine ; B 127 405 449 737 ; +C 232 ; WX 556 ; N Lslash ; B 41 0 555 718 ; +C 233 ; WX 778 ; N Oslash ; B 43 -19 890 737 ; +C 234 ; WX 1000 ; N OE ; B 98 -19 1116 737 ; +C 235 ; WX 365 ; N ordmasculine ; B 141 405 468 737 ; +C 241 ; WX 889 ; N ae ; B 61 -15 909 538 ; +C 245 ; WX 278 ; N dotlessi ; B 95 0 294 523 ; +C 248 ; WX 222 ; N lslash ; B 41 0 347 718 ; +C 249 ; WX 611 ; N oslash ; B 29 -22 647 545 ; +C 250 ; WX 944 ; N oe ; B 83 -15 964 538 ; +C 251 ; WX 611 ; N germandbls ; B 67 -15 658 728 ; +C -1 ; WX 278 ; N Idieresis ; B 91 0 458 901 ; +C -1 ; WX 556 ; N eacute ; B 84 -15 587 734 ; +C -1 ; WX 556 ; N abreve ; B 61 -15 578 731 ; +C -1 ; WX 556 ; N uhungarumlaut ; B 94 -15 677 734 ; +C -1 ; WX 556 ; N ecaron ; B 84 -15 580 734 ; +C -1 ; WX 667 ; N Ydieresis ; B 167 0 806 901 ; +C -1 ; WX 584 ; N divide ; B 85 -19 606 524 ; +C -1 ; WX 667 ; N Yacute ; B 167 0 806 929 ; +C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ; +C -1 ; WX 556 ; N aacute ; B 61 -15 587 734 ; +C -1 ; WX 722 ; N Ucircumflex ; B 123 -19 797 929 ; +C -1 ; WX 500 ; N yacute ; B 15 -214 600 734 ; +C -1 ; WX 500 ; N scommaaccent ; B 63 -225 529 538 ; +C -1 ; WX 556 ; N ecircumflex ; B 84 -15 578 734 ; +C -1 ; WX 722 ; N Uring ; B 123 -19 797 931 ; +C -1 ; WX 722 ; N Udieresis ; B 123 -19 797 901 ; +C -1 ; WX 556 ; N aogonek ; B 61 -220 559 538 ; +C -1 ; WX 722 ; N Uacute ; B 123 -19 797 929 ; +C -1 ; WX 556 ; N uogonek ; B 94 -225 600 523 ; +C -1 ; WX 667 ; N Edieresis ; B 86 0 762 901 ; +C -1 ; WX 722 ; N Dcroat ; B 69 0 764 718 ; +C -1 ; WX 250 ; N commaaccent ; B 39 -225 172 -40 ; +C -1 ; WX 737 ; N copyright ; B 54 -19 837 737 ; +C -1 ; WX 667 ; N Emacron ; B 86 0 762 879 ; +C -1 ; WX 500 ; N ccaron ; B 74 -15 553 734 ; +C -1 ; WX 556 ; N aring ; B 61 -15 559 756 ; +C -1 ; WX 722 ; N Ncommaaccent ; B 76 -225 799 718 ; +C -1 ; WX 222 ; N lacute ; B 67 0 461 929 ; +C -1 ; WX 556 ; N agrave ; B 61 -15 559 734 ; +C -1 ; WX 611 ; N Tcommaaccent ; B 148 -225 750 718 ; +C -1 ; WX 722 ; N Cacute ; B 108 -19 782 929 ; +C -1 ; WX 556 ; N atilde ; B 61 -15 592 722 ; +C -1 ; WX 667 ; N Edotaccent ; B 86 0 762 901 ; +C -1 ; WX 500 ; N scaron ; B 63 -15 552 734 ; +C -1 ; WX 500 ; N scedilla ; B 63 -225 529 538 ; +C -1 ; WX 278 ; N iacute ; B 95 0 448 734 ; +C -1 ; WX 471 ; N lozenge ; B 88 0 540 728 ; +C -1 ; WX 722 ; N Rcaron ; B 88 0 773 929 ; +C -1 ; WX 778 ; N Gcommaaccent ; B 111 -225 799 737 ; +C -1 ; WX 556 ; N ucircumflex ; B 94 -15 600 734 ; +C -1 ; WX 556 ; N acircumflex ; B 61 -15 559 734 ; +C -1 ; WX 667 ; N Amacron ; B 14 0 677 879 ; +C -1 ; WX 333 ; N rcaron ; B 77 0 508 734 ; +C -1 ; WX 500 ; N ccedilla ; B 74 -225 553 538 ; +C -1 ; WX 611 ; N Zdotaccent ; B 23 0 741 901 ; +C -1 ; WX 667 ; N Thorn ; B 86 0 712 718 ; +C -1 ; WX 778 ; N Omacron ; B 105 -19 826 879 ; +C -1 ; WX 722 ; N Racute ; B 88 0 773 929 ; +C -1 ; WX 667 ; N Sacute ; B 90 -19 713 929 ; +C -1 ; WX 643 ; N dcaron ; B 84 -15 808 718 ; +C -1 ; WX 722 ; N Umacron ; B 123 -19 797 879 ; +C -1 ; WX 556 ; N uring ; B 94 -15 600 756 ; +C -1 ; WX 333 ; N threebaseior ; B 90 270 436 703 ; +C -1 ; WX 778 ; N Ograve ; B 105 -19 826 929 ; +C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ; +C -1 ; WX 667 ; N Abreve ; B 14 0 685 926 ; +C -1 ; WX 584 ; N multiply ; B 50 0 642 506 ; +C -1 ; WX 556 ; N uacute ; B 94 -15 600 734 ; +C -1 ; WX 611 ; N Tcaron ; B 148 0 750 929 ; +C -1 ; WX 476 ; N partialdiff ; B 41 -38 550 714 ; +C -1 ; WX 500 ; N ydieresis ; B 15 -214 600 706 ; +C -1 ; WX 722 ; N Nacute ; B 76 0 799 929 ; +C -1 ; WX 278 ; N icircumflex ; B 95 0 411 734 ; +C -1 ; WX 667 ; N Ecircumflex ; B 86 0 762 929 ; +C -1 ; WX 556 ; N adieresis ; B 61 -15 559 706 ; +C -1 ; WX 556 ; N edieresis ; B 84 -15 578 706 ; +C -1 ; WX 500 ; N cacute ; B 74 -15 559 734 ; +C -1 ; WX 556 ; N nacute ; B 65 0 587 734 ; +C -1 ; WX 556 ; N umacron ; B 94 -15 600 684 ; +C -1 ; WX 722 ; N Ncaron ; B 76 0 799 929 ; +C -1 ; WX 278 ; N Iacute ; B 91 0 489 929 ; +C -1 ; WX 584 ; N plusminus ; B 39 0 618 506 ; +C -1 ; WX 260 ; N brokenbar ; B 62 -150 316 700 ; +C -1 ; WX 737 ; N registered ; B 54 -19 837 737 ; +C -1 ; WX 778 ; N Gbreve ; B 111 -19 799 926 ; +C -1 ; WX 278 ; N Idotaccent ; B 91 0 377 901 ; +C -1 ; WX 600 ; N summation ; B 15 -10 671 706 ; +C -1 ; WX 667 ; N Egrave ; B 86 0 762 929 ; +C -1 ; WX 333 ; N racute ; B 77 0 475 734 ; +C -1 ; WX 556 ; N omacron ; B 83 -14 585 684 ; +C -1 ; WX 611 ; N Zacute ; B 23 0 741 929 ; +C -1 ; WX 611 ; N Zcaron ; B 23 0 741 929 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 620 674 ; +C -1 ; WX 722 ; N Eth ; B 69 0 764 718 ; +C -1 ; WX 722 ; N Ccedilla ; B 108 -225 782 737 ; +C -1 ; WX 222 ; N lcommaaccent ; B 25 -225 308 718 ; +C -1 ; WX 317 ; N tcaron ; B 102 -7 501 808 ; +C -1 ; WX 556 ; N eogonek ; B 84 -225 578 538 ; +C -1 ; WX 722 ; N Uogonek ; B 123 -225 797 718 ; +C -1 ; WX 667 ; N Aacute ; B 14 0 683 929 ; +C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ; +C -1 ; WX 556 ; N egrave ; B 84 -15 578 734 ; +C -1 ; WX 500 ; N zacute ; B 31 0 571 734 ; +C -1 ; WX 222 ; N iogonek ; B -61 -225 308 718 ; +C -1 ; WX 778 ; N Oacute ; B 105 -19 826 929 ; +C -1 ; WX 556 ; N oacute ; B 83 -14 587 734 ; +C -1 ; WX 556 ; N amacron ; B 61 -15 580 684 ; +C -1 ; WX 500 ; N sacute ; B 63 -15 559 734 ; +C -1 ; WX 278 ; N idieresis ; B 95 0 416 706 ; +C -1 ; WX 778 ; N Ocircumflex ; B 105 -19 826 929 ; +C -1 ; WX 722 ; N Ugrave ; B 123 -19 797 929 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 556 ; N thorn ; B 14 -207 584 718 ; +C -1 ; WX 333 ; N twobaseior ; B 64 281 449 703 ; +C -1 ; WX 778 ; N Odieresis ; B 105 -19 826 901 ; +C -1 ; WX 556 ; N mu ; B 24 -207 600 523 ; +C -1 ; WX 278 ; N igrave ; B 95 0 310 734 ; +C -1 ; WX 556 ; N ohungarumlaut ; B 83 -14 677 734 ; +C -1 ; WX 667 ; N Eogonek ; B 86 -220 762 718 ; +C -1 ; WX 556 ; N dcroat ; B 84 -15 689 718 ; +C -1 ; WX 834 ; N threequarters ; B 130 -19 861 703 ; +C -1 ; WX 667 ; N Scedilla ; B 90 -225 713 737 ; +C -1 ; WX 299 ; N lcaron ; B 67 0 464 718 ; +C -1 ; WX 667 ; N Kcommaaccent ; B 76 -225 808 718 ; +C -1 ; WX 556 ; N Lacute ; B 76 0 555 929 ; +C -1 ; WX 1000 ; N trademark ; B 186 306 1056 718 ; +C -1 ; WX 556 ; N edotaccent ; B 84 -15 578 706 ; +C -1 ; WX 278 ; N Igrave ; B 91 0 351 929 ; +C -1 ; WX 278 ; N Imacron ; B 91 0 483 879 ; +C -1 ; WX 556 ; N Lcaron ; B 76 0 570 718 ; +C -1 ; WX 834 ; N onehalf ; B 114 -19 839 703 ; +C -1 ; WX 549 ; N lessequal ; B 26 0 666 674 ; +C -1 ; WX 556 ; N ocircumflex ; B 83 -14 585 734 ; +C -1 ; WX 556 ; N ntilde ; B 65 0 592 722 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 123 -19 801 929 ; +C -1 ; WX 667 ; N Eacute ; B 86 0 762 929 ; +C -1 ; WX 556 ; N emacron ; B 84 -15 580 684 ; +C -1 ; WX 556 ; N gbreve ; B 42 -220 610 731 ; +C -1 ; WX 834 ; N onequarter ; B 150 -19 802 703 ; +C -1 ; WX 667 ; N Scaron ; B 90 -19 713 929 ; +C -1 ; WX 667 ; N Scommaaccent ; B 90 -225 713 737 ; +C -1 ; WX 778 ; N Ohungarumlaut ; B 105 -19 829 929 ; +C -1 ; WX 400 ; N degree ; B 169 411 468 703 ; +C -1 ; WX 556 ; N ograve ; B 83 -14 585 734 ; +C -1 ; WX 722 ; N Ccaron ; B 108 -19 782 929 ; +C -1 ; WX 556 ; N ugrave ; B 94 -15 600 734 ; +C -1 ; WX 453 ; N radical ; B 79 -80 617 762 ; +C -1 ; WX 722 ; N Dcaron ; B 81 0 764 929 ; +C -1 ; WX 333 ; N rcommaaccent ; B 30 -225 446 538 ; +C -1 ; WX 722 ; N Ntilde ; B 76 0 799 917 ; +C -1 ; WX 556 ; N otilde ; B 83 -14 602 722 ; +C -1 ; WX 722 ; N Rcommaaccent ; B 88 -225 773 718 ; +C -1 ; WX 556 ; N Lcommaaccent ; B 76 -225 555 718 ; +C -1 ; WX 667 ; N Atilde ; B 14 0 699 917 ; +C -1 ; WX 667 ; N Aogonek ; B 14 -225 654 718 ; +C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ; +C -1 ; WX 778 ; N Otilde ; B 105 -19 826 917 ; +C -1 ; WX 500 ; N zdotaccent ; B 31 0 571 706 ; +C -1 ; WX 667 ; N Ecaron ; B 86 0 762 929 ; +C -1 ; WX 278 ; N Iogonek ; B -33 -225 341 718 ; +C -1 ; WX 500 ; N kcommaaccent ; B 67 -225 600 718 ; +C -1 ; WX 584 ; N minus ; B 85 216 606 289 ; +C -1 ; WX 278 ; N Icircumflex ; B 91 0 452 929 ; +C -1 ; WX 556 ; N ncaron ; B 65 0 580 734 ; +C -1 ; WX 278 ; N tcommaaccent ; B 63 -225 368 669 ; +C -1 ; WX 584 ; N logicalnot ; B 106 108 628 390 ; +C -1 ; WX 556 ; N odieresis ; B 83 -14 585 706 ; +C -1 ; WX 556 ; N udieresis ; B 94 -15 600 706 ; +C -1 ; WX 549 ; N notequal ; B 34 -35 623 551 ; +C -1 ; WX 556 ; N gcommaaccent ; B 42 -220 610 822 ; +C -1 ; WX 556 ; N eth ; B 81 -15 617 737 ; +C -1 ; WX 500 ; N zcaron ; B 31 0 571 734 ; +C -1 ; WX 556 ; N ncommaaccent ; B 65 -225 573 538 ; +C -1 ; WX 333 ; N onebaseior ; B 166 281 371 703 ; +C -1 ; WX 278 ; N imacron ; B 95 0 417 684 ; +C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2705 +KPX A C -30 +KPX A Cacute -30 +KPX A Ccaron -30 +KPX A Ccedilla -30 +KPX A G -30 +KPX A Gbreve -30 +KPX A Gcommaaccent -30 +KPX A O -30 +KPX A Oacute -30 +KPX A Ocircumflex -30 +KPX A Odieresis -30 +KPX A Ograve -30 +KPX A Ohungarumlaut -30 +KPX A Omacron -30 +KPX A Oslash -30 +KPX A Otilde -30 +KPX A Q -30 +KPX A T -120 +KPX A Tcaron -120 +KPX A Tcommaaccent -120 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -70 +KPX A W -50 +KPX A Y -100 +KPX A Yacute -100 +KPX A Ydieresis -100 +KPX A u -30 +KPX A uacute -30 +KPX A ucircumflex -30 +KPX A udieresis -30 +KPX A ugrave -30 +KPX A uhungarumlaut -30 +KPX A umacron -30 +KPX A uogonek -30 +KPX A uring -30 +KPX A v -40 +KPX A w -40 +KPX A y -40 +KPX A yacute -40 +KPX A ydieresis -40 +KPX Aacute C -30 +KPX Aacute Cacute -30 +KPX Aacute Ccaron -30 +KPX Aacute Ccedilla -30 +KPX Aacute G -30 +KPX Aacute Gbreve -30 +KPX Aacute Gcommaaccent -30 +KPX Aacute O -30 +KPX Aacute Oacute -30 +KPX Aacute Ocircumflex -30 +KPX Aacute Odieresis -30 +KPX Aacute Ograve -30 +KPX Aacute Ohungarumlaut -30 +KPX Aacute Omacron -30 +KPX Aacute Oslash -30 +KPX Aacute Otilde -30 +KPX Aacute Q -30 +KPX Aacute T -120 +KPX Aacute Tcaron -120 +KPX Aacute Tcommaaccent -120 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -70 +KPX Aacute W -50 +KPX Aacute Y -100 +KPX Aacute Yacute -100 +KPX Aacute Ydieresis -100 +KPX Aacute u -30 +KPX Aacute uacute -30 +KPX Aacute ucircumflex -30 +KPX Aacute udieresis -30 +KPX Aacute ugrave -30 +KPX Aacute uhungarumlaut -30 +KPX Aacute umacron -30 +KPX Aacute uogonek -30 +KPX Aacute uring -30 +KPX Aacute v -40 +KPX Aacute w -40 +KPX Aacute y -40 +KPX Aacute yacute -40 +KPX Aacute ydieresis -40 +KPX Abreve C -30 +KPX Abreve Cacute -30 +KPX Abreve Ccaron -30 +KPX Abreve Ccedilla -30 +KPX Abreve G -30 +KPX Abreve Gbreve -30 +KPX Abreve Gcommaaccent -30 +KPX Abreve O -30 +KPX Abreve Oacute -30 +KPX Abreve Ocircumflex -30 +KPX Abreve Odieresis -30 +KPX Abreve Ograve -30 +KPX Abreve Ohungarumlaut -30 +KPX Abreve Omacron -30 +KPX Abreve Oslash -30 +KPX Abreve Otilde -30 +KPX Abreve Q -30 +KPX Abreve T -120 +KPX Abreve Tcaron -120 +KPX Abreve Tcommaaccent -120 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -70 +KPX Abreve W -50 +KPX Abreve Y -100 +KPX Abreve Yacute -100 +KPX Abreve Ydieresis -100 +KPX Abreve u -30 +KPX Abreve uacute -30 +KPX Abreve ucircumflex -30 +KPX Abreve udieresis -30 +KPX Abreve ugrave -30 +KPX Abreve uhungarumlaut -30 +KPX Abreve umacron -30 +KPX Abreve uogonek -30 +KPX Abreve uring -30 +KPX Abreve v -40 +KPX Abreve w -40 +KPX Abreve y -40 +KPX Abreve yacute -40 +KPX Abreve ydieresis -40 +KPX Acircumflex C -30 +KPX Acircumflex Cacute -30 +KPX Acircumflex Ccaron -30 +KPX Acircumflex Ccedilla -30 +KPX Acircumflex G -30 +KPX Acircumflex Gbreve -30 +KPX Acircumflex Gcommaaccent -30 +KPX Acircumflex O -30 +KPX Acircumflex Oacute -30 +KPX Acircumflex Ocircumflex -30 +KPX Acircumflex Odieresis -30 +KPX Acircumflex Ograve -30 +KPX Acircumflex Ohungarumlaut -30 +KPX Acircumflex Omacron -30 +KPX Acircumflex Oslash -30 +KPX Acircumflex Otilde -30 +KPX Acircumflex Q -30 +KPX Acircumflex T -120 +KPX Acircumflex Tcaron -120 +KPX Acircumflex Tcommaaccent -120 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -70 +KPX Acircumflex W -50 +KPX Acircumflex Y -100 +KPX Acircumflex Yacute -100 +KPX Acircumflex Ydieresis -100 +KPX Acircumflex u -30 +KPX Acircumflex uacute -30 +KPX Acircumflex ucircumflex -30 +KPX Acircumflex udieresis -30 +KPX Acircumflex ugrave -30 +KPX Acircumflex uhungarumlaut -30 +KPX Acircumflex umacron -30 +KPX Acircumflex uogonek -30 +KPX Acircumflex uring -30 +KPX Acircumflex v -40 +KPX Acircumflex w -40 +KPX Acircumflex y -40 +KPX Acircumflex yacute -40 +KPX Acircumflex ydieresis -40 +KPX Adieresis C -30 +KPX Adieresis Cacute -30 +KPX Adieresis Ccaron -30 +KPX Adieresis Ccedilla -30 +KPX Adieresis G -30 +KPX Adieresis Gbreve -30 +KPX Adieresis Gcommaaccent -30 +KPX Adieresis O -30 +KPX Adieresis Oacute -30 +KPX Adieresis Ocircumflex -30 +KPX Adieresis Odieresis -30 +KPX Adieresis Ograve -30 +KPX Adieresis Ohungarumlaut -30 +KPX Adieresis Omacron -30 +KPX Adieresis Oslash -30 +KPX Adieresis Otilde -30 +KPX Adieresis Q -30 +KPX Adieresis T -120 +KPX Adieresis Tcaron -120 +KPX Adieresis Tcommaaccent -120 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -70 +KPX Adieresis W -50 +KPX Adieresis Y -100 +KPX Adieresis Yacute -100 +KPX Adieresis Ydieresis -100 +KPX Adieresis u -30 +KPX Adieresis uacute -30 +KPX Adieresis ucircumflex -30 +KPX Adieresis udieresis -30 +KPX Adieresis ugrave -30 +KPX Adieresis uhungarumlaut -30 +KPX Adieresis umacron -30 +KPX Adieresis uogonek -30 +KPX Adieresis uring -30 +KPX Adieresis v -40 +KPX Adieresis w -40 +KPX Adieresis y -40 +KPX Adieresis yacute -40 +KPX Adieresis ydieresis -40 +KPX Agrave C -30 +KPX Agrave Cacute -30 +KPX Agrave Ccaron -30 +KPX Agrave Ccedilla -30 +KPX Agrave G -30 +KPX Agrave Gbreve -30 +KPX Agrave Gcommaaccent -30 +KPX Agrave O -30 +KPX Agrave Oacute -30 +KPX Agrave Ocircumflex -30 +KPX Agrave Odieresis -30 +KPX Agrave Ograve -30 +KPX Agrave Ohungarumlaut -30 +KPX Agrave Omacron -30 +KPX Agrave Oslash -30 +KPX Agrave Otilde -30 +KPX Agrave Q -30 +KPX Agrave T -120 +KPX Agrave Tcaron -120 +KPX Agrave Tcommaaccent -120 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -70 +KPX Agrave W -50 +KPX Agrave Y -100 +KPX Agrave Yacute -100 +KPX Agrave Ydieresis -100 +KPX Agrave u -30 +KPX Agrave uacute -30 +KPX Agrave ucircumflex -30 +KPX Agrave udieresis -30 +KPX Agrave ugrave -30 +KPX Agrave uhungarumlaut -30 +KPX Agrave umacron -30 +KPX Agrave uogonek -30 +KPX Agrave uring -30 +KPX Agrave v -40 +KPX Agrave w -40 +KPX Agrave y -40 +KPX Agrave yacute -40 +KPX Agrave ydieresis -40 +KPX Amacron C -30 +KPX Amacron Cacute -30 +KPX Amacron Ccaron -30 +KPX Amacron Ccedilla -30 +KPX Amacron G -30 +KPX Amacron Gbreve -30 +KPX Amacron Gcommaaccent -30 +KPX Amacron O -30 +KPX Amacron Oacute -30 +KPX Amacron Ocircumflex -30 +KPX Amacron Odieresis -30 +KPX Amacron Ograve -30 +KPX Amacron Ohungarumlaut -30 +KPX Amacron Omacron -30 +KPX Amacron Oslash -30 +KPX Amacron Otilde -30 +KPX Amacron Q -30 +KPX Amacron T -120 +KPX Amacron Tcaron -120 +KPX Amacron Tcommaaccent -120 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -70 +KPX Amacron W -50 +KPX Amacron Y -100 +KPX Amacron Yacute -100 +KPX Amacron Ydieresis -100 +KPX Amacron u -30 +KPX Amacron uacute -30 +KPX Amacron ucircumflex -30 +KPX Amacron udieresis -30 +KPX Amacron ugrave -30 +KPX Amacron uhungarumlaut -30 +KPX Amacron umacron -30 +KPX Amacron uogonek -30 +KPX Amacron uring -30 +KPX Amacron v -40 +KPX Amacron w -40 +KPX Amacron y -40 +KPX Amacron yacute -40 +KPX Amacron ydieresis -40 +KPX Aogonek C -30 +KPX Aogonek Cacute -30 +KPX Aogonek Ccaron -30 +KPX Aogonek Ccedilla -30 +KPX Aogonek G -30 +KPX Aogonek Gbreve -30 +KPX Aogonek Gcommaaccent -30 +KPX Aogonek O -30 +KPX Aogonek Oacute -30 +KPX Aogonek Ocircumflex -30 +KPX Aogonek Odieresis -30 +KPX Aogonek Ograve -30 +KPX Aogonek Ohungarumlaut -30 +KPX Aogonek Omacron -30 +KPX Aogonek Oslash -30 +KPX Aogonek Otilde -30 +KPX Aogonek Q -30 +KPX Aogonek T -120 +KPX Aogonek Tcaron -120 +KPX Aogonek Tcommaaccent -120 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -70 +KPX Aogonek W -50 +KPX Aogonek Y -100 +KPX Aogonek Yacute -100 +KPX Aogonek Ydieresis -100 +KPX Aogonek u -30 +KPX Aogonek uacute -30 +KPX Aogonek ucircumflex -30 +KPX Aogonek udieresis -30 +KPX Aogonek ugrave -30 +KPX Aogonek uhungarumlaut -30 +KPX Aogonek umacron -30 +KPX Aogonek uogonek -30 +KPX Aogonek uring -30 +KPX Aogonek v -40 +KPX Aogonek w -40 +KPX Aogonek y -40 +KPX Aogonek yacute -40 +KPX Aogonek ydieresis -40 +KPX Aring C -30 +KPX Aring Cacute -30 +KPX Aring Ccaron -30 +KPX Aring Ccedilla -30 +KPX Aring G -30 +KPX Aring Gbreve -30 +KPX Aring Gcommaaccent -30 +KPX Aring O -30 +KPX Aring Oacute -30 +KPX Aring Ocircumflex -30 +KPX Aring Odieresis -30 +KPX Aring Ograve -30 +KPX Aring Ohungarumlaut -30 +KPX Aring Omacron -30 +KPX Aring Oslash -30 +KPX Aring Otilde -30 +KPX Aring Q -30 +KPX Aring T -120 +KPX Aring Tcaron -120 +KPX Aring Tcommaaccent -120 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -70 +KPX Aring W -50 +KPX Aring Y -100 +KPX Aring Yacute -100 +KPX Aring Ydieresis -100 +KPX Aring u -30 +KPX Aring uacute -30 +KPX Aring ucircumflex -30 +KPX Aring udieresis -30 +KPX Aring ugrave -30 +KPX Aring uhungarumlaut -30 +KPX Aring umacron -30 +KPX Aring uogonek -30 +KPX Aring uring -30 +KPX Aring v -40 +KPX Aring w -40 +KPX Aring y -40 +KPX Aring yacute -40 +KPX Aring ydieresis -40 +KPX Atilde C -30 +KPX Atilde Cacute -30 +KPX Atilde Ccaron -30 +KPX Atilde Ccedilla -30 +KPX Atilde G -30 +KPX Atilde Gbreve -30 +KPX Atilde Gcommaaccent -30 +KPX Atilde O -30 +KPX Atilde Oacute -30 +KPX Atilde Ocircumflex -30 +KPX Atilde Odieresis -30 +KPX Atilde Ograve -30 +KPX Atilde Ohungarumlaut -30 +KPX Atilde Omacron -30 +KPX Atilde Oslash -30 +KPX Atilde Otilde -30 +KPX Atilde Q -30 +KPX Atilde T -120 +KPX Atilde Tcaron -120 +KPX Atilde Tcommaaccent -120 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -70 +KPX Atilde W -50 +KPX Atilde Y -100 +KPX Atilde Yacute -100 +KPX Atilde Ydieresis -100 +KPX Atilde u -30 +KPX Atilde uacute -30 +KPX Atilde ucircumflex -30 +KPX Atilde udieresis -30 +KPX Atilde ugrave -30 +KPX Atilde uhungarumlaut -30 +KPX Atilde umacron -30 +KPX Atilde uogonek -30 +KPX Atilde uring -30 +KPX Atilde v -40 +KPX Atilde w -40 +KPX Atilde y -40 +KPX Atilde yacute -40 +KPX Atilde ydieresis -40 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX B comma -20 +KPX B period -20 +KPX C comma -30 +KPX C period -30 +KPX Cacute comma -30 +KPX Cacute period -30 +KPX Ccaron comma -30 +KPX Ccaron period -30 +KPX Ccedilla comma -30 +KPX Ccedilla period -30 +KPX D A -40 +KPX D Aacute -40 +KPX D Abreve -40 +KPX D Acircumflex -40 +KPX D Adieresis -40 +KPX D Agrave -40 +KPX D Amacron -40 +KPX D Aogonek -40 +KPX D Aring -40 +KPX D Atilde -40 +KPX D V -70 +KPX D W -40 +KPX D Y -90 +KPX D Yacute -90 +KPX D Ydieresis -90 +KPX D comma -70 +KPX D period -70 +KPX Dcaron A -40 +KPX Dcaron Aacute -40 +KPX Dcaron Abreve -40 +KPX Dcaron Acircumflex -40 +KPX Dcaron Adieresis -40 +KPX Dcaron Agrave -40 +KPX Dcaron Amacron -40 +KPX Dcaron Aogonek -40 +KPX Dcaron Aring -40 +KPX Dcaron Atilde -40 +KPX Dcaron V -70 +KPX Dcaron W -40 +KPX Dcaron Y -90 +KPX Dcaron Yacute -90 +KPX Dcaron Ydieresis -90 +KPX Dcaron comma -70 +KPX Dcaron period -70 +KPX Dcroat A -40 +KPX Dcroat Aacute -40 +KPX Dcroat Abreve -40 +KPX Dcroat Acircumflex -40 +KPX Dcroat Adieresis -40 +KPX Dcroat Agrave -40 +KPX Dcroat Amacron -40 +KPX Dcroat Aogonek -40 +KPX Dcroat Aring -40 +KPX Dcroat Atilde -40 +KPX Dcroat V -70 +KPX Dcroat W -40 +KPX Dcroat Y -90 +KPX Dcroat Yacute -90 +KPX Dcroat Ydieresis -90 +KPX Dcroat comma -70 +KPX Dcroat period -70 +KPX F A -80 +KPX F Aacute -80 +KPX F Abreve -80 +KPX F Acircumflex -80 +KPX F Adieresis -80 +KPX F Agrave -80 +KPX F Amacron -80 +KPX F Aogonek -80 +KPX F Aring -80 +KPX F Atilde -80 +KPX F a -50 +KPX F aacute -50 +KPX F abreve -50 +KPX F acircumflex -50 +KPX F adieresis -50 +KPX F agrave -50 +KPX F amacron -50 +KPX F aogonek -50 +KPX F aring -50 +KPX F atilde -50 +KPX F comma -150 +KPX F e -30 +KPX F eacute -30 +KPX F ecaron -30 +KPX F ecircumflex -30 +KPX F edieresis -30 +KPX F edotaccent -30 +KPX F egrave -30 +KPX F emacron -30 +KPX F eogonek -30 +KPX F o -30 +KPX F oacute -30 +KPX F ocircumflex -30 +KPX F odieresis -30 +KPX F ograve -30 +KPX F ohungarumlaut -30 +KPX F omacron -30 +KPX F oslash -30 +KPX F otilde -30 +KPX F period -150 +KPX F r -45 +KPX F racute -45 +KPX F rcaron -45 +KPX F rcommaaccent -45 +KPX J A -20 +KPX J Aacute -20 +KPX J Abreve -20 +KPX J Acircumflex -20 +KPX J Adieresis -20 +KPX J Agrave -20 +KPX J Amacron -20 +KPX J Aogonek -20 +KPX J Aring -20 +KPX J Atilde -20 +KPX J a -20 +KPX J aacute -20 +KPX J abreve -20 +KPX J acircumflex -20 +KPX J adieresis -20 +KPX J agrave -20 +KPX J amacron -20 +KPX J aogonek -20 +KPX J aring -20 +KPX J atilde -20 +KPX J comma -30 +KPX J period -30 +KPX J u -20 +KPX J uacute -20 +KPX J ucircumflex -20 +KPX J udieresis -20 +KPX J ugrave -20 +KPX J uhungarumlaut -20 +KPX J umacron -20 +KPX J uogonek -20 +KPX J uring -20 +KPX K O -50 +KPX K Oacute -50 +KPX K Ocircumflex -50 +KPX K Odieresis -50 +KPX K Ograve -50 +KPX K Ohungarumlaut -50 +KPX K Omacron -50 +KPX K Oslash -50 +KPX K Otilde -50 +KPX K e -40 +KPX K eacute -40 +KPX K ecaron -40 +KPX K ecircumflex -40 +KPX K edieresis -40 +KPX K edotaccent -40 +KPX K egrave -40 +KPX K emacron -40 +KPX K eogonek -40 +KPX K o -40 +KPX K oacute -40 +KPX K ocircumflex -40 +KPX K odieresis -40 +KPX K ograve -40 +KPX K ohungarumlaut -40 +KPX K omacron -40 +KPX K oslash -40 +KPX K otilde -40 +KPX K u -30 +KPX K uacute -30 +KPX K ucircumflex -30 +KPX K udieresis -30 +KPX K ugrave -30 +KPX K uhungarumlaut -30 +KPX K umacron -30 +KPX K uogonek -30 +KPX K uring -30 +KPX K y -50 +KPX K yacute -50 +KPX K ydieresis -50 +KPX Kcommaaccent O -50 +KPX Kcommaaccent Oacute -50 +KPX Kcommaaccent Ocircumflex -50 +KPX Kcommaaccent Odieresis -50 +KPX Kcommaaccent Ograve -50 +KPX Kcommaaccent Ohungarumlaut -50 +KPX Kcommaaccent Omacron -50 +KPX Kcommaaccent Oslash -50 +KPX Kcommaaccent Otilde -50 +KPX Kcommaaccent e -40 +KPX Kcommaaccent eacute -40 +KPX Kcommaaccent ecaron -40 +KPX Kcommaaccent ecircumflex -40 +KPX Kcommaaccent edieresis -40 +KPX Kcommaaccent edotaccent -40 +KPX Kcommaaccent egrave -40 +KPX Kcommaaccent emacron -40 +KPX Kcommaaccent eogonek -40 +KPX Kcommaaccent o -40 +KPX Kcommaaccent oacute -40 +KPX Kcommaaccent ocircumflex -40 +KPX Kcommaaccent odieresis -40 +KPX Kcommaaccent ograve -40 +KPX Kcommaaccent ohungarumlaut -40 +KPX Kcommaaccent omacron -40 +KPX Kcommaaccent oslash -40 +KPX Kcommaaccent otilde -40 +KPX Kcommaaccent u -30 +KPX Kcommaaccent uacute -30 +KPX Kcommaaccent ucircumflex -30 +KPX Kcommaaccent udieresis -30 +KPX Kcommaaccent ugrave -30 +KPX Kcommaaccent uhungarumlaut -30 +KPX Kcommaaccent umacron -30 +KPX Kcommaaccent uogonek -30 +KPX Kcommaaccent uring -30 +KPX Kcommaaccent y -50 +KPX Kcommaaccent yacute -50 +KPX Kcommaaccent ydieresis -50 +KPX L T -110 +KPX L Tcaron -110 +KPX L Tcommaaccent -110 +KPX L V -110 +KPX L W -70 +KPX L Y -140 +KPX L Yacute -140 +KPX L Ydieresis -140 +KPX L quotedblright -140 +KPX L quoteright -160 +KPX L y -30 +KPX L yacute -30 +KPX L ydieresis -30 +KPX Lacute T -110 +KPX Lacute Tcaron -110 +KPX Lacute Tcommaaccent -110 +KPX Lacute V -110 +KPX Lacute W -70 +KPX Lacute Y -140 +KPX Lacute Yacute -140 +KPX Lacute Ydieresis -140 +KPX Lacute quotedblright -140 +KPX Lacute quoteright -160 +KPX Lacute y -30 +KPX Lacute yacute -30 +KPX Lacute ydieresis -30 +KPX Lcaron T -110 +KPX Lcaron Tcaron -110 +KPX Lcaron Tcommaaccent -110 +KPX Lcaron V -110 +KPX Lcaron W -70 +KPX Lcaron Y -140 +KPX Lcaron Yacute -140 +KPX Lcaron Ydieresis -140 +KPX Lcaron quotedblright -140 +KPX Lcaron quoteright -160 +KPX Lcaron y -30 +KPX Lcaron yacute -30 +KPX Lcaron ydieresis -30 +KPX Lcommaaccent T -110 +KPX Lcommaaccent Tcaron -110 +KPX Lcommaaccent Tcommaaccent -110 +KPX Lcommaaccent V -110 +KPX Lcommaaccent W -70 +KPX Lcommaaccent Y -140 +KPX Lcommaaccent Yacute -140 +KPX Lcommaaccent Ydieresis -140 +KPX Lcommaaccent quotedblright -140 +KPX Lcommaaccent quoteright -160 +KPX Lcommaaccent y -30 +KPX Lcommaaccent yacute -30 +KPX Lcommaaccent ydieresis -30 +KPX Lslash T -110 +KPX Lslash Tcaron -110 +KPX Lslash Tcommaaccent -110 +KPX Lslash V -110 +KPX Lslash W -70 +KPX Lslash Y -140 +KPX Lslash Yacute -140 +KPX Lslash Ydieresis -140 +KPX Lslash quotedblright -140 +KPX Lslash quoteright -160 +KPX Lslash y -30 +KPX Lslash yacute -30 +KPX Lslash ydieresis -30 +KPX O A -20 +KPX O Aacute -20 +KPX O Abreve -20 +KPX O Acircumflex -20 +KPX O Adieresis -20 +KPX O Agrave -20 +KPX O Amacron -20 +KPX O Aogonek -20 +KPX O Aring -20 +KPX O Atilde -20 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -30 +KPX O X -60 +KPX O Y -70 +KPX O Yacute -70 +KPX O Ydieresis -70 +KPX O comma -40 +KPX O period -40 +KPX Oacute A -20 +KPX Oacute Aacute -20 +KPX Oacute Abreve -20 +KPX Oacute Acircumflex -20 +KPX Oacute Adieresis -20 +KPX Oacute Agrave -20 +KPX Oacute Amacron -20 +KPX Oacute Aogonek -20 +KPX Oacute Aring -20 +KPX Oacute Atilde -20 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -30 +KPX Oacute X -60 +KPX Oacute Y -70 +KPX Oacute Yacute -70 +KPX Oacute Ydieresis -70 +KPX Oacute comma -40 +KPX Oacute period -40 +KPX Ocircumflex A -20 +KPX Ocircumflex Aacute -20 +KPX Ocircumflex Abreve -20 +KPX Ocircumflex Acircumflex -20 +KPX Ocircumflex Adieresis -20 +KPX Ocircumflex Agrave -20 +KPX Ocircumflex Amacron -20 +KPX Ocircumflex Aogonek -20 +KPX Ocircumflex Aring -20 +KPX Ocircumflex Atilde -20 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -30 +KPX Ocircumflex X -60 +KPX Ocircumflex Y -70 +KPX Ocircumflex Yacute -70 +KPX Ocircumflex Ydieresis -70 +KPX Ocircumflex comma -40 +KPX Ocircumflex period -40 +KPX Odieresis A -20 +KPX Odieresis Aacute -20 +KPX Odieresis Abreve -20 +KPX Odieresis Acircumflex -20 +KPX Odieresis Adieresis -20 +KPX Odieresis Agrave -20 +KPX Odieresis Amacron -20 +KPX Odieresis Aogonek -20 +KPX Odieresis Aring -20 +KPX Odieresis Atilde -20 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -30 +KPX Odieresis X -60 +KPX Odieresis Y -70 +KPX Odieresis Yacute -70 +KPX Odieresis Ydieresis -70 +KPX Odieresis comma -40 +KPX Odieresis period -40 +KPX Ograve A -20 +KPX Ograve Aacute -20 +KPX Ograve Abreve -20 +KPX Ograve Acircumflex -20 +KPX Ograve Adieresis -20 +KPX Ograve Agrave -20 +KPX Ograve Amacron -20 +KPX Ograve Aogonek -20 +KPX Ograve Aring -20 +KPX Ograve Atilde -20 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -30 +KPX Ograve X -60 +KPX Ograve Y -70 +KPX Ograve Yacute -70 +KPX Ograve Ydieresis -70 +KPX Ograve comma -40 +KPX Ograve period -40 +KPX Ohungarumlaut A -20 +KPX Ohungarumlaut Aacute -20 +KPX Ohungarumlaut Abreve -20 +KPX Ohungarumlaut Acircumflex -20 +KPX Ohungarumlaut Adieresis -20 +KPX Ohungarumlaut Agrave -20 +KPX Ohungarumlaut Amacron -20 +KPX Ohungarumlaut Aogonek -20 +KPX Ohungarumlaut Aring -20 +KPX Ohungarumlaut Atilde -20 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -30 +KPX Ohungarumlaut X -60 +KPX Ohungarumlaut Y -70 +KPX Ohungarumlaut Yacute -70 +KPX Ohungarumlaut Ydieresis -70 +KPX Ohungarumlaut comma -40 +KPX Ohungarumlaut period -40 +KPX Omacron A -20 +KPX Omacron Aacute -20 +KPX Omacron Abreve -20 +KPX Omacron Acircumflex -20 +KPX Omacron Adieresis -20 +KPX Omacron Agrave -20 +KPX Omacron Amacron -20 +KPX Omacron Aogonek -20 +KPX Omacron Aring -20 +KPX Omacron Atilde -20 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -30 +KPX Omacron X -60 +KPX Omacron Y -70 +KPX Omacron Yacute -70 +KPX Omacron Ydieresis -70 +KPX Omacron comma -40 +KPX Omacron period -40 +KPX Oslash A -20 +KPX Oslash Aacute -20 +KPX Oslash Abreve -20 +KPX Oslash Acircumflex -20 +KPX Oslash Adieresis -20 +KPX Oslash Agrave -20 +KPX Oslash Amacron -20 +KPX Oslash Aogonek -20 +KPX Oslash Aring -20 +KPX Oslash Atilde -20 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -30 +KPX Oslash X -60 +KPX Oslash Y -70 +KPX Oslash Yacute -70 +KPX Oslash Ydieresis -70 +KPX Oslash comma -40 +KPX Oslash period -40 +KPX Otilde A -20 +KPX Otilde Aacute -20 +KPX Otilde Abreve -20 +KPX Otilde Acircumflex -20 +KPX Otilde Adieresis -20 +KPX Otilde Agrave -20 +KPX Otilde Amacron -20 +KPX Otilde Aogonek -20 +KPX Otilde Aring -20 +KPX Otilde Atilde -20 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -30 +KPX Otilde X -60 +KPX Otilde Y -70 +KPX Otilde Yacute -70 +KPX Otilde Ydieresis -70 +KPX Otilde comma -40 +KPX Otilde period -40 +KPX P A -120 +KPX P Aacute -120 +KPX P Abreve -120 +KPX P Acircumflex -120 +KPX P Adieresis -120 +KPX P Agrave -120 +KPX P Amacron -120 +KPX P Aogonek -120 +KPX P Aring -120 +KPX P Atilde -120 +KPX P a -40 +KPX P aacute -40 +KPX P abreve -40 +KPX P acircumflex -40 +KPX P adieresis -40 +KPX P agrave -40 +KPX P amacron -40 +KPX P aogonek -40 +KPX P aring -40 +KPX P atilde -40 +KPX P comma -180 +KPX P e -50 +KPX P eacute -50 +KPX P ecaron -50 +KPX P ecircumflex -50 +KPX P edieresis -50 +KPX P edotaccent -50 +KPX P egrave -50 +KPX P emacron -50 +KPX P eogonek -50 +KPX P o -50 +KPX P oacute -50 +KPX P ocircumflex -50 +KPX P odieresis -50 +KPX P ograve -50 +KPX P ohungarumlaut -50 +KPX P omacron -50 +KPX P oslash -50 +KPX P otilde -50 +KPX P period -180 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX R O -20 +KPX R Oacute -20 +KPX R Ocircumflex -20 +KPX R Odieresis -20 +KPX R Ograve -20 +KPX R Ohungarumlaut -20 +KPX R Omacron -20 +KPX R Oslash -20 +KPX R Otilde -20 +KPX R T -30 +KPX R Tcaron -30 +KPX R Tcommaaccent -30 +KPX R U -40 +KPX R Uacute -40 +KPX R Ucircumflex -40 +KPX R Udieresis -40 +KPX R Ugrave -40 +KPX R Uhungarumlaut -40 +KPX R Umacron -40 +KPX R Uogonek -40 +KPX R Uring -40 +KPX R V -50 +KPX R W -30 +KPX R Y -50 +KPX R Yacute -50 +KPX R Ydieresis -50 +KPX Racute O -20 +KPX Racute Oacute -20 +KPX Racute Ocircumflex -20 +KPX Racute Odieresis -20 +KPX Racute Ograve -20 +KPX Racute Ohungarumlaut -20 +KPX Racute Omacron -20 +KPX Racute Oslash -20 +KPX Racute Otilde -20 +KPX Racute T -30 +KPX Racute Tcaron -30 +KPX Racute Tcommaaccent -30 +KPX Racute U -40 +KPX Racute Uacute -40 +KPX Racute Ucircumflex -40 +KPX Racute Udieresis -40 +KPX Racute Ugrave -40 +KPX Racute Uhungarumlaut -40 +KPX Racute Umacron -40 +KPX Racute Uogonek -40 +KPX Racute Uring -40 +KPX Racute V -50 +KPX Racute W -30 +KPX Racute Y -50 +KPX Racute Yacute -50 +KPX Racute Ydieresis -50 +KPX Rcaron O -20 +KPX Rcaron Oacute -20 +KPX Rcaron Ocircumflex -20 +KPX Rcaron Odieresis -20 +KPX Rcaron Ograve -20 +KPX Rcaron Ohungarumlaut -20 +KPX Rcaron Omacron -20 +KPX Rcaron Oslash -20 +KPX Rcaron Otilde -20 +KPX Rcaron T -30 +KPX Rcaron Tcaron -30 +KPX Rcaron Tcommaaccent -30 +KPX Rcaron U -40 +KPX Rcaron Uacute -40 +KPX Rcaron Ucircumflex -40 +KPX Rcaron Udieresis -40 +KPX Rcaron Ugrave -40 +KPX Rcaron Uhungarumlaut -40 +KPX Rcaron Umacron -40 +KPX Rcaron Uogonek -40 +KPX Rcaron Uring -40 +KPX Rcaron V -50 +KPX Rcaron W -30 +KPX Rcaron Y -50 +KPX Rcaron Yacute -50 +KPX Rcaron Ydieresis -50 +KPX Rcommaaccent O -20 +KPX Rcommaaccent Oacute -20 +KPX Rcommaaccent Ocircumflex -20 +KPX Rcommaaccent Odieresis -20 +KPX Rcommaaccent Ograve -20 +KPX Rcommaaccent Ohungarumlaut -20 +KPX Rcommaaccent Omacron -20 +KPX Rcommaaccent Oslash -20 +KPX Rcommaaccent Otilde -20 +KPX Rcommaaccent T -30 +KPX Rcommaaccent Tcaron -30 +KPX Rcommaaccent Tcommaaccent -30 +KPX Rcommaaccent U -40 +KPX Rcommaaccent Uacute -40 +KPX Rcommaaccent Ucircumflex -40 +KPX Rcommaaccent Udieresis -40 +KPX Rcommaaccent Ugrave -40 +KPX Rcommaaccent Uhungarumlaut -40 +KPX Rcommaaccent Umacron -40 +KPX Rcommaaccent Uogonek -40 +KPX Rcommaaccent Uring -40 +KPX Rcommaaccent V -50 +KPX Rcommaaccent W -30 +KPX Rcommaaccent Y -50 +KPX Rcommaaccent Yacute -50 +KPX Rcommaaccent Ydieresis -50 +KPX S comma -20 +KPX S period -20 +KPX Sacute comma -20 +KPX Sacute period -20 +KPX Scaron comma -20 +KPX Scaron period -20 +KPX Scedilla comma -20 +KPX Scedilla period -20 +KPX Scommaaccent comma -20 +KPX Scommaaccent period -20 +KPX T A -120 +KPX T Aacute -120 +KPX T Abreve -120 +KPX T Acircumflex -120 +KPX T Adieresis -120 +KPX T Agrave -120 +KPX T Amacron -120 +KPX T Aogonek -120 +KPX T Aring -120 +KPX T Atilde -120 +KPX T O -40 +KPX T Oacute -40 +KPX T Ocircumflex -40 +KPX T Odieresis -40 +KPX T Ograve -40 +KPX T Ohungarumlaut -40 +KPX T Omacron -40 +KPX T Oslash -40 +KPX T Otilde -40 +KPX T a -120 +KPX T aacute -120 +KPX T abreve -60 +KPX T acircumflex -120 +KPX T adieresis -120 +KPX T agrave -120 +KPX T amacron -60 +KPX T aogonek -120 +KPX T aring -120 +KPX T atilde -60 +KPX T colon -20 +KPX T comma -120 +KPX T e -120 +KPX T eacute -120 +KPX T ecaron -120 +KPX T ecircumflex -120 +KPX T edieresis -120 +KPX T edotaccent -120 +KPX T egrave -60 +KPX T emacron -60 +KPX T eogonek -120 +KPX T hyphen -140 +KPX T o -120 +KPX T oacute -120 +KPX T ocircumflex -120 +KPX T odieresis -120 +KPX T ograve -120 +KPX T ohungarumlaut -120 +KPX T omacron -60 +KPX T oslash -120 +KPX T otilde -60 +KPX T period -120 +KPX T r -120 +KPX T racute -120 +KPX T rcaron -120 +KPX T rcommaaccent -120 +KPX T semicolon -20 +KPX T u -120 +KPX T uacute -120 +KPX T ucircumflex -120 +KPX T udieresis -120 +KPX T ugrave -120 +KPX T uhungarumlaut -120 +KPX T umacron -60 +KPX T uogonek -120 +KPX T uring -120 +KPX T w -120 +KPX T y -120 +KPX T yacute -120 +KPX T ydieresis -60 +KPX Tcaron A -120 +KPX Tcaron Aacute -120 +KPX Tcaron Abreve -120 +KPX Tcaron Acircumflex -120 +KPX Tcaron Adieresis -120 +KPX Tcaron Agrave -120 +KPX Tcaron Amacron -120 +KPX Tcaron Aogonek -120 +KPX Tcaron Aring -120 +KPX Tcaron Atilde -120 +KPX Tcaron O -40 +KPX Tcaron Oacute -40 +KPX Tcaron Ocircumflex -40 +KPX Tcaron Odieresis -40 +KPX Tcaron Ograve -40 +KPX Tcaron Ohungarumlaut -40 +KPX Tcaron Omacron -40 +KPX Tcaron Oslash -40 +KPX Tcaron Otilde -40 +KPX Tcaron a -120 +KPX Tcaron aacute -120 +KPX Tcaron abreve -60 +KPX Tcaron acircumflex -120 +KPX Tcaron adieresis -120 +KPX Tcaron agrave -120 +KPX Tcaron amacron -60 +KPX Tcaron aogonek -120 +KPX Tcaron aring -120 +KPX Tcaron atilde -60 +KPX Tcaron colon -20 +KPX Tcaron comma -120 +KPX Tcaron e -120 +KPX Tcaron eacute -120 +KPX Tcaron ecaron -120 +KPX Tcaron ecircumflex -120 +KPX Tcaron edieresis -120 +KPX Tcaron edotaccent -120 +KPX Tcaron egrave -60 +KPX Tcaron emacron -60 +KPX Tcaron eogonek -120 +KPX Tcaron hyphen -140 +KPX Tcaron o -120 +KPX Tcaron oacute -120 +KPX Tcaron ocircumflex -120 +KPX Tcaron odieresis -120 +KPX Tcaron ograve -120 +KPX Tcaron ohungarumlaut -120 +KPX Tcaron omacron -60 +KPX Tcaron oslash -120 +KPX Tcaron otilde -60 +KPX Tcaron period -120 +KPX Tcaron r -120 +KPX Tcaron racute -120 +KPX Tcaron rcaron -120 +KPX Tcaron rcommaaccent -120 +KPX Tcaron semicolon -20 +KPX Tcaron u -120 +KPX Tcaron uacute -120 +KPX Tcaron ucircumflex -120 +KPX Tcaron udieresis -120 +KPX Tcaron ugrave -120 +KPX Tcaron uhungarumlaut -120 +KPX Tcaron umacron -60 +KPX Tcaron uogonek -120 +KPX Tcaron uring -120 +KPX Tcaron w -120 +KPX Tcaron y -120 +KPX Tcaron yacute -120 +KPX Tcaron ydieresis -60 +KPX Tcommaaccent A -120 +KPX Tcommaaccent Aacute -120 +KPX Tcommaaccent Abreve -120 +KPX Tcommaaccent Acircumflex -120 +KPX Tcommaaccent Adieresis -120 +KPX Tcommaaccent Agrave -120 +KPX Tcommaaccent Amacron -120 +KPX Tcommaaccent Aogonek -120 +KPX Tcommaaccent Aring -120 +KPX Tcommaaccent Atilde -120 +KPX Tcommaaccent O -40 +KPX Tcommaaccent Oacute -40 +KPX Tcommaaccent Ocircumflex -40 +KPX Tcommaaccent Odieresis -40 +KPX Tcommaaccent Ograve -40 +KPX Tcommaaccent Ohungarumlaut -40 +KPX Tcommaaccent Omacron -40 +KPX Tcommaaccent Oslash -40 +KPX Tcommaaccent Otilde -40 +KPX Tcommaaccent a -120 +KPX Tcommaaccent aacute -120 +KPX Tcommaaccent abreve -60 +KPX Tcommaaccent acircumflex -120 +KPX Tcommaaccent adieresis -120 +KPX Tcommaaccent agrave -120 +KPX Tcommaaccent amacron -60 +KPX Tcommaaccent aogonek -120 +KPX Tcommaaccent aring -120 +KPX Tcommaaccent atilde -60 +KPX Tcommaaccent colon -20 +KPX Tcommaaccent comma -120 +KPX Tcommaaccent e -120 +KPX Tcommaaccent eacute -120 +KPX Tcommaaccent ecaron -120 +KPX Tcommaaccent ecircumflex -120 +KPX Tcommaaccent edieresis -120 +KPX Tcommaaccent edotaccent -120 +KPX Tcommaaccent egrave -60 +KPX Tcommaaccent emacron -60 +KPX Tcommaaccent eogonek -120 +KPX Tcommaaccent hyphen -140 +KPX Tcommaaccent o -120 +KPX Tcommaaccent oacute -120 +KPX Tcommaaccent ocircumflex -120 +KPX Tcommaaccent odieresis -120 +KPX Tcommaaccent ograve -120 +KPX Tcommaaccent ohungarumlaut -120 +KPX Tcommaaccent omacron -60 +KPX Tcommaaccent oslash -120 +KPX Tcommaaccent otilde -60 +KPX Tcommaaccent period -120 +KPX Tcommaaccent r -120 +KPX Tcommaaccent racute -120 +KPX Tcommaaccent rcaron -120 +KPX Tcommaaccent rcommaaccent -120 +KPX Tcommaaccent semicolon -20 +KPX Tcommaaccent u -120 +KPX Tcommaaccent uacute -120 +KPX Tcommaaccent ucircumflex -120 +KPX Tcommaaccent udieresis -120 +KPX Tcommaaccent ugrave -120 +KPX Tcommaaccent uhungarumlaut -120 +KPX Tcommaaccent umacron -60 +KPX Tcommaaccent uogonek -120 +KPX Tcommaaccent uring -120 +KPX Tcommaaccent w -120 +KPX Tcommaaccent y -120 +KPX Tcommaaccent yacute -120 +KPX Tcommaaccent ydieresis -60 +KPX U A -40 +KPX U Aacute -40 +KPX U Abreve -40 +KPX U Acircumflex -40 +KPX U Adieresis -40 +KPX U Agrave -40 +KPX U Amacron -40 +KPX U Aogonek -40 +KPX U Aring -40 +KPX U Atilde -40 +KPX U comma -40 +KPX U period -40 +KPX Uacute A -40 +KPX Uacute Aacute -40 +KPX Uacute Abreve -40 +KPX Uacute Acircumflex -40 +KPX Uacute Adieresis -40 +KPX Uacute Agrave -40 +KPX Uacute Amacron -40 +KPX Uacute Aogonek -40 +KPX Uacute Aring -40 +KPX Uacute Atilde -40 +KPX Uacute comma -40 +KPX Uacute period -40 +KPX Ucircumflex A -40 +KPX Ucircumflex Aacute -40 +KPX Ucircumflex Abreve -40 +KPX Ucircumflex Acircumflex -40 +KPX Ucircumflex Adieresis -40 +KPX Ucircumflex Agrave -40 +KPX Ucircumflex Amacron -40 +KPX Ucircumflex Aogonek -40 +KPX Ucircumflex Aring -40 +KPX Ucircumflex Atilde -40 +KPX Ucircumflex comma -40 +KPX Ucircumflex period -40 +KPX Udieresis A -40 +KPX Udieresis Aacute -40 +KPX Udieresis Abreve -40 +KPX Udieresis Acircumflex -40 +KPX Udieresis Adieresis -40 +KPX Udieresis Agrave -40 +KPX Udieresis Amacron -40 +KPX Udieresis Aogonek -40 +KPX Udieresis Aring -40 +KPX Udieresis Atilde -40 +KPX Udieresis comma -40 +KPX Udieresis period -40 +KPX Ugrave A -40 +KPX Ugrave Aacute -40 +KPX Ugrave Abreve -40 +KPX Ugrave Acircumflex -40 +KPX Ugrave Adieresis -40 +KPX Ugrave Agrave -40 +KPX Ugrave Amacron -40 +KPX Ugrave Aogonek -40 +KPX Ugrave Aring -40 +KPX Ugrave Atilde -40 +KPX Ugrave comma -40 +KPX Ugrave period -40 +KPX Uhungarumlaut A -40 +KPX Uhungarumlaut Aacute -40 +KPX Uhungarumlaut Abreve -40 +KPX Uhungarumlaut Acircumflex -40 +KPX Uhungarumlaut Adieresis -40 +KPX Uhungarumlaut Agrave -40 +KPX Uhungarumlaut Amacron -40 +KPX Uhungarumlaut Aogonek -40 +KPX Uhungarumlaut Aring -40 +KPX Uhungarumlaut Atilde -40 +KPX Uhungarumlaut comma -40 +KPX Uhungarumlaut period -40 +KPX Umacron A -40 +KPX Umacron Aacute -40 +KPX Umacron Abreve -40 +KPX Umacron Acircumflex -40 +KPX Umacron Adieresis -40 +KPX Umacron Agrave -40 +KPX Umacron Amacron -40 +KPX Umacron Aogonek -40 +KPX Umacron Aring -40 +KPX Umacron Atilde -40 +KPX Umacron comma -40 +KPX Umacron period -40 +KPX Uogonek A -40 +KPX Uogonek Aacute -40 +KPX Uogonek Abreve -40 +KPX Uogonek Acircumflex -40 +KPX Uogonek Adieresis -40 +KPX Uogonek Agrave -40 +KPX Uogonek Amacron -40 +KPX Uogonek Aogonek -40 +KPX Uogonek Aring -40 +KPX Uogonek Atilde -40 +KPX Uogonek comma -40 +KPX Uogonek period -40 +KPX Uring A -40 +KPX Uring Aacute -40 +KPX Uring Abreve -40 +KPX Uring Acircumflex -40 +KPX Uring Adieresis -40 +KPX Uring Agrave -40 +KPX Uring Amacron -40 +KPX Uring Aogonek -40 +KPX Uring Aring -40 +KPX Uring Atilde -40 +KPX Uring comma -40 +KPX Uring period -40 +KPX V A -80 +KPX V Aacute -80 +KPX V Abreve -80 +KPX V Acircumflex -80 +KPX V Adieresis -80 +KPX V Agrave -80 +KPX V Amacron -80 +KPX V Aogonek -80 +KPX V Aring -80 +KPX V Atilde -80 +KPX V G -40 +KPX V Gbreve -40 +KPX V Gcommaaccent -40 +KPX V O -40 +KPX V Oacute -40 +KPX V Ocircumflex -40 +KPX V Odieresis -40 +KPX V Ograve -40 +KPX V Ohungarumlaut -40 +KPX V Omacron -40 +KPX V Oslash -40 +KPX V Otilde -40 +KPX V a -70 +KPX V aacute -70 +KPX V abreve -70 +KPX V acircumflex -70 +KPX V adieresis -70 +KPX V agrave -70 +KPX V amacron -70 +KPX V aogonek -70 +KPX V aring -70 +KPX V atilde -70 +KPX V colon -40 +KPX V comma -125 +KPX V e -80 +KPX V eacute -80 +KPX V ecaron -80 +KPX V ecircumflex -80 +KPX V edieresis -80 +KPX V edotaccent -80 +KPX V egrave -80 +KPX V emacron -80 +KPX V eogonek -80 +KPX V hyphen -80 +KPX V o -80 +KPX V oacute -80 +KPX V ocircumflex -80 +KPX V odieresis -80 +KPX V ograve -80 +KPX V ohungarumlaut -80 +KPX V omacron -80 +KPX V oslash -80 +KPX V otilde -80 +KPX V period -125 +KPX V semicolon -40 +KPX V u -70 +KPX V uacute -70 +KPX V ucircumflex -70 +KPX V udieresis -70 +KPX V ugrave -70 +KPX V uhungarumlaut -70 +KPX V umacron -70 +KPX V uogonek -70 +KPX V uring -70 +KPX W A -50 +KPX W Aacute -50 +KPX W Abreve -50 +KPX W Acircumflex -50 +KPX W Adieresis -50 +KPX W Agrave -50 +KPX W Amacron -50 +KPX W Aogonek -50 +KPX W Aring -50 +KPX W Atilde -50 +KPX W O -20 +KPX W Oacute -20 +KPX W Ocircumflex -20 +KPX W Odieresis -20 +KPX W Ograve -20 +KPX W Ohungarumlaut -20 +KPX W Omacron -20 +KPX W Oslash -20 +KPX W Otilde -20 +KPX W a -40 +KPX W aacute -40 +KPX W abreve -40 +KPX W acircumflex -40 +KPX W adieresis -40 +KPX W agrave -40 +KPX W amacron -40 +KPX W aogonek -40 +KPX W aring -40 +KPX W atilde -40 +KPX W comma -80 +KPX W e -30 +KPX W eacute -30 +KPX W ecaron -30 +KPX W ecircumflex -30 +KPX W edieresis -30 +KPX W edotaccent -30 +KPX W egrave -30 +KPX W emacron -30 +KPX W eogonek -30 +KPX W hyphen -40 +KPX W o -30 +KPX W oacute -30 +KPX W ocircumflex -30 +KPX W odieresis -30 +KPX W ograve -30 +KPX W ohungarumlaut -30 +KPX W omacron -30 +KPX W oslash -30 +KPX W otilde -30 +KPX W period -80 +KPX W u -30 +KPX W uacute -30 +KPX W ucircumflex -30 +KPX W udieresis -30 +KPX W ugrave -30 +KPX W uhungarumlaut -30 +KPX W umacron -30 +KPX W uogonek -30 +KPX W uring -30 +KPX W y -20 +KPX W yacute -20 +KPX W ydieresis -20 +KPX Y A -110 +KPX Y Aacute -110 +KPX Y Abreve -110 +KPX Y Acircumflex -110 +KPX Y Adieresis -110 +KPX Y Agrave -110 +KPX Y Amacron -110 +KPX Y Aogonek -110 +KPX Y Aring -110 +KPX Y Atilde -110 +KPX Y O -85 +KPX Y Oacute -85 +KPX Y Ocircumflex -85 +KPX Y Odieresis -85 +KPX Y Ograve -85 +KPX Y Ohungarumlaut -85 +KPX Y Omacron -85 +KPX Y Oslash -85 +KPX Y Otilde -85 +KPX Y a -140 +KPX Y aacute -140 +KPX Y abreve -70 +KPX Y acircumflex -140 +KPX Y adieresis -140 +KPX Y agrave -140 +KPX Y amacron -70 +KPX Y aogonek -140 +KPX Y aring -140 +KPX Y atilde -140 +KPX Y colon -60 +KPX Y comma -140 +KPX Y e -140 +KPX Y eacute -140 +KPX Y ecaron -140 +KPX Y ecircumflex -140 +KPX Y edieresis -140 +KPX Y edotaccent -140 +KPX Y egrave -140 +KPX Y emacron -70 +KPX Y eogonek -140 +KPX Y hyphen -140 +KPX Y i -20 +KPX Y iacute -20 +KPX Y iogonek -20 +KPX Y o -140 +KPX Y oacute -140 +KPX Y ocircumflex -140 +KPX Y odieresis -140 +KPX Y ograve -140 +KPX Y ohungarumlaut -140 +KPX Y omacron -140 +KPX Y oslash -140 +KPX Y otilde -140 +KPX Y period -140 +KPX Y semicolon -60 +KPX Y u -110 +KPX Y uacute -110 +KPX Y ucircumflex -110 +KPX Y udieresis -110 +KPX Y ugrave -110 +KPX Y uhungarumlaut -110 +KPX Y umacron -110 +KPX Y uogonek -110 +KPX Y uring -110 +KPX Yacute A -110 +KPX Yacute Aacute -110 +KPX Yacute Abreve -110 +KPX Yacute Acircumflex -110 +KPX Yacute Adieresis -110 +KPX Yacute Agrave -110 +KPX Yacute Amacron -110 +KPX Yacute Aogonek -110 +KPX Yacute Aring -110 +KPX Yacute Atilde -110 +KPX Yacute O -85 +KPX Yacute Oacute -85 +KPX Yacute Ocircumflex -85 +KPX Yacute Odieresis -85 +KPX Yacute Ograve -85 +KPX Yacute Ohungarumlaut -85 +KPX Yacute Omacron -85 +KPX Yacute Oslash -85 +KPX Yacute Otilde -85 +KPX Yacute a -140 +KPX Yacute aacute -140 +KPX Yacute abreve -70 +KPX Yacute acircumflex -140 +KPX Yacute adieresis -140 +KPX Yacute agrave -140 +KPX Yacute amacron -70 +KPX Yacute aogonek -140 +KPX Yacute aring -140 +KPX Yacute atilde -70 +KPX Yacute colon -60 +KPX Yacute comma -140 +KPX Yacute e -140 +KPX Yacute eacute -140 +KPX Yacute ecaron -140 +KPX Yacute ecircumflex -140 +KPX Yacute edieresis -140 +KPX Yacute edotaccent -140 +KPX Yacute egrave -140 +KPX Yacute emacron -70 +KPX Yacute eogonek -140 +KPX Yacute hyphen -140 +KPX Yacute i -20 +KPX Yacute iacute -20 +KPX Yacute iogonek -20 +KPX Yacute o -140 +KPX Yacute oacute -140 +KPX Yacute ocircumflex -140 +KPX Yacute odieresis -140 +KPX Yacute ograve -140 +KPX Yacute ohungarumlaut -140 +KPX Yacute omacron -70 +KPX Yacute oslash -140 +KPX Yacute otilde -140 +KPX Yacute period -140 +KPX Yacute semicolon -60 +KPX Yacute u -110 +KPX Yacute uacute -110 +KPX Yacute ucircumflex -110 +KPX Yacute udieresis -110 +KPX Yacute ugrave -110 +KPX Yacute uhungarumlaut -110 +KPX Yacute umacron -110 +KPX Yacute uogonek -110 +KPX Yacute uring -110 +KPX Ydieresis A -110 +KPX Ydieresis Aacute -110 +KPX Ydieresis Abreve -110 +KPX Ydieresis Acircumflex -110 +KPX Ydieresis Adieresis -110 +KPX Ydieresis Agrave -110 +KPX Ydieresis Amacron -110 +KPX Ydieresis Aogonek -110 +KPX Ydieresis Aring -110 +KPX Ydieresis Atilde -110 +KPX Ydieresis O -85 +KPX Ydieresis Oacute -85 +KPX Ydieresis Ocircumflex -85 +KPX Ydieresis Odieresis -85 +KPX Ydieresis Ograve -85 +KPX Ydieresis Ohungarumlaut -85 +KPX Ydieresis Omacron -85 +KPX Ydieresis Oslash -85 +KPX Ydieresis Otilde -85 +KPX Ydieresis a -140 +KPX Ydieresis aacute -140 +KPX Ydieresis abreve -70 +KPX Ydieresis acircumflex -140 +KPX Ydieresis adieresis -140 +KPX Ydieresis agrave -140 +KPX Ydieresis amacron -70 +KPX Ydieresis aogonek -140 +KPX Ydieresis aring -140 +KPX Ydieresis atilde -70 +KPX Ydieresis colon -60 +KPX Ydieresis comma -140 +KPX Ydieresis e -140 +KPX Ydieresis eacute -140 +KPX Ydieresis ecaron -140 +KPX Ydieresis ecircumflex -140 +KPX Ydieresis edieresis -140 +KPX Ydieresis edotaccent -140 +KPX Ydieresis egrave -140 +KPX Ydieresis emacron -70 +KPX Ydieresis eogonek -140 +KPX Ydieresis hyphen -140 +KPX Ydieresis i -20 +KPX Ydieresis iacute -20 +KPX Ydieresis iogonek -20 +KPX Ydieresis o -140 +KPX Ydieresis oacute -140 +KPX Ydieresis ocircumflex -140 +KPX Ydieresis odieresis -140 +KPX Ydieresis ograve -140 +KPX Ydieresis ohungarumlaut -140 +KPX Ydieresis omacron -140 +KPX Ydieresis oslash -140 +KPX Ydieresis otilde -140 +KPX Ydieresis period -140 +KPX Ydieresis semicolon -60 +KPX Ydieresis u -110 +KPX Ydieresis uacute -110 +KPX Ydieresis ucircumflex -110 +KPX Ydieresis udieresis -110 +KPX Ydieresis ugrave -110 +KPX Ydieresis uhungarumlaut -110 +KPX Ydieresis umacron -110 +KPX Ydieresis uogonek -110 +KPX Ydieresis uring -110 +KPX a v -20 +KPX a w -20 +KPX a y -30 +KPX a yacute -30 +KPX a ydieresis -30 +KPX aacute v -20 +KPX aacute w -20 +KPX aacute y -30 +KPX aacute yacute -30 +KPX aacute ydieresis -30 +KPX abreve v -20 +KPX abreve w -20 +KPX abreve y -30 +KPX abreve yacute -30 +KPX abreve ydieresis -30 +KPX acircumflex v -20 +KPX acircumflex w -20 +KPX acircumflex y -30 +KPX acircumflex yacute -30 +KPX acircumflex ydieresis -30 +KPX adieresis v -20 +KPX adieresis w -20 +KPX adieresis y -30 +KPX adieresis yacute -30 +KPX adieresis ydieresis -30 +KPX agrave v -20 +KPX agrave w -20 +KPX agrave y -30 +KPX agrave yacute -30 +KPX agrave ydieresis -30 +KPX amacron v -20 +KPX amacron w -20 +KPX amacron y -30 +KPX amacron yacute -30 +KPX amacron ydieresis -30 +KPX aogonek v -20 +KPX aogonek w -20 +KPX aogonek y -30 +KPX aogonek yacute -30 +KPX aogonek ydieresis -30 +KPX aring v -20 +KPX aring w -20 +KPX aring y -30 +KPX aring yacute -30 +KPX aring ydieresis -30 +KPX atilde v -20 +KPX atilde w -20 +KPX atilde y -30 +KPX atilde yacute -30 +KPX atilde ydieresis -30 +KPX b b -10 +KPX b comma -40 +KPX b l -20 +KPX b lacute -20 +KPX b lcommaaccent -20 +KPX b lslash -20 +KPX b period -40 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX b v -20 +KPX b y -20 +KPX b yacute -20 +KPX b ydieresis -20 +KPX c comma -15 +KPX c k -20 +KPX c kcommaaccent -20 +KPX cacute comma -15 +KPX cacute k -20 +KPX cacute kcommaaccent -20 +KPX ccaron comma -15 +KPX ccaron k -20 +KPX ccaron kcommaaccent -20 +KPX ccedilla comma -15 +KPX ccedilla k -20 +KPX ccedilla kcommaaccent -20 +KPX colon space -50 +KPX comma quotedblright -100 +KPX comma quoteright -100 +KPX e comma -15 +KPX e period -15 +KPX e v -30 +KPX e w -20 +KPX e x -30 +KPX e y -20 +KPX e yacute -20 +KPX e ydieresis -20 +KPX eacute comma -15 +KPX eacute period -15 +KPX eacute v -30 +KPX eacute w -20 +KPX eacute x -30 +KPX eacute y -20 +KPX eacute yacute -20 +KPX eacute ydieresis -20 +KPX ecaron comma -15 +KPX ecaron period -15 +KPX ecaron v -30 +KPX ecaron w -20 +KPX ecaron x -30 +KPX ecaron y -20 +KPX ecaron yacute -20 +KPX ecaron ydieresis -20 +KPX ecircumflex comma -15 +KPX ecircumflex period -15 +KPX ecircumflex v -30 +KPX ecircumflex w -20 +KPX ecircumflex x -30 +KPX ecircumflex y -20 +KPX ecircumflex yacute -20 +KPX ecircumflex ydieresis -20 +KPX edieresis comma -15 +KPX edieresis period -15 +KPX edieresis v -30 +KPX edieresis w -20 +KPX edieresis x -30 +KPX edieresis y -20 +KPX edieresis yacute -20 +KPX edieresis ydieresis -20 +KPX edotaccent comma -15 +KPX edotaccent period -15 +KPX edotaccent v -30 +KPX edotaccent w -20 +KPX edotaccent x -30 +KPX edotaccent y -20 +KPX edotaccent yacute -20 +KPX edotaccent ydieresis -20 +KPX egrave comma -15 +KPX egrave period -15 +KPX egrave v -30 +KPX egrave w -20 +KPX egrave x -30 +KPX egrave y -20 +KPX egrave yacute -20 +KPX egrave ydieresis -20 +KPX emacron comma -15 +KPX emacron period -15 +KPX emacron v -30 +KPX emacron w -20 +KPX emacron x -30 +KPX emacron y -20 +KPX emacron yacute -20 +KPX emacron ydieresis -20 +KPX eogonek comma -15 +KPX eogonek period -15 +KPX eogonek v -30 +KPX eogonek w -20 +KPX eogonek x -30 +KPX eogonek y -20 +KPX eogonek yacute -20 +KPX eogonek ydieresis -20 +KPX f a -30 +KPX f aacute -30 +KPX f abreve -30 +KPX f acircumflex -30 +KPX f adieresis -30 +KPX f agrave -30 +KPX f amacron -30 +KPX f aogonek -30 +KPX f aring -30 +KPX f atilde -30 +KPX f comma -30 +KPX f dotlessi -28 +KPX f e -30 +KPX f eacute -30 +KPX f ecaron -30 +KPX f ecircumflex -30 +KPX f edieresis -30 +KPX f edotaccent -30 +KPX f egrave -30 +KPX f emacron -30 +KPX f eogonek -30 +KPX f o -30 +KPX f oacute -30 +KPX f ocircumflex -30 +KPX f odieresis -30 +KPX f ograve -30 +KPX f ohungarumlaut -30 +KPX f omacron -30 +KPX f oslash -30 +KPX f otilde -30 +KPX f period -30 +KPX f quotedblright 60 +KPX f quoteright 50 +KPX g r -10 +KPX g racute -10 +KPX g rcaron -10 +KPX g rcommaaccent -10 +KPX gbreve r -10 +KPX gbreve racute -10 +KPX gbreve rcaron -10 +KPX gbreve rcommaaccent -10 +KPX gcommaaccent r -10 +KPX gcommaaccent racute -10 +KPX gcommaaccent rcaron -10 +KPX gcommaaccent rcommaaccent -10 +KPX h y -30 +KPX h yacute -30 +KPX h ydieresis -30 +KPX k e -20 +KPX k eacute -20 +KPX k ecaron -20 +KPX k ecircumflex -20 +KPX k edieresis -20 +KPX k edotaccent -20 +KPX k egrave -20 +KPX k emacron -20 +KPX k eogonek -20 +KPX k o -20 +KPX k oacute -20 +KPX k ocircumflex -20 +KPX k odieresis -20 +KPX k ograve -20 +KPX k ohungarumlaut -20 +KPX k omacron -20 +KPX k oslash -20 +KPX k otilde -20 +KPX kcommaaccent e -20 +KPX kcommaaccent eacute -20 +KPX kcommaaccent ecaron -20 +KPX kcommaaccent ecircumflex -20 +KPX kcommaaccent edieresis -20 +KPX kcommaaccent edotaccent -20 +KPX kcommaaccent egrave -20 +KPX kcommaaccent emacron -20 +KPX kcommaaccent eogonek -20 +KPX kcommaaccent o -20 +KPX kcommaaccent oacute -20 +KPX kcommaaccent ocircumflex -20 +KPX kcommaaccent odieresis -20 +KPX kcommaaccent ograve -20 +KPX kcommaaccent ohungarumlaut -20 +KPX kcommaaccent omacron -20 +KPX kcommaaccent oslash -20 +KPX kcommaaccent otilde -20 +KPX m u -10 +KPX m uacute -10 +KPX m ucircumflex -10 +KPX m udieresis -10 +KPX m ugrave -10 +KPX m uhungarumlaut -10 +KPX m umacron -10 +KPX m uogonek -10 +KPX m uring -10 +KPX m y -15 +KPX m yacute -15 +KPX m ydieresis -15 +KPX n u -10 +KPX n uacute -10 +KPX n ucircumflex -10 +KPX n udieresis -10 +KPX n ugrave -10 +KPX n uhungarumlaut -10 +KPX n umacron -10 +KPX n uogonek -10 +KPX n uring -10 +KPX n v -20 +KPX n y -15 +KPX n yacute -15 +KPX n ydieresis -15 +KPX nacute u -10 +KPX nacute uacute -10 +KPX nacute ucircumflex -10 +KPX nacute udieresis -10 +KPX nacute ugrave -10 +KPX nacute uhungarumlaut -10 +KPX nacute umacron -10 +KPX nacute uogonek -10 +KPX nacute uring -10 +KPX nacute v -20 +KPX nacute y -15 +KPX nacute yacute -15 +KPX nacute ydieresis -15 +KPX ncaron u -10 +KPX ncaron uacute -10 +KPX ncaron ucircumflex -10 +KPX ncaron udieresis -10 +KPX ncaron ugrave -10 +KPX ncaron uhungarumlaut -10 +KPX ncaron umacron -10 +KPX ncaron uogonek -10 +KPX ncaron uring -10 +KPX ncaron v -20 +KPX ncaron y -15 +KPX ncaron yacute -15 +KPX ncaron ydieresis -15 +KPX ncommaaccent u -10 +KPX ncommaaccent uacute -10 +KPX ncommaaccent ucircumflex -10 +KPX ncommaaccent udieresis -10 +KPX ncommaaccent ugrave -10 +KPX ncommaaccent uhungarumlaut -10 +KPX ncommaaccent umacron -10 +KPX ncommaaccent uogonek -10 +KPX ncommaaccent uring -10 +KPX ncommaaccent v -20 +KPX ncommaaccent y -15 +KPX ncommaaccent yacute -15 +KPX ncommaaccent ydieresis -15 +KPX ntilde u -10 +KPX ntilde uacute -10 +KPX ntilde ucircumflex -10 +KPX ntilde udieresis -10 +KPX ntilde ugrave -10 +KPX ntilde uhungarumlaut -10 +KPX ntilde umacron -10 +KPX ntilde uogonek -10 +KPX ntilde uring -10 +KPX ntilde v -20 +KPX ntilde y -15 +KPX ntilde yacute -15 +KPX ntilde ydieresis -15 +KPX o comma -40 +KPX o period -40 +KPX o v -15 +KPX o w -15 +KPX o x -30 +KPX o y -30 +KPX o yacute -30 +KPX o ydieresis -30 +KPX oacute comma -40 +KPX oacute period -40 +KPX oacute v -15 +KPX oacute w -15 +KPX oacute x -30 +KPX oacute y -30 +KPX oacute yacute -30 +KPX oacute ydieresis -30 +KPX ocircumflex comma -40 +KPX ocircumflex period -40 +KPX ocircumflex v -15 +KPX ocircumflex w -15 +KPX ocircumflex x -30 +KPX ocircumflex y -30 +KPX ocircumflex yacute -30 +KPX ocircumflex ydieresis -30 +KPX odieresis comma -40 +KPX odieresis period -40 +KPX odieresis v -15 +KPX odieresis w -15 +KPX odieresis x -30 +KPX odieresis y -30 +KPX odieresis yacute -30 +KPX odieresis ydieresis -30 +KPX ograve comma -40 +KPX ograve period -40 +KPX ograve v -15 +KPX ograve w -15 +KPX ograve x -30 +KPX ograve y -30 +KPX ograve yacute -30 +KPX ograve ydieresis -30 +KPX ohungarumlaut comma -40 +KPX ohungarumlaut period -40 +KPX ohungarumlaut v -15 +KPX ohungarumlaut w -15 +KPX ohungarumlaut x -30 +KPX ohungarumlaut y -30 +KPX ohungarumlaut yacute -30 +KPX ohungarumlaut ydieresis -30 +KPX omacron comma -40 +KPX omacron period -40 +KPX omacron v -15 +KPX omacron w -15 +KPX omacron x -30 +KPX omacron y -30 +KPX omacron yacute -30 +KPX omacron ydieresis -30 +KPX oslash a -55 +KPX oslash aacute -55 +KPX oslash abreve -55 +KPX oslash acircumflex -55 +KPX oslash adieresis -55 +KPX oslash agrave -55 +KPX oslash amacron -55 +KPX oslash aogonek -55 +KPX oslash aring -55 +KPX oslash atilde -55 +KPX oslash b -55 +KPX oslash c -55 +KPX oslash cacute -55 +KPX oslash ccaron -55 +KPX oslash ccedilla -55 +KPX oslash comma -95 +KPX oslash d -55 +KPX oslash dcroat -55 +KPX oslash e -55 +KPX oslash eacute -55 +KPX oslash ecaron -55 +KPX oslash ecircumflex -55 +KPX oslash edieresis -55 +KPX oslash edotaccent -55 +KPX oslash egrave -55 +KPX oslash emacron -55 +KPX oslash eogonek -55 +KPX oslash f -55 +KPX oslash g -55 +KPX oslash gbreve -55 +KPX oslash gcommaaccent -55 +KPX oslash h -55 +KPX oslash i -55 +KPX oslash iacute -55 +KPX oslash icircumflex -55 +KPX oslash idieresis -55 +KPX oslash igrave -55 +KPX oslash imacron -55 +KPX oslash iogonek -55 +KPX oslash j -55 +KPX oslash k -55 +KPX oslash kcommaaccent -55 +KPX oslash l -55 +KPX oslash lacute -55 +KPX oslash lcommaaccent -55 +KPX oslash lslash -55 +KPX oslash m -55 +KPX oslash n -55 +KPX oslash nacute -55 +KPX oslash ncaron -55 +KPX oslash ncommaaccent -55 +KPX oslash ntilde -55 +KPX oslash o -55 +KPX oslash oacute -55 +KPX oslash ocircumflex -55 +KPX oslash odieresis -55 +KPX oslash ograve -55 +KPX oslash ohungarumlaut -55 +KPX oslash omacron -55 +KPX oslash oslash -55 +KPX oslash otilde -55 +KPX oslash p -55 +KPX oslash period -95 +KPX oslash q -55 +KPX oslash r -55 +KPX oslash racute -55 +KPX oslash rcaron -55 +KPX oslash rcommaaccent -55 +KPX oslash s -55 +KPX oslash sacute -55 +KPX oslash scaron -55 +KPX oslash scedilla -55 +KPX oslash scommaaccent -55 +KPX oslash t -55 +KPX oslash tcommaaccent -55 +KPX oslash u -55 +KPX oslash uacute -55 +KPX oslash ucircumflex -55 +KPX oslash udieresis -55 +KPX oslash ugrave -55 +KPX oslash uhungarumlaut -55 +KPX oslash umacron -55 +KPX oslash uogonek -55 +KPX oslash uring -55 +KPX oslash v -70 +KPX oslash w -70 +KPX oslash x -85 +KPX oslash y -70 +KPX oslash yacute -70 +KPX oslash ydieresis -70 +KPX oslash z -55 +KPX oslash zacute -55 +KPX oslash zcaron -55 +KPX oslash zdotaccent -55 +KPX otilde comma -40 +KPX otilde period -40 +KPX otilde v -15 +KPX otilde w -15 +KPX otilde x -30 +KPX otilde y -30 +KPX otilde yacute -30 +KPX otilde ydieresis -30 +KPX p comma -35 +KPX p period -35 +KPX p y -30 +KPX p yacute -30 +KPX p ydieresis -30 +KPX period quotedblright -100 +KPX period quoteright -100 +KPX period space -60 +KPX quotedblright space -40 +KPX quoteleft quoteleft -57 +KPX quoteright d -50 +KPX quoteright dcroat -50 +KPX quoteright quoteright -57 +KPX quoteright r -50 +KPX quoteright racute -50 +KPX quoteright rcaron -50 +KPX quoteright rcommaaccent -50 +KPX quoteright s -50 +KPX quoteright sacute -50 +KPX quoteright scaron -50 +KPX quoteright scedilla -50 +KPX quoteright scommaaccent -50 +KPX quoteright space -70 +KPX r a -10 +KPX r aacute -10 +KPX r abreve -10 +KPX r acircumflex -10 +KPX r adieresis -10 +KPX r agrave -10 +KPX r amacron -10 +KPX r aogonek -10 +KPX r aring -10 +KPX r atilde -10 +KPX r colon 30 +KPX r comma -50 +KPX r i 15 +KPX r iacute 15 +KPX r icircumflex 15 +KPX r idieresis 15 +KPX r igrave 15 +KPX r imacron 15 +KPX r iogonek 15 +KPX r k 15 +KPX r kcommaaccent 15 +KPX r l 15 +KPX r lacute 15 +KPX r lcommaaccent 15 +KPX r lslash 15 +KPX r m 25 +KPX r n 25 +KPX r nacute 25 +KPX r ncaron 25 +KPX r ncommaaccent 25 +KPX r ntilde 25 +KPX r p 30 +KPX r period -50 +KPX r semicolon 30 +KPX r t 40 +KPX r tcommaaccent 40 +KPX r u 15 +KPX r uacute 15 +KPX r ucircumflex 15 +KPX r udieresis 15 +KPX r ugrave 15 +KPX r uhungarumlaut 15 +KPX r umacron 15 +KPX r uogonek 15 +KPX r uring 15 +KPX r v 30 +KPX r y 30 +KPX r yacute 30 +KPX r ydieresis 30 +KPX racute a -10 +KPX racute aacute -10 +KPX racute abreve -10 +KPX racute acircumflex -10 +KPX racute adieresis -10 +KPX racute agrave -10 +KPX racute amacron -10 +KPX racute aogonek -10 +KPX racute aring -10 +KPX racute atilde -10 +KPX racute colon 30 +KPX racute comma -50 +KPX racute i 15 +KPX racute iacute 15 +KPX racute icircumflex 15 +KPX racute idieresis 15 +KPX racute igrave 15 +KPX racute imacron 15 +KPX racute iogonek 15 +KPX racute k 15 +KPX racute kcommaaccent 15 +KPX racute l 15 +KPX racute lacute 15 +KPX racute lcommaaccent 15 +KPX racute lslash 15 +KPX racute m 25 +KPX racute n 25 +KPX racute nacute 25 +KPX racute ncaron 25 +KPX racute ncommaaccent 25 +KPX racute ntilde 25 +KPX racute p 30 +KPX racute period -50 +KPX racute semicolon 30 +KPX racute t 40 +KPX racute tcommaaccent 40 +KPX racute u 15 +KPX racute uacute 15 +KPX racute ucircumflex 15 +KPX racute udieresis 15 +KPX racute ugrave 15 +KPX racute uhungarumlaut 15 +KPX racute umacron 15 +KPX racute uogonek 15 +KPX racute uring 15 +KPX racute v 30 +KPX racute y 30 +KPX racute yacute 30 +KPX racute ydieresis 30 +KPX rcaron a -10 +KPX rcaron aacute -10 +KPX rcaron abreve -10 +KPX rcaron acircumflex -10 +KPX rcaron adieresis -10 +KPX rcaron agrave -10 +KPX rcaron amacron -10 +KPX rcaron aogonek -10 +KPX rcaron aring -10 +KPX rcaron atilde -10 +KPX rcaron colon 30 +KPX rcaron comma -50 +KPX rcaron i 15 +KPX rcaron iacute 15 +KPX rcaron icircumflex 15 +KPX rcaron idieresis 15 +KPX rcaron igrave 15 +KPX rcaron imacron 15 +KPX rcaron iogonek 15 +KPX rcaron k 15 +KPX rcaron kcommaaccent 15 +KPX rcaron l 15 +KPX rcaron lacute 15 +KPX rcaron lcommaaccent 15 +KPX rcaron lslash 15 +KPX rcaron m 25 +KPX rcaron n 25 +KPX rcaron nacute 25 +KPX rcaron ncaron 25 +KPX rcaron ncommaaccent 25 +KPX rcaron ntilde 25 +KPX rcaron p 30 +KPX rcaron period -50 +KPX rcaron semicolon 30 +KPX rcaron t 40 +KPX rcaron tcommaaccent 40 +KPX rcaron u 15 +KPX rcaron uacute 15 +KPX rcaron ucircumflex 15 +KPX rcaron udieresis 15 +KPX rcaron ugrave 15 +KPX rcaron uhungarumlaut 15 +KPX rcaron umacron 15 +KPX rcaron uogonek 15 +KPX rcaron uring 15 +KPX rcaron v 30 +KPX rcaron y 30 +KPX rcaron yacute 30 +KPX rcaron ydieresis 30 +KPX rcommaaccent a -10 +KPX rcommaaccent aacute -10 +KPX rcommaaccent abreve -10 +KPX rcommaaccent acircumflex -10 +KPX rcommaaccent adieresis -10 +KPX rcommaaccent agrave -10 +KPX rcommaaccent amacron -10 +KPX rcommaaccent aogonek -10 +KPX rcommaaccent aring -10 +KPX rcommaaccent atilde -10 +KPX rcommaaccent colon 30 +KPX rcommaaccent comma -50 +KPX rcommaaccent i 15 +KPX rcommaaccent iacute 15 +KPX rcommaaccent icircumflex 15 +KPX rcommaaccent idieresis 15 +KPX rcommaaccent igrave 15 +KPX rcommaaccent imacron 15 +KPX rcommaaccent iogonek 15 +KPX rcommaaccent k 15 +KPX rcommaaccent kcommaaccent 15 +KPX rcommaaccent l 15 +KPX rcommaaccent lacute 15 +KPX rcommaaccent lcommaaccent 15 +KPX rcommaaccent lslash 15 +KPX rcommaaccent m 25 +KPX rcommaaccent n 25 +KPX rcommaaccent nacute 25 +KPX rcommaaccent ncaron 25 +KPX rcommaaccent ncommaaccent 25 +KPX rcommaaccent ntilde 25 +KPX rcommaaccent p 30 +KPX rcommaaccent period -50 +KPX rcommaaccent semicolon 30 +KPX rcommaaccent t 40 +KPX rcommaaccent tcommaaccent 40 +KPX rcommaaccent u 15 +KPX rcommaaccent uacute 15 +KPX rcommaaccent ucircumflex 15 +KPX rcommaaccent udieresis 15 +KPX rcommaaccent ugrave 15 +KPX rcommaaccent uhungarumlaut 15 +KPX rcommaaccent umacron 15 +KPX rcommaaccent uogonek 15 +KPX rcommaaccent uring 15 +KPX rcommaaccent v 30 +KPX rcommaaccent y 30 +KPX rcommaaccent yacute 30 +KPX rcommaaccent ydieresis 30 +KPX s comma -15 +KPX s period -15 +KPX s w -30 +KPX sacute comma -15 +KPX sacute period -15 +KPX sacute w -30 +KPX scaron comma -15 +KPX scaron period -15 +KPX scaron w -30 +KPX scedilla comma -15 +KPX scedilla period -15 +KPX scedilla w -30 +KPX scommaaccent comma -15 +KPX scommaaccent period -15 +KPX scommaaccent w -30 +KPX semicolon space -50 +KPX space T -50 +KPX space Tcaron -50 +KPX space Tcommaaccent -50 +KPX space V -50 +KPX space W -40 +KPX space Y -90 +KPX space Yacute -90 +KPX space Ydieresis -90 +KPX space quotedblleft -30 +KPX space quoteleft -60 +KPX v a -25 +KPX v aacute -25 +KPX v abreve -25 +KPX v acircumflex -25 +KPX v adieresis -25 +KPX v agrave -25 +KPX v amacron -25 +KPX v aogonek -25 +KPX v aring -25 +KPX v atilde -25 +KPX v comma -80 +KPX v e -25 +KPX v eacute -25 +KPX v ecaron -25 +KPX v ecircumflex -25 +KPX v edieresis -25 +KPX v edotaccent -25 +KPX v egrave -25 +KPX v emacron -25 +KPX v eogonek -25 +KPX v o -25 +KPX v oacute -25 +KPX v ocircumflex -25 +KPX v odieresis -25 +KPX v ograve -25 +KPX v ohungarumlaut -25 +KPX v omacron -25 +KPX v oslash -25 +KPX v otilde -25 +KPX v period -80 +KPX w a -15 +KPX w aacute -15 +KPX w abreve -15 +KPX w acircumflex -15 +KPX w adieresis -15 +KPX w agrave -15 +KPX w amacron -15 +KPX w aogonek -15 +KPX w aring -15 +KPX w atilde -15 +KPX w comma -60 +KPX w e -10 +KPX w eacute -10 +KPX w ecaron -10 +KPX w ecircumflex -10 +KPX w edieresis -10 +KPX w edotaccent -10 +KPX w egrave -10 +KPX w emacron -10 +KPX w eogonek -10 +KPX w o -10 +KPX w oacute -10 +KPX w ocircumflex -10 +KPX w odieresis -10 +KPX w ograve -10 +KPX w ohungarumlaut -10 +KPX w omacron -10 +KPX w oslash -10 +KPX w otilde -10 +KPX w period -60 +KPX x e -30 +KPX x eacute -30 +KPX x ecaron -30 +KPX x ecircumflex -30 +KPX x edieresis -30 +KPX x edotaccent -30 +KPX x egrave -30 +KPX x emacron -30 +KPX x eogonek -30 +KPX y a -20 +KPX y aacute -20 +KPX y abreve -20 +KPX y acircumflex -20 +KPX y adieresis -20 +KPX y agrave -20 +KPX y amacron -20 +KPX y aogonek -20 +KPX y aring -20 +KPX y atilde -20 +KPX y comma -100 +KPX y e -20 +KPX y eacute -20 +KPX y ecaron -20 +KPX y ecircumflex -20 +KPX y edieresis -20 +KPX y edotaccent -20 +KPX y egrave -20 +KPX y emacron -20 +KPX y eogonek -20 +KPX y o -20 +KPX y oacute -20 +KPX y ocircumflex -20 +KPX y odieresis -20 +KPX y ograve -20 +KPX y ohungarumlaut -20 +KPX y omacron -20 +KPX y oslash -20 +KPX y otilde -20 +KPX y period -100 +KPX yacute a -20 +KPX yacute aacute -20 +KPX yacute abreve -20 +KPX yacute acircumflex -20 +KPX yacute adieresis -20 +KPX yacute agrave -20 +KPX yacute amacron -20 +KPX yacute aogonek -20 +KPX yacute aring -20 +KPX yacute atilde -20 +KPX yacute comma -100 +KPX yacute e -20 +KPX yacute eacute -20 +KPX yacute ecaron -20 +KPX yacute ecircumflex -20 +KPX yacute edieresis -20 +KPX yacute edotaccent -20 +KPX yacute egrave -20 +KPX yacute emacron -20 +KPX yacute eogonek -20 +KPX yacute o -20 +KPX yacute oacute -20 +KPX yacute ocircumflex -20 +KPX yacute odieresis -20 +KPX yacute ograve -20 +KPX yacute ohungarumlaut -20 +KPX yacute omacron -20 +KPX yacute oslash -20 +KPX yacute otilde -20 +KPX yacute period -100 +KPX ydieresis a -20 +KPX ydieresis aacute -20 +KPX ydieresis abreve -20 +KPX ydieresis acircumflex -20 +KPX ydieresis adieresis -20 +KPX ydieresis agrave -20 +KPX ydieresis amacron -20 +KPX ydieresis aogonek -20 +KPX ydieresis aring -20 +KPX ydieresis atilde -20 +KPX ydieresis comma -100 +KPX ydieresis e -20 +KPX ydieresis eacute -20 +KPX ydieresis ecaron -20 +KPX ydieresis ecircumflex -20 +KPX ydieresis edieresis -20 +KPX ydieresis edotaccent -20 +KPX ydieresis egrave -20 +KPX ydieresis emacron -20 +KPX ydieresis eogonek -20 +KPX ydieresis o -20 +KPX ydieresis oacute -20 +KPX ydieresis ocircumflex -20 +KPX ydieresis odieresis -20 +KPX ydieresis ograve -20 +KPX ydieresis ohungarumlaut -20 +KPX ydieresis omacron -20 +KPX ydieresis oslash -20 +KPX ydieresis otilde -20 +KPX ydieresis period -100 +KPX z e -15 +KPX z eacute -15 +KPX z ecaron -15 +KPX z ecircumflex -15 +KPX z edieresis -15 +KPX z edotaccent -15 +KPX z egrave -15 +KPX z emacron -15 +KPX z eogonek -15 +KPX z o -15 +KPX z oacute -15 +KPX z ocircumflex -15 +KPX z odieresis -15 +KPX z ograve -15 +KPX z ohungarumlaut -15 +KPX z omacron -15 +KPX z oslash -15 +KPX z otilde -15 +KPX zacute e -15 +KPX zacute eacute -15 +KPX zacute ecaron -15 +KPX zacute ecircumflex -15 +KPX zacute edieresis -15 +KPX zacute edotaccent -15 +KPX zacute egrave -15 +KPX zacute emacron -15 +KPX zacute eogonek -15 +KPX zacute o -15 +KPX zacute oacute -15 +KPX zacute ocircumflex -15 +KPX zacute odieresis -15 +KPX zacute ograve -15 +KPX zacute ohungarumlaut -15 +KPX zacute omacron -15 +KPX zacute oslash -15 +KPX zacute otilde -15 +KPX zcaron e -15 +KPX zcaron eacute -15 +KPX zcaron ecaron -15 +KPX zcaron ecircumflex -15 +KPX zcaron edieresis -15 +KPX zcaron edotaccent -15 +KPX zcaron egrave -15 +KPX zcaron emacron -15 +KPX zcaron eogonek -15 +KPX zcaron o -15 +KPX zcaron oacute -15 +KPX zcaron ocircumflex -15 +KPX zcaron odieresis -15 +KPX zcaron ograve -15 +KPX zcaron ohungarumlaut -15 +KPX zcaron omacron -15 +KPX zcaron oslash -15 +KPX zcaron otilde -15 +KPX zdotaccent e -15 +KPX zdotaccent eacute -15 +KPX zdotaccent ecaron -15 +KPX zdotaccent ecircumflex -15 +KPX zdotaccent edieresis -15 +KPX zdotaccent edotaccent -15 +KPX zdotaccent egrave -15 +KPX zdotaccent emacron -15 +KPX zdotaccent eogonek -15 +KPX zdotaccent o -15 +KPX zdotaccent oacute -15 +KPX zdotaccent ocircumflex -15 +KPX zdotaccent odieresis -15 +KPX zdotaccent ograve -15 +KPX zdotaccent ohungarumlaut -15 +KPX zdotaccent omacron -15 +KPX zdotaccent oslash -15 +KPX zdotaccent otilde -15 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica.afm new file mode 100644 index 0000000..10746a5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Helvetica.afm @@ -0,0 +1,3051 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:38:23 1997 +Comment UniqueID 43054 +Comment VMusage 37069 48094 +FontName Helvetica +FullName Helvetica +FamilyName Helvetica +Weight Medium +ItalicAngle 0 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -166 -225 1000 931 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 718 +XHeight 523 +Ascender 718 +Descender -207 +StdHW 76 +StdVW 88 +StartCharMetrics 315 +C 32 ; WX 278 ; N space ; B 0 0 0 0 ; +C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ; +C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ; +C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ; +C 36 ; WX 556 ; N dollar ; B 32 -115 520 775 ; +C 37 ; WX 889 ; N percent ; B 39 -19 850 703 ; +C 38 ; WX 667 ; N ampersand ; B 44 -15 645 718 ; +C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ; +C 40 ; WX 333 ; N parenleft ; B 68 -207 299 733 ; +C 41 ; WX 333 ; N parenright ; B 34 -207 265 733 ; +C 42 ; WX 389 ; N asterisk ; B 39 431 349 718 ; +C 43 ; WX 584 ; N plus ; B 39 0 545 505 ; +C 44 ; WX 278 ; N comma ; B 87 -147 191 106 ; +C 45 ; WX 333 ; N hyphen ; B 44 232 289 322 ; +C 46 ; WX 278 ; N period ; B 87 0 191 106 ; +C 47 ; WX 278 ; N slash ; B -17 -19 295 737 ; +C 48 ; WX 556 ; N zero ; B 37 -19 519 703 ; +C 49 ; WX 556 ; N one ; B 101 0 359 703 ; +C 50 ; WX 556 ; N two ; B 26 0 507 703 ; +C 51 ; WX 556 ; N three ; B 34 -19 522 703 ; +C 52 ; WX 556 ; N four ; B 25 0 523 703 ; +C 53 ; WX 556 ; N five ; B 32 -19 514 688 ; +C 54 ; WX 556 ; N six ; B 38 -19 518 703 ; +C 55 ; WX 556 ; N seven ; B 37 0 523 688 ; +C 56 ; WX 556 ; N eight ; B 38 -19 517 703 ; +C 57 ; WX 556 ; N nine ; B 42 -19 514 703 ; +C 58 ; WX 278 ; N colon ; B 87 0 191 516 ; +C 59 ; WX 278 ; N semicolon ; B 87 -147 191 516 ; +C 60 ; WX 584 ; N less ; B 48 11 536 495 ; +C 61 ; WX 584 ; N equal ; B 39 115 545 390 ; +C 62 ; WX 584 ; N greater ; B 48 11 536 495 ; +C 63 ; WX 556 ; N question ; B 56 0 492 727 ; +C 64 ; WX 1015 ; N at ; B 147 -19 868 737 ; +C 65 ; WX 667 ; N A ; B 14 0 654 718 ; +C 66 ; WX 667 ; N B ; B 74 0 627 718 ; +C 67 ; WX 722 ; N C ; B 44 -19 681 737 ; +C 68 ; WX 722 ; N D ; B 81 0 674 718 ; +C 69 ; WX 667 ; N E ; B 86 0 616 718 ; +C 70 ; WX 611 ; N F ; B 86 0 583 718 ; +C 71 ; WX 778 ; N G ; B 48 -19 704 737 ; +C 72 ; WX 722 ; N H ; B 77 0 646 718 ; +C 73 ; WX 278 ; N I ; B 91 0 188 718 ; +C 74 ; WX 500 ; N J ; B 17 -19 428 718 ; +C 75 ; WX 667 ; N K ; B 76 0 663 718 ; +C 76 ; WX 556 ; N L ; B 76 0 537 718 ; +C 77 ; WX 833 ; N M ; B 73 0 761 718 ; +C 78 ; WX 722 ; N N ; B 76 0 646 718 ; +C 79 ; WX 778 ; N O ; B 39 -19 739 737 ; +C 80 ; WX 667 ; N P ; B 86 0 622 718 ; +C 81 ; WX 778 ; N Q ; B 39 -56 739 737 ; +C 82 ; WX 722 ; N R ; B 88 0 684 718 ; +C 83 ; WX 667 ; N S ; B 49 -19 620 737 ; +C 84 ; WX 611 ; N T ; B 14 0 597 718 ; +C 85 ; WX 722 ; N U ; B 79 -19 644 718 ; +C 86 ; WX 667 ; N V ; B 20 0 647 718 ; +C 87 ; WX 944 ; N W ; B 16 0 928 718 ; +C 88 ; WX 667 ; N X ; B 19 0 648 718 ; +C 89 ; WX 667 ; N Y ; B 14 0 653 718 ; +C 90 ; WX 611 ; N Z ; B 23 0 588 718 ; +C 91 ; WX 278 ; N bracketleft ; B 63 -196 250 722 ; +C 92 ; WX 278 ; N backslash ; B -17 -19 295 737 ; +C 93 ; WX 278 ; N bracketright ; B 28 -196 215 722 ; +C 94 ; WX 469 ; N asciicircum ; B -14 264 483 688 ; +C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ; +C 96 ; WX 222 ; N quoteleft ; B 65 470 169 725 ; +C 97 ; WX 556 ; N a ; B 36 -15 530 538 ; +C 98 ; WX 556 ; N b ; B 58 -15 517 718 ; +C 99 ; WX 500 ; N c ; B 30 -15 477 538 ; +C 100 ; WX 556 ; N d ; B 35 -15 499 718 ; +C 101 ; WX 556 ; N e ; B 40 -15 516 538 ; +C 102 ; WX 278 ; N f ; B 14 0 262 728 ; L i fi ; L l fl ; +C 103 ; WX 556 ; N g ; B 40 -220 499 538 ; +C 104 ; WX 556 ; N h ; B 65 0 491 718 ; +C 105 ; WX 222 ; N i ; B 67 0 155 718 ; +C 106 ; WX 222 ; N j ; B -16 -210 155 718 ; +C 107 ; WX 500 ; N k ; B 67 0 501 718 ; +C 108 ; WX 222 ; N l ; B 67 0 155 718 ; +C 109 ; WX 833 ; N m ; B 65 0 769 538 ; +C 110 ; WX 556 ; N n ; B 65 0 491 538 ; +C 111 ; WX 556 ; N o ; B 35 -14 521 538 ; +C 112 ; WX 556 ; N p ; B 58 -207 517 538 ; +C 113 ; WX 556 ; N q ; B 35 -207 494 538 ; +C 114 ; WX 333 ; N r ; B 77 0 332 538 ; +C 115 ; WX 500 ; N s ; B 32 -15 464 538 ; +C 116 ; WX 278 ; N t ; B 14 -7 257 669 ; +C 117 ; WX 556 ; N u ; B 68 -15 489 523 ; +C 118 ; WX 500 ; N v ; B 8 0 492 523 ; +C 119 ; WX 722 ; N w ; B 14 0 709 523 ; +C 120 ; WX 500 ; N x ; B 11 0 490 523 ; +C 121 ; WX 500 ; N y ; B 11 -214 489 523 ; +C 122 ; WX 500 ; N z ; B 31 0 469 523 ; +C 123 ; WX 334 ; N braceleft ; B 42 -196 292 722 ; +C 124 ; WX 260 ; N bar ; B 94 -225 167 775 ; +C 125 ; WX 334 ; N braceright ; B 42 -196 292 722 ; +C 126 ; WX 584 ; N asciitilde ; B 61 180 523 326 ; +C 161 ; WX 333 ; N exclamdown ; B 118 -195 215 523 ; +C 162 ; WX 556 ; N cent ; B 51 -115 513 623 ; +C 163 ; WX 556 ; N sterling ; B 33 -16 539 718 ; +C 164 ; WX 167 ; N fraction ; B -166 -19 333 703 ; +C 165 ; WX 556 ; N yen ; B 3 0 553 688 ; +C 166 ; WX 556 ; N florin ; B -11 -207 501 737 ; +C 167 ; WX 556 ; N section ; B 43 -191 512 737 ; +C 168 ; WX 556 ; N currency ; B 28 99 528 603 ; +C 169 ; WX 191 ; N quotesingle ; B 59 463 132 718 ; +C 170 ; WX 333 ; N quotedblleft ; B 38 470 307 725 ; +C 171 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ; +C 172 ; WX 333 ; N guilsinglleft ; B 88 108 245 446 ; +C 173 ; WX 333 ; N guilsinglright ; B 88 108 245 446 ; +C 174 ; WX 500 ; N fi ; B 14 0 434 728 ; +C 175 ; WX 500 ; N fl ; B 14 0 432 728 ; +C 177 ; WX 556 ; N endash ; B 0 240 556 313 ; +C 178 ; WX 556 ; N dagger ; B 43 -159 514 718 ; +C 179 ; WX 556 ; N daggerdbl ; B 43 -159 514 718 ; +C 180 ; WX 278 ; N periodcentered ; B 77 190 202 315 ; +C 182 ; WX 537 ; N paragraph ; B 18 -173 497 718 ; +C 183 ; WX 350 ; N bullet ; B 18 202 333 517 ; +C 184 ; WX 222 ; N quotesinglbase ; B 53 -149 157 106 ; +C 185 ; WX 333 ; N quotedblbase ; B 26 -149 295 106 ; +C 186 ; WX 333 ; N quotedblright ; B 26 463 295 718 ; +C 187 ; WX 556 ; N guillemotright ; B 97 108 459 446 ; +C 188 ; WX 1000 ; N ellipsis ; B 115 0 885 106 ; +C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 703 ; +C 191 ; WX 611 ; N questiondown ; B 91 -201 527 525 ; +C 193 ; WX 333 ; N grave ; B 14 593 211 734 ; +C 194 ; WX 333 ; N acute ; B 122 593 319 734 ; +C 195 ; WX 333 ; N circumflex ; B 21 593 312 734 ; +C 196 ; WX 333 ; N tilde ; B -4 606 337 722 ; +C 197 ; WX 333 ; N macron ; B 10 627 323 684 ; +C 198 ; WX 333 ; N breve ; B 13 595 321 731 ; +C 199 ; WX 333 ; N dotaccent ; B 121 604 212 706 ; +C 200 ; WX 333 ; N dieresis ; B 40 604 293 706 ; +C 202 ; WX 333 ; N ring ; B 75 572 259 756 ; +C 203 ; WX 333 ; N cedilla ; B 45 -225 259 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B 31 593 409 734 ; +C 206 ; WX 333 ; N ogonek ; B 73 -225 287 0 ; +C 207 ; WX 333 ; N caron ; B 21 593 312 734 ; +C 208 ; WX 1000 ; N emdash ; B 0 240 1000 313 ; +C 225 ; WX 1000 ; N AE ; B 8 0 951 718 ; +C 227 ; WX 370 ; N ordfeminine ; B 24 405 346 737 ; +C 232 ; WX 556 ; N Lslash ; B -20 0 537 718 ; +C 233 ; WX 778 ; N Oslash ; B 39 -19 740 737 ; +C 234 ; WX 1000 ; N OE ; B 36 -19 965 737 ; +C 235 ; WX 365 ; N ordmasculine ; B 25 405 341 737 ; +C 241 ; WX 889 ; N ae ; B 36 -15 847 538 ; +C 245 ; WX 278 ; N dotlessi ; B 95 0 183 523 ; +C 248 ; WX 222 ; N lslash ; B -20 0 242 718 ; +C 249 ; WX 611 ; N oslash ; B 28 -22 537 545 ; +C 250 ; WX 944 ; N oe ; B 35 -15 902 538 ; +C 251 ; WX 611 ; N germandbls ; B 67 -15 571 728 ; +C -1 ; WX 278 ; N Idieresis ; B 13 0 266 901 ; +C -1 ; WX 556 ; N eacute ; B 40 -15 516 734 ; +C -1 ; WX 556 ; N abreve ; B 36 -15 530 731 ; +C -1 ; WX 556 ; N uhungarumlaut ; B 68 -15 521 734 ; +C -1 ; WX 556 ; N ecaron ; B 40 -15 516 734 ; +C -1 ; WX 667 ; N Ydieresis ; B 14 0 653 901 ; +C -1 ; WX 584 ; N divide ; B 39 -19 545 524 ; +C -1 ; WX 667 ; N Yacute ; B 14 0 653 929 ; +C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ; +C -1 ; WX 556 ; N aacute ; B 36 -15 530 734 ; +C -1 ; WX 722 ; N Ucircumflex ; B 79 -19 644 929 ; +C -1 ; WX 500 ; N yacute ; B 11 -214 489 734 ; +C -1 ; WX 500 ; N scommaaccent ; B 32 -225 464 538 ; +C -1 ; WX 556 ; N ecircumflex ; B 40 -15 516 734 ; +C -1 ; WX 722 ; N Uring ; B 79 -19 644 931 ; +C -1 ; WX 722 ; N Udieresis ; B 79 -19 644 901 ; +C -1 ; WX 556 ; N aogonek ; B 36 -220 547 538 ; +C -1 ; WX 722 ; N Uacute ; B 79 -19 644 929 ; +C -1 ; WX 556 ; N uogonek ; B 68 -225 519 523 ; +C -1 ; WX 667 ; N Edieresis ; B 86 0 616 901 ; +C -1 ; WX 722 ; N Dcroat ; B 0 0 674 718 ; +C -1 ; WX 250 ; N commaaccent ; B 87 -225 181 -40 ; +C -1 ; WX 737 ; N copyright ; B -14 -19 752 737 ; +C -1 ; WX 667 ; N Emacron ; B 86 0 616 879 ; +C -1 ; WX 500 ; N ccaron ; B 30 -15 477 734 ; +C -1 ; WX 556 ; N aring ; B 36 -15 530 756 ; +C -1 ; WX 722 ; N Ncommaaccent ; B 76 -225 646 718 ; +C -1 ; WX 222 ; N lacute ; B 67 0 264 929 ; +C -1 ; WX 556 ; N agrave ; B 36 -15 530 734 ; +C -1 ; WX 611 ; N Tcommaaccent ; B 14 -225 597 718 ; +C -1 ; WX 722 ; N Cacute ; B 44 -19 681 929 ; +C -1 ; WX 556 ; N atilde ; B 36 -15 530 722 ; +C -1 ; WX 667 ; N Edotaccent ; B 86 0 616 901 ; +C -1 ; WX 500 ; N scaron ; B 32 -15 464 734 ; +C -1 ; WX 500 ; N scedilla ; B 32 -225 464 538 ; +C -1 ; WX 278 ; N iacute ; B 95 0 292 734 ; +C -1 ; WX 471 ; N lozenge ; B 10 0 462 728 ; +C -1 ; WX 722 ; N Rcaron ; B 88 0 684 929 ; +C -1 ; WX 778 ; N Gcommaaccent ; B 48 -225 704 737 ; +C -1 ; WX 556 ; N ucircumflex ; B 68 -15 489 734 ; +C -1 ; WX 556 ; N acircumflex ; B 36 -15 530 734 ; +C -1 ; WX 667 ; N Amacron ; B 14 0 654 879 ; +C -1 ; WX 333 ; N rcaron ; B 61 0 352 734 ; +C -1 ; WX 500 ; N ccedilla ; B 30 -225 477 538 ; +C -1 ; WX 611 ; N Zdotaccent ; B 23 0 588 901 ; +C -1 ; WX 667 ; N Thorn ; B 86 0 622 718 ; +C -1 ; WX 778 ; N Omacron ; B 39 -19 739 879 ; +C -1 ; WX 722 ; N Racute ; B 88 0 684 929 ; +C -1 ; WX 667 ; N Sacute ; B 49 -19 620 929 ; +C -1 ; WX 643 ; N dcaron ; B 35 -15 655 718 ; +C -1 ; WX 722 ; N Umacron ; B 79 -19 644 879 ; +C -1 ; WX 556 ; N uring ; B 68 -15 489 756 ; +C -1 ; WX 333 ; N threebaseior ; B 5 270 325 703 ; +C -1 ; WX 778 ; N Ograve ; B 39 -19 739 929 ; +C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ; +C -1 ; WX 667 ; N Abreve ; B 14 0 654 926 ; +C -1 ; WX 584 ; N multiply ; B 39 0 545 506 ; +C -1 ; WX 556 ; N uacute ; B 68 -15 489 734 ; +C -1 ; WX 611 ; N Tcaron ; B 14 0 597 929 ; +C -1 ; WX 476 ; N partialdiff ; B 13 -38 463 714 ; +C -1 ; WX 500 ; N ydieresis ; B 11 -214 489 706 ; +C -1 ; WX 722 ; N Nacute ; B 76 0 646 929 ; +C -1 ; WX 278 ; N icircumflex ; B -6 0 285 734 ; +C -1 ; WX 667 ; N Ecircumflex ; B 86 0 616 929 ; +C -1 ; WX 556 ; N adieresis ; B 36 -15 530 706 ; +C -1 ; WX 556 ; N edieresis ; B 40 -15 516 706 ; +C -1 ; WX 500 ; N cacute ; B 30 -15 477 734 ; +C -1 ; WX 556 ; N nacute ; B 65 0 491 734 ; +C -1 ; WX 556 ; N umacron ; B 68 -15 489 684 ; +C -1 ; WX 722 ; N Ncaron ; B 76 0 646 929 ; +C -1 ; WX 278 ; N Iacute ; B 91 0 292 929 ; +C -1 ; WX 584 ; N plusminus ; B 39 0 545 506 ; +C -1 ; WX 260 ; N brokenbar ; B 94 -150 167 700 ; +C -1 ; WX 737 ; N registered ; B -14 -19 752 737 ; +C -1 ; WX 778 ; N Gbreve ; B 48 -19 704 926 ; +C -1 ; WX 278 ; N Idotaccent ; B 91 0 188 901 ; +C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ; +C -1 ; WX 667 ; N Egrave ; B 86 0 616 929 ; +C -1 ; WX 333 ; N racute ; B 77 0 332 734 ; +C -1 ; WX 556 ; N omacron ; B 35 -14 521 684 ; +C -1 ; WX 611 ; N Zacute ; B 23 0 588 929 ; +C -1 ; WX 611 ; N Zcaron ; B 23 0 588 929 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 523 674 ; +C -1 ; WX 722 ; N Eth ; B 0 0 674 718 ; +C -1 ; WX 722 ; N Ccedilla ; B 44 -225 681 737 ; +C -1 ; WX 222 ; N lcommaaccent ; B 67 -225 167 718 ; +C -1 ; WX 317 ; N tcaron ; B 14 -7 329 808 ; +C -1 ; WX 556 ; N eogonek ; B 40 -225 516 538 ; +C -1 ; WX 722 ; N Uogonek ; B 79 -225 644 718 ; +C -1 ; WX 667 ; N Aacute ; B 14 0 654 929 ; +C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ; +C -1 ; WX 556 ; N egrave ; B 40 -15 516 734 ; +C -1 ; WX 500 ; N zacute ; B 31 0 469 734 ; +C -1 ; WX 222 ; N iogonek ; B -31 -225 183 718 ; +C -1 ; WX 778 ; N Oacute ; B 39 -19 739 929 ; +C -1 ; WX 556 ; N oacute ; B 35 -14 521 734 ; +C -1 ; WX 556 ; N amacron ; B 36 -15 530 684 ; +C -1 ; WX 500 ; N sacute ; B 32 -15 464 734 ; +C -1 ; WX 278 ; N idieresis ; B 13 0 266 706 ; +C -1 ; WX 778 ; N Ocircumflex ; B 39 -19 739 929 ; +C -1 ; WX 722 ; N Ugrave ; B 79 -19 644 929 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 556 ; N thorn ; B 58 -207 517 718 ; +C -1 ; WX 333 ; N twobaseior ; B 4 281 323 703 ; +C -1 ; WX 778 ; N Odieresis ; B 39 -19 739 901 ; +C -1 ; WX 556 ; N mu ; B 68 -207 489 523 ; +C -1 ; WX 278 ; N igrave ; B -13 0 184 734 ; +C -1 ; WX 556 ; N ohungarumlaut ; B 35 -14 521 734 ; +C -1 ; WX 667 ; N Eogonek ; B 86 -220 633 718 ; +C -1 ; WX 556 ; N dcroat ; B 35 -15 550 718 ; +C -1 ; WX 834 ; N threequarters ; B 45 -19 810 703 ; +C -1 ; WX 667 ; N Scedilla ; B 49 -225 620 737 ; +C -1 ; WX 299 ; N lcaron ; B 67 0 311 718 ; +C -1 ; WX 667 ; N Kcommaaccent ; B 76 -225 663 718 ; +C -1 ; WX 556 ; N Lacute ; B 76 0 537 929 ; +C -1 ; WX 1000 ; N trademark ; B 46 306 903 718 ; +C -1 ; WX 556 ; N edotaccent ; B 40 -15 516 706 ; +C -1 ; WX 278 ; N Igrave ; B -13 0 188 929 ; +C -1 ; WX 278 ; N Imacron ; B -17 0 296 879 ; +C -1 ; WX 556 ; N Lcaron ; B 76 0 537 718 ; +C -1 ; WX 834 ; N onehalf ; B 43 -19 773 703 ; +C -1 ; WX 549 ; N lessequal ; B 26 0 523 674 ; +C -1 ; WX 556 ; N ocircumflex ; B 35 -14 521 734 ; +C -1 ; WX 556 ; N ntilde ; B 65 0 491 722 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 79 -19 644 929 ; +C -1 ; WX 667 ; N Eacute ; B 86 0 616 929 ; +C -1 ; WX 556 ; N emacron ; B 40 -15 516 684 ; +C -1 ; WX 556 ; N gbreve ; B 40 -220 499 731 ; +C -1 ; WX 834 ; N onequarter ; B 73 -19 756 703 ; +C -1 ; WX 667 ; N Scaron ; B 49 -19 620 929 ; +C -1 ; WX 667 ; N Scommaaccent ; B 49 -225 620 737 ; +C -1 ; WX 778 ; N Ohungarumlaut ; B 39 -19 739 929 ; +C -1 ; WX 400 ; N degree ; B 54 411 346 703 ; +C -1 ; WX 556 ; N ograve ; B 35 -14 521 734 ; +C -1 ; WX 722 ; N Ccaron ; B 44 -19 681 929 ; +C -1 ; WX 556 ; N ugrave ; B 68 -15 489 734 ; +C -1 ; WX 453 ; N radical ; B -4 -80 458 762 ; +C -1 ; WX 722 ; N Dcaron ; B 81 0 674 929 ; +C -1 ; WX 333 ; N rcommaaccent ; B 77 -225 332 538 ; +C -1 ; WX 722 ; N Ntilde ; B 76 0 646 917 ; +C -1 ; WX 556 ; N otilde ; B 35 -14 521 722 ; +C -1 ; WX 722 ; N Rcommaaccent ; B 88 -225 684 718 ; +C -1 ; WX 556 ; N Lcommaaccent ; B 76 -225 537 718 ; +C -1 ; WX 667 ; N Atilde ; B 14 0 654 917 ; +C -1 ; WX 667 ; N Aogonek ; B 14 -225 654 718 ; +C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ; +C -1 ; WX 778 ; N Otilde ; B 39 -19 739 917 ; +C -1 ; WX 500 ; N zdotaccent ; B 31 0 469 706 ; +C -1 ; WX 667 ; N Ecaron ; B 86 0 616 929 ; +C -1 ; WX 278 ; N Iogonek ; B -3 -225 211 718 ; +C -1 ; WX 500 ; N kcommaaccent ; B 67 -225 501 718 ; +C -1 ; WX 584 ; N minus ; B 39 216 545 289 ; +C -1 ; WX 278 ; N Icircumflex ; B -6 0 285 929 ; +C -1 ; WX 556 ; N ncaron ; B 65 0 491 734 ; +C -1 ; WX 278 ; N tcommaaccent ; B 14 -225 257 669 ; +C -1 ; WX 584 ; N logicalnot ; B 39 108 545 390 ; +C -1 ; WX 556 ; N odieresis ; B 35 -14 521 706 ; +C -1 ; WX 556 ; N udieresis ; B 68 -15 489 706 ; +C -1 ; WX 549 ; N notequal ; B 12 -35 537 551 ; +C -1 ; WX 556 ; N gcommaaccent ; B 40 -220 499 822 ; +C -1 ; WX 556 ; N eth ; B 35 -15 522 737 ; +C -1 ; WX 500 ; N zcaron ; B 31 0 469 734 ; +C -1 ; WX 556 ; N ncommaaccent ; B 65 -225 491 538 ; +C -1 ; WX 333 ; N onebaseior ; B 43 281 222 703 ; +C -1 ; WX 278 ; N imacron ; B 5 0 272 684 ; +C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2705 +KPX A C -30 +KPX A Cacute -30 +KPX A Ccaron -30 +KPX A Ccedilla -30 +KPX A G -30 +KPX A Gbreve -30 +KPX A Gcommaaccent -30 +KPX A O -30 +KPX A Oacute -30 +KPX A Ocircumflex -30 +KPX A Odieresis -30 +KPX A Ograve -30 +KPX A Ohungarumlaut -30 +KPX A Omacron -30 +KPX A Oslash -30 +KPX A Otilde -30 +KPX A Q -30 +KPX A T -120 +KPX A Tcaron -120 +KPX A Tcommaaccent -120 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -70 +KPX A W -50 +KPX A Y -100 +KPX A Yacute -100 +KPX A Ydieresis -100 +KPX A u -30 +KPX A uacute -30 +KPX A ucircumflex -30 +KPX A udieresis -30 +KPX A ugrave -30 +KPX A uhungarumlaut -30 +KPX A umacron -30 +KPX A uogonek -30 +KPX A uring -30 +KPX A v -40 +KPX A w -40 +KPX A y -40 +KPX A yacute -40 +KPX A ydieresis -40 +KPX Aacute C -30 +KPX Aacute Cacute -30 +KPX Aacute Ccaron -30 +KPX Aacute Ccedilla -30 +KPX Aacute G -30 +KPX Aacute Gbreve -30 +KPX Aacute Gcommaaccent -30 +KPX Aacute O -30 +KPX Aacute Oacute -30 +KPX Aacute Ocircumflex -30 +KPX Aacute Odieresis -30 +KPX Aacute Ograve -30 +KPX Aacute Ohungarumlaut -30 +KPX Aacute Omacron -30 +KPX Aacute Oslash -30 +KPX Aacute Otilde -30 +KPX Aacute Q -30 +KPX Aacute T -120 +KPX Aacute Tcaron -120 +KPX Aacute Tcommaaccent -120 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -70 +KPX Aacute W -50 +KPX Aacute Y -100 +KPX Aacute Yacute -100 +KPX Aacute Ydieresis -100 +KPX Aacute u -30 +KPX Aacute uacute -30 +KPX Aacute ucircumflex -30 +KPX Aacute udieresis -30 +KPX Aacute ugrave -30 +KPX Aacute uhungarumlaut -30 +KPX Aacute umacron -30 +KPX Aacute uogonek -30 +KPX Aacute uring -30 +KPX Aacute v -40 +KPX Aacute w -40 +KPX Aacute y -40 +KPX Aacute yacute -40 +KPX Aacute ydieresis -40 +KPX Abreve C -30 +KPX Abreve Cacute -30 +KPX Abreve Ccaron -30 +KPX Abreve Ccedilla -30 +KPX Abreve G -30 +KPX Abreve Gbreve -30 +KPX Abreve Gcommaaccent -30 +KPX Abreve O -30 +KPX Abreve Oacute -30 +KPX Abreve Ocircumflex -30 +KPX Abreve Odieresis -30 +KPX Abreve Ograve -30 +KPX Abreve Ohungarumlaut -30 +KPX Abreve Omacron -30 +KPX Abreve Oslash -30 +KPX Abreve Otilde -30 +KPX Abreve Q -30 +KPX Abreve T -120 +KPX Abreve Tcaron -120 +KPX Abreve Tcommaaccent -120 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -70 +KPX Abreve W -50 +KPX Abreve Y -100 +KPX Abreve Yacute -100 +KPX Abreve Ydieresis -100 +KPX Abreve u -30 +KPX Abreve uacute -30 +KPX Abreve ucircumflex -30 +KPX Abreve udieresis -30 +KPX Abreve ugrave -30 +KPX Abreve uhungarumlaut -30 +KPX Abreve umacron -30 +KPX Abreve uogonek -30 +KPX Abreve uring -30 +KPX Abreve v -40 +KPX Abreve w -40 +KPX Abreve y -40 +KPX Abreve yacute -40 +KPX Abreve ydieresis -40 +KPX Acircumflex C -30 +KPX Acircumflex Cacute -30 +KPX Acircumflex Ccaron -30 +KPX Acircumflex Ccedilla -30 +KPX Acircumflex G -30 +KPX Acircumflex Gbreve -30 +KPX Acircumflex Gcommaaccent -30 +KPX Acircumflex O -30 +KPX Acircumflex Oacute -30 +KPX Acircumflex Ocircumflex -30 +KPX Acircumflex Odieresis -30 +KPX Acircumflex Ograve -30 +KPX Acircumflex Ohungarumlaut -30 +KPX Acircumflex Omacron -30 +KPX Acircumflex Oslash -30 +KPX Acircumflex Otilde -30 +KPX Acircumflex Q -30 +KPX Acircumflex T -120 +KPX Acircumflex Tcaron -120 +KPX Acircumflex Tcommaaccent -120 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -70 +KPX Acircumflex W -50 +KPX Acircumflex Y -100 +KPX Acircumflex Yacute -100 +KPX Acircumflex Ydieresis -100 +KPX Acircumflex u -30 +KPX Acircumflex uacute -30 +KPX Acircumflex ucircumflex -30 +KPX Acircumflex udieresis -30 +KPX Acircumflex ugrave -30 +KPX Acircumflex uhungarumlaut -30 +KPX Acircumflex umacron -30 +KPX Acircumflex uogonek -30 +KPX Acircumflex uring -30 +KPX Acircumflex v -40 +KPX Acircumflex w -40 +KPX Acircumflex y -40 +KPX Acircumflex yacute -40 +KPX Acircumflex ydieresis -40 +KPX Adieresis C -30 +KPX Adieresis Cacute -30 +KPX Adieresis Ccaron -30 +KPX Adieresis Ccedilla -30 +KPX Adieresis G -30 +KPX Adieresis Gbreve -30 +KPX Adieresis Gcommaaccent -30 +KPX Adieresis O -30 +KPX Adieresis Oacute -30 +KPX Adieresis Ocircumflex -30 +KPX Adieresis Odieresis -30 +KPX Adieresis Ograve -30 +KPX Adieresis Ohungarumlaut -30 +KPX Adieresis Omacron -30 +KPX Adieresis Oslash -30 +KPX Adieresis Otilde -30 +KPX Adieresis Q -30 +KPX Adieresis T -120 +KPX Adieresis Tcaron -120 +KPX Adieresis Tcommaaccent -120 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -70 +KPX Adieresis W -50 +KPX Adieresis Y -100 +KPX Adieresis Yacute -100 +KPX Adieresis Ydieresis -100 +KPX Adieresis u -30 +KPX Adieresis uacute -30 +KPX Adieresis ucircumflex -30 +KPX Adieresis udieresis -30 +KPX Adieresis ugrave -30 +KPX Adieresis uhungarumlaut -30 +KPX Adieresis umacron -30 +KPX Adieresis uogonek -30 +KPX Adieresis uring -30 +KPX Adieresis v -40 +KPX Adieresis w -40 +KPX Adieresis y -40 +KPX Adieresis yacute -40 +KPX Adieresis ydieresis -40 +KPX Agrave C -30 +KPX Agrave Cacute -30 +KPX Agrave Ccaron -30 +KPX Agrave Ccedilla -30 +KPX Agrave G -30 +KPX Agrave Gbreve -30 +KPX Agrave Gcommaaccent -30 +KPX Agrave O -30 +KPX Agrave Oacute -30 +KPX Agrave Ocircumflex -30 +KPX Agrave Odieresis -30 +KPX Agrave Ograve -30 +KPX Agrave Ohungarumlaut -30 +KPX Agrave Omacron -30 +KPX Agrave Oslash -30 +KPX Agrave Otilde -30 +KPX Agrave Q -30 +KPX Agrave T -120 +KPX Agrave Tcaron -120 +KPX Agrave Tcommaaccent -120 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -70 +KPX Agrave W -50 +KPX Agrave Y -100 +KPX Agrave Yacute -100 +KPX Agrave Ydieresis -100 +KPX Agrave u -30 +KPX Agrave uacute -30 +KPX Agrave ucircumflex -30 +KPX Agrave udieresis -30 +KPX Agrave ugrave -30 +KPX Agrave uhungarumlaut -30 +KPX Agrave umacron -30 +KPX Agrave uogonek -30 +KPX Agrave uring -30 +KPX Agrave v -40 +KPX Agrave w -40 +KPX Agrave y -40 +KPX Agrave yacute -40 +KPX Agrave ydieresis -40 +KPX Amacron C -30 +KPX Amacron Cacute -30 +KPX Amacron Ccaron -30 +KPX Amacron Ccedilla -30 +KPX Amacron G -30 +KPX Amacron Gbreve -30 +KPX Amacron Gcommaaccent -30 +KPX Amacron O -30 +KPX Amacron Oacute -30 +KPX Amacron Ocircumflex -30 +KPX Amacron Odieresis -30 +KPX Amacron Ograve -30 +KPX Amacron Ohungarumlaut -30 +KPX Amacron Omacron -30 +KPX Amacron Oslash -30 +KPX Amacron Otilde -30 +KPX Amacron Q -30 +KPX Amacron T -120 +KPX Amacron Tcaron -120 +KPX Amacron Tcommaaccent -120 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -70 +KPX Amacron W -50 +KPX Amacron Y -100 +KPX Amacron Yacute -100 +KPX Amacron Ydieresis -100 +KPX Amacron u -30 +KPX Amacron uacute -30 +KPX Amacron ucircumflex -30 +KPX Amacron udieresis -30 +KPX Amacron ugrave -30 +KPX Amacron uhungarumlaut -30 +KPX Amacron umacron -30 +KPX Amacron uogonek -30 +KPX Amacron uring -30 +KPX Amacron v -40 +KPX Amacron w -40 +KPX Amacron y -40 +KPX Amacron yacute -40 +KPX Amacron ydieresis -40 +KPX Aogonek C -30 +KPX Aogonek Cacute -30 +KPX Aogonek Ccaron -30 +KPX Aogonek Ccedilla -30 +KPX Aogonek G -30 +KPX Aogonek Gbreve -30 +KPX Aogonek Gcommaaccent -30 +KPX Aogonek O -30 +KPX Aogonek Oacute -30 +KPX Aogonek Ocircumflex -30 +KPX Aogonek Odieresis -30 +KPX Aogonek Ograve -30 +KPX Aogonek Ohungarumlaut -30 +KPX Aogonek Omacron -30 +KPX Aogonek Oslash -30 +KPX Aogonek Otilde -30 +KPX Aogonek Q -30 +KPX Aogonek T -120 +KPX Aogonek Tcaron -120 +KPX Aogonek Tcommaaccent -120 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -70 +KPX Aogonek W -50 +KPX Aogonek Y -100 +KPX Aogonek Yacute -100 +KPX Aogonek Ydieresis -100 +KPX Aogonek u -30 +KPX Aogonek uacute -30 +KPX Aogonek ucircumflex -30 +KPX Aogonek udieresis -30 +KPX Aogonek ugrave -30 +KPX Aogonek uhungarumlaut -30 +KPX Aogonek umacron -30 +KPX Aogonek uogonek -30 +KPX Aogonek uring -30 +KPX Aogonek v -40 +KPX Aogonek w -40 +KPX Aogonek y -40 +KPX Aogonek yacute -40 +KPX Aogonek ydieresis -40 +KPX Aring C -30 +KPX Aring Cacute -30 +KPX Aring Ccaron -30 +KPX Aring Ccedilla -30 +KPX Aring G -30 +KPX Aring Gbreve -30 +KPX Aring Gcommaaccent -30 +KPX Aring O -30 +KPX Aring Oacute -30 +KPX Aring Ocircumflex -30 +KPX Aring Odieresis -30 +KPX Aring Ograve -30 +KPX Aring Ohungarumlaut -30 +KPX Aring Omacron -30 +KPX Aring Oslash -30 +KPX Aring Otilde -30 +KPX Aring Q -30 +KPX Aring T -120 +KPX Aring Tcaron -120 +KPX Aring Tcommaaccent -120 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -70 +KPX Aring W -50 +KPX Aring Y -100 +KPX Aring Yacute -100 +KPX Aring Ydieresis -100 +KPX Aring u -30 +KPX Aring uacute -30 +KPX Aring ucircumflex -30 +KPX Aring udieresis -30 +KPX Aring ugrave -30 +KPX Aring uhungarumlaut -30 +KPX Aring umacron -30 +KPX Aring uogonek -30 +KPX Aring uring -30 +KPX Aring v -40 +KPX Aring w -40 +KPX Aring y -40 +KPX Aring yacute -40 +KPX Aring ydieresis -40 +KPX Atilde C -30 +KPX Atilde Cacute -30 +KPX Atilde Ccaron -30 +KPX Atilde Ccedilla -30 +KPX Atilde G -30 +KPX Atilde Gbreve -30 +KPX Atilde Gcommaaccent -30 +KPX Atilde O -30 +KPX Atilde Oacute -30 +KPX Atilde Ocircumflex -30 +KPX Atilde Odieresis -30 +KPX Atilde Ograve -30 +KPX Atilde Ohungarumlaut -30 +KPX Atilde Omacron -30 +KPX Atilde Oslash -30 +KPX Atilde Otilde -30 +KPX Atilde Q -30 +KPX Atilde T -120 +KPX Atilde Tcaron -120 +KPX Atilde Tcommaaccent -120 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -70 +KPX Atilde W -50 +KPX Atilde Y -100 +KPX Atilde Yacute -100 +KPX Atilde Ydieresis -100 +KPX Atilde u -30 +KPX Atilde uacute -30 +KPX Atilde ucircumflex -30 +KPX Atilde udieresis -30 +KPX Atilde ugrave -30 +KPX Atilde uhungarumlaut -30 +KPX Atilde umacron -30 +KPX Atilde uogonek -30 +KPX Atilde uring -30 +KPX Atilde v -40 +KPX Atilde w -40 +KPX Atilde y -40 +KPX Atilde yacute -40 +KPX Atilde ydieresis -40 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX B comma -20 +KPX B period -20 +KPX C comma -30 +KPX C period -30 +KPX Cacute comma -30 +KPX Cacute period -30 +KPX Ccaron comma -30 +KPX Ccaron period -30 +KPX Ccedilla comma -30 +KPX Ccedilla period -30 +KPX D A -40 +KPX D Aacute -40 +KPX D Abreve -40 +KPX D Acircumflex -40 +KPX D Adieresis -40 +KPX D Agrave -40 +KPX D Amacron -40 +KPX D Aogonek -40 +KPX D Aring -40 +KPX D Atilde -40 +KPX D V -70 +KPX D W -40 +KPX D Y -90 +KPX D Yacute -90 +KPX D Ydieresis -90 +KPX D comma -70 +KPX D period -70 +KPX Dcaron A -40 +KPX Dcaron Aacute -40 +KPX Dcaron Abreve -40 +KPX Dcaron Acircumflex -40 +KPX Dcaron Adieresis -40 +KPX Dcaron Agrave -40 +KPX Dcaron Amacron -40 +KPX Dcaron Aogonek -40 +KPX Dcaron Aring -40 +KPX Dcaron Atilde -40 +KPX Dcaron V -70 +KPX Dcaron W -40 +KPX Dcaron Y -90 +KPX Dcaron Yacute -90 +KPX Dcaron Ydieresis -90 +KPX Dcaron comma -70 +KPX Dcaron period -70 +KPX Dcroat A -40 +KPX Dcroat Aacute -40 +KPX Dcroat Abreve -40 +KPX Dcroat Acircumflex -40 +KPX Dcroat Adieresis -40 +KPX Dcroat Agrave -40 +KPX Dcroat Amacron -40 +KPX Dcroat Aogonek -40 +KPX Dcroat Aring -40 +KPX Dcroat Atilde -40 +KPX Dcroat V -70 +KPX Dcroat W -40 +KPX Dcroat Y -90 +KPX Dcroat Yacute -90 +KPX Dcroat Ydieresis -90 +KPX Dcroat comma -70 +KPX Dcroat period -70 +KPX F A -80 +KPX F Aacute -80 +KPX F Abreve -80 +KPX F Acircumflex -80 +KPX F Adieresis -80 +KPX F Agrave -80 +KPX F Amacron -80 +KPX F Aogonek -80 +KPX F Aring -80 +KPX F Atilde -80 +KPX F a -50 +KPX F aacute -50 +KPX F abreve -50 +KPX F acircumflex -50 +KPX F adieresis -50 +KPX F agrave -50 +KPX F amacron -50 +KPX F aogonek -50 +KPX F aring -50 +KPX F atilde -50 +KPX F comma -150 +KPX F e -30 +KPX F eacute -30 +KPX F ecaron -30 +KPX F ecircumflex -30 +KPX F edieresis -30 +KPX F edotaccent -30 +KPX F egrave -30 +KPX F emacron -30 +KPX F eogonek -30 +KPX F o -30 +KPX F oacute -30 +KPX F ocircumflex -30 +KPX F odieresis -30 +KPX F ograve -30 +KPX F ohungarumlaut -30 +KPX F omacron -30 +KPX F oslash -30 +KPX F otilde -30 +KPX F period -150 +KPX F r -45 +KPX F racute -45 +KPX F rcaron -45 +KPX F rcommaaccent -45 +KPX J A -20 +KPX J Aacute -20 +KPX J Abreve -20 +KPX J Acircumflex -20 +KPX J Adieresis -20 +KPX J Agrave -20 +KPX J Amacron -20 +KPX J Aogonek -20 +KPX J Aring -20 +KPX J Atilde -20 +KPX J a -20 +KPX J aacute -20 +KPX J abreve -20 +KPX J acircumflex -20 +KPX J adieresis -20 +KPX J agrave -20 +KPX J amacron -20 +KPX J aogonek -20 +KPX J aring -20 +KPX J atilde -20 +KPX J comma -30 +KPX J period -30 +KPX J u -20 +KPX J uacute -20 +KPX J ucircumflex -20 +KPX J udieresis -20 +KPX J ugrave -20 +KPX J uhungarumlaut -20 +KPX J umacron -20 +KPX J uogonek -20 +KPX J uring -20 +KPX K O -50 +KPX K Oacute -50 +KPX K Ocircumflex -50 +KPX K Odieresis -50 +KPX K Ograve -50 +KPX K Ohungarumlaut -50 +KPX K Omacron -50 +KPX K Oslash -50 +KPX K Otilde -50 +KPX K e -40 +KPX K eacute -40 +KPX K ecaron -40 +KPX K ecircumflex -40 +KPX K edieresis -40 +KPX K edotaccent -40 +KPX K egrave -40 +KPX K emacron -40 +KPX K eogonek -40 +KPX K o -40 +KPX K oacute -40 +KPX K ocircumflex -40 +KPX K odieresis -40 +KPX K ograve -40 +KPX K ohungarumlaut -40 +KPX K omacron -40 +KPX K oslash -40 +KPX K otilde -40 +KPX K u -30 +KPX K uacute -30 +KPX K ucircumflex -30 +KPX K udieresis -30 +KPX K ugrave -30 +KPX K uhungarumlaut -30 +KPX K umacron -30 +KPX K uogonek -30 +KPX K uring -30 +KPX K y -50 +KPX K yacute -50 +KPX K ydieresis -50 +KPX Kcommaaccent O -50 +KPX Kcommaaccent Oacute -50 +KPX Kcommaaccent Ocircumflex -50 +KPX Kcommaaccent Odieresis -50 +KPX Kcommaaccent Ograve -50 +KPX Kcommaaccent Ohungarumlaut -50 +KPX Kcommaaccent Omacron -50 +KPX Kcommaaccent Oslash -50 +KPX Kcommaaccent Otilde -50 +KPX Kcommaaccent e -40 +KPX Kcommaaccent eacute -40 +KPX Kcommaaccent ecaron -40 +KPX Kcommaaccent ecircumflex -40 +KPX Kcommaaccent edieresis -40 +KPX Kcommaaccent edotaccent -40 +KPX Kcommaaccent egrave -40 +KPX Kcommaaccent emacron -40 +KPX Kcommaaccent eogonek -40 +KPX Kcommaaccent o -40 +KPX Kcommaaccent oacute -40 +KPX Kcommaaccent ocircumflex -40 +KPX Kcommaaccent odieresis -40 +KPX Kcommaaccent ograve -40 +KPX Kcommaaccent ohungarumlaut -40 +KPX Kcommaaccent omacron -40 +KPX Kcommaaccent oslash -40 +KPX Kcommaaccent otilde -40 +KPX Kcommaaccent u -30 +KPX Kcommaaccent uacute -30 +KPX Kcommaaccent ucircumflex -30 +KPX Kcommaaccent udieresis -30 +KPX Kcommaaccent ugrave -30 +KPX Kcommaaccent uhungarumlaut -30 +KPX Kcommaaccent umacron -30 +KPX Kcommaaccent uogonek -30 +KPX Kcommaaccent uring -30 +KPX Kcommaaccent y -50 +KPX Kcommaaccent yacute -50 +KPX Kcommaaccent ydieresis -50 +KPX L T -110 +KPX L Tcaron -110 +KPX L Tcommaaccent -110 +KPX L V -110 +KPX L W -70 +KPX L Y -140 +KPX L Yacute -140 +KPX L Ydieresis -140 +KPX L quotedblright -140 +KPX L quoteright -160 +KPX L y -30 +KPX L yacute -30 +KPX L ydieresis -30 +KPX Lacute T -110 +KPX Lacute Tcaron -110 +KPX Lacute Tcommaaccent -110 +KPX Lacute V -110 +KPX Lacute W -70 +KPX Lacute Y -140 +KPX Lacute Yacute -140 +KPX Lacute Ydieresis -140 +KPX Lacute quotedblright -140 +KPX Lacute quoteright -160 +KPX Lacute y -30 +KPX Lacute yacute -30 +KPX Lacute ydieresis -30 +KPX Lcaron T -110 +KPX Lcaron Tcaron -110 +KPX Lcaron Tcommaaccent -110 +KPX Lcaron V -110 +KPX Lcaron W -70 +KPX Lcaron Y -140 +KPX Lcaron Yacute -140 +KPX Lcaron Ydieresis -140 +KPX Lcaron quotedblright -140 +KPX Lcaron quoteright -160 +KPX Lcaron y -30 +KPX Lcaron yacute -30 +KPX Lcaron ydieresis -30 +KPX Lcommaaccent T -110 +KPX Lcommaaccent Tcaron -110 +KPX Lcommaaccent Tcommaaccent -110 +KPX Lcommaaccent V -110 +KPX Lcommaaccent W -70 +KPX Lcommaaccent Y -140 +KPX Lcommaaccent Yacute -140 +KPX Lcommaaccent Ydieresis -140 +KPX Lcommaaccent quotedblright -140 +KPX Lcommaaccent quoteright -160 +KPX Lcommaaccent y -30 +KPX Lcommaaccent yacute -30 +KPX Lcommaaccent ydieresis -30 +KPX Lslash T -110 +KPX Lslash Tcaron -110 +KPX Lslash Tcommaaccent -110 +KPX Lslash V -110 +KPX Lslash W -70 +KPX Lslash Y -140 +KPX Lslash Yacute -140 +KPX Lslash Ydieresis -140 +KPX Lslash quotedblright -140 +KPX Lslash quoteright -160 +KPX Lslash y -30 +KPX Lslash yacute -30 +KPX Lslash ydieresis -30 +KPX O A -20 +KPX O Aacute -20 +KPX O Abreve -20 +KPX O Acircumflex -20 +KPX O Adieresis -20 +KPX O Agrave -20 +KPX O Amacron -20 +KPX O Aogonek -20 +KPX O Aring -20 +KPX O Atilde -20 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -30 +KPX O X -60 +KPX O Y -70 +KPX O Yacute -70 +KPX O Ydieresis -70 +KPX O comma -40 +KPX O period -40 +KPX Oacute A -20 +KPX Oacute Aacute -20 +KPX Oacute Abreve -20 +KPX Oacute Acircumflex -20 +KPX Oacute Adieresis -20 +KPX Oacute Agrave -20 +KPX Oacute Amacron -20 +KPX Oacute Aogonek -20 +KPX Oacute Aring -20 +KPX Oacute Atilde -20 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -30 +KPX Oacute X -60 +KPX Oacute Y -70 +KPX Oacute Yacute -70 +KPX Oacute Ydieresis -70 +KPX Oacute comma -40 +KPX Oacute period -40 +KPX Ocircumflex A -20 +KPX Ocircumflex Aacute -20 +KPX Ocircumflex Abreve -20 +KPX Ocircumflex Acircumflex -20 +KPX Ocircumflex Adieresis -20 +KPX Ocircumflex Agrave -20 +KPX Ocircumflex Amacron -20 +KPX Ocircumflex Aogonek -20 +KPX Ocircumflex Aring -20 +KPX Ocircumflex Atilde -20 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -30 +KPX Ocircumflex X -60 +KPX Ocircumflex Y -70 +KPX Ocircumflex Yacute -70 +KPX Ocircumflex Ydieresis -70 +KPX Ocircumflex comma -40 +KPX Ocircumflex period -40 +KPX Odieresis A -20 +KPX Odieresis Aacute -20 +KPX Odieresis Abreve -20 +KPX Odieresis Acircumflex -20 +KPX Odieresis Adieresis -20 +KPX Odieresis Agrave -20 +KPX Odieresis Amacron -20 +KPX Odieresis Aogonek -20 +KPX Odieresis Aring -20 +KPX Odieresis Atilde -20 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -30 +KPX Odieresis X -60 +KPX Odieresis Y -70 +KPX Odieresis Yacute -70 +KPX Odieresis Ydieresis -70 +KPX Odieresis comma -40 +KPX Odieresis period -40 +KPX Ograve A -20 +KPX Ograve Aacute -20 +KPX Ograve Abreve -20 +KPX Ograve Acircumflex -20 +KPX Ograve Adieresis -20 +KPX Ograve Agrave -20 +KPX Ograve Amacron -20 +KPX Ograve Aogonek -20 +KPX Ograve Aring -20 +KPX Ograve Atilde -20 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -30 +KPX Ograve X -60 +KPX Ograve Y -70 +KPX Ograve Yacute -70 +KPX Ograve Ydieresis -70 +KPX Ograve comma -40 +KPX Ograve period -40 +KPX Ohungarumlaut A -20 +KPX Ohungarumlaut Aacute -20 +KPX Ohungarumlaut Abreve -20 +KPX Ohungarumlaut Acircumflex -20 +KPX Ohungarumlaut Adieresis -20 +KPX Ohungarumlaut Agrave -20 +KPX Ohungarumlaut Amacron -20 +KPX Ohungarumlaut Aogonek -20 +KPX Ohungarumlaut Aring -20 +KPX Ohungarumlaut Atilde -20 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -30 +KPX Ohungarumlaut X -60 +KPX Ohungarumlaut Y -70 +KPX Ohungarumlaut Yacute -70 +KPX Ohungarumlaut Ydieresis -70 +KPX Ohungarumlaut comma -40 +KPX Ohungarumlaut period -40 +KPX Omacron A -20 +KPX Omacron Aacute -20 +KPX Omacron Abreve -20 +KPX Omacron Acircumflex -20 +KPX Omacron Adieresis -20 +KPX Omacron Agrave -20 +KPX Omacron Amacron -20 +KPX Omacron Aogonek -20 +KPX Omacron Aring -20 +KPX Omacron Atilde -20 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -30 +KPX Omacron X -60 +KPX Omacron Y -70 +KPX Omacron Yacute -70 +KPX Omacron Ydieresis -70 +KPX Omacron comma -40 +KPX Omacron period -40 +KPX Oslash A -20 +KPX Oslash Aacute -20 +KPX Oslash Abreve -20 +KPX Oslash Acircumflex -20 +KPX Oslash Adieresis -20 +KPX Oslash Agrave -20 +KPX Oslash Amacron -20 +KPX Oslash Aogonek -20 +KPX Oslash Aring -20 +KPX Oslash Atilde -20 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -30 +KPX Oslash X -60 +KPX Oslash Y -70 +KPX Oslash Yacute -70 +KPX Oslash Ydieresis -70 +KPX Oslash comma -40 +KPX Oslash period -40 +KPX Otilde A -20 +KPX Otilde Aacute -20 +KPX Otilde Abreve -20 +KPX Otilde Acircumflex -20 +KPX Otilde Adieresis -20 +KPX Otilde Agrave -20 +KPX Otilde Amacron -20 +KPX Otilde Aogonek -20 +KPX Otilde Aring -20 +KPX Otilde Atilde -20 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -30 +KPX Otilde X -60 +KPX Otilde Y -70 +KPX Otilde Yacute -70 +KPX Otilde Ydieresis -70 +KPX Otilde comma -40 +KPX Otilde period -40 +KPX P A -120 +KPX P Aacute -120 +KPX P Abreve -120 +KPX P Acircumflex -120 +KPX P Adieresis -120 +KPX P Agrave -120 +KPX P Amacron -120 +KPX P Aogonek -120 +KPX P Aring -120 +KPX P Atilde -120 +KPX P a -40 +KPX P aacute -40 +KPX P abreve -40 +KPX P acircumflex -40 +KPX P adieresis -40 +KPX P agrave -40 +KPX P amacron -40 +KPX P aogonek -40 +KPX P aring -40 +KPX P atilde -40 +KPX P comma -180 +KPX P e -50 +KPX P eacute -50 +KPX P ecaron -50 +KPX P ecircumflex -50 +KPX P edieresis -50 +KPX P edotaccent -50 +KPX P egrave -50 +KPX P emacron -50 +KPX P eogonek -50 +KPX P o -50 +KPX P oacute -50 +KPX P ocircumflex -50 +KPX P odieresis -50 +KPX P ograve -50 +KPX P ohungarumlaut -50 +KPX P omacron -50 +KPX P oslash -50 +KPX P otilde -50 +KPX P period -180 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX R O -20 +KPX R Oacute -20 +KPX R Ocircumflex -20 +KPX R Odieresis -20 +KPX R Ograve -20 +KPX R Ohungarumlaut -20 +KPX R Omacron -20 +KPX R Oslash -20 +KPX R Otilde -20 +KPX R T -30 +KPX R Tcaron -30 +KPX R Tcommaaccent -30 +KPX R U -40 +KPX R Uacute -40 +KPX R Ucircumflex -40 +KPX R Udieresis -40 +KPX R Ugrave -40 +KPX R Uhungarumlaut -40 +KPX R Umacron -40 +KPX R Uogonek -40 +KPX R Uring -40 +KPX R V -50 +KPX R W -30 +KPX R Y -50 +KPX R Yacute -50 +KPX R Ydieresis -50 +KPX Racute O -20 +KPX Racute Oacute -20 +KPX Racute Ocircumflex -20 +KPX Racute Odieresis -20 +KPX Racute Ograve -20 +KPX Racute Ohungarumlaut -20 +KPX Racute Omacron -20 +KPX Racute Oslash -20 +KPX Racute Otilde -20 +KPX Racute T -30 +KPX Racute Tcaron -30 +KPX Racute Tcommaaccent -30 +KPX Racute U -40 +KPX Racute Uacute -40 +KPX Racute Ucircumflex -40 +KPX Racute Udieresis -40 +KPX Racute Ugrave -40 +KPX Racute Uhungarumlaut -40 +KPX Racute Umacron -40 +KPX Racute Uogonek -40 +KPX Racute Uring -40 +KPX Racute V -50 +KPX Racute W -30 +KPX Racute Y -50 +KPX Racute Yacute -50 +KPX Racute Ydieresis -50 +KPX Rcaron O -20 +KPX Rcaron Oacute -20 +KPX Rcaron Ocircumflex -20 +KPX Rcaron Odieresis -20 +KPX Rcaron Ograve -20 +KPX Rcaron Ohungarumlaut -20 +KPX Rcaron Omacron -20 +KPX Rcaron Oslash -20 +KPX Rcaron Otilde -20 +KPX Rcaron T -30 +KPX Rcaron Tcaron -30 +KPX Rcaron Tcommaaccent -30 +KPX Rcaron U -40 +KPX Rcaron Uacute -40 +KPX Rcaron Ucircumflex -40 +KPX Rcaron Udieresis -40 +KPX Rcaron Ugrave -40 +KPX Rcaron Uhungarumlaut -40 +KPX Rcaron Umacron -40 +KPX Rcaron Uogonek -40 +KPX Rcaron Uring -40 +KPX Rcaron V -50 +KPX Rcaron W -30 +KPX Rcaron Y -50 +KPX Rcaron Yacute -50 +KPX Rcaron Ydieresis -50 +KPX Rcommaaccent O -20 +KPX Rcommaaccent Oacute -20 +KPX Rcommaaccent Ocircumflex -20 +KPX Rcommaaccent Odieresis -20 +KPX Rcommaaccent Ograve -20 +KPX Rcommaaccent Ohungarumlaut -20 +KPX Rcommaaccent Omacron -20 +KPX Rcommaaccent Oslash -20 +KPX Rcommaaccent Otilde -20 +KPX Rcommaaccent T -30 +KPX Rcommaaccent Tcaron -30 +KPX Rcommaaccent Tcommaaccent -30 +KPX Rcommaaccent U -40 +KPX Rcommaaccent Uacute -40 +KPX Rcommaaccent Ucircumflex -40 +KPX Rcommaaccent Udieresis -40 +KPX Rcommaaccent Ugrave -40 +KPX Rcommaaccent Uhungarumlaut -40 +KPX Rcommaaccent Umacron -40 +KPX Rcommaaccent Uogonek -40 +KPX Rcommaaccent Uring -40 +KPX Rcommaaccent V -50 +KPX Rcommaaccent W -30 +KPX Rcommaaccent Y -50 +KPX Rcommaaccent Yacute -50 +KPX Rcommaaccent Ydieresis -50 +KPX S comma -20 +KPX S period -20 +KPX Sacute comma -20 +KPX Sacute period -20 +KPX Scaron comma -20 +KPX Scaron period -20 +KPX Scedilla comma -20 +KPX Scedilla period -20 +KPX Scommaaccent comma -20 +KPX Scommaaccent period -20 +KPX T A -120 +KPX T Aacute -120 +KPX T Abreve -120 +KPX T Acircumflex -120 +KPX T Adieresis -120 +KPX T Agrave -120 +KPX T Amacron -120 +KPX T Aogonek -120 +KPX T Aring -120 +KPX T Atilde -120 +KPX T O -40 +KPX T Oacute -40 +KPX T Ocircumflex -40 +KPX T Odieresis -40 +KPX T Ograve -40 +KPX T Ohungarumlaut -40 +KPX T Omacron -40 +KPX T Oslash -40 +KPX T Otilde -40 +KPX T a -120 +KPX T aacute -120 +KPX T abreve -60 +KPX T acircumflex -120 +KPX T adieresis -120 +KPX T agrave -120 +KPX T amacron -60 +KPX T aogonek -120 +KPX T aring -120 +KPX T atilde -60 +KPX T colon -20 +KPX T comma -120 +KPX T e -120 +KPX T eacute -120 +KPX T ecaron -120 +KPX T ecircumflex -120 +KPX T edieresis -120 +KPX T edotaccent -120 +KPX T egrave -60 +KPX T emacron -60 +KPX T eogonek -120 +KPX T hyphen -140 +KPX T o -120 +KPX T oacute -120 +KPX T ocircumflex -120 +KPX T odieresis -120 +KPX T ograve -120 +KPX T ohungarumlaut -120 +KPX T omacron -60 +KPX T oslash -120 +KPX T otilde -60 +KPX T period -120 +KPX T r -120 +KPX T racute -120 +KPX T rcaron -120 +KPX T rcommaaccent -120 +KPX T semicolon -20 +KPX T u -120 +KPX T uacute -120 +KPX T ucircumflex -120 +KPX T udieresis -120 +KPX T ugrave -120 +KPX T uhungarumlaut -120 +KPX T umacron -60 +KPX T uogonek -120 +KPX T uring -120 +KPX T w -120 +KPX T y -120 +KPX T yacute -120 +KPX T ydieresis -60 +KPX Tcaron A -120 +KPX Tcaron Aacute -120 +KPX Tcaron Abreve -120 +KPX Tcaron Acircumflex -120 +KPX Tcaron Adieresis -120 +KPX Tcaron Agrave -120 +KPX Tcaron Amacron -120 +KPX Tcaron Aogonek -120 +KPX Tcaron Aring -120 +KPX Tcaron Atilde -120 +KPX Tcaron O -40 +KPX Tcaron Oacute -40 +KPX Tcaron Ocircumflex -40 +KPX Tcaron Odieresis -40 +KPX Tcaron Ograve -40 +KPX Tcaron Ohungarumlaut -40 +KPX Tcaron Omacron -40 +KPX Tcaron Oslash -40 +KPX Tcaron Otilde -40 +KPX Tcaron a -120 +KPX Tcaron aacute -120 +KPX Tcaron abreve -60 +KPX Tcaron acircumflex -120 +KPX Tcaron adieresis -120 +KPX Tcaron agrave -120 +KPX Tcaron amacron -60 +KPX Tcaron aogonek -120 +KPX Tcaron aring -120 +KPX Tcaron atilde -60 +KPX Tcaron colon -20 +KPX Tcaron comma -120 +KPX Tcaron e -120 +KPX Tcaron eacute -120 +KPX Tcaron ecaron -120 +KPX Tcaron ecircumflex -120 +KPX Tcaron edieresis -120 +KPX Tcaron edotaccent -120 +KPX Tcaron egrave -60 +KPX Tcaron emacron -60 +KPX Tcaron eogonek -120 +KPX Tcaron hyphen -140 +KPX Tcaron o -120 +KPX Tcaron oacute -120 +KPX Tcaron ocircumflex -120 +KPX Tcaron odieresis -120 +KPX Tcaron ograve -120 +KPX Tcaron ohungarumlaut -120 +KPX Tcaron omacron -60 +KPX Tcaron oslash -120 +KPX Tcaron otilde -60 +KPX Tcaron period -120 +KPX Tcaron r -120 +KPX Tcaron racute -120 +KPX Tcaron rcaron -120 +KPX Tcaron rcommaaccent -120 +KPX Tcaron semicolon -20 +KPX Tcaron u -120 +KPX Tcaron uacute -120 +KPX Tcaron ucircumflex -120 +KPX Tcaron udieresis -120 +KPX Tcaron ugrave -120 +KPX Tcaron uhungarumlaut -120 +KPX Tcaron umacron -60 +KPX Tcaron uogonek -120 +KPX Tcaron uring -120 +KPX Tcaron w -120 +KPX Tcaron y -120 +KPX Tcaron yacute -120 +KPX Tcaron ydieresis -60 +KPX Tcommaaccent A -120 +KPX Tcommaaccent Aacute -120 +KPX Tcommaaccent Abreve -120 +KPX Tcommaaccent Acircumflex -120 +KPX Tcommaaccent Adieresis -120 +KPX Tcommaaccent Agrave -120 +KPX Tcommaaccent Amacron -120 +KPX Tcommaaccent Aogonek -120 +KPX Tcommaaccent Aring -120 +KPX Tcommaaccent Atilde -120 +KPX Tcommaaccent O -40 +KPX Tcommaaccent Oacute -40 +KPX Tcommaaccent Ocircumflex -40 +KPX Tcommaaccent Odieresis -40 +KPX Tcommaaccent Ograve -40 +KPX Tcommaaccent Ohungarumlaut -40 +KPX Tcommaaccent Omacron -40 +KPX Tcommaaccent Oslash -40 +KPX Tcommaaccent Otilde -40 +KPX Tcommaaccent a -120 +KPX Tcommaaccent aacute -120 +KPX Tcommaaccent abreve -60 +KPX Tcommaaccent acircumflex -120 +KPX Tcommaaccent adieresis -120 +KPX Tcommaaccent agrave -120 +KPX Tcommaaccent amacron -60 +KPX Tcommaaccent aogonek -120 +KPX Tcommaaccent aring -120 +KPX Tcommaaccent atilde -60 +KPX Tcommaaccent colon -20 +KPX Tcommaaccent comma -120 +KPX Tcommaaccent e -120 +KPX Tcommaaccent eacute -120 +KPX Tcommaaccent ecaron -120 +KPX Tcommaaccent ecircumflex -120 +KPX Tcommaaccent edieresis -120 +KPX Tcommaaccent edotaccent -120 +KPX Tcommaaccent egrave -60 +KPX Tcommaaccent emacron -60 +KPX Tcommaaccent eogonek -120 +KPX Tcommaaccent hyphen -140 +KPX Tcommaaccent o -120 +KPX Tcommaaccent oacute -120 +KPX Tcommaaccent ocircumflex -120 +KPX Tcommaaccent odieresis -120 +KPX Tcommaaccent ograve -120 +KPX Tcommaaccent ohungarumlaut -120 +KPX Tcommaaccent omacron -60 +KPX Tcommaaccent oslash -120 +KPX Tcommaaccent otilde -60 +KPX Tcommaaccent period -120 +KPX Tcommaaccent r -120 +KPX Tcommaaccent racute -120 +KPX Tcommaaccent rcaron -120 +KPX Tcommaaccent rcommaaccent -120 +KPX Tcommaaccent semicolon -20 +KPX Tcommaaccent u -120 +KPX Tcommaaccent uacute -120 +KPX Tcommaaccent ucircumflex -120 +KPX Tcommaaccent udieresis -120 +KPX Tcommaaccent ugrave -120 +KPX Tcommaaccent uhungarumlaut -120 +KPX Tcommaaccent umacron -60 +KPX Tcommaaccent uogonek -120 +KPX Tcommaaccent uring -120 +KPX Tcommaaccent w -120 +KPX Tcommaaccent y -120 +KPX Tcommaaccent yacute -120 +KPX Tcommaaccent ydieresis -60 +KPX U A -40 +KPX U Aacute -40 +KPX U Abreve -40 +KPX U Acircumflex -40 +KPX U Adieresis -40 +KPX U Agrave -40 +KPX U Amacron -40 +KPX U Aogonek -40 +KPX U Aring -40 +KPX U Atilde -40 +KPX U comma -40 +KPX U period -40 +KPX Uacute A -40 +KPX Uacute Aacute -40 +KPX Uacute Abreve -40 +KPX Uacute Acircumflex -40 +KPX Uacute Adieresis -40 +KPX Uacute Agrave -40 +KPX Uacute Amacron -40 +KPX Uacute Aogonek -40 +KPX Uacute Aring -40 +KPX Uacute Atilde -40 +KPX Uacute comma -40 +KPX Uacute period -40 +KPX Ucircumflex A -40 +KPX Ucircumflex Aacute -40 +KPX Ucircumflex Abreve -40 +KPX Ucircumflex Acircumflex -40 +KPX Ucircumflex Adieresis -40 +KPX Ucircumflex Agrave -40 +KPX Ucircumflex Amacron -40 +KPX Ucircumflex Aogonek -40 +KPX Ucircumflex Aring -40 +KPX Ucircumflex Atilde -40 +KPX Ucircumflex comma -40 +KPX Ucircumflex period -40 +KPX Udieresis A -40 +KPX Udieresis Aacute -40 +KPX Udieresis Abreve -40 +KPX Udieresis Acircumflex -40 +KPX Udieresis Adieresis -40 +KPX Udieresis Agrave -40 +KPX Udieresis Amacron -40 +KPX Udieresis Aogonek -40 +KPX Udieresis Aring -40 +KPX Udieresis Atilde -40 +KPX Udieresis comma -40 +KPX Udieresis period -40 +KPX Ugrave A -40 +KPX Ugrave Aacute -40 +KPX Ugrave Abreve -40 +KPX Ugrave Acircumflex -40 +KPX Ugrave Adieresis -40 +KPX Ugrave Agrave -40 +KPX Ugrave Amacron -40 +KPX Ugrave Aogonek -40 +KPX Ugrave Aring -40 +KPX Ugrave Atilde -40 +KPX Ugrave comma -40 +KPX Ugrave period -40 +KPX Uhungarumlaut A -40 +KPX Uhungarumlaut Aacute -40 +KPX Uhungarumlaut Abreve -40 +KPX Uhungarumlaut Acircumflex -40 +KPX Uhungarumlaut Adieresis -40 +KPX Uhungarumlaut Agrave -40 +KPX Uhungarumlaut Amacron -40 +KPX Uhungarumlaut Aogonek -40 +KPX Uhungarumlaut Aring -40 +KPX Uhungarumlaut Atilde -40 +KPX Uhungarumlaut comma -40 +KPX Uhungarumlaut period -40 +KPX Umacron A -40 +KPX Umacron Aacute -40 +KPX Umacron Abreve -40 +KPX Umacron Acircumflex -40 +KPX Umacron Adieresis -40 +KPX Umacron Agrave -40 +KPX Umacron Amacron -40 +KPX Umacron Aogonek -40 +KPX Umacron Aring -40 +KPX Umacron Atilde -40 +KPX Umacron comma -40 +KPX Umacron period -40 +KPX Uogonek A -40 +KPX Uogonek Aacute -40 +KPX Uogonek Abreve -40 +KPX Uogonek Acircumflex -40 +KPX Uogonek Adieresis -40 +KPX Uogonek Agrave -40 +KPX Uogonek Amacron -40 +KPX Uogonek Aogonek -40 +KPX Uogonek Aring -40 +KPX Uogonek Atilde -40 +KPX Uogonek comma -40 +KPX Uogonek period -40 +KPX Uring A -40 +KPX Uring Aacute -40 +KPX Uring Abreve -40 +KPX Uring Acircumflex -40 +KPX Uring Adieresis -40 +KPX Uring Agrave -40 +KPX Uring Amacron -40 +KPX Uring Aogonek -40 +KPX Uring Aring -40 +KPX Uring Atilde -40 +KPX Uring comma -40 +KPX Uring period -40 +KPX V A -80 +KPX V Aacute -80 +KPX V Abreve -80 +KPX V Acircumflex -80 +KPX V Adieresis -80 +KPX V Agrave -80 +KPX V Amacron -80 +KPX V Aogonek -80 +KPX V Aring -80 +KPX V Atilde -80 +KPX V G -40 +KPX V Gbreve -40 +KPX V Gcommaaccent -40 +KPX V O -40 +KPX V Oacute -40 +KPX V Ocircumflex -40 +KPX V Odieresis -40 +KPX V Ograve -40 +KPX V Ohungarumlaut -40 +KPX V Omacron -40 +KPX V Oslash -40 +KPX V Otilde -40 +KPX V a -70 +KPX V aacute -70 +KPX V abreve -70 +KPX V acircumflex -70 +KPX V adieresis -70 +KPX V agrave -70 +KPX V amacron -70 +KPX V aogonek -70 +KPX V aring -70 +KPX V atilde -70 +KPX V colon -40 +KPX V comma -125 +KPX V e -80 +KPX V eacute -80 +KPX V ecaron -80 +KPX V ecircumflex -80 +KPX V edieresis -80 +KPX V edotaccent -80 +KPX V egrave -80 +KPX V emacron -80 +KPX V eogonek -80 +KPX V hyphen -80 +KPX V o -80 +KPX V oacute -80 +KPX V ocircumflex -80 +KPX V odieresis -80 +KPX V ograve -80 +KPX V ohungarumlaut -80 +KPX V omacron -80 +KPX V oslash -80 +KPX V otilde -80 +KPX V period -125 +KPX V semicolon -40 +KPX V u -70 +KPX V uacute -70 +KPX V ucircumflex -70 +KPX V udieresis -70 +KPX V ugrave -70 +KPX V uhungarumlaut -70 +KPX V umacron -70 +KPX V uogonek -70 +KPX V uring -70 +KPX W A -50 +KPX W Aacute -50 +KPX W Abreve -50 +KPX W Acircumflex -50 +KPX W Adieresis -50 +KPX W Agrave -50 +KPX W Amacron -50 +KPX W Aogonek -50 +KPX W Aring -50 +KPX W Atilde -50 +KPX W O -20 +KPX W Oacute -20 +KPX W Ocircumflex -20 +KPX W Odieresis -20 +KPX W Ograve -20 +KPX W Ohungarumlaut -20 +KPX W Omacron -20 +KPX W Oslash -20 +KPX W Otilde -20 +KPX W a -40 +KPX W aacute -40 +KPX W abreve -40 +KPX W acircumflex -40 +KPX W adieresis -40 +KPX W agrave -40 +KPX W amacron -40 +KPX W aogonek -40 +KPX W aring -40 +KPX W atilde -40 +KPX W comma -80 +KPX W e -30 +KPX W eacute -30 +KPX W ecaron -30 +KPX W ecircumflex -30 +KPX W edieresis -30 +KPX W edotaccent -30 +KPX W egrave -30 +KPX W emacron -30 +KPX W eogonek -30 +KPX W hyphen -40 +KPX W o -30 +KPX W oacute -30 +KPX W ocircumflex -30 +KPX W odieresis -30 +KPX W ograve -30 +KPX W ohungarumlaut -30 +KPX W omacron -30 +KPX W oslash -30 +KPX W otilde -30 +KPX W period -80 +KPX W u -30 +KPX W uacute -30 +KPX W ucircumflex -30 +KPX W udieresis -30 +KPX W ugrave -30 +KPX W uhungarumlaut -30 +KPX W umacron -30 +KPX W uogonek -30 +KPX W uring -30 +KPX W y -20 +KPX W yacute -20 +KPX W ydieresis -20 +KPX Y A -110 +KPX Y Aacute -110 +KPX Y Abreve -110 +KPX Y Acircumflex -110 +KPX Y Adieresis -110 +KPX Y Agrave -110 +KPX Y Amacron -110 +KPX Y Aogonek -110 +KPX Y Aring -110 +KPX Y Atilde -110 +KPX Y O -85 +KPX Y Oacute -85 +KPX Y Ocircumflex -85 +KPX Y Odieresis -85 +KPX Y Ograve -85 +KPX Y Ohungarumlaut -85 +KPX Y Omacron -85 +KPX Y Oslash -85 +KPX Y Otilde -85 +KPX Y a -140 +KPX Y aacute -140 +KPX Y abreve -70 +KPX Y acircumflex -140 +KPX Y adieresis -140 +KPX Y agrave -140 +KPX Y amacron -70 +KPX Y aogonek -140 +KPX Y aring -140 +KPX Y atilde -140 +KPX Y colon -60 +KPX Y comma -140 +KPX Y e -140 +KPX Y eacute -140 +KPX Y ecaron -140 +KPX Y ecircumflex -140 +KPX Y edieresis -140 +KPX Y edotaccent -140 +KPX Y egrave -140 +KPX Y emacron -70 +KPX Y eogonek -140 +KPX Y hyphen -140 +KPX Y i -20 +KPX Y iacute -20 +KPX Y iogonek -20 +KPX Y o -140 +KPX Y oacute -140 +KPX Y ocircumflex -140 +KPX Y odieresis -140 +KPX Y ograve -140 +KPX Y ohungarumlaut -140 +KPX Y omacron -140 +KPX Y oslash -140 +KPX Y otilde -140 +KPX Y period -140 +KPX Y semicolon -60 +KPX Y u -110 +KPX Y uacute -110 +KPX Y ucircumflex -110 +KPX Y udieresis -110 +KPX Y ugrave -110 +KPX Y uhungarumlaut -110 +KPX Y umacron -110 +KPX Y uogonek -110 +KPX Y uring -110 +KPX Yacute A -110 +KPX Yacute Aacute -110 +KPX Yacute Abreve -110 +KPX Yacute Acircumflex -110 +KPX Yacute Adieresis -110 +KPX Yacute Agrave -110 +KPX Yacute Amacron -110 +KPX Yacute Aogonek -110 +KPX Yacute Aring -110 +KPX Yacute Atilde -110 +KPX Yacute O -85 +KPX Yacute Oacute -85 +KPX Yacute Ocircumflex -85 +KPX Yacute Odieresis -85 +KPX Yacute Ograve -85 +KPX Yacute Ohungarumlaut -85 +KPX Yacute Omacron -85 +KPX Yacute Oslash -85 +KPX Yacute Otilde -85 +KPX Yacute a -140 +KPX Yacute aacute -140 +KPX Yacute abreve -70 +KPX Yacute acircumflex -140 +KPX Yacute adieresis -140 +KPX Yacute agrave -140 +KPX Yacute amacron -70 +KPX Yacute aogonek -140 +KPX Yacute aring -140 +KPX Yacute atilde -70 +KPX Yacute colon -60 +KPX Yacute comma -140 +KPX Yacute e -140 +KPX Yacute eacute -140 +KPX Yacute ecaron -140 +KPX Yacute ecircumflex -140 +KPX Yacute edieresis -140 +KPX Yacute edotaccent -140 +KPX Yacute egrave -140 +KPX Yacute emacron -70 +KPX Yacute eogonek -140 +KPX Yacute hyphen -140 +KPX Yacute i -20 +KPX Yacute iacute -20 +KPX Yacute iogonek -20 +KPX Yacute o -140 +KPX Yacute oacute -140 +KPX Yacute ocircumflex -140 +KPX Yacute odieresis -140 +KPX Yacute ograve -140 +KPX Yacute ohungarumlaut -140 +KPX Yacute omacron -70 +KPX Yacute oslash -140 +KPX Yacute otilde -140 +KPX Yacute period -140 +KPX Yacute semicolon -60 +KPX Yacute u -110 +KPX Yacute uacute -110 +KPX Yacute ucircumflex -110 +KPX Yacute udieresis -110 +KPX Yacute ugrave -110 +KPX Yacute uhungarumlaut -110 +KPX Yacute umacron -110 +KPX Yacute uogonek -110 +KPX Yacute uring -110 +KPX Ydieresis A -110 +KPX Ydieresis Aacute -110 +KPX Ydieresis Abreve -110 +KPX Ydieresis Acircumflex -110 +KPX Ydieresis Adieresis -110 +KPX Ydieresis Agrave -110 +KPX Ydieresis Amacron -110 +KPX Ydieresis Aogonek -110 +KPX Ydieresis Aring -110 +KPX Ydieresis Atilde -110 +KPX Ydieresis O -85 +KPX Ydieresis Oacute -85 +KPX Ydieresis Ocircumflex -85 +KPX Ydieresis Odieresis -85 +KPX Ydieresis Ograve -85 +KPX Ydieresis Ohungarumlaut -85 +KPX Ydieresis Omacron -85 +KPX Ydieresis Oslash -85 +KPX Ydieresis Otilde -85 +KPX Ydieresis a -140 +KPX Ydieresis aacute -140 +KPX Ydieresis abreve -70 +KPX Ydieresis acircumflex -140 +KPX Ydieresis adieresis -140 +KPX Ydieresis agrave -140 +KPX Ydieresis amacron -70 +KPX Ydieresis aogonek -140 +KPX Ydieresis aring -140 +KPX Ydieresis atilde -70 +KPX Ydieresis colon -60 +KPX Ydieresis comma -140 +KPX Ydieresis e -140 +KPX Ydieresis eacute -140 +KPX Ydieresis ecaron -140 +KPX Ydieresis ecircumflex -140 +KPX Ydieresis edieresis -140 +KPX Ydieresis edotaccent -140 +KPX Ydieresis egrave -140 +KPX Ydieresis emacron -70 +KPX Ydieresis eogonek -140 +KPX Ydieresis hyphen -140 +KPX Ydieresis i -20 +KPX Ydieresis iacute -20 +KPX Ydieresis iogonek -20 +KPX Ydieresis o -140 +KPX Ydieresis oacute -140 +KPX Ydieresis ocircumflex -140 +KPX Ydieresis odieresis -140 +KPX Ydieresis ograve -140 +KPX Ydieresis ohungarumlaut -140 +KPX Ydieresis omacron -140 +KPX Ydieresis oslash -140 +KPX Ydieresis otilde -140 +KPX Ydieresis period -140 +KPX Ydieresis semicolon -60 +KPX Ydieresis u -110 +KPX Ydieresis uacute -110 +KPX Ydieresis ucircumflex -110 +KPX Ydieresis udieresis -110 +KPX Ydieresis ugrave -110 +KPX Ydieresis uhungarumlaut -110 +KPX Ydieresis umacron -110 +KPX Ydieresis uogonek -110 +KPX Ydieresis uring -110 +KPX a v -20 +KPX a w -20 +KPX a y -30 +KPX a yacute -30 +KPX a ydieresis -30 +KPX aacute v -20 +KPX aacute w -20 +KPX aacute y -30 +KPX aacute yacute -30 +KPX aacute ydieresis -30 +KPX abreve v -20 +KPX abreve w -20 +KPX abreve y -30 +KPX abreve yacute -30 +KPX abreve ydieresis -30 +KPX acircumflex v -20 +KPX acircumflex w -20 +KPX acircumflex y -30 +KPX acircumflex yacute -30 +KPX acircumflex ydieresis -30 +KPX adieresis v -20 +KPX adieresis w -20 +KPX adieresis y -30 +KPX adieresis yacute -30 +KPX adieresis ydieresis -30 +KPX agrave v -20 +KPX agrave w -20 +KPX agrave y -30 +KPX agrave yacute -30 +KPX agrave ydieresis -30 +KPX amacron v -20 +KPX amacron w -20 +KPX amacron y -30 +KPX amacron yacute -30 +KPX amacron ydieresis -30 +KPX aogonek v -20 +KPX aogonek w -20 +KPX aogonek y -30 +KPX aogonek yacute -30 +KPX aogonek ydieresis -30 +KPX aring v -20 +KPX aring w -20 +KPX aring y -30 +KPX aring yacute -30 +KPX aring ydieresis -30 +KPX atilde v -20 +KPX atilde w -20 +KPX atilde y -30 +KPX atilde yacute -30 +KPX atilde ydieresis -30 +KPX b b -10 +KPX b comma -40 +KPX b l -20 +KPX b lacute -20 +KPX b lcommaaccent -20 +KPX b lslash -20 +KPX b period -40 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX b v -20 +KPX b y -20 +KPX b yacute -20 +KPX b ydieresis -20 +KPX c comma -15 +KPX c k -20 +KPX c kcommaaccent -20 +KPX cacute comma -15 +KPX cacute k -20 +KPX cacute kcommaaccent -20 +KPX ccaron comma -15 +KPX ccaron k -20 +KPX ccaron kcommaaccent -20 +KPX ccedilla comma -15 +KPX ccedilla k -20 +KPX ccedilla kcommaaccent -20 +KPX colon space -50 +KPX comma quotedblright -100 +KPX comma quoteright -100 +KPX e comma -15 +KPX e period -15 +KPX e v -30 +KPX e w -20 +KPX e x -30 +KPX e y -20 +KPX e yacute -20 +KPX e ydieresis -20 +KPX eacute comma -15 +KPX eacute period -15 +KPX eacute v -30 +KPX eacute w -20 +KPX eacute x -30 +KPX eacute y -20 +KPX eacute yacute -20 +KPX eacute ydieresis -20 +KPX ecaron comma -15 +KPX ecaron period -15 +KPX ecaron v -30 +KPX ecaron w -20 +KPX ecaron x -30 +KPX ecaron y -20 +KPX ecaron yacute -20 +KPX ecaron ydieresis -20 +KPX ecircumflex comma -15 +KPX ecircumflex period -15 +KPX ecircumflex v -30 +KPX ecircumflex w -20 +KPX ecircumflex x -30 +KPX ecircumflex y -20 +KPX ecircumflex yacute -20 +KPX ecircumflex ydieresis -20 +KPX edieresis comma -15 +KPX edieresis period -15 +KPX edieresis v -30 +KPX edieresis w -20 +KPX edieresis x -30 +KPX edieresis y -20 +KPX edieresis yacute -20 +KPX edieresis ydieresis -20 +KPX edotaccent comma -15 +KPX edotaccent period -15 +KPX edotaccent v -30 +KPX edotaccent w -20 +KPX edotaccent x -30 +KPX edotaccent y -20 +KPX edotaccent yacute -20 +KPX edotaccent ydieresis -20 +KPX egrave comma -15 +KPX egrave period -15 +KPX egrave v -30 +KPX egrave w -20 +KPX egrave x -30 +KPX egrave y -20 +KPX egrave yacute -20 +KPX egrave ydieresis -20 +KPX emacron comma -15 +KPX emacron period -15 +KPX emacron v -30 +KPX emacron w -20 +KPX emacron x -30 +KPX emacron y -20 +KPX emacron yacute -20 +KPX emacron ydieresis -20 +KPX eogonek comma -15 +KPX eogonek period -15 +KPX eogonek v -30 +KPX eogonek w -20 +KPX eogonek x -30 +KPX eogonek y -20 +KPX eogonek yacute -20 +KPX eogonek ydieresis -20 +KPX f a -30 +KPX f aacute -30 +KPX f abreve -30 +KPX f acircumflex -30 +KPX f adieresis -30 +KPX f agrave -30 +KPX f amacron -30 +KPX f aogonek -30 +KPX f aring -30 +KPX f atilde -30 +KPX f comma -30 +KPX f dotlessi -28 +KPX f e -30 +KPX f eacute -30 +KPX f ecaron -30 +KPX f ecircumflex -30 +KPX f edieresis -30 +KPX f edotaccent -30 +KPX f egrave -30 +KPX f emacron -30 +KPX f eogonek -30 +KPX f o -30 +KPX f oacute -30 +KPX f ocircumflex -30 +KPX f odieresis -30 +KPX f ograve -30 +KPX f ohungarumlaut -30 +KPX f omacron -30 +KPX f oslash -30 +KPX f otilde -30 +KPX f period -30 +KPX f quotedblright 60 +KPX f quoteright 50 +KPX g r -10 +KPX g racute -10 +KPX g rcaron -10 +KPX g rcommaaccent -10 +KPX gbreve r -10 +KPX gbreve racute -10 +KPX gbreve rcaron -10 +KPX gbreve rcommaaccent -10 +KPX gcommaaccent r -10 +KPX gcommaaccent racute -10 +KPX gcommaaccent rcaron -10 +KPX gcommaaccent rcommaaccent -10 +KPX h y -30 +KPX h yacute -30 +KPX h ydieresis -30 +KPX k e -20 +KPX k eacute -20 +KPX k ecaron -20 +KPX k ecircumflex -20 +KPX k edieresis -20 +KPX k edotaccent -20 +KPX k egrave -20 +KPX k emacron -20 +KPX k eogonek -20 +KPX k o -20 +KPX k oacute -20 +KPX k ocircumflex -20 +KPX k odieresis -20 +KPX k ograve -20 +KPX k ohungarumlaut -20 +KPX k omacron -20 +KPX k oslash -20 +KPX k otilde -20 +KPX kcommaaccent e -20 +KPX kcommaaccent eacute -20 +KPX kcommaaccent ecaron -20 +KPX kcommaaccent ecircumflex -20 +KPX kcommaaccent edieresis -20 +KPX kcommaaccent edotaccent -20 +KPX kcommaaccent egrave -20 +KPX kcommaaccent emacron -20 +KPX kcommaaccent eogonek -20 +KPX kcommaaccent o -20 +KPX kcommaaccent oacute -20 +KPX kcommaaccent ocircumflex -20 +KPX kcommaaccent odieresis -20 +KPX kcommaaccent ograve -20 +KPX kcommaaccent ohungarumlaut -20 +KPX kcommaaccent omacron -20 +KPX kcommaaccent oslash -20 +KPX kcommaaccent otilde -20 +KPX m u -10 +KPX m uacute -10 +KPX m ucircumflex -10 +KPX m udieresis -10 +KPX m ugrave -10 +KPX m uhungarumlaut -10 +KPX m umacron -10 +KPX m uogonek -10 +KPX m uring -10 +KPX m y -15 +KPX m yacute -15 +KPX m ydieresis -15 +KPX n u -10 +KPX n uacute -10 +KPX n ucircumflex -10 +KPX n udieresis -10 +KPX n ugrave -10 +KPX n uhungarumlaut -10 +KPX n umacron -10 +KPX n uogonek -10 +KPX n uring -10 +KPX n v -20 +KPX n y -15 +KPX n yacute -15 +KPX n ydieresis -15 +KPX nacute u -10 +KPX nacute uacute -10 +KPX nacute ucircumflex -10 +KPX nacute udieresis -10 +KPX nacute ugrave -10 +KPX nacute uhungarumlaut -10 +KPX nacute umacron -10 +KPX nacute uogonek -10 +KPX nacute uring -10 +KPX nacute v -20 +KPX nacute y -15 +KPX nacute yacute -15 +KPX nacute ydieresis -15 +KPX ncaron u -10 +KPX ncaron uacute -10 +KPX ncaron ucircumflex -10 +KPX ncaron udieresis -10 +KPX ncaron ugrave -10 +KPX ncaron uhungarumlaut -10 +KPX ncaron umacron -10 +KPX ncaron uogonek -10 +KPX ncaron uring -10 +KPX ncaron v -20 +KPX ncaron y -15 +KPX ncaron yacute -15 +KPX ncaron ydieresis -15 +KPX ncommaaccent u -10 +KPX ncommaaccent uacute -10 +KPX ncommaaccent ucircumflex -10 +KPX ncommaaccent udieresis -10 +KPX ncommaaccent ugrave -10 +KPX ncommaaccent uhungarumlaut -10 +KPX ncommaaccent umacron -10 +KPX ncommaaccent uogonek -10 +KPX ncommaaccent uring -10 +KPX ncommaaccent v -20 +KPX ncommaaccent y -15 +KPX ncommaaccent yacute -15 +KPX ncommaaccent ydieresis -15 +KPX ntilde u -10 +KPX ntilde uacute -10 +KPX ntilde ucircumflex -10 +KPX ntilde udieresis -10 +KPX ntilde ugrave -10 +KPX ntilde uhungarumlaut -10 +KPX ntilde umacron -10 +KPX ntilde uogonek -10 +KPX ntilde uring -10 +KPX ntilde v -20 +KPX ntilde y -15 +KPX ntilde yacute -15 +KPX ntilde ydieresis -15 +KPX o comma -40 +KPX o period -40 +KPX o v -15 +KPX o w -15 +KPX o x -30 +KPX o y -30 +KPX o yacute -30 +KPX o ydieresis -30 +KPX oacute comma -40 +KPX oacute period -40 +KPX oacute v -15 +KPX oacute w -15 +KPX oacute x -30 +KPX oacute y -30 +KPX oacute yacute -30 +KPX oacute ydieresis -30 +KPX ocircumflex comma -40 +KPX ocircumflex period -40 +KPX ocircumflex v -15 +KPX ocircumflex w -15 +KPX ocircumflex x -30 +KPX ocircumflex y -30 +KPX ocircumflex yacute -30 +KPX ocircumflex ydieresis -30 +KPX odieresis comma -40 +KPX odieresis period -40 +KPX odieresis v -15 +KPX odieresis w -15 +KPX odieresis x -30 +KPX odieresis y -30 +KPX odieresis yacute -30 +KPX odieresis ydieresis -30 +KPX ograve comma -40 +KPX ograve period -40 +KPX ograve v -15 +KPX ograve w -15 +KPX ograve x -30 +KPX ograve y -30 +KPX ograve yacute -30 +KPX ograve ydieresis -30 +KPX ohungarumlaut comma -40 +KPX ohungarumlaut period -40 +KPX ohungarumlaut v -15 +KPX ohungarumlaut w -15 +KPX ohungarumlaut x -30 +KPX ohungarumlaut y -30 +KPX ohungarumlaut yacute -30 +KPX ohungarumlaut ydieresis -30 +KPX omacron comma -40 +KPX omacron period -40 +KPX omacron v -15 +KPX omacron w -15 +KPX omacron x -30 +KPX omacron y -30 +KPX omacron yacute -30 +KPX omacron ydieresis -30 +KPX oslash a -55 +KPX oslash aacute -55 +KPX oslash abreve -55 +KPX oslash acircumflex -55 +KPX oslash adieresis -55 +KPX oslash agrave -55 +KPX oslash amacron -55 +KPX oslash aogonek -55 +KPX oslash aring -55 +KPX oslash atilde -55 +KPX oslash b -55 +KPX oslash c -55 +KPX oslash cacute -55 +KPX oslash ccaron -55 +KPX oslash ccedilla -55 +KPX oslash comma -95 +KPX oslash d -55 +KPX oslash dcroat -55 +KPX oslash e -55 +KPX oslash eacute -55 +KPX oslash ecaron -55 +KPX oslash ecircumflex -55 +KPX oslash edieresis -55 +KPX oslash edotaccent -55 +KPX oslash egrave -55 +KPX oslash emacron -55 +KPX oslash eogonek -55 +KPX oslash f -55 +KPX oslash g -55 +KPX oslash gbreve -55 +KPX oslash gcommaaccent -55 +KPX oslash h -55 +KPX oslash i -55 +KPX oslash iacute -55 +KPX oslash icircumflex -55 +KPX oslash idieresis -55 +KPX oslash igrave -55 +KPX oslash imacron -55 +KPX oslash iogonek -55 +KPX oslash j -55 +KPX oslash k -55 +KPX oslash kcommaaccent -55 +KPX oslash l -55 +KPX oslash lacute -55 +KPX oslash lcommaaccent -55 +KPX oslash lslash -55 +KPX oslash m -55 +KPX oslash n -55 +KPX oslash nacute -55 +KPX oslash ncaron -55 +KPX oslash ncommaaccent -55 +KPX oslash ntilde -55 +KPX oslash o -55 +KPX oslash oacute -55 +KPX oslash ocircumflex -55 +KPX oslash odieresis -55 +KPX oslash ograve -55 +KPX oslash ohungarumlaut -55 +KPX oslash omacron -55 +KPX oslash oslash -55 +KPX oslash otilde -55 +KPX oslash p -55 +KPX oslash period -95 +KPX oslash q -55 +KPX oslash r -55 +KPX oslash racute -55 +KPX oslash rcaron -55 +KPX oslash rcommaaccent -55 +KPX oslash s -55 +KPX oslash sacute -55 +KPX oslash scaron -55 +KPX oslash scedilla -55 +KPX oslash scommaaccent -55 +KPX oslash t -55 +KPX oslash tcommaaccent -55 +KPX oslash u -55 +KPX oslash uacute -55 +KPX oslash ucircumflex -55 +KPX oslash udieresis -55 +KPX oslash ugrave -55 +KPX oslash uhungarumlaut -55 +KPX oslash umacron -55 +KPX oslash uogonek -55 +KPX oslash uring -55 +KPX oslash v -70 +KPX oslash w -70 +KPX oslash x -85 +KPX oslash y -70 +KPX oslash yacute -70 +KPX oslash ydieresis -70 +KPX oslash z -55 +KPX oslash zacute -55 +KPX oslash zcaron -55 +KPX oslash zdotaccent -55 +KPX otilde comma -40 +KPX otilde period -40 +KPX otilde v -15 +KPX otilde w -15 +KPX otilde x -30 +KPX otilde y -30 +KPX otilde yacute -30 +KPX otilde ydieresis -30 +KPX p comma -35 +KPX p period -35 +KPX p y -30 +KPX p yacute -30 +KPX p ydieresis -30 +KPX period quotedblright -100 +KPX period quoteright -100 +KPX period space -60 +KPX quotedblright space -40 +KPX quoteleft quoteleft -57 +KPX quoteright d -50 +KPX quoteright dcroat -50 +KPX quoteright quoteright -57 +KPX quoteright r -50 +KPX quoteright racute -50 +KPX quoteright rcaron -50 +KPX quoteright rcommaaccent -50 +KPX quoteright s -50 +KPX quoteright sacute -50 +KPX quoteright scaron -50 +KPX quoteright scedilla -50 +KPX quoteright scommaaccent -50 +KPX quoteright space -70 +KPX r a -10 +KPX r aacute -10 +KPX r abreve -10 +KPX r acircumflex -10 +KPX r adieresis -10 +KPX r agrave -10 +KPX r amacron -10 +KPX r aogonek -10 +KPX r aring -10 +KPX r atilde -10 +KPX r colon 30 +KPX r comma -50 +KPX r i 15 +KPX r iacute 15 +KPX r icircumflex 15 +KPX r idieresis 15 +KPX r igrave 15 +KPX r imacron 15 +KPX r iogonek 15 +KPX r k 15 +KPX r kcommaaccent 15 +KPX r l 15 +KPX r lacute 15 +KPX r lcommaaccent 15 +KPX r lslash 15 +KPX r m 25 +KPX r n 25 +KPX r nacute 25 +KPX r ncaron 25 +KPX r ncommaaccent 25 +KPX r ntilde 25 +KPX r p 30 +KPX r period -50 +KPX r semicolon 30 +KPX r t 40 +KPX r tcommaaccent 40 +KPX r u 15 +KPX r uacute 15 +KPX r ucircumflex 15 +KPX r udieresis 15 +KPX r ugrave 15 +KPX r uhungarumlaut 15 +KPX r umacron 15 +KPX r uogonek 15 +KPX r uring 15 +KPX r v 30 +KPX r y 30 +KPX r yacute 30 +KPX r ydieresis 30 +KPX racute a -10 +KPX racute aacute -10 +KPX racute abreve -10 +KPX racute acircumflex -10 +KPX racute adieresis -10 +KPX racute agrave -10 +KPX racute amacron -10 +KPX racute aogonek -10 +KPX racute aring -10 +KPX racute atilde -10 +KPX racute colon 30 +KPX racute comma -50 +KPX racute i 15 +KPX racute iacute 15 +KPX racute icircumflex 15 +KPX racute idieresis 15 +KPX racute igrave 15 +KPX racute imacron 15 +KPX racute iogonek 15 +KPX racute k 15 +KPX racute kcommaaccent 15 +KPX racute l 15 +KPX racute lacute 15 +KPX racute lcommaaccent 15 +KPX racute lslash 15 +KPX racute m 25 +KPX racute n 25 +KPX racute nacute 25 +KPX racute ncaron 25 +KPX racute ncommaaccent 25 +KPX racute ntilde 25 +KPX racute p 30 +KPX racute period -50 +KPX racute semicolon 30 +KPX racute t 40 +KPX racute tcommaaccent 40 +KPX racute u 15 +KPX racute uacute 15 +KPX racute ucircumflex 15 +KPX racute udieresis 15 +KPX racute ugrave 15 +KPX racute uhungarumlaut 15 +KPX racute umacron 15 +KPX racute uogonek 15 +KPX racute uring 15 +KPX racute v 30 +KPX racute y 30 +KPX racute yacute 30 +KPX racute ydieresis 30 +KPX rcaron a -10 +KPX rcaron aacute -10 +KPX rcaron abreve -10 +KPX rcaron acircumflex -10 +KPX rcaron adieresis -10 +KPX rcaron agrave -10 +KPX rcaron amacron -10 +KPX rcaron aogonek -10 +KPX rcaron aring -10 +KPX rcaron atilde -10 +KPX rcaron colon 30 +KPX rcaron comma -50 +KPX rcaron i 15 +KPX rcaron iacute 15 +KPX rcaron icircumflex 15 +KPX rcaron idieresis 15 +KPX rcaron igrave 15 +KPX rcaron imacron 15 +KPX rcaron iogonek 15 +KPX rcaron k 15 +KPX rcaron kcommaaccent 15 +KPX rcaron l 15 +KPX rcaron lacute 15 +KPX rcaron lcommaaccent 15 +KPX rcaron lslash 15 +KPX rcaron m 25 +KPX rcaron n 25 +KPX rcaron nacute 25 +KPX rcaron ncaron 25 +KPX rcaron ncommaaccent 25 +KPX rcaron ntilde 25 +KPX rcaron p 30 +KPX rcaron period -50 +KPX rcaron semicolon 30 +KPX rcaron t 40 +KPX rcaron tcommaaccent 40 +KPX rcaron u 15 +KPX rcaron uacute 15 +KPX rcaron ucircumflex 15 +KPX rcaron udieresis 15 +KPX rcaron ugrave 15 +KPX rcaron uhungarumlaut 15 +KPX rcaron umacron 15 +KPX rcaron uogonek 15 +KPX rcaron uring 15 +KPX rcaron v 30 +KPX rcaron y 30 +KPX rcaron yacute 30 +KPX rcaron ydieresis 30 +KPX rcommaaccent a -10 +KPX rcommaaccent aacute -10 +KPX rcommaaccent abreve -10 +KPX rcommaaccent acircumflex -10 +KPX rcommaaccent adieresis -10 +KPX rcommaaccent agrave -10 +KPX rcommaaccent amacron -10 +KPX rcommaaccent aogonek -10 +KPX rcommaaccent aring -10 +KPX rcommaaccent atilde -10 +KPX rcommaaccent colon 30 +KPX rcommaaccent comma -50 +KPX rcommaaccent i 15 +KPX rcommaaccent iacute 15 +KPX rcommaaccent icircumflex 15 +KPX rcommaaccent idieresis 15 +KPX rcommaaccent igrave 15 +KPX rcommaaccent imacron 15 +KPX rcommaaccent iogonek 15 +KPX rcommaaccent k 15 +KPX rcommaaccent kcommaaccent 15 +KPX rcommaaccent l 15 +KPX rcommaaccent lacute 15 +KPX rcommaaccent lcommaaccent 15 +KPX rcommaaccent lslash 15 +KPX rcommaaccent m 25 +KPX rcommaaccent n 25 +KPX rcommaaccent nacute 25 +KPX rcommaaccent ncaron 25 +KPX rcommaaccent ncommaaccent 25 +KPX rcommaaccent ntilde 25 +KPX rcommaaccent p 30 +KPX rcommaaccent period -50 +KPX rcommaaccent semicolon 30 +KPX rcommaaccent t 40 +KPX rcommaaccent tcommaaccent 40 +KPX rcommaaccent u 15 +KPX rcommaaccent uacute 15 +KPX rcommaaccent ucircumflex 15 +KPX rcommaaccent udieresis 15 +KPX rcommaaccent ugrave 15 +KPX rcommaaccent uhungarumlaut 15 +KPX rcommaaccent umacron 15 +KPX rcommaaccent uogonek 15 +KPX rcommaaccent uring 15 +KPX rcommaaccent v 30 +KPX rcommaaccent y 30 +KPX rcommaaccent yacute 30 +KPX rcommaaccent ydieresis 30 +KPX s comma -15 +KPX s period -15 +KPX s w -30 +KPX sacute comma -15 +KPX sacute period -15 +KPX sacute w -30 +KPX scaron comma -15 +KPX scaron period -15 +KPX scaron w -30 +KPX scedilla comma -15 +KPX scedilla period -15 +KPX scedilla w -30 +KPX scommaaccent comma -15 +KPX scommaaccent period -15 +KPX scommaaccent w -30 +KPX semicolon space -50 +KPX space T -50 +KPX space Tcaron -50 +KPX space Tcommaaccent -50 +KPX space V -50 +KPX space W -40 +KPX space Y -90 +KPX space Yacute -90 +KPX space Ydieresis -90 +KPX space quotedblleft -30 +KPX space quoteleft -60 +KPX v a -25 +KPX v aacute -25 +KPX v abreve -25 +KPX v acircumflex -25 +KPX v adieresis -25 +KPX v agrave -25 +KPX v amacron -25 +KPX v aogonek -25 +KPX v aring -25 +KPX v atilde -25 +KPX v comma -80 +KPX v e -25 +KPX v eacute -25 +KPX v ecaron -25 +KPX v ecircumflex -25 +KPX v edieresis -25 +KPX v edotaccent -25 +KPX v egrave -25 +KPX v emacron -25 +KPX v eogonek -25 +KPX v o -25 +KPX v oacute -25 +KPX v ocircumflex -25 +KPX v odieresis -25 +KPX v ograve -25 +KPX v ohungarumlaut -25 +KPX v omacron -25 +KPX v oslash -25 +KPX v otilde -25 +KPX v period -80 +KPX w a -15 +KPX w aacute -15 +KPX w abreve -15 +KPX w acircumflex -15 +KPX w adieresis -15 +KPX w agrave -15 +KPX w amacron -15 +KPX w aogonek -15 +KPX w aring -15 +KPX w atilde -15 +KPX w comma -60 +KPX w e -10 +KPX w eacute -10 +KPX w ecaron -10 +KPX w ecircumflex -10 +KPX w edieresis -10 +KPX w edotaccent -10 +KPX w egrave -10 +KPX w emacron -10 +KPX w eogonek -10 +KPX w o -10 +KPX w oacute -10 +KPX w ocircumflex -10 +KPX w odieresis -10 +KPX w ograve -10 +KPX w ohungarumlaut -10 +KPX w omacron -10 +KPX w oslash -10 +KPX w otilde -10 +KPX w period -60 +KPX x e -30 +KPX x eacute -30 +KPX x ecaron -30 +KPX x ecircumflex -30 +KPX x edieresis -30 +KPX x edotaccent -30 +KPX x egrave -30 +KPX x emacron -30 +KPX x eogonek -30 +KPX y a -20 +KPX y aacute -20 +KPX y abreve -20 +KPX y acircumflex -20 +KPX y adieresis -20 +KPX y agrave -20 +KPX y amacron -20 +KPX y aogonek -20 +KPX y aring -20 +KPX y atilde -20 +KPX y comma -100 +KPX y e -20 +KPX y eacute -20 +KPX y ecaron -20 +KPX y ecircumflex -20 +KPX y edieresis -20 +KPX y edotaccent -20 +KPX y egrave -20 +KPX y emacron -20 +KPX y eogonek -20 +KPX y o -20 +KPX y oacute -20 +KPX y ocircumflex -20 +KPX y odieresis -20 +KPX y ograve -20 +KPX y ohungarumlaut -20 +KPX y omacron -20 +KPX y oslash -20 +KPX y otilde -20 +KPX y period -100 +KPX yacute a -20 +KPX yacute aacute -20 +KPX yacute abreve -20 +KPX yacute acircumflex -20 +KPX yacute adieresis -20 +KPX yacute agrave -20 +KPX yacute amacron -20 +KPX yacute aogonek -20 +KPX yacute aring -20 +KPX yacute atilde -20 +KPX yacute comma -100 +KPX yacute e -20 +KPX yacute eacute -20 +KPX yacute ecaron -20 +KPX yacute ecircumflex -20 +KPX yacute edieresis -20 +KPX yacute edotaccent -20 +KPX yacute egrave -20 +KPX yacute emacron -20 +KPX yacute eogonek -20 +KPX yacute o -20 +KPX yacute oacute -20 +KPX yacute ocircumflex -20 +KPX yacute odieresis -20 +KPX yacute ograve -20 +KPX yacute ohungarumlaut -20 +KPX yacute omacron -20 +KPX yacute oslash -20 +KPX yacute otilde -20 +KPX yacute period -100 +KPX ydieresis a -20 +KPX ydieresis aacute -20 +KPX ydieresis abreve -20 +KPX ydieresis acircumflex -20 +KPX ydieresis adieresis -20 +KPX ydieresis agrave -20 +KPX ydieresis amacron -20 +KPX ydieresis aogonek -20 +KPX ydieresis aring -20 +KPX ydieresis atilde -20 +KPX ydieresis comma -100 +KPX ydieresis e -20 +KPX ydieresis eacute -20 +KPX ydieresis ecaron -20 +KPX ydieresis ecircumflex -20 +KPX ydieresis edieresis -20 +KPX ydieresis edotaccent -20 +KPX ydieresis egrave -20 +KPX ydieresis emacron -20 +KPX ydieresis eogonek -20 +KPX ydieresis o -20 +KPX ydieresis oacute -20 +KPX ydieresis ocircumflex -20 +KPX ydieresis odieresis -20 +KPX ydieresis ograve -20 +KPX ydieresis ohungarumlaut -20 +KPX ydieresis omacron -20 +KPX ydieresis oslash -20 +KPX ydieresis otilde -20 +KPX ydieresis period -100 +KPX z e -15 +KPX z eacute -15 +KPX z ecaron -15 +KPX z ecircumflex -15 +KPX z edieresis -15 +KPX z edotaccent -15 +KPX z egrave -15 +KPX z emacron -15 +KPX z eogonek -15 +KPX z o -15 +KPX z oacute -15 +KPX z ocircumflex -15 +KPX z odieresis -15 +KPX z ograve -15 +KPX z ohungarumlaut -15 +KPX z omacron -15 +KPX z oslash -15 +KPX z otilde -15 +KPX zacute e -15 +KPX zacute eacute -15 +KPX zacute ecaron -15 +KPX zacute ecircumflex -15 +KPX zacute edieresis -15 +KPX zacute edotaccent -15 +KPX zacute egrave -15 +KPX zacute emacron -15 +KPX zacute eogonek -15 +KPX zacute o -15 +KPX zacute oacute -15 +KPX zacute ocircumflex -15 +KPX zacute odieresis -15 +KPX zacute ograve -15 +KPX zacute ohungarumlaut -15 +KPX zacute omacron -15 +KPX zacute oslash -15 +KPX zacute otilde -15 +KPX zcaron e -15 +KPX zcaron eacute -15 +KPX zcaron ecaron -15 +KPX zcaron ecircumflex -15 +KPX zcaron edieresis -15 +KPX zcaron edotaccent -15 +KPX zcaron egrave -15 +KPX zcaron emacron -15 +KPX zcaron eogonek -15 +KPX zcaron o -15 +KPX zcaron oacute -15 +KPX zcaron ocircumflex -15 +KPX zcaron odieresis -15 +KPX zcaron ograve -15 +KPX zcaron ohungarumlaut -15 +KPX zcaron omacron -15 +KPX zcaron oslash -15 +KPX zcaron otilde -15 +KPX zdotaccent e -15 +KPX zdotaccent eacute -15 +KPX zdotaccent ecaron -15 +KPX zdotaccent ecircumflex -15 +KPX zdotaccent edieresis -15 +KPX zdotaccent edotaccent -15 +KPX zdotaccent egrave -15 +KPX zdotaccent emacron -15 +KPX zdotaccent eogonek -15 +KPX zdotaccent o -15 +KPX zdotaccent oacute -15 +KPX zdotaccent ocircumflex -15 +KPX zdotaccent odieresis -15 +KPX zdotaccent ograve -15 +KPX zdotaccent ohungarumlaut -15 +KPX zdotaccent omacron -15 +KPX zdotaccent oslash -15 +KPX zdotaccent otilde -15 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Symbol.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Symbol.afm new file mode 100644 index 0000000..440ff94 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Symbol.afm @@ -0,0 +1,213 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All rights reserved. +Comment Creation Date: Thu May 1 15:12:25 1997 +Comment UniqueID 43064 +Comment VMusage 30820 39997 +FontName Symbol +FullName Symbol +FamilyName Symbol +Weight Medium +ItalicAngle 0 +IsFixedPitch false +CharacterSet Special +FontBBox -180 -293 1090 1010 +UnderlinePosition -100 +UnderlineThickness 50 +Version 001.008 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All rights reserved. +EncodingScheme FontSpecific +StdHW 92 +StdVW 85 +StartCharMetrics 190 +C 32 ; WX 250 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 128 -17 240 672 ; +C 34 ; WX 713 ; N universal ; B 31 0 681 705 ; +C 35 ; WX 500 ; N numbersign ; B 20 -16 481 673 ; +C 36 ; WX 549 ; N existential ; B 25 0 478 707 ; +C 37 ; WX 833 ; N percent ; B 63 -36 771 655 ; +C 38 ; WX 778 ; N ampersand ; B 41 -18 750 661 ; +C 39 ; WX 439 ; N suchthat ; B 48 -17 414 500 ; +C 40 ; WX 333 ; N parenleft ; B 53 -191 300 673 ; +C 41 ; WX 333 ; N parenright ; B 30 -191 277 673 ; +C 42 ; WX 500 ; N asteriskmath ; B 65 134 427 551 ; +C 43 ; WX 549 ; N plus ; B 10 0 539 533 ; +C 44 ; WX 250 ; N comma ; B 56 -152 194 104 ; +C 45 ; WX 549 ; N minus ; B 11 233 535 288 ; +C 46 ; WX 250 ; N period ; B 69 -17 181 95 ; +C 47 ; WX 278 ; N slash ; B 0 -18 254 646 ; +C 48 ; WX 500 ; N zero ; B 24 -14 476 685 ; +C 49 ; WX 500 ; N one ; B 117 0 390 673 ; +C 50 ; WX 500 ; N two ; B 25 0 475 685 ; +C 51 ; WX 500 ; N three ; B 43 -14 435 685 ; +C 52 ; WX 500 ; N four ; B 15 0 469 685 ; +C 53 ; WX 500 ; N five ; B 32 -14 445 690 ; +C 54 ; WX 500 ; N six ; B 34 -14 468 685 ; +C 55 ; WX 500 ; N seven ; B 24 -16 448 673 ; +C 56 ; WX 500 ; N eight ; B 56 -14 445 685 ; +C 57 ; WX 500 ; N nine ; B 30 -18 459 685 ; +C 58 ; WX 278 ; N colon ; B 81 -17 193 460 ; +C 59 ; WX 278 ; N semicolon ; B 83 -152 221 460 ; +C 60 ; WX 549 ; N less ; B 26 0 523 522 ; +C 61 ; WX 549 ; N equal ; B 11 141 537 390 ; +C 62 ; WX 549 ; N greater ; B 26 0 523 522 ; +C 63 ; WX 444 ; N question ; B 70 -17 412 686 ; +C 64 ; WX 549 ; N congruent ; B 11 0 537 475 ; +C 65 ; WX 722 ; N Alpha ; B 4 0 684 673 ; +C 66 ; WX 667 ; N Beta ; B 29 0 592 673 ; +C 67 ; WX 722 ; N Chi ; B -9 0 704 673 ; +C 68 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C 69 ; WX 611 ; N Epsilon ; B 32 0 617 673 ; +C 70 ; WX 763 ; N Phi ; B 26 0 741 673 ; +C 71 ; WX 603 ; N Gamma ; B 24 0 609 673 ; +C 72 ; WX 722 ; N Eta ; B 39 0 729 673 ; +C 73 ; WX 333 ; N Iota ; B 32 0 316 673 ; +C 74 ; WX 631 ; N theta1 ; B 18 -18 623 689 ; +C 75 ; WX 722 ; N Kappa ; B 35 0 722 673 ; +C 76 ; WX 686 ; N Lambda ; B 6 0 680 688 ; +C 77 ; WX 889 ; N Mu ; B 28 0 887 673 ; +C 78 ; WX 722 ; N Nu ; B 29 -8 720 673 ; +C 79 ; WX 722 ; N Omicron ; B 41 -17 715 685 ; +C 80 ; WX 768 ; N Pi ; B 25 0 745 673 ; +C 81 ; WX 741 ; N Theta ; B 41 -17 715 685 ; +C 82 ; WX 556 ; N Rho ; B 28 0 563 673 ; +C 83 ; WX 592 ; N Sigma ; B 5 0 589 673 ; +C 84 ; WX 611 ; N Tau ; B 33 0 607 673 ; +C 85 ; WX 690 ; N Upsilon ; B -8 0 694 673 ; +C 86 ; WX 439 ; N sigma1 ; B 40 -233 436 500 ; +C 87 ; WX 768 ; N Omega ; B 34 0 736 688 ; +C 88 ; WX 645 ; N Xi ; B 40 0 599 673 ; +C 89 ; WX 795 ; N Psi ; B 15 0 781 684 ; +C 90 ; WX 611 ; N Zeta ; B 44 0 636 673 ; +C 91 ; WX 333 ; N bracketleft ; B 86 -155 299 674 ; +C 92 ; WX 863 ; N therefore ; B 163 0 701 487 ; +C 93 ; WX 333 ; N bracketright ; B 33 -155 246 674 ; +C 94 ; WX 658 ; N perpendicular ; B 15 0 652 674 ; +C 95 ; WX 500 ; N underscore ; B -2 -125 502 -75 ; +C 96 ; WX 500 ; N radicalex ; B 480 881 1090 917 ; +C 97 ; WX 631 ; N alpha ; B 41 -18 622 500 ; +C 98 ; WX 549 ; N beta ; B 61 -223 515 741 ; +C 99 ; WX 549 ; N chi ; B 12 -231 522 499 ; +C 100 ; WX 494 ; N delta ; B 40 -19 481 740 ; +C 101 ; WX 439 ; N epsilon ; B 22 -19 427 502 ; +C 102 ; WX 521 ; N phi ; B 28 -224 492 673 ; +C 103 ; WX 411 ; N gamma ; B 5 -225 484 499 ; +C 104 ; WX 603 ; N eta ; B 0 -202 527 514 ; +C 105 ; WX 329 ; N iota ; B 0 -17 301 503 ; +C 106 ; WX 603 ; N phi1 ; B 36 -224 587 499 ; +C 107 ; WX 549 ; N kappa ; B 33 0 558 501 ; +C 108 ; WX 549 ; N lambda ; B 24 -17 548 739 ; +C 109 ; WX 576 ; N mu ; B 33 -223 567 500 ; +C 110 ; WX 521 ; N nu ; B -9 -16 475 507 ; +C 111 ; WX 549 ; N omicron ; B 35 -19 501 499 ; +C 112 ; WX 549 ; N pi ; B 10 -19 530 487 ; +C 113 ; WX 521 ; N theta ; B 43 -17 485 690 ; +C 114 ; WX 549 ; N rho ; B 50 -230 490 499 ; +C 115 ; WX 603 ; N sigma ; B 30 -21 588 500 ; +C 116 ; WX 439 ; N tau ; B 10 -19 418 500 ; +C 117 ; WX 576 ; N upsilon ; B 7 -18 535 507 ; +C 118 ; WX 713 ; N omega1 ; B 12 -18 671 583 ; +C 119 ; WX 686 ; N omega ; B 42 -17 684 500 ; +C 120 ; WX 493 ; N xi ; B 27 -224 469 766 ; +C 121 ; WX 686 ; N psi ; B 12 -228 701 500 ; +C 122 ; WX 494 ; N zeta ; B 60 -225 467 756 ; +C 123 ; WX 480 ; N braceleft ; B 58 -183 397 673 ; +C 124 ; WX 200 ; N bar ; B 65 -293 135 707 ; +C 125 ; WX 480 ; N braceright ; B 79 -183 418 673 ; +C 126 ; WX 549 ; N similar ; B 17 203 529 307 ; +C 160 ; WX 750 ; N Euro ; B 20 -12 714 685 ; +C 161 ; WX 620 ; N Upsilon1 ; B -2 0 610 685 ; +C 162 ; WX 247 ; N minute ; B 27 459 228 735 ; +C 163 ; WX 549 ; N lessequal ; B 29 0 526 639 ; +C 164 ; WX 167 ; N fraction ; B -180 -12 340 677 ; +C 165 ; WX 713 ; N infinity ; B 26 124 688 404 ; +C 166 ; WX 500 ; N florin ; B 2 -193 494 686 ; +C 167 ; WX 753 ; N club ; B 86 -26 660 533 ; +C 168 ; WX 753 ; N diamond ; B 142 -36 600 550 ; +C 169 ; WX 753 ; N heart ; B 117 -33 631 532 ; +C 170 ; WX 753 ; N spade ; B 113 -36 629 548 ; +C 171 ; WX 1042 ; N arrowboth ; B 24 -15 1024 511 ; +C 172 ; WX 987 ; N arrowleft ; B 32 -15 942 511 ; +C 173 ; WX 603 ; N arrowup ; B 45 0 571 910 ; +C 174 ; WX 987 ; N arrowright ; B 49 -15 959 511 ; +C 175 ; WX 603 ; N arrowdown ; B 45 -22 571 888 ; +C 176 ; WX 400 ; N degree ; B 50 385 350 685 ; +C 177 ; WX 549 ; N plusminus ; B 10 0 539 645 ; +C 178 ; WX 411 ; N second ; B 20 459 413 737 ; +C 179 ; WX 549 ; N greaterequal ; B 29 0 526 639 ; +C 180 ; WX 549 ; N multiply ; B 17 8 533 524 ; +C 181 ; WX 713 ; N proportional ; B 27 123 639 404 ; +C 182 ; WX 494 ; N partialdiff ; B 26 -20 462 746 ; +C 183 ; WX 460 ; N bullet ; B 50 113 410 473 ; +C 184 ; WX 549 ; N divide ; B 10 71 536 456 ; +C 185 ; WX 549 ; N notequal ; B 15 -25 540 549 ; +C 186 ; WX 549 ; N equivalence ; B 14 82 538 443 ; +C 187 ; WX 549 ; N approxequal ; B 14 135 527 394 ; +C 188 ; WX 1000 ; N ellipsis ; B 111 -17 889 95 ; +C 189 ; WX 603 ; N arrowvertex ; B 280 -120 336 1010 ; +C 190 ; WX 1000 ; N arrowhorizex ; B -60 220 1050 276 ; +C 191 ; WX 658 ; N carriagereturn ; B 15 -16 602 629 ; +C 192 ; WX 823 ; N aleph ; B 175 -18 661 658 ; +C 193 ; WX 686 ; N Ifraktur ; B 10 -53 578 740 ; +C 194 ; WX 795 ; N Rfraktur ; B 26 -15 759 734 ; +C 195 ; WX 987 ; N weierstrass ; B 159 -211 870 573 ; +C 196 ; WX 768 ; N circlemultiply ; B 43 -17 733 673 ; +C 197 ; WX 768 ; N circleplus ; B 43 -15 733 675 ; +C 198 ; WX 823 ; N emptyset ; B 39 -24 781 719 ; +C 199 ; WX 768 ; N intersection ; B 40 0 732 509 ; +C 200 ; WX 768 ; N union ; B 40 -17 732 492 ; +C 201 ; WX 713 ; N properbaseset ; B 20 0 673 470 ; +C 202 ; WX 713 ; N reflexbaseset ; B 20 -125 673 470 ; +C 203 ; WX 713 ; N notsubset ; B 36 -70 690 540 ; +C 204 ; WX 713 ; N propersubset ; B 37 0 690 470 ; +C 205 ; WX 713 ; N reflexsubset ; B 37 -125 690 470 ; +C 206 ; WX 713 ; N element ; B 45 0 505 468 ; +C 207 ; WX 713 ; N notelement ; B 45 -58 505 555 ; +C 208 ; WX 768 ; N angle ; B 26 0 738 673 ; +C 209 ; WX 713 ; N gradient ; B 36 -19 681 718 ; +C 210 ; WX 790 ; N registerserif ; B 50 -17 740 673 ; +C 211 ; WX 790 ; N copyrightserif ; B 51 -15 741 675 ; +C 212 ; WX 890 ; N trademarkserif ; B 18 293 855 673 ; +C 213 ; WX 823 ; N product ; B 25 -101 803 751 ; +C 214 ; WX 549 ; N radical ; B 10 -38 515 917 ; +C 215 ; WX 250 ; N dotmath ; B 69 210 169 310 ; +C 216 ; WX 713 ; N logicalnot ; B 15 0 680 288 ; +C 217 ; WX 603 ; N logicaland ; B 23 0 583 454 ; +C 218 ; WX 603 ; N logicalor ; B 30 0 578 477 ; +C 219 ; WX 1042 ; N arrowdblboth ; B 27 -20 1023 510 ; +C 220 ; WX 987 ; N arrowdblleft ; B 30 -15 939 513 ; +C 221 ; WX 603 ; N arrowdblup ; B 39 2 567 911 ; +C 222 ; WX 987 ; N arrowdblright ; B 45 -20 954 508 ; +C 223 ; WX 603 ; N arrowdbldown ; B 44 -19 572 890 ; +C 224 ; WX 494 ; N lozenge ; B 18 0 466 745 ; +C 225 ; WX 329 ; N angleleft ; B 25 -198 306 746 ; +C 226 ; WX 790 ; N registersans ; B 50 -20 740 670 ; +C 227 ; WX 790 ; N copyrightsans ; B 49 -15 739 675 ; +C 228 ; WX 786 ; N trademarksans ; B 5 293 725 673 ; +C 229 ; WX 713 ; N summation ; B 14 -108 695 752 ; +C 230 ; WX 384 ; N parenlefttp ; B 24 -293 436 926 ; +C 231 ; WX 384 ; N parenleftex ; B 24 -85 108 925 ; +C 232 ; WX 384 ; N parenleftbt ; B 24 -293 436 926 ; +C 233 ; WX 384 ; N bracketlefttp ; B 0 -80 349 926 ; +C 234 ; WX 384 ; N bracketleftex ; B 0 -79 77 925 ; +C 235 ; WX 384 ; N bracketleftbt ; B 0 -80 349 926 ; +C 236 ; WX 494 ; N bracelefttp ; B 209 -85 445 925 ; +C 237 ; WX 494 ; N braceleftmid ; B 20 -85 284 935 ; +C 238 ; WX 494 ; N braceleftbt ; B 209 -75 445 935 ; +C 239 ; WX 494 ; N braceex ; B 209 -85 284 935 ; +C 241 ; WX 329 ; N angleright ; B 21 -198 302 746 ; +C 242 ; WX 274 ; N integral ; B 2 -107 291 916 ; +C 243 ; WX 686 ; N integraltp ; B 308 -88 675 920 ; +C 244 ; WX 686 ; N integralex ; B 308 -88 378 975 ; +C 245 ; WX 686 ; N integralbt ; B 11 -87 378 921 ; +C 246 ; WX 384 ; N parenrighttp ; B 54 -293 466 926 ; +C 247 ; WX 384 ; N parenrightex ; B 382 -85 466 925 ; +C 248 ; WX 384 ; N parenrightbt ; B 54 -293 466 926 ; +C 249 ; WX 384 ; N bracketrighttp ; B 22 -80 371 926 ; +C 250 ; WX 384 ; N bracketrightex ; B 294 -79 371 925 ; +C 251 ; WX 384 ; N bracketrightbt ; B 22 -80 371 926 ; +C 252 ; WX 494 ; N bracerighttp ; B 48 -85 284 925 ; +C 253 ; WX 494 ; N bracerightmid ; B 209 -85 473 935 ; +C 254 ; WX 494 ; N bracerightbt ; B 48 -75 284 935 ; +C -1 ; WX 790 ; N apple ; B 56 -3 733 808 ; +EndCharMetrics +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Times-Bold.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Times-Bold.afm new file mode 100644 index 0000000..ecd30f7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Times-Bold.afm @@ -0,0 +1,2588 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:52:56 1997 +Comment UniqueID 43065 +Comment VMusage 41636 52661 +FontName Times-Bold +FullName Times Bold +FamilyName Times +Weight Bold +ItalicAngle 0 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -168 -218 1000 935 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 676 +XHeight 461 +Ascender 683 +Descender -217 +StdHW 44 +StdVW 139 +StartCharMetrics 315 +C 32 ; WX 250 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 81 -13 251 691 ; +C 34 ; WX 555 ; N quotedbl ; B 83 404 472 691 ; +C 35 ; WX 500 ; N numbersign ; B 4 0 496 700 ; +C 36 ; WX 500 ; N dollar ; B 29 -99 472 750 ; +C 37 ; WX 1000 ; N percent ; B 124 -14 877 692 ; +C 38 ; WX 833 ; N ampersand ; B 62 -16 787 691 ; +C 39 ; WX 333 ; N quoteright ; B 79 356 263 691 ; +C 40 ; WX 333 ; N parenleft ; B 46 -168 306 694 ; +C 41 ; WX 333 ; N parenright ; B 27 -168 287 694 ; +C 42 ; WX 500 ; N asterisk ; B 56 255 447 691 ; +C 43 ; WX 570 ; N plus ; B 33 0 537 506 ; +C 44 ; WX 250 ; N comma ; B 39 -180 223 155 ; +C 45 ; WX 333 ; N hyphen ; B 44 171 287 287 ; +C 46 ; WX 250 ; N period ; B 41 -13 210 156 ; +C 47 ; WX 278 ; N slash ; B -24 -19 302 691 ; +C 48 ; WX 500 ; N zero ; B 24 -13 476 688 ; +C 49 ; WX 500 ; N one ; B 65 0 442 688 ; +C 50 ; WX 500 ; N two ; B 17 0 478 688 ; +C 51 ; WX 500 ; N three ; B 16 -14 468 688 ; +C 52 ; WX 500 ; N four ; B 19 0 475 688 ; +C 53 ; WX 500 ; N five ; B 22 -8 470 676 ; +C 54 ; WX 500 ; N six ; B 28 -13 475 688 ; +C 55 ; WX 500 ; N seven ; B 17 0 477 676 ; +C 56 ; WX 500 ; N eight ; B 28 -13 472 688 ; +C 57 ; WX 500 ; N nine ; B 26 -13 473 688 ; +C 58 ; WX 333 ; N colon ; B 82 -13 251 472 ; +C 59 ; WX 333 ; N semicolon ; B 82 -180 266 472 ; +C 60 ; WX 570 ; N less ; B 31 -8 539 514 ; +C 61 ; WX 570 ; N equal ; B 33 107 537 399 ; +C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ; +C 63 ; WX 500 ; N question ; B 57 -13 445 689 ; +C 64 ; WX 930 ; N at ; B 108 -19 822 691 ; +C 65 ; WX 722 ; N A ; B 9 0 689 690 ; +C 66 ; WX 667 ; N B ; B 16 0 619 676 ; +C 67 ; WX 722 ; N C ; B 49 -19 687 691 ; +C 68 ; WX 722 ; N D ; B 14 0 690 676 ; +C 69 ; WX 667 ; N E ; B 16 0 641 676 ; +C 70 ; WX 611 ; N F ; B 16 0 583 676 ; +C 71 ; WX 778 ; N G ; B 37 -19 755 691 ; +C 72 ; WX 778 ; N H ; B 21 0 759 676 ; +C 73 ; WX 389 ; N I ; B 20 0 370 676 ; +C 74 ; WX 500 ; N J ; B 3 -96 479 676 ; +C 75 ; WX 778 ; N K ; B 30 0 769 676 ; +C 76 ; WX 667 ; N L ; B 19 0 638 676 ; +C 77 ; WX 944 ; N M ; B 14 0 921 676 ; +C 78 ; WX 722 ; N N ; B 16 -18 701 676 ; +C 79 ; WX 778 ; N O ; B 35 -19 743 691 ; +C 80 ; WX 611 ; N P ; B 16 0 600 676 ; +C 81 ; WX 778 ; N Q ; B 35 -176 743 691 ; +C 82 ; WX 722 ; N R ; B 26 0 715 676 ; +C 83 ; WX 556 ; N S ; B 35 -19 513 692 ; +C 84 ; WX 667 ; N T ; B 31 0 636 676 ; +C 85 ; WX 722 ; N U ; B 16 -19 701 676 ; +C 86 ; WX 722 ; N V ; B 16 -18 701 676 ; +C 87 ; WX 1000 ; N W ; B 19 -15 981 676 ; +C 88 ; WX 722 ; N X ; B 16 0 699 676 ; +C 89 ; WX 722 ; N Y ; B 15 0 699 676 ; +C 90 ; WX 667 ; N Z ; B 28 0 634 676 ; +C 91 ; WX 333 ; N bracketleft ; B 67 -149 301 678 ; +C 92 ; WX 278 ; N backslash ; B -25 -19 303 691 ; +C 93 ; WX 333 ; N bracketright ; B 32 -149 266 678 ; +C 94 ; WX 581 ; N asciicircum ; B 73 311 509 676 ; +C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ; +C 96 ; WX 333 ; N quoteleft ; B 70 356 254 691 ; +C 97 ; WX 500 ; N a ; B 25 -14 488 473 ; +C 98 ; WX 556 ; N b ; B 17 -14 521 676 ; +C 99 ; WX 444 ; N c ; B 25 -14 430 473 ; +C 100 ; WX 556 ; N d ; B 25 -14 534 676 ; +C 101 ; WX 444 ; N e ; B 25 -14 426 473 ; +C 102 ; WX 333 ; N f ; B 14 0 389 691 ; L i fi ; L l fl ; +C 103 ; WX 500 ; N g ; B 28 -206 483 473 ; +C 104 ; WX 556 ; N h ; B 16 0 534 676 ; +C 105 ; WX 278 ; N i ; B 16 0 255 691 ; +C 106 ; WX 333 ; N j ; B -57 -203 263 691 ; +C 107 ; WX 556 ; N k ; B 22 0 543 676 ; +C 108 ; WX 278 ; N l ; B 16 0 255 676 ; +C 109 ; WX 833 ; N m ; B 16 0 814 473 ; +C 110 ; WX 556 ; N n ; B 21 0 539 473 ; +C 111 ; WX 500 ; N o ; B 25 -14 476 473 ; +C 112 ; WX 556 ; N p ; B 19 -205 524 473 ; +C 113 ; WX 556 ; N q ; B 34 -205 536 473 ; +C 114 ; WX 444 ; N r ; B 29 0 434 473 ; +C 115 ; WX 389 ; N s ; B 25 -14 361 473 ; +C 116 ; WX 333 ; N t ; B 20 -12 332 630 ; +C 117 ; WX 556 ; N u ; B 16 -14 537 461 ; +C 118 ; WX 500 ; N v ; B 21 -14 485 461 ; +C 119 ; WX 722 ; N w ; B 23 -14 707 461 ; +C 120 ; WX 500 ; N x ; B 12 0 484 461 ; +C 121 ; WX 500 ; N y ; B 16 -205 480 461 ; +C 122 ; WX 444 ; N z ; B 21 0 420 461 ; +C 123 ; WX 394 ; N braceleft ; B 22 -175 340 698 ; +C 124 ; WX 220 ; N bar ; B 66 -218 154 782 ; +C 125 ; WX 394 ; N braceright ; B 54 -175 372 698 ; +C 126 ; WX 520 ; N asciitilde ; B 29 173 491 333 ; +C 161 ; WX 333 ; N exclamdown ; B 82 -203 252 501 ; +C 162 ; WX 500 ; N cent ; B 53 -140 458 588 ; +C 163 ; WX 500 ; N sterling ; B 21 -14 477 684 ; +C 164 ; WX 167 ; N fraction ; B -168 -12 329 688 ; +C 165 ; WX 500 ; N yen ; B -64 0 547 676 ; +C 166 ; WX 500 ; N florin ; B 0 -155 498 706 ; +C 167 ; WX 500 ; N section ; B 57 -132 443 691 ; +C 168 ; WX 500 ; N currency ; B -26 61 526 613 ; +C 169 ; WX 278 ; N quotesingle ; B 75 404 204 691 ; +C 170 ; WX 500 ; N quotedblleft ; B 32 356 486 691 ; +C 171 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ; +C 172 ; WX 333 ; N guilsinglleft ; B 51 36 305 415 ; +C 173 ; WX 333 ; N guilsinglright ; B 28 36 282 415 ; +C 174 ; WX 556 ; N fi ; B 14 0 536 691 ; +C 175 ; WX 556 ; N fl ; B 14 0 536 691 ; +C 177 ; WX 500 ; N endash ; B 0 181 500 271 ; +C 178 ; WX 500 ; N dagger ; B 47 -134 453 691 ; +C 179 ; WX 500 ; N daggerdbl ; B 45 -132 456 691 ; +C 180 ; WX 250 ; N periodcentered ; B 41 248 210 417 ; +C 182 ; WX 540 ; N paragraph ; B 0 -186 519 676 ; +C 183 ; WX 350 ; N bullet ; B 35 198 315 478 ; +C 184 ; WX 333 ; N quotesinglbase ; B 79 -180 263 155 ; +C 185 ; WX 500 ; N quotedblbase ; B 14 -180 468 155 ; +C 186 ; WX 500 ; N quotedblright ; B 14 356 468 691 ; +C 187 ; WX 500 ; N guillemotright ; B 27 36 477 415 ; +C 188 ; WX 1000 ; N ellipsis ; B 82 -13 917 156 ; +C 189 ; WX 1000 ; N perthousand ; B 7 -29 995 706 ; +C 191 ; WX 500 ; N questiondown ; B 55 -201 443 501 ; +C 193 ; WX 333 ; N grave ; B 8 528 246 713 ; +C 194 ; WX 333 ; N acute ; B 86 528 324 713 ; +C 195 ; WX 333 ; N circumflex ; B -2 528 335 704 ; +C 196 ; WX 333 ; N tilde ; B -16 547 349 674 ; +C 197 ; WX 333 ; N macron ; B 1 565 331 637 ; +C 198 ; WX 333 ; N breve ; B 15 528 318 691 ; +C 199 ; WX 333 ; N dotaccent ; B 103 536 258 691 ; +C 200 ; WX 333 ; N dieresis ; B -2 537 335 667 ; +C 202 ; WX 333 ; N ring ; B 60 527 273 740 ; +C 203 ; WX 333 ; N cedilla ; B 68 -218 294 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B -13 528 425 713 ; +C 206 ; WX 333 ; N ogonek ; B 90 -193 319 24 ; +C 207 ; WX 333 ; N caron ; B -2 528 335 704 ; +C 208 ; WX 1000 ; N emdash ; B 0 181 1000 271 ; +C 225 ; WX 1000 ; N AE ; B 4 0 951 676 ; +C 227 ; WX 300 ; N ordfeminine ; B -1 397 301 688 ; +C 232 ; WX 667 ; N Lslash ; B 19 0 638 676 ; +C 233 ; WX 778 ; N Oslash ; B 35 -74 743 737 ; +C 234 ; WX 1000 ; N OE ; B 22 -5 981 684 ; +C 235 ; WX 330 ; N ordmasculine ; B 18 397 312 688 ; +C 241 ; WX 722 ; N ae ; B 33 -14 693 473 ; +C 245 ; WX 278 ; N dotlessi ; B 16 0 255 461 ; +C 248 ; WX 278 ; N lslash ; B -22 0 303 676 ; +C 249 ; WX 500 ; N oslash ; B 25 -92 476 549 ; +C 250 ; WX 722 ; N oe ; B 22 -14 696 473 ; +C 251 ; WX 556 ; N germandbls ; B 19 -12 517 691 ; +C -1 ; WX 389 ; N Idieresis ; B 20 0 370 877 ; +C -1 ; WX 444 ; N eacute ; B 25 -14 426 713 ; +C -1 ; WX 500 ; N abreve ; B 25 -14 488 691 ; +C -1 ; WX 556 ; N uhungarumlaut ; B 16 -14 557 713 ; +C -1 ; WX 444 ; N ecaron ; B 25 -14 426 704 ; +C -1 ; WX 722 ; N Ydieresis ; B 15 0 699 877 ; +C -1 ; WX 570 ; N divide ; B 33 -31 537 537 ; +C -1 ; WX 722 ; N Yacute ; B 15 0 699 923 ; +C -1 ; WX 722 ; N Acircumflex ; B 9 0 689 914 ; +C -1 ; WX 500 ; N aacute ; B 25 -14 488 713 ; +C -1 ; WX 722 ; N Ucircumflex ; B 16 -19 701 914 ; +C -1 ; WX 500 ; N yacute ; B 16 -205 480 713 ; +C -1 ; WX 389 ; N scommaaccent ; B 25 -218 361 473 ; +C -1 ; WX 444 ; N ecircumflex ; B 25 -14 426 704 ; +C -1 ; WX 722 ; N Uring ; B 16 -19 701 935 ; +C -1 ; WX 722 ; N Udieresis ; B 16 -19 701 877 ; +C -1 ; WX 500 ; N aogonek ; B 25 -193 504 473 ; +C -1 ; WX 722 ; N Uacute ; B 16 -19 701 923 ; +C -1 ; WX 556 ; N uogonek ; B 16 -193 539 461 ; +C -1 ; WX 667 ; N Edieresis ; B 16 0 641 877 ; +C -1 ; WX 722 ; N Dcroat ; B 6 0 690 676 ; +C -1 ; WX 250 ; N commaaccent ; B 47 -218 203 -50 ; +C -1 ; WX 747 ; N copyright ; B 26 -19 721 691 ; +C -1 ; WX 667 ; N Emacron ; B 16 0 641 847 ; +C -1 ; WX 444 ; N ccaron ; B 25 -14 430 704 ; +C -1 ; WX 500 ; N aring ; B 25 -14 488 740 ; +C -1 ; WX 722 ; N Ncommaaccent ; B 16 -188 701 676 ; +C -1 ; WX 278 ; N lacute ; B 16 0 297 923 ; +C -1 ; WX 500 ; N agrave ; B 25 -14 488 713 ; +C -1 ; WX 667 ; N Tcommaaccent ; B 31 -218 636 676 ; +C -1 ; WX 722 ; N Cacute ; B 49 -19 687 923 ; +C -1 ; WX 500 ; N atilde ; B 25 -14 488 674 ; +C -1 ; WX 667 ; N Edotaccent ; B 16 0 641 901 ; +C -1 ; WX 389 ; N scaron ; B 25 -14 363 704 ; +C -1 ; WX 389 ; N scedilla ; B 25 -218 361 473 ; +C -1 ; WX 278 ; N iacute ; B 16 0 289 713 ; +C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ; +C -1 ; WX 722 ; N Rcaron ; B 26 0 715 914 ; +C -1 ; WX 778 ; N Gcommaaccent ; B 37 -218 755 691 ; +C -1 ; WX 556 ; N ucircumflex ; B 16 -14 537 704 ; +C -1 ; WX 500 ; N acircumflex ; B 25 -14 488 704 ; +C -1 ; WX 722 ; N Amacron ; B 9 0 689 847 ; +C -1 ; WX 444 ; N rcaron ; B 29 0 434 704 ; +C -1 ; WX 444 ; N ccedilla ; B 25 -218 430 473 ; +C -1 ; WX 667 ; N Zdotaccent ; B 28 0 634 901 ; +C -1 ; WX 611 ; N Thorn ; B 16 0 600 676 ; +C -1 ; WX 778 ; N Omacron ; B 35 -19 743 847 ; +C -1 ; WX 722 ; N Racute ; B 26 0 715 923 ; +C -1 ; WX 556 ; N Sacute ; B 35 -19 513 923 ; +C -1 ; WX 672 ; N dcaron ; B 25 -14 681 682 ; +C -1 ; WX 722 ; N Umacron ; B 16 -19 701 847 ; +C -1 ; WX 556 ; N uring ; B 16 -14 537 740 ; +C -1 ; WX 300 ; N threebaseior ; B 3 268 297 688 ; +C -1 ; WX 778 ; N Ograve ; B 35 -19 743 923 ; +C -1 ; WX 722 ; N Agrave ; B 9 0 689 923 ; +C -1 ; WX 722 ; N Abreve ; B 9 0 689 901 ; +C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ; +C -1 ; WX 556 ; N uacute ; B 16 -14 537 713 ; +C -1 ; WX 667 ; N Tcaron ; B 31 0 636 914 ; +C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ; +C -1 ; WX 500 ; N ydieresis ; B 16 -205 480 667 ; +C -1 ; WX 722 ; N Nacute ; B 16 -18 701 923 ; +C -1 ; WX 278 ; N icircumflex ; B -37 0 300 704 ; +C -1 ; WX 667 ; N Ecircumflex ; B 16 0 641 914 ; +C -1 ; WX 500 ; N adieresis ; B 25 -14 488 667 ; +C -1 ; WX 444 ; N edieresis ; B 25 -14 426 667 ; +C -1 ; WX 444 ; N cacute ; B 25 -14 430 713 ; +C -1 ; WX 556 ; N nacute ; B 21 0 539 713 ; +C -1 ; WX 556 ; N umacron ; B 16 -14 537 637 ; +C -1 ; WX 722 ; N Ncaron ; B 16 -18 701 914 ; +C -1 ; WX 389 ; N Iacute ; B 20 0 370 923 ; +C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ; +C -1 ; WX 220 ; N brokenbar ; B 66 -143 154 707 ; +C -1 ; WX 747 ; N registered ; B 26 -19 721 691 ; +C -1 ; WX 778 ; N Gbreve ; B 37 -19 755 901 ; +C -1 ; WX 389 ; N Idotaccent ; B 20 0 370 901 ; +C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ; +C -1 ; WX 667 ; N Egrave ; B 16 0 641 923 ; +C -1 ; WX 444 ; N racute ; B 29 0 434 713 ; +C -1 ; WX 500 ; N omacron ; B 25 -14 476 637 ; +C -1 ; WX 667 ; N Zacute ; B 28 0 634 923 ; +C -1 ; WX 667 ; N Zcaron ; B 28 0 634 914 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ; +C -1 ; WX 722 ; N Eth ; B 6 0 690 676 ; +C -1 ; WX 722 ; N Ccedilla ; B 49 -218 687 691 ; +C -1 ; WX 278 ; N lcommaaccent ; B 16 -218 255 676 ; +C -1 ; WX 416 ; N tcaron ; B 20 -12 425 815 ; +C -1 ; WX 444 ; N eogonek ; B 25 -193 426 473 ; +C -1 ; WX 722 ; N Uogonek ; B 16 -193 701 676 ; +C -1 ; WX 722 ; N Aacute ; B 9 0 689 923 ; +C -1 ; WX 722 ; N Adieresis ; B 9 0 689 877 ; +C -1 ; WX 444 ; N egrave ; B 25 -14 426 713 ; +C -1 ; WX 444 ; N zacute ; B 21 0 420 713 ; +C -1 ; WX 278 ; N iogonek ; B 16 -193 274 691 ; +C -1 ; WX 778 ; N Oacute ; B 35 -19 743 923 ; +C -1 ; WX 500 ; N oacute ; B 25 -14 476 713 ; +C -1 ; WX 500 ; N amacron ; B 25 -14 488 637 ; +C -1 ; WX 389 ; N sacute ; B 25 -14 361 713 ; +C -1 ; WX 278 ; N idieresis ; B -37 0 300 667 ; +C -1 ; WX 778 ; N Ocircumflex ; B 35 -19 743 914 ; +C -1 ; WX 722 ; N Ugrave ; B 16 -19 701 923 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 556 ; N thorn ; B 19 -205 524 676 ; +C -1 ; WX 300 ; N twobaseior ; B 0 275 300 688 ; +C -1 ; WX 778 ; N Odieresis ; B 35 -19 743 877 ; +C -1 ; WX 556 ; N mu ; B 33 -206 536 461 ; +C -1 ; WX 278 ; N igrave ; B -27 0 255 713 ; +C -1 ; WX 500 ; N ohungarumlaut ; B 25 -14 529 713 ; +C -1 ; WX 667 ; N Eogonek ; B 16 -193 644 676 ; +C -1 ; WX 556 ; N dcroat ; B 25 -14 534 676 ; +C -1 ; WX 750 ; N threequarters ; B 23 -12 733 688 ; +C -1 ; WX 556 ; N Scedilla ; B 35 -218 513 692 ; +C -1 ; WX 394 ; N lcaron ; B 16 0 412 682 ; +C -1 ; WX 778 ; N Kcommaaccent ; B 30 -218 769 676 ; +C -1 ; WX 667 ; N Lacute ; B 19 0 638 923 ; +C -1 ; WX 1000 ; N trademark ; B 24 271 977 676 ; +C -1 ; WX 444 ; N edotaccent ; B 25 -14 426 691 ; +C -1 ; WX 389 ; N Igrave ; B 20 0 370 923 ; +C -1 ; WX 389 ; N Imacron ; B 20 0 370 847 ; +C -1 ; WX 667 ; N Lcaron ; B 19 0 652 682 ; +C -1 ; WX 750 ; N onehalf ; B -7 -12 775 688 ; +C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ; +C -1 ; WX 500 ; N ocircumflex ; B 25 -14 476 704 ; +C -1 ; WX 556 ; N ntilde ; B 21 0 539 674 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 16 -19 701 923 ; +C -1 ; WX 667 ; N Eacute ; B 16 0 641 923 ; +C -1 ; WX 444 ; N emacron ; B 25 -14 426 637 ; +C -1 ; WX 500 ; N gbreve ; B 28 -206 483 691 ; +C -1 ; WX 750 ; N onequarter ; B 28 -12 743 688 ; +C -1 ; WX 556 ; N Scaron ; B 35 -19 513 914 ; +C -1 ; WX 556 ; N Scommaaccent ; B 35 -218 513 692 ; +C -1 ; WX 778 ; N Ohungarumlaut ; B 35 -19 743 923 ; +C -1 ; WX 400 ; N degree ; B 57 402 343 688 ; +C -1 ; WX 500 ; N ograve ; B 25 -14 476 713 ; +C -1 ; WX 722 ; N Ccaron ; B 49 -19 687 914 ; +C -1 ; WX 556 ; N ugrave ; B 16 -14 537 713 ; +C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ; +C -1 ; WX 722 ; N Dcaron ; B 14 0 690 914 ; +C -1 ; WX 444 ; N rcommaaccent ; B 29 -218 434 473 ; +C -1 ; WX 722 ; N Ntilde ; B 16 -18 701 884 ; +C -1 ; WX 500 ; N otilde ; B 25 -14 476 674 ; +C -1 ; WX 722 ; N Rcommaaccent ; B 26 -218 715 676 ; +C -1 ; WX 667 ; N Lcommaaccent ; B 19 -218 638 676 ; +C -1 ; WX 722 ; N Atilde ; B 9 0 689 884 ; +C -1 ; WX 722 ; N Aogonek ; B 9 -193 699 690 ; +C -1 ; WX 722 ; N Aring ; B 9 0 689 935 ; +C -1 ; WX 778 ; N Otilde ; B 35 -19 743 884 ; +C -1 ; WX 444 ; N zdotaccent ; B 21 0 420 691 ; +C -1 ; WX 667 ; N Ecaron ; B 16 0 641 914 ; +C -1 ; WX 389 ; N Iogonek ; B 20 -193 370 676 ; +C -1 ; WX 556 ; N kcommaaccent ; B 22 -218 543 676 ; +C -1 ; WX 570 ; N minus ; B 33 209 537 297 ; +C -1 ; WX 389 ; N Icircumflex ; B 20 0 370 914 ; +C -1 ; WX 556 ; N ncaron ; B 21 0 539 704 ; +C -1 ; WX 333 ; N tcommaaccent ; B 20 -218 332 630 ; +C -1 ; WX 570 ; N logicalnot ; B 33 108 537 399 ; +C -1 ; WX 500 ; N odieresis ; B 25 -14 476 667 ; +C -1 ; WX 556 ; N udieresis ; B 16 -14 537 667 ; +C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ; +C -1 ; WX 500 ; N gcommaaccent ; B 28 -206 483 829 ; +C -1 ; WX 500 ; N eth ; B 25 -14 476 691 ; +C -1 ; WX 444 ; N zcaron ; B 21 0 420 704 ; +C -1 ; WX 556 ; N ncommaaccent ; B 21 -218 539 473 ; +C -1 ; WX 300 ; N onebaseior ; B 28 275 273 688 ; +C -1 ; WX 278 ; N imacron ; B -8 0 272 637 ; +C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2242 +KPX A C -55 +KPX A Cacute -55 +KPX A Ccaron -55 +KPX A Ccedilla -55 +KPX A G -55 +KPX A Gbreve -55 +KPX A Gcommaaccent -55 +KPX A O -45 +KPX A Oacute -45 +KPX A Ocircumflex -45 +KPX A Odieresis -45 +KPX A Ograve -45 +KPX A Ohungarumlaut -45 +KPX A Omacron -45 +KPX A Oslash -45 +KPX A Otilde -45 +KPX A Q -45 +KPX A T -95 +KPX A Tcaron -95 +KPX A Tcommaaccent -95 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -145 +KPX A W -130 +KPX A Y -100 +KPX A Yacute -100 +KPX A Ydieresis -100 +KPX A p -25 +KPX A quoteright -74 +KPX A u -50 +KPX A uacute -50 +KPX A ucircumflex -50 +KPX A udieresis -50 +KPX A ugrave -50 +KPX A uhungarumlaut -50 +KPX A umacron -50 +KPX A uogonek -50 +KPX A uring -50 +KPX A v -100 +KPX A w -90 +KPX A y -74 +KPX A yacute -74 +KPX A ydieresis -74 +KPX Aacute C -55 +KPX Aacute Cacute -55 +KPX Aacute Ccaron -55 +KPX Aacute Ccedilla -55 +KPX Aacute G -55 +KPX Aacute Gbreve -55 +KPX Aacute Gcommaaccent -55 +KPX Aacute O -45 +KPX Aacute Oacute -45 +KPX Aacute Ocircumflex -45 +KPX Aacute Odieresis -45 +KPX Aacute Ograve -45 +KPX Aacute Ohungarumlaut -45 +KPX Aacute Omacron -45 +KPX Aacute Oslash -45 +KPX Aacute Otilde -45 +KPX Aacute Q -45 +KPX Aacute T -95 +KPX Aacute Tcaron -95 +KPX Aacute Tcommaaccent -95 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -145 +KPX Aacute W -130 +KPX Aacute Y -100 +KPX Aacute Yacute -100 +KPX Aacute Ydieresis -100 +KPX Aacute p -25 +KPX Aacute quoteright -74 +KPX Aacute u -50 +KPX Aacute uacute -50 +KPX Aacute ucircumflex -50 +KPX Aacute udieresis -50 +KPX Aacute ugrave -50 +KPX Aacute uhungarumlaut -50 +KPX Aacute umacron -50 +KPX Aacute uogonek -50 +KPX Aacute uring -50 +KPX Aacute v -100 +KPX Aacute w -90 +KPX Aacute y -74 +KPX Aacute yacute -74 +KPX Aacute ydieresis -74 +KPX Abreve C -55 +KPX Abreve Cacute -55 +KPX Abreve Ccaron -55 +KPX Abreve Ccedilla -55 +KPX Abreve G -55 +KPX Abreve Gbreve -55 +KPX Abreve Gcommaaccent -55 +KPX Abreve O -45 +KPX Abreve Oacute -45 +KPX Abreve Ocircumflex -45 +KPX Abreve Odieresis -45 +KPX Abreve Ograve -45 +KPX Abreve Ohungarumlaut -45 +KPX Abreve Omacron -45 +KPX Abreve Oslash -45 +KPX Abreve Otilde -45 +KPX Abreve Q -45 +KPX Abreve T -95 +KPX Abreve Tcaron -95 +KPX Abreve Tcommaaccent -95 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -145 +KPX Abreve W -130 +KPX Abreve Y -100 +KPX Abreve Yacute -100 +KPX Abreve Ydieresis -100 +KPX Abreve p -25 +KPX Abreve quoteright -74 +KPX Abreve u -50 +KPX Abreve uacute -50 +KPX Abreve ucircumflex -50 +KPX Abreve udieresis -50 +KPX Abreve ugrave -50 +KPX Abreve uhungarumlaut -50 +KPX Abreve umacron -50 +KPX Abreve uogonek -50 +KPX Abreve uring -50 +KPX Abreve v -100 +KPX Abreve w -90 +KPX Abreve y -74 +KPX Abreve yacute -74 +KPX Abreve ydieresis -74 +KPX Acircumflex C -55 +KPX Acircumflex Cacute -55 +KPX Acircumflex Ccaron -55 +KPX Acircumflex Ccedilla -55 +KPX Acircumflex G -55 +KPX Acircumflex Gbreve -55 +KPX Acircumflex Gcommaaccent -55 +KPX Acircumflex O -45 +KPX Acircumflex Oacute -45 +KPX Acircumflex Ocircumflex -45 +KPX Acircumflex Odieresis -45 +KPX Acircumflex Ograve -45 +KPX Acircumflex Ohungarumlaut -45 +KPX Acircumflex Omacron -45 +KPX Acircumflex Oslash -45 +KPX Acircumflex Otilde -45 +KPX Acircumflex Q -45 +KPX Acircumflex T -95 +KPX Acircumflex Tcaron -95 +KPX Acircumflex Tcommaaccent -95 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -145 +KPX Acircumflex W -130 +KPX Acircumflex Y -100 +KPX Acircumflex Yacute -100 +KPX Acircumflex Ydieresis -100 +KPX Acircumflex p -25 +KPX Acircumflex quoteright -74 +KPX Acircumflex u -50 +KPX Acircumflex uacute -50 +KPX Acircumflex ucircumflex -50 +KPX Acircumflex udieresis -50 +KPX Acircumflex ugrave -50 +KPX Acircumflex uhungarumlaut -50 +KPX Acircumflex umacron -50 +KPX Acircumflex uogonek -50 +KPX Acircumflex uring -50 +KPX Acircumflex v -100 +KPX Acircumflex w -90 +KPX Acircumflex y -74 +KPX Acircumflex yacute -74 +KPX Acircumflex ydieresis -74 +KPX Adieresis C -55 +KPX Adieresis Cacute -55 +KPX Adieresis Ccaron -55 +KPX Adieresis Ccedilla -55 +KPX Adieresis G -55 +KPX Adieresis Gbreve -55 +KPX Adieresis Gcommaaccent -55 +KPX Adieresis O -45 +KPX Adieresis Oacute -45 +KPX Adieresis Ocircumflex -45 +KPX Adieresis Odieresis -45 +KPX Adieresis Ograve -45 +KPX Adieresis Ohungarumlaut -45 +KPX Adieresis Omacron -45 +KPX Adieresis Oslash -45 +KPX Adieresis Otilde -45 +KPX Adieresis Q -45 +KPX Adieresis T -95 +KPX Adieresis Tcaron -95 +KPX Adieresis Tcommaaccent -95 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -145 +KPX Adieresis W -130 +KPX Adieresis Y -100 +KPX Adieresis Yacute -100 +KPX Adieresis Ydieresis -100 +KPX Adieresis p -25 +KPX Adieresis quoteright -74 +KPX Adieresis u -50 +KPX Adieresis uacute -50 +KPX Adieresis ucircumflex -50 +KPX Adieresis udieresis -50 +KPX Adieresis ugrave -50 +KPX Adieresis uhungarumlaut -50 +KPX Adieresis umacron -50 +KPX Adieresis uogonek -50 +KPX Adieresis uring -50 +KPX Adieresis v -100 +KPX Adieresis w -90 +KPX Adieresis y -74 +KPX Adieresis yacute -74 +KPX Adieresis ydieresis -74 +KPX Agrave C -55 +KPX Agrave Cacute -55 +KPX Agrave Ccaron -55 +KPX Agrave Ccedilla -55 +KPX Agrave G -55 +KPX Agrave Gbreve -55 +KPX Agrave Gcommaaccent -55 +KPX Agrave O -45 +KPX Agrave Oacute -45 +KPX Agrave Ocircumflex -45 +KPX Agrave Odieresis -45 +KPX Agrave Ograve -45 +KPX Agrave Ohungarumlaut -45 +KPX Agrave Omacron -45 +KPX Agrave Oslash -45 +KPX Agrave Otilde -45 +KPX Agrave Q -45 +KPX Agrave T -95 +KPX Agrave Tcaron -95 +KPX Agrave Tcommaaccent -95 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -145 +KPX Agrave W -130 +KPX Agrave Y -100 +KPX Agrave Yacute -100 +KPX Agrave Ydieresis -100 +KPX Agrave p -25 +KPX Agrave quoteright -74 +KPX Agrave u -50 +KPX Agrave uacute -50 +KPX Agrave ucircumflex -50 +KPX Agrave udieresis -50 +KPX Agrave ugrave -50 +KPX Agrave uhungarumlaut -50 +KPX Agrave umacron -50 +KPX Agrave uogonek -50 +KPX Agrave uring -50 +KPX Agrave v -100 +KPX Agrave w -90 +KPX Agrave y -74 +KPX Agrave yacute -74 +KPX Agrave ydieresis -74 +KPX Amacron C -55 +KPX Amacron Cacute -55 +KPX Amacron Ccaron -55 +KPX Amacron Ccedilla -55 +KPX Amacron G -55 +KPX Amacron Gbreve -55 +KPX Amacron Gcommaaccent -55 +KPX Amacron O -45 +KPX Amacron Oacute -45 +KPX Amacron Ocircumflex -45 +KPX Amacron Odieresis -45 +KPX Amacron Ograve -45 +KPX Amacron Ohungarumlaut -45 +KPX Amacron Omacron -45 +KPX Amacron Oslash -45 +KPX Amacron Otilde -45 +KPX Amacron Q -45 +KPX Amacron T -95 +KPX Amacron Tcaron -95 +KPX Amacron Tcommaaccent -95 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -145 +KPX Amacron W -130 +KPX Amacron Y -100 +KPX Amacron Yacute -100 +KPX Amacron Ydieresis -100 +KPX Amacron p -25 +KPX Amacron quoteright -74 +KPX Amacron u -50 +KPX Amacron uacute -50 +KPX Amacron ucircumflex -50 +KPX Amacron udieresis -50 +KPX Amacron ugrave -50 +KPX Amacron uhungarumlaut -50 +KPX Amacron umacron -50 +KPX Amacron uogonek -50 +KPX Amacron uring -50 +KPX Amacron v -100 +KPX Amacron w -90 +KPX Amacron y -74 +KPX Amacron yacute -74 +KPX Amacron ydieresis -74 +KPX Aogonek C -55 +KPX Aogonek Cacute -55 +KPX Aogonek Ccaron -55 +KPX Aogonek Ccedilla -55 +KPX Aogonek G -55 +KPX Aogonek Gbreve -55 +KPX Aogonek Gcommaaccent -55 +KPX Aogonek O -45 +KPX Aogonek Oacute -45 +KPX Aogonek Ocircumflex -45 +KPX Aogonek Odieresis -45 +KPX Aogonek Ograve -45 +KPX Aogonek Ohungarumlaut -45 +KPX Aogonek Omacron -45 +KPX Aogonek Oslash -45 +KPX Aogonek Otilde -45 +KPX Aogonek Q -45 +KPX Aogonek T -95 +KPX Aogonek Tcaron -95 +KPX Aogonek Tcommaaccent -95 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -145 +KPX Aogonek W -130 +KPX Aogonek Y -100 +KPX Aogonek Yacute -100 +KPX Aogonek Ydieresis -100 +KPX Aogonek p -25 +KPX Aogonek quoteright -74 +KPX Aogonek u -50 +KPX Aogonek uacute -50 +KPX Aogonek ucircumflex -50 +KPX Aogonek udieresis -50 +KPX Aogonek ugrave -50 +KPX Aogonek uhungarumlaut -50 +KPX Aogonek umacron -50 +KPX Aogonek uogonek -50 +KPX Aogonek uring -50 +KPX Aogonek v -100 +KPX Aogonek w -90 +KPX Aogonek y -34 +KPX Aogonek yacute -34 +KPX Aogonek ydieresis -34 +KPX Aring C -55 +KPX Aring Cacute -55 +KPX Aring Ccaron -55 +KPX Aring Ccedilla -55 +KPX Aring G -55 +KPX Aring Gbreve -55 +KPX Aring Gcommaaccent -55 +KPX Aring O -45 +KPX Aring Oacute -45 +KPX Aring Ocircumflex -45 +KPX Aring Odieresis -45 +KPX Aring Ograve -45 +KPX Aring Ohungarumlaut -45 +KPX Aring Omacron -45 +KPX Aring Oslash -45 +KPX Aring Otilde -45 +KPX Aring Q -45 +KPX Aring T -95 +KPX Aring Tcaron -95 +KPX Aring Tcommaaccent -95 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -145 +KPX Aring W -130 +KPX Aring Y -100 +KPX Aring Yacute -100 +KPX Aring Ydieresis -100 +KPX Aring p -25 +KPX Aring quoteright -74 +KPX Aring u -50 +KPX Aring uacute -50 +KPX Aring ucircumflex -50 +KPX Aring udieresis -50 +KPX Aring ugrave -50 +KPX Aring uhungarumlaut -50 +KPX Aring umacron -50 +KPX Aring uogonek -50 +KPX Aring uring -50 +KPX Aring v -100 +KPX Aring w -90 +KPX Aring y -74 +KPX Aring yacute -74 +KPX Aring ydieresis -74 +KPX Atilde C -55 +KPX Atilde Cacute -55 +KPX Atilde Ccaron -55 +KPX Atilde Ccedilla -55 +KPX Atilde G -55 +KPX Atilde Gbreve -55 +KPX Atilde Gcommaaccent -55 +KPX Atilde O -45 +KPX Atilde Oacute -45 +KPX Atilde Ocircumflex -45 +KPX Atilde Odieresis -45 +KPX Atilde Ograve -45 +KPX Atilde Ohungarumlaut -45 +KPX Atilde Omacron -45 +KPX Atilde Oslash -45 +KPX Atilde Otilde -45 +KPX Atilde Q -45 +KPX Atilde T -95 +KPX Atilde Tcaron -95 +KPX Atilde Tcommaaccent -95 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -145 +KPX Atilde W -130 +KPX Atilde Y -100 +KPX Atilde Yacute -100 +KPX Atilde Ydieresis -100 +KPX Atilde p -25 +KPX Atilde quoteright -74 +KPX Atilde u -50 +KPX Atilde uacute -50 +KPX Atilde ucircumflex -50 +KPX Atilde udieresis -50 +KPX Atilde ugrave -50 +KPX Atilde uhungarumlaut -50 +KPX Atilde umacron -50 +KPX Atilde uogonek -50 +KPX Atilde uring -50 +KPX Atilde v -100 +KPX Atilde w -90 +KPX Atilde y -74 +KPX Atilde yacute -74 +KPX Atilde ydieresis -74 +KPX B A -30 +KPX B Aacute -30 +KPX B Abreve -30 +KPX B Acircumflex -30 +KPX B Adieresis -30 +KPX B Agrave -30 +KPX B Amacron -30 +KPX B Aogonek -30 +KPX B Aring -30 +KPX B Atilde -30 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX D A -35 +KPX D Aacute -35 +KPX D Abreve -35 +KPX D Acircumflex -35 +KPX D Adieresis -35 +KPX D Agrave -35 +KPX D Amacron -35 +KPX D Aogonek -35 +KPX D Aring -35 +KPX D Atilde -35 +KPX D V -40 +KPX D W -40 +KPX D Y -40 +KPX D Yacute -40 +KPX D Ydieresis -40 +KPX D period -20 +KPX Dcaron A -35 +KPX Dcaron Aacute -35 +KPX Dcaron Abreve -35 +KPX Dcaron Acircumflex -35 +KPX Dcaron Adieresis -35 +KPX Dcaron Agrave -35 +KPX Dcaron Amacron -35 +KPX Dcaron Aogonek -35 +KPX Dcaron Aring -35 +KPX Dcaron Atilde -35 +KPX Dcaron V -40 +KPX Dcaron W -40 +KPX Dcaron Y -40 +KPX Dcaron Yacute -40 +KPX Dcaron Ydieresis -40 +KPX Dcaron period -20 +KPX Dcroat A -35 +KPX Dcroat Aacute -35 +KPX Dcroat Abreve -35 +KPX Dcroat Acircumflex -35 +KPX Dcroat Adieresis -35 +KPX Dcroat Agrave -35 +KPX Dcroat Amacron -35 +KPX Dcroat Aogonek -35 +KPX Dcroat Aring -35 +KPX Dcroat Atilde -35 +KPX Dcroat V -40 +KPX Dcroat W -40 +KPX Dcroat Y -40 +KPX Dcroat Yacute -40 +KPX Dcroat Ydieresis -40 +KPX Dcroat period -20 +KPX F A -90 +KPX F Aacute -90 +KPX F Abreve -90 +KPX F Acircumflex -90 +KPX F Adieresis -90 +KPX F Agrave -90 +KPX F Amacron -90 +KPX F Aogonek -90 +KPX F Aring -90 +KPX F Atilde -90 +KPX F a -25 +KPX F aacute -25 +KPX F abreve -25 +KPX F acircumflex -25 +KPX F adieresis -25 +KPX F agrave -25 +KPX F amacron -25 +KPX F aogonek -25 +KPX F aring -25 +KPX F atilde -25 +KPX F comma -92 +KPX F e -25 +KPX F eacute -25 +KPX F ecaron -25 +KPX F ecircumflex -25 +KPX F edieresis -25 +KPX F edotaccent -25 +KPX F egrave -25 +KPX F emacron -25 +KPX F eogonek -25 +KPX F o -25 +KPX F oacute -25 +KPX F ocircumflex -25 +KPX F odieresis -25 +KPX F ograve -25 +KPX F ohungarumlaut -25 +KPX F omacron -25 +KPX F oslash -25 +KPX F otilde -25 +KPX F period -110 +KPX J A -30 +KPX J Aacute -30 +KPX J Abreve -30 +KPX J Acircumflex -30 +KPX J Adieresis -30 +KPX J Agrave -30 +KPX J Amacron -30 +KPX J Aogonek -30 +KPX J Aring -30 +KPX J Atilde -30 +KPX J a -15 +KPX J aacute -15 +KPX J abreve -15 +KPX J acircumflex -15 +KPX J adieresis -15 +KPX J agrave -15 +KPX J amacron -15 +KPX J aogonek -15 +KPX J aring -15 +KPX J atilde -15 +KPX J e -15 +KPX J eacute -15 +KPX J ecaron -15 +KPX J ecircumflex -15 +KPX J edieresis -15 +KPX J edotaccent -15 +KPX J egrave -15 +KPX J emacron -15 +KPX J eogonek -15 +KPX J o -15 +KPX J oacute -15 +KPX J ocircumflex -15 +KPX J odieresis -15 +KPX J ograve -15 +KPX J ohungarumlaut -15 +KPX J omacron -15 +KPX J oslash -15 +KPX J otilde -15 +KPX J period -20 +KPX J u -15 +KPX J uacute -15 +KPX J ucircumflex -15 +KPX J udieresis -15 +KPX J ugrave -15 +KPX J uhungarumlaut -15 +KPX J umacron -15 +KPX J uogonek -15 +KPX J uring -15 +KPX K O -30 +KPX K Oacute -30 +KPX K Ocircumflex -30 +KPX K Odieresis -30 +KPX K Ograve -30 +KPX K Ohungarumlaut -30 +KPX K Omacron -30 +KPX K Oslash -30 +KPX K Otilde -30 +KPX K e -25 +KPX K eacute -25 +KPX K ecaron -25 +KPX K ecircumflex -25 +KPX K edieresis -25 +KPX K edotaccent -25 +KPX K egrave -25 +KPX K emacron -25 +KPX K eogonek -25 +KPX K o -25 +KPX K oacute -25 +KPX K ocircumflex -25 +KPX K odieresis -25 +KPX K ograve -25 +KPX K ohungarumlaut -25 +KPX K omacron -25 +KPX K oslash -25 +KPX K otilde -25 +KPX K u -15 +KPX K uacute -15 +KPX K ucircumflex -15 +KPX K udieresis -15 +KPX K ugrave -15 +KPX K uhungarumlaut -15 +KPX K umacron -15 +KPX K uogonek -15 +KPX K uring -15 +KPX K y -45 +KPX K yacute -45 +KPX K ydieresis -45 +KPX Kcommaaccent O -30 +KPX Kcommaaccent Oacute -30 +KPX Kcommaaccent Ocircumflex -30 +KPX Kcommaaccent Odieresis -30 +KPX Kcommaaccent Ograve -30 +KPX Kcommaaccent Ohungarumlaut -30 +KPX Kcommaaccent Omacron -30 +KPX Kcommaaccent Oslash -30 +KPX Kcommaaccent Otilde -30 +KPX Kcommaaccent e -25 +KPX Kcommaaccent eacute -25 +KPX Kcommaaccent ecaron -25 +KPX Kcommaaccent ecircumflex -25 +KPX Kcommaaccent edieresis -25 +KPX Kcommaaccent edotaccent -25 +KPX Kcommaaccent egrave -25 +KPX Kcommaaccent emacron -25 +KPX Kcommaaccent eogonek -25 +KPX Kcommaaccent o -25 +KPX Kcommaaccent oacute -25 +KPX Kcommaaccent ocircumflex -25 +KPX Kcommaaccent odieresis -25 +KPX Kcommaaccent ograve -25 +KPX Kcommaaccent ohungarumlaut -25 +KPX Kcommaaccent omacron -25 +KPX Kcommaaccent oslash -25 +KPX Kcommaaccent otilde -25 +KPX Kcommaaccent u -15 +KPX Kcommaaccent uacute -15 +KPX Kcommaaccent ucircumflex -15 +KPX Kcommaaccent udieresis -15 +KPX Kcommaaccent ugrave -15 +KPX Kcommaaccent uhungarumlaut -15 +KPX Kcommaaccent umacron -15 +KPX Kcommaaccent uogonek -15 +KPX Kcommaaccent uring -15 +KPX Kcommaaccent y -45 +KPX Kcommaaccent yacute -45 +KPX Kcommaaccent ydieresis -45 +KPX L T -92 +KPX L Tcaron -92 +KPX L Tcommaaccent -92 +KPX L V -92 +KPX L W -92 +KPX L Y -92 +KPX L Yacute -92 +KPX L Ydieresis -92 +KPX L quotedblright -20 +KPX L quoteright -110 +KPX L y -55 +KPX L yacute -55 +KPX L ydieresis -55 +KPX Lacute T -92 +KPX Lacute Tcaron -92 +KPX Lacute Tcommaaccent -92 +KPX Lacute V -92 +KPX Lacute W -92 +KPX Lacute Y -92 +KPX Lacute Yacute -92 +KPX Lacute Ydieresis -92 +KPX Lacute quotedblright -20 +KPX Lacute quoteright -110 +KPX Lacute y -55 +KPX Lacute yacute -55 +KPX Lacute ydieresis -55 +KPX Lcommaaccent T -92 +KPX Lcommaaccent Tcaron -92 +KPX Lcommaaccent Tcommaaccent -92 +KPX Lcommaaccent V -92 +KPX Lcommaaccent W -92 +KPX Lcommaaccent Y -92 +KPX Lcommaaccent Yacute -92 +KPX Lcommaaccent Ydieresis -92 +KPX Lcommaaccent quotedblright -20 +KPX Lcommaaccent quoteright -110 +KPX Lcommaaccent y -55 +KPX Lcommaaccent yacute -55 +KPX Lcommaaccent ydieresis -55 +KPX Lslash T -92 +KPX Lslash Tcaron -92 +KPX Lslash Tcommaaccent -92 +KPX Lslash V -92 +KPX Lslash W -92 +KPX Lslash Y -92 +KPX Lslash Yacute -92 +KPX Lslash Ydieresis -92 +KPX Lslash quotedblright -20 +KPX Lslash quoteright -110 +KPX Lslash y -55 +KPX Lslash yacute -55 +KPX Lslash ydieresis -55 +KPX N A -20 +KPX N Aacute -20 +KPX N Abreve -20 +KPX N Acircumflex -20 +KPX N Adieresis -20 +KPX N Agrave -20 +KPX N Amacron -20 +KPX N Aogonek -20 +KPX N Aring -20 +KPX N Atilde -20 +KPX Nacute A -20 +KPX Nacute Aacute -20 +KPX Nacute Abreve -20 +KPX Nacute Acircumflex -20 +KPX Nacute Adieresis -20 +KPX Nacute Agrave -20 +KPX Nacute Amacron -20 +KPX Nacute Aogonek -20 +KPX Nacute Aring -20 +KPX Nacute Atilde -20 +KPX Ncaron A -20 +KPX Ncaron Aacute -20 +KPX Ncaron Abreve -20 +KPX Ncaron Acircumflex -20 +KPX Ncaron Adieresis -20 +KPX Ncaron Agrave -20 +KPX Ncaron Amacron -20 +KPX Ncaron Aogonek -20 +KPX Ncaron Aring -20 +KPX Ncaron Atilde -20 +KPX Ncommaaccent A -20 +KPX Ncommaaccent Aacute -20 +KPX Ncommaaccent Abreve -20 +KPX Ncommaaccent Acircumflex -20 +KPX Ncommaaccent Adieresis -20 +KPX Ncommaaccent Agrave -20 +KPX Ncommaaccent Amacron -20 +KPX Ncommaaccent Aogonek -20 +KPX Ncommaaccent Aring -20 +KPX Ncommaaccent Atilde -20 +KPX Ntilde A -20 +KPX Ntilde Aacute -20 +KPX Ntilde Abreve -20 +KPX Ntilde Acircumflex -20 +KPX Ntilde Adieresis -20 +KPX Ntilde Agrave -20 +KPX Ntilde Amacron -20 +KPX Ntilde Aogonek -20 +KPX Ntilde Aring -20 +KPX Ntilde Atilde -20 +KPX O A -40 +KPX O Aacute -40 +KPX O Abreve -40 +KPX O Acircumflex -40 +KPX O Adieresis -40 +KPX O Agrave -40 +KPX O Amacron -40 +KPX O Aogonek -40 +KPX O Aring -40 +KPX O Atilde -40 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -50 +KPX O X -40 +KPX O Y -50 +KPX O Yacute -50 +KPX O Ydieresis -50 +KPX Oacute A -40 +KPX Oacute Aacute -40 +KPX Oacute Abreve -40 +KPX Oacute Acircumflex -40 +KPX Oacute Adieresis -40 +KPX Oacute Agrave -40 +KPX Oacute Amacron -40 +KPX Oacute Aogonek -40 +KPX Oacute Aring -40 +KPX Oacute Atilde -40 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -50 +KPX Oacute X -40 +KPX Oacute Y -50 +KPX Oacute Yacute -50 +KPX Oacute Ydieresis -50 +KPX Ocircumflex A -40 +KPX Ocircumflex Aacute -40 +KPX Ocircumflex Abreve -40 +KPX Ocircumflex Acircumflex -40 +KPX Ocircumflex Adieresis -40 +KPX Ocircumflex Agrave -40 +KPX Ocircumflex Amacron -40 +KPX Ocircumflex Aogonek -40 +KPX Ocircumflex Aring -40 +KPX Ocircumflex Atilde -40 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -50 +KPX Ocircumflex X -40 +KPX Ocircumflex Y -50 +KPX Ocircumflex Yacute -50 +KPX Ocircumflex Ydieresis -50 +KPX Odieresis A -40 +KPX Odieresis Aacute -40 +KPX Odieresis Abreve -40 +KPX Odieresis Acircumflex -40 +KPX Odieresis Adieresis -40 +KPX Odieresis Agrave -40 +KPX Odieresis Amacron -40 +KPX Odieresis Aogonek -40 +KPX Odieresis Aring -40 +KPX Odieresis Atilde -40 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -50 +KPX Odieresis X -40 +KPX Odieresis Y -50 +KPX Odieresis Yacute -50 +KPX Odieresis Ydieresis -50 +KPX Ograve A -40 +KPX Ograve Aacute -40 +KPX Ograve Abreve -40 +KPX Ograve Acircumflex -40 +KPX Ograve Adieresis -40 +KPX Ograve Agrave -40 +KPX Ograve Amacron -40 +KPX Ograve Aogonek -40 +KPX Ograve Aring -40 +KPX Ograve Atilde -40 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -50 +KPX Ograve X -40 +KPX Ograve Y -50 +KPX Ograve Yacute -50 +KPX Ograve Ydieresis -50 +KPX Ohungarumlaut A -40 +KPX Ohungarumlaut Aacute -40 +KPX Ohungarumlaut Abreve -40 +KPX Ohungarumlaut Acircumflex -40 +KPX Ohungarumlaut Adieresis -40 +KPX Ohungarumlaut Agrave -40 +KPX Ohungarumlaut Amacron -40 +KPX Ohungarumlaut Aogonek -40 +KPX Ohungarumlaut Aring -40 +KPX Ohungarumlaut Atilde -40 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -50 +KPX Ohungarumlaut X -40 +KPX Ohungarumlaut Y -50 +KPX Ohungarumlaut Yacute -50 +KPX Ohungarumlaut Ydieresis -50 +KPX Omacron A -40 +KPX Omacron Aacute -40 +KPX Omacron Abreve -40 +KPX Omacron Acircumflex -40 +KPX Omacron Adieresis -40 +KPX Omacron Agrave -40 +KPX Omacron Amacron -40 +KPX Omacron Aogonek -40 +KPX Omacron Aring -40 +KPX Omacron Atilde -40 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -50 +KPX Omacron X -40 +KPX Omacron Y -50 +KPX Omacron Yacute -50 +KPX Omacron Ydieresis -50 +KPX Oslash A -40 +KPX Oslash Aacute -40 +KPX Oslash Abreve -40 +KPX Oslash Acircumflex -40 +KPX Oslash Adieresis -40 +KPX Oslash Agrave -40 +KPX Oslash Amacron -40 +KPX Oslash Aogonek -40 +KPX Oslash Aring -40 +KPX Oslash Atilde -40 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -50 +KPX Oslash X -40 +KPX Oslash Y -50 +KPX Oslash Yacute -50 +KPX Oslash Ydieresis -50 +KPX Otilde A -40 +KPX Otilde Aacute -40 +KPX Otilde Abreve -40 +KPX Otilde Acircumflex -40 +KPX Otilde Adieresis -40 +KPX Otilde Agrave -40 +KPX Otilde Amacron -40 +KPX Otilde Aogonek -40 +KPX Otilde Aring -40 +KPX Otilde Atilde -40 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -50 +KPX Otilde X -40 +KPX Otilde Y -50 +KPX Otilde Yacute -50 +KPX Otilde Ydieresis -50 +KPX P A -74 +KPX P Aacute -74 +KPX P Abreve -74 +KPX P Acircumflex -74 +KPX P Adieresis -74 +KPX P Agrave -74 +KPX P Amacron -74 +KPX P Aogonek -74 +KPX P Aring -74 +KPX P Atilde -74 +KPX P a -10 +KPX P aacute -10 +KPX P abreve -10 +KPX P acircumflex -10 +KPX P adieresis -10 +KPX P agrave -10 +KPX P amacron -10 +KPX P aogonek -10 +KPX P aring -10 +KPX P atilde -10 +KPX P comma -92 +KPX P e -20 +KPX P eacute -20 +KPX P ecaron -20 +KPX P ecircumflex -20 +KPX P edieresis -20 +KPX P edotaccent -20 +KPX P egrave -20 +KPX P emacron -20 +KPX P eogonek -20 +KPX P o -20 +KPX P oacute -20 +KPX P ocircumflex -20 +KPX P odieresis -20 +KPX P ograve -20 +KPX P ohungarumlaut -20 +KPX P omacron -20 +KPX P oslash -20 +KPX P otilde -20 +KPX P period -110 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX Q period -20 +KPX R O -30 +KPX R Oacute -30 +KPX R Ocircumflex -30 +KPX R Odieresis -30 +KPX R Ograve -30 +KPX R Ohungarumlaut -30 +KPX R Omacron -30 +KPX R Oslash -30 +KPX R Otilde -30 +KPX R T -40 +KPX R Tcaron -40 +KPX R Tcommaaccent -40 +KPX R U -30 +KPX R Uacute -30 +KPX R Ucircumflex -30 +KPX R Udieresis -30 +KPX R Ugrave -30 +KPX R Uhungarumlaut -30 +KPX R Umacron -30 +KPX R Uogonek -30 +KPX R Uring -30 +KPX R V -55 +KPX R W -35 +KPX R Y -35 +KPX R Yacute -35 +KPX R Ydieresis -35 +KPX Racute O -30 +KPX Racute Oacute -30 +KPX Racute Ocircumflex -30 +KPX Racute Odieresis -30 +KPX Racute Ograve -30 +KPX Racute Ohungarumlaut -30 +KPX Racute Omacron -30 +KPX Racute Oslash -30 +KPX Racute Otilde -30 +KPX Racute T -40 +KPX Racute Tcaron -40 +KPX Racute Tcommaaccent -40 +KPX Racute U -30 +KPX Racute Uacute -30 +KPX Racute Ucircumflex -30 +KPX Racute Udieresis -30 +KPX Racute Ugrave -30 +KPX Racute Uhungarumlaut -30 +KPX Racute Umacron -30 +KPX Racute Uogonek -30 +KPX Racute Uring -30 +KPX Racute V -55 +KPX Racute W -35 +KPX Racute Y -35 +KPX Racute Yacute -35 +KPX Racute Ydieresis -35 +KPX Rcaron O -30 +KPX Rcaron Oacute -30 +KPX Rcaron Ocircumflex -30 +KPX Rcaron Odieresis -30 +KPX Rcaron Ograve -30 +KPX Rcaron Ohungarumlaut -30 +KPX Rcaron Omacron -30 +KPX Rcaron Oslash -30 +KPX Rcaron Otilde -30 +KPX Rcaron T -40 +KPX Rcaron Tcaron -40 +KPX Rcaron Tcommaaccent -40 +KPX Rcaron U -30 +KPX Rcaron Uacute -30 +KPX Rcaron Ucircumflex -30 +KPX Rcaron Udieresis -30 +KPX Rcaron Ugrave -30 +KPX Rcaron Uhungarumlaut -30 +KPX Rcaron Umacron -30 +KPX Rcaron Uogonek -30 +KPX Rcaron Uring -30 +KPX Rcaron V -55 +KPX Rcaron W -35 +KPX Rcaron Y -35 +KPX Rcaron Yacute -35 +KPX Rcaron Ydieresis -35 +KPX Rcommaaccent O -30 +KPX Rcommaaccent Oacute -30 +KPX Rcommaaccent Ocircumflex -30 +KPX Rcommaaccent Odieresis -30 +KPX Rcommaaccent Ograve -30 +KPX Rcommaaccent Ohungarumlaut -30 +KPX Rcommaaccent Omacron -30 +KPX Rcommaaccent Oslash -30 +KPX Rcommaaccent Otilde -30 +KPX Rcommaaccent T -40 +KPX Rcommaaccent Tcaron -40 +KPX Rcommaaccent Tcommaaccent -40 +KPX Rcommaaccent U -30 +KPX Rcommaaccent Uacute -30 +KPX Rcommaaccent Ucircumflex -30 +KPX Rcommaaccent Udieresis -30 +KPX Rcommaaccent Ugrave -30 +KPX Rcommaaccent Uhungarumlaut -30 +KPX Rcommaaccent Umacron -30 +KPX Rcommaaccent Uogonek -30 +KPX Rcommaaccent Uring -30 +KPX Rcommaaccent V -55 +KPX Rcommaaccent W -35 +KPX Rcommaaccent Y -35 +KPX Rcommaaccent Yacute -35 +KPX Rcommaaccent Ydieresis -35 +KPX T A -90 +KPX T Aacute -90 +KPX T Abreve -90 +KPX T Acircumflex -90 +KPX T Adieresis -90 +KPX T Agrave -90 +KPX T Amacron -90 +KPX T Aogonek -90 +KPX T Aring -90 +KPX T Atilde -90 +KPX T O -18 +KPX T Oacute -18 +KPX T Ocircumflex -18 +KPX T Odieresis -18 +KPX T Ograve -18 +KPX T Ohungarumlaut -18 +KPX T Omacron -18 +KPX T Oslash -18 +KPX T Otilde -18 +KPX T a -92 +KPX T aacute -92 +KPX T abreve -52 +KPX T acircumflex -52 +KPX T adieresis -52 +KPX T agrave -52 +KPX T amacron -52 +KPX T aogonek -92 +KPX T aring -92 +KPX T atilde -52 +KPX T colon -74 +KPX T comma -74 +KPX T e -92 +KPX T eacute -92 +KPX T ecaron -92 +KPX T ecircumflex -92 +KPX T edieresis -52 +KPX T edotaccent -92 +KPX T egrave -52 +KPX T emacron -52 +KPX T eogonek -92 +KPX T hyphen -92 +KPX T i -18 +KPX T iacute -18 +KPX T iogonek -18 +KPX T o -92 +KPX T oacute -92 +KPX T ocircumflex -92 +KPX T odieresis -92 +KPX T ograve -92 +KPX T ohungarumlaut -92 +KPX T omacron -92 +KPX T oslash -92 +KPX T otilde -92 +KPX T period -90 +KPX T r -74 +KPX T racute -74 +KPX T rcaron -74 +KPX T rcommaaccent -74 +KPX T semicolon -74 +KPX T u -92 +KPX T uacute -92 +KPX T ucircumflex -92 +KPX T udieresis -92 +KPX T ugrave -92 +KPX T uhungarumlaut -92 +KPX T umacron -92 +KPX T uogonek -92 +KPX T uring -92 +KPX T w -74 +KPX T y -34 +KPX T yacute -34 +KPX T ydieresis -34 +KPX Tcaron A -90 +KPX Tcaron Aacute -90 +KPX Tcaron Abreve -90 +KPX Tcaron Acircumflex -90 +KPX Tcaron Adieresis -90 +KPX Tcaron Agrave -90 +KPX Tcaron Amacron -90 +KPX Tcaron Aogonek -90 +KPX Tcaron Aring -90 +KPX Tcaron Atilde -90 +KPX Tcaron O -18 +KPX Tcaron Oacute -18 +KPX Tcaron Ocircumflex -18 +KPX Tcaron Odieresis -18 +KPX Tcaron Ograve -18 +KPX Tcaron Ohungarumlaut -18 +KPX Tcaron Omacron -18 +KPX Tcaron Oslash -18 +KPX Tcaron Otilde -18 +KPX Tcaron a -92 +KPX Tcaron aacute -92 +KPX Tcaron abreve -52 +KPX Tcaron acircumflex -52 +KPX Tcaron adieresis -52 +KPX Tcaron agrave -52 +KPX Tcaron amacron -52 +KPX Tcaron aogonek -92 +KPX Tcaron aring -92 +KPX Tcaron atilde -52 +KPX Tcaron colon -74 +KPX Tcaron comma -74 +KPX Tcaron e -92 +KPX Tcaron eacute -92 +KPX Tcaron ecaron -92 +KPX Tcaron ecircumflex -92 +KPX Tcaron edieresis -52 +KPX Tcaron edotaccent -92 +KPX Tcaron egrave -52 +KPX Tcaron emacron -52 +KPX Tcaron eogonek -92 +KPX Tcaron hyphen -92 +KPX Tcaron i -18 +KPX Tcaron iacute -18 +KPX Tcaron iogonek -18 +KPX Tcaron o -92 +KPX Tcaron oacute -92 +KPX Tcaron ocircumflex -92 +KPX Tcaron odieresis -92 +KPX Tcaron ograve -92 +KPX Tcaron ohungarumlaut -92 +KPX Tcaron omacron -92 +KPX Tcaron oslash -92 +KPX Tcaron otilde -92 +KPX Tcaron period -90 +KPX Tcaron r -74 +KPX Tcaron racute -74 +KPX Tcaron rcaron -74 +KPX Tcaron rcommaaccent -74 +KPX Tcaron semicolon -74 +KPX Tcaron u -92 +KPX Tcaron uacute -92 +KPX Tcaron ucircumflex -92 +KPX Tcaron udieresis -92 +KPX Tcaron ugrave -92 +KPX Tcaron uhungarumlaut -92 +KPX Tcaron umacron -92 +KPX Tcaron uogonek -92 +KPX Tcaron uring -92 +KPX Tcaron w -74 +KPX Tcaron y -34 +KPX Tcaron yacute -34 +KPX Tcaron ydieresis -34 +KPX Tcommaaccent A -90 +KPX Tcommaaccent Aacute -90 +KPX Tcommaaccent Abreve -90 +KPX Tcommaaccent Acircumflex -90 +KPX Tcommaaccent Adieresis -90 +KPX Tcommaaccent Agrave -90 +KPX Tcommaaccent Amacron -90 +KPX Tcommaaccent Aogonek -90 +KPX Tcommaaccent Aring -90 +KPX Tcommaaccent Atilde -90 +KPX Tcommaaccent O -18 +KPX Tcommaaccent Oacute -18 +KPX Tcommaaccent Ocircumflex -18 +KPX Tcommaaccent Odieresis -18 +KPX Tcommaaccent Ograve -18 +KPX Tcommaaccent Ohungarumlaut -18 +KPX Tcommaaccent Omacron -18 +KPX Tcommaaccent Oslash -18 +KPX Tcommaaccent Otilde -18 +KPX Tcommaaccent a -92 +KPX Tcommaaccent aacute -92 +KPX Tcommaaccent abreve -52 +KPX Tcommaaccent acircumflex -52 +KPX Tcommaaccent adieresis -52 +KPX Tcommaaccent agrave -52 +KPX Tcommaaccent amacron -52 +KPX Tcommaaccent aogonek -92 +KPX Tcommaaccent aring -92 +KPX Tcommaaccent atilde -52 +KPX Tcommaaccent colon -74 +KPX Tcommaaccent comma -74 +KPX Tcommaaccent e -92 +KPX Tcommaaccent eacute -92 +KPX Tcommaaccent ecaron -92 +KPX Tcommaaccent ecircumflex -92 +KPX Tcommaaccent edieresis -52 +KPX Tcommaaccent edotaccent -92 +KPX Tcommaaccent egrave -52 +KPX Tcommaaccent emacron -52 +KPX Tcommaaccent eogonek -92 +KPX Tcommaaccent hyphen -92 +KPX Tcommaaccent i -18 +KPX Tcommaaccent iacute -18 +KPX Tcommaaccent iogonek -18 +KPX Tcommaaccent o -92 +KPX Tcommaaccent oacute -92 +KPX Tcommaaccent ocircumflex -92 +KPX Tcommaaccent odieresis -92 +KPX Tcommaaccent ograve -92 +KPX Tcommaaccent ohungarumlaut -92 +KPX Tcommaaccent omacron -92 +KPX Tcommaaccent oslash -92 +KPX Tcommaaccent otilde -92 +KPX Tcommaaccent period -90 +KPX Tcommaaccent r -74 +KPX Tcommaaccent racute -74 +KPX Tcommaaccent rcaron -74 +KPX Tcommaaccent rcommaaccent -74 +KPX Tcommaaccent semicolon -74 +KPX Tcommaaccent u -92 +KPX Tcommaaccent uacute -92 +KPX Tcommaaccent ucircumflex -92 +KPX Tcommaaccent udieresis -92 +KPX Tcommaaccent ugrave -92 +KPX Tcommaaccent uhungarumlaut -92 +KPX Tcommaaccent umacron -92 +KPX Tcommaaccent uogonek -92 +KPX Tcommaaccent uring -92 +KPX Tcommaaccent w -74 +KPX Tcommaaccent y -34 +KPX Tcommaaccent yacute -34 +KPX Tcommaaccent ydieresis -34 +KPX U A -60 +KPX U Aacute -60 +KPX U Abreve -60 +KPX U Acircumflex -60 +KPX U Adieresis -60 +KPX U Agrave -60 +KPX U Amacron -60 +KPX U Aogonek -60 +KPX U Aring -60 +KPX U Atilde -60 +KPX U comma -50 +KPX U period -50 +KPX Uacute A -60 +KPX Uacute Aacute -60 +KPX Uacute Abreve -60 +KPX Uacute Acircumflex -60 +KPX Uacute Adieresis -60 +KPX Uacute Agrave -60 +KPX Uacute Amacron -60 +KPX Uacute Aogonek -60 +KPX Uacute Aring -60 +KPX Uacute Atilde -60 +KPX Uacute comma -50 +KPX Uacute period -50 +KPX Ucircumflex A -60 +KPX Ucircumflex Aacute -60 +KPX Ucircumflex Abreve -60 +KPX Ucircumflex Acircumflex -60 +KPX Ucircumflex Adieresis -60 +KPX Ucircumflex Agrave -60 +KPX Ucircumflex Amacron -60 +KPX Ucircumflex Aogonek -60 +KPX Ucircumflex Aring -60 +KPX Ucircumflex Atilde -60 +KPX Ucircumflex comma -50 +KPX Ucircumflex period -50 +KPX Udieresis A -60 +KPX Udieresis Aacute -60 +KPX Udieresis Abreve -60 +KPX Udieresis Acircumflex -60 +KPX Udieresis Adieresis -60 +KPX Udieresis Agrave -60 +KPX Udieresis Amacron -60 +KPX Udieresis Aogonek -60 +KPX Udieresis Aring -60 +KPX Udieresis Atilde -60 +KPX Udieresis comma -50 +KPX Udieresis period -50 +KPX Ugrave A -60 +KPX Ugrave Aacute -60 +KPX Ugrave Abreve -60 +KPX Ugrave Acircumflex -60 +KPX Ugrave Adieresis -60 +KPX Ugrave Agrave -60 +KPX Ugrave Amacron -60 +KPX Ugrave Aogonek -60 +KPX Ugrave Aring -60 +KPX Ugrave Atilde -60 +KPX Ugrave comma -50 +KPX Ugrave period -50 +KPX Uhungarumlaut A -60 +KPX Uhungarumlaut Aacute -60 +KPX Uhungarumlaut Abreve -60 +KPX Uhungarumlaut Acircumflex -60 +KPX Uhungarumlaut Adieresis -60 +KPX Uhungarumlaut Agrave -60 +KPX Uhungarumlaut Amacron -60 +KPX Uhungarumlaut Aogonek -60 +KPX Uhungarumlaut Aring -60 +KPX Uhungarumlaut Atilde -60 +KPX Uhungarumlaut comma -50 +KPX Uhungarumlaut period -50 +KPX Umacron A -60 +KPX Umacron Aacute -60 +KPX Umacron Abreve -60 +KPX Umacron Acircumflex -60 +KPX Umacron Adieresis -60 +KPX Umacron Agrave -60 +KPX Umacron Amacron -60 +KPX Umacron Aogonek -60 +KPX Umacron Aring -60 +KPX Umacron Atilde -60 +KPX Umacron comma -50 +KPX Umacron period -50 +KPX Uogonek A -60 +KPX Uogonek Aacute -60 +KPX Uogonek Abreve -60 +KPX Uogonek Acircumflex -60 +KPX Uogonek Adieresis -60 +KPX Uogonek Agrave -60 +KPX Uogonek Amacron -60 +KPX Uogonek Aogonek -60 +KPX Uogonek Aring -60 +KPX Uogonek Atilde -60 +KPX Uogonek comma -50 +KPX Uogonek period -50 +KPX Uring A -60 +KPX Uring Aacute -60 +KPX Uring Abreve -60 +KPX Uring Acircumflex -60 +KPX Uring Adieresis -60 +KPX Uring Agrave -60 +KPX Uring Amacron -60 +KPX Uring Aogonek -60 +KPX Uring Aring -60 +KPX Uring Atilde -60 +KPX Uring comma -50 +KPX Uring period -50 +KPX V A -135 +KPX V Aacute -135 +KPX V Abreve -135 +KPX V Acircumflex -135 +KPX V Adieresis -135 +KPX V Agrave -135 +KPX V Amacron -135 +KPX V Aogonek -135 +KPX V Aring -135 +KPX V Atilde -135 +KPX V G -30 +KPX V Gbreve -30 +KPX V Gcommaaccent -30 +KPX V O -45 +KPX V Oacute -45 +KPX V Ocircumflex -45 +KPX V Odieresis -45 +KPX V Ograve -45 +KPX V Ohungarumlaut -45 +KPX V Omacron -45 +KPX V Oslash -45 +KPX V Otilde -45 +KPX V a -92 +KPX V aacute -92 +KPX V abreve -92 +KPX V acircumflex -92 +KPX V adieresis -92 +KPX V agrave -92 +KPX V amacron -92 +KPX V aogonek -92 +KPX V aring -92 +KPX V atilde -92 +KPX V colon -92 +KPX V comma -129 +KPX V e -100 +KPX V eacute -100 +KPX V ecaron -100 +KPX V ecircumflex -100 +KPX V edieresis -100 +KPX V edotaccent -100 +KPX V egrave -100 +KPX V emacron -100 +KPX V eogonek -100 +KPX V hyphen -74 +KPX V i -37 +KPX V iacute -37 +KPX V icircumflex -37 +KPX V idieresis -37 +KPX V igrave -37 +KPX V imacron -37 +KPX V iogonek -37 +KPX V o -100 +KPX V oacute -100 +KPX V ocircumflex -100 +KPX V odieresis -100 +KPX V ograve -100 +KPX V ohungarumlaut -100 +KPX V omacron -100 +KPX V oslash -100 +KPX V otilde -100 +KPX V period -145 +KPX V semicolon -92 +KPX V u -92 +KPX V uacute -92 +KPX V ucircumflex -92 +KPX V udieresis -92 +KPX V ugrave -92 +KPX V uhungarumlaut -92 +KPX V umacron -92 +KPX V uogonek -92 +KPX V uring -92 +KPX W A -120 +KPX W Aacute -120 +KPX W Abreve -120 +KPX W Acircumflex -120 +KPX W Adieresis -120 +KPX W Agrave -120 +KPX W Amacron -120 +KPX W Aogonek -120 +KPX W Aring -120 +KPX W Atilde -120 +KPX W O -10 +KPX W Oacute -10 +KPX W Ocircumflex -10 +KPX W Odieresis -10 +KPX W Ograve -10 +KPX W Ohungarumlaut -10 +KPX W Omacron -10 +KPX W Oslash -10 +KPX W Otilde -10 +KPX W a -65 +KPX W aacute -65 +KPX W abreve -65 +KPX W acircumflex -65 +KPX W adieresis -65 +KPX W agrave -65 +KPX W amacron -65 +KPX W aogonek -65 +KPX W aring -65 +KPX W atilde -65 +KPX W colon -55 +KPX W comma -92 +KPX W e -65 +KPX W eacute -65 +KPX W ecaron -65 +KPX W ecircumflex -65 +KPX W edieresis -65 +KPX W edotaccent -65 +KPX W egrave -65 +KPX W emacron -65 +KPX W eogonek -65 +KPX W hyphen -37 +KPX W i -18 +KPX W iacute -18 +KPX W iogonek -18 +KPX W o -75 +KPX W oacute -75 +KPX W ocircumflex -75 +KPX W odieresis -75 +KPX W ograve -75 +KPX W ohungarumlaut -75 +KPX W omacron -75 +KPX W oslash -75 +KPX W otilde -75 +KPX W period -92 +KPX W semicolon -55 +KPX W u -50 +KPX W uacute -50 +KPX W ucircumflex -50 +KPX W udieresis -50 +KPX W ugrave -50 +KPX W uhungarumlaut -50 +KPX W umacron -50 +KPX W uogonek -50 +KPX W uring -50 +KPX W y -60 +KPX W yacute -60 +KPX W ydieresis -60 +KPX Y A -110 +KPX Y Aacute -110 +KPX Y Abreve -110 +KPX Y Acircumflex -110 +KPX Y Adieresis -110 +KPX Y Agrave -110 +KPX Y Amacron -110 +KPX Y Aogonek -110 +KPX Y Aring -110 +KPX Y Atilde -110 +KPX Y O -35 +KPX Y Oacute -35 +KPX Y Ocircumflex -35 +KPX Y Odieresis -35 +KPX Y Ograve -35 +KPX Y Ohungarumlaut -35 +KPX Y Omacron -35 +KPX Y Oslash -35 +KPX Y Otilde -35 +KPX Y a -85 +KPX Y aacute -85 +KPX Y abreve -85 +KPX Y acircumflex -85 +KPX Y adieresis -85 +KPX Y agrave -85 +KPX Y amacron -85 +KPX Y aogonek -85 +KPX Y aring -85 +KPX Y atilde -85 +KPX Y colon -92 +KPX Y comma -92 +KPX Y e -111 +KPX Y eacute -111 +KPX Y ecaron -111 +KPX Y ecircumflex -111 +KPX Y edieresis -71 +KPX Y edotaccent -111 +KPX Y egrave -71 +KPX Y emacron -71 +KPX Y eogonek -111 +KPX Y hyphen -92 +KPX Y i -37 +KPX Y iacute -37 +KPX Y iogonek -37 +KPX Y o -111 +KPX Y oacute -111 +KPX Y ocircumflex -111 +KPX Y odieresis -111 +KPX Y ograve -111 +KPX Y ohungarumlaut -111 +KPX Y omacron -111 +KPX Y oslash -111 +KPX Y otilde -111 +KPX Y period -92 +KPX Y semicolon -92 +KPX Y u -92 +KPX Y uacute -92 +KPX Y ucircumflex -92 +KPX Y udieresis -92 +KPX Y ugrave -92 +KPX Y uhungarumlaut -92 +KPX Y umacron -92 +KPX Y uogonek -92 +KPX Y uring -92 +KPX Yacute A -110 +KPX Yacute Aacute -110 +KPX Yacute Abreve -110 +KPX Yacute Acircumflex -110 +KPX Yacute Adieresis -110 +KPX Yacute Agrave -110 +KPX Yacute Amacron -110 +KPX Yacute Aogonek -110 +KPX Yacute Aring -110 +KPX Yacute Atilde -110 +KPX Yacute O -35 +KPX Yacute Oacute -35 +KPX Yacute Ocircumflex -35 +KPX Yacute Odieresis -35 +KPX Yacute Ograve -35 +KPX Yacute Ohungarumlaut -35 +KPX Yacute Omacron -35 +KPX Yacute Oslash -35 +KPX Yacute Otilde -35 +KPX Yacute a -85 +KPX Yacute aacute -85 +KPX Yacute abreve -85 +KPX Yacute acircumflex -85 +KPX Yacute adieresis -85 +KPX Yacute agrave -85 +KPX Yacute amacron -85 +KPX Yacute aogonek -85 +KPX Yacute aring -85 +KPX Yacute atilde -85 +KPX Yacute colon -92 +KPX Yacute comma -92 +KPX Yacute e -111 +KPX Yacute eacute -111 +KPX Yacute ecaron -111 +KPX Yacute ecircumflex -111 +KPX Yacute edieresis -71 +KPX Yacute edotaccent -111 +KPX Yacute egrave -71 +KPX Yacute emacron -71 +KPX Yacute eogonek -111 +KPX Yacute hyphen -92 +KPX Yacute i -37 +KPX Yacute iacute -37 +KPX Yacute iogonek -37 +KPX Yacute o -111 +KPX Yacute oacute -111 +KPX Yacute ocircumflex -111 +KPX Yacute odieresis -111 +KPX Yacute ograve -111 +KPX Yacute ohungarumlaut -111 +KPX Yacute omacron -111 +KPX Yacute oslash -111 +KPX Yacute otilde -111 +KPX Yacute period -92 +KPX Yacute semicolon -92 +KPX Yacute u -92 +KPX Yacute uacute -92 +KPX Yacute ucircumflex -92 +KPX Yacute udieresis -92 +KPX Yacute ugrave -92 +KPX Yacute uhungarumlaut -92 +KPX Yacute umacron -92 +KPX Yacute uogonek -92 +KPX Yacute uring -92 +KPX Ydieresis A -110 +KPX Ydieresis Aacute -110 +KPX Ydieresis Abreve -110 +KPX Ydieresis Acircumflex -110 +KPX Ydieresis Adieresis -110 +KPX Ydieresis Agrave -110 +KPX Ydieresis Amacron -110 +KPX Ydieresis Aogonek -110 +KPX Ydieresis Aring -110 +KPX Ydieresis Atilde -110 +KPX Ydieresis O -35 +KPX Ydieresis Oacute -35 +KPX Ydieresis Ocircumflex -35 +KPX Ydieresis Odieresis -35 +KPX Ydieresis Ograve -35 +KPX Ydieresis Ohungarumlaut -35 +KPX Ydieresis Omacron -35 +KPX Ydieresis Oslash -35 +KPX Ydieresis Otilde -35 +KPX Ydieresis a -85 +KPX Ydieresis aacute -85 +KPX Ydieresis abreve -85 +KPX Ydieresis acircumflex -85 +KPX Ydieresis adieresis -85 +KPX Ydieresis agrave -85 +KPX Ydieresis amacron -85 +KPX Ydieresis aogonek -85 +KPX Ydieresis aring -85 +KPX Ydieresis atilde -85 +KPX Ydieresis colon -92 +KPX Ydieresis comma -92 +KPX Ydieresis e -111 +KPX Ydieresis eacute -111 +KPX Ydieresis ecaron -111 +KPX Ydieresis ecircumflex -111 +KPX Ydieresis edieresis -71 +KPX Ydieresis edotaccent -111 +KPX Ydieresis egrave -71 +KPX Ydieresis emacron -71 +KPX Ydieresis eogonek -111 +KPX Ydieresis hyphen -92 +KPX Ydieresis i -37 +KPX Ydieresis iacute -37 +KPX Ydieresis iogonek -37 +KPX Ydieresis o -111 +KPX Ydieresis oacute -111 +KPX Ydieresis ocircumflex -111 +KPX Ydieresis odieresis -111 +KPX Ydieresis ograve -111 +KPX Ydieresis ohungarumlaut -111 +KPX Ydieresis omacron -111 +KPX Ydieresis oslash -111 +KPX Ydieresis otilde -111 +KPX Ydieresis period -92 +KPX Ydieresis semicolon -92 +KPX Ydieresis u -92 +KPX Ydieresis uacute -92 +KPX Ydieresis ucircumflex -92 +KPX Ydieresis udieresis -92 +KPX Ydieresis ugrave -92 +KPX Ydieresis uhungarumlaut -92 +KPX Ydieresis umacron -92 +KPX Ydieresis uogonek -92 +KPX Ydieresis uring -92 +KPX a v -25 +KPX aacute v -25 +KPX abreve v -25 +KPX acircumflex v -25 +KPX adieresis v -25 +KPX agrave v -25 +KPX amacron v -25 +KPX aogonek v -25 +KPX aring v -25 +KPX atilde v -25 +KPX b b -10 +KPX b period -40 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX b v -15 +KPX comma quotedblright -45 +KPX comma quoteright -55 +KPX d w -15 +KPX dcroat w -15 +KPX e v -15 +KPX eacute v -15 +KPX ecaron v -15 +KPX ecircumflex v -15 +KPX edieresis v -15 +KPX edotaccent v -15 +KPX egrave v -15 +KPX emacron v -15 +KPX eogonek v -15 +KPX f comma -15 +KPX f dotlessi -35 +KPX f i -25 +KPX f o -25 +KPX f oacute -25 +KPX f ocircumflex -25 +KPX f odieresis -25 +KPX f ograve -25 +KPX f ohungarumlaut -25 +KPX f omacron -25 +KPX f oslash -25 +KPX f otilde -25 +KPX f period -15 +KPX f quotedblright 50 +KPX f quoteright 55 +KPX g period -15 +KPX gbreve period -15 +KPX gcommaaccent period -15 +KPX h y -15 +KPX h yacute -15 +KPX h ydieresis -15 +KPX i v -10 +KPX iacute v -10 +KPX icircumflex v -10 +KPX idieresis v -10 +KPX igrave v -10 +KPX imacron v -10 +KPX iogonek v -10 +KPX k e -10 +KPX k eacute -10 +KPX k ecaron -10 +KPX k ecircumflex -10 +KPX k edieresis -10 +KPX k edotaccent -10 +KPX k egrave -10 +KPX k emacron -10 +KPX k eogonek -10 +KPX k o -15 +KPX k oacute -15 +KPX k ocircumflex -15 +KPX k odieresis -15 +KPX k ograve -15 +KPX k ohungarumlaut -15 +KPX k omacron -15 +KPX k oslash -15 +KPX k otilde -15 +KPX k y -15 +KPX k yacute -15 +KPX k ydieresis -15 +KPX kcommaaccent e -10 +KPX kcommaaccent eacute -10 +KPX kcommaaccent ecaron -10 +KPX kcommaaccent ecircumflex -10 +KPX kcommaaccent edieresis -10 +KPX kcommaaccent edotaccent -10 +KPX kcommaaccent egrave -10 +KPX kcommaaccent emacron -10 +KPX kcommaaccent eogonek -10 +KPX kcommaaccent o -15 +KPX kcommaaccent oacute -15 +KPX kcommaaccent ocircumflex -15 +KPX kcommaaccent odieresis -15 +KPX kcommaaccent ograve -15 +KPX kcommaaccent ohungarumlaut -15 +KPX kcommaaccent omacron -15 +KPX kcommaaccent oslash -15 +KPX kcommaaccent otilde -15 +KPX kcommaaccent y -15 +KPX kcommaaccent yacute -15 +KPX kcommaaccent ydieresis -15 +KPX n v -40 +KPX nacute v -40 +KPX ncaron v -40 +KPX ncommaaccent v -40 +KPX ntilde v -40 +KPX o v -10 +KPX o w -10 +KPX oacute v -10 +KPX oacute w -10 +KPX ocircumflex v -10 +KPX ocircumflex w -10 +KPX odieresis v -10 +KPX odieresis w -10 +KPX ograve v -10 +KPX ograve w -10 +KPX ohungarumlaut v -10 +KPX ohungarumlaut w -10 +KPX omacron v -10 +KPX omacron w -10 +KPX oslash v -10 +KPX oslash w -10 +KPX otilde v -10 +KPX otilde w -10 +KPX period quotedblright -55 +KPX period quoteright -55 +KPX quotedblleft A -10 +KPX quotedblleft Aacute -10 +KPX quotedblleft Abreve -10 +KPX quotedblleft Acircumflex -10 +KPX quotedblleft Adieresis -10 +KPX quotedblleft Agrave -10 +KPX quotedblleft Amacron -10 +KPX quotedblleft Aogonek -10 +KPX quotedblleft Aring -10 +KPX quotedblleft Atilde -10 +KPX quoteleft A -10 +KPX quoteleft Aacute -10 +KPX quoteleft Abreve -10 +KPX quoteleft Acircumflex -10 +KPX quoteleft Adieresis -10 +KPX quoteleft Agrave -10 +KPX quoteleft Amacron -10 +KPX quoteleft Aogonek -10 +KPX quoteleft Aring -10 +KPX quoteleft Atilde -10 +KPX quoteleft quoteleft -63 +KPX quoteright d -20 +KPX quoteright dcroat -20 +KPX quoteright quoteright -63 +KPX quoteright r -20 +KPX quoteright racute -20 +KPX quoteright rcaron -20 +KPX quoteright rcommaaccent -20 +KPX quoteright s -37 +KPX quoteright sacute -37 +KPX quoteright scaron -37 +KPX quoteright scedilla -37 +KPX quoteright scommaaccent -37 +KPX quoteright space -74 +KPX quoteright v -20 +KPX r c -18 +KPX r cacute -18 +KPX r ccaron -18 +KPX r ccedilla -18 +KPX r comma -92 +KPX r e -18 +KPX r eacute -18 +KPX r ecaron -18 +KPX r ecircumflex -18 +KPX r edieresis -18 +KPX r edotaccent -18 +KPX r egrave -18 +KPX r emacron -18 +KPX r eogonek -18 +KPX r g -10 +KPX r gbreve -10 +KPX r gcommaaccent -10 +KPX r hyphen -37 +KPX r n -15 +KPX r nacute -15 +KPX r ncaron -15 +KPX r ncommaaccent -15 +KPX r ntilde -15 +KPX r o -18 +KPX r oacute -18 +KPX r ocircumflex -18 +KPX r odieresis -18 +KPX r ograve -18 +KPX r ohungarumlaut -18 +KPX r omacron -18 +KPX r oslash -18 +KPX r otilde -18 +KPX r p -10 +KPX r period -100 +KPX r q -18 +KPX r v -10 +KPX racute c -18 +KPX racute cacute -18 +KPX racute ccaron -18 +KPX racute ccedilla -18 +KPX racute comma -92 +KPX racute e -18 +KPX racute eacute -18 +KPX racute ecaron -18 +KPX racute ecircumflex -18 +KPX racute edieresis -18 +KPX racute edotaccent -18 +KPX racute egrave -18 +KPX racute emacron -18 +KPX racute eogonek -18 +KPX racute g -10 +KPX racute gbreve -10 +KPX racute gcommaaccent -10 +KPX racute hyphen -37 +KPX racute n -15 +KPX racute nacute -15 +KPX racute ncaron -15 +KPX racute ncommaaccent -15 +KPX racute ntilde -15 +KPX racute o -18 +KPX racute oacute -18 +KPX racute ocircumflex -18 +KPX racute odieresis -18 +KPX racute ograve -18 +KPX racute ohungarumlaut -18 +KPX racute omacron -18 +KPX racute oslash -18 +KPX racute otilde -18 +KPX racute p -10 +KPX racute period -100 +KPX racute q -18 +KPX racute v -10 +KPX rcaron c -18 +KPX rcaron cacute -18 +KPX rcaron ccaron -18 +KPX rcaron ccedilla -18 +KPX rcaron comma -92 +KPX rcaron e -18 +KPX rcaron eacute -18 +KPX rcaron ecaron -18 +KPX rcaron ecircumflex -18 +KPX rcaron edieresis -18 +KPX rcaron edotaccent -18 +KPX rcaron egrave -18 +KPX rcaron emacron -18 +KPX rcaron eogonek -18 +KPX rcaron g -10 +KPX rcaron gbreve -10 +KPX rcaron gcommaaccent -10 +KPX rcaron hyphen -37 +KPX rcaron n -15 +KPX rcaron nacute -15 +KPX rcaron ncaron -15 +KPX rcaron ncommaaccent -15 +KPX rcaron ntilde -15 +KPX rcaron o -18 +KPX rcaron oacute -18 +KPX rcaron ocircumflex -18 +KPX rcaron odieresis -18 +KPX rcaron ograve -18 +KPX rcaron ohungarumlaut -18 +KPX rcaron omacron -18 +KPX rcaron oslash -18 +KPX rcaron otilde -18 +KPX rcaron p -10 +KPX rcaron period -100 +KPX rcaron q -18 +KPX rcaron v -10 +KPX rcommaaccent c -18 +KPX rcommaaccent cacute -18 +KPX rcommaaccent ccaron -18 +KPX rcommaaccent ccedilla -18 +KPX rcommaaccent comma -92 +KPX rcommaaccent e -18 +KPX rcommaaccent eacute -18 +KPX rcommaaccent ecaron -18 +KPX rcommaaccent ecircumflex -18 +KPX rcommaaccent edieresis -18 +KPX rcommaaccent edotaccent -18 +KPX rcommaaccent egrave -18 +KPX rcommaaccent emacron -18 +KPX rcommaaccent eogonek -18 +KPX rcommaaccent g -10 +KPX rcommaaccent gbreve -10 +KPX rcommaaccent gcommaaccent -10 +KPX rcommaaccent hyphen -37 +KPX rcommaaccent n -15 +KPX rcommaaccent nacute -15 +KPX rcommaaccent ncaron -15 +KPX rcommaaccent ncommaaccent -15 +KPX rcommaaccent ntilde -15 +KPX rcommaaccent o -18 +KPX rcommaaccent oacute -18 +KPX rcommaaccent ocircumflex -18 +KPX rcommaaccent odieresis -18 +KPX rcommaaccent ograve -18 +KPX rcommaaccent ohungarumlaut -18 +KPX rcommaaccent omacron -18 +KPX rcommaaccent oslash -18 +KPX rcommaaccent otilde -18 +KPX rcommaaccent p -10 +KPX rcommaaccent period -100 +KPX rcommaaccent q -18 +KPX rcommaaccent v -10 +KPX space A -55 +KPX space Aacute -55 +KPX space Abreve -55 +KPX space Acircumflex -55 +KPX space Adieresis -55 +KPX space Agrave -55 +KPX space Amacron -55 +KPX space Aogonek -55 +KPX space Aring -55 +KPX space Atilde -55 +KPX space T -30 +KPX space Tcaron -30 +KPX space Tcommaaccent -30 +KPX space V -45 +KPX space W -30 +KPX space Y -55 +KPX space Yacute -55 +KPX space Ydieresis -55 +KPX v a -10 +KPX v aacute -10 +KPX v abreve -10 +KPX v acircumflex -10 +KPX v adieresis -10 +KPX v agrave -10 +KPX v amacron -10 +KPX v aogonek -10 +KPX v aring -10 +KPX v atilde -10 +KPX v comma -55 +KPX v e -10 +KPX v eacute -10 +KPX v ecaron -10 +KPX v ecircumflex -10 +KPX v edieresis -10 +KPX v edotaccent -10 +KPX v egrave -10 +KPX v emacron -10 +KPX v eogonek -10 +KPX v o -10 +KPX v oacute -10 +KPX v ocircumflex -10 +KPX v odieresis -10 +KPX v ograve -10 +KPX v ohungarumlaut -10 +KPX v omacron -10 +KPX v oslash -10 +KPX v otilde -10 +KPX v period -70 +KPX w comma -55 +KPX w o -10 +KPX w oacute -10 +KPX w ocircumflex -10 +KPX w odieresis -10 +KPX w ograve -10 +KPX w ohungarumlaut -10 +KPX w omacron -10 +KPX w oslash -10 +KPX w otilde -10 +KPX w period -70 +KPX y comma -55 +KPX y e -10 +KPX y eacute -10 +KPX y ecaron -10 +KPX y ecircumflex -10 +KPX y edieresis -10 +KPX y edotaccent -10 +KPX y egrave -10 +KPX y emacron -10 +KPX y eogonek -10 +KPX y o -25 +KPX y oacute -25 +KPX y ocircumflex -25 +KPX y odieresis -25 +KPX y ograve -25 +KPX y ohungarumlaut -25 +KPX y omacron -25 +KPX y oslash -25 +KPX y otilde -25 +KPX y period -70 +KPX yacute comma -55 +KPX yacute e -10 +KPX yacute eacute -10 +KPX yacute ecaron -10 +KPX yacute ecircumflex -10 +KPX yacute edieresis -10 +KPX yacute edotaccent -10 +KPX yacute egrave -10 +KPX yacute emacron -10 +KPX yacute eogonek -10 +KPX yacute o -25 +KPX yacute oacute -25 +KPX yacute ocircumflex -25 +KPX yacute odieresis -25 +KPX yacute ograve -25 +KPX yacute ohungarumlaut -25 +KPX yacute omacron -25 +KPX yacute oslash -25 +KPX yacute otilde -25 +KPX yacute period -70 +KPX ydieresis comma -55 +KPX ydieresis e -10 +KPX ydieresis eacute -10 +KPX ydieresis ecaron -10 +KPX ydieresis ecircumflex -10 +KPX ydieresis edieresis -10 +KPX ydieresis edotaccent -10 +KPX ydieresis egrave -10 +KPX ydieresis emacron -10 +KPX ydieresis eogonek -10 +KPX ydieresis o -25 +KPX ydieresis oacute -25 +KPX ydieresis ocircumflex -25 +KPX ydieresis odieresis -25 +KPX ydieresis ograve -25 +KPX ydieresis ohungarumlaut -25 +KPX ydieresis omacron -25 +KPX ydieresis oslash -25 +KPX ydieresis otilde -25 +KPX ydieresis period -70 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Times-BoldItalic.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Times-BoldItalic.afm new file mode 100644 index 0000000..180e81e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Times-BoldItalic.afm @@ -0,0 +1,2384 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 13:04:06 1997 +Comment UniqueID 43066 +Comment VMusage 45874 56899 +FontName Times-BoldItalic +FullName Times Bold Italic +FamilyName Times +Weight Bold +ItalicAngle -15 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -200 -218 996 921 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 669 +XHeight 462 +Ascender 683 +Descender -217 +StdHW 42 +StdVW 121 +StartCharMetrics 315 +C 32 ; WX 250 ; N space ; B 0 0 0 0 ; +C 33 ; WX 389 ; N exclam ; B 67 -13 370 684 ; +C 34 ; WX 555 ; N quotedbl ; B 136 398 536 685 ; +C 35 ; WX 500 ; N numbersign ; B -33 0 533 700 ; +C 36 ; WX 500 ; N dollar ; B -20 -100 497 733 ; +C 37 ; WX 833 ; N percent ; B 39 -10 793 692 ; +C 38 ; WX 778 ; N ampersand ; B 5 -19 699 682 ; +C 39 ; WX 333 ; N quoteright ; B 98 369 302 685 ; +C 40 ; WX 333 ; N parenleft ; B 28 -179 344 685 ; +C 41 ; WX 333 ; N parenright ; B -44 -179 271 685 ; +C 42 ; WX 500 ; N asterisk ; B 65 249 456 685 ; +C 43 ; WX 570 ; N plus ; B 33 0 537 506 ; +C 44 ; WX 250 ; N comma ; B -60 -182 144 134 ; +C 45 ; WX 333 ; N hyphen ; B 2 166 271 282 ; +C 46 ; WX 250 ; N period ; B -9 -13 139 135 ; +C 47 ; WX 278 ; N slash ; B -64 -18 342 685 ; +C 48 ; WX 500 ; N zero ; B 17 -14 477 683 ; +C 49 ; WX 500 ; N one ; B 5 0 419 683 ; +C 50 ; WX 500 ; N two ; B -27 0 446 683 ; +C 51 ; WX 500 ; N three ; B -15 -13 450 683 ; +C 52 ; WX 500 ; N four ; B -15 0 503 683 ; +C 53 ; WX 500 ; N five ; B -11 -13 487 669 ; +C 54 ; WX 500 ; N six ; B 23 -15 509 679 ; +C 55 ; WX 500 ; N seven ; B 52 0 525 669 ; +C 56 ; WX 500 ; N eight ; B 3 -13 476 683 ; +C 57 ; WX 500 ; N nine ; B -12 -10 475 683 ; +C 58 ; WX 333 ; N colon ; B 23 -13 264 459 ; +C 59 ; WX 333 ; N semicolon ; B -25 -183 264 459 ; +C 60 ; WX 570 ; N less ; B 31 -8 539 514 ; +C 61 ; WX 570 ; N equal ; B 33 107 537 399 ; +C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ; +C 63 ; WX 500 ; N question ; B 79 -13 470 684 ; +C 64 ; WX 832 ; N at ; B 63 -18 770 685 ; +C 65 ; WX 667 ; N A ; B -67 0 593 683 ; +C 66 ; WX 667 ; N B ; B -24 0 624 669 ; +C 67 ; WX 667 ; N C ; B 32 -18 677 685 ; +C 68 ; WX 722 ; N D ; B -46 0 685 669 ; +C 69 ; WX 667 ; N E ; B -27 0 653 669 ; +C 70 ; WX 667 ; N F ; B -13 0 660 669 ; +C 71 ; WX 722 ; N G ; B 21 -18 706 685 ; +C 72 ; WX 778 ; N H ; B -24 0 799 669 ; +C 73 ; WX 389 ; N I ; B -32 0 406 669 ; +C 74 ; WX 500 ; N J ; B -46 -99 524 669 ; +C 75 ; WX 667 ; N K ; B -21 0 702 669 ; +C 76 ; WX 611 ; N L ; B -22 0 590 669 ; +C 77 ; WX 889 ; N M ; B -29 -12 917 669 ; +C 78 ; WX 722 ; N N ; B -27 -15 748 669 ; +C 79 ; WX 722 ; N O ; B 27 -18 691 685 ; +C 80 ; WX 611 ; N P ; B -27 0 613 669 ; +C 81 ; WX 722 ; N Q ; B 27 -208 691 685 ; +C 82 ; WX 667 ; N R ; B -29 0 623 669 ; +C 83 ; WX 556 ; N S ; B 2 -18 526 685 ; +C 84 ; WX 611 ; N T ; B 50 0 650 669 ; +C 85 ; WX 722 ; N U ; B 67 -18 744 669 ; +C 86 ; WX 667 ; N V ; B 65 -18 715 669 ; +C 87 ; WX 889 ; N W ; B 65 -18 940 669 ; +C 88 ; WX 667 ; N X ; B -24 0 694 669 ; +C 89 ; WX 611 ; N Y ; B 73 0 659 669 ; +C 90 ; WX 611 ; N Z ; B -11 0 590 669 ; +C 91 ; WX 333 ; N bracketleft ; B -37 -159 362 674 ; +C 92 ; WX 278 ; N backslash ; B -1 -18 279 685 ; +C 93 ; WX 333 ; N bracketright ; B -56 -157 343 674 ; +C 94 ; WX 570 ; N asciicircum ; B 67 304 503 669 ; +C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ; +C 96 ; WX 333 ; N quoteleft ; B 128 369 332 685 ; +C 97 ; WX 500 ; N a ; B -21 -14 455 462 ; +C 98 ; WX 500 ; N b ; B -14 -13 444 699 ; +C 99 ; WX 444 ; N c ; B -5 -13 392 462 ; +C 100 ; WX 500 ; N d ; B -21 -13 517 699 ; +C 101 ; WX 444 ; N e ; B 5 -13 398 462 ; +C 102 ; WX 333 ; N f ; B -169 -205 446 698 ; L i fi ; L l fl ; +C 103 ; WX 500 ; N g ; B -52 -203 478 462 ; +C 104 ; WX 556 ; N h ; B -13 -9 498 699 ; +C 105 ; WX 278 ; N i ; B 2 -9 263 684 ; +C 106 ; WX 278 ; N j ; B -189 -207 279 684 ; +C 107 ; WX 500 ; N k ; B -23 -8 483 699 ; +C 108 ; WX 278 ; N l ; B 2 -9 290 699 ; +C 109 ; WX 778 ; N m ; B -14 -9 722 462 ; +C 110 ; WX 556 ; N n ; B -6 -9 493 462 ; +C 111 ; WX 500 ; N o ; B -3 -13 441 462 ; +C 112 ; WX 500 ; N p ; B -120 -205 446 462 ; +C 113 ; WX 500 ; N q ; B 1 -205 471 462 ; +C 114 ; WX 389 ; N r ; B -21 0 389 462 ; +C 115 ; WX 389 ; N s ; B -19 -13 333 462 ; +C 116 ; WX 278 ; N t ; B -11 -9 281 594 ; +C 117 ; WX 556 ; N u ; B 15 -9 492 462 ; +C 118 ; WX 444 ; N v ; B 16 -13 401 462 ; +C 119 ; WX 667 ; N w ; B 16 -13 614 462 ; +C 120 ; WX 500 ; N x ; B -46 -13 469 462 ; +C 121 ; WX 444 ; N y ; B -94 -205 392 462 ; +C 122 ; WX 389 ; N z ; B -43 -78 368 449 ; +C 123 ; WX 348 ; N braceleft ; B 5 -187 436 686 ; +C 124 ; WX 220 ; N bar ; B 66 -218 154 782 ; +C 125 ; WX 348 ; N braceright ; B -129 -187 302 686 ; +C 126 ; WX 570 ; N asciitilde ; B 54 173 516 333 ; +C 161 ; WX 389 ; N exclamdown ; B 19 -205 322 492 ; +C 162 ; WX 500 ; N cent ; B 42 -143 439 576 ; +C 163 ; WX 500 ; N sterling ; B -32 -12 510 683 ; +C 164 ; WX 167 ; N fraction ; B -169 -14 324 683 ; +C 165 ; WX 500 ; N yen ; B 33 0 628 669 ; +C 166 ; WX 500 ; N florin ; B -87 -156 537 707 ; +C 167 ; WX 500 ; N section ; B 36 -143 459 685 ; +C 168 ; WX 500 ; N currency ; B -26 34 526 586 ; +C 169 ; WX 278 ; N quotesingle ; B 128 398 268 685 ; +C 170 ; WX 500 ; N quotedblleft ; B 53 369 513 685 ; +C 171 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ; +C 172 ; WX 333 ; N guilsinglleft ; B 32 32 303 415 ; +C 173 ; WX 333 ; N guilsinglright ; B 10 32 281 415 ; +C 174 ; WX 556 ; N fi ; B -188 -205 514 703 ; +C 175 ; WX 556 ; N fl ; B -186 -205 553 704 ; +C 177 ; WX 500 ; N endash ; B -40 178 477 269 ; +C 178 ; WX 500 ; N dagger ; B 91 -145 494 685 ; +C 179 ; WX 500 ; N daggerdbl ; B 10 -139 493 685 ; +C 180 ; WX 250 ; N periodcentered ; B 51 257 199 405 ; +C 182 ; WX 500 ; N paragraph ; B -57 -193 562 669 ; +C 183 ; WX 350 ; N bullet ; B 0 175 350 525 ; +C 184 ; WX 333 ; N quotesinglbase ; B -5 -182 199 134 ; +C 185 ; WX 500 ; N quotedblbase ; B -57 -182 403 134 ; +C 186 ; WX 500 ; N quotedblright ; B 53 369 513 685 ; +C 187 ; WX 500 ; N guillemotright ; B 12 32 468 415 ; +C 188 ; WX 1000 ; N ellipsis ; B 40 -13 852 135 ; +C 189 ; WX 1000 ; N perthousand ; B 7 -29 996 706 ; +C 191 ; WX 500 ; N questiondown ; B 30 -205 421 492 ; +C 193 ; WX 333 ; N grave ; B 85 516 297 697 ; +C 194 ; WX 333 ; N acute ; B 139 516 379 697 ; +C 195 ; WX 333 ; N circumflex ; B 40 516 367 690 ; +C 196 ; WX 333 ; N tilde ; B 48 536 407 655 ; +C 197 ; WX 333 ; N macron ; B 51 553 393 623 ; +C 198 ; WX 333 ; N breve ; B 71 516 387 678 ; +C 199 ; WX 333 ; N dotaccent ; B 163 550 298 684 ; +C 200 ; WX 333 ; N dieresis ; B 55 550 402 684 ; +C 202 ; WX 333 ; N ring ; B 127 516 340 729 ; +C 203 ; WX 333 ; N cedilla ; B -80 -218 156 5 ; +C 205 ; WX 333 ; N hungarumlaut ; B 69 516 498 697 ; +C 206 ; WX 333 ; N ogonek ; B 15 -183 244 34 ; +C 207 ; WX 333 ; N caron ; B 79 516 411 690 ; +C 208 ; WX 1000 ; N emdash ; B -40 178 977 269 ; +C 225 ; WX 944 ; N AE ; B -64 0 918 669 ; +C 227 ; WX 266 ; N ordfeminine ; B 16 399 330 685 ; +C 232 ; WX 611 ; N Lslash ; B -22 0 590 669 ; +C 233 ; WX 722 ; N Oslash ; B 27 -125 691 764 ; +C 234 ; WX 944 ; N OE ; B 23 -8 946 677 ; +C 235 ; WX 300 ; N ordmasculine ; B 56 400 347 685 ; +C 241 ; WX 722 ; N ae ; B -5 -13 673 462 ; +C 245 ; WX 278 ; N dotlessi ; B 2 -9 238 462 ; +C 248 ; WX 278 ; N lslash ; B -7 -9 307 699 ; +C 249 ; WX 500 ; N oslash ; B -3 -119 441 560 ; +C 250 ; WX 722 ; N oe ; B 6 -13 674 462 ; +C 251 ; WX 500 ; N germandbls ; B -200 -200 473 705 ; +C -1 ; WX 389 ; N Idieresis ; B -32 0 450 862 ; +C -1 ; WX 444 ; N eacute ; B 5 -13 435 697 ; +C -1 ; WX 500 ; N abreve ; B -21 -14 471 678 ; +C -1 ; WX 556 ; N uhungarumlaut ; B 15 -9 610 697 ; +C -1 ; WX 444 ; N ecaron ; B 5 -13 467 690 ; +C -1 ; WX 611 ; N Ydieresis ; B 73 0 659 862 ; +C -1 ; WX 570 ; N divide ; B 33 -29 537 535 ; +C -1 ; WX 611 ; N Yacute ; B 73 0 659 904 ; +C -1 ; WX 667 ; N Acircumflex ; B -67 0 593 897 ; +C -1 ; WX 500 ; N aacute ; B -21 -14 463 697 ; +C -1 ; WX 722 ; N Ucircumflex ; B 67 -18 744 897 ; +C -1 ; WX 444 ; N yacute ; B -94 -205 435 697 ; +C -1 ; WX 389 ; N scommaaccent ; B -19 -218 333 462 ; +C -1 ; WX 444 ; N ecircumflex ; B 5 -13 423 690 ; +C -1 ; WX 722 ; N Uring ; B 67 -18 744 921 ; +C -1 ; WX 722 ; N Udieresis ; B 67 -18 744 862 ; +C -1 ; WX 500 ; N aogonek ; B -21 -183 455 462 ; +C -1 ; WX 722 ; N Uacute ; B 67 -18 744 904 ; +C -1 ; WX 556 ; N uogonek ; B 15 -183 492 462 ; +C -1 ; WX 667 ; N Edieresis ; B -27 0 653 862 ; +C -1 ; WX 722 ; N Dcroat ; B -31 0 700 669 ; +C -1 ; WX 250 ; N commaaccent ; B -36 -218 131 -50 ; +C -1 ; WX 747 ; N copyright ; B 30 -18 718 685 ; +C -1 ; WX 667 ; N Emacron ; B -27 0 653 830 ; +C -1 ; WX 444 ; N ccaron ; B -5 -13 467 690 ; +C -1 ; WX 500 ; N aring ; B -21 -14 455 729 ; +C -1 ; WX 722 ; N Ncommaaccent ; B -27 -218 748 669 ; +C -1 ; WX 278 ; N lacute ; B 2 -9 392 904 ; +C -1 ; WX 500 ; N agrave ; B -21 -14 455 697 ; +C -1 ; WX 611 ; N Tcommaaccent ; B 50 -218 650 669 ; +C -1 ; WX 667 ; N Cacute ; B 32 -18 677 904 ; +C -1 ; WX 500 ; N atilde ; B -21 -14 491 655 ; +C -1 ; WX 667 ; N Edotaccent ; B -27 0 653 862 ; +C -1 ; WX 389 ; N scaron ; B -19 -13 424 690 ; +C -1 ; WX 389 ; N scedilla ; B -19 -218 333 462 ; +C -1 ; WX 278 ; N iacute ; B 2 -9 352 697 ; +C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ; +C -1 ; WX 667 ; N Rcaron ; B -29 0 623 897 ; +C -1 ; WX 722 ; N Gcommaaccent ; B 21 -218 706 685 ; +C -1 ; WX 556 ; N ucircumflex ; B 15 -9 492 690 ; +C -1 ; WX 500 ; N acircumflex ; B -21 -14 455 690 ; +C -1 ; WX 667 ; N Amacron ; B -67 0 593 830 ; +C -1 ; WX 389 ; N rcaron ; B -21 0 424 690 ; +C -1 ; WX 444 ; N ccedilla ; B -5 -218 392 462 ; +C -1 ; WX 611 ; N Zdotaccent ; B -11 0 590 862 ; +C -1 ; WX 611 ; N Thorn ; B -27 0 573 669 ; +C -1 ; WX 722 ; N Omacron ; B 27 -18 691 830 ; +C -1 ; WX 667 ; N Racute ; B -29 0 623 904 ; +C -1 ; WX 556 ; N Sacute ; B 2 -18 531 904 ; +C -1 ; WX 608 ; N dcaron ; B -21 -13 675 708 ; +C -1 ; WX 722 ; N Umacron ; B 67 -18 744 830 ; +C -1 ; WX 556 ; N uring ; B 15 -9 492 729 ; +C -1 ; WX 300 ; N threebaseior ; B 17 265 321 683 ; +C -1 ; WX 722 ; N Ograve ; B 27 -18 691 904 ; +C -1 ; WX 667 ; N Agrave ; B -67 0 593 904 ; +C -1 ; WX 667 ; N Abreve ; B -67 0 593 885 ; +C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ; +C -1 ; WX 556 ; N uacute ; B 15 -9 492 697 ; +C -1 ; WX 611 ; N Tcaron ; B 50 0 650 897 ; +C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ; +C -1 ; WX 444 ; N ydieresis ; B -94 -205 443 655 ; +C -1 ; WX 722 ; N Nacute ; B -27 -15 748 904 ; +C -1 ; WX 278 ; N icircumflex ; B -3 -9 324 690 ; +C -1 ; WX 667 ; N Ecircumflex ; B -27 0 653 897 ; +C -1 ; WX 500 ; N adieresis ; B -21 -14 476 655 ; +C -1 ; WX 444 ; N edieresis ; B 5 -13 448 655 ; +C -1 ; WX 444 ; N cacute ; B -5 -13 435 697 ; +C -1 ; WX 556 ; N nacute ; B -6 -9 493 697 ; +C -1 ; WX 556 ; N umacron ; B 15 -9 492 623 ; +C -1 ; WX 722 ; N Ncaron ; B -27 -15 748 897 ; +C -1 ; WX 389 ; N Iacute ; B -32 0 432 904 ; +C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ; +C -1 ; WX 220 ; N brokenbar ; B 66 -143 154 707 ; +C -1 ; WX 747 ; N registered ; B 30 -18 718 685 ; +C -1 ; WX 722 ; N Gbreve ; B 21 -18 706 885 ; +C -1 ; WX 389 ; N Idotaccent ; B -32 0 406 862 ; +C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ; +C -1 ; WX 667 ; N Egrave ; B -27 0 653 904 ; +C -1 ; WX 389 ; N racute ; B -21 0 407 697 ; +C -1 ; WX 500 ; N omacron ; B -3 -13 462 623 ; +C -1 ; WX 611 ; N Zacute ; B -11 0 590 904 ; +C -1 ; WX 611 ; N Zcaron ; B -11 0 590 897 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ; +C -1 ; WX 722 ; N Eth ; B -31 0 700 669 ; +C -1 ; WX 667 ; N Ccedilla ; B 32 -218 677 685 ; +C -1 ; WX 278 ; N lcommaaccent ; B -42 -218 290 699 ; +C -1 ; WX 366 ; N tcaron ; B -11 -9 434 754 ; +C -1 ; WX 444 ; N eogonek ; B 5 -183 398 462 ; +C -1 ; WX 722 ; N Uogonek ; B 67 -183 744 669 ; +C -1 ; WX 667 ; N Aacute ; B -67 0 593 904 ; +C -1 ; WX 667 ; N Adieresis ; B -67 0 593 862 ; +C -1 ; WX 444 ; N egrave ; B 5 -13 398 697 ; +C -1 ; WX 389 ; N zacute ; B -43 -78 407 697 ; +C -1 ; WX 278 ; N iogonek ; B -20 -183 263 684 ; +C -1 ; WX 722 ; N Oacute ; B 27 -18 691 904 ; +C -1 ; WX 500 ; N oacute ; B -3 -13 463 697 ; +C -1 ; WX 500 ; N amacron ; B -21 -14 467 623 ; +C -1 ; WX 389 ; N sacute ; B -19 -13 407 697 ; +C -1 ; WX 278 ; N idieresis ; B 2 -9 364 655 ; +C -1 ; WX 722 ; N Ocircumflex ; B 27 -18 691 897 ; +C -1 ; WX 722 ; N Ugrave ; B 67 -18 744 904 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 500 ; N thorn ; B -120 -205 446 699 ; +C -1 ; WX 300 ; N twobaseior ; B 2 274 313 683 ; +C -1 ; WX 722 ; N Odieresis ; B 27 -18 691 862 ; +C -1 ; WX 576 ; N mu ; B -60 -207 516 449 ; +C -1 ; WX 278 ; N igrave ; B 2 -9 259 697 ; +C -1 ; WX 500 ; N ohungarumlaut ; B -3 -13 582 697 ; +C -1 ; WX 667 ; N Eogonek ; B -27 -183 653 669 ; +C -1 ; WX 500 ; N dcroat ; B -21 -13 552 699 ; +C -1 ; WX 750 ; N threequarters ; B 7 -14 726 683 ; +C -1 ; WX 556 ; N Scedilla ; B 2 -218 526 685 ; +C -1 ; WX 382 ; N lcaron ; B 2 -9 448 708 ; +C -1 ; WX 667 ; N Kcommaaccent ; B -21 -218 702 669 ; +C -1 ; WX 611 ; N Lacute ; B -22 0 590 904 ; +C -1 ; WX 1000 ; N trademark ; B 32 263 968 669 ; +C -1 ; WX 444 ; N edotaccent ; B 5 -13 398 655 ; +C -1 ; WX 389 ; N Igrave ; B -32 0 406 904 ; +C -1 ; WX 389 ; N Imacron ; B -32 0 461 830 ; +C -1 ; WX 611 ; N Lcaron ; B -22 0 671 718 ; +C -1 ; WX 750 ; N onehalf ; B -9 -14 723 683 ; +C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ; +C -1 ; WX 500 ; N ocircumflex ; B -3 -13 451 690 ; +C -1 ; WX 556 ; N ntilde ; B -6 -9 504 655 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 67 -18 744 904 ; +C -1 ; WX 667 ; N Eacute ; B -27 0 653 904 ; +C -1 ; WX 444 ; N emacron ; B 5 -13 439 623 ; +C -1 ; WX 500 ; N gbreve ; B -52 -203 478 678 ; +C -1 ; WX 750 ; N onequarter ; B 7 -14 721 683 ; +C -1 ; WX 556 ; N Scaron ; B 2 -18 553 897 ; +C -1 ; WX 556 ; N Scommaaccent ; B 2 -218 526 685 ; +C -1 ; WX 722 ; N Ohungarumlaut ; B 27 -18 723 904 ; +C -1 ; WX 400 ; N degree ; B 83 397 369 683 ; +C -1 ; WX 500 ; N ograve ; B -3 -13 441 697 ; +C -1 ; WX 667 ; N Ccaron ; B 32 -18 677 897 ; +C -1 ; WX 556 ; N ugrave ; B 15 -9 492 697 ; +C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ; +C -1 ; WX 722 ; N Dcaron ; B -46 0 685 897 ; +C -1 ; WX 389 ; N rcommaaccent ; B -67 -218 389 462 ; +C -1 ; WX 722 ; N Ntilde ; B -27 -15 748 862 ; +C -1 ; WX 500 ; N otilde ; B -3 -13 491 655 ; +C -1 ; WX 667 ; N Rcommaaccent ; B -29 -218 623 669 ; +C -1 ; WX 611 ; N Lcommaaccent ; B -22 -218 590 669 ; +C -1 ; WX 667 ; N Atilde ; B -67 0 593 862 ; +C -1 ; WX 667 ; N Aogonek ; B -67 -183 604 683 ; +C -1 ; WX 667 ; N Aring ; B -67 0 593 921 ; +C -1 ; WX 722 ; N Otilde ; B 27 -18 691 862 ; +C -1 ; WX 389 ; N zdotaccent ; B -43 -78 368 655 ; +C -1 ; WX 667 ; N Ecaron ; B -27 0 653 897 ; +C -1 ; WX 389 ; N Iogonek ; B -32 -183 406 669 ; +C -1 ; WX 500 ; N kcommaaccent ; B -23 -218 483 699 ; +C -1 ; WX 606 ; N minus ; B 51 209 555 297 ; +C -1 ; WX 389 ; N Icircumflex ; B -32 0 450 897 ; +C -1 ; WX 556 ; N ncaron ; B -6 -9 523 690 ; +C -1 ; WX 278 ; N tcommaaccent ; B -62 -218 281 594 ; +C -1 ; WX 606 ; N logicalnot ; B 51 108 555 399 ; +C -1 ; WX 500 ; N odieresis ; B -3 -13 471 655 ; +C -1 ; WX 556 ; N udieresis ; B 15 -9 499 655 ; +C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ; +C -1 ; WX 500 ; N gcommaaccent ; B -52 -203 478 767 ; +C -1 ; WX 500 ; N eth ; B -3 -13 454 699 ; +C -1 ; WX 389 ; N zcaron ; B -43 -78 424 690 ; +C -1 ; WX 556 ; N ncommaaccent ; B -6 -218 493 462 ; +C -1 ; WX 300 ; N onebaseior ; B 30 274 301 683 ; +C -1 ; WX 278 ; N imacron ; B 2 -9 294 623 ; +C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2038 +KPX A C -65 +KPX A Cacute -65 +KPX A Ccaron -65 +KPX A Ccedilla -65 +KPX A G -60 +KPX A Gbreve -60 +KPX A Gcommaaccent -60 +KPX A O -50 +KPX A Oacute -50 +KPX A Ocircumflex -50 +KPX A Odieresis -50 +KPX A Ograve -50 +KPX A Ohungarumlaut -50 +KPX A Omacron -50 +KPX A Oslash -50 +KPX A Otilde -50 +KPX A Q -55 +KPX A T -55 +KPX A Tcaron -55 +KPX A Tcommaaccent -55 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -95 +KPX A W -100 +KPX A Y -70 +KPX A Yacute -70 +KPX A Ydieresis -70 +KPX A quoteright -74 +KPX A u -30 +KPX A uacute -30 +KPX A ucircumflex -30 +KPX A udieresis -30 +KPX A ugrave -30 +KPX A uhungarumlaut -30 +KPX A umacron -30 +KPX A uogonek -30 +KPX A uring -30 +KPX A v -74 +KPX A w -74 +KPX A y -74 +KPX A yacute -74 +KPX A ydieresis -74 +KPX Aacute C -65 +KPX Aacute Cacute -65 +KPX Aacute Ccaron -65 +KPX Aacute Ccedilla -65 +KPX Aacute G -60 +KPX Aacute Gbreve -60 +KPX Aacute Gcommaaccent -60 +KPX Aacute O -50 +KPX Aacute Oacute -50 +KPX Aacute Ocircumflex -50 +KPX Aacute Odieresis -50 +KPX Aacute Ograve -50 +KPX Aacute Ohungarumlaut -50 +KPX Aacute Omacron -50 +KPX Aacute Oslash -50 +KPX Aacute Otilde -50 +KPX Aacute Q -55 +KPX Aacute T -55 +KPX Aacute Tcaron -55 +KPX Aacute Tcommaaccent -55 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -95 +KPX Aacute W -100 +KPX Aacute Y -70 +KPX Aacute Yacute -70 +KPX Aacute Ydieresis -70 +KPX Aacute quoteright -74 +KPX Aacute u -30 +KPX Aacute uacute -30 +KPX Aacute ucircumflex -30 +KPX Aacute udieresis -30 +KPX Aacute ugrave -30 +KPX Aacute uhungarumlaut -30 +KPX Aacute umacron -30 +KPX Aacute uogonek -30 +KPX Aacute uring -30 +KPX Aacute v -74 +KPX Aacute w -74 +KPX Aacute y -74 +KPX Aacute yacute -74 +KPX Aacute ydieresis -74 +KPX Abreve C -65 +KPX Abreve Cacute -65 +KPX Abreve Ccaron -65 +KPX Abreve Ccedilla -65 +KPX Abreve G -60 +KPX Abreve Gbreve -60 +KPX Abreve Gcommaaccent -60 +KPX Abreve O -50 +KPX Abreve Oacute -50 +KPX Abreve Ocircumflex -50 +KPX Abreve Odieresis -50 +KPX Abreve Ograve -50 +KPX Abreve Ohungarumlaut -50 +KPX Abreve Omacron -50 +KPX Abreve Oslash -50 +KPX Abreve Otilde -50 +KPX Abreve Q -55 +KPX Abreve T -55 +KPX Abreve Tcaron -55 +KPX Abreve Tcommaaccent -55 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -95 +KPX Abreve W -100 +KPX Abreve Y -70 +KPX Abreve Yacute -70 +KPX Abreve Ydieresis -70 +KPX Abreve quoteright -74 +KPX Abreve u -30 +KPX Abreve uacute -30 +KPX Abreve ucircumflex -30 +KPX Abreve udieresis -30 +KPX Abreve ugrave -30 +KPX Abreve uhungarumlaut -30 +KPX Abreve umacron -30 +KPX Abreve uogonek -30 +KPX Abreve uring -30 +KPX Abreve v -74 +KPX Abreve w -74 +KPX Abreve y -74 +KPX Abreve yacute -74 +KPX Abreve ydieresis -74 +KPX Acircumflex C -65 +KPX Acircumflex Cacute -65 +KPX Acircumflex Ccaron -65 +KPX Acircumflex Ccedilla -65 +KPX Acircumflex G -60 +KPX Acircumflex Gbreve -60 +KPX Acircumflex Gcommaaccent -60 +KPX Acircumflex O -50 +KPX Acircumflex Oacute -50 +KPX Acircumflex Ocircumflex -50 +KPX Acircumflex Odieresis -50 +KPX Acircumflex Ograve -50 +KPX Acircumflex Ohungarumlaut -50 +KPX Acircumflex Omacron -50 +KPX Acircumflex Oslash -50 +KPX Acircumflex Otilde -50 +KPX Acircumflex Q -55 +KPX Acircumflex T -55 +KPX Acircumflex Tcaron -55 +KPX Acircumflex Tcommaaccent -55 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -95 +KPX Acircumflex W -100 +KPX Acircumflex Y -70 +KPX Acircumflex Yacute -70 +KPX Acircumflex Ydieresis -70 +KPX Acircumflex quoteright -74 +KPX Acircumflex u -30 +KPX Acircumflex uacute -30 +KPX Acircumflex ucircumflex -30 +KPX Acircumflex udieresis -30 +KPX Acircumflex ugrave -30 +KPX Acircumflex uhungarumlaut -30 +KPX Acircumflex umacron -30 +KPX Acircumflex uogonek -30 +KPX Acircumflex uring -30 +KPX Acircumflex v -74 +KPX Acircumflex w -74 +KPX Acircumflex y -74 +KPX Acircumflex yacute -74 +KPX Acircumflex ydieresis -74 +KPX Adieresis C -65 +KPX Adieresis Cacute -65 +KPX Adieresis Ccaron -65 +KPX Adieresis Ccedilla -65 +KPX Adieresis G -60 +KPX Adieresis Gbreve -60 +KPX Adieresis Gcommaaccent -60 +KPX Adieresis O -50 +KPX Adieresis Oacute -50 +KPX Adieresis Ocircumflex -50 +KPX Adieresis Odieresis -50 +KPX Adieresis Ograve -50 +KPX Adieresis Ohungarumlaut -50 +KPX Adieresis Omacron -50 +KPX Adieresis Oslash -50 +KPX Adieresis Otilde -50 +KPX Adieresis Q -55 +KPX Adieresis T -55 +KPX Adieresis Tcaron -55 +KPX Adieresis Tcommaaccent -55 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -95 +KPX Adieresis W -100 +KPX Adieresis Y -70 +KPX Adieresis Yacute -70 +KPX Adieresis Ydieresis -70 +KPX Adieresis quoteright -74 +KPX Adieresis u -30 +KPX Adieresis uacute -30 +KPX Adieresis ucircumflex -30 +KPX Adieresis udieresis -30 +KPX Adieresis ugrave -30 +KPX Adieresis uhungarumlaut -30 +KPX Adieresis umacron -30 +KPX Adieresis uogonek -30 +KPX Adieresis uring -30 +KPX Adieresis v -74 +KPX Adieresis w -74 +KPX Adieresis y -74 +KPX Adieresis yacute -74 +KPX Adieresis ydieresis -74 +KPX Agrave C -65 +KPX Agrave Cacute -65 +KPX Agrave Ccaron -65 +KPX Agrave Ccedilla -65 +KPX Agrave G -60 +KPX Agrave Gbreve -60 +KPX Agrave Gcommaaccent -60 +KPX Agrave O -50 +KPX Agrave Oacute -50 +KPX Agrave Ocircumflex -50 +KPX Agrave Odieresis -50 +KPX Agrave Ograve -50 +KPX Agrave Ohungarumlaut -50 +KPX Agrave Omacron -50 +KPX Agrave Oslash -50 +KPX Agrave Otilde -50 +KPX Agrave Q -55 +KPX Agrave T -55 +KPX Agrave Tcaron -55 +KPX Agrave Tcommaaccent -55 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -95 +KPX Agrave W -100 +KPX Agrave Y -70 +KPX Agrave Yacute -70 +KPX Agrave Ydieresis -70 +KPX Agrave quoteright -74 +KPX Agrave u -30 +KPX Agrave uacute -30 +KPX Agrave ucircumflex -30 +KPX Agrave udieresis -30 +KPX Agrave ugrave -30 +KPX Agrave uhungarumlaut -30 +KPX Agrave umacron -30 +KPX Agrave uogonek -30 +KPX Agrave uring -30 +KPX Agrave v -74 +KPX Agrave w -74 +KPX Agrave y -74 +KPX Agrave yacute -74 +KPX Agrave ydieresis -74 +KPX Amacron C -65 +KPX Amacron Cacute -65 +KPX Amacron Ccaron -65 +KPX Amacron Ccedilla -65 +KPX Amacron G -60 +KPX Amacron Gbreve -60 +KPX Amacron Gcommaaccent -60 +KPX Amacron O -50 +KPX Amacron Oacute -50 +KPX Amacron Ocircumflex -50 +KPX Amacron Odieresis -50 +KPX Amacron Ograve -50 +KPX Amacron Ohungarumlaut -50 +KPX Amacron Omacron -50 +KPX Amacron Oslash -50 +KPX Amacron Otilde -50 +KPX Amacron Q -55 +KPX Amacron T -55 +KPX Amacron Tcaron -55 +KPX Amacron Tcommaaccent -55 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -95 +KPX Amacron W -100 +KPX Amacron Y -70 +KPX Amacron Yacute -70 +KPX Amacron Ydieresis -70 +KPX Amacron quoteright -74 +KPX Amacron u -30 +KPX Amacron uacute -30 +KPX Amacron ucircumflex -30 +KPX Amacron udieresis -30 +KPX Amacron ugrave -30 +KPX Amacron uhungarumlaut -30 +KPX Amacron umacron -30 +KPX Amacron uogonek -30 +KPX Amacron uring -30 +KPX Amacron v -74 +KPX Amacron w -74 +KPX Amacron y -74 +KPX Amacron yacute -74 +KPX Amacron ydieresis -74 +KPX Aogonek C -65 +KPX Aogonek Cacute -65 +KPX Aogonek Ccaron -65 +KPX Aogonek Ccedilla -65 +KPX Aogonek G -60 +KPX Aogonek Gbreve -60 +KPX Aogonek Gcommaaccent -60 +KPX Aogonek O -50 +KPX Aogonek Oacute -50 +KPX Aogonek Ocircumflex -50 +KPX Aogonek Odieresis -50 +KPX Aogonek Ograve -50 +KPX Aogonek Ohungarumlaut -50 +KPX Aogonek Omacron -50 +KPX Aogonek Oslash -50 +KPX Aogonek Otilde -50 +KPX Aogonek Q -55 +KPX Aogonek T -55 +KPX Aogonek Tcaron -55 +KPX Aogonek Tcommaaccent -55 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -95 +KPX Aogonek W -100 +KPX Aogonek Y -70 +KPX Aogonek Yacute -70 +KPX Aogonek Ydieresis -70 +KPX Aogonek quoteright -74 +KPX Aogonek u -30 +KPX Aogonek uacute -30 +KPX Aogonek ucircumflex -30 +KPX Aogonek udieresis -30 +KPX Aogonek ugrave -30 +KPX Aogonek uhungarumlaut -30 +KPX Aogonek umacron -30 +KPX Aogonek uogonek -30 +KPX Aogonek uring -30 +KPX Aogonek v -74 +KPX Aogonek w -74 +KPX Aogonek y -34 +KPX Aogonek yacute -34 +KPX Aogonek ydieresis -34 +KPX Aring C -65 +KPX Aring Cacute -65 +KPX Aring Ccaron -65 +KPX Aring Ccedilla -65 +KPX Aring G -60 +KPX Aring Gbreve -60 +KPX Aring Gcommaaccent -60 +KPX Aring O -50 +KPX Aring Oacute -50 +KPX Aring Ocircumflex -50 +KPX Aring Odieresis -50 +KPX Aring Ograve -50 +KPX Aring Ohungarumlaut -50 +KPX Aring Omacron -50 +KPX Aring Oslash -50 +KPX Aring Otilde -50 +KPX Aring Q -55 +KPX Aring T -55 +KPX Aring Tcaron -55 +KPX Aring Tcommaaccent -55 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -95 +KPX Aring W -100 +KPX Aring Y -70 +KPX Aring Yacute -70 +KPX Aring Ydieresis -70 +KPX Aring quoteright -74 +KPX Aring u -30 +KPX Aring uacute -30 +KPX Aring ucircumflex -30 +KPX Aring udieresis -30 +KPX Aring ugrave -30 +KPX Aring uhungarumlaut -30 +KPX Aring umacron -30 +KPX Aring uogonek -30 +KPX Aring uring -30 +KPX Aring v -74 +KPX Aring w -74 +KPX Aring y -74 +KPX Aring yacute -74 +KPX Aring ydieresis -74 +KPX Atilde C -65 +KPX Atilde Cacute -65 +KPX Atilde Ccaron -65 +KPX Atilde Ccedilla -65 +KPX Atilde G -60 +KPX Atilde Gbreve -60 +KPX Atilde Gcommaaccent -60 +KPX Atilde O -50 +KPX Atilde Oacute -50 +KPX Atilde Ocircumflex -50 +KPX Atilde Odieresis -50 +KPX Atilde Ograve -50 +KPX Atilde Ohungarumlaut -50 +KPX Atilde Omacron -50 +KPX Atilde Oslash -50 +KPX Atilde Otilde -50 +KPX Atilde Q -55 +KPX Atilde T -55 +KPX Atilde Tcaron -55 +KPX Atilde Tcommaaccent -55 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -95 +KPX Atilde W -100 +KPX Atilde Y -70 +KPX Atilde Yacute -70 +KPX Atilde Ydieresis -70 +KPX Atilde quoteright -74 +KPX Atilde u -30 +KPX Atilde uacute -30 +KPX Atilde ucircumflex -30 +KPX Atilde udieresis -30 +KPX Atilde ugrave -30 +KPX Atilde uhungarumlaut -30 +KPX Atilde umacron -30 +KPX Atilde uogonek -30 +KPX Atilde uring -30 +KPX Atilde v -74 +KPX Atilde w -74 +KPX Atilde y -74 +KPX Atilde yacute -74 +KPX Atilde ydieresis -74 +KPX B A -25 +KPX B Aacute -25 +KPX B Abreve -25 +KPX B Acircumflex -25 +KPX B Adieresis -25 +KPX B Agrave -25 +KPX B Amacron -25 +KPX B Aogonek -25 +KPX B Aring -25 +KPX B Atilde -25 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX D A -25 +KPX D Aacute -25 +KPX D Abreve -25 +KPX D Acircumflex -25 +KPX D Adieresis -25 +KPX D Agrave -25 +KPX D Amacron -25 +KPX D Aogonek -25 +KPX D Aring -25 +KPX D Atilde -25 +KPX D V -50 +KPX D W -40 +KPX D Y -50 +KPX D Yacute -50 +KPX D Ydieresis -50 +KPX Dcaron A -25 +KPX Dcaron Aacute -25 +KPX Dcaron Abreve -25 +KPX Dcaron Acircumflex -25 +KPX Dcaron Adieresis -25 +KPX Dcaron Agrave -25 +KPX Dcaron Amacron -25 +KPX Dcaron Aogonek -25 +KPX Dcaron Aring -25 +KPX Dcaron Atilde -25 +KPX Dcaron V -50 +KPX Dcaron W -40 +KPX Dcaron Y -50 +KPX Dcaron Yacute -50 +KPX Dcaron Ydieresis -50 +KPX Dcroat A -25 +KPX Dcroat Aacute -25 +KPX Dcroat Abreve -25 +KPX Dcroat Acircumflex -25 +KPX Dcroat Adieresis -25 +KPX Dcroat Agrave -25 +KPX Dcroat Amacron -25 +KPX Dcroat Aogonek -25 +KPX Dcroat Aring -25 +KPX Dcroat Atilde -25 +KPX Dcroat V -50 +KPX Dcroat W -40 +KPX Dcroat Y -50 +KPX Dcroat Yacute -50 +KPX Dcroat Ydieresis -50 +KPX F A -100 +KPX F Aacute -100 +KPX F Abreve -100 +KPX F Acircumflex -100 +KPX F Adieresis -100 +KPX F Agrave -100 +KPX F Amacron -100 +KPX F Aogonek -100 +KPX F Aring -100 +KPX F Atilde -100 +KPX F a -95 +KPX F aacute -95 +KPX F abreve -95 +KPX F acircumflex -95 +KPX F adieresis -95 +KPX F agrave -95 +KPX F amacron -95 +KPX F aogonek -95 +KPX F aring -95 +KPX F atilde -95 +KPX F comma -129 +KPX F e -100 +KPX F eacute -100 +KPX F ecaron -100 +KPX F ecircumflex -100 +KPX F edieresis -100 +KPX F edotaccent -100 +KPX F egrave -100 +KPX F emacron -100 +KPX F eogonek -100 +KPX F i -40 +KPX F iacute -40 +KPX F icircumflex -40 +KPX F idieresis -40 +KPX F igrave -40 +KPX F imacron -40 +KPX F iogonek -40 +KPX F o -70 +KPX F oacute -70 +KPX F ocircumflex -70 +KPX F odieresis -70 +KPX F ograve -70 +KPX F ohungarumlaut -70 +KPX F omacron -70 +KPX F oslash -70 +KPX F otilde -70 +KPX F period -129 +KPX F r -50 +KPX F racute -50 +KPX F rcaron -50 +KPX F rcommaaccent -50 +KPX J A -25 +KPX J Aacute -25 +KPX J Abreve -25 +KPX J Acircumflex -25 +KPX J Adieresis -25 +KPX J Agrave -25 +KPX J Amacron -25 +KPX J Aogonek -25 +KPX J Aring -25 +KPX J Atilde -25 +KPX J a -40 +KPX J aacute -40 +KPX J abreve -40 +KPX J acircumflex -40 +KPX J adieresis -40 +KPX J agrave -40 +KPX J amacron -40 +KPX J aogonek -40 +KPX J aring -40 +KPX J atilde -40 +KPX J comma -10 +KPX J e -40 +KPX J eacute -40 +KPX J ecaron -40 +KPX J ecircumflex -40 +KPX J edieresis -40 +KPX J edotaccent -40 +KPX J egrave -40 +KPX J emacron -40 +KPX J eogonek -40 +KPX J o -40 +KPX J oacute -40 +KPX J ocircumflex -40 +KPX J odieresis -40 +KPX J ograve -40 +KPX J ohungarumlaut -40 +KPX J omacron -40 +KPX J oslash -40 +KPX J otilde -40 +KPX J period -10 +KPX J u -40 +KPX J uacute -40 +KPX J ucircumflex -40 +KPX J udieresis -40 +KPX J ugrave -40 +KPX J uhungarumlaut -40 +KPX J umacron -40 +KPX J uogonek -40 +KPX J uring -40 +KPX K O -30 +KPX K Oacute -30 +KPX K Ocircumflex -30 +KPX K Odieresis -30 +KPX K Ograve -30 +KPX K Ohungarumlaut -30 +KPX K Omacron -30 +KPX K Oslash -30 +KPX K Otilde -30 +KPX K e -25 +KPX K eacute -25 +KPX K ecaron -25 +KPX K ecircumflex -25 +KPX K edieresis -25 +KPX K edotaccent -25 +KPX K egrave -25 +KPX K emacron -25 +KPX K eogonek -25 +KPX K o -25 +KPX K oacute -25 +KPX K ocircumflex -25 +KPX K odieresis -25 +KPX K ograve -25 +KPX K ohungarumlaut -25 +KPX K omacron -25 +KPX K oslash -25 +KPX K otilde -25 +KPX K u -20 +KPX K uacute -20 +KPX K ucircumflex -20 +KPX K udieresis -20 +KPX K ugrave -20 +KPX K uhungarumlaut -20 +KPX K umacron -20 +KPX K uogonek -20 +KPX K uring -20 +KPX K y -20 +KPX K yacute -20 +KPX K ydieresis -20 +KPX Kcommaaccent O -30 +KPX Kcommaaccent Oacute -30 +KPX Kcommaaccent Ocircumflex -30 +KPX Kcommaaccent Odieresis -30 +KPX Kcommaaccent Ograve -30 +KPX Kcommaaccent Ohungarumlaut -30 +KPX Kcommaaccent Omacron -30 +KPX Kcommaaccent Oslash -30 +KPX Kcommaaccent Otilde -30 +KPX Kcommaaccent e -25 +KPX Kcommaaccent eacute -25 +KPX Kcommaaccent ecaron -25 +KPX Kcommaaccent ecircumflex -25 +KPX Kcommaaccent edieresis -25 +KPX Kcommaaccent edotaccent -25 +KPX Kcommaaccent egrave -25 +KPX Kcommaaccent emacron -25 +KPX Kcommaaccent eogonek -25 +KPX Kcommaaccent o -25 +KPX Kcommaaccent oacute -25 +KPX Kcommaaccent ocircumflex -25 +KPX Kcommaaccent odieresis -25 +KPX Kcommaaccent ograve -25 +KPX Kcommaaccent ohungarumlaut -25 +KPX Kcommaaccent omacron -25 +KPX Kcommaaccent oslash -25 +KPX Kcommaaccent otilde -25 +KPX Kcommaaccent u -20 +KPX Kcommaaccent uacute -20 +KPX Kcommaaccent ucircumflex -20 +KPX Kcommaaccent udieresis -20 +KPX Kcommaaccent ugrave -20 +KPX Kcommaaccent uhungarumlaut -20 +KPX Kcommaaccent umacron -20 +KPX Kcommaaccent uogonek -20 +KPX Kcommaaccent uring -20 +KPX Kcommaaccent y -20 +KPX Kcommaaccent yacute -20 +KPX Kcommaaccent ydieresis -20 +KPX L T -18 +KPX L Tcaron -18 +KPX L Tcommaaccent -18 +KPX L V -37 +KPX L W -37 +KPX L Y -37 +KPX L Yacute -37 +KPX L Ydieresis -37 +KPX L quoteright -55 +KPX L y -37 +KPX L yacute -37 +KPX L ydieresis -37 +KPX Lacute T -18 +KPX Lacute Tcaron -18 +KPX Lacute Tcommaaccent -18 +KPX Lacute V -37 +KPX Lacute W -37 +KPX Lacute Y -37 +KPX Lacute Yacute -37 +KPX Lacute Ydieresis -37 +KPX Lacute quoteright -55 +KPX Lacute y -37 +KPX Lacute yacute -37 +KPX Lacute ydieresis -37 +KPX Lcommaaccent T -18 +KPX Lcommaaccent Tcaron -18 +KPX Lcommaaccent Tcommaaccent -18 +KPX Lcommaaccent V -37 +KPX Lcommaaccent W -37 +KPX Lcommaaccent Y -37 +KPX Lcommaaccent Yacute -37 +KPX Lcommaaccent Ydieresis -37 +KPX Lcommaaccent quoteright -55 +KPX Lcommaaccent y -37 +KPX Lcommaaccent yacute -37 +KPX Lcommaaccent ydieresis -37 +KPX Lslash T -18 +KPX Lslash Tcaron -18 +KPX Lslash Tcommaaccent -18 +KPX Lslash V -37 +KPX Lslash W -37 +KPX Lslash Y -37 +KPX Lslash Yacute -37 +KPX Lslash Ydieresis -37 +KPX Lslash quoteright -55 +KPX Lslash y -37 +KPX Lslash yacute -37 +KPX Lslash ydieresis -37 +KPX N A -30 +KPX N Aacute -30 +KPX N Abreve -30 +KPX N Acircumflex -30 +KPX N Adieresis -30 +KPX N Agrave -30 +KPX N Amacron -30 +KPX N Aogonek -30 +KPX N Aring -30 +KPX N Atilde -30 +KPX Nacute A -30 +KPX Nacute Aacute -30 +KPX Nacute Abreve -30 +KPX Nacute Acircumflex -30 +KPX Nacute Adieresis -30 +KPX Nacute Agrave -30 +KPX Nacute Amacron -30 +KPX Nacute Aogonek -30 +KPX Nacute Aring -30 +KPX Nacute Atilde -30 +KPX Ncaron A -30 +KPX Ncaron Aacute -30 +KPX Ncaron Abreve -30 +KPX Ncaron Acircumflex -30 +KPX Ncaron Adieresis -30 +KPX Ncaron Agrave -30 +KPX Ncaron Amacron -30 +KPX Ncaron Aogonek -30 +KPX Ncaron Aring -30 +KPX Ncaron Atilde -30 +KPX Ncommaaccent A -30 +KPX Ncommaaccent Aacute -30 +KPX Ncommaaccent Abreve -30 +KPX Ncommaaccent Acircumflex -30 +KPX Ncommaaccent Adieresis -30 +KPX Ncommaaccent Agrave -30 +KPX Ncommaaccent Amacron -30 +KPX Ncommaaccent Aogonek -30 +KPX Ncommaaccent Aring -30 +KPX Ncommaaccent Atilde -30 +KPX Ntilde A -30 +KPX Ntilde Aacute -30 +KPX Ntilde Abreve -30 +KPX Ntilde Acircumflex -30 +KPX Ntilde Adieresis -30 +KPX Ntilde Agrave -30 +KPX Ntilde Amacron -30 +KPX Ntilde Aogonek -30 +KPX Ntilde Aring -30 +KPX Ntilde Atilde -30 +KPX O A -40 +KPX O Aacute -40 +KPX O Abreve -40 +KPX O Acircumflex -40 +KPX O Adieresis -40 +KPX O Agrave -40 +KPX O Amacron -40 +KPX O Aogonek -40 +KPX O Aring -40 +KPX O Atilde -40 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -50 +KPX O X -40 +KPX O Y -50 +KPX O Yacute -50 +KPX O Ydieresis -50 +KPX Oacute A -40 +KPX Oacute Aacute -40 +KPX Oacute Abreve -40 +KPX Oacute Acircumflex -40 +KPX Oacute Adieresis -40 +KPX Oacute Agrave -40 +KPX Oacute Amacron -40 +KPX Oacute Aogonek -40 +KPX Oacute Aring -40 +KPX Oacute Atilde -40 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -50 +KPX Oacute X -40 +KPX Oacute Y -50 +KPX Oacute Yacute -50 +KPX Oacute Ydieresis -50 +KPX Ocircumflex A -40 +KPX Ocircumflex Aacute -40 +KPX Ocircumflex Abreve -40 +KPX Ocircumflex Acircumflex -40 +KPX Ocircumflex Adieresis -40 +KPX Ocircumflex Agrave -40 +KPX Ocircumflex Amacron -40 +KPX Ocircumflex Aogonek -40 +KPX Ocircumflex Aring -40 +KPX Ocircumflex Atilde -40 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -50 +KPX Ocircumflex X -40 +KPX Ocircumflex Y -50 +KPX Ocircumflex Yacute -50 +KPX Ocircumflex Ydieresis -50 +KPX Odieresis A -40 +KPX Odieresis Aacute -40 +KPX Odieresis Abreve -40 +KPX Odieresis Acircumflex -40 +KPX Odieresis Adieresis -40 +KPX Odieresis Agrave -40 +KPX Odieresis Amacron -40 +KPX Odieresis Aogonek -40 +KPX Odieresis Aring -40 +KPX Odieresis Atilde -40 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -50 +KPX Odieresis X -40 +KPX Odieresis Y -50 +KPX Odieresis Yacute -50 +KPX Odieresis Ydieresis -50 +KPX Ograve A -40 +KPX Ograve Aacute -40 +KPX Ograve Abreve -40 +KPX Ograve Acircumflex -40 +KPX Ograve Adieresis -40 +KPX Ograve Agrave -40 +KPX Ograve Amacron -40 +KPX Ograve Aogonek -40 +KPX Ograve Aring -40 +KPX Ograve Atilde -40 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -50 +KPX Ograve X -40 +KPX Ograve Y -50 +KPX Ograve Yacute -50 +KPX Ograve Ydieresis -50 +KPX Ohungarumlaut A -40 +KPX Ohungarumlaut Aacute -40 +KPX Ohungarumlaut Abreve -40 +KPX Ohungarumlaut Acircumflex -40 +KPX Ohungarumlaut Adieresis -40 +KPX Ohungarumlaut Agrave -40 +KPX Ohungarumlaut Amacron -40 +KPX Ohungarumlaut Aogonek -40 +KPX Ohungarumlaut Aring -40 +KPX Ohungarumlaut Atilde -40 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -50 +KPX Ohungarumlaut X -40 +KPX Ohungarumlaut Y -50 +KPX Ohungarumlaut Yacute -50 +KPX Ohungarumlaut Ydieresis -50 +KPX Omacron A -40 +KPX Omacron Aacute -40 +KPX Omacron Abreve -40 +KPX Omacron Acircumflex -40 +KPX Omacron Adieresis -40 +KPX Omacron Agrave -40 +KPX Omacron Amacron -40 +KPX Omacron Aogonek -40 +KPX Omacron Aring -40 +KPX Omacron Atilde -40 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -50 +KPX Omacron X -40 +KPX Omacron Y -50 +KPX Omacron Yacute -50 +KPX Omacron Ydieresis -50 +KPX Oslash A -40 +KPX Oslash Aacute -40 +KPX Oslash Abreve -40 +KPX Oslash Acircumflex -40 +KPX Oslash Adieresis -40 +KPX Oslash Agrave -40 +KPX Oslash Amacron -40 +KPX Oslash Aogonek -40 +KPX Oslash Aring -40 +KPX Oslash Atilde -40 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -50 +KPX Oslash X -40 +KPX Oslash Y -50 +KPX Oslash Yacute -50 +KPX Oslash Ydieresis -50 +KPX Otilde A -40 +KPX Otilde Aacute -40 +KPX Otilde Abreve -40 +KPX Otilde Acircumflex -40 +KPX Otilde Adieresis -40 +KPX Otilde Agrave -40 +KPX Otilde Amacron -40 +KPX Otilde Aogonek -40 +KPX Otilde Aring -40 +KPX Otilde Atilde -40 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -50 +KPX Otilde X -40 +KPX Otilde Y -50 +KPX Otilde Yacute -50 +KPX Otilde Ydieresis -50 +KPX P A -85 +KPX P Aacute -85 +KPX P Abreve -85 +KPX P Acircumflex -85 +KPX P Adieresis -85 +KPX P Agrave -85 +KPX P Amacron -85 +KPX P Aogonek -85 +KPX P Aring -85 +KPX P Atilde -85 +KPX P a -40 +KPX P aacute -40 +KPX P abreve -40 +KPX P acircumflex -40 +KPX P adieresis -40 +KPX P agrave -40 +KPX P amacron -40 +KPX P aogonek -40 +KPX P aring -40 +KPX P atilde -40 +KPX P comma -129 +KPX P e -50 +KPX P eacute -50 +KPX P ecaron -50 +KPX P ecircumflex -50 +KPX P edieresis -50 +KPX P edotaccent -50 +KPX P egrave -50 +KPX P emacron -50 +KPX P eogonek -50 +KPX P o -55 +KPX P oacute -55 +KPX P ocircumflex -55 +KPX P odieresis -55 +KPX P ograve -55 +KPX P ohungarumlaut -55 +KPX P omacron -55 +KPX P oslash -55 +KPX P otilde -55 +KPX P period -129 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX R O -40 +KPX R Oacute -40 +KPX R Ocircumflex -40 +KPX R Odieresis -40 +KPX R Ograve -40 +KPX R Ohungarumlaut -40 +KPX R Omacron -40 +KPX R Oslash -40 +KPX R Otilde -40 +KPX R T -30 +KPX R Tcaron -30 +KPX R Tcommaaccent -30 +KPX R U -40 +KPX R Uacute -40 +KPX R Ucircumflex -40 +KPX R Udieresis -40 +KPX R Ugrave -40 +KPX R Uhungarumlaut -40 +KPX R Umacron -40 +KPX R Uogonek -40 +KPX R Uring -40 +KPX R V -18 +KPX R W -18 +KPX R Y -18 +KPX R Yacute -18 +KPX R Ydieresis -18 +KPX Racute O -40 +KPX Racute Oacute -40 +KPX Racute Ocircumflex -40 +KPX Racute Odieresis -40 +KPX Racute Ograve -40 +KPX Racute Ohungarumlaut -40 +KPX Racute Omacron -40 +KPX Racute Oslash -40 +KPX Racute Otilde -40 +KPX Racute T -30 +KPX Racute Tcaron -30 +KPX Racute Tcommaaccent -30 +KPX Racute U -40 +KPX Racute Uacute -40 +KPX Racute Ucircumflex -40 +KPX Racute Udieresis -40 +KPX Racute Ugrave -40 +KPX Racute Uhungarumlaut -40 +KPX Racute Umacron -40 +KPX Racute Uogonek -40 +KPX Racute Uring -40 +KPX Racute V -18 +KPX Racute W -18 +KPX Racute Y -18 +KPX Racute Yacute -18 +KPX Racute Ydieresis -18 +KPX Rcaron O -40 +KPX Rcaron Oacute -40 +KPX Rcaron Ocircumflex -40 +KPX Rcaron Odieresis -40 +KPX Rcaron Ograve -40 +KPX Rcaron Ohungarumlaut -40 +KPX Rcaron Omacron -40 +KPX Rcaron Oslash -40 +KPX Rcaron Otilde -40 +KPX Rcaron T -30 +KPX Rcaron Tcaron -30 +KPX Rcaron Tcommaaccent -30 +KPX Rcaron U -40 +KPX Rcaron Uacute -40 +KPX Rcaron Ucircumflex -40 +KPX Rcaron Udieresis -40 +KPX Rcaron Ugrave -40 +KPX Rcaron Uhungarumlaut -40 +KPX Rcaron Umacron -40 +KPX Rcaron Uogonek -40 +KPX Rcaron Uring -40 +KPX Rcaron V -18 +KPX Rcaron W -18 +KPX Rcaron Y -18 +KPX Rcaron Yacute -18 +KPX Rcaron Ydieresis -18 +KPX Rcommaaccent O -40 +KPX Rcommaaccent Oacute -40 +KPX Rcommaaccent Ocircumflex -40 +KPX Rcommaaccent Odieresis -40 +KPX Rcommaaccent Ograve -40 +KPX Rcommaaccent Ohungarumlaut -40 +KPX Rcommaaccent Omacron -40 +KPX Rcommaaccent Oslash -40 +KPX Rcommaaccent Otilde -40 +KPX Rcommaaccent T -30 +KPX Rcommaaccent Tcaron -30 +KPX Rcommaaccent Tcommaaccent -30 +KPX Rcommaaccent U -40 +KPX Rcommaaccent Uacute -40 +KPX Rcommaaccent Ucircumflex -40 +KPX Rcommaaccent Udieresis -40 +KPX Rcommaaccent Ugrave -40 +KPX Rcommaaccent Uhungarumlaut -40 +KPX Rcommaaccent Umacron -40 +KPX Rcommaaccent Uogonek -40 +KPX Rcommaaccent Uring -40 +KPX Rcommaaccent V -18 +KPX Rcommaaccent W -18 +KPX Rcommaaccent Y -18 +KPX Rcommaaccent Yacute -18 +KPX Rcommaaccent Ydieresis -18 +KPX T A -55 +KPX T Aacute -55 +KPX T Abreve -55 +KPX T Acircumflex -55 +KPX T Adieresis -55 +KPX T Agrave -55 +KPX T Amacron -55 +KPX T Aogonek -55 +KPX T Aring -55 +KPX T Atilde -55 +KPX T O -18 +KPX T Oacute -18 +KPX T Ocircumflex -18 +KPX T Odieresis -18 +KPX T Ograve -18 +KPX T Ohungarumlaut -18 +KPX T Omacron -18 +KPX T Oslash -18 +KPX T Otilde -18 +KPX T a -92 +KPX T aacute -92 +KPX T abreve -92 +KPX T acircumflex -92 +KPX T adieresis -92 +KPX T agrave -92 +KPX T amacron -92 +KPX T aogonek -92 +KPX T aring -92 +KPX T atilde -92 +KPX T colon -74 +KPX T comma -92 +KPX T e -92 +KPX T eacute -92 +KPX T ecaron -92 +KPX T ecircumflex -92 +KPX T edieresis -52 +KPX T edotaccent -92 +KPX T egrave -52 +KPX T emacron -52 +KPX T eogonek -92 +KPX T hyphen -92 +KPX T i -37 +KPX T iacute -37 +KPX T iogonek -37 +KPX T o -95 +KPX T oacute -95 +KPX T ocircumflex -95 +KPX T odieresis -95 +KPX T ograve -95 +KPX T ohungarumlaut -95 +KPX T omacron -95 +KPX T oslash -95 +KPX T otilde -95 +KPX T period -92 +KPX T r -37 +KPX T racute -37 +KPX T rcaron -37 +KPX T rcommaaccent -37 +KPX T semicolon -74 +KPX T u -37 +KPX T uacute -37 +KPX T ucircumflex -37 +KPX T udieresis -37 +KPX T ugrave -37 +KPX T uhungarumlaut -37 +KPX T umacron -37 +KPX T uogonek -37 +KPX T uring -37 +KPX T w -37 +KPX T y -37 +KPX T yacute -37 +KPX T ydieresis -37 +KPX Tcaron A -55 +KPX Tcaron Aacute -55 +KPX Tcaron Abreve -55 +KPX Tcaron Acircumflex -55 +KPX Tcaron Adieresis -55 +KPX Tcaron Agrave -55 +KPX Tcaron Amacron -55 +KPX Tcaron Aogonek -55 +KPX Tcaron Aring -55 +KPX Tcaron Atilde -55 +KPX Tcaron O -18 +KPX Tcaron Oacute -18 +KPX Tcaron Ocircumflex -18 +KPX Tcaron Odieresis -18 +KPX Tcaron Ograve -18 +KPX Tcaron Ohungarumlaut -18 +KPX Tcaron Omacron -18 +KPX Tcaron Oslash -18 +KPX Tcaron Otilde -18 +KPX Tcaron a -92 +KPX Tcaron aacute -92 +KPX Tcaron abreve -92 +KPX Tcaron acircumflex -92 +KPX Tcaron adieresis -92 +KPX Tcaron agrave -92 +KPX Tcaron amacron -92 +KPX Tcaron aogonek -92 +KPX Tcaron aring -92 +KPX Tcaron atilde -92 +KPX Tcaron colon -74 +KPX Tcaron comma -92 +KPX Tcaron e -92 +KPX Tcaron eacute -92 +KPX Tcaron ecaron -92 +KPX Tcaron ecircumflex -92 +KPX Tcaron edieresis -52 +KPX Tcaron edotaccent -92 +KPX Tcaron egrave -52 +KPX Tcaron emacron -52 +KPX Tcaron eogonek -92 +KPX Tcaron hyphen -92 +KPX Tcaron i -37 +KPX Tcaron iacute -37 +KPX Tcaron iogonek -37 +KPX Tcaron o -95 +KPX Tcaron oacute -95 +KPX Tcaron ocircumflex -95 +KPX Tcaron odieresis -95 +KPX Tcaron ograve -95 +KPX Tcaron ohungarumlaut -95 +KPX Tcaron omacron -95 +KPX Tcaron oslash -95 +KPX Tcaron otilde -95 +KPX Tcaron period -92 +KPX Tcaron r -37 +KPX Tcaron racute -37 +KPX Tcaron rcaron -37 +KPX Tcaron rcommaaccent -37 +KPX Tcaron semicolon -74 +KPX Tcaron u -37 +KPX Tcaron uacute -37 +KPX Tcaron ucircumflex -37 +KPX Tcaron udieresis -37 +KPX Tcaron ugrave -37 +KPX Tcaron uhungarumlaut -37 +KPX Tcaron umacron -37 +KPX Tcaron uogonek -37 +KPX Tcaron uring -37 +KPX Tcaron w -37 +KPX Tcaron y -37 +KPX Tcaron yacute -37 +KPX Tcaron ydieresis -37 +KPX Tcommaaccent A -55 +KPX Tcommaaccent Aacute -55 +KPX Tcommaaccent Abreve -55 +KPX Tcommaaccent Acircumflex -55 +KPX Tcommaaccent Adieresis -55 +KPX Tcommaaccent Agrave -55 +KPX Tcommaaccent Amacron -55 +KPX Tcommaaccent Aogonek -55 +KPX Tcommaaccent Aring -55 +KPX Tcommaaccent Atilde -55 +KPX Tcommaaccent O -18 +KPX Tcommaaccent Oacute -18 +KPX Tcommaaccent Ocircumflex -18 +KPX Tcommaaccent Odieresis -18 +KPX Tcommaaccent Ograve -18 +KPX Tcommaaccent Ohungarumlaut -18 +KPX Tcommaaccent Omacron -18 +KPX Tcommaaccent Oslash -18 +KPX Tcommaaccent Otilde -18 +KPX Tcommaaccent a -92 +KPX Tcommaaccent aacute -92 +KPX Tcommaaccent abreve -92 +KPX Tcommaaccent acircumflex -92 +KPX Tcommaaccent adieresis -92 +KPX Tcommaaccent agrave -92 +KPX Tcommaaccent amacron -92 +KPX Tcommaaccent aogonek -92 +KPX Tcommaaccent aring -92 +KPX Tcommaaccent atilde -92 +KPX Tcommaaccent colon -74 +KPX Tcommaaccent comma -92 +KPX Tcommaaccent e -92 +KPX Tcommaaccent eacute -92 +KPX Tcommaaccent ecaron -92 +KPX Tcommaaccent ecircumflex -92 +KPX Tcommaaccent edieresis -52 +KPX Tcommaaccent edotaccent -92 +KPX Tcommaaccent egrave -52 +KPX Tcommaaccent emacron -52 +KPX Tcommaaccent eogonek -92 +KPX Tcommaaccent hyphen -92 +KPX Tcommaaccent i -37 +KPX Tcommaaccent iacute -37 +KPX Tcommaaccent iogonek -37 +KPX Tcommaaccent o -95 +KPX Tcommaaccent oacute -95 +KPX Tcommaaccent ocircumflex -95 +KPX Tcommaaccent odieresis -95 +KPX Tcommaaccent ograve -95 +KPX Tcommaaccent ohungarumlaut -95 +KPX Tcommaaccent omacron -95 +KPX Tcommaaccent oslash -95 +KPX Tcommaaccent otilde -95 +KPX Tcommaaccent period -92 +KPX Tcommaaccent r -37 +KPX Tcommaaccent racute -37 +KPX Tcommaaccent rcaron -37 +KPX Tcommaaccent rcommaaccent -37 +KPX Tcommaaccent semicolon -74 +KPX Tcommaaccent u -37 +KPX Tcommaaccent uacute -37 +KPX Tcommaaccent ucircumflex -37 +KPX Tcommaaccent udieresis -37 +KPX Tcommaaccent ugrave -37 +KPX Tcommaaccent uhungarumlaut -37 +KPX Tcommaaccent umacron -37 +KPX Tcommaaccent uogonek -37 +KPX Tcommaaccent uring -37 +KPX Tcommaaccent w -37 +KPX Tcommaaccent y -37 +KPX Tcommaaccent yacute -37 +KPX Tcommaaccent ydieresis -37 +KPX U A -45 +KPX U Aacute -45 +KPX U Abreve -45 +KPX U Acircumflex -45 +KPX U Adieresis -45 +KPX U Agrave -45 +KPX U Amacron -45 +KPX U Aogonek -45 +KPX U Aring -45 +KPX U Atilde -45 +KPX Uacute A -45 +KPX Uacute Aacute -45 +KPX Uacute Abreve -45 +KPX Uacute Acircumflex -45 +KPX Uacute Adieresis -45 +KPX Uacute Agrave -45 +KPX Uacute Amacron -45 +KPX Uacute Aogonek -45 +KPX Uacute Aring -45 +KPX Uacute Atilde -45 +KPX Ucircumflex A -45 +KPX Ucircumflex Aacute -45 +KPX Ucircumflex Abreve -45 +KPX Ucircumflex Acircumflex -45 +KPX Ucircumflex Adieresis -45 +KPX Ucircumflex Agrave -45 +KPX Ucircumflex Amacron -45 +KPX Ucircumflex Aogonek -45 +KPX Ucircumflex Aring -45 +KPX Ucircumflex Atilde -45 +KPX Udieresis A -45 +KPX Udieresis Aacute -45 +KPX Udieresis Abreve -45 +KPX Udieresis Acircumflex -45 +KPX Udieresis Adieresis -45 +KPX Udieresis Agrave -45 +KPX Udieresis Amacron -45 +KPX Udieresis Aogonek -45 +KPX Udieresis Aring -45 +KPX Udieresis Atilde -45 +KPX Ugrave A -45 +KPX Ugrave Aacute -45 +KPX Ugrave Abreve -45 +KPX Ugrave Acircumflex -45 +KPX Ugrave Adieresis -45 +KPX Ugrave Agrave -45 +KPX Ugrave Amacron -45 +KPX Ugrave Aogonek -45 +KPX Ugrave Aring -45 +KPX Ugrave Atilde -45 +KPX Uhungarumlaut A -45 +KPX Uhungarumlaut Aacute -45 +KPX Uhungarumlaut Abreve -45 +KPX Uhungarumlaut Acircumflex -45 +KPX Uhungarumlaut Adieresis -45 +KPX Uhungarumlaut Agrave -45 +KPX Uhungarumlaut Amacron -45 +KPX Uhungarumlaut Aogonek -45 +KPX Uhungarumlaut Aring -45 +KPX Uhungarumlaut Atilde -45 +KPX Umacron A -45 +KPX Umacron Aacute -45 +KPX Umacron Abreve -45 +KPX Umacron Acircumflex -45 +KPX Umacron Adieresis -45 +KPX Umacron Agrave -45 +KPX Umacron Amacron -45 +KPX Umacron Aogonek -45 +KPX Umacron Aring -45 +KPX Umacron Atilde -45 +KPX Uogonek A -45 +KPX Uogonek Aacute -45 +KPX Uogonek Abreve -45 +KPX Uogonek Acircumflex -45 +KPX Uogonek Adieresis -45 +KPX Uogonek Agrave -45 +KPX Uogonek Amacron -45 +KPX Uogonek Aogonek -45 +KPX Uogonek Aring -45 +KPX Uogonek Atilde -45 +KPX Uring A -45 +KPX Uring Aacute -45 +KPX Uring Abreve -45 +KPX Uring Acircumflex -45 +KPX Uring Adieresis -45 +KPX Uring Agrave -45 +KPX Uring Amacron -45 +KPX Uring Aogonek -45 +KPX Uring Aring -45 +KPX Uring Atilde -45 +KPX V A -85 +KPX V Aacute -85 +KPX V Abreve -85 +KPX V Acircumflex -85 +KPX V Adieresis -85 +KPX V Agrave -85 +KPX V Amacron -85 +KPX V Aogonek -85 +KPX V Aring -85 +KPX V Atilde -85 +KPX V G -10 +KPX V Gbreve -10 +KPX V Gcommaaccent -10 +KPX V O -30 +KPX V Oacute -30 +KPX V Ocircumflex -30 +KPX V Odieresis -30 +KPX V Ograve -30 +KPX V Ohungarumlaut -30 +KPX V Omacron -30 +KPX V Oslash -30 +KPX V Otilde -30 +KPX V a -111 +KPX V aacute -111 +KPX V abreve -111 +KPX V acircumflex -111 +KPX V adieresis -111 +KPX V agrave -111 +KPX V amacron -111 +KPX V aogonek -111 +KPX V aring -111 +KPX V atilde -111 +KPX V colon -74 +KPX V comma -129 +KPX V e -111 +KPX V eacute -111 +KPX V ecaron -111 +KPX V ecircumflex -111 +KPX V edieresis -71 +KPX V edotaccent -111 +KPX V egrave -71 +KPX V emacron -71 +KPX V eogonek -111 +KPX V hyphen -70 +KPX V i -55 +KPX V iacute -55 +KPX V iogonek -55 +KPX V o -111 +KPX V oacute -111 +KPX V ocircumflex -111 +KPX V odieresis -111 +KPX V ograve -111 +KPX V ohungarumlaut -111 +KPX V omacron -111 +KPX V oslash -111 +KPX V otilde -111 +KPX V period -129 +KPX V semicolon -74 +KPX V u -55 +KPX V uacute -55 +KPX V ucircumflex -55 +KPX V udieresis -55 +KPX V ugrave -55 +KPX V uhungarumlaut -55 +KPX V umacron -55 +KPX V uogonek -55 +KPX V uring -55 +KPX W A -74 +KPX W Aacute -74 +KPX W Abreve -74 +KPX W Acircumflex -74 +KPX W Adieresis -74 +KPX W Agrave -74 +KPX W Amacron -74 +KPX W Aogonek -74 +KPX W Aring -74 +KPX W Atilde -74 +KPX W O -15 +KPX W Oacute -15 +KPX W Ocircumflex -15 +KPX W Odieresis -15 +KPX W Ograve -15 +KPX W Ohungarumlaut -15 +KPX W Omacron -15 +KPX W Oslash -15 +KPX W Otilde -15 +KPX W a -85 +KPX W aacute -85 +KPX W abreve -85 +KPX W acircumflex -85 +KPX W adieresis -85 +KPX W agrave -85 +KPX W amacron -85 +KPX W aogonek -85 +KPX W aring -85 +KPX W atilde -85 +KPX W colon -55 +KPX W comma -74 +KPX W e -90 +KPX W eacute -90 +KPX W ecaron -90 +KPX W ecircumflex -90 +KPX W edieresis -50 +KPX W edotaccent -90 +KPX W egrave -50 +KPX W emacron -50 +KPX W eogonek -90 +KPX W hyphen -50 +KPX W i -37 +KPX W iacute -37 +KPX W iogonek -37 +KPX W o -80 +KPX W oacute -80 +KPX W ocircumflex -80 +KPX W odieresis -80 +KPX W ograve -80 +KPX W ohungarumlaut -80 +KPX W omacron -80 +KPX W oslash -80 +KPX W otilde -80 +KPX W period -74 +KPX W semicolon -55 +KPX W u -55 +KPX W uacute -55 +KPX W ucircumflex -55 +KPX W udieresis -55 +KPX W ugrave -55 +KPX W uhungarumlaut -55 +KPX W umacron -55 +KPX W uogonek -55 +KPX W uring -55 +KPX W y -55 +KPX W yacute -55 +KPX W ydieresis -55 +KPX Y A -74 +KPX Y Aacute -74 +KPX Y Abreve -74 +KPX Y Acircumflex -74 +KPX Y Adieresis -74 +KPX Y Agrave -74 +KPX Y Amacron -74 +KPX Y Aogonek -74 +KPX Y Aring -74 +KPX Y Atilde -74 +KPX Y O -25 +KPX Y Oacute -25 +KPX Y Ocircumflex -25 +KPX Y Odieresis -25 +KPX Y Ograve -25 +KPX Y Ohungarumlaut -25 +KPX Y Omacron -25 +KPX Y Oslash -25 +KPX Y Otilde -25 +KPX Y a -92 +KPX Y aacute -92 +KPX Y abreve -92 +KPX Y acircumflex -92 +KPX Y adieresis -92 +KPX Y agrave -92 +KPX Y amacron -92 +KPX Y aogonek -92 +KPX Y aring -92 +KPX Y atilde -92 +KPX Y colon -92 +KPX Y comma -92 +KPX Y e -111 +KPX Y eacute -111 +KPX Y ecaron -111 +KPX Y ecircumflex -71 +KPX Y edieresis -71 +KPX Y edotaccent -111 +KPX Y egrave -71 +KPX Y emacron -71 +KPX Y eogonek -111 +KPX Y hyphen -92 +KPX Y i -55 +KPX Y iacute -55 +KPX Y iogonek -55 +KPX Y o -111 +KPX Y oacute -111 +KPX Y ocircumflex -111 +KPX Y odieresis -111 +KPX Y ograve -111 +KPX Y ohungarumlaut -111 +KPX Y omacron -111 +KPX Y oslash -111 +KPX Y otilde -111 +KPX Y period -74 +KPX Y semicolon -92 +KPX Y u -92 +KPX Y uacute -92 +KPX Y ucircumflex -92 +KPX Y udieresis -92 +KPX Y ugrave -92 +KPX Y uhungarumlaut -92 +KPX Y umacron -92 +KPX Y uogonek -92 +KPX Y uring -92 +KPX Yacute A -74 +KPX Yacute Aacute -74 +KPX Yacute Abreve -74 +KPX Yacute Acircumflex -74 +KPX Yacute Adieresis -74 +KPX Yacute Agrave -74 +KPX Yacute Amacron -74 +KPX Yacute Aogonek -74 +KPX Yacute Aring -74 +KPX Yacute Atilde -74 +KPX Yacute O -25 +KPX Yacute Oacute -25 +KPX Yacute Ocircumflex -25 +KPX Yacute Odieresis -25 +KPX Yacute Ograve -25 +KPX Yacute Ohungarumlaut -25 +KPX Yacute Omacron -25 +KPX Yacute Oslash -25 +KPX Yacute Otilde -25 +KPX Yacute a -92 +KPX Yacute aacute -92 +KPX Yacute abreve -92 +KPX Yacute acircumflex -92 +KPX Yacute adieresis -92 +KPX Yacute agrave -92 +KPX Yacute amacron -92 +KPX Yacute aogonek -92 +KPX Yacute aring -92 +KPX Yacute atilde -92 +KPX Yacute colon -92 +KPX Yacute comma -92 +KPX Yacute e -111 +KPX Yacute eacute -111 +KPX Yacute ecaron -111 +KPX Yacute ecircumflex -71 +KPX Yacute edieresis -71 +KPX Yacute edotaccent -111 +KPX Yacute egrave -71 +KPX Yacute emacron -71 +KPX Yacute eogonek -111 +KPX Yacute hyphen -92 +KPX Yacute i -55 +KPX Yacute iacute -55 +KPX Yacute iogonek -55 +KPX Yacute o -111 +KPX Yacute oacute -111 +KPX Yacute ocircumflex -111 +KPX Yacute odieresis -111 +KPX Yacute ograve -111 +KPX Yacute ohungarumlaut -111 +KPX Yacute omacron -111 +KPX Yacute oslash -111 +KPX Yacute otilde -111 +KPX Yacute period -74 +KPX Yacute semicolon -92 +KPX Yacute u -92 +KPX Yacute uacute -92 +KPX Yacute ucircumflex -92 +KPX Yacute udieresis -92 +KPX Yacute ugrave -92 +KPX Yacute uhungarumlaut -92 +KPX Yacute umacron -92 +KPX Yacute uogonek -92 +KPX Yacute uring -92 +KPX Ydieresis A -74 +KPX Ydieresis Aacute -74 +KPX Ydieresis Abreve -74 +KPX Ydieresis Acircumflex -74 +KPX Ydieresis Adieresis -74 +KPX Ydieresis Agrave -74 +KPX Ydieresis Amacron -74 +KPX Ydieresis Aogonek -74 +KPX Ydieresis Aring -74 +KPX Ydieresis Atilde -74 +KPX Ydieresis O -25 +KPX Ydieresis Oacute -25 +KPX Ydieresis Ocircumflex -25 +KPX Ydieresis Odieresis -25 +KPX Ydieresis Ograve -25 +KPX Ydieresis Ohungarumlaut -25 +KPX Ydieresis Omacron -25 +KPX Ydieresis Oslash -25 +KPX Ydieresis Otilde -25 +KPX Ydieresis a -92 +KPX Ydieresis aacute -92 +KPX Ydieresis abreve -92 +KPX Ydieresis acircumflex -92 +KPX Ydieresis adieresis -92 +KPX Ydieresis agrave -92 +KPX Ydieresis amacron -92 +KPX Ydieresis aogonek -92 +KPX Ydieresis aring -92 +KPX Ydieresis atilde -92 +KPX Ydieresis colon -92 +KPX Ydieresis comma -92 +KPX Ydieresis e -111 +KPX Ydieresis eacute -111 +KPX Ydieresis ecaron -111 +KPX Ydieresis ecircumflex -71 +KPX Ydieresis edieresis -71 +KPX Ydieresis edotaccent -111 +KPX Ydieresis egrave -71 +KPX Ydieresis emacron -71 +KPX Ydieresis eogonek -111 +KPX Ydieresis hyphen -92 +KPX Ydieresis i -55 +KPX Ydieresis iacute -55 +KPX Ydieresis iogonek -55 +KPX Ydieresis o -111 +KPX Ydieresis oacute -111 +KPX Ydieresis ocircumflex -111 +KPX Ydieresis odieresis -111 +KPX Ydieresis ograve -111 +KPX Ydieresis ohungarumlaut -111 +KPX Ydieresis omacron -111 +KPX Ydieresis oslash -111 +KPX Ydieresis otilde -111 +KPX Ydieresis period -74 +KPX Ydieresis semicolon -92 +KPX Ydieresis u -92 +KPX Ydieresis uacute -92 +KPX Ydieresis ucircumflex -92 +KPX Ydieresis udieresis -92 +KPX Ydieresis ugrave -92 +KPX Ydieresis uhungarumlaut -92 +KPX Ydieresis umacron -92 +KPX Ydieresis uogonek -92 +KPX Ydieresis uring -92 +KPX b b -10 +KPX b period -40 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX c h -10 +KPX c k -10 +KPX c kcommaaccent -10 +KPX cacute h -10 +KPX cacute k -10 +KPX cacute kcommaaccent -10 +KPX ccaron h -10 +KPX ccaron k -10 +KPX ccaron kcommaaccent -10 +KPX ccedilla h -10 +KPX ccedilla k -10 +KPX ccedilla kcommaaccent -10 +KPX comma quotedblright -95 +KPX comma quoteright -95 +KPX e b -10 +KPX eacute b -10 +KPX ecaron b -10 +KPX ecircumflex b -10 +KPX edieresis b -10 +KPX edotaccent b -10 +KPX egrave b -10 +KPX emacron b -10 +KPX eogonek b -10 +KPX f comma -10 +KPX f dotlessi -30 +KPX f e -10 +KPX f eacute -10 +KPX f edotaccent -10 +KPX f eogonek -10 +KPX f f -18 +KPX f o -10 +KPX f oacute -10 +KPX f ocircumflex -10 +KPX f ograve -10 +KPX f ohungarumlaut -10 +KPX f oslash -10 +KPX f otilde -10 +KPX f period -10 +KPX f quoteright 55 +KPX k e -30 +KPX k eacute -30 +KPX k ecaron -30 +KPX k ecircumflex -30 +KPX k edieresis -30 +KPX k edotaccent -30 +KPX k egrave -30 +KPX k emacron -30 +KPX k eogonek -30 +KPX k o -10 +KPX k oacute -10 +KPX k ocircumflex -10 +KPX k odieresis -10 +KPX k ograve -10 +KPX k ohungarumlaut -10 +KPX k omacron -10 +KPX k oslash -10 +KPX k otilde -10 +KPX kcommaaccent e -30 +KPX kcommaaccent eacute -30 +KPX kcommaaccent ecaron -30 +KPX kcommaaccent ecircumflex -30 +KPX kcommaaccent edieresis -30 +KPX kcommaaccent edotaccent -30 +KPX kcommaaccent egrave -30 +KPX kcommaaccent emacron -30 +KPX kcommaaccent eogonek -30 +KPX kcommaaccent o -10 +KPX kcommaaccent oacute -10 +KPX kcommaaccent ocircumflex -10 +KPX kcommaaccent odieresis -10 +KPX kcommaaccent ograve -10 +KPX kcommaaccent ohungarumlaut -10 +KPX kcommaaccent omacron -10 +KPX kcommaaccent oslash -10 +KPX kcommaaccent otilde -10 +KPX n v -40 +KPX nacute v -40 +KPX ncaron v -40 +KPX ncommaaccent v -40 +KPX ntilde v -40 +KPX o v -15 +KPX o w -25 +KPX o x -10 +KPX o y -10 +KPX o yacute -10 +KPX o ydieresis -10 +KPX oacute v -15 +KPX oacute w -25 +KPX oacute x -10 +KPX oacute y -10 +KPX oacute yacute -10 +KPX oacute ydieresis -10 +KPX ocircumflex v -15 +KPX ocircumflex w -25 +KPX ocircumflex x -10 +KPX ocircumflex y -10 +KPX ocircumflex yacute -10 +KPX ocircumflex ydieresis -10 +KPX odieresis v -15 +KPX odieresis w -25 +KPX odieresis x -10 +KPX odieresis y -10 +KPX odieresis yacute -10 +KPX odieresis ydieresis -10 +KPX ograve v -15 +KPX ograve w -25 +KPX ograve x -10 +KPX ograve y -10 +KPX ograve yacute -10 +KPX ograve ydieresis -10 +KPX ohungarumlaut v -15 +KPX ohungarumlaut w -25 +KPX ohungarumlaut x -10 +KPX ohungarumlaut y -10 +KPX ohungarumlaut yacute -10 +KPX ohungarumlaut ydieresis -10 +KPX omacron v -15 +KPX omacron w -25 +KPX omacron x -10 +KPX omacron y -10 +KPX omacron yacute -10 +KPX omacron ydieresis -10 +KPX oslash v -15 +KPX oslash w -25 +KPX oslash x -10 +KPX oslash y -10 +KPX oslash yacute -10 +KPX oslash ydieresis -10 +KPX otilde v -15 +KPX otilde w -25 +KPX otilde x -10 +KPX otilde y -10 +KPX otilde yacute -10 +KPX otilde ydieresis -10 +KPX period quotedblright -95 +KPX period quoteright -95 +KPX quoteleft quoteleft -74 +KPX quoteright d -15 +KPX quoteright dcroat -15 +KPX quoteright quoteright -74 +KPX quoteright r -15 +KPX quoteright racute -15 +KPX quoteright rcaron -15 +KPX quoteright rcommaaccent -15 +KPX quoteright s -74 +KPX quoteright sacute -74 +KPX quoteright scaron -74 +KPX quoteright scedilla -74 +KPX quoteright scommaaccent -74 +KPX quoteright space -74 +KPX quoteright t -37 +KPX quoteright tcommaaccent -37 +KPX quoteright v -15 +KPX r comma -65 +KPX r period -65 +KPX racute comma -65 +KPX racute period -65 +KPX rcaron comma -65 +KPX rcaron period -65 +KPX rcommaaccent comma -65 +KPX rcommaaccent period -65 +KPX space A -37 +KPX space Aacute -37 +KPX space Abreve -37 +KPX space Acircumflex -37 +KPX space Adieresis -37 +KPX space Agrave -37 +KPX space Amacron -37 +KPX space Aogonek -37 +KPX space Aring -37 +KPX space Atilde -37 +KPX space V -70 +KPX space W -70 +KPX space Y -70 +KPX space Yacute -70 +KPX space Ydieresis -70 +KPX v comma -37 +KPX v e -15 +KPX v eacute -15 +KPX v ecaron -15 +KPX v ecircumflex -15 +KPX v edieresis -15 +KPX v edotaccent -15 +KPX v egrave -15 +KPX v emacron -15 +KPX v eogonek -15 +KPX v o -15 +KPX v oacute -15 +KPX v ocircumflex -15 +KPX v odieresis -15 +KPX v ograve -15 +KPX v ohungarumlaut -15 +KPX v omacron -15 +KPX v oslash -15 +KPX v otilde -15 +KPX v period -37 +KPX w a -10 +KPX w aacute -10 +KPX w abreve -10 +KPX w acircumflex -10 +KPX w adieresis -10 +KPX w agrave -10 +KPX w amacron -10 +KPX w aogonek -10 +KPX w aring -10 +KPX w atilde -10 +KPX w comma -37 +KPX w e -10 +KPX w eacute -10 +KPX w ecaron -10 +KPX w ecircumflex -10 +KPX w edieresis -10 +KPX w edotaccent -10 +KPX w egrave -10 +KPX w emacron -10 +KPX w eogonek -10 +KPX w o -15 +KPX w oacute -15 +KPX w ocircumflex -15 +KPX w odieresis -15 +KPX w ograve -15 +KPX w ohungarumlaut -15 +KPX w omacron -15 +KPX w oslash -15 +KPX w otilde -15 +KPX w period -37 +KPX x e -10 +KPX x eacute -10 +KPX x ecaron -10 +KPX x ecircumflex -10 +KPX x edieresis -10 +KPX x edotaccent -10 +KPX x egrave -10 +KPX x emacron -10 +KPX x eogonek -10 +KPX y comma -37 +KPX y period -37 +KPX yacute comma -37 +KPX yacute period -37 +KPX ydieresis comma -37 +KPX ydieresis period -37 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Times-Italic.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Times-Italic.afm new file mode 100644 index 0000000..041f0e8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Times-Italic.afm @@ -0,0 +1,2667 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:56:55 1997 +Comment UniqueID 43067 +Comment VMusage 47727 58752 +FontName Times-Italic +FullName Times Italic +FamilyName Times +Weight Medium +ItalicAngle -15.5 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -169 -217 1010 883 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 653 +XHeight 441 +Ascender 683 +Descender -217 +StdHW 32 +StdVW 76 +StartCharMetrics 315 +C 32 ; WX 250 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 39 -11 302 667 ; +C 34 ; WX 420 ; N quotedbl ; B 144 421 432 666 ; +C 35 ; WX 500 ; N numbersign ; B 2 0 540 676 ; +C 36 ; WX 500 ; N dollar ; B 31 -89 497 731 ; +C 37 ; WX 833 ; N percent ; B 79 -13 790 676 ; +C 38 ; WX 778 ; N ampersand ; B 76 -18 723 666 ; +C 39 ; WX 333 ; N quoteright ; B 151 436 290 666 ; +C 40 ; WX 333 ; N parenleft ; B 42 -181 315 669 ; +C 41 ; WX 333 ; N parenright ; B 16 -180 289 669 ; +C 42 ; WX 500 ; N asterisk ; B 128 255 492 666 ; +C 43 ; WX 675 ; N plus ; B 86 0 590 506 ; +C 44 ; WX 250 ; N comma ; B -4 -129 135 101 ; +C 45 ; WX 333 ; N hyphen ; B 49 192 282 255 ; +C 46 ; WX 250 ; N period ; B 27 -11 138 100 ; +C 47 ; WX 278 ; N slash ; B -65 -18 386 666 ; +C 48 ; WX 500 ; N zero ; B 32 -7 497 676 ; +C 49 ; WX 500 ; N one ; B 49 0 409 676 ; +C 50 ; WX 500 ; N two ; B 12 0 452 676 ; +C 51 ; WX 500 ; N three ; B 15 -7 465 676 ; +C 52 ; WX 500 ; N four ; B 1 0 479 676 ; +C 53 ; WX 500 ; N five ; B 15 -7 491 666 ; +C 54 ; WX 500 ; N six ; B 30 -7 521 686 ; +C 55 ; WX 500 ; N seven ; B 75 -8 537 666 ; +C 56 ; WX 500 ; N eight ; B 30 -7 493 676 ; +C 57 ; WX 500 ; N nine ; B 23 -17 492 676 ; +C 58 ; WX 333 ; N colon ; B 50 -11 261 441 ; +C 59 ; WX 333 ; N semicolon ; B 27 -129 261 441 ; +C 60 ; WX 675 ; N less ; B 84 -8 592 514 ; +C 61 ; WX 675 ; N equal ; B 86 120 590 386 ; +C 62 ; WX 675 ; N greater ; B 84 -8 592 514 ; +C 63 ; WX 500 ; N question ; B 132 -12 472 664 ; +C 64 ; WX 920 ; N at ; B 118 -18 806 666 ; +C 65 ; WX 611 ; N A ; B -51 0 564 668 ; +C 66 ; WX 611 ; N B ; B -8 0 588 653 ; +C 67 ; WX 667 ; N C ; B 66 -18 689 666 ; +C 68 ; WX 722 ; N D ; B -8 0 700 653 ; +C 69 ; WX 611 ; N E ; B -1 0 634 653 ; +C 70 ; WX 611 ; N F ; B 8 0 645 653 ; +C 71 ; WX 722 ; N G ; B 52 -18 722 666 ; +C 72 ; WX 722 ; N H ; B -8 0 767 653 ; +C 73 ; WX 333 ; N I ; B -8 0 384 653 ; +C 74 ; WX 444 ; N J ; B -6 -18 491 653 ; +C 75 ; WX 667 ; N K ; B 7 0 722 653 ; +C 76 ; WX 556 ; N L ; B -8 0 559 653 ; +C 77 ; WX 833 ; N M ; B -18 0 873 653 ; +C 78 ; WX 667 ; N N ; B -20 -15 727 653 ; +C 79 ; WX 722 ; N O ; B 60 -18 699 666 ; +C 80 ; WX 611 ; N P ; B 0 0 605 653 ; +C 81 ; WX 722 ; N Q ; B 59 -182 699 666 ; +C 82 ; WX 611 ; N R ; B -13 0 588 653 ; +C 83 ; WX 500 ; N S ; B 17 -18 508 667 ; +C 84 ; WX 556 ; N T ; B 59 0 633 653 ; +C 85 ; WX 722 ; N U ; B 102 -18 765 653 ; +C 86 ; WX 611 ; N V ; B 76 -18 688 653 ; +C 87 ; WX 833 ; N W ; B 71 -18 906 653 ; +C 88 ; WX 611 ; N X ; B -29 0 655 653 ; +C 89 ; WX 556 ; N Y ; B 78 0 633 653 ; +C 90 ; WX 556 ; N Z ; B -6 0 606 653 ; +C 91 ; WX 389 ; N bracketleft ; B 21 -153 391 663 ; +C 92 ; WX 278 ; N backslash ; B -41 -18 319 666 ; +C 93 ; WX 389 ; N bracketright ; B 12 -153 382 663 ; +C 94 ; WX 422 ; N asciicircum ; B 0 301 422 666 ; +C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ; +C 96 ; WX 333 ; N quoteleft ; B 171 436 310 666 ; +C 97 ; WX 500 ; N a ; B 17 -11 476 441 ; +C 98 ; WX 500 ; N b ; B 23 -11 473 683 ; +C 99 ; WX 444 ; N c ; B 30 -11 425 441 ; +C 100 ; WX 500 ; N d ; B 15 -13 527 683 ; +C 101 ; WX 444 ; N e ; B 31 -11 412 441 ; +C 102 ; WX 278 ; N f ; B -147 -207 424 678 ; L i fi ; L l fl ; +C 103 ; WX 500 ; N g ; B 8 -206 472 441 ; +C 104 ; WX 500 ; N h ; B 19 -9 478 683 ; +C 105 ; WX 278 ; N i ; B 49 -11 264 654 ; +C 106 ; WX 278 ; N j ; B -124 -207 276 654 ; +C 107 ; WX 444 ; N k ; B 14 -11 461 683 ; +C 108 ; WX 278 ; N l ; B 41 -11 279 683 ; +C 109 ; WX 722 ; N m ; B 12 -9 704 441 ; +C 110 ; WX 500 ; N n ; B 14 -9 474 441 ; +C 111 ; WX 500 ; N o ; B 27 -11 468 441 ; +C 112 ; WX 500 ; N p ; B -75 -205 469 441 ; +C 113 ; WX 500 ; N q ; B 25 -209 483 441 ; +C 114 ; WX 389 ; N r ; B 45 0 412 441 ; +C 115 ; WX 389 ; N s ; B 16 -13 366 442 ; +C 116 ; WX 278 ; N t ; B 37 -11 296 546 ; +C 117 ; WX 500 ; N u ; B 42 -11 475 441 ; +C 118 ; WX 444 ; N v ; B 21 -18 426 441 ; +C 119 ; WX 667 ; N w ; B 16 -18 648 441 ; +C 120 ; WX 444 ; N x ; B -27 -11 447 441 ; +C 121 ; WX 444 ; N y ; B -24 -206 426 441 ; +C 122 ; WX 389 ; N z ; B -2 -81 380 428 ; +C 123 ; WX 400 ; N braceleft ; B 51 -177 407 687 ; +C 124 ; WX 275 ; N bar ; B 105 -217 171 783 ; +C 125 ; WX 400 ; N braceright ; B -7 -177 349 687 ; +C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ; +C 161 ; WX 389 ; N exclamdown ; B 59 -205 322 473 ; +C 162 ; WX 500 ; N cent ; B 77 -143 472 560 ; +C 163 ; WX 500 ; N sterling ; B 10 -6 517 670 ; +C 164 ; WX 167 ; N fraction ; B -169 -10 337 676 ; +C 165 ; WX 500 ; N yen ; B 27 0 603 653 ; +C 166 ; WX 500 ; N florin ; B 25 -182 507 682 ; +C 167 ; WX 500 ; N section ; B 53 -162 461 666 ; +C 168 ; WX 500 ; N currency ; B -22 53 522 597 ; +C 169 ; WX 214 ; N quotesingle ; B 132 421 241 666 ; +C 170 ; WX 556 ; N quotedblleft ; B 166 436 514 666 ; +C 171 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ; +C 172 ; WX 333 ; N guilsinglleft ; B 51 37 281 403 ; +C 173 ; WX 333 ; N guilsinglright ; B 52 37 282 403 ; +C 174 ; WX 500 ; N fi ; B -141 -207 481 681 ; +C 175 ; WX 500 ; N fl ; B -141 -204 518 682 ; +C 177 ; WX 500 ; N endash ; B -6 197 505 243 ; +C 178 ; WX 500 ; N dagger ; B 101 -159 488 666 ; +C 179 ; WX 500 ; N daggerdbl ; B 22 -143 491 666 ; +C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ; +C 182 ; WX 523 ; N paragraph ; B 55 -123 616 653 ; +C 183 ; WX 350 ; N bullet ; B 40 191 310 461 ; +C 184 ; WX 333 ; N quotesinglbase ; B 44 -129 183 101 ; +C 185 ; WX 556 ; N quotedblbase ; B 57 -129 405 101 ; +C 186 ; WX 556 ; N quotedblright ; B 151 436 499 666 ; +C 187 ; WX 500 ; N guillemotright ; B 55 37 447 403 ; +C 188 ; WX 889 ; N ellipsis ; B 57 -11 762 100 ; +C 189 ; WX 1000 ; N perthousand ; B 25 -19 1010 706 ; +C 191 ; WX 500 ; N questiondown ; B 28 -205 368 471 ; +C 193 ; WX 333 ; N grave ; B 121 492 311 664 ; +C 194 ; WX 333 ; N acute ; B 180 494 403 664 ; +C 195 ; WX 333 ; N circumflex ; B 91 492 385 661 ; +C 196 ; WX 333 ; N tilde ; B 100 517 427 624 ; +C 197 ; WX 333 ; N macron ; B 99 532 411 583 ; +C 198 ; WX 333 ; N breve ; B 117 492 418 650 ; +C 199 ; WX 333 ; N dotaccent ; B 207 548 305 646 ; +C 200 ; WX 333 ; N dieresis ; B 107 548 405 646 ; +C 202 ; WX 333 ; N ring ; B 155 492 355 691 ; +C 203 ; WX 333 ; N cedilla ; B -30 -217 182 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B 93 494 486 664 ; +C 206 ; WX 333 ; N ogonek ; B 20 -169 203 40 ; +C 207 ; WX 333 ; N caron ; B 121 492 426 661 ; +C 208 ; WX 889 ; N emdash ; B -6 197 894 243 ; +C 225 ; WX 889 ; N AE ; B -27 0 911 653 ; +C 227 ; WX 276 ; N ordfeminine ; B 42 406 352 676 ; +C 232 ; WX 556 ; N Lslash ; B -8 0 559 653 ; +C 233 ; WX 722 ; N Oslash ; B 60 -105 699 722 ; +C 234 ; WX 944 ; N OE ; B 49 -8 964 666 ; +C 235 ; WX 310 ; N ordmasculine ; B 67 406 362 676 ; +C 241 ; WX 667 ; N ae ; B 23 -11 640 441 ; +C 245 ; WX 278 ; N dotlessi ; B 49 -11 235 441 ; +C 248 ; WX 278 ; N lslash ; B 41 -11 312 683 ; +C 249 ; WX 500 ; N oslash ; B 28 -135 469 554 ; +C 250 ; WX 667 ; N oe ; B 20 -12 646 441 ; +C 251 ; WX 500 ; N germandbls ; B -168 -207 493 679 ; +C -1 ; WX 333 ; N Idieresis ; B -8 0 435 818 ; +C -1 ; WX 444 ; N eacute ; B 31 -11 459 664 ; +C -1 ; WX 500 ; N abreve ; B 17 -11 502 650 ; +C -1 ; WX 500 ; N uhungarumlaut ; B 42 -11 580 664 ; +C -1 ; WX 444 ; N ecaron ; B 31 -11 482 661 ; +C -1 ; WX 556 ; N Ydieresis ; B 78 0 633 818 ; +C -1 ; WX 675 ; N divide ; B 86 -11 590 517 ; +C -1 ; WX 556 ; N Yacute ; B 78 0 633 876 ; +C -1 ; WX 611 ; N Acircumflex ; B -51 0 564 873 ; +C -1 ; WX 500 ; N aacute ; B 17 -11 487 664 ; +C -1 ; WX 722 ; N Ucircumflex ; B 102 -18 765 873 ; +C -1 ; WX 444 ; N yacute ; B -24 -206 459 664 ; +C -1 ; WX 389 ; N scommaaccent ; B 16 -217 366 442 ; +C -1 ; WX 444 ; N ecircumflex ; B 31 -11 441 661 ; +C -1 ; WX 722 ; N Uring ; B 102 -18 765 883 ; +C -1 ; WX 722 ; N Udieresis ; B 102 -18 765 818 ; +C -1 ; WX 500 ; N aogonek ; B 17 -169 476 441 ; +C -1 ; WX 722 ; N Uacute ; B 102 -18 765 876 ; +C -1 ; WX 500 ; N uogonek ; B 42 -169 477 441 ; +C -1 ; WX 611 ; N Edieresis ; B -1 0 634 818 ; +C -1 ; WX 722 ; N Dcroat ; B -8 0 700 653 ; +C -1 ; WX 250 ; N commaaccent ; B 8 -217 133 -50 ; +C -1 ; WX 760 ; N copyright ; B 41 -18 719 666 ; +C -1 ; WX 611 ; N Emacron ; B -1 0 634 795 ; +C -1 ; WX 444 ; N ccaron ; B 30 -11 482 661 ; +C -1 ; WX 500 ; N aring ; B 17 -11 476 691 ; +C -1 ; WX 667 ; N Ncommaaccent ; B -20 -187 727 653 ; +C -1 ; WX 278 ; N lacute ; B 41 -11 395 876 ; +C -1 ; WX 500 ; N agrave ; B 17 -11 476 664 ; +C -1 ; WX 556 ; N Tcommaaccent ; B 59 -217 633 653 ; +C -1 ; WX 667 ; N Cacute ; B 66 -18 690 876 ; +C -1 ; WX 500 ; N atilde ; B 17 -11 511 624 ; +C -1 ; WX 611 ; N Edotaccent ; B -1 0 634 818 ; +C -1 ; WX 389 ; N scaron ; B 16 -13 454 661 ; +C -1 ; WX 389 ; N scedilla ; B 16 -217 366 442 ; +C -1 ; WX 278 ; N iacute ; B 49 -11 355 664 ; +C -1 ; WX 471 ; N lozenge ; B 13 0 459 724 ; +C -1 ; WX 611 ; N Rcaron ; B -13 0 588 873 ; +C -1 ; WX 722 ; N Gcommaaccent ; B 52 -217 722 666 ; +C -1 ; WX 500 ; N ucircumflex ; B 42 -11 475 661 ; +C -1 ; WX 500 ; N acircumflex ; B 17 -11 476 661 ; +C -1 ; WX 611 ; N Amacron ; B -51 0 564 795 ; +C -1 ; WX 389 ; N rcaron ; B 45 0 434 661 ; +C -1 ; WX 444 ; N ccedilla ; B 30 -217 425 441 ; +C -1 ; WX 556 ; N Zdotaccent ; B -6 0 606 818 ; +C -1 ; WX 611 ; N Thorn ; B 0 0 569 653 ; +C -1 ; WX 722 ; N Omacron ; B 60 -18 699 795 ; +C -1 ; WX 611 ; N Racute ; B -13 0 588 876 ; +C -1 ; WX 500 ; N Sacute ; B 17 -18 508 876 ; +C -1 ; WX 544 ; N dcaron ; B 15 -13 658 683 ; +C -1 ; WX 722 ; N Umacron ; B 102 -18 765 795 ; +C -1 ; WX 500 ; N uring ; B 42 -11 475 691 ; +C -1 ; WX 300 ; N threebaseior ; B 43 268 339 676 ; +C -1 ; WX 722 ; N Ograve ; B 60 -18 699 876 ; +C -1 ; WX 611 ; N Agrave ; B -51 0 564 876 ; +C -1 ; WX 611 ; N Abreve ; B -51 0 564 862 ; +C -1 ; WX 675 ; N multiply ; B 93 8 582 497 ; +C -1 ; WX 500 ; N uacute ; B 42 -11 477 664 ; +C -1 ; WX 556 ; N Tcaron ; B 59 0 633 873 ; +C -1 ; WX 476 ; N partialdiff ; B 17 -38 459 710 ; +C -1 ; WX 444 ; N ydieresis ; B -24 -206 441 606 ; +C -1 ; WX 667 ; N Nacute ; B -20 -15 727 876 ; +C -1 ; WX 278 ; N icircumflex ; B 33 -11 327 661 ; +C -1 ; WX 611 ; N Ecircumflex ; B -1 0 634 873 ; +C -1 ; WX 500 ; N adieresis ; B 17 -11 489 606 ; +C -1 ; WX 444 ; N edieresis ; B 31 -11 451 606 ; +C -1 ; WX 444 ; N cacute ; B 30 -11 459 664 ; +C -1 ; WX 500 ; N nacute ; B 14 -9 477 664 ; +C -1 ; WX 500 ; N umacron ; B 42 -11 485 583 ; +C -1 ; WX 667 ; N Ncaron ; B -20 -15 727 873 ; +C -1 ; WX 333 ; N Iacute ; B -8 0 433 876 ; +C -1 ; WX 675 ; N plusminus ; B 86 0 590 506 ; +C -1 ; WX 275 ; N brokenbar ; B 105 -142 171 708 ; +C -1 ; WX 760 ; N registered ; B 41 -18 719 666 ; +C -1 ; WX 722 ; N Gbreve ; B 52 -18 722 862 ; +C -1 ; WX 333 ; N Idotaccent ; B -8 0 384 818 ; +C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ; +C -1 ; WX 611 ; N Egrave ; B -1 0 634 876 ; +C -1 ; WX 389 ; N racute ; B 45 0 431 664 ; +C -1 ; WX 500 ; N omacron ; B 27 -11 495 583 ; +C -1 ; WX 556 ; N Zacute ; B -6 0 606 876 ; +C -1 ; WX 556 ; N Zcaron ; B -6 0 606 873 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 523 658 ; +C -1 ; WX 722 ; N Eth ; B -8 0 700 653 ; +C -1 ; WX 667 ; N Ccedilla ; B 66 -217 689 666 ; +C -1 ; WX 278 ; N lcommaaccent ; B 22 -217 279 683 ; +C -1 ; WX 300 ; N tcaron ; B 37 -11 407 681 ; +C -1 ; WX 444 ; N eogonek ; B 31 -169 412 441 ; +C -1 ; WX 722 ; N Uogonek ; B 102 -184 765 653 ; +C -1 ; WX 611 ; N Aacute ; B -51 0 564 876 ; +C -1 ; WX 611 ; N Adieresis ; B -51 0 564 818 ; +C -1 ; WX 444 ; N egrave ; B 31 -11 412 664 ; +C -1 ; WX 389 ; N zacute ; B -2 -81 431 664 ; +C -1 ; WX 278 ; N iogonek ; B 49 -169 264 654 ; +C -1 ; WX 722 ; N Oacute ; B 60 -18 699 876 ; +C -1 ; WX 500 ; N oacute ; B 27 -11 487 664 ; +C -1 ; WX 500 ; N amacron ; B 17 -11 495 583 ; +C -1 ; WX 389 ; N sacute ; B 16 -13 431 664 ; +C -1 ; WX 278 ; N idieresis ; B 49 -11 352 606 ; +C -1 ; WX 722 ; N Ocircumflex ; B 60 -18 699 873 ; +C -1 ; WX 722 ; N Ugrave ; B 102 -18 765 876 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 500 ; N thorn ; B -75 -205 469 683 ; +C -1 ; WX 300 ; N twobaseior ; B 33 271 324 676 ; +C -1 ; WX 722 ; N Odieresis ; B 60 -18 699 818 ; +C -1 ; WX 500 ; N mu ; B -30 -209 497 428 ; +C -1 ; WX 278 ; N igrave ; B 49 -11 284 664 ; +C -1 ; WX 500 ; N ohungarumlaut ; B 27 -11 590 664 ; +C -1 ; WX 611 ; N Eogonek ; B -1 -169 634 653 ; +C -1 ; WX 500 ; N dcroat ; B 15 -13 572 683 ; +C -1 ; WX 750 ; N threequarters ; B 23 -10 736 676 ; +C -1 ; WX 500 ; N Scedilla ; B 17 -217 508 667 ; +C -1 ; WX 300 ; N lcaron ; B 41 -11 407 683 ; +C -1 ; WX 667 ; N Kcommaaccent ; B 7 -217 722 653 ; +C -1 ; WX 556 ; N Lacute ; B -8 0 559 876 ; +C -1 ; WX 980 ; N trademark ; B 30 247 957 653 ; +C -1 ; WX 444 ; N edotaccent ; B 31 -11 412 606 ; +C -1 ; WX 333 ; N Igrave ; B -8 0 384 876 ; +C -1 ; WX 333 ; N Imacron ; B -8 0 441 795 ; +C -1 ; WX 611 ; N Lcaron ; B -8 0 586 653 ; +C -1 ; WX 750 ; N onehalf ; B 34 -10 749 676 ; +C -1 ; WX 549 ; N lessequal ; B 26 0 523 658 ; +C -1 ; WX 500 ; N ocircumflex ; B 27 -11 468 661 ; +C -1 ; WX 500 ; N ntilde ; B 14 -9 476 624 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 102 -18 765 876 ; +C -1 ; WX 611 ; N Eacute ; B -1 0 634 876 ; +C -1 ; WX 444 ; N emacron ; B 31 -11 457 583 ; +C -1 ; WX 500 ; N gbreve ; B 8 -206 487 650 ; +C -1 ; WX 750 ; N onequarter ; B 33 -10 736 676 ; +C -1 ; WX 500 ; N Scaron ; B 17 -18 520 873 ; +C -1 ; WX 500 ; N Scommaaccent ; B 17 -217 508 667 ; +C -1 ; WX 722 ; N Ohungarumlaut ; B 60 -18 699 876 ; +C -1 ; WX 400 ; N degree ; B 101 390 387 676 ; +C -1 ; WX 500 ; N ograve ; B 27 -11 468 664 ; +C -1 ; WX 667 ; N Ccaron ; B 66 -18 689 873 ; +C -1 ; WX 500 ; N ugrave ; B 42 -11 475 664 ; +C -1 ; WX 453 ; N radical ; B 2 -60 452 768 ; +C -1 ; WX 722 ; N Dcaron ; B -8 0 700 873 ; +C -1 ; WX 389 ; N rcommaaccent ; B -3 -217 412 441 ; +C -1 ; WX 667 ; N Ntilde ; B -20 -15 727 836 ; +C -1 ; WX 500 ; N otilde ; B 27 -11 496 624 ; +C -1 ; WX 611 ; N Rcommaaccent ; B -13 -187 588 653 ; +C -1 ; WX 556 ; N Lcommaaccent ; B -8 -217 559 653 ; +C -1 ; WX 611 ; N Atilde ; B -51 0 566 836 ; +C -1 ; WX 611 ; N Aogonek ; B -51 -169 566 668 ; +C -1 ; WX 611 ; N Aring ; B -51 0 564 883 ; +C -1 ; WX 722 ; N Otilde ; B 60 -18 699 836 ; +C -1 ; WX 389 ; N zdotaccent ; B -2 -81 380 606 ; +C -1 ; WX 611 ; N Ecaron ; B -1 0 634 873 ; +C -1 ; WX 333 ; N Iogonek ; B -8 -169 384 653 ; +C -1 ; WX 444 ; N kcommaaccent ; B 14 -187 461 683 ; +C -1 ; WX 675 ; N minus ; B 86 220 590 286 ; +C -1 ; WX 333 ; N Icircumflex ; B -8 0 425 873 ; +C -1 ; WX 500 ; N ncaron ; B 14 -9 510 661 ; +C -1 ; WX 278 ; N tcommaaccent ; B 2 -217 296 546 ; +C -1 ; WX 675 ; N logicalnot ; B 86 108 590 386 ; +C -1 ; WX 500 ; N odieresis ; B 27 -11 489 606 ; +C -1 ; WX 500 ; N udieresis ; B 42 -11 479 606 ; +C -1 ; WX 549 ; N notequal ; B 12 -29 537 541 ; +C -1 ; WX 500 ; N gcommaaccent ; B 8 -206 472 706 ; +C -1 ; WX 500 ; N eth ; B 27 -11 482 683 ; +C -1 ; WX 389 ; N zcaron ; B -2 -81 434 661 ; +C -1 ; WX 500 ; N ncommaaccent ; B 14 -187 474 441 ; +C -1 ; WX 300 ; N onebaseior ; B 43 271 284 676 ; +C -1 ; WX 278 ; N imacron ; B 46 -11 311 583 ; +C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2321 +KPX A C -30 +KPX A Cacute -30 +KPX A Ccaron -30 +KPX A Ccedilla -30 +KPX A G -35 +KPX A Gbreve -35 +KPX A Gcommaaccent -35 +KPX A O -40 +KPX A Oacute -40 +KPX A Ocircumflex -40 +KPX A Odieresis -40 +KPX A Ograve -40 +KPX A Ohungarumlaut -40 +KPX A Omacron -40 +KPX A Oslash -40 +KPX A Otilde -40 +KPX A Q -40 +KPX A T -37 +KPX A Tcaron -37 +KPX A Tcommaaccent -37 +KPX A U -50 +KPX A Uacute -50 +KPX A Ucircumflex -50 +KPX A Udieresis -50 +KPX A Ugrave -50 +KPX A Uhungarumlaut -50 +KPX A Umacron -50 +KPX A Uogonek -50 +KPX A Uring -50 +KPX A V -105 +KPX A W -95 +KPX A Y -55 +KPX A Yacute -55 +KPX A Ydieresis -55 +KPX A quoteright -37 +KPX A u -20 +KPX A uacute -20 +KPX A ucircumflex -20 +KPX A udieresis -20 +KPX A ugrave -20 +KPX A uhungarumlaut -20 +KPX A umacron -20 +KPX A uogonek -20 +KPX A uring -20 +KPX A v -55 +KPX A w -55 +KPX A y -55 +KPX A yacute -55 +KPX A ydieresis -55 +KPX Aacute C -30 +KPX Aacute Cacute -30 +KPX Aacute Ccaron -30 +KPX Aacute Ccedilla -30 +KPX Aacute G -35 +KPX Aacute Gbreve -35 +KPX Aacute Gcommaaccent -35 +KPX Aacute O -40 +KPX Aacute Oacute -40 +KPX Aacute Ocircumflex -40 +KPX Aacute Odieresis -40 +KPX Aacute Ograve -40 +KPX Aacute Ohungarumlaut -40 +KPX Aacute Omacron -40 +KPX Aacute Oslash -40 +KPX Aacute Otilde -40 +KPX Aacute Q -40 +KPX Aacute T -37 +KPX Aacute Tcaron -37 +KPX Aacute Tcommaaccent -37 +KPX Aacute U -50 +KPX Aacute Uacute -50 +KPX Aacute Ucircumflex -50 +KPX Aacute Udieresis -50 +KPX Aacute Ugrave -50 +KPX Aacute Uhungarumlaut -50 +KPX Aacute Umacron -50 +KPX Aacute Uogonek -50 +KPX Aacute Uring -50 +KPX Aacute V -105 +KPX Aacute W -95 +KPX Aacute Y -55 +KPX Aacute Yacute -55 +KPX Aacute Ydieresis -55 +KPX Aacute quoteright -37 +KPX Aacute u -20 +KPX Aacute uacute -20 +KPX Aacute ucircumflex -20 +KPX Aacute udieresis -20 +KPX Aacute ugrave -20 +KPX Aacute uhungarumlaut -20 +KPX Aacute umacron -20 +KPX Aacute uogonek -20 +KPX Aacute uring -20 +KPX Aacute v -55 +KPX Aacute w -55 +KPX Aacute y -55 +KPX Aacute yacute -55 +KPX Aacute ydieresis -55 +KPX Abreve C -30 +KPX Abreve Cacute -30 +KPX Abreve Ccaron -30 +KPX Abreve Ccedilla -30 +KPX Abreve G -35 +KPX Abreve Gbreve -35 +KPX Abreve Gcommaaccent -35 +KPX Abreve O -40 +KPX Abreve Oacute -40 +KPX Abreve Ocircumflex -40 +KPX Abreve Odieresis -40 +KPX Abreve Ograve -40 +KPX Abreve Ohungarumlaut -40 +KPX Abreve Omacron -40 +KPX Abreve Oslash -40 +KPX Abreve Otilde -40 +KPX Abreve Q -40 +KPX Abreve T -37 +KPX Abreve Tcaron -37 +KPX Abreve Tcommaaccent -37 +KPX Abreve U -50 +KPX Abreve Uacute -50 +KPX Abreve Ucircumflex -50 +KPX Abreve Udieresis -50 +KPX Abreve Ugrave -50 +KPX Abreve Uhungarumlaut -50 +KPX Abreve Umacron -50 +KPX Abreve Uogonek -50 +KPX Abreve Uring -50 +KPX Abreve V -105 +KPX Abreve W -95 +KPX Abreve Y -55 +KPX Abreve Yacute -55 +KPX Abreve Ydieresis -55 +KPX Abreve quoteright -37 +KPX Abreve u -20 +KPX Abreve uacute -20 +KPX Abreve ucircumflex -20 +KPX Abreve udieresis -20 +KPX Abreve ugrave -20 +KPX Abreve uhungarumlaut -20 +KPX Abreve umacron -20 +KPX Abreve uogonek -20 +KPX Abreve uring -20 +KPX Abreve v -55 +KPX Abreve w -55 +KPX Abreve y -55 +KPX Abreve yacute -55 +KPX Abreve ydieresis -55 +KPX Acircumflex C -30 +KPX Acircumflex Cacute -30 +KPX Acircumflex Ccaron -30 +KPX Acircumflex Ccedilla -30 +KPX Acircumflex G -35 +KPX Acircumflex Gbreve -35 +KPX Acircumflex Gcommaaccent -35 +KPX Acircumflex O -40 +KPX Acircumflex Oacute -40 +KPX Acircumflex Ocircumflex -40 +KPX Acircumflex Odieresis -40 +KPX Acircumflex Ograve -40 +KPX Acircumflex Ohungarumlaut -40 +KPX Acircumflex Omacron -40 +KPX Acircumflex Oslash -40 +KPX Acircumflex Otilde -40 +KPX Acircumflex Q -40 +KPX Acircumflex T -37 +KPX Acircumflex Tcaron -37 +KPX Acircumflex Tcommaaccent -37 +KPX Acircumflex U -50 +KPX Acircumflex Uacute -50 +KPX Acircumflex Ucircumflex -50 +KPX Acircumflex Udieresis -50 +KPX Acircumflex Ugrave -50 +KPX Acircumflex Uhungarumlaut -50 +KPX Acircumflex Umacron -50 +KPX Acircumflex Uogonek -50 +KPX Acircumflex Uring -50 +KPX Acircumflex V -105 +KPX Acircumflex W -95 +KPX Acircumflex Y -55 +KPX Acircumflex Yacute -55 +KPX Acircumflex Ydieresis -55 +KPX Acircumflex quoteright -37 +KPX Acircumflex u -20 +KPX Acircumflex uacute -20 +KPX Acircumflex ucircumflex -20 +KPX Acircumflex udieresis -20 +KPX Acircumflex ugrave -20 +KPX Acircumflex uhungarumlaut -20 +KPX Acircumflex umacron -20 +KPX Acircumflex uogonek -20 +KPX Acircumflex uring -20 +KPX Acircumflex v -55 +KPX Acircumflex w -55 +KPX Acircumflex y -55 +KPX Acircumflex yacute -55 +KPX Acircumflex ydieresis -55 +KPX Adieresis C -30 +KPX Adieresis Cacute -30 +KPX Adieresis Ccaron -30 +KPX Adieresis Ccedilla -30 +KPX Adieresis G -35 +KPX Adieresis Gbreve -35 +KPX Adieresis Gcommaaccent -35 +KPX Adieresis O -40 +KPX Adieresis Oacute -40 +KPX Adieresis Ocircumflex -40 +KPX Adieresis Odieresis -40 +KPX Adieresis Ograve -40 +KPX Adieresis Ohungarumlaut -40 +KPX Adieresis Omacron -40 +KPX Adieresis Oslash -40 +KPX Adieresis Otilde -40 +KPX Adieresis Q -40 +KPX Adieresis T -37 +KPX Adieresis Tcaron -37 +KPX Adieresis Tcommaaccent -37 +KPX Adieresis U -50 +KPX Adieresis Uacute -50 +KPX Adieresis Ucircumflex -50 +KPX Adieresis Udieresis -50 +KPX Adieresis Ugrave -50 +KPX Adieresis Uhungarumlaut -50 +KPX Adieresis Umacron -50 +KPX Adieresis Uogonek -50 +KPX Adieresis Uring -50 +KPX Adieresis V -105 +KPX Adieresis W -95 +KPX Adieresis Y -55 +KPX Adieresis Yacute -55 +KPX Adieresis Ydieresis -55 +KPX Adieresis quoteright -37 +KPX Adieresis u -20 +KPX Adieresis uacute -20 +KPX Adieresis ucircumflex -20 +KPX Adieresis udieresis -20 +KPX Adieresis ugrave -20 +KPX Adieresis uhungarumlaut -20 +KPX Adieresis umacron -20 +KPX Adieresis uogonek -20 +KPX Adieresis uring -20 +KPX Adieresis v -55 +KPX Adieresis w -55 +KPX Adieresis y -55 +KPX Adieresis yacute -55 +KPX Adieresis ydieresis -55 +KPX Agrave C -30 +KPX Agrave Cacute -30 +KPX Agrave Ccaron -30 +KPX Agrave Ccedilla -30 +KPX Agrave G -35 +KPX Agrave Gbreve -35 +KPX Agrave Gcommaaccent -35 +KPX Agrave O -40 +KPX Agrave Oacute -40 +KPX Agrave Ocircumflex -40 +KPX Agrave Odieresis -40 +KPX Agrave Ograve -40 +KPX Agrave Ohungarumlaut -40 +KPX Agrave Omacron -40 +KPX Agrave Oslash -40 +KPX Agrave Otilde -40 +KPX Agrave Q -40 +KPX Agrave T -37 +KPX Agrave Tcaron -37 +KPX Agrave Tcommaaccent -37 +KPX Agrave U -50 +KPX Agrave Uacute -50 +KPX Agrave Ucircumflex -50 +KPX Agrave Udieresis -50 +KPX Agrave Ugrave -50 +KPX Agrave Uhungarumlaut -50 +KPX Agrave Umacron -50 +KPX Agrave Uogonek -50 +KPX Agrave Uring -50 +KPX Agrave V -105 +KPX Agrave W -95 +KPX Agrave Y -55 +KPX Agrave Yacute -55 +KPX Agrave Ydieresis -55 +KPX Agrave quoteright -37 +KPX Agrave u -20 +KPX Agrave uacute -20 +KPX Agrave ucircumflex -20 +KPX Agrave udieresis -20 +KPX Agrave ugrave -20 +KPX Agrave uhungarumlaut -20 +KPX Agrave umacron -20 +KPX Agrave uogonek -20 +KPX Agrave uring -20 +KPX Agrave v -55 +KPX Agrave w -55 +KPX Agrave y -55 +KPX Agrave yacute -55 +KPX Agrave ydieresis -55 +KPX Amacron C -30 +KPX Amacron Cacute -30 +KPX Amacron Ccaron -30 +KPX Amacron Ccedilla -30 +KPX Amacron G -35 +KPX Amacron Gbreve -35 +KPX Amacron Gcommaaccent -35 +KPX Amacron O -40 +KPX Amacron Oacute -40 +KPX Amacron Ocircumflex -40 +KPX Amacron Odieresis -40 +KPX Amacron Ograve -40 +KPX Amacron Ohungarumlaut -40 +KPX Amacron Omacron -40 +KPX Amacron Oslash -40 +KPX Amacron Otilde -40 +KPX Amacron Q -40 +KPX Amacron T -37 +KPX Amacron Tcaron -37 +KPX Amacron Tcommaaccent -37 +KPX Amacron U -50 +KPX Amacron Uacute -50 +KPX Amacron Ucircumflex -50 +KPX Amacron Udieresis -50 +KPX Amacron Ugrave -50 +KPX Amacron Uhungarumlaut -50 +KPX Amacron Umacron -50 +KPX Amacron Uogonek -50 +KPX Amacron Uring -50 +KPX Amacron V -105 +KPX Amacron W -95 +KPX Amacron Y -55 +KPX Amacron Yacute -55 +KPX Amacron Ydieresis -55 +KPX Amacron quoteright -37 +KPX Amacron u -20 +KPX Amacron uacute -20 +KPX Amacron ucircumflex -20 +KPX Amacron udieresis -20 +KPX Amacron ugrave -20 +KPX Amacron uhungarumlaut -20 +KPX Amacron umacron -20 +KPX Amacron uogonek -20 +KPX Amacron uring -20 +KPX Amacron v -55 +KPX Amacron w -55 +KPX Amacron y -55 +KPX Amacron yacute -55 +KPX Amacron ydieresis -55 +KPX Aogonek C -30 +KPX Aogonek Cacute -30 +KPX Aogonek Ccaron -30 +KPX Aogonek Ccedilla -30 +KPX Aogonek G -35 +KPX Aogonek Gbreve -35 +KPX Aogonek Gcommaaccent -35 +KPX Aogonek O -40 +KPX Aogonek Oacute -40 +KPX Aogonek Ocircumflex -40 +KPX Aogonek Odieresis -40 +KPX Aogonek Ograve -40 +KPX Aogonek Ohungarumlaut -40 +KPX Aogonek Omacron -40 +KPX Aogonek Oslash -40 +KPX Aogonek Otilde -40 +KPX Aogonek Q -40 +KPX Aogonek T -37 +KPX Aogonek Tcaron -37 +KPX Aogonek Tcommaaccent -37 +KPX Aogonek U -50 +KPX Aogonek Uacute -50 +KPX Aogonek Ucircumflex -50 +KPX Aogonek Udieresis -50 +KPX Aogonek Ugrave -50 +KPX Aogonek Uhungarumlaut -50 +KPX Aogonek Umacron -50 +KPX Aogonek Uogonek -50 +KPX Aogonek Uring -50 +KPX Aogonek V -105 +KPX Aogonek W -95 +KPX Aogonek Y -55 +KPX Aogonek Yacute -55 +KPX Aogonek Ydieresis -55 +KPX Aogonek quoteright -37 +KPX Aogonek u -20 +KPX Aogonek uacute -20 +KPX Aogonek ucircumflex -20 +KPX Aogonek udieresis -20 +KPX Aogonek ugrave -20 +KPX Aogonek uhungarumlaut -20 +KPX Aogonek umacron -20 +KPX Aogonek uogonek -20 +KPX Aogonek uring -20 +KPX Aogonek v -55 +KPX Aogonek w -55 +KPX Aogonek y -55 +KPX Aogonek yacute -55 +KPX Aogonek ydieresis -55 +KPX Aring C -30 +KPX Aring Cacute -30 +KPX Aring Ccaron -30 +KPX Aring Ccedilla -30 +KPX Aring G -35 +KPX Aring Gbreve -35 +KPX Aring Gcommaaccent -35 +KPX Aring O -40 +KPX Aring Oacute -40 +KPX Aring Ocircumflex -40 +KPX Aring Odieresis -40 +KPX Aring Ograve -40 +KPX Aring Ohungarumlaut -40 +KPX Aring Omacron -40 +KPX Aring Oslash -40 +KPX Aring Otilde -40 +KPX Aring Q -40 +KPX Aring T -37 +KPX Aring Tcaron -37 +KPX Aring Tcommaaccent -37 +KPX Aring U -50 +KPX Aring Uacute -50 +KPX Aring Ucircumflex -50 +KPX Aring Udieresis -50 +KPX Aring Ugrave -50 +KPX Aring Uhungarumlaut -50 +KPX Aring Umacron -50 +KPX Aring Uogonek -50 +KPX Aring Uring -50 +KPX Aring V -105 +KPX Aring W -95 +KPX Aring Y -55 +KPX Aring Yacute -55 +KPX Aring Ydieresis -55 +KPX Aring quoteright -37 +KPX Aring u -20 +KPX Aring uacute -20 +KPX Aring ucircumflex -20 +KPX Aring udieresis -20 +KPX Aring ugrave -20 +KPX Aring uhungarumlaut -20 +KPX Aring umacron -20 +KPX Aring uogonek -20 +KPX Aring uring -20 +KPX Aring v -55 +KPX Aring w -55 +KPX Aring y -55 +KPX Aring yacute -55 +KPX Aring ydieresis -55 +KPX Atilde C -30 +KPX Atilde Cacute -30 +KPX Atilde Ccaron -30 +KPX Atilde Ccedilla -30 +KPX Atilde G -35 +KPX Atilde Gbreve -35 +KPX Atilde Gcommaaccent -35 +KPX Atilde O -40 +KPX Atilde Oacute -40 +KPX Atilde Ocircumflex -40 +KPX Atilde Odieresis -40 +KPX Atilde Ograve -40 +KPX Atilde Ohungarumlaut -40 +KPX Atilde Omacron -40 +KPX Atilde Oslash -40 +KPX Atilde Otilde -40 +KPX Atilde Q -40 +KPX Atilde T -37 +KPX Atilde Tcaron -37 +KPX Atilde Tcommaaccent -37 +KPX Atilde U -50 +KPX Atilde Uacute -50 +KPX Atilde Ucircumflex -50 +KPX Atilde Udieresis -50 +KPX Atilde Ugrave -50 +KPX Atilde Uhungarumlaut -50 +KPX Atilde Umacron -50 +KPX Atilde Uogonek -50 +KPX Atilde Uring -50 +KPX Atilde V -105 +KPX Atilde W -95 +KPX Atilde Y -55 +KPX Atilde Yacute -55 +KPX Atilde Ydieresis -55 +KPX Atilde quoteright -37 +KPX Atilde u -20 +KPX Atilde uacute -20 +KPX Atilde ucircumflex -20 +KPX Atilde udieresis -20 +KPX Atilde ugrave -20 +KPX Atilde uhungarumlaut -20 +KPX Atilde umacron -20 +KPX Atilde uogonek -20 +KPX Atilde uring -20 +KPX Atilde v -55 +KPX Atilde w -55 +KPX Atilde y -55 +KPX Atilde yacute -55 +KPX Atilde ydieresis -55 +KPX B A -25 +KPX B Aacute -25 +KPX B Abreve -25 +KPX B Acircumflex -25 +KPX B Adieresis -25 +KPX B Agrave -25 +KPX B Amacron -25 +KPX B Aogonek -25 +KPX B Aring -25 +KPX B Atilde -25 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX D A -35 +KPX D Aacute -35 +KPX D Abreve -35 +KPX D Acircumflex -35 +KPX D Adieresis -35 +KPX D Agrave -35 +KPX D Amacron -35 +KPX D Aogonek -35 +KPX D Aring -35 +KPX D Atilde -35 +KPX D V -40 +KPX D W -40 +KPX D Y -40 +KPX D Yacute -40 +KPX D Ydieresis -40 +KPX Dcaron A -35 +KPX Dcaron Aacute -35 +KPX Dcaron Abreve -35 +KPX Dcaron Acircumflex -35 +KPX Dcaron Adieresis -35 +KPX Dcaron Agrave -35 +KPX Dcaron Amacron -35 +KPX Dcaron Aogonek -35 +KPX Dcaron Aring -35 +KPX Dcaron Atilde -35 +KPX Dcaron V -40 +KPX Dcaron W -40 +KPX Dcaron Y -40 +KPX Dcaron Yacute -40 +KPX Dcaron Ydieresis -40 +KPX Dcroat A -35 +KPX Dcroat Aacute -35 +KPX Dcroat Abreve -35 +KPX Dcroat Acircumflex -35 +KPX Dcroat Adieresis -35 +KPX Dcroat Agrave -35 +KPX Dcroat Amacron -35 +KPX Dcroat Aogonek -35 +KPX Dcroat Aring -35 +KPX Dcroat Atilde -35 +KPX Dcroat V -40 +KPX Dcroat W -40 +KPX Dcroat Y -40 +KPX Dcroat Yacute -40 +KPX Dcroat Ydieresis -40 +KPX F A -115 +KPX F Aacute -115 +KPX F Abreve -115 +KPX F Acircumflex -115 +KPX F Adieresis -115 +KPX F Agrave -115 +KPX F Amacron -115 +KPX F Aogonek -115 +KPX F Aring -115 +KPX F Atilde -115 +KPX F a -75 +KPX F aacute -75 +KPX F abreve -75 +KPX F acircumflex -75 +KPX F adieresis -75 +KPX F agrave -75 +KPX F amacron -75 +KPX F aogonek -75 +KPX F aring -75 +KPX F atilde -75 +KPX F comma -135 +KPX F e -75 +KPX F eacute -75 +KPX F ecaron -75 +KPX F ecircumflex -75 +KPX F edieresis -75 +KPX F edotaccent -75 +KPX F egrave -75 +KPX F emacron -75 +KPX F eogonek -75 +KPX F i -45 +KPX F iacute -45 +KPX F icircumflex -45 +KPX F idieresis -45 +KPX F igrave -45 +KPX F imacron -45 +KPX F iogonek -45 +KPX F o -105 +KPX F oacute -105 +KPX F ocircumflex -105 +KPX F odieresis -105 +KPX F ograve -105 +KPX F ohungarumlaut -105 +KPX F omacron -105 +KPX F oslash -105 +KPX F otilde -105 +KPX F period -135 +KPX F r -55 +KPX F racute -55 +KPX F rcaron -55 +KPX F rcommaaccent -55 +KPX J A -40 +KPX J Aacute -40 +KPX J Abreve -40 +KPX J Acircumflex -40 +KPX J Adieresis -40 +KPX J Agrave -40 +KPX J Amacron -40 +KPX J Aogonek -40 +KPX J Aring -40 +KPX J Atilde -40 +KPX J a -35 +KPX J aacute -35 +KPX J abreve -35 +KPX J acircumflex -35 +KPX J adieresis -35 +KPX J agrave -35 +KPX J amacron -35 +KPX J aogonek -35 +KPX J aring -35 +KPX J atilde -35 +KPX J comma -25 +KPX J e -25 +KPX J eacute -25 +KPX J ecaron -25 +KPX J ecircumflex -25 +KPX J edieresis -25 +KPX J edotaccent -25 +KPX J egrave -25 +KPX J emacron -25 +KPX J eogonek -25 +KPX J o -25 +KPX J oacute -25 +KPX J ocircumflex -25 +KPX J odieresis -25 +KPX J ograve -25 +KPX J ohungarumlaut -25 +KPX J omacron -25 +KPX J oslash -25 +KPX J otilde -25 +KPX J period -25 +KPX J u -35 +KPX J uacute -35 +KPX J ucircumflex -35 +KPX J udieresis -35 +KPX J ugrave -35 +KPX J uhungarumlaut -35 +KPX J umacron -35 +KPX J uogonek -35 +KPX J uring -35 +KPX K O -50 +KPX K Oacute -50 +KPX K Ocircumflex -50 +KPX K Odieresis -50 +KPX K Ograve -50 +KPX K Ohungarumlaut -50 +KPX K Omacron -50 +KPX K Oslash -50 +KPX K Otilde -50 +KPX K e -35 +KPX K eacute -35 +KPX K ecaron -35 +KPX K ecircumflex -35 +KPX K edieresis -35 +KPX K edotaccent -35 +KPX K egrave -35 +KPX K emacron -35 +KPX K eogonek -35 +KPX K o -40 +KPX K oacute -40 +KPX K ocircumflex -40 +KPX K odieresis -40 +KPX K ograve -40 +KPX K ohungarumlaut -40 +KPX K omacron -40 +KPX K oslash -40 +KPX K otilde -40 +KPX K u -40 +KPX K uacute -40 +KPX K ucircumflex -40 +KPX K udieresis -40 +KPX K ugrave -40 +KPX K uhungarumlaut -40 +KPX K umacron -40 +KPX K uogonek -40 +KPX K uring -40 +KPX K y -40 +KPX K yacute -40 +KPX K ydieresis -40 +KPX Kcommaaccent O -50 +KPX Kcommaaccent Oacute -50 +KPX Kcommaaccent Ocircumflex -50 +KPX Kcommaaccent Odieresis -50 +KPX Kcommaaccent Ograve -50 +KPX Kcommaaccent Ohungarumlaut -50 +KPX Kcommaaccent Omacron -50 +KPX Kcommaaccent Oslash -50 +KPX Kcommaaccent Otilde -50 +KPX Kcommaaccent e -35 +KPX Kcommaaccent eacute -35 +KPX Kcommaaccent ecaron -35 +KPX Kcommaaccent ecircumflex -35 +KPX Kcommaaccent edieresis -35 +KPX Kcommaaccent edotaccent -35 +KPX Kcommaaccent egrave -35 +KPX Kcommaaccent emacron -35 +KPX Kcommaaccent eogonek -35 +KPX Kcommaaccent o -40 +KPX Kcommaaccent oacute -40 +KPX Kcommaaccent ocircumflex -40 +KPX Kcommaaccent odieresis -40 +KPX Kcommaaccent ograve -40 +KPX Kcommaaccent ohungarumlaut -40 +KPX Kcommaaccent omacron -40 +KPX Kcommaaccent oslash -40 +KPX Kcommaaccent otilde -40 +KPX Kcommaaccent u -40 +KPX Kcommaaccent uacute -40 +KPX Kcommaaccent ucircumflex -40 +KPX Kcommaaccent udieresis -40 +KPX Kcommaaccent ugrave -40 +KPX Kcommaaccent uhungarumlaut -40 +KPX Kcommaaccent umacron -40 +KPX Kcommaaccent uogonek -40 +KPX Kcommaaccent uring -40 +KPX Kcommaaccent y -40 +KPX Kcommaaccent yacute -40 +KPX Kcommaaccent ydieresis -40 +KPX L T -20 +KPX L Tcaron -20 +KPX L Tcommaaccent -20 +KPX L V -55 +KPX L W -55 +KPX L Y -20 +KPX L Yacute -20 +KPX L Ydieresis -20 +KPX L quoteright -37 +KPX L y -30 +KPX L yacute -30 +KPX L ydieresis -30 +KPX Lacute T -20 +KPX Lacute Tcaron -20 +KPX Lacute Tcommaaccent -20 +KPX Lacute V -55 +KPX Lacute W -55 +KPX Lacute Y -20 +KPX Lacute Yacute -20 +KPX Lacute Ydieresis -20 +KPX Lacute quoteright -37 +KPX Lacute y -30 +KPX Lacute yacute -30 +KPX Lacute ydieresis -30 +KPX Lcommaaccent T -20 +KPX Lcommaaccent Tcaron -20 +KPX Lcommaaccent Tcommaaccent -20 +KPX Lcommaaccent V -55 +KPX Lcommaaccent W -55 +KPX Lcommaaccent Y -20 +KPX Lcommaaccent Yacute -20 +KPX Lcommaaccent Ydieresis -20 +KPX Lcommaaccent quoteright -37 +KPX Lcommaaccent y -30 +KPX Lcommaaccent yacute -30 +KPX Lcommaaccent ydieresis -30 +KPX Lslash T -20 +KPX Lslash Tcaron -20 +KPX Lslash Tcommaaccent -20 +KPX Lslash V -55 +KPX Lslash W -55 +KPX Lslash Y -20 +KPX Lslash Yacute -20 +KPX Lslash Ydieresis -20 +KPX Lslash quoteright -37 +KPX Lslash y -30 +KPX Lslash yacute -30 +KPX Lslash ydieresis -30 +KPX N A -27 +KPX N Aacute -27 +KPX N Abreve -27 +KPX N Acircumflex -27 +KPX N Adieresis -27 +KPX N Agrave -27 +KPX N Amacron -27 +KPX N Aogonek -27 +KPX N Aring -27 +KPX N Atilde -27 +KPX Nacute A -27 +KPX Nacute Aacute -27 +KPX Nacute Abreve -27 +KPX Nacute Acircumflex -27 +KPX Nacute Adieresis -27 +KPX Nacute Agrave -27 +KPX Nacute Amacron -27 +KPX Nacute Aogonek -27 +KPX Nacute Aring -27 +KPX Nacute Atilde -27 +KPX Ncaron A -27 +KPX Ncaron Aacute -27 +KPX Ncaron Abreve -27 +KPX Ncaron Acircumflex -27 +KPX Ncaron Adieresis -27 +KPX Ncaron Agrave -27 +KPX Ncaron Amacron -27 +KPX Ncaron Aogonek -27 +KPX Ncaron Aring -27 +KPX Ncaron Atilde -27 +KPX Ncommaaccent A -27 +KPX Ncommaaccent Aacute -27 +KPX Ncommaaccent Abreve -27 +KPX Ncommaaccent Acircumflex -27 +KPX Ncommaaccent Adieresis -27 +KPX Ncommaaccent Agrave -27 +KPX Ncommaaccent Amacron -27 +KPX Ncommaaccent Aogonek -27 +KPX Ncommaaccent Aring -27 +KPX Ncommaaccent Atilde -27 +KPX Ntilde A -27 +KPX Ntilde Aacute -27 +KPX Ntilde Abreve -27 +KPX Ntilde Acircumflex -27 +KPX Ntilde Adieresis -27 +KPX Ntilde Agrave -27 +KPX Ntilde Amacron -27 +KPX Ntilde Aogonek -27 +KPX Ntilde Aring -27 +KPX Ntilde Atilde -27 +KPX O A -55 +KPX O Aacute -55 +KPX O Abreve -55 +KPX O Acircumflex -55 +KPX O Adieresis -55 +KPX O Agrave -55 +KPX O Amacron -55 +KPX O Aogonek -55 +KPX O Aring -55 +KPX O Atilde -55 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -50 +KPX O X -40 +KPX O Y -50 +KPX O Yacute -50 +KPX O Ydieresis -50 +KPX Oacute A -55 +KPX Oacute Aacute -55 +KPX Oacute Abreve -55 +KPX Oacute Acircumflex -55 +KPX Oacute Adieresis -55 +KPX Oacute Agrave -55 +KPX Oacute Amacron -55 +KPX Oacute Aogonek -55 +KPX Oacute Aring -55 +KPX Oacute Atilde -55 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -50 +KPX Oacute X -40 +KPX Oacute Y -50 +KPX Oacute Yacute -50 +KPX Oacute Ydieresis -50 +KPX Ocircumflex A -55 +KPX Ocircumflex Aacute -55 +KPX Ocircumflex Abreve -55 +KPX Ocircumflex Acircumflex -55 +KPX Ocircumflex Adieresis -55 +KPX Ocircumflex Agrave -55 +KPX Ocircumflex Amacron -55 +KPX Ocircumflex Aogonek -55 +KPX Ocircumflex Aring -55 +KPX Ocircumflex Atilde -55 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -50 +KPX Ocircumflex X -40 +KPX Ocircumflex Y -50 +KPX Ocircumflex Yacute -50 +KPX Ocircumflex Ydieresis -50 +KPX Odieresis A -55 +KPX Odieresis Aacute -55 +KPX Odieresis Abreve -55 +KPX Odieresis Acircumflex -55 +KPX Odieresis Adieresis -55 +KPX Odieresis Agrave -55 +KPX Odieresis Amacron -55 +KPX Odieresis Aogonek -55 +KPX Odieresis Aring -55 +KPX Odieresis Atilde -55 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -50 +KPX Odieresis X -40 +KPX Odieresis Y -50 +KPX Odieresis Yacute -50 +KPX Odieresis Ydieresis -50 +KPX Ograve A -55 +KPX Ograve Aacute -55 +KPX Ograve Abreve -55 +KPX Ograve Acircumflex -55 +KPX Ograve Adieresis -55 +KPX Ograve Agrave -55 +KPX Ograve Amacron -55 +KPX Ograve Aogonek -55 +KPX Ograve Aring -55 +KPX Ograve Atilde -55 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -50 +KPX Ograve X -40 +KPX Ograve Y -50 +KPX Ograve Yacute -50 +KPX Ograve Ydieresis -50 +KPX Ohungarumlaut A -55 +KPX Ohungarumlaut Aacute -55 +KPX Ohungarumlaut Abreve -55 +KPX Ohungarumlaut Acircumflex -55 +KPX Ohungarumlaut Adieresis -55 +KPX Ohungarumlaut Agrave -55 +KPX Ohungarumlaut Amacron -55 +KPX Ohungarumlaut Aogonek -55 +KPX Ohungarumlaut Aring -55 +KPX Ohungarumlaut Atilde -55 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -50 +KPX Ohungarumlaut X -40 +KPX Ohungarumlaut Y -50 +KPX Ohungarumlaut Yacute -50 +KPX Ohungarumlaut Ydieresis -50 +KPX Omacron A -55 +KPX Omacron Aacute -55 +KPX Omacron Abreve -55 +KPX Omacron Acircumflex -55 +KPX Omacron Adieresis -55 +KPX Omacron Agrave -55 +KPX Omacron Amacron -55 +KPX Omacron Aogonek -55 +KPX Omacron Aring -55 +KPX Omacron Atilde -55 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -50 +KPX Omacron X -40 +KPX Omacron Y -50 +KPX Omacron Yacute -50 +KPX Omacron Ydieresis -50 +KPX Oslash A -55 +KPX Oslash Aacute -55 +KPX Oslash Abreve -55 +KPX Oslash Acircumflex -55 +KPX Oslash Adieresis -55 +KPX Oslash Agrave -55 +KPX Oslash Amacron -55 +KPX Oslash Aogonek -55 +KPX Oslash Aring -55 +KPX Oslash Atilde -55 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -50 +KPX Oslash X -40 +KPX Oslash Y -50 +KPX Oslash Yacute -50 +KPX Oslash Ydieresis -50 +KPX Otilde A -55 +KPX Otilde Aacute -55 +KPX Otilde Abreve -55 +KPX Otilde Acircumflex -55 +KPX Otilde Adieresis -55 +KPX Otilde Agrave -55 +KPX Otilde Amacron -55 +KPX Otilde Aogonek -55 +KPX Otilde Aring -55 +KPX Otilde Atilde -55 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -50 +KPX Otilde X -40 +KPX Otilde Y -50 +KPX Otilde Yacute -50 +KPX Otilde Ydieresis -50 +KPX P A -90 +KPX P Aacute -90 +KPX P Abreve -90 +KPX P Acircumflex -90 +KPX P Adieresis -90 +KPX P Agrave -90 +KPX P Amacron -90 +KPX P Aogonek -90 +KPX P Aring -90 +KPX P Atilde -90 +KPX P a -80 +KPX P aacute -80 +KPX P abreve -80 +KPX P acircumflex -80 +KPX P adieresis -80 +KPX P agrave -80 +KPX P amacron -80 +KPX P aogonek -80 +KPX P aring -80 +KPX P atilde -80 +KPX P comma -135 +KPX P e -80 +KPX P eacute -80 +KPX P ecaron -80 +KPX P ecircumflex -80 +KPX P edieresis -80 +KPX P edotaccent -80 +KPX P egrave -80 +KPX P emacron -80 +KPX P eogonek -80 +KPX P o -80 +KPX P oacute -80 +KPX P ocircumflex -80 +KPX P odieresis -80 +KPX P ograve -80 +KPX P ohungarumlaut -80 +KPX P omacron -80 +KPX P oslash -80 +KPX P otilde -80 +KPX P period -135 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX R O -40 +KPX R Oacute -40 +KPX R Ocircumflex -40 +KPX R Odieresis -40 +KPX R Ograve -40 +KPX R Ohungarumlaut -40 +KPX R Omacron -40 +KPX R Oslash -40 +KPX R Otilde -40 +KPX R U -40 +KPX R Uacute -40 +KPX R Ucircumflex -40 +KPX R Udieresis -40 +KPX R Ugrave -40 +KPX R Uhungarumlaut -40 +KPX R Umacron -40 +KPX R Uogonek -40 +KPX R Uring -40 +KPX R V -18 +KPX R W -18 +KPX R Y -18 +KPX R Yacute -18 +KPX R Ydieresis -18 +KPX Racute O -40 +KPX Racute Oacute -40 +KPX Racute Ocircumflex -40 +KPX Racute Odieresis -40 +KPX Racute Ograve -40 +KPX Racute Ohungarumlaut -40 +KPX Racute Omacron -40 +KPX Racute Oslash -40 +KPX Racute Otilde -40 +KPX Racute U -40 +KPX Racute Uacute -40 +KPX Racute Ucircumflex -40 +KPX Racute Udieresis -40 +KPX Racute Ugrave -40 +KPX Racute Uhungarumlaut -40 +KPX Racute Umacron -40 +KPX Racute Uogonek -40 +KPX Racute Uring -40 +KPX Racute V -18 +KPX Racute W -18 +KPX Racute Y -18 +KPX Racute Yacute -18 +KPX Racute Ydieresis -18 +KPX Rcaron O -40 +KPX Rcaron Oacute -40 +KPX Rcaron Ocircumflex -40 +KPX Rcaron Odieresis -40 +KPX Rcaron Ograve -40 +KPX Rcaron Ohungarumlaut -40 +KPX Rcaron Omacron -40 +KPX Rcaron Oslash -40 +KPX Rcaron Otilde -40 +KPX Rcaron U -40 +KPX Rcaron Uacute -40 +KPX Rcaron Ucircumflex -40 +KPX Rcaron Udieresis -40 +KPX Rcaron Ugrave -40 +KPX Rcaron Uhungarumlaut -40 +KPX Rcaron Umacron -40 +KPX Rcaron Uogonek -40 +KPX Rcaron Uring -40 +KPX Rcaron V -18 +KPX Rcaron W -18 +KPX Rcaron Y -18 +KPX Rcaron Yacute -18 +KPX Rcaron Ydieresis -18 +KPX Rcommaaccent O -40 +KPX Rcommaaccent Oacute -40 +KPX Rcommaaccent Ocircumflex -40 +KPX Rcommaaccent Odieresis -40 +KPX Rcommaaccent Ograve -40 +KPX Rcommaaccent Ohungarumlaut -40 +KPX Rcommaaccent Omacron -40 +KPX Rcommaaccent Oslash -40 +KPX Rcommaaccent Otilde -40 +KPX Rcommaaccent U -40 +KPX Rcommaaccent Uacute -40 +KPX Rcommaaccent Ucircumflex -40 +KPX Rcommaaccent Udieresis -40 +KPX Rcommaaccent Ugrave -40 +KPX Rcommaaccent Uhungarumlaut -40 +KPX Rcommaaccent Umacron -40 +KPX Rcommaaccent Uogonek -40 +KPX Rcommaaccent Uring -40 +KPX Rcommaaccent V -18 +KPX Rcommaaccent W -18 +KPX Rcommaaccent Y -18 +KPX Rcommaaccent Yacute -18 +KPX Rcommaaccent Ydieresis -18 +KPX T A -50 +KPX T Aacute -50 +KPX T Abreve -50 +KPX T Acircumflex -50 +KPX T Adieresis -50 +KPX T Agrave -50 +KPX T Amacron -50 +KPX T Aogonek -50 +KPX T Aring -50 +KPX T Atilde -50 +KPX T O -18 +KPX T Oacute -18 +KPX T Ocircumflex -18 +KPX T Odieresis -18 +KPX T Ograve -18 +KPX T Ohungarumlaut -18 +KPX T Omacron -18 +KPX T Oslash -18 +KPX T Otilde -18 +KPX T a -92 +KPX T aacute -92 +KPX T abreve -92 +KPX T acircumflex -92 +KPX T adieresis -92 +KPX T agrave -92 +KPX T amacron -92 +KPX T aogonek -92 +KPX T aring -92 +KPX T atilde -92 +KPX T colon -55 +KPX T comma -74 +KPX T e -92 +KPX T eacute -92 +KPX T ecaron -92 +KPX T ecircumflex -52 +KPX T edieresis -52 +KPX T edotaccent -92 +KPX T egrave -52 +KPX T emacron -52 +KPX T eogonek -92 +KPX T hyphen -74 +KPX T i -55 +KPX T iacute -55 +KPX T iogonek -55 +KPX T o -92 +KPX T oacute -92 +KPX T ocircumflex -92 +KPX T odieresis -92 +KPX T ograve -92 +KPX T ohungarumlaut -92 +KPX T omacron -92 +KPX T oslash -92 +KPX T otilde -92 +KPX T period -74 +KPX T r -55 +KPX T racute -55 +KPX T rcaron -55 +KPX T rcommaaccent -55 +KPX T semicolon -65 +KPX T u -55 +KPX T uacute -55 +KPX T ucircumflex -55 +KPX T udieresis -55 +KPX T ugrave -55 +KPX T uhungarumlaut -55 +KPX T umacron -55 +KPX T uogonek -55 +KPX T uring -55 +KPX T w -74 +KPX T y -74 +KPX T yacute -74 +KPX T ydieresis -34 +KPX Tcaron A -50 +KPX Tcaron Aacute -50 +KPX Tcaron Abreve -50 +KPX Tcaron Acircumflex -50 +KPX Tcaron Adieresis -50 +KPX Tcaron Agrave -50 +KPX Tcaron Amacron -50 +KPX Tcaron Aogonek -50 +KPX Tcaron Aring -50 +KPX Tcaron Atilde -50 +KPX Tcaron O -18 +KPX Tcaron Oacute -18 +KPX Tcaron Ocircumflex -18 +KPX Tcaron Odieresis -18 +KPX Tcaron Ograve -18 +KPX Tcaron Ohungarumlaut -18 +KPX Tcaron Omacron -18 +KPX Tcaron Oslash -18 +KPX Tcaron Otilde -18 +KPX Tcaron a -92 +KPX Tcaron aacute -92 +KPX Tcaron abreve -92 +KPX Tcaron acircumflex -92 +KPX Tcaron adieresis -92 +KPX Tcaron agrave -92 +KPX Tcaron amacron -92 +KPX Tcaron aogonek -92 +KPX Tcaron aring -92 +KPX Tcaron atilde -92 +KPX Tcaron colon -55 +KPX Tcaron comma -74 +KPX Tcaron e -92 +KPX Tcaron eacute -92 +KPX Tcaron ecaron -92 +KPX Tcaron ecircumflex -52 +KPX Tcaron edieresis -52 +KPX Tcaron edotaccent -92 +KPX Tcaron egrave -52 +KPX Tcaron emacron -52 +KPX Tcaron eogonek -92 +KPX Tcaron hyphen -74 +KPX Tcaron i -55 +KPX Tcaron iacute -55 +KPX Tcaron iogonek -55 +KPX Tcaron o -92 +KPX Tcaron oacute -92 +KPX Tcaron ocircumflex -92 +KPX Tcaron odieresis -92 +KPX Tcaron ograve -92 +KPX Tcaron ohungarumlaut -92 +KPX Tcaron omacron -92 +KPX Tcaron oslash -92 +KPX Tcaron otilde -92 +KPX Tcaron period -74 +KPX Tcaron r -55 +KPX Tcaron racute -55 +KPX Tcaron rcaron -55 +KPX Tcaron rcommaaccent -55 +KPX Tcaron semicolon -65 +KPX Tcaron u -55 +KPX Tcaron uacute -55 +KPX Tcaron ucircumflex -55 +KPX Tcaron udieresis -55 +KPX Tcaron ugrave -55 +KPX Tcaron uhungarumlaut -55 +KPX Tcaron umacron -55 +KPX Tcaron uogonek -55 +KPX Tcaron uring -55 +KPX Tcaron w -74 +KPX Tcaron y -74 +KPX Tcaron yacute -74 +KPX Tcaron ydieresis -34 +KPX Tcommaaccent A -50 +KPX Tcommaaccent Aacute -50 +KPX Tcommaaccent Abreve -50 +KPX Tcommaaccent Acircumflex -50 +KPX Tcommaaccent Adieresis -50 +KPX Tcommaaccent Agrave -50 +KPX Tcommaaccent Amacron -50 +KPX Tcommaaccent Aogonek -50 +KPX Tcommaaccent Aring -50 +KPX Tcommaaccent Atilde -50 +KPX Tcommaaccent O -18 +KPX Tcommaaccent Oacute -18 +KPX Tcommaaccent Ocircumflex -18 +KPX Tcommaaccent Odieresis -18 +KPX Tcommaaccent Ograve -18 +KPX Tcommaaccent Ohungarumlaut -18 +KPX Tcommaaccent Omacron -18 +KPX Tcommaaccent Oslash -18 +KPX Tcommaaccent Otilde -18 +KPX Tcommaaccent a -92 +KPX Tcommaaccent aacute -92 +KPX Tcommaaccent abreve -92 +KPX Tcommaaccent acircumflex -92 +KPX Tcommaaccent adieresis -92 +KPX Tcommaaccent agrave -92 +KPX Tcommaaccent amacron -92 +KPX Tcommaaccent aogonek -92 +KPX Tcommaaccent aring -92 +KPX Tcommaaccent atilde -92 +KPX Tcommaaccent colon -55 +KPX Tcommaaccent comma -74 +KPX Tcommaaccent e -92 +KPX Tcommaaccent eacute -92 +KPX Tcommaaccent ecaron -92 +KPX Tcommaaccent ecircumflex -52 +KPX Tcommaaccent edieresis -52 +KPX Tcommaaccent edotaccent -92 +KPX Tcommaaccent egrave -52 +KPX Tcommaaccent emacron -52 +KPX Tcommaaccent eogonek -92 +KPX Tcommaaccent hyphen -74 +KPX Tcommaaccent i -55 +KPX Tcommaaccent iacute -55 +KPX Tcommaaccent iogonek -55 +KPX Tcommaaccent o -92 +KPX Tcommaaccent oacute -92 +KPX Tcommaaccent ocircumflex -92 +KPX Tcommaaccent odieresis -92 +KPX Tcommaaccent ograve -92 +KPX Tcommaaccent ohungarumlaut -92 +KPX Tcommaaccent omacron -92 +KPX Tcommaaccent oslash -92 +KPX Tcommaaccent otilde -92 +KPX Tcommaaccent period -74 +KPX Tcommaaccent r -55 +KPX Tcommaaccent racute -55 +KPX Tcommaaccent rcaron -55 +KPX Tcommaaccent rcommaaccent -55 +KPX Tcommaaccent semicolon -65 +KPX Tcommaaccent u -55 +KPX Tcommaaccent uacute -55 +KPX Tcommaaccent ucircumflex -55 +KPX Tcommaaccent udieresis -55 +KPX Tcommaaccent ugrave -55 +KPX Tcommaaccent uhungarumlaut -55 +KPX Tcommaaccent umacron -55 +KPX Tcommaaccent uogonek -55 +KPX Tcommaaccent uring -55 +KPX Tcommaaccent w -74 +KPX Tcommaaccent y -74 +KPX Tcommaaccent yacute -74 +KPX Tcommaaccent ydieresis -34 +KPX U A -40 +KPX U Aacute -40 +KPX U Abreve -40 +KPX U Acircumflex -40 +KPX U Adieresis -40 +KPX U Agrave -40 +KPX U Amacron -40 +KPX U Aogonek -40 +KPX U Aring -40 +KPX U Atilde -40 +KPX U comma -25 +KPX U period -25 +KPX Uacute A -40 +KPX Uacute Aacute -40 +KPX Uacute Abreve -40 +KPX Uacute Acircumflex -40 +KPX Uacute Adieresis -40 +KPX Uacute Agrave -40 +KPX Uacute Amacron -40 +KPX Uacute Aogonek -40 +KPX Uacute Aring -40 +KPX Uacute Atilde -40 +KPX Uacute comma -25 +KPX Uacute period -25 +KPX Ucircumflex A -40 +KPX Ucircumflex Aacute -40 +KPX Ucircumflex Abreve -40 +KPX Ucircumflex Acircumflex -40 +KPX Ucircumflex Adieresis -40 +KPX Ucircumflex Agrave -40 +KPX Ucircumflex Amacron -40 +KPX Ucircumflex Aogonek -40 +KPX Ucircumflex Aring -40 +KPX Ucircumflex Atilde -40 +KPX Ucircumflex comma -25 +KPX Ucircumflex period -25 +KPX Udieresis A -40 +KPX Udieresis Aacute -40 +KPX Udieresis Abreve -40 +KPX Udieresis Acircumflex -40 +KPX Udieresis Adieresis -40 +KPX Udieresis Agrave -40 +KPX Udieresis Amacron -40 +KPX Udieresis Aogonek -40 +KPX Udieresis Aring -40 +KPX Udieresis Atilde -40 +KPX Udieresis comma -25 +KPX Udieresis period -25 +KPX Ugrave A -40 +KPX Ugrave Aacute -40 +KPX Ugrave Abreve -40 +KPX Ugrave Acircumflex -40 +KPX Ugrave Adieresis -40 +KPX Ugrave Agrave -40 +KPX Ugrave Amacron -40 +KPX Ugrave Aogonek -40 +KPX Ugrave Aring -40 +KPX Ugrave Atilde -40 +KPX Ugrave comma -25 +KPX Ugrave period -25 +KPX Uhungarumlaut A -40 +KPX Uhungarumlaut Aacute -40 +KPX Uhungarumlaut Abreve -40 +KPX Uhungarumlaut Acircumflex -40 +KPX Uhungarumlaut Adieresis -40 +KPX Uhungarumlaut Agrave -40 +KPX Uhungarumlaut Amacron -40 +KPX Uhungarumlaut Aogonek -40 +KPX Uhungarumlaut Aring -40 +KPX Uhungarumlaut Atilde -40 +KPX Uhungarumlaut comma -25 +KPX Uhungarumlaut period -25 +KPX Umacron A -40 +KPX Umacron Aacute -40 +KPX Umacron Abreve -40 +KPX Umacron Acircumflex -40 +KPX Umacron Adieresis -40 +KPX Umacron Agrave -40 +KPX Umacron Amacron -40 +KPX Umacron Aogonek -40 +KPX Umacron Aring -40 +KPX Umacron Atilde -40 +KPX Umacron comma -25 +KPX Umacron period -25 +KPX Uogonek A -40 +KPX Uogonek Aacute -40 +KPX Uogonek Abreve -40 +KPX Uogonek Acircumflex -40 +KPX Uogonek Adieresis -40 +KPX Uogonek Agrave -40 +KPX Uogonek Amacron -40 +KPX Uogonek Aogonek -40 +KPX Uogonek Aring -40 +KPX Uogonek Atilde -40 +KPX Uogonek comma -25 +KPX Uogonek period -25 +KPX Uring A -40 +KPX Uring Aacute -40 +KPX Uring Abreve -40 +KPX Uring Acircumflex -40 +KPX Uring Adieresis -40 +KPX Uring Agrave -40 +KPX Uring Amacron -40 +KPX Uring Aogonek -40 +KPX Uring Aring -40 +KPX Uring Atilde -40 +KPX Uring comma -25 +KPX Uring period -25 +KPX V A -60 +KPX V Aacute -60 +KPX V Abreve -60 +KPX V Acircumflex -60 +KPX V Adieresis -60 +KPX V Agrave -60 +KPX V Amacron -60 +KPX V Aogonek -60 +KPX V Aring -60 +KPX V Atilde -60 +KPX V O -30 +KPX V Oacute -30 +KPX V Ocircumflex -30 +KPX V Odieresis -30 +KPX V Ograve -30 +KPX V Ohungarumlaut -30 +KPX V Omacron -30 +KPX V Oslash -30 +KPX V Otilde -30 +KPX V a -111 +KPX V aacute -111 +KPX V abreve -111 +KPX V acircumflex -111 +KPX V adieresis -111 +KPX V agrave -111 +KPX V amacron -111 +KPX V aogonek -111 +KPX V aring -111 +KPX V atilde -111 +KPX V colon -65 +KPX V comma -129 +KPX V e -111 +KPX V eacute -111 +KPX V ecaron -111 +KPX V ecircumflex -111 +KPX V edieresis -71 +KPX V edotaccent -111 +KPX V egrave -71 +KPX V emacron -71 +KPX V eogonek -111 +KPX V hyphen -55 +KPX V i -74 +KPX V iacute -74 +KPX V icircumflex -34 +KPX V idieresis -34 +KPX V igrave -34 +KPX V imacron -34 +KPX V iogonek -74 +KPX V o -111 +KPX V oacute -111 +KPX V ocircumflex -111 +KPX V odieresis -111 +KPX V ograve -111 +KPX V ohungarumlaut -111 +KPX V omacron -111 +KPX V oslash -111 +KPX V otilde -111 +KPX V period -129 +KPX V semicolon -74 +KPX V u -74 +KPX V uacute -74 +KPX V ucircumflex -74 +KPX V udieresis -74 +KPX V ugrave -74 +KPX V uhungarumlaut -74 +KPX V umacron -74 +KPX V uogonek -74 +KPX V uring -74 +KPX W A -60 +KPX W Aacute -60 +KPX W Abreve -60 +KPX W Acircumflex -60 +KPX W Adieresis -60 +KPX W Agrave -60 +KPX W Amacron -60 +KPX W Aogonek -60 +KPX W Aring -60 +KPX W Atilde -60 +KPX W O -25 +KPX W Oacute -25 +KPX W Ocircumflex -25 +KPX W Odieresis -25 +KPX W Ograve -25 +KPX W Ohungarumlaut -25 +KPX W Omacron -25 +KPX W Oslash -25 +KPX W Otilde -25 +KPX W a -92 +KPX W aacute -92 +KPX W abreve -92 +KPX W acircumflex -92 +KPX W adieresis -92 +KPX W agrave -92 +KPX W amacron -92 +KPX W aogonek -92 +KPX W aring -92 +KPX W atilde -92 +KPX W colon -65 +KPX W comma -92 +KPX W e -92 +KPX W eacute -92 +KPX W ecaron -92 +KPX W ecircumflex -92 +KPX W edieresis -52 +KPX W edotaccent -92 +KPX W egrave -52 +KPX W emacron -52 +KPX W eogonek -92 +KPX W hyphen -37 +KPX W i -55 +KPX W iacute -55 +KPX W iogonek -55 +KPX W o -92 +KPX W oacute -92 +KPX W ocircumflex -92 +KPX W odieresis -92 +KPX W ograve -92 +KPX W ohungarumlaut -92 +KPX W omacron -92 +KPX W oslash -92 +KPX W otilde -92 +KPX W period -92 +KPX W semicolon -65 +KPX W u -55 +KPX W uacute -55 +KPX W ucircumflex -55 +KPX W udieresis -55 +KPX W ugrave -55 +KPX W uhungarumlaut -55 +KPX W umacron -55 +KPX W uogonek -55 +KPX W uring -55 +KPX W y -70 +KPX W yacute -70 +KPX W ydieresis -70 +KPX Y A -50 +KPX Y Aacute -50 +KPX Y Abreve -50 +KPX Y Acircumflex -50 +KPX Y Adieresis -50 +KPX Y Agrave -50 +KPX Y Amacron -50 +KPX Y Aogonek -50 +KPX Y Aring -50 +KPX Y Atilde -50 +KPX Y O -15 +KPX Y Oacute -15 +KPX Y Ocircumflex -15 +KPX Y Odieresis -15 +KPX Y Ograve -15 +KPX Y Ohungarumlaut -15 +KPX Y Omacron -15 +KPX Y Oslash -15 +KPX Y Otilde -15 +KPX Y a -92 +KPX Y aacute -92 +KPX Y abreve -92 +KPX Y acircumflex -92 +KPX Y adieresis -92 +KPX Y agrave -92 +KPX Y amacron -92 +KPX Y aogonek -92 +KPX Y aring -92 +KPX Y atilde -92 +KPX Y colon -65 +KPX Y comma -92 +KPX Y e -92 +KPX Y eacute -92 +KPX Y ecaron -92 +KPX Y ecircumflex -92 +KPX Y edieresis -52 +KPX Y edotaccent -92 +KPX Y egrave -52 +KPX Y emacron -52 +KPX Y eogonek -92 +KPX Y hyphen -74 +KPX Y i -74 +KPX Y iacute -74 +KPX Y icircumflex -34 +KPX Y idieresis -34 +KPX Y igrave -34 +KPX Y imacron -34 +KPX Y iogonek -74 +KPX Y o -92 +KPX Y oacute -92 +KPX Y ocircumflex -92 +KPX Y odieresis -92 +KPX Y ograve -92 +KPX Y ohungarumlaut -92 +KPX Y omacron -92 +KPX Y oslash -92 +KPX Y otilde -92 +KPX Y period -92 +KPX Y semicolon -65 +KPX Y u -92 +KPX Y uacute -92 +KPX Y ucircumflex -92 +KPX Y udieresis -92 +KPX Y ugrave -92 +KPX Y uhungarumlaut -92 +KPX Y umacron -92 +KPX Y uogonek -92 +KPX Y uring -92 +KPX Yacute A -50 +KPX Yacute Aacute -50 +KPX Yacute Abreve -50 +KPX Yacute Acircumflex -50 +KPX Yacute Adieresis -50 +KPX Yacute Agrave -50 +KPX Yacute Amacron -50 +KPX Yacute Aogonek -50 +KPX Yacute Aring -50 +KPX Yacute Atilde -50 +KPX Yacute O -15 +KPX Yacute Oacute -15 +KPX Yacute Ocircumflex -15 +KPX Yacute Odieresis -15 +KPX Yacute Ograve -15 +KPX Yacute Ohungarumlaut -15 +KPX Yacute Omacron -15 +KPX Yacute Oslash -15 +KPX Yacute Otilde -15 +KPX Yacute a -92 +KPX Yacute aacute -92 +KPX Yacute abreve -92 +KPX Yacute acircumflex -92 +KPX Yacute adieresis -92 +KPX Yacute agrave -92 +KPX Yacute amacron -92 +KPX Yacute aogonek -92 +KPX Yacute aring -92 +KPX Yacute atilde -92 +KPX Yacute colon -65 +KPX Yacute comma -92 +KPX Yacute e -92 +KPX Yacute eacute -92 +KPX Yacute ecaron -92 +KPX Yacute ecircumflex -92 +KPX Yacute edieresis -52 +KPX Yacute edotaccent -92 +KPX Yacute egrave -52 +KPX Yacute emacron -52 +KPX Yacute eogonek -92 +KPX Yacute hyphen -74 +KPX Yacute i -74 +KPX Yacute iacute -74 +KPX Yacute icircumflex -34 +KPX Yacute idieresis -34 +KPX Yacute igrave -34 +KPX Yacute imacron -34 +KPX Yacute iogonek -74 +KPX Yacute o -92 +KPX Yacute oacute -92 +KPX Yacute ocircumflex -92 +KPX Yacute odieresis -92 +KPX Yacute ograve -92 +KPX Yacute ohungarumlaut -92 +KPX Yacute omacron -92 +KPX Yacute oslash -92 +KPX Yacute otilde -92 +KPX Yacute period -92 +KPX Yacute semicolon -65 +KPX Yacute u -92 +KPX Yacute uacute -92 +KPX Yacute ucircumflex -92 +KPX Yacute udieresis -92 +KPX Yacute ugrave -92 +KPX Yacute uhungarumlaut -92 +KPX Yacute umacron -92 +KPX Yacute uogonek -92 +KPX Yacute uring -92 +KPX Ydieresis A -50 +KPX Ydieresis Aacute -50 +KPX Ydieresis Abreve -50 +KPX Ydieresis Acircumflex -50 +KPX Ydieresis Adieresis -50 +KPX Ydieresis Agrave -50 +KPX Ydieresis Amacron -50 +KPX Ydieresis Aogonek -50 +KPX Ydieresis Aring -50 +KPX Ydieresis Atilde -50 +KPX Ydieresis O -15 +KPX Ydieresis Oacute -15 +KPX Ydieresis Ocircumflex -15 +KPX Ydieresis Odieresis -15 +KPX Ydieresis Ograve -15 +KPX Ydieresis Ohungarumlaut -15 +KPX Ydieresis Omacron -15 +KPX Ydieresis Oslash -15 +KPX Ydieresis Otilde -15 +KPX Ydieresis a -92 +KPX Ydieresis aacute -92 +KPX Ydieresis abreve -92 +KPX Ydieresis acircumflex -92 +KPX Ydieresis adieresis -92 +KPX Ydieresis agrave -92 +KPX Ydieresis amacron -92 +KPX Ydieresis aogonek -92 +KPX Ydieresis aring -92 +KPX Ydieresis atilde -92 +KPX Ydieresis colon -65 +KPX Ydieresis comma -92 +KPX Ydieresis e -92 +KPX Ydieresis eacute -92 +KPX Ydieresis ecaron -92 +KPX Ydieresis ecircumflex -92 +KPX Ydieresis edieresis -52 +KPX Ydieresis edotaccent -92 +KPX Ydieresis egrave -52 +KPX Ydieresis emacron -52 +KPX Ydieresis eogonek -92 +KPX Ydieresis hyphen -74 +KPX Ydieresis i -74 +KPX Ydieresis iacute -74 +KPX Ydieresis icircumflex -34 +KPX Ydieresis idieresis -34 +KPX Ydieresis igrave -34 +KPX Ydieresis imacron -34 +KPX Ydieresis iogonek -74 +KPX Ydieresis o -92 +KPX Ydieresis oacute -92 +KPX Ydieresis ocircumflex -92 +KPX Ydieresis odieresis -92 +KPX Ydieresis ograve -92 +KPX Ydieresis ohungarumlaut -92 +KPX Ydieresis omacron -92 +KPX Ydieresis oslash -92 +KPX Ydieresis otilde -92 +KPX Ydieresis period -92 +KPX Ydieresis semicolon -65 +KPX Ydieresis u -92 +KPX Ydieresis uacute -92 +KPX Ydieresis ucircumflex -92 +KPX Ydieresis udieresis -92 +KPX Ydieresis ugrave -92 +KPX Ydieresis uhungarumlaut -92 +KPX Ydieresis umacron -92 +KPX Ydieresis uogonek -92 +KPX Ydieresis uring -92 +KPX a g -10 +KPX a gbreve -10 +KPX a gcommaaccent -10 +KPX aacute g -10 +KPX aacute gbreve -10 +KPX aacute gcommaaccent -10 +KPX abreve g -10 +KPX abreve gbreve -10 +KPX abreve gcommaaccent -10 +KPX acircumflex g -10 +KPX acircumflex gbreve -10 +KPX acircumflex gcommaaccent -10 +KPX adieresis g -10 +KPX adieresis gbreve -10 +KPX adieresis gcommaaccent -10 +KPX agrave g -10 +KPX agrave gbreve -10 +KPX agrave gcommaaccent -10 +KPX amacron g -10 +KPX amacron gbreve -10 +KPX amacron gcommaaccent -10 +KPX aogonek g -10 +KPX aogonek gbreve -10 +KPX aogonek gcommaaccent -10 +KPX aring g -10 +KPX aring gbreve -10 +KPX aring gcommaaccent -10 +KPX atilde g -10 +KPX atilde gbreve -10 +KPX atilde gcommaaccent -10 +KPX b period -40 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX c h -15 +KPX c k -20 +KPX c kcommaaccent -20 +KPX cacute h -15 +KPX cacute k -20 +KPX cacute kcommaaccent -20 +KPX ccaron h -15 +KPX ccaron k -20 +KPX ccaron kcommaaccent -20 +KPX ccedilla h -15 +KPX ccedilla k -20 +KPX ccedilla kcommaaccent -20 +KPX comma quotedblright -140 +KPX comma quoteright -140 +KPX e comma -10 +KPX e g -40 +KPX e gbreve -40 +KPX e gcommaaccent -40 +KPX e period -15 +KPX e v -15 +KPX e w -15 +KPX e x -20 +KPX e y -30 +KPX e yacute -30 +KPX e ydieresis -30 +KPX eacute comma -10 +KPX eacute g -40 +KPX eacute gbreve -40 +KPX eacute gcommaaccent -40 +KPX eacute period -15 +KPX eacute v -15 +KPX eacute w -15 +KPX eacute x -20 +KPX eacute y -30 +KPX eacute yacute -30 +KPX eacute ydieresis -30 +KPX ecaron comma -10 +KPX ecaron g -40 +KPX ecaron gbreve -40 +KPX ecaron gcommaaccent -40 +KPX ecaron period -15 +KPX ecaron v -15 +KPX ecaron w -15 +KPX ecaron x -20 +KPX ecaron y -30 +KPX ecaron yacute -30 +KPX ecaron ydieresis -30 +KPX ecircumflex comma -10 +KPX ecircumflex g -40 +KPX ecircumflex gbreve -40 +KPX ecircumflex gcommaaccent -40 +KPX ecircumflex period -15 +KPX ecircumflex v -15 +KPX ecircumflex w -15 +KPX ecircumflex x -20 +KPX ecircumflex y -30 +KPX ecircumflex yacute -30 +KPX ecircumflex ydieresis -30 +KPX edieresis comma -10 +KPX edieresis g -40 +KPX edieresis gbreve -40 +KPX edieresis gcommaaccent -40 +KPX edieresis period -15 +KPX edieresis v -15 +KPX edieresis w -15 +KPX edieresis x -20 +KPX edieresis y -30 +KPX edieresis yacute -30 +KPX edieresis ydieresis -30 +KPX edotaccent comma -10 +KPX edotaccent g -40 +KPX edotaccent gbreve -40 +KPX edotaccent gcommaaccent -40 +KPX edotaccent period -15 +KPX edotaccent v -15 +KPX edotaccent w -15 +KPX edotaccent x -20 +KPX edotaccent y -30 +KPX edotaccent yacute -30 +KPX edotaccent ydieresis -30 +KPX egrave comma -10 +KPX egrave g -40 +KPX egrave gbreve -40 +KPX egrave gcommaaccent -40 +KPX egrave period -15 +KPX egrave v -15 +KPX egrave w -15 +KPX egrave x -20 +KPX egrave y -30 +KPX egrave yacute -30 +KPX egrave ydieresis -30 +KPX emacron comma -10 +KPX emacron g -40 +KPX emacron gbreve -40 +KPX emacron gcommaaccent -40 +KPX emacron period -15 +KPX emacron v -15 +KPX emacron w -15 +KPX emacron x -20 +KPX emacron y -30 +KPX emacron yacute -30 +KPX emacron ydieresis -30 +KPX eogonek comma -10 +KPX eogonek g -40 +KPX eogonek gbreve -40 +KPX eogonek gcommaaccent -40 +KPX eogonek period -15 +KPX eogonek v -15 +KPX eogonek w -15 +KPX eogonek x -20 +KPX eogonek y -30 +KPX eogonek yacute -30 +KPX eogonek ydieresis -30 +KPX f comma -10 +KPX f dotlessi -60 +KPX f f -18 +KPX f i -20 +KPX f iogonek -20 +KPX f period -15 +KPX f quoteright 92 +KPX g comma -10 +KPX g e -10 +KPX g eacute -10 +KPX g ecaron -10 +KPX g ecircumflex -10 +KPX g edieresis -10 +KPX g edotaccent -10 +KPX g egrave -10 +KPX g emacron -10 +KPX g eogonek -10 +KPX g g -10 +KPX g gbreve -10 +KPX g gcommaaccent -10 +KPX g period -15 +KPX gbreve comma -10 +KPX gbreve e -10 +KPX gbreve eacute -10 +KPX gbreve ecaron -10 +KPX gbreve ecircumflex -10 +KPX gbreve edieresis -10 +KPX gbreve edotaccent -10 +KPX gbreve egrave -10 +KPX gbreve emacron -10 +KPX gbreve eogonek -10 +KPX gbreve g -10 +KPX gbreve gbreve -10 +KPX gbreve gcommaaccent -10 +KPX gbreve period -15 +KPX gcommaaccent comma -10 +KPX gcommaaccent e -10 +KPX gcommaaccent eacute -10 +KPX gcommaaccent ecaron -10 +KPX gcommaaccent ecircumflex -10 +KPX gcommaaccent edieresis -10 +KPX gcommaaccent edotaccent -10 +KPX gcommaaccent egrave -10 +KPX gcommaaccent emacron -10 +KPX gcommaaccent eogonek -10 +KPX gcommaaccent g -10 +KPX gcommaaccent gbreve -10 +KPX gcommaaccent gcommaaccent -10 +KPX gcommaaccent period -15 +KPX k e -10 +KPX k eacute -10 +KPX k ecaron -10 +KPX k ecircumflex -10 +KPX k edieresis -10 +KPX k edotaccent -10 +KPX k egrave -10 +KPX k emacron -10 +KPX k eogonek -10 +KPX k o -10 +KPX k oacute -10 +KPX k ocircumflex -10 +KPX k odieresis -10 +KPX k ograve -10 +KPX k ohungarumlaut -10 +KPX k omacron -10 +KPX k oslash -10 +KPX k otilde -10 +KPX k y -10 +KPX k yacute -10 +KPX k ydieresis -10 +KPX kcommaaccent e -10 +KPX kcommaaccent eacute -10 +KPX kcommaaccent ecaron -10 +KPX kcommaaccent ecircumflex -10 +KPX kcommaaccent edieresis -10 +KPX kcommaaccent edotaccent -10 +KPX kcommaaccent egrave -10 +KPX kcommaaccent emacron -10 +KPX kcommaaccent eogonek -10 +KPX kcommaaccent o -10 +KPX kcommaaccent oacute -10 +KPX kcommaaccent ocircumflex -10 +KPX kcommaaccent odieresis -10 +KPX kcommaaccent ograve -10 +KPX kcommaaccent ohungarumlaut -10 +KPX kcommaaccent omacron -10 +KPX kcommaaccent oslash -10 +KPX kcommaaccent otilde -10 +KPX kcommaaccent y -10 +KPX kcommaaccent yacute -10 +KPX kcommaaccent ydieresis -10 +KPX n v -40 +KPX nacute v -40 +KPX ncaron v -40 +KPX ncommaaccent v -40 +KPX ntilde v -40 +KPX o g -10 +KPX o gbreve -10 +KPX o gcommaaccent -10 +KPX o v -10 +KPX oacute g -10 +KPX oacute gbreve -10 +KPX oacute gcommaaccent -10 +KPX oacute v -10 +KPX ocircumflex g -10 +KPX ocircumflex gbreve -10 +KPX ocircumflex gcommaaccent -10 +KPX ocircumflex v -10 +KPX odieresis g -10 +KPX odieresis gbreve -10 +KPX odieresis gcommaaccent -10 +KPX odieresis v -10 +KPX ograve g -10 +KPX ograve gbreve -10 +KPX ograve gcommaaccent -10 +KPX ograve v -10 +KPX ohungarumlaut g -10 +KPX ohungarumlaut gbreve -10 +KPX ohungarumlaut gcommaaccent -10 +KPX ohungarumlaut v -10 +KPX omacron g -10 +KPX omacron gbreve -10 +KPX omacron gcommaaccent -10 +KPX omacron v -10 +KPX oslash g -10 +KPX oslash gbreve -10 +KPX oslash gcommaaccent -10 +KPX oslash v -10 +KPX otilde g -10 +KPX otilde gbreve -10 +KPX otilde gcommaaccent -10 +KPX otilde v -10 +KPX period quotedblright -140 +KPX period quoteright -140 +KPX quoteleft quoteleft -111 +KPX quoteright d -25 +KPX quoteright dcroat -25 +KPX quoteright quoteright -111 +KPX quoteright r -25 +KPX quoteright racute -25 +KPX quoteright rcaron -25 +KPX quoteright rcommaaccent -25 +KPX quoteright s -40 +KPX quoteright sacute -40 +KPX quoteright scaron -40 +KPX quoteright scedilla -40 +KPX quoteright scommaaccent -40 +KPX quoteright space -111 +KPX quoteright t -30 +KPX quoteright tcommaaccent -30 +KPX quoteright v -10 +KPX r a -15 +KPX r aacute -15 +KPX r abreve -15 +KPX r acircumflex -15 +KPX r adieresis -15 +KPX r agrave -15 +KPX r amacron -15 +KPX r aogonek -15 +KPX r aring -15 +KPX r atilde -15 +KPX r c -37 +KPX r cacute -37 +KPX r ccaron -37 +KPX r ccedilla -37 +KPX r comma -111 +KPX r d -37 +KPX r dcroat -37 +KPX r e -37 +KPX r eacute -37 +KPX r ecaron -37 +KPX r ecircumflex -37 +KPX r edieresis -37 +KPX r edotaccent -37 +KPX r egrave -37 +KPX r emacron -37 +KPX r eogonek -37 +KPX r g -37 +KPX r gbreve -37 +KPX r gcommaaccent -37 +KPX r hyphen -20 +KPX r o -45 +KPX r oacute -45 +KPX r ocircumflex -45 +KPX r odieresis -45 +KPX r ograve -45 +KPX r ohungarumlaut -45 +KPX r omacron -45 +KPX r oslash -45 +KPX r otilde -45 +KPX r period -111 +KPX r q -37 +KPX r s -10 +KPX r sacute -10 +KPX r scaron -10 +KPX r scedilla -10 +KPX r scommaaccent -10 +KPX racute a -15 +KPX racute aacute -15 +KPX racute abreve -15 +KPX racute acircumflex -15 +KPX racute adieresis -15 +KPX racute agrave -15 +KPX racute amacron -15 +KPX racute aogonek -15 +KPX racute aring -15 +KPX racute atilde -15 +KPX racute c -37 +KPX racute cacute -37 +KPX racute ccaron -37 +KPX racute ccedilla -37 +KPX racute comma -111 +KPX racute d -37 +KPX racute dcroat -37 +KPX racute e -37 +KPX racute eacute -37 +KPX racute ecaron -37 +KPX racute ecircumflex -37 +KPX racute edieresis -37 +KPX racute edotaccent -37 +KPX racute egrave -37 +KPX racute emacron -37 +KPX racute eogonek -37 +KPX racute g -37 +KPX racute gbreve -37 +KPX racute gcommaaccent -37 +KPX racute hyphen -20 +KPX racute o -45 +KPX racute oacute -45 +KPX racute ocircumflex -45 +KPX racute odieresis -45 +KPX racute ograve -45 +KPX racute ohungarumlaut -45 +KPX racute omacron -45 +KPX racute oslash -45 +KPX racute otilde -45 +KPX racute period -111 +KPX racute q -37 +KPX racute s -10 +KPX racute sacute -10 +KPX racute scaron -10 +KPX racute scedilla -10 +KPX racute scommaaccent -10 +KPX rcaron a -15 +KPX rcaron aacute -15 +KPX rcaron abreve -15 +KPX rcaron acircumflex -15 +KPX rcaron adieresis -15 +KPX rcaron agrave -15 +KPX rcaron amacron -15 +KPX rcaron aogonek -15 +KPX rcaron aring -15 +KPX rcaron atilde -15 +KPX rcaron c -37 +KPX rcaron cacute -37 +KPX rcaron ccaron -37 +KPX rcaron ccedilla -37 +KPX rcaron comma -111 +KPX rcaron d -37 +KPX rcaron dcroat -37 +KPX rcaron e -37 +KPX rcaron eacute -37 +KPX rcaron ecaron -37 +KPX rcaron ecircumflex -37 +KPX rcaron edieresis -37 +KPX rcaron edotaccent -37 +KPX rcaron egrave -37 +KPX rcaron emacron -37 +KPX rcaron eogonek -37 +KPX rcaron g -37 +KPX rcaron gbreve -37 +KPX rcaron gcommaaccent -37 +KPX rcaron hyphen -20 +KPX rcaron o -45 +KPX rcaron oacute -45 +KPX rcaron ocircumflex -45 +KPX rcaron odieresis -45 +KPX rcaron ograve -45 +KPX rcaron ohungarumlaut -45 +KPX rcaron omacron -45 +KPX rcaron oslash -45 +KPX rcaron otilde -45 +KPX rcaron period -111 +KPX rcaron q -37 +KPX rcaron s -10 +KPX rcaron sacute -10 +KPX rcaron scaron -10 +KPX rcaron scedilla -10 +KPX rcaron scommaaccent -10 +KPX rcommaaccent a -15 +KPX rcommaaccent aacute -15 +KPX rcommaaccent abreve -15 +KPX rcommaaccent acircumflex -15 +KPX rcommaaccent adieresis -15 +KPX rcommaaccent agrave -15 +KPX rcommaaccent amacron -15 +KPX rcommaaccent aogonek -15 +KPX rcommaaccent aring -15 +KPX rcommaaccent atilde -15 +KPX rcommaaccent c -37 +KPX rcommaaccent cacute -37 +KPX rcommaaccent ccaron -37 +KPX rcommaaccent ccedilla -37 +KPX rcommaaccent comma -111 +KPX rcommaaccent d -37 +KPX rcommaaccent dcroat -37 +KPX rcommaaccent e -37 +KPX rcommaaccent eacute -37 +KPX rcommaaccent ecaron -37 +KPX rcommaaccent ecircumflex -37 +KPX rcommaaccent edieresis -37 +KPX rcommaaccent edotaccent -37 +KPX rcommaaccent egrave -37 +KPX rcommaaccent emacron -37 +KPX rcommaaccent eogonek -37 +KPX rcommaaccent g -37 +KPX rcommaaccent gbreve -37 +KPX rcommaaccent gcommaaccent -37 +KPX rcommaaccent hyphen -20 +KPX rcommaaccent o -45 +KPX rcommaaccent oacute -45 +KPX rcommaaccent ocircumflex -45 +KPX rcommaaccent odieresis -45 +KPX rcommaaccent ograve -45 +KPX rcommaaccent ohungarumlaut -45 +KPX rcommaaccent omacron -45 +KPX rcommaaccent oslash -45 +KPX rcommaaccent otilde -45 +KPX rcommaaccent period -111 +KPX rcommaaccent q -37 +KPX rcommaaccent s -10 +KPX rcommaaccent sacute -10 +KPX rcommaaccent scaron -10 +KPX rcommaaccent scedilla -10 +KPX rcommaaccent scommaaccent -10 +KPX space A -18 +KPX space Aacute -18 +KPX space Abreve -18 +KPX space Acircumflex -18 +KPX space Adieresis -18 +KPX space Agrave -18 +KPX space Amacron -18 +KPX space Aogonek -18 +KPX space Aring -18 +KPX space Atilde -18 +KPX space T -18 +KPX space Tcaron -18 +KPX space Tcommaaccent -18 +KPX space V -35 +KPX space W -40 +KPX space Y -75 +KPX space Yacute -75 +KPX space Ydieresis -75 +KPX v comma -74 +KPX v period -74 +KPX w comma -74 +KPX w period -74 +KPX y comma -55 +KPX y period -55 +KPX yacute comma -55 +KPX yacute period -55 +KPX ydieresis comma -55 +KPX ydieresis period -55 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/Times-Roman.afm b/iTechSharp/iTextSharp/text/pdf/fonts/Times-Roman.afm new file mode 100644 index 0000000..354775b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/Times-Roman.afm @@ -0,0 +1,2419 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 12:49:17 1997 +Comment UniqueID 43068 +Comment VMusage 43909 54934 +FontName Times-Roman +FullName Times Roman +FamilyName Times +Weight Roman +ItalicAngle 0 +IsFixedPitch false +CharacterSet ExtendedRoman +FontBBox -168 -218 1000 898 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries. +EncodingScheme AdobeStandardEncoding +CapHeight 662 +XHeight 450 +Ascender 683 +Descender -217 +StdHW 28 +StdVW 84 +StartCharMetrics 315 +C 32 ; WX 250 ; N space ; B 0 0 0 0 ; +C 33 ; WX 333 ; N exclam ; B 130 -9 238 676 ; +C 34 ; WX 408 ; N quotedbl ; B 77 431 331 676 ; +C 35 ; WX 500 ; N numbersign ; B 5 0 496 662 ; +C 36 ; WX 500 ; N dollar ; B 44 -87 457 727 ; +C 37 ; WX 833 ; N percent ; B 61 -13 772 676 ; +C 38 ; WX 778 ; N ampersand ; B 42 -13 750 676 ; +C 39 ; WX 333 ; N quoteright ; B 79 433 218 676 ; +C 40 ; WX 333 ; N parenleft ; B 48 -177 304 676 ; +C 41 ; WX 333 ; N parenright ; B 29 -177 285 676 ; +C 42 ; WX 500 ; N asterisk ; B 69 265 432 676 ; +C 43 ; WX 564 ; N plus ; B 30 0 534 506 ; +C 44 ; WX 250 ; N comma ; B 56 -141 195 102 ; +C 45 ; WX 333 ; N hyphen ; B 39 194 285 257 ; +C 46 ; WX 250 ; N period ; B 70 -11 181 100 ; +C 47 ; WX 278 ; N slash ; B -9 -14 287 676 ; +C 48 ; WX 500 ; N zero ; B 24 -14 476 676 ; +C 49 ; WX 500 ; N one ; B 111 0 394 676 ; +C 50 ; WX 500 ; N two ; B 30 0 475 676 ; +C 51 ; WX 500 ; N three ; B 43 -14 431 676 ; +C 52 ; WX 500 ; N four ; B 12 0 472 676 ; +C 53 ; WX 500 ; N five ; B 32 -14 438 688 ; +C 54 ; WX 500 ; N six ; B 34 -14 468 684 ; +C 55 ; WX 500 ; N seven ; B 20 -8 449 662 ; +C 56 ; WX 500 ; N eight ; B 56 -14 445 676 ; +C 57 ; WX 500 ; N nine ; B 30 -22 459 676 ; +C 58 ; WX 278 ; N colon ; B 81 -11 192 459 ; +C 59 ; WX 278 ; N semicolon ; B 80 -141 219 459 ; +C 60 ; WX 564 ; N less ; B 28 -8 536 514 ; +C 61 ; WX 564 ; N equal ; B 30 120 534 386 ; +C 62 ; WX 564 ; N greater ; B 28 -8 536 514 ; +C 63 ; WX 444 ; N question ; B 68 -8 414 676 ; +C 64 ; WX 921 ; N at ; B 116 -14 809 676 ; +C 65 ; WX 722 ; N A ; B 15 0 706 674 ; +C 66 ; WX 667 ; N B ; B 17 0 593 662 ; +C 67 ; WX 667 ; N C ; B 28 -14 633 676 ; +C 68 ; WX 722 ; N D ; B 16 0 685 662 ; +C 69 ; WX 611 ; N E ; B 12 0 597 662 ; +C 70 ; WX 556 ; N F ; B 12 0 546 662 ; +C 71 ; WX 722 ; N G ; B 32 -14 709 676 ; +C 72 ; WX 722 ; N H ; B 19 0 702 662 ; +C 73 ; WX 333 ; N I ; B 18 0 315 662 ; +C 74 ; WX 389 ; N J ; B 10 -14 370 662 ; +C 75 ; WX 722 ; N K ; B 34 0 723 662 ; +C 76 ; WX 611 ; N L ; B 12 0 598 662 ; +C 77 ; WX 889 ; N M ; B 12 0 863 662 ; +C 78 ; WX 722 ; N N ; B 12 -11 707 662 ; +C 79 ; WX 722 ; N O ; B 34 -14 688 676 ; +C 80 ; WX 556 ; N P ; B 16 0 542 662 ; +C 81 ; WX 722 ; N Q ; B 34 -178 701 676 ; +C 82 ; WX 667 ; N R ; B 17 0 659 662 ; +C 83 ; WX 556 ; N S ; B 42 -14 491 676 ; +C 84 ; WX 611 ; N T ; B 17 0 593 662 ; +C 85 ; WX 722 ; N U ; B 14 -14 705 662 ; +C 86 ; WX 722 ; N V ; B 16 -11 697 662 ; +C 87 ; WX 944 ; N W ; B 5 -11 932 662 ; +C 88 ; WX 722 ; N X ; B 10 0 704 662 ; +C 89 ; WX 722 ; N Y ; B 22 0 703 662 ; +C 90 ; WX 611 ; N Z ; B 9 0 597 662 ; +C 91 ; WX 333 ; N bracketleft ; B 88 -156 299 662 ; +C 92 ; WX 278 ; N backslash ; B -9 -14 287 676 ; +C 93 ; WX 333 ; N bracketright ; B 34 -156 245 662 ; +C 94 ; WX 469 ; N asciicircum ; B 24 297 446 662 ; +C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ; +C 96 ; WX 333 ; N quoteleft ; B 115 433 254 676 ; +C 97 ; WX 444 ; N a ; B 37 -10 442 460 ; +C 98 ; WX 500 ; N b ; B 3 -10 468 683 ; +C 99 ; WX 444 ; N c ; B 25 -10 412 460 ; +C 100 ; WX 500 ; N d ; B 27 -10 491 683 ; +C 101 ; WX 444 ; N e ; B 25 -10 424 460 ; +C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L i fi ; L l fl ; +C 103 ; WX 500 ; N g ; B 28 -218 470 460 ; +C 104 ; WX 500 ; N h ; B 9 0 487 683 ; +C 105 ; WX 278 ; N i ; B 16 0 253 683 ; +C 106 ; WX 278 ; N j ; B -70 -218 194 683 ; +C 107 ; WX 500 ; N k ; B 7 0 505 683 ; +C 108 ; WX 278 ; N l ; B 19 0 257 683 ; +C 109 ; WX 778 ; N m ; B 16 0 775 460 ; +C 110 ; WX 500 ; N n ; B 16 0 485 460 ; +C 111 ; WX 500 ; N o ; B 29 -10 470 460 ; +C 112 ; WX 500 ; N p ; B 5 -217 470 460 ; +C 113 ; WX 500 ; N q ; B 24 -217 488 460 ; +C 114 ; WX 333 ; N r ; B 5 0 335 460 ; +C 115 ; WX 389 ; N s ; B 51 -10 348 460 ; +C 116 ; WX 278 ; N t ; B 13 -10 279 579 ; +C 117 ; WX 500 ; N u ; B 9 -10 479 450 ; +C 118 ; WX 500 ; N v ; B 19 -14 477 450 ; +C 119 ; WX 722 ; N w ; B 21 -14 694 450 ; +C 120 ; WX 500 ; N x ; B 17 0 479 450 ; +C 121 ; WX 500 ; N y ; B 14 -218 475 450 ; +C 122 ; WX 444 ; N z ; B 27 0 418 450 ; +C 123 ; WX 480 ; N braceleft ; B 100 -181 350 680 ; +C 124 ; WX 200 ; N bar ; B 67 -218 133 782 ; +C 125 ; WX 480 ; N braceright ; B 130 -181 380 680 ; +C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ; +C 161 ; WX 333 ; N exclamdown ; B 97 -218 205 467 ; +C 162 ; WX 500 ; N cent ; B 53 -138 448 579 ; +C 163 ; WX 500 ; N sterling ; B 12 -8 490 676 ; +C 164 ; WX 167 ; N fraction ; B -168 -14 331 676 ; +C 165 ; WX 500 ; N yen ; B -53 0 512 662 ; +C 166 ; WX 500 ; N florin ; B 7 -189 490 676 ; +C 167 ; WX 500 ; N section ; B 70 -148 426 676 ; +C 168 ; WX 500 ; N currency ; B -22 58 522 602 ; +C 169 ; WX 180 ; N quotesingle ; B 48 431 133 676 ; +C 170 ; WX 444 ; N quotedblleft ; B 43 433 414 676 ; +C 171 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ; +C 172 ; WX 333 ; N guilsinglleft ; B 63 33 285 416 ; +C 173 ; WX 333 ; N guilsinglright ; B 48 33 270 416 ; +C 174 ; WX 556 ; N fi ; B 31 0 521 683 ; +C 175 ; WX 556 ; N fl ; B 32 0 521 683 ; +C 177 ; WX 500 ; N endash ; B 0 201 500 250 ; +C 178 ; WX 500 ; N dagger ; B 59 -149 442 676 ; +C 179 ; WX 500 ; N daggerdbl ; B 58 -153 442 676 ; +C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ; +C 182 ; WX 453 ; N paragraph ; B -22 -154 450 662 ; +C 183 ; WX 350 ; N bullet ; B 40 196 310 466 ; +C 184 ; WX 333 ; N quotesinglbase ; B 79 -141 218 102 ; +C 185 ; WX 444 ; N quotedblbase ; B 45 -141 416 102 ; +C 186 ; WX 444 ; N quotedblright ; B 30 433 401 676 ; +C 187 ; WX 500 ; N guillemotright ; B 44 33 458 416 ; +C 188 ; WX 1000 ; N ellipsis ; B 111 -11 888 100 ; +C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 706 ; +C 191 ; WX 444 ; N questiondown ; B 30 -218 376 466 ; +C 193 ; WX 333 ; N grave ; B 19 507 242 678 ; +C 194 ; WX 333 ; N acute ; B 93 507 317 678 ; +C 195 ; WX 333 ; N circumflex ; B 11 507 322 674 ; +C 196 ; WX 333 ; N tilde ; B 1 532 331 638 ; +C 197 ; WX 333 ; N macron ; B 11 547 322 601 ; +C 198 ; WX 333 ; N breve ; B 26 507 307 664 ; +C 199 ; WX 333 ; N dotaccent ; B 118 581 216 681 ; +C 200 ; WX 333 ; N dieresis ; B 18 581 315 681 ; +C 202 ; WX 333 ; N ring ; B 67 512 266 711 ; +C 203 ; WX 333 ; N cedilla ; B 52 -215 261 0 ; +C 205 ; WX 333 ; N hungarumlaut ; B -3 507 377 678 ; +C 206 ; WX 333 ; N ogonek ; B 62 -165 243 0 ; +C 207 ; WX 333 ; N caron ; B 11 507 322 674 ; +C 208 ; WX 1000 ; N emdash ; B 0 201 1000 250 ; +C 225 ; WX 889 ; N AE ; B 0 0 863 662 ; +C 227 ; WX 276 ; N ordfeminine ; B 4 394 270 676 ; +C 232 ; WX 611 ; N Lslash ; B 12 0 598 662 ; +C 233 ; WX 722 ; N Oslash ; B 34 -80 688 734 ; +C 234 ; WX 889 ; N OE ; B 30 -6 885 668 ; +C 235 ; WX 310 ; N ordmasculine ; B 6 394 304 676 ; +C 241 ; WX 667 ; N ae ; B 38 -10 632 460 ; +C 245 ; WX 278 ; N dotlessi ; B 16 0 253 460 ; +C 248 ; WX 278 ; N lslash ; B 19 0 259 683 ; +C 249 ; WX 500 ; N oslash ; B 29 -112 470 551 ; +C 250 ; WX 722 ; N oe ; B 30 -10 690 460 ; +C 251 ; WX 500 ; N germandbls ; B 12 -9 468 683 ; +C -1 ; WX 333 ; N Idieresis ; B 18 0 315 835 ; +C -1 ; WX 444 ; N eacute ; B 25 -10 424 678 ; +C -1 ; WX 444 ; N abreve ; B 37 -10 442 664 ; +C -1 ; WX 500 ; N uhungarumlaut ; B 9 -10 501 678 ; +C -1 ; WX 444 ; N ecaron ; B 25 -10 424 674 ; +C -1 ; WX 722 ; N Ydieresis ; B 22 0 703 835 ; +C -1 ; WX 564 ; N divide ; B 30 -10 534 516 ; +C -1 ; WX 722 ; N Yacute ; B 22 0 703 890 ; +C -1 ; WX 722 ; N Acircumflex ; B 15 0 706 886 ; +C -1 ; WX 444 ; N aacute ; B 37 -10 442 678 ; +C -1 ; WX 722 ; N Ucircumflex ; B 14 -14 705 886 ; +C -1 ; WX 500 ; N yacute ; B 14 -218 475 678 ; +C -1 ; WX 389 ; N scommaaccent ; B 51 -218 348 460 ; +C -1 ; WX 444 ; N ecircumflex ; B 25 -10 424 674 ; +C -1 ; WX 722 ; N Uring ; B 14 -14 705 898 ; +C -1 ; WX 722 ; N Udieresis ; B 14 -14 705 835 ; +C -1 ; WX 444 ; N aogonek ; B 37 -165 469 460 ; +C -1 ; WX 722 ; N Uacute ; B 14 -14 705 890 ; +C -1 ; WX 500 ; N uogonek ; B 9 -155 487 450 ; +C -1 ; WX 611 ; N Edieresis ; B 12 0 597 835 ; +C -1 ; WX 722 ; N Dcroat ; B 16 0 685 662 ; +C -1 ; WX 250 ; N commaaccent ; B 59 -218 184 -50 ; +C -1 ; WX 760 ; N copyright ; B 38 -14 722 676 ; +C -1 ; WX 611 ; N Emacron ; B 12 0 597 813 ; +C -1 ; WX 444 ; N ccaron ; B 25 -10 412 674 ; +C -1 ; WX 444 ; N aring ; B 37 -10 442 711 ; +C -1 ; WX 722 ; N Ncommaaccent ; B 12 -198 707 662 ; +C -1 ; WX 278 ; N lacute ; B 19 0 290 890 ; +C -1 ; WX 444 ; N agrave ; B 37 -10 442 678 ; +C -1 ; WX 611 ; N Tcommaaccent ; B 17 -218 593 662 ; +C -1 ; WX 667 ; N Cacute ; B 28 -14 633 890 ; +C -1 ; WX 444 ; N atilde ; B 37 -10 442 638 ; +C -1 ; WX 611 ; N Edotaccent ; B 12 0 597 835 ; +C -1 ; WX 389 ; N scaron ; B 39 -10 350 674 ; +C -1 ; WX 389 ; N scedilla ; B 51 -215 348 460 ; +C -1 ; WX 278 ; N iacute ; B 16 0 290 678 ; +C -1 ; WX 471 ; N lozenge ; B 13 0 459 724 ; +C -1 ; WX 667 ; N Rcaron ; B 17 0 659 886 ; +C -1 ; WX 722 ; N Gcommaaccent ; B 32 -218 709 676 ; +C -1 ; WX 500 ; N ucircumflex ; B 9 -10 479 674 ; +C -1 ; WX 444 ; N acircumflex ; B 37 -10 442 674 ; +C -1 ; WX 722 ; N Amacron ; B 15 0 706 813 ; +C -1 ; WX 333 ; N rcaron ; B 5 0 335 674 ; +C -1 ; WX 444 ; N ccedilla ; B 25 -215 412 460 ; +C -1 ; WX 611 ; N Zdotaccent ; B 9 0 597 835 ; +C -1 ; WX 556 ; N Thorn ; B 16 0 542 662 ; +C -1 ; WX 722 ; N Omacron ; B 34 -14 688 813 ; +C -1 ; WX 667 ; N Racute ; B 17 0 659 890 ; +C -1 ; WX 556 ; N Sacute ; B 42 -14 491 890 ; +C -1 ; WX 588 ; N dcaron ; B 27 -10 589 695 ; +C -1 ; WX 722 ; N Umacron ; B 14 -14 705 813 ; +C -1 ; WX 500 ; N uring ; B 9 -10 479 711 ; +C -1 ; WX 300 ; N threebaseior ; B 15 262 291 676 ; +C -1 ; WX 722 ; N Ograve ; B 34 -14 688 890 ; +C -1 ; WX 722 ; N Agrave ; B 15 0 706 890 ; +C -1 ; WX 722 ; N Abreve ; B 15 0 706 876 ; +C -1 ; WX 564 ; N multiply ; B 38 8 527 497 ; +C -1 ; WX 500 ; N uacute ; B 9 -10 479 678 ; +C -1 ; WX 611 ; N Tcaron ; B 17 0 593 886 ; +C -1 ; WX 476 ; N partialdiff ; B 17 -38 459 710 ; +C -1 ; WX 500 ; N ydieresis ; B 14 -218 475 623 ; +C -1 ; WX 722 ; N Nacute ; B 12 -11 707 890 ; +C -1 ; WX 278 ; N icircumflex ; B -16 0 295 674 ; +C -1 ; WX 611 ; N Ecircumflex ; B 12 0 597 886 ; +C -1 ; WX 444 ; N adieresis ; B 37 -10 442 623 ; +C -1 ; WX 444 ; N edieresis ; B 25 -10 424 623 ; +C -1 ; WX 444 ; N cacute ; B 25 -10 413 678 ; +C -1 ; WX 500 ; N nacute ; B 16 0 485 678 ; +C -1 ; WX 500 ; N umacron ; B 9 -10 479 601 ; +C -1 ; WX 722 ; N Ncaron ; B 12 -11 707 886 ; +C -1 ; WX 333 ; N Iacute ; B 18 0 317 890 ; +C -1 ; WX 564 ; N plusminus ; B 30 0 534 506 ; +C -1 ; WX 200 ; N brokenbar ; B 67 -143 133 707 ; +C -1 ; WX 760 ; N registered ; B 38 -14 722 676 ; +C -1 ; WX 722 ; N Gbreve ; B 32 -14 709 876 ; +C -1 ; WX 333 ; N Idotaccent ; B 18 0 315 835 ; +C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ; +C -1 ; WX 611 ; N Egrave ; B 12 0 597 890 ; +C -1 ; WX 333 ; N racute ; B 5 0 335 678 ; +C -1 ; WX 500 ; N omacron ; B 29 -10 470 601 ; +C -1 ; WX 611 ; N Zacute ; B 9 0 597 890 ; +C -1 ; WX 611 ; N Zcaron ; B 9 0 597 886 ; +C -1 ; WX 549 ; N greaterequal ; B 26 0 523 666 ; +C -1 ; WX 722 ; N Eth ; B 16 0 685 662 ; +C -1 ; WX 667 ; N Ccedilla ; B 28 -215 633 676 ; +C -1 ; WX 278 ; N lcommaaccent ; B 19 -218 257 683 ; +C -1 ; WX 326 ; N tcaron ; B 13 -10 318 722 ; +C -1 ; WX 444 ; N eogonek ; B 25 -165 424 460 ; +C -1 ; WX 722 ; N Uogonek ; B 14 -165 705 662 ; +C -1 ; WX 722 ; N Aacute ; B 15 0 706 890 ; +C -1 ; WX 722 ; N Adieresis ; B 15 0 706 835 ; +C -1 ; WX 444 ; N egrave ; B 25 -10 424 678 ; +C -1 ; WX 444 ; N zacute ; B 27 0 418 678 ; +C -1 ; WX 278 ; N iogonek ; B 16 -165 265 683 ; +C -1 ; WX 722 ; N Oacute ; B 34 -14 688 890 ; +C -1 ; WX 500 ; N oacute ; B 29 -10 470 678 ; +C -1 ; WX 444 ; N amacron ; B 37 -10 442 601 ; +C -1 ; WX 389 ; N sacute ; B 51 -10 348 678 ; +C -1 ; WX 278 ; N idieresis ; B -9 0 288 623 ; +C -1 ; WX 722 ; N Ocircumflex ; B 34 -14 688 886 ; +C -1 ; WX 722 ; N Ugrave ; B 14 -14 705 890 ; +C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; +C -1 ; WX 500 ; N thorn ; B 5 -217 470 683 ; +C -1 ; WX 300 ; N twobaseior ; B 1 270 296 676 ; +C -1 ; WX 722 ; N Odieresis ; B 34 -14 688 835 ; +C -1 ; WX 500 ; N mu ; B 36 -218 512 450 ; +C -1 ; WX 278 ; N igrave ; B -8 0 253 678 ; +C -1 ; WX 500 ; N ohungarumlaut ; B 29 -10 491 678 ; +C -1 ; WX 611 ; N Eogonek ; B 12 -165 597 662 ; +C -1 ; WX 500 ; N dcroat ; B 27 -10 500 683 ; +C -1 ; WX 750 ; N threequarters ; B 15 -14 718 676 ; +C -1 ; WX 556 ; N Scedilla ; B 42 -215 491 676 ; +C -1 ; WX 344 ; N lcaron ; B 19 0 347 695 ; +C -1 ; WX 722 ; N Kcommaaccent ; B 34 -198 723 662 ; +C -1 ; WX 611 ; N Lacute ; B 12 0 598 890 ; +C -1 ; WX 980 ; N trademark ; B 30 256 957 662 ; +C -1 ; WX 444 ; N edotaccent ; B 25 -10 424 623 ; +C -1 ; WX 333 ; N Igrave ; B 18 0 315 890 ; +C -1 ; WX 333 ; N Imacron ; B 11 0 322 813 ; +C -1 ; WX 611 ; N Lcaron ; B 12 0 598 676 ; +C -1 ; WX 750 ; N onehalf ; B 31 -14 746 676 ; +C -1 ; WX 549 ; N lessequal ; B 26 0 523 666 ; +C -1 ; WX 500 ; N ocircumflex ; B 29 -10 470 674 ; +C -1 ; WX 500 ; N ntilde ; B 16 0 485 638 ; +C -1 ; WX 722 ; N Uhungarumlaut ; B 14 -14 705 890 ; +C -1 ; WX 611 ; N Eacute ; B 12 0 597 890 ; +C -1 ; WX 444 ; N emacron ; B 25 -10 424 601 ; +C -1 ; WX 500 ; N gbreve ; B 28 -218 470 664 ; +C -1 ; WX 750 ; N onequarter ; B 37 -14 718 676 ; +C -1 ; WX 556 ; N Scaron ; B 42 -14 491 886 ; +C -1 ; WX 556 ; N Scommaaccent ; B 42 -218 491 676 ; +C -1 ; WX 722 ; N Ohungarumlaut ; B 34 -14 688 890 ; +C -1 ; WX 400 ; N degree ; B 57 390 343 676 ; +C -1 ; WX 500 ; N ograve ; B 29 -10 470 678 ; +C -1 ; WX 667 ; N Ccaron ; B 28 -14 633 886 ; +C -1 ; WX 500 ; N ugrave ; B 9 -10 479 678 ; +C -1 ; WX 453 ; N radical ; B 2 -60 452 768 ; +C -1 ; WX 722 ; N Dcaron ; B 16 0 685 886 ; +C -1 ; WX 333 ; N rcommaaccent ; B 5 -218 335 460 ; +C -1 ; WX 722 ; N Ntilde ; B 12 -11 707 850 ; +C -1 ; WX 500 ; N otilde ; B 29 -10 470 638 ; +C -1 ; WX 667 ; N Rcommaaccent ; B 17 -198 659 662 ; +C -1 ; WX 611 ; N Lcommaaccent ; B 12 -218 598 662 ; +C -1 ; WX 722 ; N Atilde ; B 15 0 706 850 ; +C -1 ; WX 722 ; N Aogonek ; B 15 -165 738 674 ; +C -1 ; WX 722 ; N Aring ; B 15 0 706 898 ; +C -1 ; WX 722 ; N Otilde ; B 34 -14 688 850 ; +C -1 ; WX 444 ; N zdotaccent ; B 27 0 418 623 ; +C -1 ; WX 611 ; N Ecaron ; B 12 0 597 886 ; +C -1 ; WX 333 ; N Iogonek ; B 18 -165 315 662 ; +C -1 ; WX 500 ; N kcommaaccent ; B 7 -218 505 683 ; +C -1 ; WX 564 ; N minus ; B 30 220 534 286 ; +C -1 ; WX 333 ; N Icircumflex ; B 11 0 322 886 ; +C -1 ; WX 500 ; N ncaron ; B 16 0 485 674 ; +C -1 ; WX 278 ; N tcommaaccent ; B 13 -218 279 579 ; +C -1 ; WX 564 ; N logicalnot ; B 30 108 534 386 ; +C -1 ; WX 500 ; N odieresis ; B 29 -10 470 623 ; +C -1 ; WX 500 ; N udieresis ; B 9 -10 479 623 ; +C -1 ; WX 549 ; N notequal ; B 12 -31 537 547 ; +C -1 ; WX 500 ; N gcommaaccent ; B 28 -218 470 749 ; +C -1 ; WX 500 ; N eth ; B 29 -10 471 686 ; +C -1 ; WX 444 ; N zcaron ; B 27 0 418 674 ; +C -1 ; WX 500 ; N ncommaaccent ; B 16 -218 485 460 ; +C -1 ; WX 300 ; N onebaseior ; B 57 270 248 676 ; +C -1 ; WX 278 ; N imacron ; B 6 0 271 601 ; +C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ; +EndCharMetrics +StartKernData +StartKernPairs 2073 +KPX A C -40 +KPX A Cacute -40 +KPX A Ccaron -40 +KPX A Ccedilla -40 +KPX A G -40 +KPX A Gbreve -40 +KPX A Gcommaaccent -40 +KPX A O -55 +KPX A Oacute -55 +KPX A Ocircumflex -55 +KPX A Odieresis -55 +KPX A Ograve -55 +KPX A Ohungarumlaut -55 +KPX A Omacron -55 +KPX A Oslash -55 +KPX A Otilde -55 +KPX A Q -55 +KPX A T -111 +KPX A Tcaron -111 +KPX A Tcommaaccent -111 +KPX A U -55 +KPX A Uacute -55 +KPX A Ucircumflex -55 +KPX A Udieresis -55 +KPX A Ugrave -55 +KPX A Uhungarumlaut -55 +KPX A Umacron -55 +KPX A Uogonek -55 +KPX A Uring -55 +KPX A V -135 +KPX A W -90 +KPX A Y -105 +KPX A Yacute -105 +KPX A Ydieresis -105 +KPX A quoteright -111 +KPX A v -74 +KPX A w -92 +KPX A y -92 +KPX A yacute -92 +KPX A ydieresis -92 +KPX Aacute C -40 +KPX Aacute Cacute -40 +KPX Aacute Ccaron -40 +KPX Aacute Ccedilla -40 +KPX Aacute G -40 +KPX Aacute Gbreve -40 +KPX Aacute Gcommaaccent -40 +KPX Aacute O -55 +KPX Aacute Oacute -55 +KPX Aacute Ocircumflex -55 +KPX Aacute Odieresis -55 +KPX Aacute Ograve -55 +KPX Aacute Ohungarumlaut -55 +KPX Aacute Omacron -55 +KPX Aacute Oslash -55 +KPX Aacute Otilde -55 +KPX Aacute Q -55 +KPX Aacute T -111 +KPX Aacute Tcaron -111 +KPX Aacute Tcommaaccent -111 +KPX Aacute U -55 +KPX Aacute Uacute -55 +KPX Aacute Ucircumflex -55 +KPX Aacute Udieresis -55 +KPX Aacute Ugrave -55 +KPX Aacute Uhungarumlaut -55 +KPX Aacute Umacron -55 +KPX Aacute Uogonek -55 +KPX Aacute Uring -55 +KPX Aacute V -135 +KPX Aacute W -90 +KPX Aacute Y -105 +KPX Aacute Yacute -105 +KPX Aacute Ydieresis -105 +KPX Aacute quoteright -111 +KPX Aacute v -74 +KPX Aacute w -92 +KPX Aacute y -92 +KPX Aacute yacute -92 +KPX Aacute ydieresis -92 +KPX Abreve C -40 +KPX Abreve Cacute -40 +KPX Abreve Ccaron -40 +KPX Abreve Ccedilla -40 +KPX Abreve G -40 +KPX Abreve Gbreve -40 +KPX Abreve Gcommaaccent -40 +KPX Abreve O -55 +KPX Abreve Oacute -55 +KPX Abreve Ocircumflex -55 +KPX Abreve Odieresis -55 +KPX Abreve Ograve -55 +KPX Abreve Ohungarumlaut -55 +KPX Abreve Omacron -55 +KPX Abreve Oslash -55 +KPX Abreve Otilde -55 +KPX Abreve Q -55 +KPX Abreve T -111 +KPX Abreve Tcaron -111 +KPX Abreve Tcommaaccent -111 +KPX Abreve U -55 +KPX Abreve Uacute -55 +KPX Abreve Ucircumflex -55 +KPX Abreve Udieresis -55 +KPX Abreve Ugrave -55 +KPX Abreve Uhungarumlaut -55 +KPX Abreve Umacron -55 +KPX Abreve Uogonek -55 +KPX Abreve Uring -55 +KPX Abreve V -135 +KPX Abreve W -90 +KPX Abreve Y -105 +KPX Abreve Yacute -105 +KPX Abreve Ydieresis -105 +KPX Abreve quoteright -111 +KPX Abreve v -74 +KPX Abreve w -92 +KPX Abreve y -92 +KPX Abreve yacute -92 +KPX Abreve ydieresis -92 +KPX Acircumflex C -40 +KPX Acircumflex Cacute -40 +KPX Acircumflex Ccaron -40 +KPX Acircumflex Ccedilla -40 +KPX Acircumflex G -40 +KPX Acircumflex Gbreve -40 +KPX Acircumflex Gcommaaccent -40 +KPX Acircumflex O -55 +KPX Acircumflex Oacute -55 +KPX Acircumflex Ocircumflex -55 +KPX Acircumflex Odieresis -55 +KPX Acircumflex Ograve -55 +KPX Acircumflex Ohungarumlaut -55 +KPX Acircumflex Omacron -55 +KPX Acircumflex Oslash -55 +KPX Acircumflex Otilde -55 +KPX Acircumflex Q -55 +KPX Acircumflex T -111 +KPX Acircumflex Tcaron -111 +KPX Acircumflex Tcommaaccent -111 +KPX Acircumflex U -55 +KPX Acircumflex Uacute -55 +KPX Acircumflex Ucircumflex -55 +KPX Acircumflex Udieresis -55 +KPX Acircumflex Ugrave -55 +KPX Acircumflex Uhungarumlaut -55 +KPX Acircumflex Umacron -55 +KPX Acircumflex Uogonek -55 +KPX Acircumflex Uring -55 +KPX Acircumflex V -135 +KPX Acircumflex W -90 +KPX Acircumflex Y -105 +KPX Acircumflex Yacute -105 +KPX Acircumflex Ydieresis -105 +KPX Acircumflex quoteright -111 +KPX Acircumflex v -74 +KPX Acircumflex w -92 +KPX Acircumflex y -92 +KPX Acircumflex yacute -92 +KPX Acircumflex ydieresis -92 +KPX Adieresis C -40 +KPX Adieresis Cacute -40 +KPX Adieresis Ccaron -40 +KPX Adieresis Ccedilla -40 +KPX Adieresis G -40 +KPX Adieresis Gbreve -40 +KPX Adieresis Gcommaaccent -40 +KPX Adieresis O -55 +KPX Adieresis Oacute -55 +KPX Adieresis Ocircumflex -55 +KPX Adieresis Odieresis -55 +KPX Adieresis Ograve -55 +KPX Adieresis Ohungarumlaut -55 +KPX Adieresis Omacron -55 +KPX Adieresis Oslash -55 +KPX Adieresis Otilde -55 +KPX Adieresis Q -55 +KPX Adieresis T -111 +KPX Adieresis Tcaron -111 +KPX Adieresis Tcommaaccent -111 +KPX Adieresis U -55 +KPX Adieresis Uacute -55 +KPX Adieresis Ucircumflex -55 +KPX Adieresis Udieresis -55 +KPX Adieresis Ugrave -55 +KPX Adieresis Uhungarumlaut -55 +KPX Adieresis Umacron -55 +KPX Adieresis Uogonek -55 +KPX Adieresis Uring -55 +KPX Adieresis V -135 +KPX Adieresis W -90 +KPX Adieresis Y -105 +KPX Adieresis Yacute -105 +KPX Adieresis Ydieresis -105 +KPX Adieresis quoteright -111 +KPX Adieresis v -74 +KPX Adieresis w -92 +KPX Adieresis y -92 +KPX Adieresis yacute -92 +KPX Adieresis ydieresis -92 +KPX Agrave C -40 +KPX Agrave Cacute -40 +KPX Agrave Ccaron -40 +KPX Agrave Ccedilla -40 +KPX Agrave G -40 +KPX Agrave Gbreve -40 +KPX Agrave Gcommaaccent -40 +KPX Agrave O -55 +KPX Agrave Oacute -55 +KPX Agrave Ocircumflex -55 +KPX Agrave Odieresis -55 +KPX Agrave Ograve -55 +KPX Agrave Ohungarumlaut -55 +KPX Agrave Omacron -55 +KPX Agrave Oslash -55 +KPX Agrave Otilde -55 +KPX Agrave Q -55 +KPX Agrave T -111 +KPX Agrave Tcaron -111 +KPX Agrave Tcommaaccent -111 +KPX Agrave U -55 +KPX Agrave Uacute -55 +KPX Agrave Ucircumflex -55 +KPX Agrave Udieresis -55 +KPX Agrave Ugrave -55 +KPX Agrave Uhungarumlaut -55 +KPX Agrave Umacron -55 +KPX Agrave Uogonek -55 +KPX Agrave Uring -55 +KPX Agrave V -135 +KPX Agrave W -90 +KPX Agrave Y -105 +KPX Agrave Yacute -105 +KPX Agrave Ydieresis -105 +KPX Agrave quoteright -111 +KPX Agrave v -74 +KPX Agrave w -92 +KPX Agrave y -92 +KPX Agrave yacute -92 +KPX Agrave ydieresis -92 +KPX Amacron C -40 +KPX Amacron Cacute -40 +KPX Amacron Ccaron -40 +KPX Amacron Ccedilla -40 +KPX Amacron G -40 +KPX Amacron Gbreve -40 +KPX Amacron Gcommaaccent -40 +KPX Amacron O -55 +KPX Amacron Oacute -55 +KPX Amacron Ocircumflex -55 +KPX Amacron Odieresis -55 +KPX Amacron Ograve -55 +KPX Amacron Ohungarumlaut -55 +KPX Amacron Omacron -55 +KPX Amacron Oslash -55 +KPX Amacron Otilde -55 +KPX Amacron Q -55 +KPX Amacron T -111 +KPX Amacron Tcaron -111 +KPX Amacron Tcommaaccent -111 +KPX Amacron U -55 +KPX Amacron Uacute -55 +KPX Amacron Ucircumflex -55 +KPX Amacron Udieresis -55 +KPX Amacron Ugrave -55 +KPX Amacron Uhungarumlaut -55 +KPX Amacron Umacron -55 +KPX Amacron Uogonek -55 +KPX Amacron Uring -55 +KPX Amacron V -135 +KPX Amacron W -90 +KPX Amacron Y -105 +KPX Amacron Yacute -105 +KPX Amacron Ydieresis -105 +KPX Amacron quoteright -111 +KPX Amacron v -74 +KPX Amacron w -92 +KPX Amacron y -92 +KPX Amacron yacute -92 +KPX Amacron ydieresis -92 +KPX Aogonek C -40 +KPX Aogonek Cacute -40 +KPX Aogonek Ccaron -40 +KPX Aogonek Ccedilla -40 +KPX Aogonek G -40 +KPX Aogonek Gbreve -40 +KPX Aogonek Gcommaaccent -40 +KPX Aogonek O -55 +KPX Aogonek Oacute -55 +KPX Aogonek Ocircumflex -55 +KPX Aogonek Odieresis -55 +KPX Aogonek Ograve -55 +KPX Aogonek Ohungarumlaut -55 +KPX Aogonek Omacron -55 +KPX Aogonek Oslash -55 +KPX Aogonek Otilde -55 +KPX Aogonek Q -55 +KPX Aogonek T -111 +KPX Aogonek Tcaron -111 +KPX Aogonek Tcommaaccent -111 +KPX Aogonek U -55 +KPX Aogonek Uacute -55 +KPX Aogonek Ucircumflex -55 +KPX Aogonek Udieresis -55 +KPX Aogonek Ugrave -55 +KPX Aogonek Uhungarumlaut -55 +KPX Aogonek Umacron -55 +KPX Aogonek Uogonek -55 +KPX Aogonek Uring -55 +KPX Aogonek V -135 +KPX Aogonek W -90 +KPX Aogonek Y -105 +KPX Aogonek Yacute -105 +KPX Aogonek Ydieresis -105 +KPX Aogonek quoteright -111 +KPX Aogonek v -74 +KPX Aogonek w -52 +KPX Aogonek y -52 +KPX Aogonek yacute -52 +KPX Aogonek ydieresis -52 +KPX Aring C -40 +KPX Aring Cacute -40 +KPX Aring Ccaron -40 +KPX Aring Ccedilla -40 +KPX Aring G -40 +KPX Aring Gbreve -40 +KPX Aring Gcommaaccent -40 +KPX Aring O -55 +KPX Aring Oacute -55 +KPX Aring Ocircumflex -55 +KPX Aring Odieresis -55 +KPX Aring Ograve -55 +KPX Aring Ohungarumlaut -55 +KPX Aring Omacron -55 +KPX Aring Oslash -55 +KPX Aring Otilde -55 +KPX Aring Q -55 +KPX Aring T -111 +KPX Aring Tcaron -111 +KPX Aring Tcommaaccent -111 +KPX Aring U -55 +KPX Aring Uacute -55 +KPX Aring Ucircumflex -55 +KPX Aring Udieresis -55 +KPX Aring Ugrave -55 +KPX Aring Uhungarumlaut -55 +KPX Aring Umacron -55 +KPX Aring Uogonek -55 +KPX Aring Uring -55 +KPX Aring V -135 +KPX Aring W -90 +KPX Aring Y -105 +KPX Aring Yacute -105 +KPX Aring Ydieresis -105 +KPX Aring quoteright -111 +KPX Aring v -74 +KPX Aring w -92 +KPX Aring y -92 +KPX Aring yacute -92 +KPX Aring ydieresis -92 +KPX Atilde C -40 +KPX Atilde Cacute -40 +KPX Atilde Ccaron -40 +KPX Atilde Ccedilla -40 +KPX Atilde G -40 +KPX Atilde Gbreve -40 +KPX Atilde Gcommaaccent -40 +KPX Atilde O -55 +KPX Atilde Oacute -55 +KPX Atilde Ocircumflex -55 +KPX Atilde Odieresis -55 +KPX Atilde Ograve -55 +KPX Atilde Ohungarumlaut -55 +KPX Atilde Omacron -55 +KPX Atilde Oslash -55 +KPX Atilde Otilde -55 +KPX Atilde Q -55 +KPX Atilde T -111 +KPX Atilde Tcaron -111 +KPX Atilde Tcommaaccent -111 +KPX Atilde U -55 +KPX Atilde Uacute -55 +KPX Atilde Ucircumflex -55 +KPX Atilde Udieresis -55 +KPX Atilde Ugrave -55 +KPX Atilde Uhungarumlaut -55 +KPX Atilde Umacron -55 +KPX Atilde Uogonek -55 +KPX Atilde Uring -55 +KPX Atilde V -135 +KPX Atilde W -90 +KPX Atilde Y -105 +KPX Atilde Yacute -105 +KPX Atilde Ydieresis -105 +KPX Atilde quoteright -111 +KPX Atilde v -74 +KPX Atilde w -92 +KPX Atilde y -92 +KPX Atilde yacute -92 +KPX Atilde ydieresis -92 +KPX B A -35 +KPX B Aacute -35 +KPX B Abreve -35 +KPX B Acircumflex -35 +KPX B Adieresis -35 +KPX B Agrave -35 +KPX B Amacron -35 +KPX B Aogonek -35 +KPX B Aring -35 +KPX B Atilde -35 +KPX B U -10 +KPX B Uacute -10 +KPX B Ucircumflex -10 +KPX B Udieresis -10 +KPX B Ugrave -10 +KPX B Uhungarumlaut -10 +KPX B Umacron -10 +KPX B Uogonek -10 +KPX B Uring -10 +KPX D A -40 +KPX D Aacute -40 +KPX D Abreve -40 +KPX D Acircumflex -40 +KPX D Adieresis -40 +KPX D Agrave -40 +KPX D Amacron -40 +KPX D Aogonek -40 +KPX D Aring -40 +KPX D Atilde -40 +KPX D V -40 +KPX D W -30 +KPX D Y -55 +KPX D Yacute -55 +KPX D Ydieresis -55 +KPX Dcaron A -40 +KPX Dcaron Aacute -40 +KPX Dcaron Abreve -40 +KPX Dcaron Acircumflex -40 +KPX Dcaron Adieresis -40 +KPX Dcaron Agrave -40 +KPX Dcaron Amacron -40 +KPX Dcaron Aogonek -40 +KPX Dcaron Aring -40 +KPX Dcaron Atilde -40 +KPX Dcaron V -40 +KPX Dcaron W -30 +KPX Dcaron Y -55 +KPX Dcaron Yacute -55 +KPX Dcaron Ydieresis -55 +KPX Dcroat A -40 +KPX Dcroat Aacute -40 +KPX Dcroat Abreve -40 +KPX Dcroat Acircumflex -40 +KPX Dcroat Adieresis -40 +KPX Dcroat Agrave -40 +KPX Dcroat Amacron -40 +KPX Dcroat Aogonek -40 +KPX Dcroat Aring -40 +KPX Dcroat Atilde -40 +KPX Dcroat V -40 +KPX Dcroat W -30 +KPX Dcroat Y -55 +KPX Dcroat Yacute -55 +KPX Dcroat Ydieresis -55 +KPX F A -74 +KPX F Aacute -74 +KPX F Abreve -74 +KPX F Acircumflex -74 +KPX F Adieresis -74 +KPX F Agrave -74 +KPX F Amacron -74 +KPX F Aogonek -74 +KPX F Aring -74 +KPX F Atilde -74 +KPX F a -15 +KPX F aacute -15 +KPX F abreve -15 +KPX F acircumflex -15 +KPX F adieresis -15 +KPX F agrave -15 +KPX F amacron -15 +KPX F aogonek -15 +KPX F aring -15 +KPX F atilde -15 +KPX F comma -80 +KPX F o -15 +KPX F oacute -15 +KPX F ocircumflex -15 +KPX F odieresis -15 +KPX F ograve -15 +KPX F ohungarumlaut -15 +KPX F omacron -15 +KPX F oslash -15 +KPX F otilde -15 +KPX F period -80 +KPX J A -60 +KPX J Aacute -60 +KPX J Abreve -60 +KPX J Acircumflex -60 +KPX J Adieresis -60 +KPX J Agrave -60 +KPX J Amacron -60 +KPX J Aogonek -60 +KPX J Aring -60 +KPX J Atilde -60 +KPX K O -30 +KPX K Oacute -30 +KPX K Ocircumflex -30 +KPX K Odieresis -30 +KPX K Ograve -30 +KPX K Ohungarumlaut -30 +KPX K Omacron -30 +KPX K Oslash -30 +KPX K Otilde -30 +KPX K e -25 +KPX K eacute -25 +KPX K ecaron -25 +KPX K ecircumflex -25 +KPX K edieresis -25 +KPX K edotaccent -25 +KPX K egrave -25 +KPX K emacron -25 +KPX K eogonek -25 +KPX K o -35 +KPX K oacute -35 +KPX K ocircumflex -35 +KPX K odieresis -35 +KPX K ograve -35 +KPX K ohungarumlaut -35 +KPX K omacron -35 +KPX K oslash -35 +KPX K otilde -35 +KPX K u -15 +KPX K uacute -15 +KPX K ucircumflex -15 +KPX K udieresis -15 +KPX K ugrave -15 +KPX K uhungarumlaut -15 +KPX K umacron -15 +KPX K uogonek -15 +KPX K uring -15 +KPX K y -25 +KPX K yacute -25 +KPX K ydieresis -25 +KPX Kcommaaccent O -30 +KPX Kcommaaccent Oacute -30 +KPX Kcommaaccent Ocircumflex -30 +KPX Kcommaaccent Odieresis -30 +KPX Kcommaaccent Ograve -30 +KPX Kcommaaccent Ohungarumlaut -30 +KPX Kcommaaccent Omacron -30 +KPX Kcommaaccent Oslash -30 +KPX Kcommaaccent Otilde -30 +KPX Kcommaaccent e -25 +KPX Kcommaaccent eacute -25 +KPX Kcommaaccent ecaron -25 +KPX Kcommaaccent ecircumflex -25 +KPX Kcommaaccent edieresis -25 +KPX Kcommaaccent edotaccent -25 +KPX Kcommaaccent egrave -25 +KPX Kcommaaccent emacron -25 +KPX Kcommaaccent eogonek -25 +KPX Kcommaaccent o -35 +KPX Kcommaaccent oacute -35 +KPX Kcommaaccent ocircumflex -35 +KPX Kcommaaccent odieresis -35 +KPX Kcommaaccent ograve -35 +KPX Kcommaaccent ohungarumlaut -35 +KPX Kcommaaccent omacron -35 +KPX Kcommaaccent oslash -35 +KPX Kcommaaccent otilde -35 +KPX Kcommaaccent u -15 +KPX Kcommaaccent uacute -15 +KPX Kcommaaccent ucircumflex -15 +KPX Kcommaaccent udieresis -15 +KPX Kcommaaccent ugrave -15 +KPX Kcommaaccent uhungarumlaut -15 +KPX Kcommaaccent umacron -15 +KPX Kcommaaccent uogonek -15 +KPX Kcommaaccent uring -15 +KPX Kcommaaccent y -25 +KPX Kcommaaccent yacute -25 +KPX Kcommaaccent ydieresis -25 +KPX L T -92 +KPX L Tcaron -92 +KPX L Tcommaaccent -92 +KPX L V -100 +KPX L W -74 +KPX L Y -100 +KPX L Yacute -100 +KPX L Ydieresis -100 +KPX L quoteright -92 +KPX L y -55 +KPX L yacute -55 +KPX L ydieresis -55 +KPX Lacute T -92 +KPX Lacute Tcaron -92 +KPX Lacute Tcommaaccent -92 +KPX Lacute V -100 +KPX Lacute W -74 +KPX Lacute Y -100 +KPX Lacute Yacute -100 +KPX Lacute Ydieresis -100 +KPX Lacute quoteright -92 +KPX Lacute y -55 +KPX Lacute yacute -55 +KPX Lacute ydieresis -55 +KPX Lcaron quoteright -92 +KPX Lcaron y -55 +KPX Lcaron yacute -55 +KPX Lcaron ydieresis -55 +KPX Lcommaaccent T -92 +KPX Lcommaaccent Tcaron -92 +KPX Lcommaaccent Tcommaaccent -92 +KPX Lcommaaccent V -100 +KPX Lcommaaccent W -74 +KPX Lcommaaccent Y -100 +KPX Lcommaaccent Yacute -100 +KPX Lcommaaccent Ydieresis -100 +KPX Lcommaaccent quoteright -92 +KPX Lcommaaccent y -55 +KPX Lcommaaccent yacute -55 +KPX Lcommaaccent ydieresis -55 +KPX Lslash T -92 +KPX Lslash Tcaron -92 +KPX Lslash Tcommaaccent -92 +KPX Lslash V -100 +KPX Lslash W -74 +KPX Lslash Y -100 +KPX Lslash Yacute -100 +KPX Lslash Ydieresis -100 +KPX Lslash quoteright -92 +KPX Lslash y -55 +KPX Lslash yacute -55 +KPX Lslash ydieresis -55 +KPX N A -35 +KPX N Aacute -35 +KPX N Abreve -35 +KPX N Acircumflex -35 +KPX N Adieresis -35 +KPX N Agrave -35 +KPX N Amacron -35 +KPX N Aogonek -35 +KPX N Aring -35 +KPX N Atilde -35 +KPX Nacute A -35 +KPX Nacute Aacute -35 +KPX Nacute Abreve -35 +KPX Nacute Acircumflex -35 +KPX Nacute Adieresis -35 +KPX Nacute Agrave -35 +KPX Nacute Amacron -35 +KPX Nacute Aogonek -35 +KPX Nacute Aring -35 +KPX Nacute Atilde -35 +KPX Ncaron A -35 +KPX Ncaron Aacute -35 +KPX Ncaron Abreve -35 +KPX Ncaron Acircumflex -35 +KPX Ncaron Adieresis -35 +KPX Ncaron Agrave -35 +KPX Ncaron Amacron -35 +KPX Ncaron Aogonek -35 +KPX Ncaron Aring -35 +KPX Ncaron Atilde -35 +KPX Ncommaaccent A -35 +KPX Ncommaaccent Aacute -35 +KPX Ncommaaccent Abreve -35 +KPX Ncommaaccent Acircumflex -35 +KPX Ncommaaccent Adieresis -35 +KPX Ncommaaccent Agrave -35 +KPX Ncommaaccent Amacron -35 +KPX Ncommaaccent Aogonek -35 +KPX Ncommaaccent Aring -35 +KPX Ncommaaccent Atilde -35 +KPX Ntilde A -35 +KPX Ntilde Aacute -35 +KPX Ntilde Abreve -35 +KPX Ntilde Acircumflex -35 +KPX Ntilde Adieresis -35 +KPX Ntilde Agrave -35 +KPX Ntilde Amacron -35 +KPX Ntilde Aogonek -35 +KPX Ntilde Aring -35 +KPX Ntilde Atilde -35 +KPX O A -35 +KPX O Aacute -35 +KPX O Abreve -35 +KPX O Acircumflex -35 +KPX O Adieresis -35 +KPX O Agrave -35 +KPX O Amacron -35 +KPX O Aogonek -35 +KPX O Aring -35 +KPX O Atilde -35 +KPX O T -40 +KPX O Tcaron -40 +KPX O Tcommaaccent -40 +KPX O V -50 +KPX O W -35 +KPX O X -40 +KPX O Y -50 +KPX O Yacute -50 +KPX O Ydieresis -50 +KPX Oacute A -35 +KPX Oacute Aacute -35 +KPX Oacute Abreve -35 +KPX Oacute Acircumflex -35 +KPX Oacute Adieresis -35 +KPX Oacute Agrave -35 +KPX Oacute Amacron -35 +KPX Oacute Aogonek -35 +KPX Oacute Aring -35 +KPX Oacute Atilde -35 +KPX Oacute T -40 +KPX Oacute Tcaron -40 +KPX Oacute Tcommaaccent -40 +KPX Oacute V -50 +KPX Oacute W -35 +KPX Oacute X -40 +KPX Oacute Y -50 +KPX Oacute Yacute -50 +KPX Oacute Ydieresis -50 +KPX Ocircumflex A -35 +KPX Ocircumflex Aacute -35 +KPX Ocircumflex Abreve -35 +KPX Ocircumflex Acircumflex -35 +KPX Ocircumflex Adieresis -35 +KPX Ocircumflex Agrave -35 +KPX Ocircumflex Amacron -35 +KPX Ocircumflex Aogonek -35 +KPX Ocircumflex Aring -35 +KPX Ocircumflex Atilde -35 +KPX Ocircumflex T -40 +KPX Ocircumflex Tcaron -40 +KPX Ocircumflex Tcommaaccent -40 +KPX Ocircumflex V -50 +KPX Ocircumflex W -35 +KPX Ocircumflex X -40 +KPX Ocircumflex Y -50 +KPX Ocircumflex Yacute -50 +KPX Ocircumflex Ydieresis -50 +KPX Odieresis A -35 +KPX Odieresis Aacute -35 +KPX Odieresis Abreve -35 +KPX Odieresis Acircumflex -35 +KPX Odieresis Adieresis -35 +KPX Odieresis Agrave -35 +KPX Odieresis Amacron -35 +KPX Odieresis Aogonek -35 +KPX Odieresis Aring -35 +KPX Odieresis Atilde -35 +KPX Odieresis T -40 +KPX Odieresis Tcaron -40 +KPX Odieresis Tcommaaccent -40 +KPX Odieresis V -50 +KPX Odieresis W -35 +KPX Odieresis X -40 +KPX Odieresis Y -50 +KPX Odieresis Yacute -50 +KPX Odieresis Ydieresis -50 +KPX Ograve A -35 +KPX Ograve Aacute -35 +KPX Ograve Abreve -35 +KPX Ograve Acircumflex -35 +KPX Ograve Adieresis -35 +KPX Ograve Agrave -35 +KPX Ograve Amacron -35 +KPX Ograve Aogonek -35 +KPX Ograve Aring -35 +KPX Ograve Atilde -35 +KPX Ograve T -40 +KPX Ograve Tcaron -40 +KPX Ograve Tcommaaccent -40 +KPX Ograve V -50 +KPX Ograve W -35 +KPX Ograve X -40 +KPX Ograve Y -50 +KPX Ograve Yacute -50 +KPX Ograve Ydieresis -50 +KPX Ohungarumlaut A -35 +KPX Ohungarumlaut Aacute -35 +KPX Ohungarumlaut Abreve -35 +KPX Ohungarumlaut Acircumflex -35 +KPX Ohungarumlaut Adieresis -35 +KPX Ohungarumlaut Agrave -35 +KPX Ohungarumlaut Amacron -35 +KPX Ohungarumlaut Aogonek -35 +KPX Ohungarumlaut Aring -35 +KPX Ohungarumlaut Atilde -35 +KPX Ohungarumlaut T -40 +KPX Ohungarumlaut Tcaron -40 +KPX Ohungarumlaut Tcommaaccent -40 +KPX Ohungarumlaut V -50 +KPX Ohungarumlaut W -35 +KPX Ohungarumlaut X -40 +KPX Ohungarumlaut Y -50 +KPX Ohungarumlaut Yacute -50 +KPX Ohungarumlaut Ydieresis -50 +KPX Omacron A -35 +KPX Omacron Aacute -35 +KPX Omacron Abreve -35 +KPX Omacron Acircumflex -35 +KPX Omacron Adieresis -35 +KPX Omacron Agrave -35 +KPX Omacron Amacron -35 +KPX Omacron Aogonek -35 +KPX Omacron Aring -35 +KPX Omacron Atilde -35 +KPX Omacron T -40 +KPX Omacron Tcaron -40 +KPX Omacron Tcommaaccent -40 +KPX Omacron V -50 +KPX Omacron W -35 +KPX Omacron X -40 +KPX Omacron Y -50 +KPX Omacron Yacute -50 +KPX Omacron Ydieresis -50 +KPX Oslash A -35 +KPX Oslash Aacute -35 +KPX Oslash Abreve -35 +KPX Oslash Acircumflex -35 +KPX Oslash Adieresis -35 +KPX Oslash Agrave -35 +KPX Oslash Amacron -35 +KPX Oslash Aogonek -35 +KPX Oslash Aring -35 +KPX Oslash Atilde -35 +KPX Oslash T -40 +KPX Oslash Tcaron -40 +KPX Oslash Tcommaaccent -40 +KPX Oslash V -50 +KPX Oslash W -35 +KPX Oslash X -40 +KPX Oslash Y -50 +KPX Oslash Yacute -50 +KPX Oslash Ydieresis -50 +KPX Otilde A -35 +KPX Otilde Aacute -35 +KPX Otilde Abreve -35 +KPX Otilde Acircumflex -35 +KPX Otilde Adieresis -35 +KPX Otilde Agrave -35 +KPX Otilde Amacron -35 +KPX Otilde Aogonek -35 +KPX Otilde Aring -35 +KPX Otilde Atilde -35 +KPX Otilde T -40 +KPX Otilde Tcaron -40 +KPX Otilde Tcommaaccent -40 +KPX Otilde V -50 +KPX Otilde W -35 +KPX Otilde X -40 +KPX Otilde Y -50 +KPX Otilde Yacute -50 +KPX Otilde Ydieresis -50 +KPX P A -92 +KPX P Aacute -92 +KPX P Abreve -92 +KPX P Acircumflex -92 +KPX P Adieresis -92 +KPX P Agrave -92 +KPX P Amacron -92 +KPX P Aogonek -92 +KPX P Aring -92 +KPX P Atilde -92 +KPX P a -15 +KPX P aacute -15 +KPX P abreve -15 +KPX P acircumflex -15 +KPX P adieresis -15 +KPX P agrave -15 +KPX P amacron -15 +KPX P aogonek -15 +KPX P aring -15 +KPX P atilde -15 +KPX P comma -111 +KPX P period -111 +KPX Q U -10 +KPX Q Uacute -10 +KPX Q Ucircumflex -10 +KPX Q Udieresis -10 +KPX Q Ugrave -10 +KPX Q Uhungarumlaut -10 +KPX Q Umacron -10 +KPX Q Uogonek -10 +KPX Q Uring -10 +KPX R O -40 +KPX R Oacute -40 +KPX R Ocircumflex -40 +KPX R Odieresis -40 +KPX R Ograve -40 +KPX R Ohungarumlaut -40 +KPX R Omacron -40 +KPX R Oslash -40 +KPX R Otilde -40 +KPX R T -60 +KPX R Tcaron -60 +KPX R Tcommaaccent -60 +KPX R U -40 +KPX R Uacute -40 +KPX R Ucircumflex -40 +KPX R Udieresis -40 +KPX R Ugrave -40 +KPX R Uhungarumlaut -40 +KPX R Umacron -40 +KPX R Uogonek -40 +KPX R Uring -40 +KPX R V -80 +KPX R W -55 +KPX R Y -65 +KPX R Yacute -65 +KPX R Ydieresis -65 +KPX Racute O -40 +KPX Racute Oacute -40 +KPX Racute Ocircumflex -40 +KPX Racute Odieresis -40 +KPX Racute Ograve -40 +KPX Racute Ohungarumlaut -40 +KPX Racute Omacron -40 +KPX Racute Oslash -40 +KPX Racute Otilde -40 +KPX Racute T -60 +KPX Racute Tcaron -60 +KPX Racute Tcommaaccent -60 +KPX Racute U -40 +KPX Racute Uacute -40 +KPX Racute Ucircumflex -40 +KPX Racute Udieresis -40 +KPX Racute Ugrave -40 +KPX Racute Uhungarumlaut -40 +KPX Racute Umacron -40 +KPX Racute Uogonek -40 +KPX Racute Uring -40 +KPX Racute V -80 +KPX Racute W -55 +KPX Racute Y -65 +KPX Racute Yacute -65 +KPX Racute Ydieresis -65 +KPX Rcaron O -40 +KPX Rcaron Oacute -40 +KPX Rcaron Ocircumflex -40 +KPX Rcaron Odieresis -40 +KPX Rcaron Ograve -40 +KPX Rcaron Ohungarumlaut -40 +KPX Rcaron Omacron -40 +KPX Rcaron Oslash -40 +KPX Rcaron Otilde -40 +KPX Rcaron T -60 +KPX Rcaron Tcaron -60 +KPX Rcaron Tcommaaccent -60 +KPX Rcaron U -40 +KPX Rcaron Uacute -40 +KPX Rcaron Ucircumflex -40 +KPX Rcaron Udieresis -40 +KPX Rcaron Ugrave -40 +KPX Rcaron Uhungarumlaut -40 +KPX Rcaron Umacron -40 +KPX Rcaron Uogonek -40 +KPX Rcaron Uring -40 +KPX Rcaron V -80 +KPX Rcaron W -55 +KPX Rcaron Y -65 +KPX Rcaron Yacute -65 +KPX Rcaron Ydieresis -65 +KPX Rcommaaccent O -40 +KPX Rcommaaccent Oacute -40 +KPX Rcommaaccent Ocircumflex -40 +KPX Rcommaaccent Odieresis -40 +KPX Rcommaaccent Ograve -40 +KPX Rcommaaccent Ohungarumlaut -40 +KPX Rcommaaccent Omacron -40 +KPX Rcommaaccent Oslash -40 +KPX Rcommaaccent Otilde -40 +KPX Rcommaaccent T -60 +KPX Rcommaaccent Tcaron -60 +KPX Rcommaaccent Tcommaaccent -60 +KPX Rcommaaccent U -40 +KPX Rcommaaccent Uacute -40 +KPX Rcommaaccent Ucircumflex -40 +KPX Rcommaaccent Udieresis -40 +KPX Rcommaaccent Ugrave -40 +KPX Rcommaaccent Uhungarumlaut -40 +KPX Rcommaaccent Umacron -40 +KPX Rcommaaccent Uogonek -40 +KPX Rcommaaccent Uring -40 +KPX Rcommaaccent V -80 +KPX Rcommaaccent W -55 +KPX Rcommaaccent Y -65 +KPX Rcommaaccent Yacute -65 +KPX Rcommaaccent Ydieresis -65 +KPX T A -93 +KPX T Aacute -93 +KPX T Abreve -93 +KPX T Acircumflex -93 +KPX T Adieresis -93 +KPX T Agrave -93 +KPX T Amacron -93 +KPX T Aogonek -93 +KPX T Aring -93 +KPX T Atilde -93 +KPX T O -18 +KPX T Oacute -18 +KPX T Ocircumflex -18 +KPX T Odieresis -18 +KPX T Ograve -18 +KPX T Ohungarumlaut -18 +KPX T Omacron -18 +KPX T Oslash -18 +KPX T Otilde -18 +KPX T a -80 +KPX T aacute -80 +KPX T abreve -80 +KPX T acircumflex -80 +KPX T adieresis -40 +KPX T agrave -40 +KPX T amacron -40 +KPX T aogonek -80 +KPX T aring -80 +KPX T atilde -40 +KPX T colon -50 +KPX T comma -74 +KPX T e -70 +KPX T eacute -70 +KPX T ecaron -70 +KPX T ecircumflex -70 +KPX T edieresis -30 +KPX T edotaccent -70 +KPX T egrave -70 +KPX T emacron -30 +KPX T eogonek -70 +KPX T hyphen -92 +KPX T i -35 +KPX T iacute -35 +KPX T iogonek -35 +KPX T o -80 +KPX T oacute -80 +KPX T ocircumflex -80 +KPX T odieresis -80 +KPX T ograve -80 +KPX T ohungarumlaut -80 +KPX T omacron -80 +KPX T oslash -80 +KPX T otilde -80 +KPX T period -74 +KPX T r -35 +KPX T racute -35 +KPX T rcaron -35 +KPX T rcommaaccent -35 +KPX T semicolon -55 +KPX T u -45 +KPX T uacute -45 +KPX T ucircumflex -45 +KPX T udieresis -45 +KPX T ugrave -45 +KPX T uhungarumlaut -45 +KPX T umacron -45 +KPX T uogonek -45 +KPX T uring -45 +KPX T w -80 +KPX T y -80 +KPX T yacute -80 +KPX T ydieresis -80 +KPX Tcaron A -93 +KPX Tcaron Aacute -93 +KPX Tcaron Abreve -93 +KPX Tcaron Acircumflex -93 +KPX Tcaron Adieresis -93 +KPX Tcaron Agrave -93 +KPX Tcaron Amacron -93 +KPX Tcaron Aogonek -93 +KPX Tcaron Aring -93 +KPX Tcaron Atilde -93 +KPX Tcaron O -18 +KPX Tcaron Oacute -18 +KPX Tcaron Ocircumflex -18 +KPX Tcaron Odieresis -18 +KPX Tcaron Ograve -18 +KPX Tcaron Ohungarumlaut -18 +KPX Tcaron Omacron -18 +KPX Tcaron Oslash -18 +KPX Tcaron Otilde -18 +KPX Tcaron a -80 +KPX Tcaron aacute -80 +KPX Tcaron abreve -80 +KPX Tcaron acircumflex -80 +KPX Tcaron adieresis -40 +KPX Tcaron agrave -40 +KPX Tcaron amacron -40 +KPX Tcaron aogonek -80 +KPX Tcaron aring -80 +KPX Tcaron atilde -40 +KPX Tcaron colon -50 +KPX Tcaron comma -74 +KPX Tcaron e -70 +KPX Tcaron eacute -70 +KPX Tcaron ecaron -70 +KPX Tcaron ecircumflex -30 +KPX Tcaron edieresis -30 +KPX Tcaron edotaccent -70 +KPX Tcaron egrave -70 +KPX Tcaron emacron -30 +KPX Tcaron eogonek -70 +KPX Tcaron hyphen -92 +KPX Tcaron i -35 +KPX Tcaron iacute -35 +KPX Tcaron iogonek -35 +KPX Tcaron o -80 +KPX Tcaron oacute -80 +KPX Tcaron ocircumflex -80 +KPX Tcaron odieresis -80 +KPX Tcaron ograve -80 +KPX Tcaron ohungarumlaut -80 +KPX Tcaron omacron -80 +KPX Tcaron oslash -80 +KPX Tcaron otilde -80 +KPX Tcaron period -74 +KPX Tcaron r -35 +KPX Tcaron racute -35 +KPX Tcaron rcaron -35 +KPX Tcaron rcommaaccent -35 +KPX Tcaron semicolon -55 +KPX Tcaron u -45 +KPX Tcaron uacute -45 +KPX Tcaron ucircumflex -45 +KPX Tcaron udieresis -45 +KPX Tcaron ugrave -45 +KPX Tcaron uhungarumlaut -45 +KPX Tcaron umacron -45 +KPX Tcaron uogonek -45 +KPX Tcaron uring -45 +KPX Tcaron w -80 +KPX Tcaron y -80 +KPX Tcaron yacute -80 +KPX Tcaron ydieresis -80 +KPX Tcommaaccent A -93 +KPX Tcommaaccent Aacute -93 +KPX Tcommaaccent Abreve -93 +KPX Tcommaaccent Acircumflex -93 +KPX Tcommaaccent Adieresis -93 +KPX Tcommaaccent Agrave -93 +KPX Tcommaaccent Amacron -93 +KPX Tcommaaccent Aogonek -93 +KPX Tcommaaccent Aring -93 +KPX Tcommaaccent Atilde -93 +KPX Tcommaaccent O -18 +KPX Tcommaaccent Oacute -18 +KPX Tcommaaccent Ocircumflex -18 +KPX Tcommaaccent Odieresis -18 +KPX Tcommaaccent Ograve -18 +KPX Tcommaaccent Ohungarumlaut -18 +KPX Tcommaaccent Omacron -18 +KPX Tcommaaccent Oslash -18 +KPX Tcommaaccent Otilde -18 +KPX Tcommaaccent a -80 +KPX Tcommaaccent aacute -80 +KPX Tcommaaccent abreve -80 +KPX Tcommaaccent acircumflex -80 +KPX Tcommaaccent adieresis -40 +KPX Tcommaaccent agrave -40 +KPX Tcommaaccent amacron -40 +KPX Tcommaaccent aogonek -80 +KPX Tcommaaccent aring -80 +KPX Tcommaaccent atilde -40 +KPX Tcommaaccent colon -50 +KPX Tcommaaccent comma -74 +KPX Tcommaaccent e -70 +KPX Tcommaaccent eacute -70 +KPX Tcommaaccent ecaron -70 +KPX Tcommaaccent ecircumflex -30 +KPX Tcommaaccent edieresis -30 +KPX Tcommaaccent edotaccent -70 +KPX Tcommaaccent egrave -30 +KPX Tcommaaccent emacron -70 +KPX Tcommaaccent eogonek -70 +KPX Tcommaaccent hyphen -92 +KPX Tcommaaccent i -35 +KPX Tcommaaccent iacute -35 +KPX Tcommaaccent iogonek -35 +KPX Tcommaaccent o -80 +KPX Tcommaaccent oacute -80 +KPX Tcommaaccent ocircumflex -80 +KPX Tcommaaccent odieresis -80 +KPX Tcommaaccent ograve -80 +KPX Tcommaaccent ohungarumlaut -80 +KPX Tcommaaccent omacron -80 +KPX Tcommaaccent oslash -80 +KPX Tcommaaccent otilde -80 +KPX Tcommaaccent period -74 +KPX Tcommaaccent r -35 +KPX Tcommaaccent racute -35 +KPX Tcommaaccent rcaron -35 +KPX Tcommaaccent rcommaaccent -35 +KPX Tcommaaccent semicolon -55 +KPX Tcommaaccent u -45 +KPX Tcommaaccent uacute -45 +KPX Tcommaaccent ucircumflex -45 +KPX Tcommaaccent udieresis -45 +KPX Tcommaaccent ugrave -45 +KPX Tcommaaccent uhungarumlaut -45 +KPX Tcommaaccent umacron -45 +KPX Tcommaaccent uogonek -45 +KPX Tcommaaccent uring -45 +KPX Tcommaaccent w -80 +KPX Tcommaaccent y -80 +KPX Tcommaaccent yacute -80 +KPX Tcommaaccent ydieresis -80 +KPX U A -40 +KPX U Aacute -40 +KPX U Abreve -40 +KPX U Acircumflex -40 +KPX U Adieresis -40 +KPX U Agrave -40 +KPX U Amacron -40 +KPX U Aogonek -40 +KPX U Aring -40 +KPX U Atilde -40 +KPX Uacute A -40 +KPX Uacute Aacute -40 +KPX Uacute Abreve -40 +KPX Uacute Acircumflex -40 +KPX Uacute Adieresis -40 +KPX Uacute Agrave -40 +KPX Uacute Amacron -40 +KPX Uacute Aogonek -40 +KPX Uacute Aring -40 +KPX Uacute Atilde -40 +KPX Ucircumflex A -40 +KPX Ucircumflex Aacute -40 +KPX Ucircumflex Abreve -40 +KPX Ucircumflex Acircumflex -40 +KPX Ucircumflex Adieresis -40 +KPX Ucircumflex Agrave -40 +KPX Ucircumflex Amacron -40 +KPX Ucircumflex Aogonek -40 +KPX Ucircumflex Aring -40 +KPX Ucircumflex Atilde -40 +KPX Udieresis A -40 +KPX Udieresis Aacute -40 +KPX Udieresis Abreve -40 +KPX Udieresis Acircumflex -40 +KPX Udieresis Adieresis -40 +KPX Udieresis Agrave -40 +KPX Udieresis Amacron -40 +KPX Udieresis Aogonek -40 +KPX Udieresis Aring -40 +KPX Udieresis Atilde -40 +KPX Ugrave A -40 +KPX Ugrave Aacute -40 +KPX Ugrave Abreve -40 +KPX Ugrave Acircumflex -40 +KPX Ugrave Adieresis -40 +KPX Ugrave Agrave -40 +KPX Ugrave Amacron -40 +KPX Ugrave Aogonek -40 +KPX Ugrave Aring -40 +KPX Ugrave Atilde -40 +KPX Uhungarumlaut A -40 +KPX Uhungarumlaut Aacute -40 +KPX Uhungarumlaut Abreve -40 +KPX Uhungarumlaut Acircumflex -40 +KPX Uhungarumlaut Adieresis -40 +KPX Uhungarumlaut Agrave -40 +KPX Uhungarumlaut Amacron -40 +KPX Uhungarumlaut Aogonek -40 +KPX Uhungarumlaut Aring -40 +KPX Uhungarumlaut Atilde -40 +KPX Umacron A -40 +KPX Umacron Aacute -40 +KPX Umacron Abreve -40 +KPX Umacron Acircumflex -40 +KPX Umacron Adieresis -40 +KPX Umacron Agrave -40 +KPX Umacron Amacron -40 +KPX Umacron Aogonek -40 +KPX Umacron Aring -40 +KPX Umacron Atilde -40 +KPX Uogonek A -40 +KPX Uogonek Aacute -40 +KPX Uogonek Abreve -40 +KPX Uogonek Acircumflex -40 +KPX Uogonek Adieresis -40 +KPX Uogonek Agrave -40 +KPX Uogonek Amacron -40 +KPX Uogonek Aogonek -40 +KPX Uogonek Aring -40 +KPX Uogonek Atilde -40 +KPX Uring A -40 +KPX Uring Aacute -40 +KPX Uring Abreve -40 +KPX Uring Acircumflex -40 +KPX Uring Adieresis -40 +KPX Uring Agrave -40 +KPX Uring Amacron -40 +KPX Uring Aogonek -40 +KPX Uring Aring -40 +KPX Uring Atilde -40 +KPX V A -135 +KPX V Aacute -135 +KPX V Abreve -135 +KPX V Acircumflex -135 +KPX V Adieresis -135 +KPX V Agrave -135 +KPX V Amacron -135 +KPX V Aogonek -135 +KPX V Aring -135 +KPX V Atilde -135 +KPX V G -15 +KPX V Gbreve -15 +KPX V Gcommaaccent -15 +KPX V O -40 +KPX V Oacute -40 +KPX V Ocircumflex -40 +KPX V Odieresis -40 +KPX V Ograve -40 +KPX V Ohungarumlaut -40 +KPX V Omacron -40 +KPX V Oslash -40 +KPX V Otilde -40 +KPX V a -111 +KPX V aacute -111 +KPX V abreve -111 +KPX V acircumflex -71 +KPX V adieresis -71 +KPX V agrave -71 +KPX V amacron -71 +KPX V aogonek -111 +KPX V aring -111 +KPX V atilde -71 +KPX V colon -74 +KPX V comma -129 +KPX V e -111 +KPX V eacute -111 +KPX V ecaron -71 +KPX V ecircumflex -71 +KPX V edieresis -71 +KPX V edotaccent -111 +KPX V egrave -71 +KPX V emacron -71 +KPX V eogonek -111 +KPX V hyphen -100 +KPX V i -60 +KPX V iacute -60 +KPX V icircumflex -20 +KPX V idieresis -20 +KPX V igrave -20 +KPX V imacron -20 +KPX V iogonek -60 +KPX V o -129 +KPX V oacute -129 +KPX V ocircumflex -129 +KPX V odieresis -89 +KPX V ograve -89 +KPX V ohungarumlaut -129 +KPX V omacron -89 +KPX V oslash -129 +KPX V otilde -89 +KPX V period -129 +KPX V semicolon -74 +KPX V u -75 +KPX V uacute -75 +KPX V ucircumflex -75 +KPX V udieresis -75 +KPX V ugrave -75 +KPX V uhungarumlaut -75 +KPX V umacron -75 +KPX V uogonek -75 +KPX V uring -75 +KPX W A -120 +KPX W Aacute -120 +KPX W Abreve -120 +KPX W Acircumflex -120 +KPX W Adieresis -120 +KPX W Agrave -120 +KPX W Amacron -120 +KPX W Aogonek -120 +KPX W Aring -120 +KPX W Atilde -120 +KPX W O -10 +KPX W Oacute -10 +KPX W Ocircumflex -10 +KPX W Odieresis -10 +KPX W Ograve -10 +KPX W Ohungarumlaut -10 +KPX W Omacron -10 +KPX W Oslash -10 +KPX W Otilde -10 +KPX W a -80 +KPX W aacute -80 +KPX W abreve -80 +KPX W acircumflex -80 +KPX W adieresis -80 +KPX W agrave -80 +KPX W amacron -80 +KPX W aogonek -80 +KPX W aring -80 +KPX W atilde -80 +KPX W colon -37 +KPX W comma -92 +KPX W e -80 +KPX W eacute -80 +KPX W ecaron -80 +KPX W ecircumflex -80 +KPX W edieresis -40 +KPX W edotaccent -80 +KPX W egrave -40 +KPX W emacron -40 +KPX W eogonek -80 +KPX W hyphen -65 +KPX W i -40 +KPX W iacute -40 +KPX W iogonek -40 +KPX W o -80 +KPX W oacute -80 +KPX W ocircumflex -80 +KPX W odieresis -80 +KPX W ograve -80 +KPX W ohungarumlaut -80 +KPX W omacron -80 +KPX W oslash -80 +KPX W otilde -80 +KPX W period -92 +KPX W semicolon -37 +KPX W u -50 +KPX W uacute -50 +KPX W ucircumflex -50 +KPX W udieresis -50 +KPX W ugrave -50 +KPX W uhungarumlaut -50 +KPX W umacron -50 +KPX W uogonek -50 +KPX W uring -50 +KPX W y -73 +KPX W yacute -73 +KPX W ydieresis -73 +KPX Y A -120 +KPX Y Aacute -120 +KPX Y Abreve -120 +KPX Y Acircumflex -120 +KPX Y Adieresis -120 +KPX Y Agrave -120 +KPX Y Amacron -120 +KPX Y Aogonek -120 +KPX Y Aring -120 +KPX Y Atilde -120 +KPX Y O -30 +KPX Y Oacute -30 +KPX Y Ocircumflex -30 +KPX Y Odieresis -30 +KPX Y Ograve -30 +KPX Y Ohungarumlaut -30 +KPX Y Omacron -30 +KPX Y Oslash -30 +KPX Y Otilde -30 +KPX Y a -100 +KPX Y aacute -100 +KPX Y abreve -100 +KPX Y acircumflex -100 +KPX Y adieresis -60 +KPX Y agrave -60 +KPX Y amacron -60 +KPX Y aogonek -100 +KPX Y aring -100 +KPX Y atilde -60 +KPX Y colon -92 +KPX Y comma -129 +KPX Y e -100 +KPX Y eacute -100 +KPX Y ecaron -100 +KPX Y ecircumflex -100 +KPX Y edieresis -60 +KPX Y edotaccent -100 +KPX Y egrave -60 +KPX Y emacron -60 +KPX Y eogonek -100 +KPX Y hyphen -111 +KPX Y i -55 +KPX Y iacute -55 +KPX Y iogonek -55 +KPX Y o -110 +KPX Y oacute -110 +KPX Y ocircumflex -110 +KPX Y odieresis -70 +KPX Y ograve -70 +KPX Y ohungarumlaut -110 +KPX Y omacron -70 +KPX Y oslash -110 +KPX Y otilde -70 +KPX Y period -129 +KPX Y semicolon -92 +KPX Y u -111 +KPX Y uacute -111 +KPX Y ucircumflex -111 +KPX Y udieresis -71 +KPX Y ugrave -71 +KPX Y uhungarumlaut -111 +KPX Y umacron -71 +KPX Y uogonek -111 +KPX Y uring -111 +KPX Yacute A -120 +KPX Yacute Aacute -120 +KPX Yacute Abreve -120 +KPX Yacute Acircumflex -120 +KPX Yacute Adieresis -120 +KPX Yacute Agrave -120 +KPX Yacute Amacron -120 +KPX Yacute Aogonek -120 +KPX Yacute Aring -120 +KPX Yacute Atilde -120 +KPX Yacute O -30 +KPX Yacute Oacute -30 +KPX Yacute Ocircumflex -30 +KPX Yacute Odieresis -30 +KPX Yacute Ograve -30 +KPX Yacute Ohungarumlaut -30 +KPX Yacute Omacron -30 +KPX Yacute Oslash -30 +KPX Yacute Otilde -30 +KPX Yacute a -100 +KPX Yacute aacute -100 +KPX Yacute abreve -100 +KPX Yacute acircumflex -100 +KPX Yacute adieresis -60 +KPX Yacute agrave -60 +KPX Yacute amacron -60 +KPX Yacute aogonek -100 +KPX Yacute aring -100 +KPX Yacute atilde -60 +KPX Yacute colon -92 +KPX Yacute comma -129 +KPX Yacute e -100 +KPX Yacute eacute -100 +KPX Yacute ecaron -100 +KPX Yacute ecircumflex -100 +KPX Yacute edieresis -60 +KPX Yacute edotaccent -100 +KPX Yacute egrave -60 +KPX Yacute emacron -60 +KPX Yacute eogonek -100 +KPX Yacute hyphen -111 +KPX Yacute i -55 +KPX Yacute iacute -55 +KPX Yacute iogonek -55 +KPX Yacute o -110 +KPX Yacute oacute -110 +KPX Yacute ocircumflex -110 +KPX Yacute odieresis -70 +KPX Yacute ograve -70 +KPX Yacute ohungarumlaut -110 +KPX Yacute omacron -70 +KPX Yacute oslash -110 +KPX Yacute otilde -70 +KPX Yacute period -129 +KPX Yacute semicolon -92 +KPX Yacute u -111 +KPX Yacute uacute -111 +KPX Yacute ucircumflex -111 +KPX Yacute udieresis -71 +KPX Yacute ugrave -71 +KPX Yacute uhungarumlaut -111 +KPX Yacute umacron -71 +KPX Yacute uogonek -111 +KPX Yacute uring -111 +KPX Ydieresis A -120 +KPX Ydieresis Aacute -120 +KPX Ydieresis Abreve -120 +KPX Ydieresis Acircumflex -120 +KPX Ydieresis Adieresis -120 +KPX Ydieresis Agrave -120 +KPX Ydieresis Amacron -120 +KPX Ydieresis Aogonek -120 +KPX Ydieresis Aring -120 +KPX Ydieresis Atilde -120 +KPX Ydieresis O -30 +KPX Ydieresis Oacute -30 +KPX Ydieresis Ocircumflex -30 +KPX Ydieresis Odieresis -30 +KPX Ydieresis Ograve -30 +KPX Ydieresis Ohungarumlaut -30 +KPX Ydieresis Omacron -30 +KPX Ydieresis Oslash -30 +KPX Ydieresis Otilde -30 +KPX Ydieresis a -100 +KPX Ydieresis aacute -100 +KPX Ydieresis abreve -100 +KPX Ydieresis acircumflex -100 +KPX Ydieresis adieresis -60 +KPX Ydieresis agrave -60 +KPX Ydieresis amacron -60 +KPX Ydieresis aogonek -100 +KPX Ydieresis aring -100 +KPX Ydieresis atilde -100 +KPX Ydieresis colon -92 +KPX Ydieresis comma -129 +KPX Ydieresis e -100 +KPX Ydieresis eacute -100 +KPX Ydieresis ecaron -100 +KPX Ydieresis ecircumflex -100 +KPX Ydieresis edieresis -60 +KPX Ydieresis edotaccent -100 +KPX Ydieresis egrave -60 +KPX Ydieresis emacron -60 +KPX Ydieresis eogonek -100 +KPX Ydieresis hyphen -111 +KPX Ydieresis i -55 +KPX Ydieresis iacute -55 +KPX Ydieresis iogonek -55 +KPX Ydieresis o -110 +KPX Ydieresis oacute -110 +KPX Ydieresis ocircumflex -110 +KPX Ydieresis odieresis -70 +KPX Ydieresis ograve -70 +KPX Ydieresis ohungarumlaut -110 +KPX Ydieresis omacron -70 +KPX Ydieresis oslash -110 +KPX Ydieresis otilde -70 +KPX Ydieresis period -129 +KPX Ydieresis semicolon -92 +KPX Ydieresis u -111 +KPX Ydieresis uacute -111 +KPX Ydieresis ucircumflex -111 +KPX Ydieresis udieresis -71 +KPX Ydieresis ugrave -71 +KPX Ydieresis uhungarumlaut -111 +KPX Ydieresis umacron -71 +KPX Ydieresis uogonek -111 +KPX Ydieresis uring -111 +KPX a v -20 +KPX a w -15 +KPX aacute v -20 +KPX aacute w -15 +KPX abreve v -20 +KPX abreve w -15 +KPX acircumflex v -20 +KPX acircumflex w -15 +KPX adieresis v -20 +KPX adieresis w -15 +KPX agrave v -20 +KPX agrave w -15 +KPX amacron v -20 +KPX amacron w -15 +KPX aogonek v -20 +KPX aogonek w -15 +KPX aring v -20 +KPX aring w -15 +KPX atilde v -20 +KPX atilde w -15 +KPX b period -40 +KPX b u -20 +KPX b uacute -20 +KPX b ucircumflex -20 +KPX b udieresis -20 +KPX b ugrave -20 +KPX b uhungarumlaut -20 +KPX b umacron -20 +KPX b uogonek -20 +KPX b uring -20 +KPX b v -15 +KPX c y -15 +KPX c yacute -15 +KPX c ydieresis -15 +KPX cacute y -15 +KPX cacute yacute -15 +KPX cacute ydieresis -15 +KPX ccaron y -15 +KPX ccaron yacute -15 +KPX ccaron ydieresis -15 +KPX ccedilla y -15 +KPX ccedilla yacute -15 +KPX ccedilla ydieresis -15 +KPX comma quotedblright -70 +KPX comma quoteright -70 +KPX e g -15 +KPX e gbreve -15 +KPX e gcommaaccent -15 +KPX e v -25 +KPX e w -25 +KPX e x -15 +KPX e y -15 +KPX e yacute -15 +KPX e ydieresis -15 +KPX eacute g -15 +KPX eacute gbreve -15 +KPX eacute gcommaaccent -15 +KPX eacute v -25 +KPX eacute w -25 +KPX eacute x -15 +KPX eacute y -15 +KPX eacute yacute -15 +KPX eacute ydieresis -15 +KPX ecaron g -15 +KPX ecaron gbreve -15 +KPX ecaron gcommaaccent -15 +KPX ecaron v -25 +KPX ecaron w -25 +KPX ecaron x -15 +KPX ecaron y -15 +KPX ecaron yacute -15 +KPX ecaron ydieresis -15 +KPX ecircumflex g -15 +KPX ecircumflex gbreve -15 +KPX ecircumflex gcommaaccent -15 +KPX ecircumflex v -25 +KPX ecircumflex w -25 +KPX ecircumflex x -15 +KPX ecircumflex y -15 +KPX ecircumflex yacute -15 +KPX ecircumflex ydieresis -15 +KPX edieresis g -15 +KPX edieresis gbreve -15 +KPX edieresis gcommaaccent -15 +KPX edieresis v -25 +KPX edieresis w -25 +KPX edieresis x -15 +KPX edieresis y -15 +KPX edieresis yacute -15 +KPX edieresis ydieresis -15 +KPX edotaccent g -15 +KPX edotaccent gbreve -15 +KPX edotaccent gcommaaccent -15 +KPX edotaccent v -25 +KPX edotaccent w -25 +KPX edotaccent x -15 +KPX edotaccent y -15 +KPX edotaccent yacute -15 +KPX edotaccent ydieresis -15 +KPX egrave g -15 +KPX egrave gbreve -15 +KPX egrave gcommaaccent -15 +KPX egrave v -25 +KPX egrave w -25 +KPX egrave x -15 +KPX egrave y -15 +KPX egrave yacute -15 +KPX egrave ydieresis -15 +KPX emacron g -15 +KPX emacron gbreve -15 +KPX emacron gcommaaccent -15 +KPX emacron v -25 +KPX emacron w -25 +KPX emacron x -15 +KPX emacron y -15 +KPX emacron yacute -15 +KPX emacron ydieresis -15 +KPX eogonek g -15 +KPX eogonek gbreve -15 +KPX eogonek gcommaaccent -15 +KPX eogonek v -25 +KPX eogonek w -25 +KPX eogonek x -15 +KPX eogonek y -15 +KPX eogonek yacute -15 +KPX eogonek ydieresis -15 +KPX f a -10 +KPX f aacute -10 +KPX f abreve -10 +KPX f acircumflex -10 +KPX f adieresis -10 +KPX f agrave -10 +KPX f amacron -10 +KPX f aogonek -10 +KPX f aring -10 +KPX f atilde -10 +KPX f dotlessi -50 +KPX f f -25 +KPX f i -20 +KPX f iacute -20 +KPX f quoteright 55 +KPX g a -5 +KPX g aacute -5 +KPX g abreve -5 +KPX g acircumflex -5 +KPX g adieresis -5 +KPX g agrave -5 +KPX g amacron -5 +KPX g aogonek -5 +KPX g aring -5 +KPX g atilde -5 +KPX gbreve a -5 +KPX gbreve aacute -5 +KPX gbreve abreve -5 +KPX gbreve acircumflex -5 +KPX gbreve adieresis -5 +KPX gbreve agrave -5 +KPX gbreve amacron -5 +KPX gbreve aogonek -5 +KPX gbreve aring -5 +KPX gbreve atilde -5 +KPX gcommaaccent a -5 +KPX gcommaaccent aacute -5 +KPX gcommaaccent abreve -5 +KPX gcommaaccent acircumflex -5 +KPX gcommaaccent adieresis -5 +KPX gcommaaccent agrave -5 +KPX gcommaaccent amacron -5 +KPX gcommaaccent aogonek -5 +KPX gcommaaccent aring -5 +KPX gcommaaccent atilde -5 +KPX h y -5 +KPX h yacute -5 +KPX h ydieresis -5 +KPX i v -25 +KPX iacute v -25 +KPX icircumflex v -25 +KPX idieresis v -25 +KPX igrave v -25 +KPX imacron v -25 +KPX iogonek v -25 +KPX k e -10 +KPX k eacute -10 +KPX k ecaron -10 +KPX k ecircumflex -10 +KPX k edieresis -10 +KPX k edotaccent -10 +KPX k egrave -10 +KPX k emacron -10 +KPX k eogonek -10 +KPX k o -10 +KPX k oacute -10 +KPX k ocircumflex -10 +KPX k odieresis -10 +KPX k ograve -10 +KPX k ohungarumlaut -10 +KPX k omacron -10 +KPX k oslash -10 +KPX k otilde -10 +KPX k y -15 +KPX k yacute -15 +KPX k ydieresis -15 +KPX kcommaaccent e -10 +KPX kcommaaccent eacute -10 +KPX kcommaaccent ecaron -10 +KPX kcommaaccent ecircumflex -10 +KPX kcommaaccent edieresis -10 +KPX kcommaaccent edotaccent -10 +KPX kcommaaccent egrave -10 +KPX kcommaaccent emacron -10 +KPX kcommaaccent eogonek -10 +KPX kcommaaccent o -10 +KPX kcommaaccent oacute -10 +KPX kcommaaccent ocircumflex -10 +KPX kcommaaccent odieresis -10 +KPX kcommaaccent ograve -10 +KPX kcommaaccent ohungarumlaut -10 +KPX kcommaaccent omacron -10 +KPX kcommaaccent oslash -10 +KPX kcommaaccent otilde -10 +KPX kcommaaccent y -15 +KPX kcommaaccent yacute -15 +KPX kcommaaccent ydieresis -15 +KPX l w -10 +KPX lacute w -10 +KPX lcommaaccent w -10 +KPX lslash w -10 +KPX n v -40 +KPX n y -15 +KPX n yacute -15 +KPX n ydieresis -15 +KPX nacute v -40 +KPX nacute y -15 +KPX nacute yacute -15 +KPX nacute ydieresis -15 +KPX ncaron v -40 +KPX ncaron y -15 +KPX ncaron yacute -15 +KPX ncaron ydieresis -15 +KPX ncommaaccent v -40 +KPX ncommaaccent y -15 +KPX ncommaaccent yacute -15 +KPX ncommaaccent ydieresis -15 +KPX ntilde v -40 +KPX ntilde y -15 +KPX ntilde yacute -15 +KPX ntilde ydieresis -15 +KPX o v -15 +KPX o w -25 +KPX o y -10 +KPX o yacute -10 +KPX o ydieresis -10 +KPX oacute v -15 +KPX oacute w -25 +KPX oacute y -10 +KPX oacute yacute -10 +KPX oacute ydieresis -10 +KPX ocircumflex v -15 +KPX ocircumflex w -25 +KPX ocircumflex y -10 +KPX ocircumflex yacute -10 +KPX ocircumflex ydieresis -10 +KPX odieresis v -15 +KPX odieresis w -25 +KPX odieresis y -10 +KPX odieresis yacute -10 +KPX odieresis ydieresis -10 +KPX ograve v -15 +KPX ograve w -25 +KPX ograve y -10 +KPX ograve yacute -10 +KPX ograve ydieresis -10 +KPX ohungarumlaut v -15 +KPX ohungarumlaut w -25 +KPX ohungarumlaut y -10 +KPX ohungarumlaut yacute -10 +KPX ohungarumlaut ydieresis -10 +KPX omacron v -15 +KPX omacron w -25 +KPX omacron y -10 +KPX omacron yacute -10 +KPX omacron ydieresis -10 +KPX oslash v -15 +KPX oslash w -25 +KPX oslash y -10 +KPX oslash yacute -10 +KPX oslash ydieresis -10 +KPX otilde v -15 +KPX otilde w -25 +KPX otilde y -10 +KPX otilde yacute -10 +KPX otilde ydieresis -10 +KPX p y -10 +KPX p yacute -10 +KPX p ydieresis -10 +KPX period quotedblright -70 +KPX period quoteright -70 +KPX quotedblleft A -80 +KPX quotedblleft Aacute -80 +KPX quotedblleft Abreve -80 +KPX quotedblleft Acircumflex -80 +KPX quotedblleft Adieresis -80 +KPX quotedblleft Agrave -80 +KPX quotedblleft Amacron -80 +KPX quotedblleft Aogonek -80 +KPX quotedblleft Aring -80 +KPX quotedblleft Atilde -80 +KPX quoteleft A -80 +KPX quoteleft Aacute -80 +KPX quoteleft Abreve -80 +KPX quoteleft Acircumflex -80 +KPX quoteleft Adieresis -80 +KPX quoteleft Agrave -80 +KPX quoteleft Amacron -80 +KPX quoteleft Aogonek -80 +KPX quoteleft Aring -80 +KPX quoteleft Atilde -80 +KPX quoteleft quoteleft -74 +KPX quoteright d -50 +KPX quoteright dcroat -50 +KPX quoteright l -10 +KPX quoteright lacute -10 +KPX quoteright lcommaaccent -10 +KPX quoteright lslash -10 +KPX quoteright quoteright -74 +KPX quoteright r -50 +KPX quoteright racute -50 +KPX quoteright rcaron -50 +KPX quoteright rcommaaccent -50 +KPX quoteright s -55 +KPX quoteright sacute -55 +KPX quoteright scaron -55 +KPX quoteright scedilla -55 +KPX quoteright scommaaccent -55 +KPX quoteright space -74 +KPX quoteright t -18 +KPX quoteright tcommaaccent -18 +KPX quoteright v -50 +KPX r comma -40 +KPX r g -18 +KPX r gbreve -18 +KPX r gcommaaccent -18 +KPX r hyphen -20 +KPX r period -55 +KPX racute comma -40 +KPX racute g -18 +KPX racute gbreve -18 +KPX racute gcommaaccent -18 +KPX racute hyphen -20 +KPX racute period -55 +KPX rcaron comma -40 +KPX rcaron g -18 +KPX rcaron gbreve -18 +KPX rcaron gcommaaccent -18 +KPX rcaron hyphen -20 +KPX rcaron period -55 +KPX rcommaaccent comma -40 +KPX rcommaaccent g -18 +KPX rcommaaccent gbreve -18 +KPX rcommaaccent gcommaaccent -18 +KPX rcommaaccent hyphen -20 +KPX rcommaaccent period -55 +KPX space A -55 +KPX space Aacute -55 +KPX space Abreve -55 +KPX space Acircumflex -55 +KPX space Adieresis -55 +KPX space Agrave -55 +KPX space Amacron -55 +KPX space Aogonek -55 +KPX space Aring -55 +KPX space Atilde -55 +KPX space T -18 +KPX space Tcaron -18 +KPX space Tcommaaccent -18 +KPX space V -50 +KPX space W -30 +KPX space Y -90 +KPX space Yacute -90 +KPX space Ydieresis -90 +KPX v a -25 +KPX v aacute -25 +KPX v abreve -25 +KPX v acircumflex -25 +KPX v adieresis -25 +KPX v agrave -25 +KPX v amacron -25 +KPX v aogonek -25 +KPX v aring -25 +KPX v atilde -25 +KPX v comma -65 +KPX v e -15 +KPX v eacute -15 +KPX v ecaron -15 +KPX v ecircumflex -15 +KPX v edieresis -15 +KPX v edotaccent -15 +KPX v egrave -15 +KPX v emacron -15 +KPX v eogonek -15 +KPX v o -20 +KPX v oacute -20 +KPX v ocircumflex -20 +KPX v odieresis -20 +KPX v ograve -20 +KPX v ohungarumlaut -20 +KPX v omacron -20 +KPX v oslash -20 +KPX v otilde -20 +KPX v period -65 +KPX w a -10 +KPX w aacute -10 +KPX w abreve -10 +KPX w acircumflex -10 +KPX w adieresis -10 +KPX w agrave -10 +KPX w amacron -10 +KPX w aogonek -10 +KPX w aring -10 +KPX w atilde -10 +KPX w comma -65 +KPX w o -10 +KPX w oacute -10 +KPX w ocircumflex -10 +KPX w odieresis -10 +KPX w ograve -10 +KPX w ohungarumlaut -10 +KPX w omacron -10 +KPX w oslash -10 +KPX w otilde -10 +KPX w period -65 +KPX x e -15 +KPX x eacute -15 +KPX x ecaron -15 +KPX x ecircumflex -15 +KPX x edieresis -15 +KPX x edotaccent -15 +KPX x egrave -15 +KPX x emacron -15 +KPX x eogonek -15 +KPX y comma -65 +KPX y period -65 +KPX yacute comma -65 +KPX yacute period -65 +KPX ydieresis comma -65 +KPX ydieresis period -65 +EndKernPairs +EndKernData +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/ZapfDingbats.afm b/iTechSharp/iTextSharp/text/pdf/fonts/ZapfDingbats.afm new file mode 100644 index 0000000..b274505 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/ZapfDingbats.afm @@ -0,0 +1,225 @@ +StartFontMetrics 4.1 +Comment Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved. +Comment Creation Date: Thu May 1 15:14:13 1997 +Comment UniqueID 43082 +Comment VMusage 45775 55535 +FontName ZapfDingbats +FullName ITC Zapf Dingbats +FamilyName ZapfDingbats +Weight Medium +ItalicAngle 0 +IsFixedPitch false +CharacterSet Special +FontBBox -1 -143 981 820 +UnderlinePosition -100 +UnderlineThickness 50 +Version 002.000 +Notice Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation. +EncodingScheme FontSpecific +StdHW 28 +StdVW 90 +StartCharMetrics 202 +C 32 ; WX 278 ; N space ; B 0 0 0 0 ; +C 33 ; WX 974 ; N a1 ; B 35 72 939 621 ; +C 34 ; WX 961 ; N a2 ; B 35 81 927 611 ; +C 35 ; WX 974 ; N a202 ; B 35 72 939 621 ; +C 36 ; WX 980 ; N a3 ; B 35 0 945 692 ; +C 37 ; WX 719 ; N a4 ; B 34 139 685 566 ; +C 38 ; WX 789 ; N a5 ; B 35 -14 755 705 ; +C 39 ; WX 790 ; N a119 ; B 35 -14 755 705 ; +C 40 ; WX 791 ; N a118 ; B 35 -13 761 705 ; +C 41 ; WX 690 ; N a117 ; B 34 138 655 553 ; +C 42 ; WX 960 ; N a11 ; B 35 123 925 568 ; +C 43 ; WX 939 ; N a12 ; B 35 134 904 559 ; +C 44 ; WX 549 ; N a13 ; B 29 -11 516 705 ; +C 45 ; WX 855 ; N a14 ; B 34 59 820 632 ; +C 46 ; WX 911 ; N a15 ; B 35 50 876 642 ; +C 47 ; WX 933 ; N a16 ; B 35 139 899 550 ; +C 48 ; WX 911 ; N a105 ; B 35 50 876 642 ; +C 49 ; WX 945 ; N a17 ; B 35 139 909 553 ; +C 50 ; WX 974 ; N a18 ; B 35 104 938 587 ; +C 51 ; WX 755 ; N a19 ; B 34 -13 721 705 ; +C 52 ; WX 846 ; N a20 ; B 36 -14 811 705 ; +C 53 ; WX 762 ; N a21 ; B 35 0 727 692 ; +C 54 ; WX 761 ; N a22 ; B 35 0 727 692 ; +C 55 ; WX 571 ; N a23 ; B -1 -68 571 661 ; +C 56 ; WX 677 ; N a24 ; B 36 -13 642 705 ; +C 57 ; WX 763 ; N a25 ; B 35 0 728 692 ; +C 58 ; WX 760 ; N a26 ; B 35 0 726 692 ; +C 59 ; WX 759 ; N a27 ; B 35 0 725 692 ; +C 60 ; WX 754 ; N a28 ; B 35 0 720 692 ; +C 61 ; WX 494 ; N a6 ; B 35 0 460 692 ; +C 62 ; WX 552 ; N a7 ; B 35 0 517 692 ; +C 63 ; WX 537 ; N a8 ; B 35 0 503 692 ; +C 64 ; WX 577 ; N a9 ; B 35 96 542 596 ; +C 65 ; WX 692 ; N a10 ; B 35 -14 657 705 ; +C 66 ; WX 786 ; N a29 ; B 35 -14 751 705 ; +C 67 ; WX 788 ; N a30 ; B 35 -14 752 705 ; +C 68 ; WX 788 ; N a31 ; B 35 -14 753 705 ; +C 69 ; WX 790 ; N a32 ; B 35 -14 756 705 ; +C 70 ; WX 793 ; N a33 ; B 35 -13 759 705 ; +C 71 ; WX 794 ; N a34 ; B 35 -13 759 705 ; +C 72 ; WX 816 ; N a35 ; B 35 -14 782 705 ; +C 73 ; WX 823 ; N a36 ; B 35 -14 787 705 ; +C 74 ; WX 789 ; N a37 ; B 35 -14 754 705 ; +C 75 ; WX 841 ; N a38 ; B 35 -14 807 705 ; +C 76 ; WX 823 ; N a39 ; B 35 -14 789 705 ; +C 77 ; WX 833 ; N a40 ; B 35 -14 798 705 ; +C 78 ; WX 816 ; N a41 ; B 35 -13 782 705 ; +C 79 ; WX 831 ; N a42 ; B 35 -14 796 705 ; +C 80 ; WX 923 ; N a43 ; B 35 -14 888 705 ; +C 81 ; WX 744 ; N a44 ; B 35 0 710 692 ; +C 82 ; WX 723 ; N a45 ; B 35 0 688 692 ; +C 83 ; WX 749 ; N a46 ; B 35 0 714 692 ; +C 84 ; WX 790 ; N a47 ; B 34 -14 756 705 ; +C 85 ; WX 792 ; N a48 ; B 35 -14 758 705 ; +C 86 ; WX 695 ; N a49 ; B 35 -14 661 706 ; +C 87 ; WX 776 ; N a50 ; B 35 -6 741 699 ; +C 88 ; WX 768 ; N a51 ; B 35 -7 734 699 ; +C 89 ; WX 792 ; N a52 ; B 35 -14 757 705 ; +C 90 ; WX 759 ; N a53 ; B 35 0 725 692 ; +C 91 ; WX 707 ; N a54 ; B 35 -13 672 704 ; +C 92 ; WX 708 ; N a55 ; B 35 -14 672 705 ; +C 93 ; WX 682 ; N a56 ; B 35 -14 647 705 ; +C 94 ; WX 701 ; N a57 ; B 35 -14 666 705 ; +C 95 ; WX 826 ; N a58 ; B 35 -14 791 705 ; +C 96 ; WX 815 ; N a59 ; B 35 -14 780 705 ; +C 97 ; WX 789 ; N a60 ; B 35 -14 754 705 ; +C 98 ; WX 789 ; N a61 ; B 35 -14 754 705 ; +C 99 ; WX 707 ; N a62 ; B 34 -14 673 705 ; +C 100 ; WX 687 ; N a63 ; B 36 0 651 692 ; +C 101 ; WX 696 ; N a64 ; B 35 0 661 691 ; +C 102 ; WX 689 ; N a65 ; B 35 0 655 692 ; +C 103 ; WX 786 ; N a66 ; B 34 -14 751 705 ; +C 104 ; WX 787 ; N a67 ; B 35 -14 752 705 ; +C 105 ; WX 713 ; N a68 ; B 35 -14 678 705 ; +C 106 ; WX 791 ; N a69 ; B 35 -14 756 705 ; +C 107 ; WX 785 ; N a70 ; B 36 -14 751 705 ; +C 108 ; WX 791 ; N a71 ; B 35 -14 757 705 ; +C 109 ; WX 873 ; N a72 ; B 35 -14 838 705 ; +C 110 ; WX 761 ; N a73 ; B 35 0 726 692 ; +C 111 ; WX 762 ; N a74 ; B 35 0 727 692 ; +C 112 ; WX 762 ; N a203 ; B 35 0 727 692 ; +C 113 ; WX 759 ; N a75 ; B 35 0 725 692 ; +C 114 ; WX 759 ; N a204 ; B 35 0 725 692 ; +C 115 ; WX 892 ; N a76 ; B 35 0 858 705 ; +C 116 ; WX 892 ; N a77 ; B 35 -14 858 692 ; +C 117 ; WX 788 ; N a78 ; B 35 -14 754 705 ; +C 118 ; WX 784 ; N a79 ; B 35 -14 749 705 ; +C 119 ; WX 438 ; N a81 ; B 35 -14 403 705 ; +C 120 ; WX 138 ; N a82 ; B 35 0 104 692 ; +C 121 ; WX 277 ; N a83 ; B 35 0 242 692 ; +C 122 ; WX 415 ; N a84 ; B 35 0 380 692 ; +C 123 ; WX 392 ; N a97 ; B 35 263 357 705 ; +C 124 ; WX 392 ; N a98 ; B 34 263 357 705 ; +C 125 ; WX 668 ; N a99 ; B 35 263 633 705 ; +C 126 ; WX 668 ; N a100 ; B 36 263 634 705 ; +C 128 ; WX 390 ; N a89 ; B 35 -14 356 705 ; +C 129 ; WX 390 ; N a90 ; B 35 -14 355 705 ; +C 130 ; WX 317 ; N a93 ; B 35 0 283 692 ; +C 131 ; WX 317 ; N a94 ; B 35 0 283 692 ; +C 132 ; WX 276 ; N a91 ; B 35 0 242 692 ; +C 133 ; WX 276 ; N a92 ; B 35 0 242 692 ; +C 134 ; WX 509 ; N a205 ; B 35 0 475 692 ; +C 135 ; WX 509 ; N a85 ; B 35 0 475 692 ; +C 136 ; WX 410 ; N a206 ; B 35 0 375 692 ; +C 137 ; WX 410 ; N a86 ; B 35 0 375 692 ; +C 138 ; WX 234 ; N a87 ; B 35 -14 199 705 ; +C 139 ; WX 234 ; N a88 ; B 35 -14 199 705 ; +C 140 ; WX 334 ; N a95 ; B 35 0 299 692 ; +C 141 ; WX 334 ; N a96 ; B 35 0 299 692 ; +C 161 ; WX 732 ; N a101 ; B 35 -143 697 806 ; +C 162 ; WX 544 ; N a102 ; B 56 -14 488 706 ; +C 163 ; WX 544 ; N a103 ; B 34 -14 508 705 ; +C 164 ; WX 910 ; N a104 ; B 35 40 875 651 ; +C 165 ; WX 667 ; N a106 ; B 35 -14 633 705 ; +C 166 ; WX 760 ; N a107 ; B 35 -14 726 705 ; +C 167 ; WX 760 ; N a108 ; B 0 121 758 569 ; +C 168 ; WX 776 ; N a112 ; B 35 0 741 705 ; +C 169 ; WX 595 ; N a111 ; B 34 -14 560 705 ; +C 170 ; WX 694 ; N a110 ; B 35 -14 659 705 ; +C 171 ; WX 626 ; N a109 ; B 34 0 591 705 ; +C 172 ; WX 788 ; N a120 ; B 35 -14 754 705 ; +C 173 ; WX 788 ; N a121 ; B 35 -14 754 705 ; +C 174 ; WX 788 ; N a122 ; B 35 -14 754 705 ; +C 175 ; WX 788 ; N a123 ; B 35 -14 754 705 ; +C 176 ; WX 788 ; N a124 ; B 35 -14 754 705 ; +C 177 ; WX 788 ; N a125 ; B 35 -14 754 705 ; +C 178 ; WX 788 ; N a126 ; B 35 -14 754 705 ; +C 179 ; WX 788 ; N a127 ; B 35 -14 754 705 ; +C 180 ; WX 788 ; N a128 ; B 35 -14 754 705 ; +C 181 ; WX 788 ; N a129 ; B 35 -14 754 705 ; +C 182 ; WX 788 ; N a130 ; B 35 -14 754 705 ; +C 183 ; WX 788 ; N a131 ; B 35 -14 754 705 ; +C 184 ; WX 788 ; N a132 ; B 35 -14 754 705 ; +C 185 ; WX 788 ; N a133 ; B 35 -14 754 705 ; +C 186 ; WX 788 ; N a134 ; B 35 -14 754 705 ; +C 187 ; WX 788 ; N a135 ; B 35 -14 754 705 ; +C 188 ; WX 788 ; N a136 ; B 35 -14 754 705 ; +C 189 ; WX 788 ; N a137 ; B 35 -14 754 705 ; +C 190 ; WX 788 ; N a138 ; B 35 -14 754 705 ; +C 191 ; WX 788 ; N a139 ; B 35 -14 754 705 ; +C 192 ; WX 788 ; N a140 ; B 35 -14 754 705 ; +C 193 ; WX 788 ; N a141 ; B 35 -14 754 705 ; +C 194 ; WX 788 ; N a142 ; B 35 -14 754 705 ; +C 195 ; WX 788 ; N a143 ; B 35 -14 754 705 ; +C 196 ; WX 788 ; N a144 ; B 35 -14 754 705 ; +C 197 ; WX 788 ; N a145 ; B 35 -14 754 705 ; +C 198 ; WX 788 ; N a146 ; B 35 -14 754 705 ; +C 199 ; WX 788 ; N a147 ; B 35 -14 754 705 ; +C 200 ; WX 788 ; N a148 ; B 35 -14 754 705 ; +C 201 ; WX 788 ; N a149 ; B 35 -14 754 705 ; +C 202 ; WX 788 ; N a150 ; B 35 -14 754 705 ; +C 203 ; WX 788 ; N a151 ; B 35 -14 754 705 ; +C 204 ; WX 788 ; N a152 ; B 35 -14 754 705 ; +C 205 ; WX 788 ; N a153 ; B 35 -14 754 705 ; +C 206 ; WX 788 ; N a154 ; B 35 -14 754 705 ; +C 207 ; WX 788 ; N a155 ; B 35 -14 754 705 ; +C 208 ; WX 788 ; N a156 ; B 35 -14 754 705 ; +C 209 ; WX 788 ; N a157 ; B 35 -14 754 705 ; +C 210 ; WX 788 ; N a158 ; B 35 -14 754 705 ; +C 211 ; WX 788 ; N a159 ; B 35 -14 754 705 ; +C 212 ; WX 894 ; N a160 ; B 35 58 860 634 ; +C 213 ; WX 838 ; N a161 ; B 35 152 803 540 ; +C 214 ; WX 1016 ; N a163 ; B 34 152 981 540 ; +C 215 ; WX 458 ; N a164 ; B 35 -127 422 820 ; +C 216 ; WX 748 ; N a196 ; B 35 94 698 597 ; +C 217 ; WX 924 ; N a165 ; B 35 140 890 552 ; +C 218 ; WX 748 ; N a192 ; B 35 94 698 597 ; +C 219 ; WX 918 ; N a166 ; B 35 166 884 526 ; +C 220 ; WX 927 ; N a167 ; B 35 32 892 660 ; +C 221 ; WX 928 ; N a168 ; B 35 129 891 562 ; +C 222 ; WX 928 ; N a169 ; B 35 128 893 563 ; +C 223 ; WX 834 ; N a170 ; B 35 155 799 537 ; +C 224 ; WX 873 ; N a171 ; B 35 93 838 599 ; +C 225 ; WX 828 ; N a172 ; B 35 104 791 588 ; +C 226 ; WX 924 ; N a173 ; B 35 98 889 594 ; +C 227 ; WX 924 ; N a162 ; B 35 98 889 594 ; +C 228 ; WX 917 ; N a174 ; B 35 0 882 692 ; +C 229 ; WX 930 ; N a175 ; B 35 84 896 608 ; +C 230 ; WX 931 ; N a176 ; B 35 84 896 608 ; +C 231 ; WX 463 ; N a177 ; B 35 -99 429 791 ; +C 232 ; WX 883 ; N a178 ; B 35 71 848 623 ; +C 233 ; WX 836 ; N a179 ; B 35 44 802 648 ; +C 234 ; WX 836 ; N a193 ; B 35 44 802 648 ; +C 235 ; WX 867 ; N a180 ; B 35 101 832 591 ; +C 236 ; WX 867 ; N a199 ; B 35 101 832 591 ; +C 237 ; WX 696 ; N a181 ; B 35 44 661 648 ; +C 238 ; WX 696 ; N a200 ; B 35 44 661 648 ; +C 239 ; WX 874 ; N a182 ; B 35 77 840 619 ; +C 241 ; WX 874 ; N a201 ; B 35 73 840 615 ; +C 242 ; WX 760 ; N a183 ; B 35 0 725 692 ; +C 243 ; WX 946 ; N a184 ; B 35 160 911 533 ; +C 244 ; WX 771 ; N a197 ; B 34 37 736 655 ; +C 245 ; WX 865 ; N a185 ; B 35 207 830 481 ; +C 246 ; WX 771 ; N a194 ; B 34 37 736 655 ; +C 247 ; WX 888 ; N a198 ; B 34 -19 853 712 ; +C 248 ; WX 967 ; N a186 ; B 35 124 932 568 ; +C 249 ; WX 888 ; N a195 ; B 34 -19 853 712 ; +C 250 ; WX 831 ; N a187 ; B 35 113 796 579 ; +C 251 ; WX 873 ; N a188 ; B 36 118 838 578 ; +C 252 ; WX 927 ; N a189 ; B 35 150 891 542 ; +C 253 ; WX 970 ; N a190 ; B 35 76 931 616 ; +C 254 ; WX 918 ; N a191 ; B 34 99 884 593 ; +EndCharMetrics +EndFontMetrics diff --git a/iTechSharp/iTextSharp/text/pdf/fonts/glyphlist.txt b/iTechSharp/iTextSharp/text/pdf/fonts/glyphlist.txt new file mode 100644 index 0000000..6805d6e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/fonts/glyphlist.txt @@ -0,0 +1,5430 @@ +# Name: Adobe Glyph List +# Table version: 2.0 +# Date: September 20, 2002 +# +# See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html +# +# Format: Semicolon-delimited fields: +# (1) glyph name +# (2) Unicode scalar value +A;0041 +AE;00C6 +AEacute;01FC +AEmacron;01E2 +AEsmall;F7E6 +Aacute;00C1 +Aacutesmall;F7E1 +Abreve;0102 +Abreveacute;1EAE +Abrevecyrillic;04D0 +Abrevedotbelow;1EB6 +Abrevegrave;1EB0 +Abrevehookabove;1EB2 +Abrevetilde;1EB4 +Acaron;01CD +Acircle;24B6 +Acircumflex;00C2 +Acircumflexacute;1EA4 +Acircumflexdotbelow;1EAC +Acircumflexgrave;1EA6 +Acircumflexhookabove;1EA8 +Acircumflexsmall;F7E2 +Acircumflextilde;1EAA +Acute;F6C9 +Acutesmall;F7B4 +Acyrillic;0410 +Adblgrave;0200 +Adieresis;00C4 +Adieresiscyrillic;04D2 +Adieresismacron;01DE +Adieresissmall;F7E4 +Adotbelow;1EA0 +Adotmacron;01E0 +Agrave;00C0 +Agravesmall;F7E0 +Ahookabove;1EA2 +Aiecyrillic;04D4 +Ainvertedbreve;0202 +Alpha;0391 +Alphatonos;0386 +Amacron;0100 +Amonospace;FF21 +Aogonek;0104 +Aring;00C5 +Aringacute;01FA +Aringbelow;1E00 +Aringsmall;F7E5 +Asmall;F761 +Atilde;00C3 +Atildesmall;F7E3 +Aybarmenian;0531 +B;0042 +Bcircle;24B7 +Bdotaccent;1E02 +Bdotbelow;1E04 +Becyrillic;0411 +Benarmenian;0532 +Beta;0392 +Bhook;0181 +Blinebelow;1E06 +Bmonospace;FF22 +Brevesmall;F6F4 +Bsmall;F762 +Btopbar;0182 +C;0043 +Caarmenian;053E +Cacute;0106 +Caron;F6CA +Caronsmall;F6F5 +Ccaron;010C +Ccedilla;00C7 +Ccedillaacute;1E08 +Ccedillasmall;F7E7 +Ccircle;24B8 +Ccircumflex;0108 +Cdot;010A +Cdotaccent;010A +Cedillasmall;F7B8 +Chaarmenian;0549 +Cheabkhasiancyrillic;04BC +Checyrillic;0427 +Chedescenderabkhasiancyrillic;04BE +Chedescendercyrillic;04B6 +Chedieresiscyrillic;04F4 +Cheharmenian;0543 +Chekhakassiancyrillic;04CB +Cheverticalstrokecyrillic;04B8 +Chi;03A7 +Chook;0187 +Circumflexsmall;F6F6 +Cmonospace;FF23 +Coarmenian;0551 +Csmall;F763 +D;0044 +DZ;01F1 +DZcaron;01C4 +Daarmenian;0534 +Dafrican;0189 +Dcaron;010E +Dcedilla;1E10 +Dcircle;24B9 +Dcircumflexbelow;1E12 +Dcroat;0110 +Ddotaccent;1E0A +Ddotbelow;1E0C +Decyrillic;0414 +Deicoptic;03EE +Delta;2206 +Deltagreek;0394 +Dhook;018A +Dieresis;F6CB +DieresisAcute;F6CC +DieresisGrave;F6CD +Dieresissmall;F7A8 +Digammagreek;03DC +Djecyrillic;0402 +Dlinebelow;1E0E +Dmonospace;FF24 +Dotaccentsmall;F6F7 +Dslash;0110 +Dsmall;F764 +Dtopbar;018B +Dz;01F2 +Dzcaron;01C5 +Dzeabkhasiancyrillic;04E0 +Dzecyrillic;0405 +Dzhecyrillic;040F +E;0045 +Eacute;00C9 +Eacutesmall;F7E9 +Ebreve;0114 +Ecaron;011A +Ecedillabreve;1E1C +Echarmenian;0535 +Ecircle;24BA +Ecircumflex;00CA +Ecircumflexacute;1EBE +Ecircumflexbelow;1E18 +Ecircumflexdotbelow;1EC6 +Ecircumflexgrave;1EC0 +Ecircumflexhookabove;1EC2 +Ecircumflexsmall;F7EA +Ecircumflextilde;1EC4 +Ecyrillic;0404 +Edblgrave;0204 +Edieresis;00CB +Edieresissmall;F7EB +Edot;0116 +Edotaccent;0116 +Edotbelow;1EB8 +Efcyrillic;0424 +Egrave;00C8 +Egravesmall;F7E8 +Eharmenian;0537 +Ehookabove;1EBA +Eightroman;2167 +Einvertedbreve;0206 +Eiotifiedcyrillic;0464 +Elcyrillic;041B +Elevenroman;216A +Emacron;0112 +Emacronacute;1E16 +Emacrongrave;1E14 +Emcyrillic;041C +Emonospace;FF25 +Encyrillic;041D +Endescendercyrillic;04A2 +Eng;014A +Enghecyrillic;04A4 +Enhookcyrillic;04C7 +Eogonek;0118 +Eopen;0190 +Epsilon;0395 +Epsilontonos;0388 +Ercyrillic;0420 +Ereversed;018E +Ereversedcyrillic;042D +Escyrillic;0421 +Esdescendercyrillic;04AA +Esh;01A9 +Esmall;F765 +Eta;0397 +Etarmenian;0538 +Etatonos;0389 +Eth;00D0 +Ethsmall;F7F0 +Etilde;1EBC +Etildebelow;1E1A +Euro;20AC +Ezh;01B7 +Ezhcaron;01EE +Ezhreversed;01B8 +F;0046 +Fcircle;24BB +Fdotaccent;1E1E +Feharmenian;0556 +Feicoptic;03E4 +Fhook;0191 +Fitacyrillic;0472 +Fiveroman;2164 +Fmonospace;FF26 +Fourroman;2163 +Fsmall;F766 +G;0047 +GBsquare;3387 +Gacute;01F4 +Gamma;0393 +Gammaafrican;0194 +Gangiacoptic;03EA +Gbreve;011E +Gcaron;01E6 +Gcedilla;0122 +Gcircle;24BC +Gcircumflex;011C +Gcommaaccent;0122 +Gdot;0120 +Gdotaccent;0120 +Gecyrillic;0413 +Ghadarmenian;0542 +Ghemiddlehookcyrillic;0494 +Ghestrokecyrillic;0492 +Gheupturncyrillic;0490 +Ghook;0193 +Gimarmenian;0533 +Gjecyrillic;0403 +Gmacron;1E20 +Gmonospace;FF27 +Grave;F6CE +Gravesmall;F760 +Gsmall;F767 +Gsmallhook;029B +Gstroke;01E4 +H;0048 +H18533;25CF +H18543;25AA +H18551;25AB +H22073;25A1 +HPsquare;33CB +Haabkhasiancyrillic;04A8 +Hadescendercyrillic;04B2 +Hardsigncyrillic;042A +Hbar;0126 +Hbrevebelow;1E2A +Hcedilla;1E28 +Hcircle;24BD +Hcircumflex;0124 +Hdieresis;1E26 +Hdotaccent;1E22 +Hdotbelow;1E24 +Hmonospace;FF28 +Hoarmenian;0540 +Horicoptic;03E8 +Hsmall;F768 +Hungarumlaut;F6CF +Hungarumlautsmall;F6F8 +Hzsquare;3390 +I;0049 +IAcyrillic;042F +IJ;0132 +IUcyrillic;042E +Iacute;00CD +Iacutesmall;F7ED +Ibreve;012C +Icaron;01CF +Icircle;24BE +Icircumflex;00CE +Icircumflexsmall;F7EE +Icyrillic;0406 +Idblgrave;0208 +Idieresis;00CF +Idieresisacute;1E2E +Idieresiscyrillic;04E4 +Idieresissmall;F7EF +Idot;0130 +Idotaccent;0130 +Idotbelow;1ECA +Iebrevecyrillic;04D6 +Iecyrillic;0415 +Ifraktur;2111 +Igrave;00CC +Igravesmall;F7EC +Ihookabove;1EC8 +Iicyrillic;0418 +Iinvertedbreve;020A +Iishortcyrillic;0419 +Imacron;012A +Imacroncyrillic;04E2 +Imonospace;FF29 +Iniarmenian;053B +Iocyrillic;0401 +Iogonek;012E +Iota;0399 +Iotaafrican;0196 +Iotadieresis;03AA +Iotatonos;038A +Ismall;F769 +Istroke;0197 +Itilde;0128 +Itildebelow;1E2C +Izhitsacyrillic;0474 +Izhitsadblgravecyrillic;0476 +J;004A +Jaarmenian;0541 +Jcircle;24BF +Jcircumflex;0134 +Jecyrillic;0408 +Jheharmenian;054B +Jmonospace;FF2A +Jsmall;F76A +K;004B +KBsquare;3385 +KKsquare;33CD +Kabashkircyrillic;04A0 +Kacute;1E30 +Kacyrillic;041A +Kadescendercyrillic;049A +Kahookcyrillic;04C3 +Kappa;039A +Kastrokecyrillic;049E +Kaverticalstrokecyrillic;049C +Kcaron;01E8 +Kcedilla;0136 +Kcircle;24C0 +Kcommaaccent;0136 +Kdotbelow;1E32 +Keharmenian;0554 +Kenarmenian;053F +Khacyrillic;0425 +Kheicoptic;03E6 +Khook;0198 +Kjecyrillic;040C +Klinebelow;1E34 +Kmonospace;FF2B +Koppacyrillic;0480 +Koppagreek;03DE +Ksicyrillic;046E +Ksmall;F76B +L;004C +LJ;01C7 +LL;F6BF +Lacute;0139 +Lambda;039B +Lcaron;013D +Lcedilla;013B +Lcircle;24C1 +Lcircumflexbelow;1E3C +Lcommaaccent;013B +Ldot;013F +Ldotaccent;013F +Ldotbelow;1E36 +Ldotbelowmacron;1E38 +Liwnarmenian;053C +Lj;01C8 +Ljecyrillic;0409 +Llinebelow;1E3A +Lmonospace;FF2C +Lslash;0141 +Lslashsmall;F6F9 +Lsmall;F76C +M;004D +MBsquare;3386 +Macron;F6D0 +Macronsmall;F7AF +Macute;1E3E +Mcircle;24C2 +Mdotaccent;1E40 +Mdotbelow;1E42 +Menarmenian;0544 +Mmonospace;FF2D +Msmall;F76D +Mturned;019C +Mu;039C +N;004E +NJ;01CA +Nacute;0143 +Ncaron;0147 +Ncedilla;0145 +Ncircle;24C3 +Ncircumflexbelow;1E4A +Ncommaaccent;0145 +Ndotaccent;1E44 +Ndotbelow;1E46 +Nhookleft;019D +Nineroman;2168 +Nj;01CB +Njecyrillic;040A +Nlinebelow;1E48 +Nmonospace;FF2E +Nowarmenian;0546 +Nsmall;F76E +Ntilde;00D1 +Ntildesmall;F7F1 +Nu;039D +O;004F +OE;0152 +OEsmall;F6FA +Oacute;00D3 +Oacutesmall;F7F3 +Obarredcyrillic;04E8 +Obarreddieresiscyrillic;04EA +Obreve;014E +Ocaron;01D1 +Ocenteredtilde;019F +Ocircle;24C4 +Ocircumflex;00D4 +Ocircumflexacute;1ED0 +Ocircumflexdotbelow;1ED8 +Ocircumflexgrave;1ED2 +Ocircumflexhookabove;1ED4 +Ocircumflexsmall;F7F4 +Ocircumflextilde;1ED6 +Ocyrillic;041E +Odblacute;0150 +Odblgrave;020C +Odieresis;00D6 +Odieresiscyrillic;04E6 +Odieresissmall;F7F6 +Odotbelow;1ECC +Ogoneksmall;F6FB +Ograve;00D2 +Ogravesmall;F7F2 +Oharmenian;0555 +Ohm;2126 +Ohookabove;1ECE +Ohorn;01A0 +Ohornacute;1EDA +Ohorndotbelow;1EE2 +Ohorngrave;1EDC +Ohornhookabove;1EDE +Ohorntilde;1EE0 +Ohungarumlaut;0150 +Oi;01A2 +Oinvertedbreve;020E +Omacron;014C +Omacronacute;1E52 +Omacrongrave;1E50 +Omega;2126 +Omegacyrillic;0460 +Omegagreek;03A9 +Omegaroundcyrillic;047A +Omegatitlocyrillic;047C +Omegatonos;038F +Omicron;039F +Omicrontonos;038C +Omonospace;FF2F +Oneroman;2160 +Oogonek;01EA +Oogonekmacron;01EC +Oopen;0186 +Oslash;00D8 +Oslashacute;01FE +Oslashsmall;F7F8 +Osmall;F76F +Ostrokeacute;01FE +Otcyrillic;047E +Otilde;00D5 +Otildeacute;1E4C +Otildedieresis;1E4E +Otildesmall;F7F5 +P;0050 +Pacute;1E54 +Pcircle;24C5 +Pdotaccent;1E56 +Pecyrillic;041F +Peharmenian;054A +Pemiddlehookcyrillic;04A6 +Phi;03A6 +Phook;01A4 +Pi;03A0 +Piwrarmenian;0553 +Pmonospace;FF30 +Psi;03A8 +Psicyrillic;0470 +Psmall;F770 +Q;0051 +Qcircle;24C6 +Qmonospace;FF31 +Qsmall;F771 +R;0052 +Raarmenian;054C +Racute;0154 +Rcaron;0158 +Rcedilla;0156 +Rcircle;24C7 +Rcommaaccent;0156 +Rdblgrave;0210 +Rdotaccent;1E58 +Rdotbelow;1E5A +Rdotbelowmacron;1E5C +Reharmenian;0550 +Rfraktur;211C +Rho;03A1 +Ringsmall;F6FC +Rinvertedbreve;0212 +Rlinebelow;1E5E +Rmonospace;FF32 +Rsmall;F772 +Rsmallinverted;0281 +Rsmallinvertedsuperior;02B6 +S;0053 +SF010000;250C +SF020000;2514 +SF030000;2510 +SF040000;2518 +SF050000;253C +SF060000;252C +SF070000;2534 +SF080000;251C +SF090000;2524 +SF100000;2500 +SF110000;2502 +SF190000;2561 +SF200000;2562 +SF210000;2556 +SF220000;2555 +SF230000;2563 +SF240000;2551 +SF250000;2557 +SF260000;255D +SF270000;255C +SF280000;255B +SF360000;255E +SF370000;255F +SF380000;255A +SF390000;2554 +SF400000;2569 +SF410000;2566 +SF420000;2560 +SF430000;2550 +SF440000;256C +SF450000;2567 +SF460000;2568 +SF470000;2564 +SF480000;2565 +SF490000;2559 +SF500000;2558 +SF510000;2552 +SF520000;2553 +SF530000;256B +SF540000;256A +Sacute;015A +Sacutedotaccent;1E64 +Sampigreek;03E0 +Scaron;0160 +Scarondotaccent;1E66 +Scaronsmall;F6FD +Scedilla;015E +Schwa;018F +Schwacyrillic;04D8 +Schwadieresiscyrillic;04DA +Scircle;24C8 +Scircumflex;015C +Scommaaccent;0218 +Sdotaccent;1E60 +Sdotbelow;1E62 +Sdotbelowdotaccent;1E68 +Seharmenian;054D +Sevenroman;2166 +Shaarmenian;0547 +Shacyrillic;0428 +Shchacyrillic;0429 +Sheicoptic;03E2 +Shhacyrillic;04BA +Shimacoptic;03EC +Sigma;03A3 +Sixroman;2165 +Smonospace;FF33 +Softsigncyrillic;042C +Ssmall;F773 +Stigmagreek;03DA +T;0054 +Tau;03A4 +Tbar;0166 +Tcaron;0164 +Tcedilla;0162 +Tcircle;24C9 +Tcircumflexbelow;1E70 +Tcommaaccent;0162 +Tdotaccent;1E6A +Tdotbelow;1E6C +Tecyrillic;0422 +Tedescendercyrillic;04AC +Tenroman;2169 +Tetsecyrillic;04B4 +Theta;0398 +Thook;01AC +Thorn;00DE +Thornsmall;F7FE +Threeroman;2162 +Tildesmall;F6FE +Tiwnarmenian;054F +Tlinebelow;1E6E +Tmonospace;FF34 +Toarmenian;0539 +Tonefive;01BC +Tonesix;0184 +Tonetwo;01A7 +Tretroflexhook;01AE +Tsecyrillic;0426 +Tshecyrillic;040B +Tsmall;F774 +Twelveroman;216B +Tworoman;2161 +U;0055 +Uacute;00DA +Uacutesmall;F7FA +Ubreve;016C +Ucaron;01D3 +Ucircle;24CA +Ucircumflex;00DB +Ucircumflexbelow;1E76 +Ucircumflexsmall;F7FB +Ucyrillic;0423 +Udblacute;0170 +Udblgrave;0214 +Udieresis;00DC +Udieresisacute;01D7 +Udieresisbelow;1E72 +Udieresiscaron;01D9 +Udieresiscyrillic;04F0 +Udieresisgrave;01DB +Udieresismacron;01D5 +Udieresissmall;F7FC +Udotbelow;1EE4 +Ugrave;00D9 +Ugravesmall;F7F9 +Uhookabove;1EE6 +Uhorn;01AF +Uhornacute;1EE8 +Uhorndotbelow;1EF0 +Uhorngrave;1EEA +Uhornhookabove;1EEC +Uhorntilde;1EEE +Uhungarumlaut;0170 +Uhungarumlautcyrillic;04F2 +Uinvertedbreve;0216 +Ukcyrillic;0478 +Umacron;016A +Umacroncyrillic;04EE +Umacrondieresis;1E7A +Umonospace;FF35 +Uogonek;0172 +Upsilon;03A5 +Upsilon1;03D2 +Upsilonacutehooksymbolgreek;03D3 +Upsilonafrican;01B1 +Upsilondieresis;03AB +Upsilondieresishooksymbolgreek;03D4 +Upsilonhooksymbol;03D2 +Upsilontonos;038E +Uring;016E +Ushortcyrillic;040E +Usmall;F775 +Ustraightcyrillic;04AE +Ustraightstrokecyrillic;04B0 +Utilde;0168 +Utildeacute;1E78 +Utildebelow;1E74 +V;0056 +Vcircle;24CB +Vdotbelow;1E7E +Vecyrillic;0412 +Vewarmenian;054E +Vhook;01B2 +Vmonospace;FF36 +Voarmenian;0548 +Vsmall;F776 +Vtilde;1E7C +W;0057 +Wacute;1E82 +Wcircle;24CC +Wcircumflex;0174 +Wdieresis;1E84 +Wdotaccent;1E86 +Wdotbelow;1E88 +Wgrave;1E80 +Wmonospace;FF37 +Wsmall;F777 +X;0058 +Xcircle;24CD +Xdieresis;1E8C +Xdotaccent;1E8A +Xeharmenian;053D +Xi;039E +Xmonospace;FF38 +Xsmall;F778 +Y;0059 +Yacute;00DD +Yacutesmall;F7FD +Yatcyrillic;0462 +Ycircle;24CE +Ycircumflex;0176 +Ydieresis;0178 +Ydieresissmall;F7FF +Ydotaccent;1E8E +Ydotbelow;1EF4 +Yericyrillic;042B +Yerudieresiscyrillic;04F8 +Ygrave;1EF2 +Yhook;01B3 +Yhookabove;1EF6 +Yiarmenian;0545 +Yicyrillic;0407 +Yiwnarmenian;0552 +Ymonospace;FF39 +Ysmall;F779 +Ytilde;1EF8 +Yusbigcyrillic;046A +Yusbigiotifiedcyrillic;046C +Yuslittlecyrillic;0466 +Yuslittleiotifiedcyrillic;0468 +Z;005A +Zaarmenian;0536 +Zacute;0179 +Zcaron;017D +Zcaronsmall;F6FF +Zcircle;24CF +Zcircumflex;1E90 +Zdot;017B +Zdotaccent;017B +Zdotbelow;1E92 +Zecyrillic;0417 +Zedescendercyrillic;0498 +Zedieresiscyrillic;04DE +Zeta;0396 +Zhearmenian;053A +Zhebrevecyrillic;04C1 +Zhecyrillic;0416 +Zhedescendercyrillic;0496 +Zhedieresiscyrillic;04DC +Zlinebelow;1E94 +Zmonospace;FF3A +Zsmall;F77A +Zstroke;01B5 +a;0061 +aabengali;0986 +aacute;00E1 +aadeva;0906 +aagujarati;0A86 +aagurmukhi;0A06 +aamatragurmukhi;0A3E +aarusquare;3303 +aavowelsignbengali;09BE +aavowelsigndeva;093E +aavowelsigngujarati;0ABE +abbreviationmarkarmenian;055F +abbreviationsigndeva;0970 +abengali;0985 +abopomofo;311A +abreve;0103 +abreveacute;1EAF +abrevecyrillic;04D1 +abrevedotbelow;1EB7 +abrevegrave;1EB1 +abrevehookabove;1EB3 +abrevetilde;1EB5 +acaron;01CE +acircle;24D0 +acircumflex;00E2 +acircumflexacute;1EA5 +acircumflexdotbelow;1EAD +acircumflexgrave;1EA7 +acircumflexhookabove;1EA9 +acircumflextilde;1EAB +acute;00B4 +acutebelowcmb;0317 +acutecmb;0301 +acutecomb;0301 +acutedeva;0954 +acutelowmod;02CF +acutetonecmb;0341 +acyrillic;0430 +adblgrave;0201 +addakgurmukhi;0A71 +adeva;0905 +adieresis;00E4 +adieresiscyrillic;04D3 +adieresismacron;01DF +adotbelow;1EA1 +adotmacron;01E1 +ae;00E6 +aeacute;01FD +aekorean;3150 +aemacron;01E3 +afii00208;2015 +afii08941;20A4 +afii10017;0410 +afii10018;0411 +afii10019;0412 +afii10020;0413 +afii10021;0414 +afii10022;0415 +afii10023;0401 +afii10024;0416 +afii10025;0417 +afii10026;0418 +afii10027;0419 +afii10028;041A +afii10029;041B +afii10030;041C +afii10031;041D +afii10032;041E +afii10033;041F +afii10034;0420 +afii10035;0421 +afii10036;0422 +afii10037;0423 +afii10038;0424 +afii10039;0425 +afii10040;0426 +afii10041;0427 +afii10042;0428 +afii10043;0429 +afii10044;042A +afii10045;042B +afii10046;042C +afii10047;042D +afii10048;042E +afii10049;042F +afii10050;0490 +afii10051;0402 +afii10052;0403 +afii10053;0404 +afii10054;0405 +afii10055;0406 +afii10056;0407 +afii10057;0408 +afii10058;0409 +afii10059;040A +afii10060;040B +afii10061;040C +afii10062;040E +afii10063;F6C4 +afii10064;F6C5 +afii10065;0430 +afii10066;0431 +afii10067;0432 +afii10068;0433 +afii10069;0434 +afii10070;0435 +afii10071;0451 +afii10072;0436 +afii10073;0437 +afii10074;0438 +afii10075;0439 +afii10076;043A +afii10077;043B +afii10078;043C +afii10079;043D +afii10080;043E +afii10081;043F +afii10082;0440 +afii10083;0441 +afii10084;0442 +afii10085;0443 +afii10086;0444 +afii10087;0445 +afii10088;0446 +afii10089;0447 +afii10090;0448 +afii10091;0449 +afii10092;044A +afii10093;044B +afii10094;044C +afii10095;044D +afii10096;044E +afii10097;044F +afii10098;0491 +afii10099;0452 +afii10100;0453 +afii10101;0454 +afii10102;0455 +afii10103;0456 +afii10104;0457 +afii10105;0458 +afii10106;0459 +afii10107;045A +afii10108;045B +afii10109;045C +afii10110;045E +afii10145;040F +afii10146;0462 +afii10147;0472 +afii10148;0474 +afii10192;F6C6 +afii10193;045F +afii10194;0463 +afii10195;0473 +afii10196;0475 +afii10831;F6C7 +afii10832;F6C8 +afii10846;04D9 +afii299;200E +afii300;200F +afii301;200D +afii57381;066A +afii57388;060C +afii57392;0660 +afii57393;0661 +afii57394;0662 +afii57395;0663 +afii57396;0664 +afii57397;0665 +afii57398;0666 +afii57399;0667 +afii57400;0668 +afii57401;0669 +afii57403;061B +afii57407;061F +afii57409;0621 +afii57410;0622 +afii57411;0623 +afii57412;0624 +afii57413;0625 +afii57414;0626 +afii57415;0627 +afii57416;0628 +afii57417;0629 +afii57418;062A +afii57419;062B +afii57420;062C +afii57421;062D +afii57422;062E +afii57423;062F +afii57424;0630 +afii57425;0631 +afii57426;0632 +afii57427;0633 +afii57428;0634 +afii57429;0635 +afii57430;0636 +afii57431;0637 +afii57432;0638 +afii57433;0639 +afii57434;063A +afii57440;0640 +afii57441;0641 +afii57442;0642 +afii57443;0643 +afii57444;0644 +afii57445;0645 +afii57446;0646 +afii57448;0648 +afii57449;0649 +afii57450;064A +afii57451;064B +afii57452;064C +afii57453;064D +afii57454;064E +afii57455;064F +afii57456;0650 +afii57457;0651 +afii57458;0652 +afii57470;0647 +afii57505;06A4 +afii57506;067E +afii57507;0686 +afii57508;0698 +afii57509;06AF +afii57511;0679 +afii57512;0688 +afii57513;0691 +afii57514;06BA +afii57519;06D2 +afii57534;06D5 +afii57636;20AA +afii57645;05BE +afii57658;05C3 +afii57664;05D0 +afii57665;05D1 +afii57666;05D2 +afii57667;05D3 +afii57668;05D4 +afii57669;05D5 +afii57670;05D6 +afii57671;05D7 +afii57672;05D8 +afii57673;05D9 +afii57674;05DA +afii57675;05DB +afii57676;05DC +afii57677;05DD +afii57678;05DE +afii57679;05DF +afii57680;05E0 +afii57681;05E1 +afii57682;05E2 +afii57683;05E3 +afii57684;05E4 +afii57685;05E5 +afii57686;05E6 +afii57687;05E7 +afii57688;05E8 +afii57689;05E9 +afii57690;05EA +afii57694;FB2A +afii57695;FB2B +afii57700;FB4B +afii57705;FB1F +afii57716;05F0 +afii57717;05F1 +afii57718;05F2 +afii57723;FB35 +afii57793;05B4 +afii57794;05B5 +afii57795;05B6 +afii57796;05BB +afii57797;05B8 +afii57798;05B7 +afii57799;05B0 +afii57800;05B2 +afii57801;05B1 +afii57802;05B3 +afii57803;05C2 +afii57804;05C1 +afii57806;05B9 +afii57807;05BC +afii57839;05BD +afii57841;05BF +afii57842;05C0 +afii57929;02BC +afii61248;2105 +afii61289;2113 +afii61352;2116 +afii61573;202C +afii61574;202D +afii61575;202E +afii61664;200C +afii63167;066D +afii64937;02BD +agrave;00E0 +agujarati;0A85 +agurmukhi;0A05 +ahiragana;3042 +ahookabove;1EA3 +aibengali;0990 +aibopomofo;311E +aideva;0910 +aiecyrillic;04D5 +aigujarati;0A90 +aigurmukhi;0A10 +aimatragurmukhi;0A48 +ainarabic;0639 +ainfinalarabic;FECA +aininitialarabic;FECB +ainmedialarabic;FECC +ainvertedbreve;0203 +aivowelsignbengali;09C8 +aivowelsigndeva;0948 +aivowelsigngujarati;0AC8 +akatakana;30A2 +akatakanahalfwidth;FF71 +akorean;314F +alef;05D0 +alefarabic;0627 +alefdageshhebrew;FB30 +aleffinalarabic;FE8E +alefhamzaabovearabic;0623 +alefhamzaabovefinalarabic;FE84 +alefhamzabelowarabic;0625 +alefhamzabelowfinalarabic;FE88 +alefhebrew;05D0 +aleflamedhebrew;FB4F +alefmaddaabovearabic;0622 +alefmaddaabovefinalarabic;FE82 +alefmaksuraarabic;0649 +alefmaksurafinalarabic;FEF0 +alefmaksurainitialarabic;FEF3 +alefmaksuramedialarabic;FEF4 +alefpatahhebrew;FB2E +alefqamatshebrew;FB2F +aleph;2135 +allequal;224C +alpha;03B1 +alphatonos;03AC +amacron;0101 +amonospace;FF41 +ampersand;0026 +ampersandmonospace;FF06 +ampersandsmall;F726 +amsquare;33C2 +anbopomofo;3122 +angbopomofo;3124 +angkhankhuthai;0E5A +angle;2220 +anglebracketleft;3008 +anglebracketleftvertical;FE3F +anglebracketright;3009 +anglebracketrightvertical;FE40 +angleleft;2329 +angleright;232A +angstrom;212B +anoteleia;0387 +anudattadeva;0952 +anusvarabengali;0982 +anusvaradeva;0902 +anusvaragujarati;0A82 +aogonek;0105 +apaatosquare;3300 +aparen;249C +apostrophearmenian;055A +apostrophemod;02BC +apple;F8FF +approaches;2250 +approxequal;2248 +approxequalorimage;2252 +approximatelyequal;2245 +araeaekorean;318E +araeakorean;318D +arc;2312 +arighthalfring;1E9A +aring;00E5 +aringacute;01FB +aringbelow;1E01 +arrowboth;2194 +arrowdashdown;21E3 +arrowdashleft;21E0 +arrowdashright;21E2 +arrowdashup;21E1 +arrowdblboth;21D4 +arrowdbldown;21D3 +arrowdblleft;21D0 +arrowdblright;21D2 +arrowdblup;21D1 +arrowdown;2193 +arrowdownleft;2199 +arrowdownright;2198 +arrowdownwhite;21E9 +arrowheaddownmod;02C5 +arrowheadleftmod;02C2 +arrowheadrightmod;02C3 +arrowheadupmod;02C4 +arrowhorizex;F8E7 +arrowleft;2190 +arrowleftdbl;21D0 +arrowleftdblstroke;21CD +arrowleftoverright;21C6 +arrowleftwhite;21E6 +arrowright;2192 +arrowrightdblstroke;21CF +arrowrightheavy;279E +arrowrightoverleft;21C4 +arrowrightwhite;21E8 +arrowtableft;21E4 +arrowtabright;21E5 +arrowup;2191 +arrowupdn;2195 +arrowupdnbse;21A8 +arrowupdownbase;21A8 +arrowupleft;2196 +arrowupleftofdown;21C5 +arrowupright;2197 +arrowupwhite;21E7 +arrowvertex;F8E6 +asciicircum;005E +asciicircummonospace;FF3E +asciitilde;007E +asciitildemonospace;FF5E +ascript;0251 +ascriptturned;0252 +asmallhiragana;3041 +asmallkatakana;30A1 +asmallkatakanahalfwidth;FF67 +asterisk;002A +asteriskaltonearabic;066D +asteriskarabic;066D +asteriskmath;2217 +asteriskmonospace;FF0A +asterisksmall;FE61 +asterism;2042 +asuperior;F6E9 +asymptoticallyequal;2243 +at;0040 +atilde;00E3 +atmonospace;FF20 +atsmall;FE6B +aturned;0250 +aubengali;0994 +aubopomofo;3120 +audeva;0914 +augujarati;0A94 +augurmukhi;0A14 +aulengthmarkbengali;09D7 +aumatragurmukhi;0A4C +auvowelsignbengali;09CC +auvowelsigndeva;094C +auvowelsigngujarati;0ACC +avagrahadeva;093D +aybarmenian;0561 +ayin;05E2 +ayinaltonehebrew;FB20 +ayinhebrew;05E2 +b;0062 +babengali;09AC +backslash;005C +backslashmonospace;FF3C +badeva;092C +bagujarati;0AAC +bagurmukhi;0A2C +bahiragana;3070 +bahtthai;0E3F +bakatakana;30D0 +bar;007C +barmonospace;FF5C +bbopomofo;3105 +bcircle;24D1 +bdotaccent;1E03 +bdotbelow;1E05 +beamedsixteenthnotes;266C +because;2235 +becyrillic;0431 +beharabic;0628 +behfinalarabic;FE90 +behinitialarabic;FE91 +behiragana;3079 +behmedialarabic;FE92 +behmeeminitialarabic;FC9F +behmeemisolatedarabic;FC08 +behnoonfinalarabic;FC6D +bekatakana;30D9 +benarmenian;0562 +bet;05D1 +beta;03B2 +betasymbolgreek;03D0 +betdagesh;FB31 +betdageshhebrew;FB31 +bethebrew;05D1 +betrafehebrew;FB4C +bhabengali;09AD +bhadeva;092D +bhagujarati;0AAD +bhagurmukhi;0A2D +bhook;0253 +bihiragana;3073 +bikatakana;30D3 +bilabialclick;0298 +bindigurmukhi;0A02 +birusquare;3331 +blackcircle;25CF +blackdiamond;25C6 +blackdownpointingtriangle;25BC +blackleftpointingpointer;25C4 +blackleftpointingtriangle;25C0 +blacklenticularbracketleft;3010 +blacklenticularbracketleftvertical;FE3B +blacklenticularbracketright;3011 +blacklenticularbracketrightvertical;FE3C +blacklowerlefttriangle;25E3 +blacklowerrighttriangle;25E2 +blackrectangle;25AC +blackrightpointingpointer;25BA +blackrightpointingtriangle;25B6 +blacksmallsquare;25AA +blacksmilingface;263B +blacksquare;25A0 +blackstar;2605 +blackupperlefttriangle;25E4 +blackupperrighttriangle;25E5 +blackuppointingsmalltriangle;25B4 +blackuppointingtriangle;25B2 +blank;2423 +blinebelow;1E07 +block;2588 +bmonospace;FF42 +bobaimaithai;0E1A +bohiragana;307C +bokatakana;30DC +bparen;249D +bqsquare;33C3 +braceex;F8F4 +braceleft;007B +braceleftbt;F8F3 +braceleftmid;F8F2 +braceleftmonospace;FF5B +braceleftsmall;FE5B +bracelefttp;F8F1 +braceleftvertical;FE37 +braceright;007D +bracerightbt;F8FE +bracerightmid;F8FD +bracerightmonospace;FF5D +bracerightsmall;FE5C +bracerighttp;F8FC +bracerightvertical;FE38 +bracketleft;005B +bracketleftbt;F8F0 +bracketleftex;F8EF +bracketleftmonospace;FF3B +bracketlefttp;F8EE +bracketright;005D +bracketrightbt;F8FB +bracketrightex;F8FA +bracketrightmonospace;FF3D +bracketrighttp;F8F9 +breve;02D8 +brevebelowcmb;032E +brevecmb;0306 +breveinvertedbelowcmb;032F +breveinvertedcmb;0311 +breveinverteddoublecmb;0361 +bridgebelowcmb;032A +bridgeinvertedbelowcmb;033A +brokenbar;00A6 +bstroke;0180 +bsuperior;F6EA +btopbar;0183 +buhiragana;3076 +bukatakana;30D6 +bullet;2022 +bulletinverse;25D8 +bulletoperator;2219 +bullseye;25CE +c;0063 +caarmenian;056E +cabengali;099A +cacute;0107 +cadeva;091A +cagujarati;0A9A +cagurmukhi;0A1A +calsquare;3388 +candrabindubengali;0981 +candrabinducmb;0310 +candrabindudeva;0901 +candrabindugujarati;0A81 +capslock;21EA +careof;2105 +caron;02C7 +caronbelowcmb;032C +caroncmb;030C +carriagereturn;21B5 +cbopomofo;3118 +ccaron;010D +ccedilla;00E7 +ccedillaacute;1E09 +ccircle;24D2 +ccircumflex;0109 +ccurl;0255 +cdot;010B +cdotaccent;010B +cdsquare;33C5 +cedilla;00B8 +cedillacmb;0327 +cent;00A2 +centigrade;2103 +centinferior;F6DF +centmonospace;FFE0 +centoldstyle;F7A2 +centsuperior;F6E0 +chaarmenian;0579 +chabengali;099B +chadeva;091B +chagujarati;0A9B +chagurmukhi;0A1B +chbopomofo;3114 +cheabkhasiancyrillic;04BD +checkmark;2713 +checyrillic;0447 +chedescenderabkhasiancyrillic;04BF +chedescendercyrillic;04B7 +chedieresiscyrillic;04F5 +cheharmenian;0573 +chekhakassiancyrillic;04CC +cheverticalstrokecyrillic;04B9 +chi;03C7 +chieuchacirclekorean;3277 +chieuchaparenkorean;3217 +chieuchcirclekorean;3269 +chieuchkorean;314A +chieuchparenkorean;3209 +chochangthai;0E0A +chochanthai;0E08 +chochingthai;0E09 +chochoethai;0E0C +chook;0188 +cieucacirclekorean;3276 +cieucaparenkorean;3216 +cieuccirclekorean;3268 +cieuckorean;3148 +cieucparenkorean;3208 +cieucuparenkorean;321C +circle;25CB +circlemultiply;2297 +circleot;2299 +circleplus;2295 +circlepostalmark;3036 +circlewithlefthalfblack;25D0 +circlewithrighthalfblack;25D1 +circumflex;02C6 +circumflexbelowcmb;032D +circumflexcmb;0302 +clear;2327 +clickalveolar;01C2 +clickdental;01C0 +clicklateral;01C1 +clickretroflex;01C3 +club;2663 +clubsuitblack;2663 +clubsuitwhite;2667 +cmcubedsquare;33A4 +cmonospace;FF43 +cmsquaredsquare;33A0 +coarmenian;0581 +colon;003A +colonmonetary;20A1 +colonmonospace;FF1A +colonsign;20A1 +colonsmall;FE55 +colontriangularhalfmod;02D1 +colontriangularmod;02D0 +comma;002C +commaabovecmb;0313 +commaaboverightcmb;0315 +commaaccent;F6C3 +commaarabic;060C +commaarmenian;055D +commainferior;F6E1 +commamonospace;FF0C +commareversedabovecmb;0314 +commareversedmod;02BD +commasmall;FE50 +commasuperior;F6E2 +commaturnedabovecmb;0312 +commaturnedmod;02BB +compass;263C +congruent;2245 +contourintegral;222E +control;2303 +controlACK;0006 +controlBEL;0007 +controlBS;0008 +controlCAN;0018 +controlCR;000D +controlDC1;0011 +controlDC2;0012 +controlDC3;0013 +controlDC4;0014 +controlDEL;007F +controlDLE;0010 +controlEM;0019 +controlENQ;0005 +controlEOT;0004 +controlESC;001B +controlETB;0017 +controlETX;0003 +controlFF;000C +controlFS;001C +controlGS;001D +controlHT;0009 +controlLF;000A +controlNAK;0015 +controlRS;001E +controlSI;000F +controlSO;000E +controlSOT;0002 +controlSTX;0001 +controlSUB;001A +controlSYN;0016 +controlUS;001F +controlVT;000B +copyright;00A9 +copyrightsans;F8E9 +copyrightserif;F6D9 +cornerbracketleft;300C +cornerbracketlefthalfwidth;FF62 +cornerbracketleftvertical;FE41 +cornerbracketright;300D +cornerbracketrighthalfwidth;FF63 +cornerbracketrightvertical;FE42 +corporationsquare;337F +cosquare;33C7 +coverkgsquare;33C6 +cparen;249E +cruzeiro;20A2 +cstretched;0297 +curlyand;22CF +curlyor;22CE +currency;00A4 +cyrBreve;F6D1 +cyrFlex;F6D2 +cyrbreve;F6D4 +cyrflex;F6D5 +d;0064 +daarmenian;0564 +dabengali;09A6 +dadarabic;0636 +dadeva;0926 +dadfinalarabic;FEBE +dadinitialarabic;FEBF +dadmedialarabic;FEC0 +dagesh;05BC +dageshhebrew;05BC +dagger;2020 +daggerdbl;2021 +dagujarati;0AA6 +dagurmukhi;0A26 +dahiragana;3060 +dakatakana;30C0 +dalarabic;062F +dalet;05D3 +daletdagesh;FB33 +daletdageshhebrew;FB33 +dalethatafpatah;05D3 05B2 +dalethatafpatahhebrew;05D3 05B2 +dalethatafsegol;05D3 05B1 +dalethatafsegolhebrew;05D3 05B1 +dalethebrew;05D3 +dalethiriq;05D3 05B4 +dalethiriqhebrew;05D3 05B4 +daletholam;05D3 05B9 +daletholamhebrew;05D3 05B9 +daletpatah;05D3 05B7 +daletpatahhebrew;05D3 05B7 +daletqamats;05D3 05B8 +daletqamatshebrew;05D3 05B8 +daletqubuts;05D3 05BB +daletqubutshebrew;05D3 05BB +daletsegol;05D3 05B6 +daletsegolhebrew;05D3 05B6 +daletsheva;05D3 05B0 +daletshevahebrew;05D3 05B0 +dalettsere;05D3 05B5 +dalettserehebrew;05D3 05B5 +dalfinalarabic;FEAA +dammaarabic;064F +dammalowarabic;064F +dammatanaltonearabic;064C +dammatanarabic;064C +danda;0964 +dargahebrew;05A7 +dargalefthebrew;05A7 +dasiapneumatacyrilliccmb;0485 +dblGrave;F6D3 +dblanglebracketleft;300A +dblanglebracketleftvertical;FE3D +dblanglebracketright;300B +dblanglebracketrightvertical;FE3E +dblarchinvertedbelowcmb;032B +dblarrowleft;21D4 +dblarrowright;21D2 +dbldanda;0965 +dblgrave;F6D6 +dblgravecmb;030F +dblintegral;222C +dbllowline;2017 +dbllowlinecmb;0333 +dbloverlinecmb;033F +dblprimemod;02BA +dblverticalbar;2016 +dblverticallineabovecmb;030E +dbopomofo;3109 +dbsquare;33C8 +dcaron;010F +dcedilla;1E11 +dcircle;24D3 +dcircumflexbelow;1E13 +dcroat;0111 +ddabengali;09A1 +ddadeva;0921 +ddagujarati;0AA1 +ddagurmukhi;0A21 +ddalarabic;0688 +ddalfinalarabic;FB89 +dddhadeva;095C +ddhabengali;09A2 +ddhadeva;0922 +ddhagujarati;0AA2 +ddhagurmukhi;0A22 +ddotaccent;1E0B +ddotbelow;1E0D +decimalseparatorarabic;066B +decimalseparatorpersian;066B +decyrillic;0434 +degree;00B0 +dehihebrew;05AD +dehiragana;3067 +deicoptic;03EF +dekatakana;30C7 +deleteleft;232B +deleteright;2326 +delta;03B4 +deltaturned;018D +denominatorminusonenumeratorbengali;09F8 +dezh;02A4 +dhabengali;09A7 +dhadeva;0927 +dhagujarati;0AA7 +dhagurmukhi;0A27 +dhook;0257 +dialytikatonos;0385 +dialytikatonoscmb;0344 +diamond;2666 +diamondsuitwhite;2662 +dieresis;00A8 +dieresisacute;F6D7 +dieresisbelowcmb;0324 +dieresiscmb;0308 +dieresisgrave;F6D8 +dieresistonos;0385 +dihiragana;3062 +dikatakana;30C2 +dittomark;3003 +divide;00F7 +divides;2223 +divisionslash;2215 +djecyrillic;0452 +dkshade;2593 +dlinebelow;1E0F +dlsquare;3397 +dmacron;0111 +dmonospace;FF44 +dnblock;2584 +dochadathai;0E0E +dodekthai;0E14 +dohiragana;3069 +dokatakana;30C9 +dollar;0024 +dollarinferior;F6E3 +dollarmonospace;FF04 +dollaroldstyle;F724 +dollarsmall;FE69 +dollarsuperior;F6E4 +dong;20AB +dorusquare;3326 +dotaccent;02D9 +dotaccentcmb;0307 +dotbelowcmb;0323 +dotbelowcomb;0323 +dotkatakana;30FB +dotlessi;0131 +dotlessj;F6BE +dotlessjstrokehook;0284 +dotmath;22C5 +dottedcircle;25CC +doubleyodpatah;FB1F +doubleyodpatahhebrew;FB1F +downtackbelowcmb;031E +downtackmod;02D5 +dparen;249F +dsuperior;F6EB +dtail;0256 +dtopbar;018C +duhiragana;3065 +dukatakana;30C5 +dz;01F3 +dzaltone;02A3 +dzcaron;01C6 +dzcurl;02A5 +dzeabkhasiancyrillic;04E1 +dzecyrillic;0455 +dzhecyrillic;045F +e;0065 +eacute;00E9 +earth;2641 +ebengali;098F +ebopomofo;311C +ebreve;0115 +ecandradeva;090D +ecandragujarati;0A8D +ecandravowelsigndeva;0945 +ecandravowelsigngujarati;0AC5 +ecaron;011B +ecedillabreve;1E1D +echarmenian;0565 +echyiwnarmenian;0587 +ecircle;24D4 +ecircumflex;00EA +ecircumflexacute;1EBF +ecircumflexbelow;1E19 +ecircumflexdotbelow;1EC7 +ecircumflexgrave;1EC1 +ecircumflexhookabove;1EC3 +ecircumflextilde;1EC5 +ecyrillic;0454 +edblgrave;0205 +edeva;090F +edieresis;00EB +edot;0117 +edotaccent;0117 +edotbelow;1EB9 +eegurmukhi;0A0F +eematragurmukhi;0A47 +efcyrillic;0444 +egrave;00E8 +egujarati;0A8F +eharmenian;0567 +ehbopomofo;311D +ehiragana;3048 +ehookabove;1EBB +eibopomofo;311F +eight;0038 +eightarabic;0668 +eightbengali;09EE +eightcircle;2467 +eightcircleinversesansserif;2791 +eightdeva;096E +eighteencircle;2471 +eighteenparen;2485 +eighteenperiod;2499 +eightgujarati;0AEE +eightgurmukhi;0A6E +eighthackarabic;0668 +eighthangzhou;3028 +eighthnotebeamed;266B +eightideographicparen;3227 +eightinferior;2088 +eightmonospace;FF18 +eightoldstyle;F738 +eightparen;247B +eightperiod;248F +eightpersian;06F8 +eightroman;2177 +eightsuperior;2078 +eightthai;0E58 +einvertedbreve;0207 +eiotifiedcyrillic;0465 +ekatakana;30A8 +ekatakanahalfwidth;FF74 +ekonkargurmukhi;0A74 +ekorean;3154 +elcyrillic;043B +element;2208 +elevencircle;246A +elevenparen;247E +elevenperiod;2492 +elevenroman;217A +ellipsis;2026 +ellipsisvertical;22EE +emacron;0113 +emacronacute;1E17 +emacrongrave;1E15 +emcyrillic;043C +emdash;2014 +emdashvertical;FE31 +emonospace;FF45 +emphasismarkarmenian;055B +emptyset;2205 +enbopomofo;3123 +encyrillic;043D +endash;2013 +endashvertical;FE32 +endescendercyrillic;04A3 +eng;014B +engbopomofo;3125 +enghecyrillic;04A5 +enhookcyrillic;04C8 +enspace;2002 +eogonek;0119 +eokorean;3153 +eopen;025B +eopenclosed;029A +eopenreversed;025C +eopenreversedclosed;025E +eopenreversedhook;025D +eparen;24A0 +epsilon;03B5 +epsilontonos;03AD +equal;003D +equalmonospace;FF1D +equalsmall;FE66 +equalsuperior;207C +equivalence;2261 +erbopomofo;3126 +ercyrillic;0440 +ereversed;0258 +ereversedcyrillic;044D +escyrillic;0441 +esdescendercyrillic;04AB +esh;0283 +eshcurl;0286 +eshortdeva;090E +eshortvowelsigndeva;0946 +eshreversedloop;01AA +eshsquatreversed;0285 +esmallhiragana;3047 +esmallkatakana;30A7 +esmallkatakanahalfwidth;FF6A +estimated;212E +esuperior;F6EC +eta;03B7 +etarmenian;0568 +etatonos;03AE +eth;00F0 +etilde;1EBD +etildebelow;1E1B +etnahtafoukhhebrew;0591 +etnahtafoukhlefthebrew;0591 +etnahtahebrew;0591 +etnahtalefthebrew;0591 +eturned;01DD +eukorean;3161 +euro;20AC +evowelsignbengali;09C7 +evowelsigndeva;0947 +evowelsigngujarati;0AC7 +exclam;0021 +exclamarmenian;055C +exclamdbl;203C +exclamdown;00A1 +exclamdownsmall;F7A1 +exclammonospace;FF01 +exclamsmall;F721 +existential;2203 +ezh;0292 +ezhcaron;01EF +ezhcurl;0293 +ezhreversed;01B9 +ezhtail;01BA +f;0066 +fadeva;095E +fagurmukhi;0A5E +fahrenheit;2109 +fathaarabic;064E +fathalowarabic;064E +fathatanarabic;064B +fbopomofo;3108 +fcircle;24D5 +fdotaccent;1E1F +feharabic;0641 +feharmenian;0586 +fehfinalarabic;FED2 +fehinitialarabic;FED3 +fehmedialarabic;FED4 +feicoptic;03E5 +female;2640 +ff;FB00 +ffi;FB03 +ffl;FB04 +fi;FB01 +fifteencircle;246E +fifteenparen;2482 +fifteenperiod;2496 +figuredash;2012 +filledbox;25A0 +filledrect;25AC +finalkaf;05DA +finalkafdagesh;FB3A +finalkafdageshhebrew;FB3A +finalkafhebrew;05DA +finalkafqamats;05DA 05B8 +finalkafqamatshebrew;05DA 05B8 +finalkafsheva;05DA 05B0 +finalkafshevahebrew;05DA 05B0 +finalmem;05DD +finalmemhebrew;05DD +finalnun;05DF +finalnunhebrew;05DF +finalpe;05E3 +finalpehebrew;05E3 +finaltsadi;05E5 +finaltsadihebrew;05E5 +firsttonechinese;02C9 +fisheye;25C9 +fitacyrillic;0473 +five;0035 +fivearabic;0665 +fivebengali;09EB +fivecircle;2464 +fivecircleinversesansserif;278E +fivedeva;096B +fiveeighths;215D +fivegujarati;0AEB +fivegurmukhi;0A6B +fivehackarabic;0665 +fivehangzhou;3025 +fiveideographicparen;3224 +fiveinferior;2085 +fivemonospace;FF15 +fiveoldstyle;F735 +fiveparen;2478 +fiveperiod;248C +fivepersian;06F5 +fiveroman;2174 +fivesuperior;2075 +fivethai;0E55 +fl;FB02 +florin;0192 +fmonospace;FF46 +fmsquare;3399 +fofanthai;0E1F +fofathai;0E1D +fongmanthai;0E4F +forall;2200 +four;0034 +fourarabic;0664 +fourbengali;09EA +fourcircle;2463 +fourcircleinversesansserif;278D +fourdeva;096A +fourgujarati;0AEA +fourgurmukhi;0A6A +fourhackarabic;0664 +fourhangzhou;3024 +fourideographicparen;3223 +fourinferior;2084 +fourmonospace;FF14 +fournumeratorbengali;09F7 +fouroldstyle;F734 +fourparen;2477 +fourperiod;248B +fourpersian;06F4 +fourroman;2173 +foursuperior;2074 +fourteencircle;246D +fourteenparen;2481 +fourteenperiod;2495 +fourthai;0E54 +fourthtonechinese;02CB +fparen;24A1 +fraction;2044 +franc;20A3 +g;0067 +gabengali;0997 +gacute;01F5 +gadeva;0917 +gafarabic;06AF +gaffinalarabic;FB93 +gafinitialarabic;FB94 +gafmedialarabic;FB95 +gagujarati;0A97 +gagurmukhi;0A17 +gahiragana;304C +gakatakana;30AC +gamma;03B3 +gammalatinsmall;0263 +gammasuperior;02E0 +gangiacoptic;03EB +gbopomofo;310D +gbreve;011F +gcaron;01E7 +gcedilla;0123 +gcircle;24D6 +gcircumflex;011D +gcommaaccent;0123 +gdot;0121 +gdotaccent;0121 +gecyrillic;0433 +gehiragana;3052 +gekatakana;30B2 +geometricallyequal;2251 +gereshaccenthebrew;059C +gereshhebrew;05F3 +gereshmuqdamhebrew;059D +germandbls;00DF +gershayimaccenthebrew;059E +gershayimhebrew;05F4 +getamark;3013 +ghabengali;0998 +ghadarmenian;0572 +ghadeva;0918 +ghagujarati;0A98 +ghagurmukhi;0A18 +ghainarabic;063A +ghainfinalarabic;FECE +ghaininitialarabic;FECF +ghainmedialarabic;FED0 +ghemiddlehookcyrillic;0495 +ghestrokecyrillic;0493 +gheupturncyrillic;0491 +ghhadeva;095A +ghhagurmukhi;0A5A +ghook;0260 +ghzsquare;3393 +gihiragana;304E +gikatakana;30AE +gimarmenian;0563 +gimel;05D2 +gimeldagesh;FB32 +gimeldageshhebrew;FB32 +gimelhebrew;05D2 +gjecyrillic;0453 +glottalinvertedstroke;01BE +glottalstop;0294 +glottalstopinverted;0296 +glottalstopmod;02C0 +glottalstopreversed;0295 +glottalstopreversedmod;02C1 +glottalstopreversedsuperior;02E4 +glottalstopstroke;02A1 +glottalstopstrokereversed;02A2 +gmacron;1E21 +gmonospace;FF47 +gohiragana;3054 +gokatakana;30B4 +gparen;24A2 +gpasquare;33AC +gradient;2207 +grave;0060 +gravebelowcmb;0316 +gravecmb;0300 +gravecomb;0300 +gravedeva;0953 +gravelowmod;02CE +gravemonospace;FF40 +gravetonecmb;0340 +greater;003E +greaterequal;2265 +greaterequalorless;22DB +greatermonospace;FF1E +greaterorequivalent;2273 +greaterorless;2277 +greateroverequal;2267 +greatersmall;FE65 +gscript;0261 +gstroke;01E5 +guhiragana;3050 +guillemotleft;00AB +guillemotright;00BB +guilsinglleft;2039 +guilsinglright;203A +gukatakana;30B0 +guramusquare;3318 +gysquare;33C9 +h;0068 +haabkhasiancyrillic;04A9 +haaltonearabic;06C1 +habengali;09B9 +hadescendercyrillic;04B3 +hadeva;0939 +hagujarati;0AB9 +hagurmukhi;0A39 +haharabic;062D +hahfinalarabic;FEA2 +hahinitialarabic;FEA3 +hahiragana;306F +hahmedialarabic;FEA4 +haitusquare;332A +hakatakana;30CF +hakatakanahalfwidth;FF8A +halantgurmukhi;0A4D +hamzaarabic;0621 +hamzadammaarabic;0621 064F +hamzadammatanarabic;0621 064C +hamzafathaarabic;0621 064E +hamzafathatanarabic;0621 064B +hamzalowarabic;0621 +hamzalowkasraarabic;0621 0650 +hamzalowkasratanarabic;0621 064D +hamzasukunarabic;0621 0652 +hangulfiller;3164 +hardsigncyrillic;044A +harpoonleftbarbup;21BC +harpoonrightbarbup;21C0 +hasquare;33CA +hatafpatah;05B2 +hatafpatah16;05B2 +hatafpatah23;05B2 +hatafpatah2f;05B2 +hatafpatahhebrew;05B2 +hatafpatahnarrowhebrew;05B2 +hatafpatahquarterhebrew;05B2 +hatafpatahwidehebrew;05B2 +hatafqamats;05B3 +hatafqamats1b;05B3 +hatafqamats28;05B3 +hatafqamats34;05B3 +hatafqamatshebrew;05B3 +hatafqamatsnarrowhebrew;05B3 +hatafqamatsquarterhebrew;05B3 +hatafqamatswidehebrew;05B3 +hatafsegol;05B1 +hatafsegol17;05B1 +hatafsegol24;05B1 +hatafsegol30;05B1 +hatafsegolhebrew;05B1 +hatafsegolnarrowhebrew;05B1 +hatafsegolquarterhebrew;05B1 +hatafsegolwidehebrew;05B1 +hbar;0127 +hbopomofo;310F +hbrevebelow;1E2B +hcedilla;1E29 +hcircle;24D7 +hcircumflex;0125 +hdieresis;1E27 +hdotaccent;1E23 +hdotbelow;1E25 +he;05D4 +heart;2665 +heartsuitblack;2665 +heartsuitwhite;2661 +hedagesh;FB34 +hedageshhebrew;FB34 +hehaltonearabic;06C1 +heharabic;0647 +hehebrew;05D4 +hehfinalaltonearabic;FBA7 +hehfinalalttwoarabic;FEEA +hehfinalarabic;FEEA +hehhamzaabovefinalarabic;FBA5 +hehhamzaaboveisolatedarabic;FBA4 +hehinitialaltonearabic;FBA8 +hehinitialarabic;FEEB +hehiragana;3078 +hehmedialaltonearabic;FBA9 +hehmedialarabic;FEEC +heiseierasquare;337B +hekatakana;30D8 +hekatakanahalfwidth;FF8D +hekutaarusquare;3336 +henghook;0267 +herutusquare;3339 +het;05D7 +hethebrew;05D7 +hhook;0266 +hhooksuperior;02B1 +hieuhacirclekorean;327B +hieuhaparenkorean;321B +hieuhcirclekorean;326D +hieuhkorean;314E +hieuhparenkorean;320D +hihiragana;3072 +hikatakana;30D2 +hikatakanahalfwidth;FF8B +hiriq;05B4 +hiriq14;05B4 +hiriq21;05B4 +hiriq2d;05B4 +hiriqhebrew;05B4 +hiriqnarrowhebrew;05B4 +hiriqquarterhebrew;05B4 +hiriqwidehebrew;05B4 +hlinebelow;1E96 +hmonospace;FF48 +hoarmenian;0570 +hohipthai;0E2B +hohiragana;307B +hokatakana;30DB +hokatakanahalfwidth;FF8E +holam;05B9 +holam19;05B9 +holam26;05B9 +holam32;05B9 +holamhebrew;05B9 +holamnarrowhebrew;05B9 +holamquarterhebrew;05B9 +holamwidehebrew;05B9 +honokhukthai;0E2E +hookabovecomb;0309 +hookcmb;0309 +hookpalatalizedbelowcmb;0321 +hookretroflexbelowcmb;0322 +hoonsquare;3342 +horicoptic;03E9 +horizontalbar;2015 +horncmb;031B +hotsprings;2668 +house;2302 +hparen;24A3 +hsuperior;02B0 +hturned;0265 +huhiragana;3075 +huiitosquare;3333 +hukatakana;30D5 +hukatakanahalfwidth;FF8C +hungarumlaut;02DD +hungarumlautcmb;030B +hv;0195 +hyphen;002D +hypheninferior;F6E5 +hyphenmonospace;FF0D +hyphensmall;FE63 +hyphensuperior;F6E6 +hyphentwo;2010 +i;0069 +iacute;00ED +iacyrillic;044F +ibengali;0987 +ibopomofo;3127 +ibreve;012D +icaron;01D0 +icircle;24D8 +icircumflex;00EE +icyrillic;0456 +idblgrave;0209 +ideographearthcircle;328F +ideographfirecircle;328B +ideographicallianceparen;323F +ideographiccallparen;323A +ideographiccentrecircle;32A5 +ideographicclose;3006 +ideographiccomma;3001 +ideographiccommaleft;FF64 +ideographiccongratulationparen;3237 +ideographiccorrectcircle;32A3 +ideographicearthparen;322F +ideographicenterpriseparen;323D +ideographicexcellentcircle;329D +ideographicfestivalparen;3240 +ideographicfinancialcircle;3296 +ideographicfinancialparen;3236 +ideographicfireparen;322B +ideographichaveparen;3232 +ideographichighcircle;32A4 +ideographiciterationmark;3005 +ideographiclaborcircle;3298 +ideographiclaborparen;3238 +ideographicleftcircle;32A7 +ideographiclowcircle;32A6 +ideographicmedicinecircle;32A9 +ideographicmetalparen;322E +ideographicmoonparen;322A +ideographicnameparen;3234 +ideographicperiod;3002 +ideographicprintcircle;329E +ideographicreachparen;3243 +ideographicrepresentparen;3239 +ideographicresourceparen;323E +ideographicrightcircle;32A8 +ideographicsecretcircle;3299 +ideographicselfparen;3242 +ideographicsocietyparen;3233 +ideographicspace;3000 +ideographicspecialparen;3235 +ideographicstockparen;3231 +ideographicstudyparen;323B +ideographicsunparen;3230 +ideographicsuperviseparen;323C +ideographicwaterparen;322C +ideographicwoodparen;322D +ideographiczero;3007 +ideographmetalcircle;328E +ideographmooncircle;328A +ideographnamecircle;3294 +ideographsuncircle;3290 +ideographwatercircle;328C +ideographwoodcircle;328D +ideva;0907 +idieresis;00EF +idieresisacute;1E2F +idieresiscyrillic;04E5 +idotbelow;1ECB +iebrevecyrillic;04D7 +iecyrillic;0435 +ieungacirclekorean;3275 +ieungaparenkorean;3215 +ieungcirclekorean;3267 +ieungkorean;3147 +ieungparenkorean;3207 +igrave;00EC +igujarati;0A87 +igurmukhi;0A07 +ihiragana;3044 +ihookabove;1EC9 +iibengali;0988 +iicyrillic;0438 +iideva;0908 +iigujarati;0A88 +iigurmukhi;0A08 +iimatragurmukhi;0A40 +iinvertedbreve;020B +iishortcyrillic;0439 +iivowelsignbengali;09C0 +iivowelsigndeva;0940 +iivowelsigngujarati;0AC0 +ij;0133 +ikatakana;30A4 +ikatakanahalfwidth;FF72 +ikorean;3163 +ilde;02DC +iluyhebrew;05AC +imacron;012B +imacroncyrillic;04E3 +imageorapproximatelyequal;2253 +imatragurmukhi;0A3F +imonospace;FF49 +increment;2206 +infinity;221E +iniarmenian;056B +integral;222B +integralbottom;2321 +integralbt;2321 +integralex;F8F5 +integraltop;2320 +integraltp;2320 +intersection;2229 +intisquare;3305 +invbullet;25D8 +invcircle;25D9 +invsmileface;263B +iocyrillic;0451 +iogonek;012F +iota;03B9 +iotadieresis;03CA +iotadieresistonos;0390 +iotalatin;0269 +iotatonos;03AF +iparen;24A4 +irigurmukhi;0A72 +ismallhiragana;3043 +ismallkatakana;30A3 +ismallkatakanahalfwidth;FF68 +issharbengali;09FA +istroke;0268 +isuperior;F6ED +iterationhiragana;309D +iterationkatakana;30FD +itilde;0129 +itildebelow;1E2D +iubopomofo;3129 +iucyrillic;044E +ivowelsignbengali;09BF +ivowelsigndeva;093F +ivowelsigngujarati;0ABF +izhitsacyrillic;0475 +izhitsadblgravecyrillic;0477 +j;006A +jaarmenian;0571 +jabengali;099C +jadeva;091C +jagujarati;0A9C +jagurmukhi;0A1C +jbopomofo;3110 +jcaron;01F0 +jcircle;24D9 +jcircumflex;0135 +jcrossedtail;029D +jdotlessstroke;025F +jecyrillic;0458 +jeemarabic;062C +jeemfinalarabic;FE9E +jeeminitialarabic;FE9F +jeemmedialarabic;FEA0 +jeharabic;0698 +jehfinalarabic;FB8B +jhabengali;099D +jhadeva;091D +jhagujarati;0A9D +jhagurmukhi;0A1D +jheharmenian;057B +jis;3004 +jmonospace;FF4A +jparen;24A5 +jsuperior;02B2 +k;006B +kabashkircyrillic;04A1 +kabengali;0995 +kacute;1E31 +kacyrillic;043A +kadescendercyrillic;049B +kadeva;0915 +kaf;05DB +kafarabic;0643 +kafdagesh;FB3B +kafdageshhebrew;FB3B +kaffinalarabic;FEDA +kafhebrew;05DB +kafinitialarabic;FEDB +kafmedialarabic;FEDC +kafrafehebrew;FB4D +kagujarati;0A95 +kagurmukhi;0A15 +kahiragana;304B +kahookcyrillic;04C4 +kakatakana;30AB +kakatakanahalfwidth;FF76 +kappa;03BA +kappasymbolgreek;03F0 +kapyeounmieumkorean;3171 +kapyeounphieuphkorean;3184 +kapyeounpieupkorean;3178 +kapyeounssangpieupkorean;3179 +karoriisquare;330D +kashidaautoarabic;0640 +kashidaautonosidebearingarabic;0640 +kasmallkatakana;30F5 +kasquare;3384 +kasraarabic;0650 +kasratanarabic;064D +kastrokecyrillic;049F +katahiraprolongmarkhalfwidth;FF70 +kaverticalstrokecyrillic;049D +kbopomofo;310E +kcalsquare;3389 +kcaron;01E9 +kcedilla;0137 +kcircle;24DA +kcommaaccent;0137 +kdotbelow;1E33 +keharmenian;0584 +kehiragana;3051 +kekatakana;30B1 +kekatakanahalfwidth;FF79 +kenarmenian;056F +kesmallkatakana;30F6 +kgreenlandic;0138 +khabengali;0996 +khacyrillic;0445 +khadeva;0916 +khagujarati;0A96 +khagurmukhi;0A16 +khaharabic;062E +khahfinalarabic;FEA6 +khahinitialarabic;FEA7 +khahmedialarabic;FEA8 +kheicoptic;03E7 +khhadeva;0959 +khhagurmukhi;0A59 +khieukhacirclekorean;3278 +khieukhaparenkorean;3218 +khieukhcirclekorean;326A +khieukhkorean;314B +khieukhparenkorean;320A +khokhaithai;0E02 +khokhonthai;0E05 +khokhuatthai;0E03 +khokhwaithai;0E04 +khomutthai;0E5B +khook;0199 +khorakhangthai;0E06 +khzsquare;3391 +kihiragana;304D +kikatakana;30AD +kikatakanahalfwidth;FF77 +kiroguramusquare;3315 +kiromeetorusquare;3316 +kirosquare;3314 +kiyeokacirclekorean;326E +kiyeokaparenkorean;320E +kiyeokcirclekorean;3260 +kiyeokkorean;3131 +kiyeokparenkorean;3200 +kiyeoksioskorean;3133 +kjecyrillic;045C +klinebelow;1E35 +klsquare;3398 +kmcubedsquare;33A6 +kmonospace;FF4B +kmsquaredsquare;33A2 +kohiragana;3053 +kohmsquare;33C0 +kokaithai;0E01 +kokatakana;30B3 +kokatakanahalfwidth;FF7A +kooposquare;331E +koppacyrillic;0481 +koreanstandardsymbol;327F +koroniscmb;0343 +kparen;24A6 +kpasquare;33AA +ksicyrillic;046F +ktsquare;33CF +kturned;029E +kuhiragana;304F +kukatakana;30AF +kukatakanahalfwidth;FF78 +kvsquare;33B8 +kwsquare;33BE +l;006C +labengali;09B2 +lacute;013A +ladeva;0932 +lagujarati;0AB2 +lagurmukhi;0A32 +lakkhangyaothai;0E45 +lamaleffinalarabic;FEFC +lamalefhamzaabovefinalarabic;FEF8 +lamalefhamzaaboveisolatedarabic;FEF7 +lamalefhamzabelowfinalarabic;FEFA +lamalefhamzabelowisolatedarabic;FEF9 +lamalefisolatedarabic;FEFB +lamalefmaddaabovefinalarabic;FEF6 +lamalefmaddaaboveisolatedarabic;FEF5 +lamarabic;0644 +lambda;03BB +lambdastroke;019B +lamed;05DC +lameddagesh;FB3C +lameddageshhebrew;FB3C +lamedhebrew;05DC +lamedholam;05DC 05B9 +lamedholamdagesh;05DC 05B9 05BC +lamedholamdageshhebrew;05DC 05B9 05BC +lamedholamhebrew;05DC 05B9 +lamfinalarabic;FEDE +lamhahinitialarabic;FCCA +laminitialarabic;FEDF +lamjeeminitialarabic;FCC9 +lamkhahinitialarabic;FCCB +lamlamhehisolatedarabic;FDF2 +lammedialarabic;FEE0 +lammeemhahinitialarabic;FD88 +lammeeminitialarabic;FCCC +lammeemjeeminitialarabic;FEDF FEE4 FEA0 +lammeemkhahinitialarabic;FEDF FEE4 FEA8 +largecircle;25EF +lbar;019A +lbelt;026C +lbopomofo;310C +lcaron;013E +lcedilla;013C +lcircle;24DB +lcircumflexbelow;1E3D +lcommaaccent;013C +ldot;0140 +ldotaccent;0140 +ldotbelow;1E37 +ldotbelowmacron;1E39 +leftangleabovecmb;031A +lefttackbelowcmb;0318 +less;003C +lessequal;2264 +lessequalorgreater;22DA +lessmonospace;FF1C +lessorequivalent;2272 +lessorgreater;2276 +lessoverequal;2266 +lesssmall;FE64 +lezh;026E +lfblock;258C +lhookretroflex;026D +lira;20A4 +liwnarmenian;056C +lj;01C9 +ljecyrillic;0459 +ll;F6C0 +lladeva;0933 +llagujarati;0AB3 +llinebelow;1E3B +llladeva;0934 +llvocalicbengali;09E1 +llvocalicdeva;0961 +llvocalicvowelsignbengali;09E3 +llvocalicvowelsigndeva;0963 +lmiddletilde;026B +lmonospace;FF4C +lmsquare;33D0 +lochulathai;0E2C +logicaland;2227 +logicalnot;00AC +logicalnotreversed;2310 +logicalor;2228 +lolingthai;0E25 +longs;017F +lowlinecenterline;FE4E +lowlinecmb;0332 +lowlinedashed;FE4D +lozenge;25CA +lparen;24A7 +lslash;0142 +lsquare;2113 +lsuperior;F6EE +ltshade;2591 +luthai;0E26 +lvocalicbengali;098C +lvocalicdeva;090C +lvocalicvowelsignbengali;09E2 +lvocalicvowelsigndeva;0962 +lxsquare;33D3 +m;006D +mabengali;09AE +macron;00AF +macronbelowcmb;0331 +macroncmb;0304 +macronlowmod;02CD +macronmonospace;FFE3 +macute;1E3F +madeva;092E +magujarati;0AAE +magurmukhi;0A2E +mahapakhhebrew;05A4 +mahapakhlefthebrew;05A4 +mahiragana;307E +maichattawalowleftthai;F895 +maichattawalowrightthai;F894 +maichattawathai;0E4B +maichattawaupperleftthai;F893 +maieklowleftthai;F88C +maieklowrightthai;F88B +maiekthai;0E48 +maiekupperleftthai;F88A +maihanakatleftthai;F884 +maihanakatthai;0E31 +maitaikhuleftthai;F889 +maitaikhuthai;0E47 +maitholowleftthai;F88F +maitholowrightthai;F88E +maithothai;0E49 +maithoupperleftthai;F88D +maitrilowleftthai;F892 +maitrilowrightthai;F891 +maitrithai;0E4A +maitriupperleftthai;F890 +maiyamokthai;0E46 +makatakana;30DE +makatakanahalfwidth;FF8F +male;2642 +mansyonsquare;3347 +maqafhebrew;05BE +mars;2642 +masoracirclehebrew;05AF +masquare;3383 +mbopomofo;3107 +mbsquare;33D4 +mcircle;24DC +mcubedsquare;33A5 +mdotaccent;1E41 +mdotbelow;1E43 +meemarabic;0645 +meemfinalarabic;FEE2 +meeminitialarabic;FEE3 +meemmedialarabic;FEE4 +meemmeeminitialarabic;FCD1 +meemmeemisolatedarabic;FC48 +meetorusquare;334D +mehiragana;3081 +meizierasquare;337E +mekatakana;30E1 +mekatakanahalfwidth;FF92 +mem;05DE +memdagesh;FB3E +memdageshhebrew;FB3E +memhebrew;05DE +menarmenian;0574 +merkhahebrew;05A5 +merkhakefulahebrew;05A6 +merkhakefulalefthebrew;05A6 +merkhalefthebrew;05A5 +mhook;0271 +mhzsquare;3392 +middledotkatakanahalfwidth;FF65 +middot;00B7 +mieumacirclekorean;3272 +mieumaparenkorean;3212 +mieumcirclekorean;3264 +mieumkorean;3141 +mieumpansioskorean;3170 +mieumparenkorean;3204 +mieumpieupkorean;316E +mieumsioskorean;316F +mihiragana;307F +mikatakana;30DF +mikatakanahalfwidth;FF90 +minus;2212 +minusbelowcmb;0320 +minuscircle;2296 +minusmod;02D7 +minusplus;2213 +minute;2032 +miribaarusquare;334A +mirisquare;3349 +mlonglegturned;0270 +mlsquare;3396 +mmcubedsquare;33A3 +mmonospace;FF4D +mmsquaredsquare;339F +mohiragana;3082 +mohmsquare;33C1 +mokatakana;30E2 +mokatakanahalfwidth;FF93 +molsquare;33D6 +momathai;0E21 +moverssquare;33A7 +moverssquaredsquare;33A8 +mparen;24A8 +mpasquare;33AB +mssquare;33B3 +msuperior;F6EF +mturned;026F +mu;00B5 +mu1;00B5 +muasquare;3382 +muchgreater;226B +muchless;226A +mufsquare;338C +mugreek;03BC +mugsquare;338D +muhiragana;3080 +mukatakana;30E0 +mukatakanahalfwidth;FF91 +mulsquare;3395 +multiply;00D7 +mumsquare;339B +munahhebrew;05A3 +munahlefthebrew;05A3 +musicalnote;266A +musicalnotedbl;266B +musicflatsign;266D +musicsharpsign;266F +mussquare;33B2 +muvsquare;33B6 +muwsquare;33BC +mvmegasquare;33B9 +mvsquare;33B7 +mwmegasquare;33BF +mwsquare;33BD +n;006E +nabengali;09A8 +nabla;2207 +nacute;0144 +nadeva;0928 +nagujarati;0AA8 +nagurmukhi;0A28 +nahiragana;306A +nakatakana;30CA +nakatakanahalfwidth;FF85 +napostrophe;0149 +nasquare;3381 +nbopomofo;310B +nbspace;00A0 +ncaron;0148 +ncedilla;0146 +ncircle;24DD +ncircumflexbelow;1E4B +ncommaaccent;0146 +ndotaccent;1E45 +ndotbelow;1E47 +nehiragana;306D +nekatakana;30CD +nekatakanahalfwidth;FF88 +newsheqelsign;20AA +nfsquare;338B +ngabengali;0999 +ngadeva;0919 +ngagujarati;0A99 +ngagurmukhi;0A19 +ngonguthai;0E07 +nhiragana;3093 +nhookleft;0272 +nhookretroflex;0273 +nieunacirclekorean;326F +nieunaparenkorean;320F +nieuncieuckorean;3135 +nieuncirclekorean;3261 +nieunhieuhkorean;3136 +nieunkorean;3134 +nieunpansioskorean;3168 +nieunparenkorean;3201 +nieunsioskorean;3167 +nieuntikeutkorean;3166 +nihiragana;306B +nikatakana;30CB +nikatakanahalfwidth;FF86 +nikhahitleftthai;F899 +nikhahitthai;0E4D +nine;0039 +ninearabic;0669 +ninebengali;09EF +ninecircle;2468 +ninecircleinversesansserif;2792 +ninedeva;096F +ninegujarati;0AEF +ninegurmukhi;0A6F +ninehackarabic;0669 +ninehangzhou;3029 +nineideographicparen;3228 +nineinferior;2089 +ninemonospace;FF19 +nineoldstyle;F739 +nineparen;247C +nineperiod;2490 +ninepersian;06F9 +nineroman;2178 +ninesuperior;2079 +nineteencircle;2472 +nineteenparen;2486 +nineteenperiod;249A +ninethai;0E59 +nj;01CC +njecyrillic;045A +nkatakana;30F3 +nkatakanahalfwidth;FF9D +nlegrightlong;019E +nlinebelow;1E49 +nmonospace;FF4E +nmsquare;339A +nnabengali;09A3 +nnadeva;0923 +nnagujarati;0AA3 +nnagurmukhi;0A23 +nnnadeva;0929 +nohiragana;306E +nokatakana;30CE +nokatakanahalfwidth;FF89 +nonbreakingspace;00A0 +nonenthai;0E13 +nonuthai;0E19 +noonarabic;0646 +noonfinalarabic;FEE6 +noonghunnaarabic;06BA +noonghunnafinalarabic;FB9F +noonhehinitialarabic;FEE7 FEEC +nooninitialarabic;FEE7 +noonjeeminitialarabic;FCD2 +noonjeemisolatedarabic;FC4B +noonmedialarabic;FEE8 +noonmeeminitialarabic;FCD5 +noonmeemisolatedarabic;FC4E +noonnoonfinalarabic;FC8D +notcontains;220C +notelement;2209 +notelementof;2209 +notequal;2260 +notgreater;226F +notgreaternorequal;2271 +notgreaternorless;2279 +notidentical;2262 +notless;226E +notlessnorequal;2270 +notparallel;2226 +notprecedes;2280 +notsubset;2284 +notsucceeds;2281 +notsuperset;2285 +nowarmenian;0576 +nparen;24A9 +nssquare;33B1 +nsuperior;207F +ntilde;00F1 +nu;03BD +nuhiragana;306C +nukatakana;30CC +nukatakanahalfwidth;FF87 +nuktabengali;09BC +nuktadeva;093C +nuktagujarati;0ABC +nuktagurmukhi;0A3C +numbersign;0023 +numbersignmonospace;FF03 +numbersignsmall;FE5F +numeralsigngreek;0374 +numeralsignlowergreek;0375 +numero;2116 +nun;05E0 +nundagesh;FB40 +nundageshhebrew;FB40 +nunhebrew;05E0 +nvsquare;33B5 +nwsquare;33BB +nyabengali;099E +nyadeva;091E +nyagujarati;0A9E +nyagurmukhi;0A1E +o;006F +oacute;00F3 +oangthai;0E2D +obarred;0275 +obarredcyrillic;04E9 +obarreddieresiscyrillic;04EB +obengali;0993 +obopomofo;311B +obreve;014F +ocandradeva;0911 +ocandragujarati;0A91 +ocandravowelsigndeva;0949 +ocandravowelsigngujarati;0AC9 +ocaron;01D2 +ocircle;24DE +ocircumflex;00F4 +ocircumflexacute;1ED1 +ocircumflexdotbelow;1ED9 +ocircumflexgrave;1ED3 +ocircumflexhookabove;1ED5 +ocircumflextilde;1ED7 +ocyrillic;043E +odblacute;0151 +odblgrave;020D +odeva;0913 +odieresis;00F6 +odieresiscyrillic;04E7 +odotbelow;1ECD +oe;0153 +oekorean;315A +ogonek;02DB +ogonekcmb;0328 +ograve;00F2 +ogujarati;0A93 +oharmenian;0585 +ohiragana;304A +ohookabove;1ECF +ohorn;01A1 +ohornacute;1EDB +ohorndotbelow;1EE3 +ohorngrave;1EDD +ohornhookabove;1EDF +ohorntilde;1EE1 +ohungarumlaut;0151 +oi;01A3 +oinvertedbreve;020F +okatakana;30AA +okatakanahalfwidth;FF75 +okorean;3157 +olehebrew;05AB +omacron;014D +omacronacute;1E53 +omacrongrave;1E51 +omdeva;0950 +omega;03C9 +omega1;03D6 +omegacyrillic;0461 +omegalatinclosed;0277 +omegaroundcyrillic;047B +omegatitlocyrillic;047D +omegatonos;03CE +omgujarati;0AD0 +omicron;03BF +omicrontonos;03CC +omonospace;FF4F +one;0031 +onearabic;0661 +onebengali;09E7 +onecircle;2460 +onecircleinversesansserif;278A +onedeva;0967 +onedotenleader;2024 +oneeighth;215B +onefitted;F6DC +onegujarati;0AE7 +onegurmukhi;0A67 +onehackarabic;0661 +onehalf;00BD +onehangzhou;3021 +oneideographicparen;3220 +oneinferior;2081 +onemonospace;FF11 +onenumeratorbengali;09F4 +oneoldstyle;F731 +oneparen;2474 +oneperiod;2488 +onepersian;06F1 +onequarter;00BC +oneroman;2170 +onesuperior;00B9 +onethai;0E51 +onethird;2153 +oogonek;01EB +oogonekmacron;01ED +oogurmukhi;0A13 +oomatragurmukhi;0A4B +oopen;0254 +oparen;24AA +openbullet;25E6 +option;2325 +ordfeminine;00AA +ordmasculine;00BA +orthogonal;221F +oshortdeva;0912 +oshortvowelsigndeva;094A +oslash;00F8 +oslashacute;01FF +osmallhiragana;3049 +osmallkatakana;30A9 +osmallkatakanahalfwidth;FF6B +ostrokeacute;01FF +osuperior;F6F0 +otcyrillic;047F +otilde;00F5 +otildeacute;1E4D +otildedieresis;1E4F +oubopomofo;3121 +overline;203E +overlinecenterline;FE4A +overlinecmb;0305 +overlinedashed;FE49 +overlinedblwavy;FE4C +overlinewavy;FE4B +overscore;00AF +ovowelsignbengali;09CB +ovowelsigndeva;094B +ovowelsigngujarati;0ACB +p;0070 +paampssquare;3380 +paasentosquare;332B +pabengali;09AA +pacute;1E55 +padeva;092A +pagedown;21DF +pageup;21DE +pagujarati;0AAA +pagurmukhi;0A2A +pahiragana;3071 +paiyannoithai;0E2F +pakatakana;30D1 +palatalizationcyrilliccmb;0484 +palochkacyrillic;04C0 +pansioskorean;317F +paragraph;00B6 +parallel;2225 +parenleft;0028 +parenleftaltonearabic;FD3E +parenleftbt;F8ED +parenleftex;F8EC +parenleftinferior;208D +parenleftmonospace;FF08 +parenleftsmall;FE59 +parenleftsuperior;207D +parenlefttp;F8EB +parenleftvertical;FE35 +parenright;0029 +parenrightaltonearabic;FD3F +parenrightbt;F8F8 +parenrightex;F8F7 +parenrightinferior;208E +parenrightmonospace;FF09 +parenrightsmall;FE5A +parenrightsuperior;207E +parenrighttp;F8F6 +parenrightvertical;FE36 +partialdiff;2202 +paseqhebrew;05C0 +pashtahebrew;0599 +pasquare;33A9 +patah;05B7 +patah11;05B7 +patah1d;05B7 +patah2a;05B7 +patahhebrew;05B7 +patahnarrowhebrew;05B7 +patahquarterhebrew;05B7 +patahwidehebrew;05B7 +pazerhebrew;05A1 +pbopomofo;3106 +pcircle;24DF +pdotaccent;1E57 +pe;05E4 +pecyrillic;043F +pedagesh;FB44 +pedageshhebrew;FB44 +peezisquare;333B +pefinaldageshhebrew;FB43 +peharabic;067E +peharmenian;057A +pehebrew;05E4 +pehfinalarabic;FB57 +pehinitialarabic;FB58 +pehiragana;307A +pehmedialarabic;FB59 +pekatakana;30DA +pemiddlehookcyrillic;04A7 +perafehebrew;FB4E +percent;0025 +percentarabic;066A +percentmonospace;FF05 +percentsmall;FE6A +period;002E +periodarmenian;0589 +periodcentered;00B7 +periodhalfwidth;FF61 +periodinferior;F6E7 +periodmonospace;FF0E +periodsmall;FE52 +periodsuperior;F6E8 +perispomenigreekcmb;0342 +perpendicular;22A5 +perthousand;2030 +peseta;20A7 +pfsquare;338A +phabengali;09AB +phadeva;092B +phagujarati;0AAB +phagurmukhi;0A2B +phi;03C6 +phi1;03D5 +phieuphacirclekorean;327A +phieuphaparenkorean;321A +phieuphcirclekorean;326C +phieuphkorean;314D +phieuphparenkorean;320C +philatin;0278 +phinthuthai;0E3A +phisymbolgreek;03D5 +phook;01A5 +phophanthai;0E1E +phophungthai;0E1C +phosamphaothai;0E20 +pi;03C0 +pieupacirclekorean;3273 +pieupaparenkorean;3213 +pieupcieuckorean;3176 +pieupcirclekorean;3265 +pieupkiyeokkorean;3172 +pieupkorean;3142 +pieupparenkorean;3205 +pieupsioskiyeokkorean;3174 +pieupsioskorean;3144 +pieupsiostikeutkorean;3175 +pieupthieuthkorean;3177 +pieuptikeutkorean;3173 +pihiragana;3074 +pikatakana;30D4 +pisymbolgreek;03D6 +piwrarmenian;0583 +plus;002B +plusbelowcmb;031F +pluscircle;2295 +plusminus;00B1 +plusmod;02D6 +plusmonospace;FF0B +plussmall;FE62 +plussuperior;207A +pmonospace;FF50 +pmsquare;33D8 +pohiragana;307D +pointingindexdownwhite;261F +pointingindexleftwhite;261C +pointingindexrightwhite;261E +pointingindexupwhite;261D +pokatakana;30DD +poplathai;0E1B +postalmark;3012 +postalmarkface;3020 +pparen;24AB +precedes;227A +prescription;211E +primemod;02B9 +primereversed;2035 +product;220F +projective;2305 +prolongedkana;30FC +propellor;2318 +propersubset;2282 +propersuperset;2283 +proportion;2237 +proportional;221D +psi;03C8 +psicyrillic;0471 +psilipneumatacyrilliccmb;0486 +pssquare;33B0 +puhiragana;3077 +pukatakana;30D7 +pvsquare;33B4 +pwsquare;33BA +q;0071 +qadeva;0958 +qadmahebrew;05A8 +qafarabic;0642 +qaffinalarabic;FED6 +qafinitialarabic;FED7 +qafmedialarabic;FED8 +qamats;05B8 +qamats10;05B8 +qamats1a;05B8 +qamats1c;05B8 +qamats27;05B8 +qamats29;05B8 +qamats33;05B8 +qamatsde;05B8 +qamatshebrew;05B8 +qamatsnarrowhebrew;05B8 +qamatsqatanhebrew;05B8 +qamatsqatannarrowhebrew;05B8 +qamatsqatanquarterhebrew;05B8 +qamatsqatanwidehebrew;05B8 +qamatsquarterhebrew;05B8 +qamatswidehebrew;05B8 +qarneyparahebrew;059F +qbopomofo;3111 +qcircle;24E0 +qhook;02A0 +qmonospace;FF51 +qof;05E7 +qofdagesh;FB47 +qofdageshhebrew;FB47 +qofhatafpatah;05E7 05B2 +qofhatafpatahhebrew;05E7 05B2 +qofhatafsegol;05E7 05B1 +qofhatafsegolhebrew;05E7 05B1 +qofhebrew;05E7 +qofhiriq;05E7 05B4 +qofhiriqhebrew;05E7 05B4 +qofholam;05E7 05B9 +qofholamhebrew;05E7 05B9 +qofpatah;05E7 05B7 +qofpatahhebrew;05E7 05B7 +qofqamats;05E7 05B8 +qofqamatshebrew;05E7 05B8 +qofqubuts;05E7 05BB +qofqubutshebrew;05E7 05BB +qofsegol;05E7 05B6 +qofsegolhebrew;05E7 05B6 +qofsheva;05E7 05B0 +qofshevahebrew;05E7 05B0 +qoftsere;05E7 05B5 +qoftserehebrew;05E7 05B5 +qparen;24AC +quarternote;2669 +qubuts;05BB +qubuts18;05BB +qubuts25;05BB +qubuts31;05BB +qubutshebrew;05BB +qubutsnarrowhebrew;05BB +qubutsquarterhebrew;05BB +qubutswidehebrew;05BB +question;003F +questionarabic;061F +questionarmenian;055E +questiondown;00BF +questiondownsmall;F7BF +questiongreek;037E +questionmonospace;FF1F +questionsmall;F73F +quotedbl;0022 +quotedblbase;201E +quotedblleft;201C +quotedblmonospace;FF02 +quotedblprime;301E +quotedblprimereversed;301D +quotedblright;201D +quoteleft;2018 +quoteleftreversed;201B +quotereversed;201B +quoteright;2019 +quoterightn;0149 +quotesinglbase;201A +quotesingle;0027 +quotesinglemonospace;FF07 +r;0072 +raarmenian;057C +rabengali;09B0 +racute;0155 +radeva;0930 +radical;221A +radicalex;F8E5 +radoverssquare;33AE +radoverssquaredsquare;33AF +radsquare;33AD +rafe;05BF +rafehebrew;05BF +ragujarati;0AB0 +ragurmukhi;0A30 +rahiragana;3089 +rakatakana;30E9 +rakatakanahalfwidth;FF97 +ralowerdiagonalbengali;09F1 +ramiddlediagonalbengali;09F0 +ramshorn;0264 +ratio;2236 +rbopomofo;3116 +rcaron;0159 +rcedilla;0157 +rcircle;24E1 +rcommaaccent;0157 +rdblgrave;0211 +rdotaccent;1E59 +rdotbelow;1E5B +rdotbelowmacron;1E5D +referencemark;203B +reflexsubset;2286 +reflexsuperset;2287 +registered;00AE +registersans;F8E8 +registerserif;F6DA +reharabic;0631 +reharmenian;0580 +rehfinalarabic;FEAE +rehiragana;308C +rehyehaleflamarabic;0631 FEF3 FE8E 0644 +rekatakana;30EC +rekatakanahalfwidth;FF9A +resh;05E8 +reshdageshhebrew;FB48 +reshhatafpatah;05E8 05B2 +reshhatafpatahhebrew;05E8 05B2 +reshhatafsegol;05E8 05B1 +reshhatafsegolhebrew;05E8 05B1 +reshhebrew;05E8 +reshhiriq;05E8 05B4 +reshhiriqhebrew;05E8 05B4 +reshholam;05E8 05B9 +reshholamhebrew;05E8 05B9 +reshpatah;05E8 05B7 +reshpatahhebrew;05E8 05B7 +reshqamats;05E8 05B8 +reshqamatshebrew;05E8 05B8 +reshqubuts;05E8 05BB +reshqubutshebrew;05E8 05BB +reshsegol;05E8 05B6 +reshsegolhebrew;05E8 05B6 +reshsheva;05E8 05B0 +reshshevahebrew;05E8 05B0 +reshtsere;05E8 05B5 +reshtserehebrew;05E8 05B5 +reversedtilde;223D +reviahebrew;0597 +reviamugrashhebrew;0597 +revlogicalnot;2310 +rfishhook;027E +rfishhookreversed;027F +rhabengali;09DD +rhadeva;095D +rho;03C1 +rhook;027D +rhookturned;027B +rhookturnedsuperior;02B5 +rhosymbolgreek;03F1 +rhotichookmod;02DE +rieulacirclekorean;3271 +rieulaparenkorean;3211 +rieulcirclekorean;3263 +rieulhieuhkorean;3140 +rieulkiyeokkorean;313A +rieulkiyeoksioskorean;3169 +rieulkorean;3139 +rieulmieumkorean;313B +rieulpansioskorean;316C +rieulparenkorean;3203 +rieulphieuphkorean;313F +rieulpieupkorean;313C +rieulpieupsioskorean;316B +rieulsioskorean;313D +rieulthieuthkorean;313E +rieultikeutkorean;316A +rieulyeorinhieuhkorean;316D +rightangle;221F +righttackbelowcmb;0319 +righttriangle;22BF +rihiragana;308A +rikatakana;30EA +rikatakanahalfwidth;FF98 +ring;02DA +ringbelowcmb;0325 +ringcmb;030A +ringhalfleft;02BF +ringhalfleftarmenian;0559 +ringhalfleftbelowcmb;031C +ringhalfleftcentered;02D3 +ringhalfright;02BE +ringhalfrightbelowcmb;0339 +ringhalfrightcentered;02D2 +rinvertedbreve;0213 +rittorusquare;3351 +rlinebelow;1E5F +rlongleg;027C +rlonglegturned;027A +rmonospace;FF52 +rohiragana;308D +rokatakana;30ED +rokatakanahalfwidth;FF9B +roruathai;0E23 +rparen;24AD +rrabengali;09DC +rradeva;0931 +rragurmukhi;0A5C +rreharabic;0691 +rrehfinalarabic;FB8D +rrvocalicbengali;09E0 +rrvocalicdeva;0960 +rrvocalicgujarati;0AE0 +rrvocalicvowelsignbengali;09C4 +rrvocalicvowelsigndeva;0944 +rrvocalicvowelsigngujarati;0AC4 +rsuperior;F6F1 +rtblock;2590 +rturned;0279 +rturnedsuperior;02B4 +ruhiragana;308B +rukatakana;30EB +rukatakanahalfwidth;FF99 +rupeemarkbengali;09F2 +rupeesignbengali;09F3 +rupiah;F6DD +ruthai;0E24 +rvocalicbengali;098B +rvocalicdeva;090B +rvocalicgujarati;0A8B +rvocalicvowelsignbengali;09C3 +rvocalicvowelsigndeva;0943 +rvocalicvowelsigngujarati;0AC3 +s;0073 +sabengali;09B8 +sacute;015B +sacutedotaccent;1E65 +sadarabic;0635 +sadeva;0938 +sadfinalarabic;FEBA +sadinitialarabic;FEBB +sadmedialarabic;FEBC +sagujarati;0AB8 +sagurmukhi;0A38 +sahiragana;3055 +sakatakana;30B5 +sakatakanahalfwidth;FF7B +sallallahoualayhewasallamarabic;FDFA +samekh;05E1 +samekhdagesh;FB41 +samekhdageshhebrew;FB41 +samekhhebrew;05E1 +saraaathai;0E32 +saraaethai;0E41 +saraaimaimalaithai;0E44 +saraaimaimuanthai;0E43 +saraamthai;0E33 +saraathai;0E30 +saraethai;0E40 +saraiileftthai;F886 +saraiithai;0E35 +saraileftthai;F885 +saraithai;0E34 +saraothai;0E42 +saraueeleftthai;F888 +saraueethai;0E37 +saraueleftthai;F887 +sarauethai;0E36 +sarauthai;0E38 +sarauuthai;0E39 +sbopomofo;3119 +scaron;0161 +scarondotaccent;1E67 +scedilla;015F +schwa;0259 +schwacyrillic;04D9 +schwadieresiscyrillic;04DB +schwahook;025A +scircle;24E2 +scircumflex;015D +scommaaccent;0219 +sdotaccent;1E61 +sdotbelow;1E63 +sdotbelowdotaccent;1E69 +seagullbelowcmb;033C +second;2033 +secondtonechinese;02CA +section;00A7 +seenarabic;0633 +seenfinalarabic;FEB2 +seeninitialarabic;FEB3 +seenmedialarabic;FEB4 +segol;05B6 +segol13;05B6 +segol1f;05B6 +segol2c;05B6 +segolhebrew;05B6 +segolnarrowhebrew;05B6 +segolquarterhebrew;05B6 +segoltahebrew;0592 +segolwidehebrew;05B6 +seharmenian;057D +sehiragana;305B +sekatakana;30BB +sekatakanahalfwidth;FF7E +semicolon;003B +semicolonarabic;061B +semicolonmonospace;FF1B +semicolonsmall;FE54 +semivoicedmarkkana;309C +semivoicedmarkkanahalfwidth;FF9F +sentisquare;3322 +sentosquare;3323 +seven;0037 +sevenarabic;0667 +sevenbengali;09ED +sevencircle;2466 +sevencircleinversesansserif;2790 +sevendeva;096D +seveneighths;215E +sevengujarati;0AED +sevengurmukhi;0A6D +sevenhackarabic;0667 +sevenhangzhou;3027 +sevenideographicparen;3226 +seveninferior;2087 +sevenmonospace;FF17 +sevenoldstyle;F737 +sevenparen;247A +sevenperiod;248E +sevenpersian;06F7 +sevenroman;2176 +sevensuperior;2077 +seventeencircle;2470 +seventeenparen;2484 +seventeenperiod;2498 +seventhai;0E57 +sfthyphen;00AD +shaarmenian;0577 +shabengali;09B6 +shacyrillic;0448 +shaddaarabic;0651 +shaddadammaarabic;FC61 +shaddadammatanarabic;FC5E +shaddafathaarabic;FC60 +shaddafathatanarabic;0651 064B +shaddakasraarabic;FC62 +shaddakasratanarabic;FC5F +shade;2592 +shadedark;2593 +shadelight;2591 +shademedium;2592 +shadeva;0936 +shagujarati;0AB6 +shagurmukhi;0A36 +shalshelethebrew;0593 +shbopomofo;3115 +shchacyrillic;0449 +sheenarabic;0634 +sheenfinalarabic;FEB6 +sheeninitialarabic;FEB7 +sheenmedialarabic;FEB8 +sheicoptic;03E3 +sheqel;20AA +sheqelhebrew;20AA +sheva;05B0 +sheva115;05B0 +sheva15;05B0 +sheva22;05B0 +sheva2e;05B0 +shevahebrew;05B0 +shevanarrowhebrew;05B0 +shevaquarterhebrew;05B0 +shevawidehebrew;05B0 +shhacyrillic;04BB +shimacoptic;03ED +shin;05E9 +shindagesh;FB49 +shindageshhebrew;FB49 +shindageshshindot;FB2C +shindageshshindothebrew;FB2C +shindageshsindot;FB2D +shindageshsindothebrew;FB2D +shindothebrew;05C1 +shinhebrew;05E9 +shinshindot;FB2A +shinshindothebrew;FB2A +shinsindot;FB2B +shinsindothebrew;FB2B +shook;0282 +sigma;03C3 +sigma1;03C2 +sigmafinal;03C2 +sigmalunatesymbolgreek;03F2 +sihiragana;3057 +sikatakana;30B7 +sikatakanahalfwidth;FF7C +siluqhebrew;05BD +siluqlefthebrew;05BD +similar;223C +sindothebrew;05C2 +siosacirclekorean;3274 +siosaparenkorean;3214 +sioscieuckorean;317E +sioscirclekorean;3266 +sioskiyeokkorean;317A +sioskorean;3145 +siosnieunkorean;317B +siosparenkorean;3206 +siospieupkorean;317D +siostikeutkorean;317C +six;0036 +sixarabic;0666 +sixbengali;09EC +sixcircle;2465 +sixcircleinversesansserif;278F +sixdeva;096C +sixgujarati;0AEC +sixgurmukhi;0A6C +sixhackarabic;0666 +sixhangzhou;3026 +sixideographicparen;3225 +sixinferior;2086 +sixmonospace;FF16 +sixoldstyle;F736 +sixparen;2479 +sixperiod;248D +sixpersian;06F6 +sixroman;2175 +sixsuperior;2076 +sixteencircle;246F +sixteencurrencydenominatorbengali;09F9 +sixteenparen;2483 +sixteenperiod;2497 +sixthai;0E56 +slash;002F +slashmonospace;FF0F +slong;017F +slongdotaccent;1E9B +smileface;263A +smonospace;FF53 +sofpasuqhebrew;05C3 +softhyphen;00AD +softsigncyrillic;044C +sohiragana;305D +sokatakana;30BD +sokatakanahalfwidth;FF7F +soliduslongoverlaycmb;0338 +solidusshortoverlaycmb;0337 +sorusithai;0E29 +sosalathai;0E28 +sosothai;0E0B +sosuathai;0E2A +space;0020 +spacehackarabic;0020 +spade;2660 +spadesuitblack;2660 +spadesuitwhite;2664 +sparen;24AE +squarebelowcmb;033B +squarecc;33C4 +squarecm;339D +squarediagonalcrosshatchfill;25A9 +squarehorizontalfill;25A4 +squarekg;338F +squarekm;339E +squarekmcapital;33CE +squareln;33D1 +squarelog;33D2 +squaremg;338E +squaremil;33D5 +squaremm;339C +squaremsquared;33A1 +squareorthogonalcrosshatchfill;25A6 +squareupperlefttolowerrightfill;25A7 +squareupperrighttolowerleftfill;25A8 +squareverticalfill;25A5 +squarewhitewithsmallblack;25A3 +srsquare;33DB +ssabengali;09B7 +ssadeva;0937 +ssagujarati;0AB7 +ssangcieuckorean;3149 +ssanghieuhkorean;3185 +ssangieungkorean;3180 +ssangkiyeokkorean;3132 +ssangnieunkorean;3165 +ssangpieupkorean;3143 +ssangsioskorean;3146 +ssangtikeutkorean;3138 +ssuperior;F6F2 +sterling;00A3 +sterlingmonospace;FFE1 +strokelongoverlaycmb;0336 +strokeshortoverlaycmb;0335 +subset;2282 +subsetnotequal;228A +subsetorequal;2286 +succeeds;227B +suchthat;220B +suhiragana;3059 +sukatakana;30B9 +sukatakanahalfwidth;FF7D +sukunarabic;0652 +summation;2211 +sun;263C +superset;2283 +supersetnotequal;228B +supersetorequal;2287 +svsquare;33DC +syouwaerasquare;337C +t;0074 +tabengali;09A4 +tackdown;22A4 +tackleft;22A3 +tadeva;0924 +tagujarati;0AA4 +tagurmukhi;0A24 +taharabic;0637 +tahfinalarabic;FEC2 +tahinitialarabic;FEC3 +tahiragana;305F +tahmedialarabic;FEC4 +taisyouerasquare;337D +takatakana;30BF +takatakanahalfwidth;FF80 +tatweelarabic;0640 +tau;03C4 +tav;05EA +tavdages;FB4A +tavdagesh;FB4A +tavdageshhebrew;FB4A +tavhebrew;05EA +tbar;0167 +tbopomofo;310A +tcaron;0165 +tccurl;02A8 +tcedilla;0163 +tcheharabic;0686 +tchehfinalarabic;FB7B +tchehinitialarabic;FB7C +tchehmedialarabic;FB7D +tchehmeeminitialarabic;FB7C FEE4 +tcircle;24E3 +tcircumflexbelow;1E71 +tcommaaccent;0163 +tdieresis;1E97 +tdotaccent;1E6B +tdotbelow;1E6D +tecyrillic;0442 +tedescendercyrillic;04AD +teharabic;062A +tehfinalarabic;FE96 +tehhahinitialarabic;FCA2 +tehhahisolatedarabic;FC0C +tehinitialarabic;FE97 +tehiragana;3066 +tehjeeminitialarabic;FCA1 +tehjeemisolatedarabic;FC0B +tehmarbutaarabic;0629 +tehmarbutafinalarabic;FE94 +tehmedialarabic;FE98 +tehmeeminitialarabic;FCA4 +tehmeemisolatedarabic;FC0E +tehnoonfinalarabic;FC73 +tekatakana;30C6 +tekatakanahalfwidth;FF83 +telephone;2121 +telephoneblack;260E +telishagedolahebrew;05A0 +telishaqetanahebrew;05A9 +tencircle;2469 +tenideographicparen;3229 +tenparen;247D +tenperiod;2491 +tenroman;2179 +tesh;02A7 +tet;05D8 +tetdagesh;FB38 +tetdageshhebrew;FB38 +tethebrew;05D8 +tetsecyrillic;04B5 +tevirhebrew;059B +tevirlefthebrew;059B +thabengali;09A5 +thadeva;0925 +thagujarati;0AA5 +thagurmukhi;0A25 +thalarabic;0630 +thalfinalarabic;FEAC +thanthakhatlowleftthai;F898 +thanthakhatlowrightthai;F897 +thanthakhatthai;0E4C +thanthakhatupperleftthai;F896 +theharabic;062B +thehfinalarabic;FE9A +thehinitialarabic;FE9B +thehmedialarabic;FE9C +thereexists;2203 +therefore;2234 +theta;03B8 +theta1;03D1 +thetasymbolgreek;03D1 +thieuthacirclekorean;3279 +thieuthaparenkorean;3219 +thieuthcirclekorean;326B +thieuthkorean;314C +thieuthparenkorean;320B +thirteencircle;246C +thirteenparen;2480 +thirteenperiod;2494 +thonangmonthothai;0E11 +thook;01AD +thophuthaothai;0E12 +thorn;00FE +thothahanthai;0E17 +thothanthai;0E10 +thothongthai;0E18 +thothungthai;0E16 +thousandcyrillic;0482 +thousandsseparatorarabic;066C +thousandsseparatorpersian;066C +three;0033 +threearabic;0663 +threebengali;09E9 +threecircle;2462 +threecircleinversesansserif;278C +threedeva;0969 +threeeighths;215C +threegujarati;0AE9 +threegurmukhi;0A69 +threehackarabic;0663 +threehangzhou;3023 +threeideographicparen;3222 +threeinferior;2083 +threemonospace;FF13 +threenumeratorbengali;09F6 +threeoldstyle;F733 +threeparen;2476 +threeperiod;248A +threepersian;06F3 +threequarters;00BE +threequartersemdash;F6DE +threeroman;2172 +threesuperior;00B3 +threethai;0E53 +thzsquare;3394 +tihiragana;3061 +tikatakana;30C1 +tikatakanahalfwidth;FF81 +tikeutacirclekorean;3270 +tikeutaparenkorean;3210 +tikeutcirclekorean;3262 +tikeutkorean;3137 +tikeutparenkorean;3202 +tilde;02DC +tildebelowcmb;0330 +tildecmb;0303 +tildecomb;0303 +tildedoublecmb;0360 +tildeoperator;223C +tildeoverlaycmb;0334 +tildeverticalcmb;033E +timescircle;2297 +tipehahebrew;0596 +tipehalefthebrew;0596 +tippigurmukhi;0A70 +titlocyrilliccmb;0483 +tiwnarmenian;057F +tlinebelow;1E6F +tmonospace;FF54 +toarmenian;0569 +tohiragana;3068 +tokatakana;30C8 +tokatakanahalfwidth;FF84 +tonebarextrahighmod;02E5 +tonebarextralowmod;02E9 +tonebarhighmod;02E6 +tonebarlowmod;02E8 +tonebarmidmod;02E7 +tonefive;01BD +tonesix;0185 +tonetwo;01A8 +tonos;0384 +tonsquare;3327 +topatakthai;0E0F +tortoiseshellbracketleft;3014 +tortoiseshellbracketleftsmall;FE5D +tortoiseshellbracketleftvertical;FE39 +tortoiseshellbracketright;3015 +tortoiseshellbracketrightsmall;FE5E +tortoiseshellbracketrightvertical;FE3A +totaothai;0E15 +tpalatalhook;01AB +tparen;24AF +trademark;2122 +trademarksans;F8EA +trademarkserif;F6DB +tretroflexhook;0288 +triagdn;25BC +triaglf;25C4 +triagrt;25BA +triagup;25B2 +ts;02A6 +tsadi;05E6 +tsadidagesh;FB46 +tsadidageshhebrew;FB46 +tsadihebrew;05E6 +tsecyrillic;0446 +tsere;05B5 +tsere12;05B5 +tsere1e;05B5 +tsere2b;05B5 +tserehebrew;05B5 +tserenarrowhebrew;05B5 +tserequarterhebrew;05B5 +tserewidehebrew;05B5 +tshecyrillic;045B +tsuperior;F6F3 +ttabengali;099F +ttadeva;091F +ttagujarati;0A9F +ttagurmukhi;0A1F +tteharabic;0679 +ttehfinalarabic;FB67 +ttehinitialarabic;FB68 +ttehmedialarabic;FB69 +tthabengali;09A0 +tthadeva;0920 +tthagujarati;0AA0 +tthagurmukhi;0A20 +tturned;0287 +tuhiragana;3064 +tukatakana;30C4 +tukatakanahalfwidth;FF82 +tusmallhiragana;3063 +tusmallkatakana;30C3 +tusmallkatakanahalfwidth;FF6F +twelvecircle;246B +twelveparen;247F +twelveperiod;2493 +twelveroman;217B +twentycircle;2473 +twentyhangzhou;5344 +twentyparen;2487 +twentyperiod;249B +two;0032 +twoarabic;0662 +twobengali;09E8 +twocircle;2461 +twocircleinversesansserif;278B +twodeva;0968 +twodotenleader;2025 +twodotleader;2025 +twodotleadervertical;FE30 +twogujarati;0AE8 +twogurmukhi;0A68 +twohackarabic;0662 +twohangzhou;3022 +twoideographicparen;3221 +twoinferior;2082 +twomonospace;FF12 +twonumeratorbengali;09F5 +twooldstyle;F732 +twoparen;2475 +twoperiod;2489 +twopersian;06F2 +tworoman;2171 +twostroke;01BB +twosuperior;00B2 +twothai;0E52 +twothirds;2154 +u;0075 +uacute;00FA +ubar;0289 +ubengali;0989 +ubopomofo;3128 +ubreve;016D +ucaron;01D4 +ucircle;24E4 +ucircumflex;00FB +ucircumflexbelow;1E77 +ucyrillic;0443 +udattadeva;0951 +udblacute;0171 +udblgrave;0215 +udeva;0909 +udieresis;00FC +udieresisacute;01D8 +udieresisbelow;1E73 +udieresiscaron;01DA +udieresiscyrillic;04F1 +udieresisgrave;01DC +udieresismacron;01D6 +udotbelow;1EE5 +ugrave;00F9 +ugujarati;0A89 +ugurmukhi;0A09 +uhiragana;3046 +uhookabove;1EE7 +uhorn;01B0 +uhornacute;1EE9 +uhorndotbelow;1EF1 +uhorngrave;1EEB +uhornhookabove;1EED +uhorntilde;1EEF +uhungarumlaut;0171 +uhungarumlautcyrillic;04F3 +uinvertedbreve;0217 +ukatakana;30A6 +ukatakanahalfwidth;FF73 +ukcyrillic;0479 +ukorean;315C +umacron;016B +umacroncyrillic;04EF +umacrondieresis;1E7B +umatragurmukhi;0A41 +umonospace;FF55 +underscore;005F +underscoredbl;2017 +underscoremonospace;FF3F +underscorevertical;FE33 +underscorewavy;FE4F +union;222A +universal;2200 +uogonek;0173 +uparen;24B0 +upblock;2580 +upperdothebrew;05C4 +upsilon;03C5 +upsilondieresis;03CB +upsilondieresistonos;03B0 +upsilonlatin;028A +upsilontonos;03CD +uptackbelowcmb;031D +uptackmod;02D4 +uragurmukhi;0A73 +uring;016F +ushortcyrillic;045E +usmallhiragana;3045 +usmallkatakana;30A5 +usmallkatakanahalfwidth;FF69 +ustraightcyrillic;04AF +ustraightstrokecyrillic;04B1 +utilde;0169 +utildeacute;1E79 +utildebelow;1E75 +uubengali;098A +uudeva;090A +uugujarati;0A8A +uugurmukhi;0A0A +uumatragurmukhi;0A42 +uuvowelsignbengali;09C2 +uuvowelsigndeva;0942 +uuvowelsigngujarati;0AC2 +uvowelsignbengali;09C1 +uvowelsigndeva;0941 +uvowelsigngujarati;0AC1 +v;0076 +vadeva;0935 +vagujarati;0AB5 +vagurmukhi;0A35 +vakatakana;30F7 +vav;05D5 +vavdagesh;FB35 +vavdagesh65;FB35 +vavdageshhebrew;FB35 +vavhebrew;05D5 +vavholam;FB4B +vavholamhebrew;FB4B +vavvavhebrew;05F0 +vavyodhebrew;05F1 +vcircle;24E5 +vdotbelow;1E7F +vecyrillic;0432 +veharabic;06A4 +vehfinalarabic;FB6B +vehinitialarabic;FB6C +vehmedialarabic;FB6D +vekatakana;30F9 +venus;2640 +verticalbar;007C +verticallineabovecmb;030D +verticallinebelowcmb;0329 +verticallinelowmod;02CC +verticallinemod;02C8 +vewarmenian;057E +vhook;028B +vikatakana;30F8 +viramabengali;09CD +viramadeva;094D +viramagujarati;0ACD +visargabengali;0983 +visargadeva;0903 +visargagujarati;0A83 +vmonospace;FF56 +voarmenian;0578 +voicediterationhiragana;309E +voicediterationkatakana;30FE +voicedmarkkana;309B +voicedmarkkanahalfwidth;FF9E +vokatakana;30FA +vparen;24B1 +vtilde;1E7D +vturned;028C +vuhiragana;3094 +vukatakana;30F4 +w;0077 +wacute;1E83 +waekorean;3159 +wahiragana;308F +wakatakana;30EF +wakatakanahalfwidth;FF9C +wakorean;3158 +wasmallhiragana;308E +wasmallkatakana;30EE +wattosquare;3357 +wavedash;301C +wavyunderscorevertical;FE34 +wawarabic;0648 +wawfinalarabic;FEEE +wawhamzaabovearabic;0624 +wawhamzaabovefinalarabic;FE86 +wbsquare;33DD +wcircle;24E6 +wcircumflex;0175 +wdieresis;1E85 +wdotaccent;1E87 +wdotbelow;1E89 +wehiragana;3091 +weierstrass;2118 +wekatakana;30F1 +wekorean;315E +weokorean;315D +wgrave;1E81 +whitebullet;25E6 +whitecircle;25CB +whitecircleinverse;25D9 +whitecornerbracketleft;300E +whitecornerbracketleftvertical;FE43 +whitecornerbracketright;300F +whitecornerbracketrightvertical;FE44 +whitediamond;25C7 +whitediamondcontainingblacksmalldiamond;25C8 +whitedownpointingsmalltriangle;25BF +whitedownpointingtriangle;25BD +whiteleftpointingsmalltriangle;25C3 +whiteleftpointingtriangle;25C1 +whitelenticularbracketleft;3016 +whitelenticularbracketright;3017 +whiterightpointingsmalltriangle;25B9 +whiterightpointingtriangle;25B7 +whitesmallsquare;25AB +whitesmilingface;263A +whitesquare;25A1 +whitestar;2606 +whitetelephone;260F +whitetortoiseshellbracketleft;3018 +whitetortoiseshellbracketright;3019 +whiteuppointingsmalltriangle;25B5 +whiteuppointingtriangle;25B3 +wihiragana;3090 +wikatakana;30F0 +wikorean;315F +wmonospace;FF57 +wohiragana;3092 +wokatakana;30F2 +wokatakanahalfwidth;FF66 +won;20A9 +wonmonospace;FFE6 +wowaenthai;0E27 +wparen;24B2 +wring;1E98 +wsuperior;02B7 +wturned;028D +wynn;01BF +x;0078 +xabovecmb;033D +xbopomofo;3112 +xcircle;24E7 +xdieresis;1E8D +xdotaccent;1E8B +xeharmenian;056D +xi;03BE +xmonospace;FF58 +xparen;24B3 +xsuperior;02E3 +y;0079 +yaadosquare;334E +yabengali;09AF +yacute;00FD +yadeva;092F +yaekorean;3152 +yagujarati;0AAF +yagurmukhi;0A2F +yahiragana;3084 +yakatakana;30E4 +yakatakanahalfwidth;FF94 +yakorean;3151 +yamakkanthai;0E4E +yasmallhiragana;3083 +yasmallkatakana;30E3 +yasmallkatakanahalfwidth;FF6C +yatcyrillic;0463 +ycircle;24E8 +ycircumflex;0177 +ydieresis;00FF +ydotaccent;1E8F +ydotbelow;1EF5 +yeharabic;064A +yehbarreearabic;06D2 +yehbarreefinalarabic;FBAF +yehfinalarabic;FEF2 +yehhamzaabovearabic;0626 +yehhamzaabovefinalarabic;FE8A +yehhamzaaboveinitialarabic;FE8B +yehhamzaabovemedialarabic;FE8C +yehinitialarabic;FEF3 +yehmedialarabic;FEF4 +yehmeeminitialarabic;FCDD +yehmeemisolatedarabic;FC58 +yehnoonfinalarabic;FC94 +yehthreedotsbelowarabic;06D1 +yekorean;3156 +yen;00A5 +yenmonospace;FFE5 +yeokorean;3155 +yeorinhieuhkorean;3186 +yerahbenyomohebrew;05AA +yerahbenyomolefthebrew;05AA +yericyrillic;044B +yerudieresiscyrillic;04F9 +yesieungkorean;3181 +yesieungpansioskorean;3183 +yesieungsioskorean;3182 +yetivhebrew;059A +ygrave;1EF3 +yhook;01B4 +yhookabove;1EF7 +yiarmenian;0575 +yicyrillic;0457 +yikorean;3162 +yinyang;262F +yiwnarmenian;0582 +ymonospace;FF59 +yod;05D9 +yoddagesh;FB39 +yoddageshhebrew;FB39 +yodhebrew;05D9 +yodyodhebrew;05F2 +yodyodpatahhebrew;FB1F +yohiragana;3088 +yoikorean;3189 +yokatakana;30E8 +yokatakanahalfwidth;FF96 +yokorean;315B +yosmallhiragana;3087 +yosmallkatakana;30E7 +yosmallkatakanahalfwidth;FF6E +yotgreek;03F3 +yoyaekorean;3188 +yoyakorean;3187 +yoyakthai;0E22 +yoyingthai;0E0D +yparen;24B4 +ypogegrammeni;037A +ypogegrammenigreekcmb;0345 +yr;01A6 +yring;1E99 +ysuperior;02B8 +ytilde;1EF9 +yturned;028E +yuhiragana;3086 +yuikorean;318C +yukatakana;30E6 +yukatakanahalfwidth;FF95 +yukorean;3160 +yusbigcyrillic;046B +yusbigiotifiedcyrillic;046D +yuslittlecyrillic;0467 +yuslittleiotifiedcyrillic;0469 +yusmallhiragana;3085 +yusmallkatakana;30E5 +yusmallkatakanahalfwidth;FF6D +yuyekorean;318B +yuyeokorean;318A +yyabengali;09DF +yyadeva;095F +z;007A +zaarmenian;0566 +zacute;017A +zadeva;095B +zagurmukhi;0A5B +zaharabic;0638 +zahfinalarabic;FEC6 +zahinitialarabic;FEC7 +zahiragana;3056 +zahmedialarabic;FEC8 +zainarabic;0632 +zainfinalarabic;FEB0 +zakatakana;30B6 +zaqefgadolhebrew;0595 +zaqefqatanhebrew;0594 +zarqahebrew;0598 +zayin;05D6 +zayindagesh;FB36 +zayindageshhebrew;FB36 +zayinhebrew;05D6 +zbopomofo;3117 +zcaron;017E +zcircle;24E9 +zcircumflex;1E91 +zcurl;0291 +zdot;017C +zdotaccent;017C +zdotbelow;1E93 +zecyrillic;0437 +zedescendercyrillic;0499 +zedieresiscyrillic;04DF +zehiragana;305C +zekatakana;30BC +zero;0030 +zeroarabic;0660 +zerobengali;09E6 +zerodeva;0966 +zerogujarati;0AE6 +zerogurmukhi;0A66 +zerohackarabic;0660 +zeroinferior;2080 +zeromonospace;FF10 +zerooldstyle;F730 +zeropersian;06F0 +zerosuperior;2070 +zerothai;0E50 +zerowidthjoiner;FEFF +zerowidthnonjoiner;200C +zerowidthspace;200B +zeta;03B6 +zhbopomofo;3113 +zhearmenian;056A +zhebrevecyrillic;04C2 +zhecyrillic;0436 +zhedescendercyrillic;0497 +zhedieresiscyrillic;04DD +zihiragana;3058 +zikatakana;30B8 +zinorhebrew;05AE +zlinebelow;1E95 +zmonospace;FF5A +zohiragana;305E +zokatakana;30BE +zparen;24B5 +zretroflexhook;0290 +zstroke;01B6 +zuhiragana;305A +zukatakana;30BA +#--end +# +# Name: Adobe Glyph List +# Table version: 1.2 +# Date: 22 Oct 1998 +# +# Description: +# +# The Adobe Glyph List (AGL) list relates Unicode values (UVs) to glyph +# names, and should be used only as described in the document "Unicode and +# Glyph Names," at +# http://partners.adobe.com/asn/developer/typeforum/unicodegn.html . +# +# The glyph name to UV relation is one to many. 12 glyph names are mapped to +# two UVs each; each UV has a separate entry. All other glyph names are +# mapped to one UV each. +# +# The Unicode Standard version 2.1 is used for all UVs outside of the Private +# Use area, except for 4 entries (see Revision History for 1.2 below). +# +# There are 1051 entries in this list, 171 of which are in the Corporate Use +# subarea (CUS). Refer to the document "Unicode Corporate Use Subarea as used +# by Adobe Systems," at +# http://partners.adobe.com/asn/developer/typeforum/corporateuse.txt +# for compatibility decompositions for these characters, and to the document +# "Unicode and Glyph Names" for more information the CUS. +# +# Format: Semicolon-delimited fields: +# +# (1) Standard UV or CUS UV. (4 uppercase hexadecimal digits) +# +# (2) Glyph name. (upper- and lowercase letters, digits) +# +# (3) Character names: Unicode character names for standard UVs, and +# descriptive names for CUS UVs. (uppercase letters, hyphen, space) +# +# (4) [optional] Comment. A comment of "Duplicate" indicates one of two +# UVs of a double-mapping. It is the UV that may be given a uni +# override, or the UV that is in the CUS, as described in the document +# "Unicode and Glyph Names." +# +# The entries are sorted by glyph name in increasing ASCII order; entries +# with the same glyph name are sorted in decreasing priority order. +# +# Lines starting with "#" are comments; blank lines should be ignored. +# +# Revision History: +# +# 1.2 [22 Oct 1998] +# +# Some Central European glyph names were remapped and the glyph "dotlessj" +# was added. Some entries in the table below have not changed but are +# included to provide a complete context for other glyphs that have been +# remapped or double-mapped. "-" means that the entry for that UV does not +# exist in the AGL. +# +# -------- ---------------------- ---------------- -------------- +# UV Character name AGL 1.1 AGL 1.2 +# (shortened) glyph name glyph name +# -------- ---------------------- ---------------- -------------- +# 015E/F S/s with cedilla S/scommaaccent S/scedilla +# 0162/3 T/t with cedilla T/tcommaaccent T/tcommaaccent +# 0218/9 S/s with comma below - S/scommaaccent +# 021A/B T/t with comma below - T/tcommaaccent +# 1E9E/F S/s with comma below S/scedilla - +# F6C1/2 S/s with cedilla S/scedilla S/scedilla +# F6BE dotless j - dotlessj +# -------- ---------------------- ---------------- -------------- +# +# The characters at U+1E9E/F in AGL 1.1, LATIN CAPITAL/SMALL LETTER S WITH +# COMMA BELOW, which are proposed new characters (see (b) in the notes for +# AGL 1.1 below), have since been reassigned by the Unicode Standard to new +# proposed values of U+0218/9. These characters, as well as U+021A/B, LATIN +# CAPITAL/SMALL LETTER T WITH COMMA BELOW, are not in the Unicode Standard +# 2.1. +# +# Entries with the same glyph name are now sorted in decreasing priority +# order instead of in increasing UV order. +# +# 1.1 [24 Nov 1997] +# +# a. The "Euro" glyph's UV assignment is changed from U+20A0 (EURO-CURRENCY +# SIGN) to U+20AC (EURO SIGN). While U+20AC is not defined in the +# Unicode Standard 2.0, it has been accepted by the Unicode Technical +# Committee for the next version of the Standard; it has not yet passed +# the ISO approval process as of 7 November '97. +# +# b. Glyphs "Scedilla" and "scedilla", which were assigned in the Corporate +# Use Subarea in AGL 1.0, are now additionally mapped to U+1E9E and +# U+1E9F respectively. These two UVs share the same Unicode approval +# status as the Euro glyph (see a. above). +# +# c. The "fraction" glyph is now additionally mapped to U+2215, to match +# Windows Glyph List 4. +# +# d. The descriptive name for glyph "onefitted", in the Corporate Use +# subarea, is changed from "TABULAR DIGIT ONE" to "PROPORTIONAL DIGIT +# ONE". +# +# 1.0 [17 Jul 1997] Original version +# +A;0041 +AE;00C6 +AEacute;01FC +AEsmall;F7E6 +Aacute;00C1 +Aacutesmall;F7E1 +Abreve;0102 +Acircumflex;00C2 +Acircumflexsmall;F7E2 +Acute;F6C9 +Acutesmall;F7B4 +Adieresis;00C4 +Adieresissmall;F7E4 +Agrave;00C0 +Agravesmall;F7E0 +Alpha;0391 +Alphatonos;0386 +Amacron;0100 +Aogonek;0104 +Aring;00C5 +Aringacute;01FA +Aringsmall;F7E5 +Asmall;F761 +Atilde;00C3 +Atildesmall;F7E3 +B;0042 +Beta;0392 +Brevesmall;F6F4 +Bsmall;F762 +C;0043 +Cacute;0106 +Caron;F6CA +Caronsmall;F6F5 +Ccaron;010C +Ccedilla;00C7 +Ccedillasmall;F7E7 +Ccircumflex;0108 +Cdotaccent;010A +Cedillasmall;F7B8 +Chi;03A7 +Circumflexsmall;F6F6 +Csmall;F763 +D;0044 +Dcaron;010E +Dcroat;0110 +Delta;0394 +Dieresis;F6CB +DieresisAcute;F6CC +DieresisGrave;F6CD +Dieresissmall;F7A8 +Dotaccentsmall;F6F7 +Dsmall;F764 +E;0045 +Eacute;00C9 +Eacutesmall;F7E9 +Ebreve;0114 +Ecaron;011A +Ecircumflex;00CA +Ecircumflexsmall;F7EA +Edieresis;00CB +Edieresissmall;F7EB +Edotaccent;0116 +Egrave;00C8 +Egravesmall;F7E8 +Emacron;0112 +Eng;014A +Eogonek;0118 +Epsilon;0395 +Epsilontonos;0388 +Esmall;F765 +Eta;0397 +Etatonos;0389 +Eth;00D0 +Ethsmall;F7F0 +Euro;20AC +F;0046 +Fsmall;F766 +G;0047 +Gamma;0393 +Gbreve;011E +Gcaron;01E6 +Gcircumflex;011C +Gcommaaccent;0122 +Gdotaccent;0120 +Grave;F6CE +Gravesmall;F760 +Gsmall;F767 +H;0048 +H18533;25CF +H18543;25AA +H18551;25AB +H22073;25A1 +Hbar;0126 +Hcircumflex;0124 +Hsmall;F768 +Hungarumlaut;F6CF +Hungarumlautsmall;F6F8 +I;0049 +IJ;0132 +Iacute;00CD +Iacutesmall;F7ED +Ibreve;012C +Icircumflex;00CE +Icircumflexsmall;F7EE +Idieresis;00CF +Idieresissmall;F7EF +Idotaccent;0130 +Ifraktur;2111 +Igrave;00CC +Igravesmall;F7EC +Imacron;012A +Iogonek;012E +Iota;0399 +Iotadieresis;03AA +Iotatonos;038A +Ismall;F769 +Itilde;0128 +J;004A +Jcircumflex;0134 +Jsmall;F76A +K;004B +Kappa;039A +Kcommaaccent;0136 +Ksmall;F76B +L;004C +LL;F6BF +Lacute;0139 +Lambda;039B +Lcaron;013D +Lcommaaccent;013B +Ldot;013F +Lslash;0141 +Lslashsmall;F6F9 +Lsmall;F76C +M;004D +Macron;F6D0 +Macronsmall;F7AF +Msmall;F76D +Mu;039C +N;004E +Nacute;0143 +Ncaron;0147 +Ncommaaccent;0145 +Nsmall;F76E +Ntilde;00D1 +Ntildesmall;F7F1 +Nu;039D +O;004F +OE;0152 +OEsmall;F6FA +Oacute;00D3 +Oacutesmall;F7F3 +Obreve;014E +Ocircumflex;00D4 +Ocircumflexsmall;F7F4 +Odieresis;00D6 +Odieresissmall;F7F6 +Ogoneksmall;F6FB +Ograve;00D2 +Ogravesmall;F7F2 +Ohorn;01A0 +Ohungarumlaut;0150 +Omacron;014C +Omega;03A9 +Omegatonos;038F +Omicron;039F +Omicrontonos;038C +Oslash;00D8 +Oslashacute;01FE +Oslashsmall;F7F8 +Osmall;F76F +Otilde;00D5 +Otildesmall;F7F5 +P;0050 +Phi;03A6 +Pi;03A0 +Psi;03A8 +Psmall;F770 +Q;0051 +Qsmall;F771 +R;0052 +Racute;0154 +Rcaron;0158 +Rcommaaccent;0156 +Rfraktur;211C +Rho;03A1 +Ringsmall;F6FC +Rsmall;F772 +S;0053 +SF010000;250C +SF020000;2514 +SF030000;2510 +SF040000;2518 +SF050000;253C +SF060000;252C +SF070000;2534 +SF080000;251C +SF090000;2524 +SF100000;2500 +SF110000;2502 +SF190000;2561 +SF200000;2562 +SF210000;2556 +SF220000;2555 +SF230000;2563 +SF240000;2551 +SF250000;2557 +SF260000;255D +SF270000;255C +SF280000;255B +SF360000;255E +SF370000;255F +SF380000;255A +SF390000;2554 +SF400000;2569 +SF410000;2566 +SF420000;2560 +SF430000;2550 +SF440000;256C +SF450000;2567 +SF460000;2568 +SF470000;2564 +SF480000;2565 +SF490000;2559 +SF500000;2558 +SF510000;2552 +SF520000;2553 +SF530000;256B +SF540000;256A +Sacute;015A +Scaron;0160 +Scaronsmall;F6FD +Scedilla;015E +Scircumflex;015C +Scommaaccent;0218 +Sigma;03A3 +Ssmall;F773 +T;0054 +Tau;03A4 +Tbar;0166 +Tcaron;0164 +Tcommaaccent;0162 +Theta;0398 +Thorn;00DE +Thornsmall;F7FE +Tildesmall;F6FE +Tsmall;F774 +U;0055 +Uacute;00DA +Uacutesmall;F7FA +Ubreve;016C +Ucircumflex;00DB +Ucircumflexsmall;F7FB +Udieresis;00DC +Udieresissmall;F7FC +Ugrave;00D9 +Ugravesmall;F7F9 +Uhorn;01AF +Uhungarumlaut;0170 +Umacron;016A +Uogonek;0172 +Upsilon;03A5 +Upsilon1;03D2 +Upsilondieresis;03AB +Upsilontonos;038E +Uring;016E +Usmall;F775 +Utilde;0168 +V;0056 +Vsmall;F776 +W;0057 +Wacute;1E82 +Wcircumflex;0174 +Wdieresis;1E84 +Wgrave;1E80 +Wsmall;F777 +X;0058 +Xi;039E +Xsmall;F778 +Y;0059 +Yacute;00DD +Yacutesmall;F7FD +Ycircumflex;0176 +Ydieresis;0178 +Ydieresissmall;F7FF +Ygrave;1EF2 +Ysmall;F779 +Z;005A +Zacute;0179 +Zcaron;017D +Zcaronsmall;F6FF +Zdotaccent;017B +Zeta;0396 +Zsmall;F77A +a;0061 +aacute;00E1 +abreve;0103 +acircumflex;00E2 +acute;00B4 +acutecomb;0301 +adieresis;00E4 +ae;00E6 +aeacute;01FD +afii00208;2015 +afii10017;0410 +afii10018;0411 +afii10019;0412 +afii10020;0413 +afii10021;0414 +afii10022;0415 +afii10023;0401 +afii10024;0416 +afii10025;0417 +afii10026;0418 +afii10027;0419 +afii10028;041A +afii10029;041B +afii10030;041C +afii10031;041D +afii10032;041E +afii10033;041F +afii10034;0420 +afii10035;0421 +afii10036;0422 +afii10037;0423 +afii10038;0424 +afii10039;0425 +afii10040;0426 +afii10041;0427 +afii10042;0428 +afii10043;0429 +afii10044;042A +afii10045;042B +afii10046;042C +afii10047;042D +afii10048;042E +afii10049;042F +afii10050;0490 +afii10051;0402 +afii10052;0403 +afii10053;0404 +afii10054;0405 +afii10055;0406 +afii10056;0407 +afii10057;0408 +afii10058;0409 +afii10059;040A +afii10060;040B +afii10061;040C +afii10062;040E +afii10063;F6C4 +afii10064;F6C5 +afii10065;0430 +afii10066;0431 +afii10067;0432 +afii10068;0433 +afii10069;0434 +afii10070;0435 +afii10071;0451 +afii10072;0436 +afii10073;0437 +afii10074;0438 +afii10075;0439 +afii10076;043A +afii10077;043B +afii10078;043C +afii10079;043D +afii10080;043E +afii10081;043F +afii10082;0440 +afii10083;0441 +afii10084;0442 +afii10085;0443 +afii10086;0444 +afii10087;0445 +afii10088;0446 +afii10089;0447 +afii10090;0448 +afii10091;0449 +afii10092;044A +afii10093;044B +afii10094;044C +afii10095;044D +afii10096;044E +afii10097;044F +afii10098;0491 +afii10099;0452 +afii10100;0453 +afii10101;0454 +afii10102;0455 +afii10103;0456 +afii10104;0457 +afii10105;0458 +afii10106;0459 +afii10107;045A +afii10108;045B +afii10109;045C +afii10110;045E +afii10145;040F +afii10146;0462 +afii10147;0472 +afii10148;0474 +afii10192;F6C6 +afii10193;045F +afii10194;0463 +afii10195;0473 +afii10196;0475 +afii10831;F6C7 +afii10832;F6C8 +afii10846;04D9 +afii299;200E +afii300;200F +afii301;200D +afii57381;066A +afii57388;060C +afii57392;0660 +afii57393;0661 +afii57394;0662 +afii57395;0663 +afii57396;0664 +afii57397;0665 +afii57398;0666 +afii57399;0667 +afii57400;0668 +afii57401;0669 +afii57403;061B +afii57407;061F +afii57409;0621 +afii57410;0622 +afii57411;0623 +afii57412;0624 +afii57413;0625 +afii57414;0626 +afii57415;0627 +afii57416;0628 +afii57417;0629 +afii57418;062A +afii57419;062B +afii57420;062C +afii57421;062D +afii57422;062E +afii57423;062F +afii57424;0630 +afii57425;0631 +afii57426;0632 +afii57427;0633 +afii57428;0634 +afii57429;0635 +afii57430;0636 +afii57431;0637 +afii57432;0638 +afii57433;0639 +afii57434;063A +afii57440;0640 +afii57441;0641 +afii57442;0642 +afii57443;0643 +afii57444;0644 +afii57445;0645 +afii57446;0646 +afii57448;0648 +afii57449;0649 +afii57450;064A +afii57451;064B +afii57452;064C +afii57453;064D +afii57454;064E +afii57455;064F +afii57456;0650 +afii57457;0651 +afii57458;0652 +afii57470;0647 +afii57505;06A4 +afii57506;067E +afii57507;0686 +afii57508;0698 +afii57509;06AF +afii57511;0679 +afii57512;0688 +afii57513;0691 +afii57514;06BA +afii57519;06D2 +afii57534;06D5 +afii57636;20AA +afii57645;05BE +afii57658;05C3 +afii57664;05D0 +afii57665;05D1 +afii57666;05D2 +afii57667;05D3 +afii57668;05D4 +afii57669;05D5 +afii57670;05D6 +afii57671;05D7 +afii57672;05D8 +afii57673;05D9 +afii57674;05DA +afii57675;05DB +afii57676;05DC +afii57677;05DD +afii57678;05DE +afii57679;05DF +afii57680;05E0 +afii57681;05E1 +afii57682;05E2 +afii57683;05E3 +afii57684;05E4 +afii57685;05E5 +afii57686;05E6 +afii57687;05E7 +afii57688;05E8 +afii57689;05E9 +afii57690;05EA +afii57694;FB2A +afii57695;FB2B +afii57700;FB4B +afii57705;FB1F +afii57716;05F0 +afii57717;05F1 +afii57718;05F2 +afii57723;FB35 +afii57793;05B4 +afii57794;05B5 +afii57795;05B6 +afii57796;05BB +afii57797;05B8 +afii57798;05B7 +afii57799;05B0 +afii57800;05B2 +afii57801;05B1 +afii57802;05B3 +afii57803;05C2 +afii57804;05C1 +afii57806;05B9 +afii57807;05BC +afii57839;05BD +afii57841;05BF +afii57842;05C0 +afii57929;02BC +afii61248;2105 +afii61289;2113 +afii61352;2116 +afii61573;202C +afii61574;202D +afii61575;202E +afii61664;200C +afii63167;066D +afii64937;02BD +agrave;00E0 +aleph;2135 +alpha;03B1 +alphatonos;03AC +amacron;0101 +ampersand;0026 +ampersandsmall;F726 +angle;2220 +angleleft;2329 +angleright;232A +anoteleia;0387 +aogonek;0105 +approxequal;2248 +aring;00E5 +aringacute;01FB +arrowboth;2194 +arrowdblboth;21D4 +arrowdbldown;21D3 +arrowdblleft;21D0 +arrowdblright;21D2 +arrowdblup;21D1 +arrowdown;2193 +arrowhorizex;F8E7 +arrowleft;2190 +arrowright;2192 +arrowup;2191 +arrowupdn;2195 +arrowupdnbse;21A8 +arrowvertex;F8E6 +asciicircum;005E +asciitilde;007E +asterisk;002A +asteriskmath;2217 +asuperior;F6E9 +at;0040 +atilde;00E3 +b;0062 +backslash;005C +bar;007C +beta;03B2 +block;2588 +braceex;F8F4 +braceleft;007B +braceleftbt;F8F3 +braceleftmid;F8F2 +bracelefttp;F8F1 +braceright;007D +bracerightbt;F8FE +bracerightmid;F8FD +bracerighttp;F8FC +bracketleft;005B +bracketleftbt;F8F0 +bracketleftex;F8EF +bracketlefttp;F8EE +bracketright;005D +bracketrightbt;F8FB +bracketrightex;F8FA +bracketrighttp;F8F9 +breve;02D8 +brokenbar;00A6 +bsuperior;F6EA +bullet;2022 +c;0063 +cacute;0107 +caron;02C7 +carriagereturn;21B5 +ccaron;010D +ccedilla;00E7 +ccircumflex;0109 +cdotaccent;010B +cedilla;00B8 +cent;00A2 +centinferior;F6DF +centoldstyle;F7A2 +centsuperior;F6E0 +chi;03C7 +circle;25CB +circlemultiply;2297 +circleplus;2295 +circumflex;02C6 +club;2663 +colon;003A +colonmonetary;20A1 +comma;002C +commaaccent;F6C3 +commainferior;F6E1 +commasuperior;F6E2 +congruent;2245 +copyright;00A9 +copyrightsans;F8E9 +copyrightserif;F6D9 +currency;00A4 +cyrBreve;F6D1 +cyrFlex;F6D2 +cyrbreve;F6D4 +cyrflex;F6D5 +d;0064 +dagger;2020 +daggerdbl;2021 +dblGrave;F6D3 +dblgrave;F6D6 +dcaron;010F +dcroat;0111 +degree;00B0 +delta;03B4 +diamond;2666 +dieresis;00A8 +dieresisacute;F6D7 +dieresisgrave;F6D8 +dieresistonos;0385 +divide;00F7 +dkshade;2593 +dnblock;2584 +dollar;0024 +dollarinferior;F6E3 +dollaroldstyle;F724 +dollarsuperior;F6E4 +dong;20AB +dotaccent;02D9 +dotbelowcomb;0323 +dotlessi;0131 +dotlessj;F6BE +dotmath;22C5 +dsuperior;F6EB +e;0065 +eacute;00E9 +ebreve;0115 +ecaron;011B +ecircumflex;00EA +edieresis;00EB +edotaccent;0117 +egrave;00E8 +eight;0038 +eightinferior;2088 +eightoldstyle;F738 +eightsuperior;2078 +element;2208 +ellipsis;2026 +emacron;0113 +emdash;2014 +emptyset;2205 +endash;2013 +eng;014B +eogonek;0119 +epsilon;03B5 +epsilontonos;03AD +equal;003D +equivalence;2261 +estimated;212E +esuperior;F6EC +eta;03B7 +etatonos;03AE +eth;00F0 +exclam;0021 +exclamdbl;203C +exclamdown;00A1 +exclamdownsmall;F7A1 +exclamsmall;F721 +existential;2203 +f;0066 +female;2640 +ff;FB00 +ffi;FB03 +ffl;FB04 +fi;FB01 +figuredash;2012 +filledbox;25A0 +filledrect;25AC +five;0035 +fiveeighths;215D +fiveinferior;2085 +fiveoldstyle;F735 +fivesuperior;2075 +fl;FB02 +florin;0192 +four;0034 +fourinferior;2084 +fouroldstyle;F734 +foursuperior;2074 +fraction;2044 +franc;20A3 +g;0067 +gamma;03B3 +gbreve;011F +gcaron;01E7 +gcircumflex;011D +gcommaaccent;0123 +gdotaccent;0121 +germandbls;00DF +gradient;2207 +grave;0060 +gravecomb;0300 +greater;003E +greaterequal;2265 +guillemotleft;00AB +guillemotright;00BB +guilsinglleft;2039 +guilsinglright;203A +h;0068 +hbar;0127 +hcircumflex;0125 +heart;2665 +hookabovecomb;0309 +house;2302 +hungarumlaut;02DD +hyphen;002D +hypheninferior;F6E5 +hyphensuperior;F6E6 +i;0069 +iacute;00ED +ibreve;012D +icircumflex;00EE +idieresis;00EF +igrave;00EC +ij;0133 +imacron;012B +infinity;221E +integral;222B +integralbt;2321 +integralex;F8F5 +integraltp;2320 +intersection;2229 +invbullet;25D8 +invcircle;25D9 +invsmileface;263B +iogonek;012F +iota;03B9 +iotadieresis;03CA +iotadieresistonos;0390 +iotatonos;03AF +isuperior;F6ED +itilde;0129 +j;006A +jcircumflex;0135 +k;006B +kappa;03BA +kcommaaccent;0137 +kgreenlandic;0138 +l;006C +lacute;013A +lambda;03BB +lcaron;013E +lcommaaccent;013C +ldot;0140 +less;003C +lessequal;2264 +lfblock;258C +lira;20A4 +ll;F6C0 +logicaland;2227 +logicalnot;00AC +logicalor;2228 +longs;017F +lozenge;25CA +lslash;0142 +lsuperior;F6EE +ltshade;2591 +m;006D +macron;00AF +male;2642 +minus;2212 +minute;2032 +msuperior;F6EF +mu;03BC +multiply;00D7 +musicalnote;266A +musicalnotedbl;266B +n;006E +nacute;0144 +napostrophe;0149 +ncaron;0148 +ncommaaccent;0146 +nine;0039 +nineinferior;2089 +nineoldstyle;F739 +ninesuperior;2079 +notelement;2209 +notequal;2260 +notsubset;2284 +nsuperior;207F +ntilde;00F1 +nu;03BD +numbersign;0023 +o;006F +oacute;00F3 +obreve;014F +ocircumflex;00F4 +odieresis;00F6 +oe;0153 +ogonek;02DB +ograve;00F2 +ohorn;01A1 +ohungarumlaut;0151 +omacron;014D +omega;03C9 +omega1;03D6 +omegatonos;03CE +omicron;03BF +omicrontonos;03CC +one;0031 +onedotenleader;2024 +oneeighth;215B +onefitted;F6DC +onehalf;00BD +oneinferior;2081 +oneoldstyle;F731 +onequarter;00BC +onesuperior;00B9 +onethird;2153 +openbullet;25E6 +ordfeminine;00AA +ordmasculine;00BA +orthogonal;221F +oslash;00F8 +oslashacute;01FF +osuperior;F6F0 +otilde;00F5 +p;0070 +paragraph;00B6 +parenleft;0028 +parenleftbt;F8ED +parenleftex;F8EC +parenleftinferior;208D +parenleftsuperior;207D +parenlefttp;F8EB +parenright;0029 +parenrightbt;F8F8 +parenrightex;F8F7 +parenrightinferior;208E +parenrightsuperior;207E +parenrighttp;F8F6 +partialdiff;2202 +percent;0025 +period;002E +periodcentered;00B7 +periodinferior;F6E7 +periodsuperior;F6E8 +perpendicular;22A5 +perthousand;2030 +peseta;20A7 +phi;03C6 +phi1;03D5 +pi;03C0 +plus;002B +plusminus;00B1 +prescription;211E +product;220F +propersubset;2282 +propersuperset;2283 +proportional;221D +psi;03C8 +q;0071 +question;003F +questiondown;00BF +questiondownsmall;F7BF +questionsmall;F73F +quotedbl;0022 +quotedblbase;201E +quotedblleft;201C +quotedblright;201D +quoteleft;2018 +quotereversed;201B +quoteright;2019 +quotesinglbase;201A +quotesingle;0027 +r;0072 +racute;0155 +radical;221A +radicalex;F8E5 +rcaron;0159 +rcommaaccent;0157 +reflexsubset;2286 +reflexsuperset;2287 +registered;00AE +registersans;F8E8 +registerserif;F6DA +revlogicalnot;2310 +rho;03C1 +ring;02DA +rsuperior;F6F1 +rtblock;2590 +rupiah;F6DD +s;0073 +sacute;015B +scaron;0161 +scedilla;015F +scircumflex;015D +scommaaccent;0219 +second;2033 +section;00A7 +semicolon;003B +seven;0037 +seveneighths;215E +seveninferior;2087 +sevenoldstyle;F737 +sevensuperior;2077 +shade;2592 +sigma;03C3 +sigma1;03C2 +similar;223C +six;0036 +sixinferior;2086 +sixoldstyle;F736 +sixsuperior;2076 +slash;002F +smileface;263A +space;0020 +spade;2660 +ssuperior;F6F2 +sterling;00A3 +suchthat;220B +summation;2211 +sun;263C +t;0074 +tau;03C4 +tbar;0167 +tcaron;0165 +tcommaaccent;0163 +therefore;2234 +theta;03B8 +theta1;03D1 +thorn;00FE +three;0033 +threeeighths;215C +threeinferior;2083 +threeoldstyle;F733 +threequarters;00BE +threequartersemdash;F6DE +threesuperior;00B3 +tilde;02DC +tildecomb;0303 +tonos;0384 +trademark;2122 +trademarksans;F8EA +trademarkserif;F6DB +triagdn;25BC +triaglf;25C4 +triagrt;25BA +triagup;25B2 +tsuperior;F6F3 +two;0032 +twodotenleader;2025 +twoinferior;2082 +twooldstyle;F732 +twosuperior;00B2 +twothirds;2154 +u;0075 +uacute;00FA +ubreve;016D +ucircumflex;00FB +udieresis;00FC +ugrave;00F9 +uhorn;01B0 +uhungarumlaut;0171 +umacron;016B +underscore;005F +underscoredbl;2017 +union;222A +universal;2200 +uogonek;0173 +upblock;2580 +upsilon;03C5 +upsilondieresis;03CB +upsilondieresistonos;03B0 +upsilontonos;03CD +uring;016F +utilde;0169 +v;0076 +w;0077 +wacute;1E83 +wcircumflex;0175 +wdieresis;1E85 +weierstrass;2118 +wgrave;1E81 +x;0078 +xi;03BE +y;0079 +yacute;00FD +ycircumflex;0177 +ydieresis;00FF +yen;00A5 +ygrave;1EF3 +z;007A +zacute;017A +zcaron;017E +zdotaccent;017C +zero;0030 +zeroinferior;2080 +zerooldstyle;F730 +zerosuperior;2070 +zeta;03B6 diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/ByteVector.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/ByteVector.cs new file mode 100644 index 0000000..05687f2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/ByteVector.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections; + +/* + * $Id: ByteVector.cs,v 1.2 2005/06/18 08:17:05 psoares33 Exp $ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This class implements a simple byte vector with access to the + * underlying array. + * + * @author Carlos Villegas + */ + public class ByteVector { + + /** + * Capacity increment size + */ + private static int DEFAULT_BLOCK_SIZE = 2048; + private int BLOCK_SIZE; + + /** + * The encapsulated array + */ + private byte[] arr; + + /** + * Points to next free item + */ + private int n; + + public ByteVector() : this(DEFAULT_BLOCK_SIZE) {} + + public ByteVector(int capacity) { + if (capacity > 0) + BLOCK_SIZE = capacity; + else + BLOCK_SIZE = DEFAULT_BLOCK_SIZE; + arr = new byte[BLOCK_SIZE]; + n = 0; + } + + public ByteVector(byte[] a) { + BLOCK_SIZE = DEFAULT_BLOCK_SIZE; + arr = a; + n = 0; + } + + public ByteVector(byte[] a, int capacity) { + if (capacity > 0) + BLOCK_SIZE = capacity; + else + BLOCK_SIZE = DEFAULT_BLOCK_SIZE; + arr = a; + n = 0; + } + + public byte[] Arr { + get { + return arr; + } + } + + /** + * return number of items in array + */ + public int Length { + get { + return n; + } + } + + /** + * returns current capacity of array + */ + public int Capacity { + get { + return arr.Length; + } + } + + public byte this[int index] { + get { + return arr[index]; + } + + set { + arr[index] = value; + } + } + + /** + * This is to implement memory allocation in the array. Like Malloc(). + */ + public int Alloc(int size) { + int index = n; + int len = arr.Length; + if (n + size >= len) { + byte[] aux = new byte[len + BLOCK_SIZE]; + Array.Copy(arr, 0, aux, 0, len); + arr = aux; + } + n += size; + return index; + } + + public void TrimToSize() { + if (n < arr.Length) { + byte[] aux = new byte[n]; + Array.Copy(arr, 0, aux, 0, n); + arr = aux; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/CharVector.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/CharVector.cs new file mode 100644 index 0000000..fde362b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/CharVector.cs @@ -0,0 +1,128 @@ +using System; + +/* + * $Id: CharVector.cs,v 1.2 2005/06/18 08:17:05 psoares33 Exp $ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This class implements a simple char vector with access to the + * underlying array. + * + * @author Carlos Villegas + */ + public class CharVector : ICloneable { + + /** + * Capacity increment size + */ + private static int DEFAULT_BLOCK_SIZE = 2048; + private int BLOCK_SIZE; + + /** + * The encapsulated array + */ + private char[] array; + + /** + * Points to next free item + */ + private int n; + + public CharVector() : this(DEFAULT_BLOCK_SIZE) {} + + public CharVector(int capacity) { + if (capacity > 0) + BLOCK_SIZE = capacity; + else + BLOCK_SIZE = DEFAULT_BLOCK_SIZE; + array = new char[BLOCK_SIZE]; + n = 0; + } + + public CharVector(char[] a) { + BLOCK_SIZE = DEFAULT_BLOCK_SIZE; + array = a; + n = a.Length; + } + + public CharVector(char[] a, int capacity) { + if (capacity > 0) + BLOCK_SIZE = capacity; + else + BLOCK_SIZE = DEFAULT_BLOCK_SIZE; + array = a; + n = a.Length; + } + + /** + * Reset Vector but don't resize or clear elements + */ + public void Clear() { + n = 0; + } + + public Object Clone() { + CharVector cv = new CharVector((char[])array.Clone(), BLOCK_SIZE); + cv.n = this.n; + return cv; + } + + public char[] Arr { + get { + return array; + } + } + + /** + * return number of items in array + */ + public int Length { + get { + return n; + } + } + + /** + * returns current capacity of array + */ + public int Capacity { + get { + return array.Length; + } + } + + public char this[int index] { + get { + return array[index]; + } + + set { + array[index] = value; + } + } + + public int Alloc(int size) { + int index = n; + int len = array.Length; + if (n + size >= len) { + char[] aux = new char[len + BLOCK_SIZE]; + Array.Copy(array, 0, aux, 0, len); + array = aux; + } + n += size; + return index; + } + + public void TrimToSize() { + if (n < array.Length) { + char[] aux = new char[n]; + Array.Copy(array, 0, aux, 0, n); + array = aux; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphen.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphen.cs new file mode 100644 index 0000000..8f846e8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphen.cs @@ -0,0 +1,67 @@ +using System; +using System.Text; +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This class represents a hyphen. A 'full' hyphen is made of 3 parts: + * the pre-break text, post-break text and no-break. If no line-break + * is generated at this position, the no-break text is used, otherwise, + * pre-break and post-break are used. Typically, pre-break is equal to + * the hyphen character and the others are empty. However, this general + * scheme allows support for cases in some languages where words change + * spelling if they're split across lines, like german's 'backen' which + * hyphenates 'bak-ken'. BTW, this comes from TeX. + * + * @author Carlos Villegas + */ + + public class Hyphen { + public String preBreak; + public String noBreak; + public String postBreak; + + internal Hyphen(String pre, String no, String post) { + preBreak = pre; + noBreak = no; + postBreak = post; + } + + internal Hyphen(String pre) { + preBreak = pre; + noBreak = null; + postBreak = null; + } + + public override String ToString() { + if (noBreak == null + && postBreak == null + && preBreak != null + && preBreak.Equals("-")) { + return "-"; + } + StringBuilder res = new StringBuilder("{"); + res.Append(preBreak); + res.Append("}{"); + res.Append(postBreak); + res.Append("}{"); + res.Append(noBreak); + res.Append('}'); + return res.ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenation.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenation.cs new file mode 100644 index 0000000..c7cb35f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenation.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; + +/* + * $Id: Hyphenation.cs,v 1.2 2005/06/18 08:17:05 psoares33 Exp $ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This class represents a hyphenated word. + * + * @author Carlos Villegas + */ + public class Hyphenation { + int[] hyphenPoints; + string word; + + /** + * number of hyphenation points in word + */ + int len; + + /** + * rawWord as made of alternating strings and {@link Hyphen Hyphen} + * instances + */ + internal Hyphenation(string word, int[] points) { + this.word = word; + hyphenPoints = points; + len = points.Length; + } + + /** + * @return the number of hyphenation points in the word + */ + public int Length { + get { + return len; + } + } + + /** + * @return the pre-break text, not including the hyphen character + */ + public string GetPreHyphenText(int index) { + return word.Substring(0, hyphenPoints[index]); + } + + /** + * @return the post-break text + */ + public string GetPostHyphenText(int index) { + return word.Substring(hyphenPoints[index]); + } + + /** + * @return the hyphenation points + */ + public int[] HyphenationPoints { + get { + return hyphenPoints; + } + } + + public override string ToString() { + StringBuilder str = new StringBuilder(); + int start = 0; + for (int i = 0; i < len; i++) { + str.Append(word.Substring(start, hyphenPoints[i]) + "-"); + start = hyphenPoints[i]; + } + str.Append(word.Substring(start)); + return str.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationException.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationException.cs new file mode 100644 index 0000000..d7e1f90 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationException.cs @@ -0,0 +1,27 @@ +using System; +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * @author Carlos Villegas + */ + public class HyphenationException : Exception { + + public HyphenationException(String msg) : base(msg) { + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationTree.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationTree.cs new file mode 100644 index 0000000..9b3a889 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationTree.cs @@ -0,0 +1,451 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: HyphenationTree.cs,v 1.2 2005/06/18 08:05:23 psoares33 Exp $ */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This tree structure stores the hyphenation patterns in an efficient + * way for fast lookup. It provides the provides the method to + * hyphenate a word. + * + * @author Carlos Villegas + */ + public class HyphenationTree : TernaryTree, IPatternConsumer { + + /** + * value space: stores the inteletter values + */ + protected ByteVector vspace; + + /** + * This map stores hyphenation exceptions + */ + protected Hashtable stoplist; + + /** + * This map stores the character classes + */ + protected TernaryTree classmap; + + /** + * Temporary map to store interletter values on pattern loading. + */ + private TernaryTree ivalues; + + public HyphenationTree() { + stoplist = new Hashtable(23); // usually a small table + classmap = new TernaryTree(); + vspace = new ByteVector(); + vspace.Alloc(1); // this reserves index 0, which we don't use + } + + /** + * Packs the values by storing them in 4 bits, two values into a byte + * Values range is from 0 to 9. We use zero as terminator, + * so we'll add 1 to the value. + * @param values a string of digits from '0' to '9' representing the + * interletter values. + * @return the index into the vspace array where the packed values + * are stored. + */ + protected int PackValues(String values) { + int i, n = values.Length; + int m = (n & 1) == 1 ? (n >> 1) + 2 : (n >> 1) + 1; + int offset = vspace.Alloc(m); + byte[] va = vspace.Arr; + for (i = 0; i < n; i++) { + int j = i >> 1; + byte v = (byte)((values[i] - '0' + 1) & 0x0f); + if ((i & 1) == 1) { + va[j + offset] = (byte)(va[j + offset] | v); + } else { + va[j + offset] = (byte)(v << 4); // big endian + } + } + va[m - 1 + offset] = 0; // terminator + return offset; + } + + protected String UnpackValues(int k) { + StringBuilder buf = new StringBuilder(); + byte v = vspace[k++]; + while (v != 0) { + char c = (char)((v >> 4) - 1 + '0'); + buf.Append(c); + c = (char)(v & 0x0f); + if (c == 0) { + break; + } + c = (char)(c - 1 + '0'); + buf.Append(c); + v = vspace[k++]; + } + return buf.ToString(); + } + + public void LoadSimplePatterns(Stream stream) { + SimplePatternParser pp = new SimplePatternParser(); + ivalues = new TernaryTree(); + + pp.Parse(stream, this); + + // patterns/values should be now in the tree + // let's optimize a bit + TrimToSize(); + vspace.TrimToSize(); + classmap.TrimToSize(); + + // get rid of the auxiliary map + ivalues = null; + } + + + public String FindPattern(String pat) { + int k = base.Find(pat); + if (k >= 0) { + return UnpackValues(k); + } + return ""; + } + + /** + * String compare, returns 0 if equal or + * t is a substring of s + */ + protected int Hstrcmp(char[] s, int si, char[] t, int ti) { + for (; s[si] == t[ti]; si++, ti++) { + if (s[si] == 0) { + return 0; + } + } + if (t[ti] == 0) { + return 0; + } + return s[si] - t[ti]; + } + + protected byte[] GetValues(int k) { + StringBuilder buf = new StringBuilder(); + byte v = vspace[k++]; + while (v != 0) { + char c = (char)((v >> 4) - 1); + buf.Append(c); + c = (char)(v & 0x0f); + if (c == 0) { + break; + } + c = (char)(c - 1); + buf.Append(c); + v = vspace[k++]; + } + byte[] res = new byte[buf.Length]; + for (int i = 0; i < res.Length; i++) { + res[i] = (byte)buf[i]; + } + return res; + } + + /** + *

    Search for all possible partial matches of word starting + * at index an update interletter values. In other words, it + * does something like:

    + * + * for (i=0; i + *

    But it is done in an efficient way since the patterns are + * stored in a ternary tree. In fact, this is the whole purpose + * of having the tree: doing this search without having to test + * every single pattern. The number of patterns for languages + * such as English range from 4000 to 10000. Thus, doing thousands + * of string comparisons for each word to hyphenate would be + * really slow without the tree. The tradeoff is memory, but + * using a ternary tree instead of a trie, almost halves the + * the memory used by Lout or TeX. It's also faster than using + * a hash table

    + * @param word null terminated word to match + * @param index start index from word + * @param il interletter values array to update + */ + protected void SearchPatterns(char[] word, int index, byte[] il) { + byte[] values; + int i = index; + char p, q; + char sp = word[i]; + p = root; + + while (p > 0 && p < sc.Length) { + if (sc[p] == 0xFFFF) { + if (Hstrcmp(word, i, kv.Arr, lo[p]) == 0) { + values = GetValues(eq[p]); // data pointer is in eq[] + int j = index; + for (int k = 0; k < values.Length; k++) { + if (j < il.Length && values[k] > il[j]) { + il[j] = values[k]; + } + j++; + } + } + return; + } + int d = sp - sc[p]; + if (d == 0) { + if (sp == 0) { + break; + } + sp = word[++i]; + p = eq[p]; + q = p; + + // look for a pattern ending at this position by searching for + // the null char ( splitchar == 0 ) + while (q > 0 && q < sc.Length) { + if (sc[q] == 0xFFFF) { // stop at compressed branch + break; + } + if (sc[q] == 0) { + values = GetValues(eq[q]); + int j = index; + for (int k = 0; k < values.Length; k++) { + if (j < il.Length && values[k] > il[j]) { + il[j] = values[k]; + } + j++; + } + break; + } else { + q = lo[q]; + + /** + * actually the code should be: + * q = sc[q] < 0 ? hi[q] : lo[q]; + * but java chars are unsigned + */ + } + } + } else { + p = d < 0 ? lo[p] : hi[p]; + } + } + } + + /** + * Hyphenate word and return a Hyphenation object. + * @param word the word to be hyphenated + * @param remainCharCount Minimum number of characters allowed + * before the hyphenation point. + * @param pushCharCount Minimum number of characters allowed after + * the hyphenation point. + * @return a {@link Hyphenation Hyphenation} object representing + * the hyphenated word or null if word is not hyphenated. + */ + public Hyphenation Hyphenate(String word, int remainCharCount, + int pushCharCount) { + char[] w = word.ToCharArray(); + return Hyphenate(w, 0, w.Length, remainCharCount, pushCharCount); + } + + /** + * w = "****nnllllllnnn*****", + * where n is a non-letter, l is a letter, + * all n may be absent, the first n is at offset, + * the first l is at offset + iIgnoreAtBeginning; + * word = ".llllll.'\0'***", + * where all l in w are copied into word. + * In the first part of the routine len = w.length, + * in the second part of the routine len = word.length. + * Three indices are used: + * Index(w), the index in w, + * Index(word), the index in word, + * Letterindex(word), the index in the letter part of word. + * The following relations exist: + * Index(w) = offset + i - 1 + * Index(word) = i - iIgnoreAtBeginning + * Letterindex(word) = Index(word) - 1 + * (see first loop). + * It follows that: + * Index(w) - Index(word) = offset - 1 + iIgnoreAtBeginning + * Index(w) = Letterindex(word) + offset + iIgnoreAtBeginning + */ + + /** + * Hyphenate word and return an array of hyphenation points. + * @param w char array that contains the word + * @param offset Offset to first character in word + * @param len Length of word + * @param remainCharCount Minimum number of characters allowed + * before the hyphenation point. + * @param pushCharCount Minimum number of characters allowed after + * the hyphenation point. + * @return a {@link Hyphenation Hyphenation} object representing + * the hyphenated word or null if word is not hyphenated. + */ + public Hyphenation Hyphenate(char[] w, int offset, int len, + int remainCharCount, int pushCharCount) { + int i; + char[] word = new char[len + 3]; + + // normalize word + char[] c = new char[2]; + int iIgnoreAtBeginning = 0; + int iLength = len; + bool bEndOfLetters = false; + for (i = 1; i <= len; i++) { + c[0] = w[offset + i - 1]; + int nc = classmap.Find(c, 0); + if (nc < 0) { // found a non-letter character ... + if (i == (1 + iIgnoreAtBeginning)) { + // ... before any letter character + iIgnoreAtBeginning ++; + } else { + // ... after a letter character + bEndOfLetters = true; + } + iLength --; + } else { + if (!bEndOfLetters) { + word[i - iIgnoreAtBeginning] = (char)nc; + } else { + return null; + } + } + } + len = iLength; + if (len < (remainCharCount + pushCharCount)) { + // word is too short to be hyphenated + return null; + } + int[] result = new int[len + 1]; + int k = 0; + + // check exception list first + String sw = new String(word, 1, len); + if (stoplist.ContainsKey(sw)) { + // assume only simple hyphens (Hyphen.pre="-", Hyphen.post = Hyphen.no = null) + ArrayList hw = (ArrayList)stoplist[sw]; + int j = 0; + for (i = 0; i < hw.Count; i++) { + Object o = hw[i]; + // j = Index(sw) = Letterindex(word)? + // result[k] = corresponding Index(w) + if (o is String) { + j += ((String)o).Length; + if (j >= remainCharCount && j < (len - pushCharCount)) { + result[k++] = j + iIgnoreAtBeginning; + } + } + } + } else { + // use algorithm to get hyphenation points + word[0] = '.'; // word start marker + word[len + 1] = '.'; // word end marker + word[len + 2] = (char)0; // null terminated + byte[] il = new byte[len + 3]; // initialized to zero + for (i = 0; i < len + 1; i++) { + SearchPatterns(word, i, il); + } + + // hyphenation points are located where interletter value is odd + // i is Letterindex(word), + // i + 1 is Index(word), + // result[k] = corresponding Index(w) + for (i = 0; i < len; i++) { + if (((il[i + 1] & 1) == 1) && i >= remainCharCount + && i <= (len - pushCharCount)) { + result[k++] = i + iIgnoreAtBeginning; + } + } + } + + + if (k > 0) { + // trim result array + int[] res = new int[k]; + Array.Copy(result, 0, res, 0, k); + return new Hyphenation(new String(w, offset, len), res); + } else { + return null; + } + } + + /** + * Add a character class to the tree. It is used by + * {@link SimplePatternParser SimplePatternParser} as callback to + * add character classes. Character classes define the + * valid word characters for hyphenation. If a word contains + * a character not defined in any of the classes, it is not hyphenated. + * It also defines a way to normalize the characters in order + * to compare them with the stored patterns. Usually pattern + * files use only lower case characters, in this case a class + * for letter 'a', for example, should be defined as "aA", the first + * character being the normalization char. + */ + public void AddClass(String chargroup) { + if (chargroup.Length > 0) { + char equivChar = chargroup[0]; + char[] key = new char[2]; + key[1] = (char)0; + for (int i = 0; i < chargroup.Length; i++) { + key[0] = chargroup[i]; + classmap.Insert(key, 0, equivChar); + } + } + } + + /** + * Add an exception to the tree. It is used by + * {@link SimplePatternParser SimplePatternParser} class as callback to + * store the hyphenation exceptions. + * @param word normalized word + * @param hyphenatedword a vector of alternating strings and + * {@link Hyphen hyphen} objects. + */ + public void AddException(String word, ArrayList hyphenatedword) { + stoplist[word] = hyphenatedword; + } + + /** + * Add a pattern to the tree. Mainly, to be used by + * {@link SimplePatternParser SimplePatternParser} class as callback to + * add a pattern to the tree. + * @param pattern the hyphenation pattern + * @param ivalue interletter weight values indicating the + * desirability and priority of hyphenating at a given point + * within the pattern. It should contain only digit characters. + * (i.e. '0' to '9'). + */ + public void AddPattern(String pattern, String ivalue) { + int k = ivalues.Find(ivalue); + if (k <= 0) { + k = PackValues(ivalue); + ivalues.Insert(ivalue, (char)k); + } + Insert(pattern, (char)k); + } + + public override void PrintStats() { + Console.WriteLine("Value space size = " + vspace.Length); + base.PrintStats(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenator.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenator.cs new file mode 100644 index 0000000..6bea2a1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenator.cs @@ -0,0 +1,220 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.pdf; +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This class is the main entry point to the hyphenation package. + * You can use only the static methods or create an instance. + * + * @author Carlos Villegas + */ + public class Hyphenator { + + /** TODO: Don't use statics */ + private static Hashtable hyphenTrees = Hashtable.Synchronized(new Hashtable()); + + private HyphenationTree hyphenTree = null; + private int remainCharCount = 2; + private int pushCharCount = 2; + private const String defaultHyphLocation = "iTextSharp.text.pdf.hyphenation.hyph."; + + /** + * @param lang + * @param country + * @param leftMin + * @param rightMin + */ + public Hyphenator(String lang, String country, int leftMin, + int rightMin) { + hyphenTree = GetHyphenationTree(lang, country); + remainCharCount = leftMin; + pushCharCount = rightMin; + } + + /** + * @param lang + * @param country + * @return the hyphenation tree + */ + public static HyphenationTree GetHyphenationTree(String lang, + String country) { + String key = lang; + // check whether the country code has been used + if (country != null && !country.Equals("none")) { + key += "_" + country; + } + // first try to find it in the cache + if (hyphenTrees.ContainsKey(key)) { + return (HyphenationTree)hyphenTrees[key]; + } + if (hyphenTrees.ContainsKey(lang)) { + return (HyphenationTree)hyphenTrees[lang]; + } + + HyphenationTree hTree = GetResourceHyphenationTree(key); + //if (hTree == null) + // hTree = GetFileHyphenationTree(key); + // put it into the pattern cache + if (hTree != null) { + hyphenTrees[key] = hTree; + } + return hTree; + } + + /** + * @param key + * @return a hyphenation tree + */ + public static HyphenationTree GetResourceHyphenationTree(String key) { + try { + Stream stream = BaseFont.GetResourceStream(defaultHyphLocation + key + ".xml"); + if (stream == null && key.Length > 2) + stream = BaseFont.GetResourceStream(defaultHyphLocation + key.Substring(0, 2) + ".xml"); + if (stream == null) + return null; + HyphenationTree hTree = new HyphenationTree(); + hTree.LoadSimplePatterns(stream); + return hTree; + } + catch { + return null; + } + } + + /** + * @param key + * @return a hyphenation tree + */ +/* public static HyphenationTree GetFileHyphenationTree(String key) { + try { + if (hyphenDir == null) + return null; + Stream stream = null; + string hyphenFile = Path.Combine(hyphenDir, key + ".xml"); + if (File.Exists(hyphenFile)) + stream = new FileStream(hyphenFile, FileMode.Open, FileAccess.Read, FileShare.Read); + if (stream == null && key.Length > 2) { + hyphenFile = Path.Combine(hyphenDir, key.Substring(0, 2) + ".xml"); + if (File.Exists(hyphenFile)) + stream = new FileStream(hyphenFile, FileMode.Open, FileAccess.Read, FileShare.Read); + } + if (stream == null) + return null; + HyphenationTree hTree = new HyphenationTree(); + hTree.LoadSimplePatterns(stream); + return hTree; + } + catch (Exception e) { + return null; + } + }*/ + + /** + * @param lang + * @param country + * @param word + * @param leftMin + * @param rightMin + * @return a hyphenation object + */ + public static Hyphenation Hyphenate(String lang, String country, + String word, int leftMin, + int rightMin) { + HyphenationTree hTree = GetHyphenationTree(lang, country); + if (hTree == null) { + //log.Error("Error building hyphenation tree for language " + // + lang); + return null; + } + return hTree.Hyphenate(word, leftMin, rightMin); + } + + /** + * @param lang + * @param country + * @param word + * @param offset + * @param len + * @param leftMin + * @param rightMin + * @return a hyphenation object + */ + public static Hyphenation Hyphenate(String lang, String country, + char[] word, int offset, int len, + int leftMin, int rightMin) { + HyphenationTree hTree = GetHyphenationTree(lang, country); + if (hTree == null) { + //log.Error("Error building hyphenation tree for language " + // + lang); + return null; + } + return hTree.Hyphenate(word, offset, len, leftMin, rightMin); + } + + /** + * @param min + */ + public void SetMinRemainCharCount(int min) { + remainCharCount = min; + } + + /** + * @param min + */ + public void SetMinPushCharCount(int min) { + pushCharCount = min; + } + + /** + * @param lang + * @param country + */ + public void SetLanguage(String lang, String country) { + hyphenTree = GetHyphenationTree(lang, country); + } + + /** + * @param word + * @param offset + * @param len + * @return a hyphenation object + */ + public Hyphenation Hyphenate(char[] word, int offset, int len) { + if (hyphenTree == null) { + return null; + } + return hyphenTree.Hyphenate(word, offset, len, remainCharCount, + pushCharCount); + } + + /** + * @param word + * @return a hyphenation object + */ + public Hyphenation Hyphenate(String word) { + if (hyphenTree == null) { + return null; + } + return hyphenTree.Hyphenate(word, remainCharCount, pushCharCount); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/IPatternConsumer.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/IPatternConsumer.cs new file mode 100644 index 0000000..2431cfe --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/IPatternConsumer.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + * This interface is used to connect the XML pattern file parser to + * the hyphenation tree. + * + * @author Carlos Villegas + */ + public interface IPatternConsumer { + + /** + * Add a character class. + * A character class defines characters that are considered + * equivalent for the purpose of hyphenation (e.g. "aA"). It + * usually means to ignore case. + * @param chargroup character group + */ + void AddClass(String chargroup); + + /** + * Add a hyphenation exception. An exception replaces the + * result obtained by the algorithm for cases for which this + * fails or the user wants to provide his own hyphenation. + * A hyphenatedword is a vector of alternating String's and + * {@link Hyphen Hyphen} instances + */ + void AddException(String word, ArrayList hyphenatedword); + + /** + * Add hyphenation patterns. + * @param pattern the pattern + * @param values interletter values expressed as a string of + * digit characters. + */ + void AddPattern(String pattern, String values); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/SimplePatternParser.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/SimplePatternParser.cs new file mode 100644 index 0000000..980e415 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/SimplePatternParser.cs @@ -0,0 +1,247 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.xml.simpleparser; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** Parses the xml hyphenation pattern. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class SimplePatternParser : ISimpleXMLDocHandler { + internal int currElement; + internal IPatternConsumer consumer; + internal StringBuilder token; + internal ArrayList exception; + internal char hyphenChar; + + internal const int ELEM_CLASSES = 1; + internal const int ELEM_EXCEPTIONS = 2; + internal const int ELEM_PATTERNS = 3; + internal const int ELEM_HYPHEN = 4; + + /** Creates a new instance of PatternParser2 */ + public SimplePatternParser() { + token = new StringBuilder(); + hyphenChar = '-'; // default + } + + public void Parse(Stream stream, IPatternConsumer consumer) { + this.consumer = consumer; + try { + SimpleXMLParser.Parse(this, stream); + } + finally { + try{stream.Close();}catch{} + } + } + + protected static String GetPattern(String word) { + StringBuilder pat = new StringBuilder(); + int len = word.Length; + for (int i = 0; i < len; i++) { + if (!char.IsDigit(word[i])) { + pat.Append(word[i]); + } + } + return pat.ToString(); + } + + protected ArrayList NormalizeException(ArrayList ex) { + ArrayList res = new ArrayList(); + for (int i = 0; i < ex.Count; i++) { + Object item = ex[i]; + if (item is String) { + String str = (String)item; + StringBuilder buf = new StringBuilder(); + for (int j = 0; j < str.Length; j++) { + char c = str[j]; + if (c != hyphenChar) { + buf.Append(c); + } else { + res.Add(buf.ToString()); + buf.Length = 0; + char[] h = new char[1]; + h[0] = hyphenChar; + // we use here hyphenChar which is not necessarily + // the one to be printed + res.Add(new Hyphen(new String(h), null, null)); + } + } + if (buf.Length > 0) { + res.Add(buf.ToString()); + } + } else { + res.Add(item); + } + } + return res; + } + + protected String GetExceptionWord(ArrayList ex) { + StringBuilder res = new StringBuilder(); + for (int i = 0; i < ex.Count; i++) { + Object item = ex[i]; + if (item is String) { + res.Append((String)item); + } else { + if (((Hyphen)item).noBreak != null) { + res.Append(((Hyphen)item).noBreak); + } + } + } + return res.ToString(); + } + + protected static String GetInterletterValues(String pat) { + StringBuilder il = new StringBuilder(); + String word = pat + "a"; // add dummy letter to serve as sentinel + int len = word.Length; + for (int i = 0; i < len; i++) { + char c = word[i]; + if (char.IsDigit(c)) { + il.Append(c); + i++; + } else { + il.Append('0'); + } + } + return il.ToString(); + } + + public void EndDocument() { + } + + public void EndElement(String tag) { + if (token.Length > 0) { + String word = token.ToString(); + switch (currElement) { + case ELEM_CLASSES: + consumer.AddClass(word); + break; + case ELEM_EXCEPTIONS: + exception.Add(word); + exception = NormalizeException(exception); + consumer.AddException(GetExceptionWord(exception), + (ArrayList)exception.Clone()); + break; + case ELEM_PATTERNS: + consumer.AddPattern(GetPattern(word), + GetInterletterValues(word)); + break; + case ELEM_HYPHEN: + // nothing to do + break; + } + if (currElement != ELEM_HYPHEN) { + token.Length = 0; + } + } + if (currElement == ELEM_HYPHEN) { + currElement = ELEM_EXCEPTIONS; + } else { + currElement = 0; + } + } + + public void StartDocument() { + } + + public void StartElement(String tag, Hashtable h) { + if (tag.Equals("hyphen-char")) { + String hh = (String)h["value"]; + if (hh != null && hh.Length == 1) { + hyphenChar = hh[0]; + } + } else if (tag.Equals("classes")) { + currElement = ELEM_CLASSES; + } else if (tag.Equals("patterns")) { + currElement = ELEM_PATTERNS; + } else if (tag.Equals("exceptions")) { + currElement = ELEM_EXCEPTIONS; + exception = new ArrayList(); + } else if (tag.Equals("hyphen")) { + if (token.Length > 0) { + exception.Add(token.ToString()); + } + exception.Add(new Hyphen((String)h["pre"], + (String)h["no"], + (String)h["post"])); + currElement = ELEM_HYPHEN; + } + token.Length = 0; + } + + public void Text(String str) { + StringTokenizer tk = new StringTokenizer(str); + while (tk.HasMoreTokens()) { + String word = tk.NextToken(); + // System.out.Println("\"" + word + "\""); + switch (currElement) { + case ELEM_CLASSES: + consumer.AddClass(word); + break; + case ELEM_EXCEPTIONS: + exception.Add(word); + exception = NormalizeException(exception); + consumer.AddException(GetExceptionWord(exception), + (ArrayList)exception.Clone()); + exception.Clear(); + break; + case ELEM_PATTERNS: + consumer.AddPattern(GetPattern(word), + GetInterletterValues(word)); + break; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/hyphenation/TernaryTree.cs b/iTechSharp/iTextSharp/text/pdf/hyphenation/TernaryTree.cs new file mode 100644 index 0000000..4297e8e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/hyphenation/TernaryTree.cs @@ -0,0 +1,631 @@ +using System; +using System.Collections; +using System.Text; + +/* + * $Id: TernaryTree.cs,v 1.2 2005/06/18 08:17:05 psoares33 Exp $ + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +namespace iTextSharp.text.pdf.hyphenation { + /** + *

    Ternary Search Tree

    + * + *

    A ternary search tree is a hibrid between a binary tree and + * a digital search tree (trie). Keys are limited to strings. + * A data value of type char is stored in each leaf node. + * It can be used as an index (or pointer) to the data. + * Branches that only contain one key are compressed to one node + * by storing a pointer to the trailer substring of the key. + * This class is intended to serve as base class or helper class + * to implement Dictionary collections or the like. Ternary trees + * have some nice properties as the following: the tree can be + * traversed in sorted order, partial matches (wildcard) can be + * implemented, retrieval of all keys within a given distance + * from the target, etc. The storage requirements are higher than + * a binary tree but a lot less than a trie. Performance is + * comparable with a hash table, sometimes it outperforms a hash + * function (most of the time can determine a miss faster than a hash).

    + * + *

    The main purpose of this java port is to serve as a base for + * implementing TeX's hyphenation algorithm (see The TeXBook, + * appendix H). Each language requires from 5000 to 15000 hyphenation + * patterns which will be keys in this tree. The strings patterns + * are usually small (from 2 to 5 characters), but each char in the + * tree is stored in a node. Thus memory usage is the main concern. + * We will sacrify 'elegance' to keep memory requirenments to the + * minimum. Using java's char type as pointer (yes, I know pointer + * it is a forbidden word in java) we can keep the size of the node + * to be just 8 bytes (3 pointers and the data char). This gives + * room for about 65000 nodes. In my tests the english patterns + * took 7694 nodes and the german patterns 10055 nodes, + * so I think we are safe.

    + * + *

    All said, this is a map with strings as keys and char as value. + * Pretty limited!. It can be extended to a general map by + * using the string representation of an object and using the + * char value as an index to an array that contains the object + * values.

    + * + * @author cav@uniscope.co.jp + */ + + public class TernaryTree : ICloneable { + + /** + * We use 4 arrays to represent a node. I guess I should have created + * a proper node class, but somehow Knuth's pascal code made me forget + * we now have a portable language with memory management and + * automatic garbage collection! And now is kind of late, furthermore, + * if it ain't broken, don't fix it. + */ + + /** + * Pointer to low branch and to rest of the key when it is + * stored directly in this node, we don't have unions in java! + */ + protected char[] lo; + + /** + * Pointer to high branch. + */ + protected char[] hi; + + /** + * Pointer to equal branch and to data when this node is a string terminator. + */ + protected char[] eq; + + /** + *

    The character stored in this node: splitchar + * Two special values are reserved:

    + *
    • 0x0000 as string terminator
    • + *
    • 0xFFFF to indicate that the branch starting at + * this node is compressed
    + *

    This shouldn't be a problem if we give the usual semantics to + * strings since 0xFFFF is garanteed not to be an Unicode character.

    + */ + protected char[] sc; + + /** + * This vector holds the trailing of the keys when the branch is compressed. + */ + protected CharVector kv; + + protected char root; + protected char freenode; + protected int length; // number of items in tree + + protected static int BLOCK_SIZE = 2048; // allocation size for arrays + + internal TernaryTree() { + Init(); + } + + protected void Init() { + root = (char)0; + freenode = (char)1; + length = 0; + lo = new char[BLOCK_SIZE]; + hi = new char[BLOCK_SIZE]; + eq = new char[BLOCK_SIZE]; + sc = new char[BLOCK_SIZE]; + kv = new CharVector(); + } + + /** + * Branches are initially compressed, needing + * one node per key plus the size of the string + * key. They are decompressed as needed when + * another key with same prefix + * is inserted. This saves a lot of space, + * specially for long keys. + */ + public void Insert(string key, char val) { + // make sure we have enough room in the arrays + int len = key.Length + + 1; // maximum number of nodes that may be generated + if (freenode + len > eq.Length) + RedimNodeArrays(eq.Length + BLOCK_SIZE); + char[] strkey = new char[len--]; + key.CopyTo(0, strkey, 0, len); + strkey[len] = (char)0; + root = Insert(root, strkey, 0, val); + } + + public void Insert(char[] key, int start, char val) { + int len = Strlen(key) + 1; + if (freenode + len > eq.Length) + RedimNodeArrays(eq.Length + BLOCK_SIZE); + root = Insert(root, key, start, val); + } + + /** + * The actual insertion function, recursive version. + */ + private char Insert(char p, char[] key, int start, char val) { + int len = Strlen(key, start); + if (p == 0) { + // this means there is no branch, this node will start a new branch. + // Instead of doing that, we store the key somewhere else and create + // only one node with a pointer to the key + p = freenode++; + eq[p] = val; // holds data + length++; + hi[p] = (char)0; + if (len > 0) { + sc[p] = (char)0xFFFF; // indicates branch is compressed + lo[p] = (char)kv.Alloc(len + + 1); // use 'lo' to hold pointer to key + Strcpy(kv.Arr, lo[p], key, start); + } else { + sc[p] = (char)0; + lo[p] = (char)0; + } + return p; + } + + if (sc[p] == 0xFFFF) { + // branch is compressed: need to decompress + // this will generate garbage in the external key array + // but we can do some garbage collection later + char pp = freenode++; + lo[pp] = lo[p]; // previous pointer to key + eq[pp] = eq[p]; // previous pointer to data + lo[p] = (char)0; + if (len > 0) { + sc[p] = kv[lo[pp]]; + eq[p] = pp; + lo[pp]++; + if (kv[lo[pp]] == 0) { + // key completly decompressed leaving garbage in key array + lo[pp] = (char)0; + sc[pp] = (char)0; + hi[pp] = (char)0; + } else + sc[pp] = + (char)0xFFFF; // we only got first char of key, rest is still there + } else { + // In this case we can save a node by swapping the new node + // with the compressed node + sc[pp] = (char)0xFFFF; + hi[p] = pp; + sc[p] = (char)0; + eq[p] = val; + length++; + return p; + } + } + char s = key[start]; + if (s < sc[p]) + lo[p] = Insert(lo[p], key, start, val); + else if (s == sc[p]) { + if (s != 0) + eq[p] = Insert(eq[p], key, start + 1, val); + else { + // key already in tree, overwrite data + eq[p] = val; + } + + } else + hi[p] = Insert(hi[p], key, start, val); + return p; + } + + /** + * Compares 2 null terminated char arrays + */ + public static int Strcmp(char[] a, int startA, char[] b, int startB) { + for (; a[startA] == b[startB]; startA++, startB++) + if (a[startA] == 0) + return 0; + return a[startA] - b[startB]; + } + + /** + * Compares a string with null terminated char array + */ + public static int Strcmp(string str, char[] a, int start) { + int i, d, len = str.Length; + for (i = 0; i < len; i++) { + d = (int)str[i] - a[start + i]; + if (d != 0) + return d; + if (a[start + i] == 0) + return d; + } + if (a[start + i] != 0) + return (int)-a[start + i]; + return 0; + + } + + public static void Strcpy(char[] dst, int di, char[] src, int si) { + while (src[si] != 0) + dst[di++] = src[si++]; + dst[di] = (char)0; + } + + public static int Strlen(char[] a, int start) { + int len = 0; + for (int i = start; i < a.Length && a[i] != 0; i++) + len++; + return len; + } + + public static int Strlen(char[] a) { + return Strlen(a, 0); + } + + public int Find(string key) { + int len = key.Length; + char[] strkey = new char[len + 1]; + key.CopyTo(0, strkey, 0, len); + strkey[len] = (char)0; + + return Find(strkey, 0); + } + + public int Find(char[] key, int start) { + int d; + char p = root; + int i = start; + char c; + + while (p != 0) { + if (sc[p] == 0xFFFF) { + if (Strcmp(key, i, kv.Arr, lo[p]) == 0) + return eq[p]; + else + return -1; + } + c = key[i]; + d = c - sc[p]; + if (d == 0) { + if (c == 0) + return eq[p]; + i++; + p = eq[p]; + } else if (d < 0) + p = lo[p]; + else + p = hi[p]; + } + return -1; + } + + public bool Knows(string key) { + return (Find(key) >= 0); + } + + // redimension the arrays + private void RedimNodeArrays(int newsize) { + int len = newsize < lo.Length ? newsize : lo.Length; + char[] na = new char[newsize]; + Array.Copy(lo, 0, na, 0, len); + lo = na; + na = new char[newsize]; + Array.Copy(hi, 0, na, 0, len); + hi = na; + na = new char[newsize]; + Array.Copy(eq, 0, na, 0, len); + eq = na; + na = new char[newsize]; + Array.Copy(sc, 0, na, 0, len); + sc = na; + } + + public int Size { + get { + return length; + } + } + + public Object Clone() { + TernaryTree t = new TernaryTree(); + t.lo = (char[])this.lo.Clone(); + t.hi = (char[])this.hi.Clone(); + t.eq = (char[])this.eq.Clone(); + t.sc = (char[])this.sc.Clone(); + t.kv = (CharVector)this.kv.Clone(); + t.root = this.root; + t.freenode = this.freenode; + t.length = this.length; + + return t; + } + + /** + * Recursively insert the median first and then the median of the + * lower and upper halves, and so on in order to get a balanced + * tree. The array of keys is assumed to be sorted in ascending + * order. + */ + protected void InsertBalanced(string[] k, char[] v, int offset, int n) { + int m; + if (n < 1) + return; + m = n >> 1; + + Insert(k[m + offset], v[m + offset]); + InsertBalanced(k, v, offset, m); + + InsertBalanced(k, v, offset + m + 1, n - m - 1); + } + + + /** + * Balance the tree for best search performance + */ + public void Balance() { + // System.out.Print("Before root splitchar = "); System.out.Println(sc[root]); + + int i = 0, n = length; + string[] k = new string[n]; + char[] v = new char[n]; + Iterator iter = new Iterator(this); + while (iter.HasMoreElements()) { + v[i] = iter.Value; + k[i++] = (string)iter.NextElement(); + } + Init(); + InsertBalanced(k, v, 0, n); + + // With uniform letter distribution sc[root] should be around 'm' + // System.out.Print("After root splitchar = "); System.out.Println(sc[root]); + } + + /** + * Each node stores a character (splitchar) which is part of + * some Key(s). In a compressed branch (one that only contain + * a single string key) the trailer of the key which is not + * already in nodes is stored externally in the kv array. + * As items are inserted, key substrings decrease. + * Some substrings may completely disappear when the whole + * branch is totally decompressed. + * The tree is traversed to find the key substrings actually + * used. In addition, duplicate substrings are removed using + * a map (implemented with a TernaryTree!). + * + */ + public void TrimToSize() { + // first balance the tree for best performance + Balance(); + + // redimension the node arrays + RedimNodeArrays(freenode); + + // ok, compact kv array + CharVector kx = new CharVector(); + kx.Alloc(1); + TernaryTree map = new TernaryTree(); + Compact(kx, map, root); + kv = kx; + kv.TrimToSize(); + } + + private void Compact(CharVector kx, TernaryTree map, char p) { + int k; + if (p == 0) + return; + if (sc[p] == 0xFFFF) { + k = map.Find(kv.Arr, lo[p]); + if (k < 0) { + k = kx.Alloc(Strlen(kv.Arr, lo[p]) + 1); + Strcpy(kx.Arr, k, kv.Arr, lo[p]); + map.Insert(kx.Arr, k, (char)k); + } + lo[p] = (char)k; + } else { + Compact(kx, map, lo[p]); + if (sc[p] != 0) + Compact(kx, map, eq[p]); + Compact(kx, map, hi[p]); + } + } + + + public Iterator Keys { + get { + return new Iterator(this); + } + } + + public class Iterator { + + /** + * current node index + */ + int cur; + + /** + * current key + */ + string curkey; + + /** + * TernaryTree parent + */ + TernaryTree parent; + + private class Item : ICloneable { + internal char parent; + internal char child; + + public Item() { + parent = (char)0; + child = (char)0; + } + + public Item(char p, char c) { + parent = p; + child = c; + } + + public Object Clone() { + return new Item(parent, child); + } + + } + + /** + * Node stack + */ + Stack ns; + + /** + * key stack implemented with a StringBuilder + */ + StringBuilder ks; + + public Iterator(TernaryTree parent) { + this.parent = parent; + cur = -1; + ns = new Stack(); + ks = new StringBuilder(); + Rewind(); + } + + public void Rewind() { + ns.Clear(); + ks.Length = 0; + cur = parent.root; + Run(); + } + + public Object NextElement() { + string res = curkey; + cur = Up(); + Run(); + return res; + } + + public char Value { + get { + if (cur >= 0) + return this.parent.eq[cur]; + return (char)0; + } + } + + public bool HasMoreElements() { + return (cur != -1); + } + + /** + * traverse upwards + */ + private int Up() { + Item i = new Item(); + int res = 0; + + if (ns.Count == 0) + return -1; + + if (cur != 0 && parent.sc[cur] == 0) + return parent.lo[cur]; + + bool climb = true; + + while (climb) { + i = (Item)ns.Pop(); + i.child++; + switch (i.child) { + case (char)1: + if (parent.sc[i.parent] != 0) { + res = parent.eq[i.parent]; + ns.Push(i.Clone()); + ks.Append(parent.sc[i.parent]); + } else { + i.child++; + ns.Push(i.Clone()); + res = parent.hi[i.parent]; + } + climb = false; + break; + + case (char)2: + res = parent.hi[i.parent]; + ns.Push(i.Clone()); + if (ks.Length > 0) + ks.Length = ks.Length - 1; // pop + climb = false; + break; + + default: + if (ns.Count == 0) + return -1; + climb = true; + break; + } + } + return res; + } + + /** + * traverse the tree to find next key + */ + private int Run() { + if (cur == -1) + return -1; + + bool leaf = false; + for (; ; ) { + // first go down on low branch until leaf or compressed branch + while (cur != 0) { + if (parent.sc[cur] == 0xFFFF) { + leaf = true; + break; + } + ns.Push(new Item((char)cur, '\u0000')); + if (parent.sc[cur] == 0) { + leaf = true; + break; + } + cur = parent.lo[cur]; + } + if (leaf) + break; + // nothing found, go up one node and try again + cur = Up(); + if (cur == -1) { + return -1; + } + } + // The current node should be a data node and + // the key should be in the key stack (at least partially) + StringBuilder buf = new StringBuilder(ks.ToString()); + if (parent.sc[cur] == 0xFFFF) { + int p = parent.lo[cur]; + while (parent.kv[p] != 0) + buf.Append(parent.kv[p++]); + } + curkey = buf.ToString(); + return 0; + } + + } + + public virtual void PrintStats() { + Console.Error.WriteLine("Number of keys = " + length.ToString()); + Console.Error.WriteLine("Node count = " + freenode.ToString()); + // Console.Error.WriteLine("Array length = " + int.ToString(eq.Length)); + Console.Error.WriteLine("Key Array length = " + + kv.Length.ToString()); + + /* + * for (int i=0; iPdfAnnotation
    or a PdfFormField + * to the document. Only the top parent of a PdfFormField + * needs to be added. + * @param annot the PdfAnnotation or the PdfFormField to add + */ + void AddAnnotation(PdfAnnotation annot); + + /** + * Use this method to adds the PdfAnnotation + * to the calculation order array. + * @param annot the PdfAnnotation to be added + */ + void AddCalculationOrder(PdfFormField annot); + + /** + * Use this method to set the signature flags. + * @param f the flags. This flags are ORed with current ones + */ + int SigFlags { + set; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfDocumentActions.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfDocumentActions.cs new file mode 100644 index 0000000..f13f947 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfDocumentActions.cs @@ -0,0 +1,87 @@ +using System; +using iTextSharp.text.pdf; +/* + * $Id: IPdfDocumentActions.cs,v 1.1 2007/02/09 15:34:40 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + /** + * A PDF document can have an open action and other additional actions. + */ + + public interface IPdfDocumentActions { + /** + * When the document opens it will jump to the destination with + * this name. + * @param name the name of the destination to jump to + */ + void SetOpenAction(String name); + + /** + * When the document opens this action will be + * invoked. + * @param action the action to be invoked + */ + void SetOpenAction(PdfAction action); + + /** + * Additional-actions defining the actions to be taken in + * response to various trigger events affecting the document + * as a whole. The actions types allowed are: DOCUMENT_CLOSE, + * WILL_SAVE, DID_SAVE, WILL_PRINT + * and DID_PRINT. + * + * @param actionType the action type + * @param action the action to execute in response to the trigger + * @throws DocumentException on invalid action type + */ + void SetAdditionalAction(PdfName actionType, PdfAction action); + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfEncryptionSettings.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfEncryptionSettings.cs new file mode 100644 index 0000000..8250d59 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfEncryptionSettings.cs @@ -0,0 +1,96 @@ +using System; +using Org.BouncyCastle.X509; +/* + * $Id: IPdfEncryptionSettings.cs,v 1.2 2007/04/29 13:57:00 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + /** + * Encryption settings are described in section 3.5 (more specifically + * section 3.5.2) of the PDF Reference 1.7. + * They are explained in section 3.3.3 of the book 'iText in Action'. + * The values of the different preferences were originally stored + * in class PdfWriter, but they have been moved to this separate interface + * for reasons of convenience. + */ + + public interface IPdfEncryptionSettings { + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @throws DocumentException if the document is already open + */ + void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType); + + /** + * Sets the certificate encryption options for this document. An array of one or more public certificates + * must be provided together with an array of the same size for the permissions for each certificate. + * The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param certs the public certificates to be used for the encryption + * @param permissions the user permissions for each of the certicates + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * @throws DocumentException if the document is already open + */ + void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfPageActions.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfPageActions.cs new file mode 100644 index 0000000..a1fd316 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfPageActions.cs @@ -0,0 +1,85 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * $Id: IPdfPageActions.cs,v 1.1 2007/02/09 15:34:40 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + /** + * A PDF page can have an open and/or close action. + */ + + public interface IPdfPageActions { + /** + * Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @throws DocumentException if the action type is invalid + */ + void SetPageAction(PdfName actionType, PdfAction action); + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page + */ + int Duration { + set; + } + + /** + * Sets the transition for the page + * @param transition the Transition object + */ + PdfTransition Transition { + set; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfRunDirection.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfRunDirection.cs new file mode 100644 index 0000000..b3c563c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfRunDirection.cs @@ -0,0 +1,63 @@ +using System; +/* + * $Id: IPdfRunDirection.cs,v 1.1 2007/02/09 15:34:40 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + public interface IPdfRunDirection { + /** Sets the run direction. This is only used as a placeholder + * as it does not affect anything. + * @param runDirection the run direction + */ + int RunDirection { + set; + get; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfVersion.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfVersion.cs new file mode 100644 index 0000000..6a55b14 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfVersion.cs @@ -0,0 +1,94 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * $Id: IPdfVersion.cs,v 1.1 2007/02/09 15:34:40 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + /** + * The PDF version is described in the PDF Reference 1.7 p92 + * (about the PDF Header) and page 139 (the version entry in + * the Catalog). You'll also find info about setting the version + * in the book 'iText in Action' sections 2.1.3 (PDF Header) + * and 3.3 (Version history). + */ + + public interface IPdfVersion { + + /** + * If the PDF Header hasn't been written yet, + * this changes the version as it will appear in the PDF Header. + * If the PDF header was already written to the Stream, + * this changes the version as it will appear in the Catalog. + * @param version a character representing the PDF version + */ + char PdfVersion { + set; + } + + /** + * If the PDF Header hasn't been written yet, + * this changes the version as it will appear in the PDF Header, + * but only if param refers to a higher version. + * If the PDF header was already written to the Stream, + * this changes the version as it will appear in the Catalog. + * @param version a character representing the PDF version + */ + void SetAtLeastPdfVersion(char version); + /** + * Sets the PDF version as it will appear in the Catalog. + * Note that this only has effect if you use a later version + * than the one that appears in the header; this method + * ignores the parameter if you try to set a lower version. + * @param version the PDF name that will be used for the Version key in the catalog + */ + void SetPdfVersion(PdfName version); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfViewerPreferences.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfViewerPreferences.cs new file mode 100644 index 0000000..e5eb88f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfViewerPreferences.cs @@ -0,0 +1,202 @@ +using System; +using iTextSharp.text.pdf; +/* + * $Id: IPdfViewerPreferences.cs,v 1.3 2008/05/02 15:58:08 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + /** + * Viewer preferences are described in section 3.6.1 and 8.1 of the + * PDF Reference 1.7 (Table 3.25 on p139-142 and Table 8.1 on p579-581). + * They are explained in section 13.1 of the book 'iText in Action'. + * The values of the different preferences were originally stored + * in class PdfWriter, but they have been moved to this separate interface + * for reasons of convenience. + */ + + public interface IPdfViewerPreferences { + + /** + * Sets the page layout and page mode preferences by ORing one or two of these constants. + *

    + *

      + *
    • The page layout to be used when the document is opened (choose one). + *
        + *
      • PAGE_LAYOUT_SINGLE_PAGE - Display one page at a time. (default) + *
      • PAGE_LAYOUT_ONE_COLUMN - Display the pages in one column. + *
      • PAGE_LAYOUT_TWO_COLUMN_LEFT - Display the pages in two columns, with + * oddnumbered pages on the left. + *
      • PAGE_LAYOUT_TWO_COLUMN_RIGHT - Display the pages in two columns, with + * oddnumbered pages on the right. + *
      • PAGE_LAYOUT_TWO_PAGE_LEFT - Display the pages two at a time, with + * oddnumbered pages on the left. + *
      • PAGE_LAYOUT_TWO_PAGE_RIGHT - Display the pages two at a time, with + * oddnumbered pages on the right. + *
      + *
    • The page mode how the document should be displayed + * when opened (choose one). + *
        + *
      • PAGE_MODE_USE_NONE - Neither document outline nor thumbnail images visible. (default) + *
      • PAGE_MODE_USE_OUTLINES - Document outline visible. + *
      • PAGE_MODE_USE_THUMBS - Thumbnail images visible. + *
      • PAGE_MODE_FULL_SCREEN - Full-screen mode, with no menu bar, window + * controls, or any other window visible. + *
      • PAGE_MODE_USE_OC - Optional content group panel visible + *
      • PAGE_MODE_USE_ATTACHMENTS - Attachments panel visible + *
      + *
    + * For backward compatibility these values are also supported, + * but it's better to use method addViewerPreference(key, value) + * if you want to change the following preferences: + *
      + *
    • HIDE_TOOLBAR - A flag specifying whether to hide the viewer application's tool + * bars when the document is active. + *
    • HIDE_MENUBAR - A flag specifying whether to hide the viewer application's + * menu bar when the document is active. + *
    • HIDE_WINDOW_UI - A flag specifying whether to hide user interface elements in + * the document's window (such as scroll bars and navigation controls), + * leaving only the document's contents displayed. + *
    • FIT_WINDOW - A flag specifying whether to resize the document's window to + * fit the size of the first displayed page. + *
    • CENTER_WINDOW - A flag specifying whether to position the document's window + * in the center of the screen. + *
    • DISPLAY_DOC_TITLE - A flag specifying whether to display the document's title + * in the top bar. + *
    • The predominant reading order for text. This entry has no direct effect on the + * document's contents or page numbering, but can be used to determine the relative + * positioning of pages when displayed side by side or printed n-up (choose one). + *
        + *
      • DIRECTION_L2R - Left to right + *
      • DIRECTION_R2L - Right to left (including vertical writing systems such as + * Chinese, Japanese, and Korean) + *
      + *
    • The document's page mode, specifying how to display the + * document on exiting full-screen mode. It is meaningful only + * if the page mode is PageModeFullScreen (choose one). + *
        + *
      • NON_FULL_SCREEN_PAGE_MODE_USE_NONE - Neither document outline nor thumbnail images + * visible + *
      • NON_FULL_SCREEN_PAGE_MODE_USE_OUTLINES - Document outline visible + *
      • NON_FULL_SCREEN_PAGE_MODE_USE_THUMBS - Thumbnail images visible + *
      • NON_FULL_SCREEN_PAGE_MODE_USE_OC - Optional content group panel visible + *
      + *
    • PRINT_SCALING_NONE - Indicates that the print dialog should reflect no page scaling. + *
    + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + int ViewerPreferences { + set; + } + + /** + * Adds a viewer preference. + *
      + *
    • In case the key is one of these values: + *
        + *
      • PdfName.HIDETOOLBAR + *
      • PdfName.HIDEMENUBAR + *
      • PdfName.HIDEWINDOWUI + *
      • PdfName.FITWINDOW + *
      • PdfName.CENTERWINDOW + *
      • PdfName.DISPLAYDOCTITLE + *
      + * The value must be a of type PdfBoolean (true or false). + *
    • In case the key is PdfName.NONFULLSCREENPAGEMODE, + * the value must be one of these names: + *
        + *
      • PdfName.USENONE + *
      • PdfName.USEOUTLINES + *
      • PdfName.USETHUMBS + *
      • PdfName.USEOC + *
      + *
    • In case the key is PdfName.DIRECTION, + * the value must be one of these names: + *
        + *
      • PdfName.L2R + *
      • PdfName.R2L + *
      + *
    • In case the key is one of these values: + *
        + *
      • PdfName.VIEWAREA + *
      • PdfName.VIEWCLIP + *
      • PdfName.PRINTAREA + *
      • PdfName.PRINTCLIP + *
      + * The value must be one of these names: + *
        + *
      • PdfName.MEDIABOX + *
      • PdfName.CROPBOX + *
      • PdfName.BLEEDBOX + *
      • PdfName.TRIMBOX + *
      • PdfName.ARTBOX + *
      + *
    • In case the key is PdfName.PRINTSCALING, the value can be + *
        + *
      • PdfName.APPDEFAULT + *
      • PdfName.NONE + *
      + *
    • In case the key is PdfName.DUPLEX, the value can be: + *
        + *
      • PdfName.SIMPLEX + *
      • PdfName.DUPLEXFLIPSHORTEDGE + *
      • PdfName.DUPLEXFLIPLONGEDGE + *
      + *
    • In case the key is PdfName.PICKTRAYBYPDFSIZE, the value must be of type PdfBoolean. + *
    • In case the key is PdfName.PRINTPAGERANGE, the value must be of type PdfArray. + *
    • In case the key is PdfName.NUMCOPIES, the value must be of type PdfNumber. + *
        + *
      + * @param key the name of the viewer preference + * @param value the value of the viewer preference + * @see PdfViewerPreferences#setViewerPreferences + */ + void AddViewerPreference(PdfName key, PdfObject value); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfXConformance.cs b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfXConformance.cs new file mode 100644 index 0000000..d347c37 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/interfaces/IPdfXConformance.cs @@ -0,0 +1,71 @@ +using System; +/* + * $Id: IPdfXConformance.cs,v 1.2 2007/06/05 15:00:43 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.interfaces { + + public interface IPdfXConformance { + /** + * Sets the PDF/X conformance level. + * Allowed values are PDFX1A2001, PDFX32002, PDFA1A and PDFA1B. + * It must be called before opening the document. + * @param pdfxConformance the conformance level + */ + int PDFXConformance{ + set; + get; + } + + /** + * Checks if the PDF/X Conformance is necessary. + * @return true if the PDF has to be in conformance with any of the PDF/X specifications + */ + bool IsPdfX(); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/intern/PdfAnnotationsImp.cs b/iTechSharp/iTextSharp/text/pdf/intern/PdfAnnotationsImp.cs new file mode 100644 index 0000000..c24b2e9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/intern/PdfAnnotationsImp.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; +using iTextSharp.text; +/* + * $Id: PdfAnnotationsImp.cs,v 1.1 2007/02/09 15:34:40 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.intern { + + public class PdfAnnotationsImp { + + /** + * This is the AcroForm object for the complete document. + */ + protected internal PdfAcroForm acroForm; + + /** + * This is the array containing the references to annotations + * that were added to the document. + */ + protected internal ArrayList annotations; + + /** + * This is an array containg references to some delayed annotations + * (that were added for a page that doesn't exist yet). + */ + protected internal ArrayList delayedAnnotations = new ArrayList(); + + + public PdfAnnotationsImp(PdfWriter writer) { + acroForm = new PdfAcroForm(writer); + } + + /** + * Checks if the AcroForm is valid. + */ + public bool HasValidAcroForm() { + return acroForm.IsValid(); + } + + /** + * Gets the AcroForm object. + * @return the PdfAcroform object of the PdfDocument + */ + public PdfAcroForm AcroForm { + get { + return acroForm; + } + } + + public int SigFlags { + set { + acroForm.SigFlags = value; + } + } + + public void AddCalculationOrder(PdfFormField formField) { + acroForm.AddCalculationOrder(formField); + } + + public void AddAnnotation(PdfAnnotation annot) { + if (annot.IsForm()) { + PdfFormField field = (PdfFormField)annot; + if (field.Parent == null) + AddFormFieldRaw(field); + } + else + annotations.Add(annot); + } + + public void AddPlainAnnotation(PdfAnnotation annot) { + annotations.Add(annot); + } + + void AddFormFieldRaw(PdfFormField field) { + annotations.Add(field); + ArrayList kids = field.Kids; + if (kids != null) { + for (int k = 0; k < kids.Count; ++k) + AddFormFieldRaw((PdfFormField)kids[k]); + } + } + + public bool HasUnusedAnnotations() { + return annotations.Count > 0; + } + + public void ResetAnnotations() { + annotations = delayedAnnotations; + delayedAnnotations = new ArrayList(); + } + + public PdfArray RotateAnnotations(PdfWriter writer, Rectangle pageSize) { + PdfArray array = new PdfArray(); + int rotation = pageSize.Rotation % 360; + int currentPage = writer.CurrentPageNumber; + for (int k = 0; k < annotations.Count; ++k) { + PdfAnnotation dic = (PdfAnnotation)annotations[k]; + int page = dic.PlaceInPage; + if (page > currentPage) { + delayedAnnotations.Add(dic); + continue; + } + if (dic.IsForm()) { + if (!dic.IsUsed()) { + Hashtable templates = dic.Templates; + if (templates != null) + acroForm.AddFieldTemplates(templates); + } + PdfFormField field = (PdfFormField)dic; + if (field.Parent == null) + acroForm.AddDocumentField(field.IndirectReference); + } + if (dic.IsAnnotation()) { + array.Add(dic.IndirectReference); + if (!dic.IsUsed()) { + PdfRectangle rect = (PdfRectangle)dic.Get(PdfName.RECT); + if (rect != null) { + switch (rotation) { + case 90: + dic.Put(PdfName.RECT, new PdfRectangle( + pageSize.Top - rect.Bottom, + rect.Left, + pageSize.Top - rect.Top, + rect.Right)); + break; + case 180: + dic.Put(PdfName.RECT, new PdfRectangle( + pageSize.Right - rect.Left, + pageSize.Top - rect.Bottom, + pageSize.Right - rect.Right, + pageSize.Top - rect.Top)); + break; + case 270: + dic.Put(PdfName.RECT, new PdfRectangle( + rect.Bottom, + pageSize.Right - rect.Left, + rect.Top, + pageSize.Right - rect.Right)); + break; + } + } + } + } + if (!dic.IsUsed()) { + dic.SetUsed(); + writer.AddToBody(dic, dic.IndirectReference); + } + } + return array; + } + + public static PdfAnnotation ConvertAnnotation(PdfWriter writer, Annotation annot, Rectangle defaultRect) { + switch (annot.AnnotationType) { + case Annotation.URL_NET: + return new PdfAnnotation(writer, annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry(), new PdfAction((Uri) annot.Attributes[Annotation.URL])); + case Annotation.URL_AS_STRING: + return new PdfAnnotation(writer, annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry(), new PdfAction((String) annot.Attributes[Annotation.FILE])); + case Annotation.FILE_DEST: + return new PdfAnnotation(writer, annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry(), new PdfAction((String) annot.Attributes[Annotation.FILE], (String) annot.Attributes[Annotation.DESTINATION])); + case Annotation.SCREEN: + bool[] sparams = (bool[])annot.Attributes[Annotation.PARAMETERS]; + String fname = (String) annot.Attributes[Annotation.FILE]; + String mimetype = (String) annot.Attributes[Annotation.MIMETYPE]; + PdfFileSpecification fs; + if (sparams[0]) + fs = PdfFileSpecification.FileEmbedded(writer, fname, fname, null); + else + fs = PdfFileSpecification.FileExtern(writer, fname); + PdfAnnotation ann = PdfAnnotation.CreateScreen(writer, new Rectangle(annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry()), + fname, fs, mimetype, sparams[1]); + return ann; + case Annotation.FILE_PAGE: + return new PdfAnnotation(writer, annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry(), new PdfAction((String) annot.Attributes[Annotation.FILE], (int)annot.Attributes[Annotation.PAGE])); + case Annotation.NAMED_DEST: + return new PdfAnnotation(writer, annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry(), new PdfAction((int) annot.Attributes[Annotation.NAMED])); + case Annotation.LAUNCH: + return new PdfAnnotation(writer, annot.GetLlx(), annot.GetLly(), annot.GetUrx(), annot.GetUry(), new PdfAction((String) annot.Attributes[Annotation.APPLICATION],(String) annot.Attributes[Annotation.PARAMETERS],(String) annot.Attributes[Annotation.OPERATION],(String) annot.Attributes[Annotation.DEFAULTDIR])); + default: + return new PdfAnnotation(writer, defaultRect.Left, defaultRect.Bottom, defaultRect.Right, defaultRect.Top, new PdfString(annot.Title, PdfObject.TEXT_UNICODE), new PdfString(annot.Content, PdfObject.TEXT_UNICODE)); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/intern/PdfVersionImp.cs b/iTechSharp/iTextSharp/text/pdf/intern/PdfVersionImp.cs new file mode 100644 index 0000000..121a74f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/intern/PdfVersionImp.cs @@ -0,0 +1,172 @@ +using System; +using iTextSharp.text.pdf; +using iTextSharp.text; +using iTextSharp.text.pdf.interfaces; +/* + * $Id: PdfVersionImp.cs,v 1.1 2007/02/09 15:34:40 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.intern { + + /** + * Stores the PDF version information, + * knows how to write a PDF Header, + * and how to add the version to the catalog (if necessary). + */ + + public class PdfVersionImp : IPdfVersion { + + /** Contains different strings that are part of the header. */ + public static readonly byte[][] HEADER = { + DocWriter.GetISOBytes("\n"), + DocWriter.GetISOBytes("%PDF-"), + DocWriter.GetISOBytes("\n%\u00e2\u00e3\u00cf\u00d3\n") + }; + /** Indicates if the header was already written. */ + protected bool headerWasWritten = false; + /** Indicates if we are working in append mode. */ + protected bool appendmode = false; + /** The version that was or will be written to the header. */ + protected char header_version = PdfWriter.VERSION_1_4; + /** The version that will be written to the catalog. */ + protected PdfName catalog_version = null; + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(char) + */ + public char PdfVersion { + set { + if (headerWasWritten || appendmode) { + SetPdfVersion(GetVersionAsName(value)); + } + else { + this.header_version = value; + } + } + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setAtLeastPdfVersion(char) + */ + public void SetAtLeastPdfVersion(char version) { + if (version > header_version) { + PdfVersion = version; + } + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(com.lowagie.text.pdf.PdfName) + */ + public void SetPdfVersion(PdfName version) { + if (catalog_version == null || catalog_version.CompareTo(version) < 0) { + this.catalog_version = version; + } + } + + /** + * Sets the append mode. + */ + public void SetAppendmode(bool appendmode) { + this.appendmode = appendmode; + } + + /** + * Writes the header to the OutputStreamCounter. + * @throws IOException + */ + public void WriteHeader(OutputStreamCounter os) { + if (appendmode) { + os.Write(HEADER[0], 0, HEADER[0].Length); + } + else { + os.Write(HEADER[1], 0, HEADER[1].Length); + os.Write(GetVersionAsByteArray(header_version), 0, GetVersionAsByteArray(header_version).Length); + os.Write(HEADER[2], 0, HEADER[2].Length); + headerWasWritten = true; + } + } + + /** + * Returns the PDF version as a name. + * @param version the version character. + */ + public PdfName GetVersionAsName(char version) { + switch (version) { + case PdfWriter.VERSION_1_2: + return PdfWriter.PDF_VERSION_1_2; + case PdfWriter.VERSION_1_3: + return PdfWriter.PDF_VERSION_1_3; + case PdfWriter.VERSION_1_4: + return PdfWriter.PDF_VERSION_1_4; + case PdfWriter.VERSION_1_5: + return PdfWriter.PDF_VERSION_1_5; + case PdfWriter.VERSION_1_6: + return PdfWriter.PDF_VERSION_1_6; + case PdfWriter.VERSION_1_7: + return PdfWriter.PDF_VERSION_1_7; + default: + return PdfWriter.PDF_VERSION_1_4; + } + } + + /** + * Returns the version as a byte[]. + * @param version the version character + */ + public byte[] GetVersionAsByteArray(char version) { + return DocWriter.GetISOBytes(GetVersionAsName(version).ToString().Substring(1)); + } + + /** Adds the version to the Catalog dictionary. */ + public void AddToCatalog(PdfDictionary catalog) { + if(catalog_version != null) { + catalog.Put(PdfName.VERSION, catalog_version); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/intern/PdfViewerPreferencesImp.cs b/iTechSharp/iTextSharp/text/pdf/intern/PdfViewerPreferencesImp.cs new file mode 100644 index 0000000..f449467 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/intern/PdfViewerPreferencesImp.cs @@ -0,0 +1,359 @@ +using System; +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.interfaces; + +/* + * $Id: PdfViewerPreferencesImp.cs,v 1.7 2008/05/04 10:49:46 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.intern { + + /** + * Stores the information concerning viewer preferences, + * and contains the business logic that allows you to set viewer preferences. + */ + public class PdfViewerPreferencesImp : IPdfViewerPreferences { + + public static readonly PdfName[] VIEWER_PREFERENCES = { + PdfName.HIDETOOLBAR, // 0 + PdfName.HIDEMENUBAR, // 1 + PdfName.HIDEWINDOWUI, // 2 + PdfName.FITWINDOW, // 3 + PdfName.CENTERWINDOW, // 4 + PdfName.DISPLAYDOCTITLE, // 5 + PdfName.NONFULLSCREENPAGEMODE, // 6 + PdfName.DIRECTION, // 7 + PdfName.VIEWAREA, // 8 + PdfName.VIEWCLIP, // 9 + PdfName.PRINTAREA, // 10 + PdfName.PRINTCLIP, // 11 + PdfName.PRINTSCALING, // 12 + PdfName.DUPLEX, // 13 + PdfName.PICKTRAYBYPDFSIZE, // 14 + PdfName.PRINTPAGERANGE, // 15 + PdfName.NUMCOPIES // 16 + }; + + + /** A series of viewer preferences. */ + public static readonly PdfName[] NONFULLSCREENPAGEMODE_PREFERENCES = { + PdfName.USENONE, PdfName.USEOUTLINES, PdfName.USETHUMBS, PdfName.USEOC + }; + /** A series of viewer preferences. */ + public static readonly PdfName[] DIRECTION_PREFERENCES = { + PdfName.L2R, PdfName.R2L + }; + /** A series of viewer preferences. */ + public static readonly PdfName[] PAGE_BOUNDARIES = { + PdfName.MEDIABOX, PdfName.CROPBOX, PdfName.BLEEDBOX, PdfName.TRIMBOX, PdfName.ARTBOX + }; + /** A series of viewer preferences */ + public static readonly PdfName[] PRINTSCALING_PREFERENCES = { + PdfName.APPDEFAULT, PdfName.NONE + }; + /** A series of viewer preferences. */ + public static readonly PdfName[] DUPLEX_PREFERENCES = { + PdfName.SIMPLEX, PdfName.DUPLEXFLIPSHORTEDGE, PdfName.DUPLEXFLIPLONGEDGE + }; + /** This value will hold the viewer preferences for the page layout and page mode. */ + private int pageLayoutAndMode = 0; + + /** This dictionary holds the viewer preferences (other than page layout and page mode). */ + private PdfDictionary viewerPreferences = new PdfDictionary(); + + /** The mask to decide if a ViewerPreferences dictionary is needed */ + private const int viewerPreferencesMask = 0xfff000; + + /** + * Returns the page layout and page mode value. + */ + public int PageLayoutAndMode { + get { + return pageLayoutAndMode; + } + } + + /** + * Returns the viewer preferences. + */ + public PdfDictionary GetViewerPreferences() { + return viewerPreferences; + } + + /** + * Sets the viewer preferences as the sum of several constants. + * + * @param preferences + * the viewer preferences + * @see PdfWriter#setViewerPreferences + */ + public int ViewerPreferences { + set { + int preferences = value; + this.pageLayoutAndMode |= preferences; + // for backwards compatibility, it is also possible + // to set the following viewer preferences with this method: + if ((preferences & viewerPreferencesMask) != 0) { + pageLayoutAndMode = ~viewerPreferencesMask & pageLayoutAndMode; + if ((preferences & PdfWriter.HideToolbar) != 0) + viewerPreferences.Put(PdfName.HIDETOOLBAR, PdfBoolean.PDFTRUE); + if ((preferences & PdfWriter.HideMenubar) != 0) + viewerPreferences.Put(PdfName.HIDEMENUBAR, PdfBoolean.PDFTRUE); + if ((preferences & PdfWriter.HideWindowUI) != 0) + viewerPreferences.Put(PdfName.HIDEWINDOWUI, PdfBoolean.PDFTRUE); + if ((preferences & PdfWriter.FitWindow) != 0) + viewerPreferences.Put(PdfName.FITWINDOW, PdfBoolean.PDFTRUE); + if ((preferences & PdfWriter.CenterWindow) != 0) + viewerPreferences.Put(PdfName.CENTERWINDOW, PdfBoolean.PDFTRUE); + if ((preferences & PdfWriter.DisplayDocTitle) != 0) + viewerPreferences.Put(PdfName.DISPLAYDOCTITLE, PdfBoolean.PDFTRUE); + + if ((preferences & PdfWriter.NonFullScreenPageModeUseNone) != 0) + viewerPreferences.Put(PdfName.NONFULLSCREENPAGEMODE, PdfName.USENONE); + else if ((preferences & PdfWriter.NonFullScreenPageModeUseOutlines) != 0) + viewerPreferences.Put(PdfName.NONFULLSCREENPAGEMODE, PdfName.USEOUTLINES); + else if ((preferences & PdfWriter.NonFullScreenPageModeUseThumbs) != 0) + viewerPreferences.Put(PdfName.NONFULLSCREENPAGEMODE, PdfName.USETHUMBS); + else if ((preferences & PdfWriter.NonFullScreenPageModeUseOC) != 0) + viewerPreferences.Put(PdfName.NONFULLSCREENPAGEMODE, PdfName.USEOC); + + if ((preferences & PdfWriter.DirectionL2R) != 0) + viewerPreferences.Put(PdfName.DIRECTION, PdfName.L2R); + else if ((preferences & PdfWriter.DirectionR2L) != 0) + viewerPreferences.Put(PdfName.DIRECTION, PdfName.R2L); + + if ((preferences & PdfWriter.PrintScalingNone) != 0) + viewerPreferences.Put(PdfName.PRINTSCALING, PdfName.NONE); + } + } + } + + /** + * Given a key for a viewer preference (a PdfName object), + * this method returns the index in the VIEWER_PREFERENCES array. + * @param key a PdfName referring to a viewer preference + * @return an index in the VIEWER_PREFERENCES array + */ + private int GetIndex(PdfName key) { + for (int i = 0; i < VIEWER_PREFERENCES.Length; i++) { + if (VIEWER_PREFERENCES[i].Equals(key)) + return i; + } + return -1; + } + + /** + * Checks if some value is valid for a certain key. + */ + private bool IsPossibleValue(PdfName value, PdfName[] accepted) { + for (int i = 0; i < accepted.Length; i++) { + if (accepted[i].Equals(value)) { + return true; + } + } + return false; + } + + /** + * Sets the viewer preferences for printing. + */ + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + switch (GetIndex(key)) { + case 0: // HIDETOOLBAR + case 1: // HIDEMENUBAR + case 2: // HIDEWINDOWUI + case 3: // FITWINDOW + case 4: // CENTERWINDOW + case 5: // DISPLAYDOCTITLE + case 14: // PICKTRAYBYPDFSIZE + if (value is PdfBoolean) { + viewerPreferences.Put(key, value); + } + break; + case 6: // NONFULLSCREENPAGEMODE + if (value is PdfName + && IsPossibleValue((PdfName)value, NONFULLSCREENPAGEMODE_PREFERENCES)) { + viewerPreferences.Put(key, value); + } + break; + case 7: // DIRECTION + if (value is PdfName + && IsPossibleValue((PdfName)value, DIRECTION_PREFERENCES)) { + viewerPreferences.Put(key, value); + } + break; + case 8: // VIEWAREA + case 9: // VIEWCLIP + case 10: // PRINTAREA + case 11: // PRINTCLIP + if (value is PdfName + && IsPossibleValue((PdfName)value, PAGE_BOUNDARIES)) { + viewerPreferences.Put(key, value); + } + break; + case 12: // PRINTSCALING + if (value is PdfName + && IsPossibleValue((PdfName)value, PRINTSCALING_PREFERENCES)) { + viewerPreferences.Put(key, value); + } + break; + case 13: // DUPLEX + if (value is PdfName + && IsPossibleValue((PdfName)value, DUPLEX_PREFERENCES)) { + viewerPreferences.Put(key, value); + } + break; + case 15: // PRINTPAGERANGE + if (value is PdfArray) { + viewerPreferences.Put(key, value); + } + break; + case 16: // NUMCOPIES + if (value is PdfNumber) { + viewerPreferences.Put(key, value); + } + break; + } + } + + /** + * Adds the viewer preferences defined in the preferences parameter to a + * PdfDictionary (more specifically the root or catalog of a PDF file). + * + * @param catalog + */ + public void AddToCatalog(PdfDictionary catalog) { + // Page Layout + catalog.Remove(PdfName.PAGELAYOUT); + if ((pageLayoutAndMode & PdfWriter.PageLayoutSinglePage) != 0) + catalog.Put(PdfName.PAGELAYOUT, PdfName.SINGLEPAGE); + else if ((pageLayoutAndMode & PdfWriter.PageLayoutOneColumn) != 0) + catalog.Put(PdfName.PAGELAYOUT, PdfName.ONECOLUMN); + else if ((pageLayoutAndMode & PdfWriter.PageLayoutTwoColumnLeft) != 0) + catalog.Put(PdfName.PAGELAYOUT, PdfName.TWOCOLUMNLEFT); + else if ((pageLayoutAndMode & PdfWriter.PageLayoutTwoColumnRight) != 0) + catalog.Put(PdfName.PAGELAYOUT, PdfName.TWOCOLUMNRIGHT); + else if ((pageLayoutAndMode & PdfWriter.PageLayoutTwoPageLeft) != 0) + catalog.Put(PdfName.PAGELAYOUT, PdfName.TWOPAGELEFT); + else if ((pageLayoutAndMode & PdfWriter.PageLayoutTwoPageRight) != 0) + catalog.Put(PdfName.PAGELAYOUT, PdfName.TWOPAGERIGHT); + + // Page Mode + catalog.Remove(PdfName.PAGEMODE); + if ((pageLayoutAndMode & PdfWriter.PageModeUseNone) != 0) + catalog.Put(PdfName.PAGEMODE, PdfName.USENONE); + else if ((pageLayoutAndMode & PdfWriter.PageModeUseOutlines) != 0) + catalog.Put(PdfName.PAGEMODE, PdfName.USEOUTLINES); + else if ((pageLayoutAndMode & PdfWriter.PageModeUseThumbs) != 0) + catalog.Put(PdfName.PAGEMODE, PdfName.USETHUMBS); + else if ((pageLayoutAndMode & PdfWriter.PageModeFullScreen) != 0) + catalog.Put(PdfName.PAGEMODE, PdfName.FULLSCREEN); + else if ((pageLayoutAndMode & PdfWriter.PageModeUseOC) != 0) + catalog.Put(PdfName.PAGEMODE, PdfName.USEOC); + else if ((pageLayoutAndMode & PdfWriter.PageModeUseAttachments) != 0) + catalog.Put(PdfName.PAGEMODE, PdfName.USEATTACHMENTS); + + // viewer preferences (Table 8.1 of the PDF Reference) + catalog.Remove(PdfName.VIEWERPREFERENCES); + if (viewerPreferences.Size > 0) { + catalog.Put(PdfName.VIEWERPREFERENCES, viewerPreferences); + } + } + + public static PdfViewerPreferencesImp GetViewerPreferences(PdfDictionary catalog) { + PdfViewerPreferencesImp preferences = new PdfViewerPreferencesImp(); + int prefs = 0; + PdfName name = null; + // page layout + PdfObject obj = PdfReader.GetPdfObjectRelease(catalog.Get(PdfName.PAGELAYOUT)); + if (obj != null && obj.IsName()) { + name = (PdfName) obj; + if (name.Equals(PdfName.SINGLEPAGE)) + prefs |= PdfWriter.PageLayoutSinglePage; + else if (name.Equals(PdfName.ONECOLUMN)) + prefs |= PdfWriter.PageLayoutOneColumn; + else if (name.Equals(PdfName.TWOCOLUMNLEFT)) + prefs |= PdfWriter.PageLayoutTwoColumnLeft; + else if (name.Equals(PdfName.TWOCOLUMNRIGHT)) + prefs |= PdfWriter.PageLayoutTwoColumnRight; + else if (name.Equals(PdfName.TWOPAGELEFT)) + prefs |= PdfWriter.PageLayoutTwoPageLeft; + else if (name.Equals(PdfName.TWOPAGERIGHT)) + prefs |= PdfWriter.PageLayoutTwoPageRight; + } + // page mode + obj = PdfReader.GetPdfObjectRelease(catalog.Get(PdfName.PAGEMODE)); + if (obj != null && obj.IsName()) { + name = (PdfName) obj; + if (name.Equals(PdfName.USENONE)) + prefs |= PdfWriter.PageModeUseNone; + else if (name.Equals(PdfName.USEOUTLINES)) + prefs |= PdfWriter.PageModeUseOutlines; + else if (name.Equals(PdfName.USETHUMBS)) + prefs |= PdfWriter.PageModeUseThumbs; + else if (name.Equals(PdfName.USEOC)) + prefs |= PdfWriter.PageModeUseOC; + else if (name.Equals(PdfName.USEATTACHMENTS)) + prefs |= PdfWriter.PageModeUseAttachments; + } + // set page layout and page mode preferences + preferences.ViewerPreferences = prefs; + // other preferences + obj = PdfReader.GetPdfObjectRelease(catalog + .Get(PdfName.VIEWERPREFERENCES)); + if (obj != null && obj.IsDictionary()) { + PdfDictionary vp = (PdfDictionary) obj; + for (int i = 0; i < VIEWER_PREFERENCES.Length; i++) { + obj = PdfReader.GetPdfObjectRelease(vp.Get(VIEWER_PREFERENCES[i])); + preferences.AddViewerPreference(VIEWER_PREFERENCES[i], obj); + } + } + return preferences; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/intern/PdfXConformanceImp.cs b/iTechSharp/iTextSharp/text/pdf/intern/PdfXConformanceImp.cs new file mode 100644 index 0000000..296a053 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/intern/PdfXConformanceImp.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; +using iTextSharp.text; +using iTextSharp.text.pdf.interfaces; + +/* + * $Id: PdfXConformanceImp.cs,v 1.3 2007/06/05 15:00:44 psoares33 Exp $ + * + * Copyright 2006 Bruno Lowagie (based on code by Paulo Soares) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf.intern { + + public class PdfXConformanceImp : IPdfXConformance { + + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_COLOR = 1; + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_CMYK = 2; + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_RGB = 3; + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_FONT = 4; + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_IMAGE = 5; + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_GSTATE = 6; + /** A key for an aspect that can be checked for PDF/X Conformance. */ + public const int PDFXKEY_LAYER = 7; + + /** + * The value indicating if the PDF has to be in conformance with PDF/X. + */ + protected internal int pdfxConformance = PdfWriter.PDFXNONE; + + /** + * @see com.lowagie.text.pdf.interfaces.PdfXConformance#setPDFXConformance(int) + */ + public int PDFXConformance { + set { + this.pdfxConformance = value; + } + get { + return pdfxConformance; + } + } + + /** + * Checks if the PDF/X Conformance is necessary. + * @return true if the PDF has to be in conformance with any of the PDF/X specifications + */ + public bool IsPdfX() { + return pdfxConformance != PdfWriter.PDFXNONE; + } + /** + * Checks if the PDF has to be in conformance with PDF/X-1a:2001 + * @return true of the PDF has to be in conformance with PDF/X-1a:2001 + */ + public bool IsPdfX1A2001() { + return pdfxConformance == PdfWriter.PDFX1A2001; + } + /** + * Checks if the PDF has to be in conformance with PDF/X-3:2002 + * @return true of the PDF has to be in conformance with PDF/X-3:2002 + */ + public bool IsPdfX32002() { + return pdfxConformance == PdfWriter.PDFX32002; + } + + /** + * Checks if the PDF has to be in conformance with PDFA1 + * @return true of the PDF has to be in conformance with PDFA1 + */ + public bool IsPdfA1() { + return pdfxConformance == PdfWriter.PDFA1A || pdfxConformance == PdfWriter.PDFA1B; + } + + /** + * Checks if the PDF has to be in conformance with PDFA1A + * @return true of the PDF has to be in conformance with PDFA1A + */ + public bool IsPdfA1A() { + return pdfxConformance == PdfWriter.PDFA1A; + } + + public void CompleteInfoDictionary(PdfDictionary info) { + if (IsPdfX() && !IsPdfA1()) { + if (info.Get(PdfName.GTS_PDFXVERSION) == null) { + if (IsPdfX1A2001()) { + info.Put(PdfName.GTS_PDFXVERSION, new PdfString("PDF/X-1:2001")); + info.Put(new PdfName("GTS_PDFXConformance"), new PdfString("PDF/X-1a:2001")); + } + else if (IsPdfX32002()) + info.Put(PdfName.GTS_PDFXVERSION, new PdfString("PDF/X-3:2002")); + } + if (info.Get(PdfName.TITLE) == null) { + info.Put(PdfName.TITLE, new PdfString("Pdf document")); + } + if (info.Get(PdfName.CREATOR) == null) { + info.Put(PdfName.CREATOR, new PdfString("Unknown")); + } + if (info.Get(PdfName.TRAPPED) == null) { + info.Put(PdfName.TRAPPED, new PdfName("False")); + } + } + } + + public void CompleteExtraCatalog(PdfDictionary extraCatalog) { + if (IsPdfX() && !IsPdfA1()) { + if (extraCatalog.Get(PdfName.OUTPUTINTENTS) == null) { + PdfDictionary outp = new PdfDictionary(PdfName.OUTPUTINTENT); + outp.Put(PdfName.OUTPUTCONDITION, new PdfString("SWOP CGATS TR 001-1995")); + outp.Put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString("CGATS TR 001")); + outp.Put(PdfName.REGISTRYNAME, new PdfString("http://www.color.org")); + outp.Put(PdfName.INFO, new PdfString("")); + outp.Put(PdfName.S, PdfName.GTS_PDFX); + extraCatalog.Put(PdfName.OUTPUTINTENTS, new PdfArray(outp)); + } + } + } + + /** + * Business logic that checks if a certain object is in conformance with PDF/X. + * @param writer the writer that is supposed to write the PDF/X file + * @param key the type of PDF/X conformance that has to be checked + * @param obj1 the object that is checked for conformance + */ + public static void CheckPDFXConformance(PdfWriter writer, int key, Object obj1) { + if (writer == null || !writer.IsPdfX()) + return; + int conf = writer.PDFXConformance; + switch (key) { + case PDFXKEY_COLOR: + switch (conf) { + case PdfWriter.PDFX1A2001: + if (obj1 is ExtendedColor) { + ExtendedColor ec = (ExtendedColor)obj1; + switch (ec.Type) { + case ExtendedColor.TYPE_CMYK: + case ExtendedColor.TYPE_GRAY: + return; + case ExtendedColor.TYPE_RGB: + throw new PdfXConformanceException("Colorspace RGB is not allowed."); + case ExtendedColor.TYPE_SEPARATION: + SpotColor sc = (SpotColor)ec; + CheckPDFXConformance(writer, PDFXKEY_COLOR, sc.PdfSpotColor.AlternativeCS); + break; + case ExtendedColor.TYPE_SHADING: + ShadingColor xc = (ShadingColor)ec; + CheckPDFXConformance(writer, PDFXKEY_COLOR, xc.PdfShadingPattern.Shading.ColorSpace); + break; + case ExtendedColor.TYPE_PATTERN: + PatternColor pc = (PatternColor)ec; + CheckPDFXConformance(writer, PDFXKEY_COLOR, pc.Painter.DefaultColor); + break; + } + } + else if (obj1 is Color) + throw new PdfXConformanceException("Colorspace RGB is not allowed."); + break; + } + break; + case PDFXKEY_CMYK: + break; + case PDFXKEY_RGB: + if (conf == PdfWriter.PDFX1A2001) + throw new PdfXConformanceException("Colorspace RGB is not allowed."); + break; + case PDFXKEY_FONT: + if (!((BaseFont)obj1).IsEmbedded()) + throw new PdfXConformanceException("All the fonts must be embedded."); + break; + case PDFXKEY_IMAGE: + PdfImage image = (PdfImage)obj1; + if (image.Get(PdfName.SMASK) != null) + throw new PdfXConformanceException("The /SMask key is not allowed in images."); + switch (conf) { + case PdfWriter.PDFX1A2001: + PdfObject cs = image.Get(PdfName.COLORSPACE); + if (cs == null) + return; + if (cs.IsName()) { + if (PdfName.DEVICERGB.Equals(cs)) + throw new PdfXConformanceException("Colorspace RGB is not allowed."); + } + else if (cs.IsArray()) { + if (PdfName.CALRGB.Equals(((PdfArray)cs).ArrayList[0])) + throw new PdfXConformanceException("Colorspace CalRGB is not allowed."); + } + break; + } + break; + case PDFXKEY_GSTATE: + PdfDictionary gs = (PdfDictionary)obj1; + PdfObject obj = gs.Get(PdfName.BM); + if (obj != null && !PdfGState.BM_NORMAL.Equals(obj) && !PdfGState.BM_COMPATIBLE.Equals(obj)) + throw new PdfXConformanceException("Blend mode " + obj.ToString() + " not allowed."); + obj = gs.Get(PdfName.CA); + double v = 0.0; + if (obj != null && (v = ((PdfNumber)obj).DoubleValue) != 1.0) + throw new PdfXConformanceException("Transparency is not allowed: /CA = " + v); + obj = gs.Get(PdfName.ca_); + v = 0.0; + if (obj != null && (v = ((PdfNumber)obj).DoubleValue) != 1.0) + throw new PdfXConformanceException("Transparency is not allowed: /ca = " + v); + break; + case PDFXKEY_LAYER: + throw new PdfXConformanceException("Layers are not allowed."); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/IEventListener.cs b/iTechSharp/iTextSharp/text/rtf/IEventListener.cs new file mode 100644 index 0000000..61e1c4e --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/IEventListener.cs @@ -0,0 +1,6 @@ +using System; + +namespace iTextSharp.text.rtf { + public interface IEventListener { + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/IRtfBasicElement.cs b/iTechSharp/iTextSharp/text/rtf/IRtfBasicElement.cs new file mode 100644 index 0000000..330ce19 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/IRtfBasicElement.cs @@ -0,0 +1,87 @@ +using System; +using System.IO; +using iTextSharp.text.rtf.document; +using iTextSharp.text; +/* + * $Id: IRtfBasicElement.cs,v 1.4 2008/05/13 11:25:42 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf { + + public interface IRtfBasicElement : IRtfElementInterface { + + /** + * Writes the element content to the given output stream. + * + * @param out The OutputStream to write the content to + */ + void WriteContent(Stream outp); + + /** + * Sets the RtfDocument this RtfElement belongs to + * + * @param doc The @link{com.lowagie.text.rtf.document.RtfDocument} this RtfElement belongs to + */ + void SetRtfDocument(RtfDocument doc); + + /** + * Sets whether this IRtfBasicElement is in a table + * + * @param inTable Whether this IRtfBasicElement is in a table + */ + void SetInTable(bool inTable); + + /** + * Sets whether this IRtfBasicElement is in a header + * + * @param inHeader Whether this IRtfBasicElement is in a header + */ + void SetInHeader(bool inHeader); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/IRtfExtendedElement.cs b/iTechSharp/iTextSharp/text/rtf/IRtfExtendedElement.cs new file mode 100644 index 0000000..74c5ddd --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/IRtfExtendedElement.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; + +/* + * $Id: IRtfExtendedElement.cs,v 1.5 2008/05/16 19:30:12 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf { + + /** + * The RtfExtendedElement interface is to be used for elements that also + * write data into the definition part of the rtf document + * Version: $Id: IRtfExtendedElement.cs,v 1.5 2008/05/16 19:30:12 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public interface IRtfExtendedElement : IRtfBasicElement { + /** + * Write the definition part of the element + * + * @param doc The OutputStream to write the element definition to + */ + void WriteDefinition(Stream outp); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/RtfAddableElement.cs b/iTechSharp/iTextSharp/text/rtf/RtfAddableElement.cs new file mode 100644 index 0000000..89b9b4a --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/RtfAddableElement.cs @@ -0,0 +1,134 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfAddableElement.cs,v 1.6 2008/05/16 19:30:13 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * Co-Developer of the code is Mark Hall. Portions created by the Co-Developer are + * Copyright (C) 2006 by Mark Hall. All Rights Reserved + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf { + + /** + * The RtfAddableElement is the superclass for all rtf specific elements + * that need to be added to an iText document. It is an extension of Chunk + * and it also implements RtfBasicElement. It is an abstract class thus it + * cannot be instantiated itself and has to be subclassed to be used. + * + * @version $Revision: 1.6 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public abstract class RtfAddableElement : Chunk, IRtfBasicElement { + + /** + * The RtfDocument this RtfAddableElement belongs to. + */ + protected RtfDocument doc = null; + /** + * Whether this RtfAddableElement is contained in a table. + */ + protected bool inTable = false; + /** + * Whether this RtfAddableElement is contained in a header. + */ + protected bool inHeader = false; + + /** + * Constructs a new RtfAddableElement. The Chunk content is + * set to an empty string and the font to the default Font(). + */ + public RtfAddableElement() : base("", new Font()) { + } + + /** + * Writes the element content to the given output stream. + */ + public abstract void WriteContent(Stream outp); + + /** + * Sets the RtfDocument this RtfAddableElement belongs to. + */ + public void SetRtfDocument(RtfDocument doc) { + this.doc = doc; + } + + /** + * Sets whether this RtfAddableElement is contained in a table. + */ + public void SetInTable(bool inTable) { + this.inTable = inTable; + } + + /** + * Sets whether this RtfAddableElement is contained in a header/footer. + */ + public void SetInHeader(bool inHeader) { + this.inHeader = inHeader; + } + + /** + * Transforms an integer into its String representation and then returns the bytes + * of that string. + * + * @param i The integer to convert + * @return A byte array representing the integer + */ + public byte[] IntToByteArray(int i) { + return DocWriter.GetISOBytes(i.ToString()); + } + + /** + * RtfAddableElement subclasses are never assumed to be empty. + */ + public override bool IsEmpty() { + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/RtfElement.cs b/iTechSharp/iTextSharp/text/rtf/RtfElement.cs new file mode 100644 index 0000000..71cabe4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/RtfElement.cs @@ -0,0 +1,159 @@ +using System; +using System.IO; +using iTextSharp.text.rtf.document; +using iTextSharp.text; +/* + * $Id: RtfElement.cs,v 1.5 2008/05/16 19:30:14 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf { + + /** + * RtfElement is the base class for all RTF Element classes + * + * Version: $Id: RtfElement.cs,v 1.5 2008/05/16 19:30:14 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public abstract class RtfElement : IRtfBasicElement { + /** + * Constant for the beginning of a rtf group + */ + public static byte[] OPEN_GROUP = {(byte)'{'}; + /** + * Constant for the end of an rtf group + */ + public static byte[] CLOSE_GROUP = {(byte)'}'}; + /** + * Constant for a delimiter in rtf + */ + public static byte[] DELIMITER = {(byte)' '}; + /** + * Constant for a comma delimiter in rtf + */ + public static byte[] COMMA_DELIMITER = {(byte)';'}; + /** + * The factor to use for translating from iText to rtf measurments + */ + public const double TWIPS_FACTOR = 20; + + /** + * The RtfDocument this RtfElement belongs to + */ + protected RtfDocument document = null; + /** + * Whether this RtfElement is in a table + */ + protected bool inTable = false; + /** + * Whether this RtfElement is in a header + */ + protected bool inHeader = false; + + /** + * Constructs a RtfElement belonging to the specified RtfDocument. + * + * @param doc The RtfDocument this RtfElement belongs to + */ + public RtfElement(RtfDocument doc) : base(){ + this.document = doc; + } + + /** + * Transforms an integer into its String representation and then returns the bytes + * of that string. + * + * @param i The integer to convert + * @return A byte array representing the integer + */ + public byte[] IntToByteArray(int i) { + return DocWriter.GetISOBytes(i.ToString()); + } + + /** + * Writes the element content to the given output stream. + */ + public abstract void WriteContent(Stream outp); + + /** + * Sets the RtfDocument this RtfElement belongs to + * + * @param doc The RtfDocument to use + */ + public virtual void SetRtfDocument(RtfDocument doc) { + this.document = doc; + } + + /** + * Gets whether this RtfElement is in a table + * + * @return Whether this RtfElement is in a table + */ + public virtual bool IsInTable() { + return inTable; + } + + /** + * Sets whether this RtfElement is in a table + * + * @param inTable True if this RtfElement is in a table, false otherwise + */ + public virtual void SetInTable(bool inTable) { + this.inTable = inTable; + } + + /** + * Sets whether this RtfElement is in a header + * + * @param inHeader True if this RtfElement is in a header, false otherwise + */ + public virtual void SetInHeader(bool inHeader) { + this.inHeader = inHeader; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/RtfMapper.cs b/iTechSharp/iTextSharp/text/rtf/RtfMapper.cs new file mode 100644 index 0000000..ea4e103 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/RtfMapper.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.field; +using iTextSharp.text.rtf.graphic; +using iTextSharp.text.rtf.list; +using iTextSharp.text.rtf.table; +using iTextSharp.text.rtf.text; +/* + * $Id: RtfMapper.cs,v 1.4 2008/05/16 19:30:14 psoares33 Exp $ + * + * + * Copyright 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf { + + /** + * The RtfMapper provides mappings between com.lowagie.text.* classes + * and the corresponding com.lowagie.text.rtf.** classes. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfMapper { + + /** + * The RtfDocument this RtfMapper belongs to + */ + RtfDocument rtfDoc; + + /** + * Constructs a RtfMapper for a RtfDocument + * + * @param doc The RtfDocument this RtfMapper belongs to + */ + public RtfMapper(RtfDocument doc) { + this.rtfDoc = doc; + } + + /** + * Takes an Element subclass and returns an array of RtfBasicElement + * subclasses, that contained the mapped RTF equivalent to the Element + * passed in. + * + * @param element The Element to wrap + * @return An array of RtfBasicElement wrapping the Element + * @throws DocumentException + */ + public IRtfBasicElement[] MapElement(IElement element) { + ArrayList rtfElements = new ArrayList(); + + if (element is IRtfBasicElement) { + IRtfBasicElement rtfElement = (IRtfBasicElement) element; + rtfElement.SetRtfDocument(this.rtfDoc); + return new IRtfBasicElement[]{rtfElement}; + } + switch (element.Type) { + case Element.CHUNK: + Chunk chunk = (Chunk) element; + if (chunk.HasAttributes()) { + if (chunk.Attributes.ContainsKey(Chunk.IMAGE)) { + rtfElements.Add(new RtfImage(rtfDoc, (Image) chunk.Attributes[Chunk.IMAGE])); + } else if (chunk.Attributes.ContainsKey(Chunk.NEWPAGE)) { + rtfElements.Add(new RtfNewPage(rtfDoc)); + } else if (chunk.Attributes.ContainsKey(Chunk.TAB)) { + float tabPos = (float) ((Object[]) chunk.Attributes[Chunk.TAB])[1]; + RtfTab tab = new RtfTab(tabPos, RtfTab.TAB_LEFT_ALIGN); + tab.SetRtfDocument(rtfDoc); + rtfElements.Add(tab); + rtfElements.Add(new RtfChunk(rtfDoc, new Chunk("\t"))); + } else { + rtfElements.Add(new RtfChunk(rtfDoc, (Chunk) element)); + } + } else { + rtfElements.Add(new RtfChunk(rtfDoc, (Chunk) element)); + } + break; + case Element.PHRASE: + rtfElements.Add(new RtfPhrase(rtfDoc, (Phrase) element)); + break; + case Element.PARAGRAPH: + rtfElements.Add(new RtfParagraph(rtfDoc, (Paragraph) element)); + break; + case Element.ANCHOR: + rtfElements.Add(new RtfAnchor(rtfDoc, (Anchor) element)); + break; + case Element.ANNOTATION: + rtfElements.Add(new RtfAnnotation(rtfDoc, (Annotation) element)); + break; + case Element.IMGRAW: + case Element.IMGTEMPLATE: + case Element.JPEG: + rtfElements.Add(new RtfImage(rtfDoc, (Image) element)); + break; + case Element.AUTHOR: + case Element.SUBJECT: + case Element.KEYWORDS: + case Element.TITLE: + case Element.PRODUCER: + case Element.CREATIONDATE: + rtfElements.Add(new RtfInfoElement(rtfDoc, (Meta) element)); + break; + case Element.LIST: + rtfElements.Add(new RtfList(rtfDoc, (List) element)); + break; + case Element.LISTITEM: + rtfElements.Add(new RtfListItem(rtfDoc, (ListItem) element)); + break; + case Element.SECTION: + rtfElements.Add(new RtfSection(rtfDoc, (Section) element)); + break; + case Element.CHAPTER: + rtfElements.Add(new RtfChapter(rtfDoc, (Chapter) element)); + break; + case Element.TABLE: + try { + rtfElements.Add(new RtfTable(rtfDoc, (Table) element)); + } + catch (InvalidCastException) { + rtfElements.Add(new RtfTable(rtfDoc, ((SimpleTable) element).CreateTable())); + } + break; + } + + return (IRtfBasicElement[]) rtfElements.ToArray(typeof(IRtfBasicElement)); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/RtfWriter2.cs b/iTechSharp/iTextSharp/text/rtf/RtfWriter2.cs new file mode 100644 index 0000000..a663d45 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/RtfWriter2.cs @@ -0,0 +1,334 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.text; +using iTextSharp.text.rtf.parser; +/* + * $Id: RtfWriter2.cs,v 1.11 2008/05/23 17:24:11 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf { + + /** + * The RtfWriter allows the creation of rtf documents via the iText system + * + * Version: $Id: RtfWriter2.cs,v 1.11 2008/05/23 17:24:11 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfWriter2 : DocWriter { + /** + * The RtfDocument this RtfWriter is creating + */ + private RtfDocument rtfDoc = null; + + /** + * Constructs a new RtfWriter that listens to the specified Document and + * writes its output to the Stream. + * + * @param doc The Document that this RtfWriter listens to + * @param os The Stream to write to + */ + protected RtfWriter2(Document doc, Stream os) : base(doc, os) { + doc.AddDocListener(this); + rtfDoc = new RtfDocument(); + } + + /** + * Static method to generate RtfWriters + * + * @param doc The Document that this RtfWriter listens to + * @param os The Stream to write to + * @return The new RtfWriter + */ + public static RtfWriter2 GetInstance(Document doc, Stream os) { + return new RtfWriter2(doc, os); + } + + /** + * Sets the header to use + * + * @param hf The HeaderFooter to use + */ + public override HeaderFooter Header { + set { + this.rtfDoc.GetDocumentHeader().SetHeader(value); + } + } + + /** + * Resets the header + */ + public override void ResetHeader() { + this.rtfDoc.GetDocumentHeader().SetHeader(null); + } + + /** + * Sets the footer to use + * + * @param hf The HeaderFooter to use + */ + public override HeaderFooter Footer { + set { + this.rtfDoc.GetDocumentHeader().SetFooter(value); + } + } + + /** + * Resets the footer + */ + public override void ResetFooter() { + this.rtfDoc.GetDocumentHeader().SetFooter(null); + } + + /** + * This method is not supported in the RtfWriter + * @param i Unused + */ + public override int PageCount { + set {} + } + + /** + * This method is not supported in the RtfWriter + */ + public override void ResetPageCount() { + } + + /** + * Opens the RtfDocument + */ + public override void Open() { + base.Open(); + this.rtfDoc.Open(); + } + + /** + * Closes the RtfDocument. This causes the document to be written + * to the specified Stream + */ + public override void Close() { + if (open) { + rtfDoc.WriteDocument(os); + base.Close(); + this.rtfDoc = new RtfDocument(); + } + } + + /** + * Adds an Element to the Document + * + * @param element The element to be added + * @return false + * @throws DocumentException + */ + public override bool Add(IElement element) { + if (pause) { + return false; + } + IRtfBasicElement[] rtfElements = rtfDoc.GetMapper().MapElement(element); + if(rtfElements.Length != 0) { + for (int i = 0; i < rtfElements.Length; i++) { + if (rtfElements[i] != null) { + rtfDoc.Add(rtfElements[i]); + } + } + return true; + } else { + return false; + } + } + + /** + * Adds a page break + * + * @return false + */ + public override bool NewPage() { + rtfDoc.Add(new RtfNewPage(rtfDoc)); + return true; + } + + /** + * Sets the page margins + * + * @param left The left margin + * @param right The right margin + * @param top The top margin + * @param bottom The bottom margin + * @return false + */ + public override bool SetMargins(float left, float right, float top, float bottom) { + rtfDoc.GetDocumentHeader().GetPageSetting().SetMarginLeft((int) (left * RtfElement.TWIPS_FACTOR)); + rtfDoc.GetDocumentHeader().GetPageSetting().SetMarginRight((int) (right * RtfElement.TWIPS_FACTOR)); + rtfDoc.GetDocumentHeader().GetPageSetting().SetMarginTop((int) (top * RtfElement.TWIPS_FACTOR)); + rtfDoc.GetDocumentHeader().GetPageSetting().SetMarginBottom((int) (bottom * RtfElement.TWIPS_FACTOR)); + return true; + } + + /** + * Sets the size of the page + * + * @param rect A Rectangle representing the page + * @return false + */ + public override bool SetPageSize(Rectangle rect) { + rtfDoc.GetDocumentHeader().GetPageSetting().SetPageSize(rect); + return true; + } + + /** + * Whether to automagically generate table of contents entries when + * adding Chapters or Sections. + * + * @param autogenerate Whether to automatically generate TOC entries + */ + public void SetAutogenerateTOCEntries(bool autogenerate) { + this.rtfDoc.SetAutogenerateTOCEntries(autogenerate); + } + + /** + * Gets the RtfDocumentSettings that specify how the rtf document is generated. + * + * @return The current RtfDocumentSettings. + */ + public RtfDocumentSettings GetDocumentSettings() { + return this.rtfDoc.GetDocumentSettings(); + } + + /** + * Adds the complete RTF document to the current RTF document being generated. + * It will parse the font and color tables and correct the font and color references + * so that the imported RTF document retains its formattings. + * + * @param documentSource The Stream to read the RTF document from. + * @throws IOException On errors reading the RTF document. + * @throws DocumentException On errors adding to this RTF document. + */ + public void ImportRtfDocument(Stream documentSource) { + ImportRtfDocument(documentSource, null); + } + + /** + * Adds the complete RTF document to the current RTF document being generated. + * It will parse the font and color tables and correct the font and color references + * so that the imported RTF document retains its formattings. + * Uses new RtfParser object. + * + * @param documentSource The Stream to read the RTF document from. + * @param eventListeners The array of event listeners. May be null + * @throws IOException + * @throws DocumentException + * + * @see com.lowagie.text.rtf.parser.RtfParser + * @see com.lowagie.text.rtf.parser.RtfParser#importRtfDocument(Reader, RtfDocument) + * @since 2.0.8 + * @author Howard Shank + */ + public void ImportRtfDocument(Stream documentSource, IEventListener[] events ) { + if(!this.open) { + throw new DocumentException("The document must be open to import RTF documents."); + } + RtfParser rtfImport = new RtfParser(); + if(events != null) { + for(int idx=0;idx
      + * + * For convenience the RtfDirectContent provides a DIRECT_SOFT_LINEBREAK + * constant that makes it possible to easily add soft line-breaks anywhere in + * the RTF document. + * + * @version $Revision: 1.6 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfDirectContent : RtfAddableElement { + /** + * Add the DIRECT_SOFT_LINEBREAK to the Document to insert + * a soft line-break at that position. + */ + public static RtfDirectContent DIRECT_SOFT_LINEBREAK = new RtfDirectContent("\\line"); + + /** + * The direct content to add. + */ + private String directContent = ""; + + /** + * Constructs a new RtfDirectContent with the content to add. + * + * @param directContent The content to add. + */ + public RtfDirectContent(String directContent) { + this.directContent = directContent; + } + + /** + * Writes the element content to the given output stream. + */ + public override void WriteContent(Stream outp) { + byte[] contentBytes = DocWriter.GetISOBytes(this.directContent); + outp.Write(contentBytes, 0, contentBytes.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfCodePage.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfCodePage.cs new file mode 100644 index 0000000..408714c --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfCodePage.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfCodePage.cs,v 1.5 2008/05/16 19:30:50 psoares33 Exp $ + * + * + * Copyright 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfCodePage class allows different code pages to be used in the rtf document. + * Currently always ansi / ansicpg1252 + * + * Version: $Id: RtfCodePage.cs,v 1.5 2008/05/16 19:30:50 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfCodePage : RtfElement, IRtfExtendedElement { + /** + * Constant for ansi encoded rtf documents + */ + private static byte[] ANSI = DocWriter.GetISOBytes("\\ansi"); + /** + * Constant for the ansi codepage + */ + private static byte[] ANSI_CODEPAGE = DocWriter.GetISOBytes("\\ansicpg"); + + /** + * Construct an RtfCodePage + * + * @param doc The RtfDocument this RtfCodePage belongs to + */ + public RtfCodePage(RtfDocument doc) : base(doc) { + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Writes the selected codepage + */ + public virtual void WriteDefinition(Stream result) { + result.Write(ANSI, 0, ANSI.Length); + result.Write(ANSI_CODEPAGE, 0, ANSI_CODEPAGE.Length); + byte[] t = IntToByteArray(1252); + result.Write(t, 0, t.Length); + result.WriteByte((byte)'\n'); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfDocument.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfDocument.cs new file mode 100644 index 0000000..efee2ec --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfDocument.cs @@ -0,0 +1,347 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document.output; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.graphic; +/* + * $Id: RtfDocument.cs,v 1.12 2008/05/16 19:30:50 psoares33 Exp $ + * + * + * Copyright 2003, 2004, 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfDocument stores all document related data and also the main data stream. + * INTERNAL CLASS - NOT TO BE USED DIRECTLY + * + * Version: $Id: RtfDocument.cs,v 1.12 2008/05/16 19:30:50 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Todd Bush (Todd.Bush@canopysystems.com) [Tab support] + */ + public class RtfDocument : RtfElement { + /** + * Stores the actual document data + */ + private IRtfDataCache data = null; + /** + * The RtfMapper to use in this RtfDocument + */ + private RtfMapper mapper = null; + /** + * The RtfDocumentHeader that handles all document header methods + */ + private RtfDocumentHeader documentHeader = null; + /** + * Stores integers that have been generated as unique random numbers + */ + private ArrayList previousRandomInts = null; + /** + * Whether to automatically generate TOC entries for Chapters and Sections. Defaults to false + */ + private bool autogenerateTOCEntries = false; + /** + * The RtfDocumentSettings for this RtfDocument. + */ + private RtfDocumentSettings documentSettings = null; + + /** + * The last RtfBasicElement that was added directly to the RtfDocument. + */ + private IRtfBasicElement lastElementWritten = null; + + /** + * Constant for the Rtf document start + */ + private static byte[] RTF_DOCUMENT = DocWriter.GetISOBytes("\\rtf1"); + private static byte[] FSC_LINE = DocWriter.GetISOBytes("\\line "); + private static byte[] FSC_PAR = DocWriter.GetISOBytes("\\par "); + private static byte[] FSC_TAB = DocWriter.GetISOBytes("\\tab "); + private static byte[] FSC_PAGE_PAR = DocWriter.GetISOBytes("\\page\\par "); + private static byte[] FSC_NEWPAGE = DocWriter.GetISOBytes("$newpage$"); + private static byte[] FSC_BACKSLASH = DocWriter.GetISOBytes("\\"); + private static byte[] FSC_HEX_PREFIX = DocWriter.GetISOBytes("\\\'"); + private static byte[] FSC_UNI_PREFIX = DocWriter.GetISOBytes("\\u"); + + private static Random random = new Random(); + + /** + * The default constructor for a RtfDocument + */ + public RtfDocument() : base(null) { + this.data = new RtfMemoryCache(); + this.mapper = new RtfMapper(this); + this.documentHeader = new RtfDocumentHeader(this); + this.documentHeader.Init(); + this.previousRandomInts = new ArrayList(); + this.documentSettings = new RtfDocumentSettings(this); + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Writes the document + * + * @param outs The Stream to write the RTF document to. + */ + public void WriteDocument(Stream outs) { + try { + outs.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + outs.Write(RtfDocument.RTF_DOCUMENT, 0, RtfDocument.RTF_DOCUMENT.Length); + this.documentHeader.WriteContent(outs); + this.data.WriteTo(outs); + outs.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } catch (IOException) { + } + } + + /** + * Opens the RtfDocument and initialises the data cache. If the data cache is + * set to CACHE_DISK, but the cache cannot be initialised then the memory cache + * is used. + */ + public void Open() { + try { + switch (this.documentSettings.GetDataCacheStyle()) { + case RtfDataCache.CACHE_MEMORY_EFFICIENT: + this.data = new RtfEfficientMemoryCache(); + break; + case RtfDataCache.CACHE_MEMORY: + this.data = new RtfMemoryCache(); + break; + case RtfDataCache.CACHE_DISK: + this.data = new RtfDiskCache(); + break; + default: + throw new ArgumentException("unknown"); + } + } catch (IOException) { + this.data = new RtfMemoryCache(); + } + } + + /** + * Adds an element to the rtf document + * + * @param element The element to add + */ + public void Add(IRtfBasicElement element) { + try { + if (element is RtfInfoElement) { + this.documentHeader.AddInfoElement((RtfInfoElement) element); + } else { + if (element is RtfImage) { + ((RtfImage) element).SetTopLevelElement(true); + } + element.WriteContent(this.data.GetOutputStream()); + this.lastElementWritten = element; + } + } catch (IOException) { + } + } + + /** + * Gets the RtfMapper object of this RtfDocument + * + * @return The RtfMapper + */ + public RtfMapper GetMapper() { + return this.mapper; + } + + /** + * Generates a random integer that is unique with respect to the document. + * + * @return A random int + */ + public int GetRandomInt() { + int newInt; + do { + lock (random) { + newInt = random.Next(int.MaxValue - 2); + } + } while (this.previousRandomInts.Contains(newInt)); + this.previousRandomInts.Add(newInt); + return newInt; + } + + /** + * Gets the RtfDocumentHeader of this RtfDocument + * + * @return The RtfDocumentHeader of this RtfDocument + */ + public RtfDocumentHeader GetDocumentHeader() { + return this.documentHeader; + } + + /** + * Writes the given string to the given {@link Stream} encoding the string characters. + * + * @param outp destination Stream + * @param str string to write + * @param useHex if true hex encoding characters is preferred to unicode encoding if possible + * @param softLineBreaks if true return characters are written as soft line breaks + * + * @throws IOException + */ + public void FilterSpecialChar(Stream outp, String str, bool useHex, bool softLineBreaks) { + if (outp == null) { + throw new ArgumentException("null OutpuStream"); + } + + bool alwaysUseUniCode = this.documentSettings.IsAlwaysUseUnicode(); + if (str == null) { + return; + } + int len = str.Length; + if (len == 0) { + return; + } + byte[] t = null; + for (int k = 0; k < len; k++) { + char c = str[k]; + if (c < 0x20) { + //allow return and tab only + if (c == '\n') { + outp.Write(t = softLineBreaks ? FSC_LINE : FSC_PAR, 0, t.Length); + } else if (c == '\t') { + outp.Write(FSC_TAB, 0, FSC_TAB.Length); + } else { + outp.WriteByte((byte)'?'); + } + } else if ((c == '\\') || (c == '{') || (c == '}')) { + //escape + outp.Write(FSC_BACKSLASH, 0, FSC_BACKSLASH.Length); + outp.WriteByte((byte)c); + } else if ((c == '$') && (len-k >= FSC_NEWPAGE.Length) && SubMatch(str, k, FSC_NEWPAGE)) { + outp.Write(FSC_PAGE_PAR, 0, FSC_PAGE_PAR.Length); + k += FSC_NEWPAGE.Length-1; + } else { + if ((c > 0xff) || ((c > 'z') && alwaysUseUniCode)) { + if (useHex && (c <= 0xff)) { + //encode as 2 char hex string + outp.Write(FSC_HEX_PREFIX, 0, FSC_HEX_PREFIX.Length); + outp.Write(RtfImage.byte2charLUT, c*2, 2); + } else { + //encode as decimal, signed short value + outp.Write(FSC_UNI_PREFIX, 0, FSC_UNI_PREFIX.Length); + String s = ((short)c).ToString(); + for (int x = 0; x < s.Length; x++) { + outp.WriteByte((byte)s[x]); + } + outp.WriteByte((byte)'?'); + } + } else { + outp.WriteByte((byte)c); + } + } + } + } + /** + * Returns true if m.length characters in str, starting at offset soff + * match the bytes in the given array m. + * + * @param str the string to search for a match + * @param soff the starting offset in str + * @param m the array to match + * @return true if there is match + */ + private static bool SubMatch(String str, int soff, byte[] m) + { + for (int k = 0; k < m.Length; k++) { + if (str[soff++] != (char)m[k]) { + return false; + } + } + return true; + } + + /** + * Whether to automagically generate table of contents entries when + * adding Chapters or Sections. + * + * @param autogenerate Whether to automatically generate TOC entries + */ + public void SetAutogenerateTOCEntries(bool autogenerate) { + this.autogenerateTOCEntries = autogenerate; + } + + /** + * Get whether to autmatically generate table of contents entries + * + * @return Wheter to automatically generate TOC entries + */ + public bool GetAutogenerateTOCEntries() { + return this.autogenerateTOCEntries; + } + + /** + * Gets the RtfDocumentSettings that specify how the rtf document is generated. + * + * @return The current RtfDocumentSettings. + */ + public RtfDocumentSettings GetDocumentSettings() { + return this.documentSettings; + } + /** + * Gets the last RtfBasicElement that was directly added to the RtfDocument. + * + * @return The last RtfBasicElement that was directly added to the RtfDocument. + */ + public IRtfBasicElement GetLastElementWritten() { + return this.lastElementWritten; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfDocumentHeader.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfDocumentHeader.cs new file mode 100644 index 0000000..d00b788 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfDocumentHeader.cs @@ -0,0 +1,321 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document.output; +using iTextSharp.text.rtf.list; +using ST = iTextSharp.text.rtf.style; +using iTextSharp.text.rtf.style; +using HF = iTextSharp.text.rtf.headerfooter; +using iTextSharp.text.rtf.headerfooter; +//using iTextSharp.text.rtf; +/* + * $Id: RtfDocumentHeader.cs,v 1.11 2008/05/16 19:30:51 psoares33 Exp $ + * + * + * Copyright 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfDocumentHeader contains all classes required for the generation of + * the document header area. + * + * @version $Id: RtfDocumentHeader.cs,v 1.11 2008/05/16 19:30:51 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Thomas Bickel (tmb99@inode.at) + */ + public class RtfDocumentHeader : RtfElement { + /** + * Constant for the title page + */ + private static byte[] TITLE_PAGE = DocWriter.GetISOBytes("\\titlepg"); + /** + * Constant for facing pages + */ + private static byte[] FACING_PAGES = DocWriter.GetISOBytes("\\facingp"); + + /** + * The code page to use + */ + private RtfCodePage codePage = null; + /** + * Stores all the colors used in the document + */ + private RtfColorList colorList = null; + /** + * Stores all the fonts used in the document + */ + private RtfFontList fontList = null; + /** + * Manages List tables + */ + private RtfListTable listTable = null; + /** + * Stores all paragraph styles used in the document. + */ + private RtfStylesheetList stylesheetList = null; + /** + * Generator string in document + */ + private RtfGenerator generator = null; + /** + * The information group with author/subject/keywords/title/producer/creationdate data + */ + private RtfInfoGroup infoGroup = null; + /** + * The protection settings + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private RtfProtectionSetting protectionSetting = null; + /** + * The page settings + */ + private RtfPageSetting pageSetting = null; + /** + * The current RtfHeaderFooterGroup for the header + */ + private HeaderFooter header = null; + /** + * The current RtfHeaderFooterGroup for the footer + */ + private HeaderFooter footer = null; + + /** + * Constructs a RtfDocumentHeader for a RtfDocument + * + * @param doc The RtfDocument this RtfDocumentHeader belongs to + */ + protected internal RtfDocumentHeader(RtfDocument doc) : base(doc) { + } + + /** + * Initialises the RtfDocumentHeader. + */ + protected internal void Init() { + this.codePage = new RtfCodePage(this.document); + this.colorList = new RtfColorList(this.document); + this.fontList = new RtfFontList(this.document); + this.listTable = new RtfListTable(this.document); + this.stylesheetList = new RtfStylesheetList(this.document); + this.infoGroup = new RtfInfoGroup(this.document); + this.protectionSetting = new RtfProtectionSetting(this.document); + this.pageSetting = new RtfPageSetting(this.document); + this.header = new RtfHeaderFooterGroup(this.document, HF.RtfHeaderFooter.TYPE_HEADER); + this.footer = new RtfHeaderFooterGroup(this.document, HF.RtfHeaderFooter.TYPE_FOOTER); + this.generator = new RtfGenerator(this.document); + } + + /** + * Write the contents of the document header area. + */ + public override void WriteContent(Stream result) { + try { + // This is so that all colour, font and similar information is processed once, before + // the header section is written. + WriteSectionDefinition(new RtfNilOutputStream()); + + this.codePage.WriteDefinition(result); + this.fontList.WriteDefinition(result); + this.colorList.WriteDefinition(result); + this.stylesheetList.WriteDefinition(result); + this.listTable.WriteDefinition(result); + this.generator.WriteContent(result); + this.infoGroup.WriteContent(result); + this.protectionSetting.WriteDefinition(result); + this.pageSetting.WriteDefinition(result); + + WriteSectionDefinition(result); + } catch (IOException) { + } + } + + /** + * Writes the section definition data + * @param result + */ + public void WriteSectionDefinition(Stream result) { + try { + RtfHeaderFooterGroup header = ConvertHeaderFooter(this.header, HF.RtfHeaderFooter.TYPE_HEADER); + RtfHeaderFooterGroup footer = ConvertHeaderFooter(this.footer, HF.RtfHeaderFooter.TYPE_FOOTER); + if (header.HasTitlePage() || footer.HasTitlePage()) { + result.Write(TITLE_PAGE, 0, TITLE_PAGE.Length); + header.SetHasTitlePage(); + footer.SetHasTitlePage(); + } + if (header.HasFacingPages() || footer.HasFacingPages()) { + result.Write(FACING_PAGES, 0, FACING_PAGES.Length); + header.SetHasFacingPages(); + footer.SetHasFacingPages(); + } + footer.WriteContent(result); + header.WriteContent(result); + pageSetting.WriteSectionDefinition(result); + } catch (IOException) { + } + } + + /** + * Gets the number of the specified RtfFont + * + * @param font The RtfFont for which to get the number + * @return The number of the font + */ + public int GetFontNumber(ST.RtfFont font) { + return this.fontList.GetFontNumber(font); + } + + /** + * Gets the number of the specified RtfColor + * + * @param color The RtfColor for which to get the number + * @return The number of the color + */ + public int GetColorNumber(ST.RtfColor color) { + return this.colorList.GetColorNumber(color); + } + + /** + * Gets the number of the specified RtfList + * + * @param list The RtfList for which to get the number + * @return The number of the list + */ + public int GetListNumber(RtfList list) { + return this.listTable.GetListNumber(list); + } + + /** + * Gets the RtfParagraphStyle with the given style name. + * + * @param styleName The style name of the RtfParagraphStyle to get. + * @return The RtfParagraphStyle with the given style name or null. + */ + public RtfParagraphStyle GetRtfParagraphStyle(String styleName) { + return this.stylesheetList.GetRtfParagraphStyle(styleName); + } + + /** + * Removes a RtfList from the list table + * + * @param list The RtfList to remove + */ + public void FreeListNumber(RtfList list) { + this.listTable.FreeListNumber(list); + } + + /** + * Gets the RtfPageSetting object of this RtfDocument + * + * @return The RtfPageSetting object + */ + public RtfPageSetting GetPageSetting() { + return this.pageSetting; + } + + /** + * Adds an RtfInfoElement to the list of RtfInfoElements + * + * @param rtfInfoElement The RtfInfoElement to add + */ + public void AddInfoElement(RtfInfoElement rtfInfoElement) { + this.infoGroup.Add(rtfInfoElement); + } + + /** + * Sets the current header to use + * + * @param header The HeaderFooter to use as header + */ + public void SetHeader(HeaderFooter header) { + this.header = header; + } + + /** + * Sets the current footer to use + * + * @param footer The HeaderFooter to use as footer + */ + public void SetFooter(HeaderFooter footer) { + this.footer = footer; + } + + /** + * Registers the RtfParagraphStyle for further use in the document. + * + * @param rtfParagraphStyle The RtfParagraphStyle to register. + */ + public void RegisterParagraphStyle(RtfParagraphStyle rtfParagraphStyle) { + this.stylesheetList.RegisterParagraphStyle(rtfParagraphStyle); + } + + /** + * Converts a HeaderFooter into a RtfHeaderFooterGroup. Depending on which class + * the HeaderFooter is, the correct RtfHeaderFooterGroup is created. + * + * @param hf The HeaderFooter to convert. + * @param type Whether the conversion is being done on a footer or header + * @return The converted RtfHeaderFooterGroup. + * @see com.lowagie.text.rtf.headerfooter.RtfHeaderFooter + * @see com.lowagie.text.rtf.headerfooter.RtfHeaderFooterGroup + */ + private RtfHeaderFooterGroup ConvertHeaderFooter(HeaderFooter hf, int type) { + if (hf != null) { + if (hf is RtfHeaderFooterGroup) { + return new RtfHeaderFooterGroup(this.document, (RtfHeaderFooterGroup) hf, type); + } else if (hf is RtfHeaderFooter) { + return new RtfHeaderFooterGroup(this.document, (RtfHeaderFooter) hf, type); + } else { + return new RtfHeaderFooterGroup(this.document, hf, type); + } + } else { + return new RtfHeaderFooterGroup(this.document, type); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfDocumentSettings.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfDocumentSettings.cs new file mode 100644 index 0000000..657e307 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfDocumentSettings.cs @@ -0,0 +1,566 @@ +using System; +using iTextSharp.text.rtf.style; +using iTextSharp.text.rtf.document.output; + +/* + * $Id: RtfDocumentSettings.cs,v 1.10 2008/05/16 19:30:51 psoares33 Exp $ + * + * + * Copyright 2003, 2004, 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfDocumentSettings contains output specific settings. These settings modify + * how the actual document is then generated and some settings may mean that some + * RTF readers can't read the document or render it wrongly. + * + * @version $Id: RtfDocumentSettings.cs,v 1.10 2008/05/16 19:30:51 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Thomas Bickel (tmb99@inode.at) + */ + public class RtfDocumentSettings { + + /** + * The RtfDocument this RtfDocumentSettings belongs to. + */ + private RtfDocument document = null; + /** + * Whether to also output the table row definition after the cell content. + */ + private bool outputTableRowDefinitionAfter = true; + /** + * Whether to output the line breaks that make the rtf document source more readable. + */ + private bool outputDebugLineBreaks = true; + /** + * Whether to always generate soft linebreaks for \n in Chunks. + */ + private bool alwaysGenerateSoftLinebreaks = false; + /** + * Whether to always translate characters past 'z' into unicode representations. + */ + private bool alwaysUseUnicode = true; + /** + * How to cache the document during generation. Defaults to RtfDataCache.CACHE_MEMORY; + */ + private int dataCacheStyle = RtfDataCache.CACHE_MEMORY; + /** + * Whether to write image scaling information. This is required for Word 2000, 97 and Word for Mac + */ + private bool writeImageScalingInformation = false; + /** + * Whether images should be written in order to mimick the PDF output. + */ + private bool imagePDFConformance = true; + /** + * Document protection level + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private int protectionLevel = RtfProtection.LEVEL_NONE; + /** + * Document protection level password hash. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private String protectionHash = null; + /** + * Document read password hash + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + //private String writereservhash = null; //\*\writereservhash - not implemented + /** + * Document recommended to be opened in read only mode. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private bool readOnlyRecommended = false; + /** + * Images are written as binary data and not hex encoded. + * @since 2.1.1 + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + private bool imageWrittenAsBinary = true; + + /** + * Constructs a new RtfDocumentSettings object. + * + * @param document The RtfDocument this RtfDocumentSettings belong to. + */ + public RtfDocumentSettings(RtfDocument document) { + this.document = document; + } + + /** + * Gets whether to output the line breaks for increased rtf document readability. + * + * @return Whether to output line breaks. + */ + public bool IsOutputDebugLineBreaks() { + return outputDebugLineBreaks; + } + + /** + * Sets whether to output the line breaks for increased rtf document readability. + * Some line breaks may be added where the rtf specification demands it. + * + * @param outputDebugLineBreaks The outputDebugLineBreaks to set. + */ + public void SetOutputDebugLineBreaks(bool outputDebugLineBreaks) { + this.outputDebugLineBreaks = outputDebugLineBreaks; + } + + /** + * Gets whether the table row definition should also be written after the cell content. + * + * @return Returns the outputTableRowDefinitionAfter. + */ + public bool IsOutputTableRowDefinitionAfter() { + return outputTableRowDefinitionAfter; + } + + /** + * Sets whether the table row definition should also be written after the cell content. + * This is recommended to be set to true if you need Word2000 compatiblity and + * false if the document should be opened in OpenOffice.org Writer. + * + * @param outputTableRowDefinitionAfter The outputTableRowDefinitionAfter to set. + */ + public void SetOutputTableRowDefinitionAfter( + bool outputTableRowDefinitionAfter) { + this.outputTableRowDefinitionAfter = outputTableRowDefinitionAfter; + } + + /** + * Gets whether all linebreaks inside Chunks are generated as soft linebreaks. + * + * @return True if soft linebreaks are generated, false for hard linebreaks. + */ + public bool IsAlwaysGenerateSoftLinebreaks() { + return this.alwaysGenerateSoftLinebreaks; + } + + /** + * Sets whether to always generate soft linebreaks. + * + * @param alwaysGenerateSoftLinebreaks Whether to always generate soft linebreaks. + */ + public void SetAlwaysGenerateSoftLinebreaks(bool alwaysGenerateSoftLinebreaks) { + this.alwaysGenerateSoftLinebreaks = alwaysGenerateSoftLinebreaks; + } + + /** + * Gets whether all characters bigger than 'z' are represented as unicode. + * + * @return True if unicode representation is used, false otherwise. + */ + public bool IsAlwaysUseUnicode() { + return this.alwaysUseUnicode; + } + + /** + * Sets whether to represent all characters bigger than 'z' as unicode. + * + * @param alwaysUseUnicode True to use unicode representation, false otherwise. + */ + public void SetAlwaysUseUnicode(bool alwaysUseUnicode) { + this.alwaysUseUnicode = alwaysUseUnicode; + } + + /** + * Registers the RtfParagraphStyle for further use in the document. This does not need to be + * done for the default styles in the RtfParagraphStyle object. Those are added automatically. + * + * @param rtfParagraphStyle The RtfParagraphStyle to register. + */ + public void RegisterParagraphStyle(RtfParagraphStyle rtfParagraphStyle) { + this.document.GetDocumentHeader().RegisterParagraphStyle(rtfParagraphStyle); + } + + /** + * Sets the data cache style. This controls where the document is cached during + * generation. Two cache styles are supported: + *
        + *
      • RtfDataCache.CACHE_MEMORY: The document is cached in memory. This is fast, + * but places a limit on how big the document can get before causing + * OutOfMemoryExceptions.
      • + *
      • RtfDataCache.CACHE_DISK: The document is cached on disk. This is slower + * than the CACHE_MEMORY setting, but the document size is now only constrained + * by the amount of free disk space.
      • + *
      + * + * @param dataCacheStyle The data cache style to set. Valid constants can be found + * in RtfDataCache. + * @see com.lowagie.text.rtf.document.output.output.RtfDataCache. + */ + public void SetDataCacheStyle(int dataCacheStyle) { + switch (dataCacheStyle) { + case RtfDataCache.CACHE_MEMORY_EFFICIENT: + this.dataCacheStyle = RtfDataCache.CACHE_MEMORY_EFFICIENT; + break; + case RtfDataCache.CACHE_DISK: + this.dataCacheStyle = RtfDataCache.CACHE_DISK; + break; + default: + //case RtfDataCache.CACHE_MEMORY: + this.dataCacheStyle = RtfDataCache.CACHE_MEMORY; + break; + } + } + + /** + * Gets the current data cache style. + * + * @return The current data cache style. + */ + public int GetDataCacheStyle() { + return this.dataCacheStyle; + } + + /** + * Gets the current setting on image PDF conformance. + * + * @return The current image PDF conformance. + */ + public bool IsImagePDFConformance() { + return this.imagePDFConformance; + } + + + /** + * Sets the image PDF conformance setting. By default images will be added + * as if they were displayed with 72dpi. Set this to false + * if images should be generated with the Word default DPI setting. + * + * @param imagePDFConformance True if PDF equivalence is desired, false + * for the default Word display. + */ + public void SetImagePDFConformance(bool imagePDFConformance) { + this.imagePDFConformance = imagePDFConformance; + } + + + /** + * Gets whether to write scaling information for images. + * + * @return Whether to write scaling information for images. + */ + public bool IsWriteImageScalingInformation() { + return this.writeImageScalingInformation; + } + + + /** + * Sets whether image scaling information should be written. This needs to be set to true + * MS Word 2000, MS Word 97 and Word for Mac. + * + * @param writeImageScalingInformation Whether to write image scaling information. + */ + public void SetWriteImageScalingInformation(bool writeImageScalingInformation) { + this.writeImageScalingInformation = writeImageScalingInformation; + } + + /** + * Set the options required for RTF documents to display correctly in MS Word 2000 + * and MS Word 97. + * Sets outputTableRowDefinitionAfter = true and writeImageScalingInformation = true. + */ + public void SetOptionsForMSWord2000And97() { + this.SetOutputTableRowDefinitionAfter(true); + this.SetWriteImageScalingInformation(true); + } + + /** + * Set the options required for RTF documents to display correctly in MS Word for Mac. + * Sets writeImageScalingInformation = true. + */ + public void SetOptionsForMSWordForMac() { + this.SetWriteImageScalingInformation(true); + } + + /** + * Set the options required for RTF documents to display correctly in MS Word XP (2002). + * Sets writeImageScalingInformation = false. + */ + public void SetOptionsForMSWordXP() { + this.SetWriteImageScalingInformation(false); + } + + /** + * Set the options required for RTF documents to display correctly in OpenOffice.Org + * Writer. + * Sets outputTableRowDefinitionAfter = false. + */ + public void SetOptionsForOpenOfficeOrg() { + this.SetOutputTableRowDefinitionAfter(false); + } + + /** + * @param level Document protecton level + * @param pwd Document password - clear text + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public bool SetProtection(int level, String pwd) { + bool result = false; + if (this.protectionHash == null) { + if (!SetProtectionLevel(level)) { + result = false; + } + else + { + protectionHash = RtfProtection.GenerateHash(pwd); + result = true; + } + } + else { + if (this.protectionHash.Equals(RtfProtection.GenerateHash(pwd))) { + if (!SetProtectionLevel(level)) { + result = false; + } + else + { + protectionHash = RtfProtection.GenerateHash(pwd); + result = true; + } + } + } + return result; + } + + /** + * @param pwd Document password - clear text + * @return true if document unprotected, false if protection is not removed. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public bool UnprotectDocument(String pwd) { + bool result = false; + if (this.protectionHash.Equals(RtfProtection.GenerateHash(pwd))) { + this.protectionLevel = RtfProtection.LEVEL_NONE; + this.protectionHash = null; + result = true; + } + return result; + } + + /** + * @param level Document protection level + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public bool SetProtectionLevel(int level) { + bool result = false; + switch (level) { + case RtfProtection.LEVEL_NONE: + if (this.protectionHash == null) { + break; + } + goto case RtfProtection.LEVEL_ANNOTPROT; + case RtfProtection.LEVEL_ANNOTPROT: + case RtfProtection.LEVEL_FORMPROT: + case RtfProtection.LEVEL_REVPROT: + case RtfProtection.LEVEL_READPROT: + this.protectionLevel = level; + result = true; + break; + } + return result; + } + + /** + * This function is not intended for general use. Please see 'public bool SetProtection(int level, String pwd)' + * @param pwd Password HASH to set the document password hash to. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public void SetPasswordHash(String pwd) { + if (pwd != null && pwd.Length != 8) return; + this.protectionHash = pwd; + } + + /** + * Converts protection level from internal bitmap value to protlevel output value + * @return
      +        * 0 = Revision protection
      +        * 1 = Annotation/Comment protection
      +        * 2 = Form protection
      +        * 3 = Read only protection
      +        * 
      + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private int ConvertProtectionLevel() { + int level = 0; + switch (this.protectionLevel) { + case RtfProtection.LEVEL_NONE: + break; + case RtfProtection.LEVEL_REVPROT: + level = 0; + break; + case RtfProtection.LEVEL_ANNOTPROT: + level = 1; + break; + case RtfProtection.LEVEL_FORMPROT: + level = 2; + break; + case RtfProtection.LEVEL_READPROT: + level = 3; + break; + } + return level; + + } + + /** + * @return RTF document protection level + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public int GetProtectionLevelRaw() { + return this.protectionLevel; + } + + /** + * @return RTF document protection level + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public int GetProtectionLevel() { + return ConvertProtectionLevel(); + } + + /** + * @return RTF document protection level as a byte array (byte[]) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public byte[] GetProtectionLevelBytes() { + return DocWriter.GetISOBytes(ConvertProtectionLevel().ToString()); + } + + /** + * @param oldPwd Old password - clear text + * @param newPwd New password - clear text + * @return true if password set, false if password not set + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public bool SetNewPassword(String oldPwd, String newPwd) { + bool result = false; + if (this.protectionHash.Equals(RtfProtection.GenerateHash(oldPwd))) { + this.protectionHash = RtfProtection.GenerateHash(newPwd); + result = true; + } + return result; + } + + /** + * Set the RTF flag that recommends the document be opened in read only mode. + * @param value true if the flag is to be set, false if it is NOT to be set + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public void SetReadOnlyRecommended(bool value) { + this.readOnlyRecommended = value; + } + + /** + * Get the RTF flag that recommends if the the document should be opened in read only mode. + * @return true if flag is set, false if it is not set + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public bool GetReadOnlyRecommended() { + return this.readOnlyRecommended; + } + + /** + * Determine if document has protection enabled. + * @return true if protection is enabled, false if it is not enabled + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public bool IsDocumentProtected() { + return !(this.protectionHash == null); + } + + /** + * Obtain the password has as a byte array. + * @return The bytes of the password hash as a byte array (byte[]) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public byte[] GetProtectionHashBytes() { + return DocWriter.GetISOBytes(this.protectionHash); + } + + /** + * Set whether images are written as binary data or are hex encoded. + * + * @param imageWrittenAsBinary True to write images as binary data, false for hex encoding. + * @since 2.1.1 + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public void SetImageWrittenAsBinary(bool imageWrittenAsBinary) { + this.imageWrittenAsBinary = imageWrittenAsBinary; + } + + /** + * Gets whether images are written as binary data or are hex encoded. Defaults to true. + * + * @since 2.1.1 + * @return True if images are written as binary data, false if hex encoded. + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public bool IsImageWrittenAsBinary() { + return this.imageWrittenAsBinary; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfGenerator.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfGenerator.cs new file mode 100644 index 0000000..a46f483 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfGenerator.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfGenerator.cs,v 1.3 2008/05/13 11:25:44 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + + +namespace iTextSharp.text.rtf.document { + /** + * The RtfGenerator creates the (\*\generator ...} element. + * + * @version $Id: RtfGenerator.cs,v 1.3 2008/05/13 11:25:44 psoares33 Exp $ + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfGenerator : RtfElement { + /** + * Generator group starting tag + */ + private static byte[] GENERATOR = DocWriter.GetISOBytes("\\*\\generator"); + + /** + * Constructs a RtfGenerator belonging to a RtfDocument + * + * @param doc The RtfDocument this RtfGenerator belongs to + */ + public RtfGenerator(RtfDocument doc) : base(doc) { + } + + + /** + * Writes the RTF generator group. + */ + public override void WriteContent(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(GENERATOR, 0, GENERATOR.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + byte[] t; + result.Write(t = DocWriter.GetISOBytes(Document.Version), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + } +} diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfInfoElement.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfInfoElement.cs new file mode 100644 index 0000000..242fc49 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfInfoElement.cs @@ -0,0 +1,168 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfInfoElement.cs,v 1.6 2008/05/16 19:30:51 psoares33 Exp $ + * + * + * Copyright 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * Stores one information group element. Valid elements are + * author, title, subject, keywords, producer and creationdate. + * + * @version $Id: RtfInfoElement.cs,v 1.6 2008/05/16 19:30:51 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Thomas Bickel (tmb99@inode.at) + */ + public class RtfInfoElement : RtfElement { + + /** + * Constant for the author element + */ + private static byte[] INFO_AUTHOR = DocWriter.GetISOBytes("\\author"); + /** + * Constant for the subject element + */ + private static byte[] INFO_SUBJECT = DocWriter.GetISOBytes("\\subject"); + /** + * Constant for the keywords element + */ + private static byte[] INFO_KEYWORDS = DocWriter.GetISOBytes("\\keywords"); + /** + * Constant for the title element + */ + private static byte[] INFO_TITLE = DocWriter.GetISOBytes("\\title"); + /** + * Constant for the producer element + */ + private static byte[] INFO_PRODUCER = DocWriter.GetISOBytes("\\operator"); + /** + * Constant for the creationdate element + */ + private static byte[] INFO_CREATION_DATE = DocWriter.GetISOBytes("\\creationdate"); + + /** + * The type of this RtfInfoElement. The values from Element.INFO_ELEMENT_NAME are used. + */ + private int infoType = -1; + /** + * The content of this RtfInfoElement + */ + private String content = ""; + + /** + * Constructs a RtfInfoElement based on the given Meta object + * + * @param doc The RtfDocument this RtfInfoElement belongs to + * @param meta The Meta object this RtfInfoElement is based on + */ + public RtfInfoElement(RtfDocument doc, Meta meta) : base(doc) { + infoType = meta.Type; + content = meta.Content; + } + + /** + * Writes the content of one RTF information element. + */ + public override void WriteContent(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + switch (infoType) { + case Element.AUTHOR: + result.Write(INFO_AUTHOR, 0, INFO_AUTHOR.Length); + break; + case Element.SUBJECT: + result.Write(INFO_SUBJECT, 0, INFO_SUBJECT.Length); + break; + case Element.KEYWORDS: + result.Write(INFO_KEYWORDS, 0, INFO_KEYWORDS.Length); + break; + case Element.TITLE: + result.Write(INFO_TITLE, 0, INFO_TITLE.Length); + break; + case Element.PRODUCER: + result.Write(INFO_PRODUCER, 0, INFO_PRODUCER.Length); + break; + case Element.CREATIONDATE: + result.Write(INFO_CREATION_DATE, 0, INFO_CREATION_DATE.Length); + break; + default: + result.Write(INFO_AUTHOR, 0, INFO_AUTHOR.Length); + break; + } + result.Write(DELIMITER, 0, DELIMITER.Length); + byte[] t; + if (infoType == Element.CREATIONDATE) { + t = DocWriter.GetISOBytes(ConvertDate(content)); + result.Write(t, 0, t.Length); + } else { + document.FilterSpecialChar(result, content, false, false); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + + /** + * Converts a date from the format used by iText to the format required by + * rtf.
      iText: EEE MMM dd HH:mm:ss zzz yyyy - rtf: \\'yr'yyyy\\'mo'MM\\'dy'dd\\'hr'HH\\'min'mm\\'sec'ss + * + * @param date The date formated by iText + * @return The date formated for rtf + */ + private String ConvertDate(String date) { + DateTime d; + try { + d = DateTime.Parse(date); + } catch { + d = DateTime.Now; + } + return d.ToString("'\\\\yr'yyyy'\\\\mo'MM'\\\\dy'dd'\\\\hr'HH'\\\\min'mm'\\\\sec'ss"); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfInfoGroup.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfInfoGroup.cs new file mode 100644 index 0000000..7f41939 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfInfoGroup.cs @@ -0,0 +1,125 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfInfoGroup.cs,v 1.6 2008/05/16 19:30:51 psoares33 Exp $ + * + * + * Copyright 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfInfoGroup stores information group elements. + * + * @version $Id: RtfInfoGroup.cs,v 1.6 2008/05/16 19:30:51 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Thomas Bickel (tmb99@inode.at) + */ + public class RtfInfoGroup : RtfElement { + /** + * Information group starting tag + */ + private static byte[] INFO_GROUP = DocWriter.GetISOBytes("\\info"); + + /** + * Constant for the password element + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] INFO_PASSWORD = DocWriter.GetISOBytes("\\*\\password"); + + /** + * The RtfInfoElements that belong to this RtfInfoGroup + */ + ArrayList infoElements = null; + + /** + * Constructs a RtfInfoGroup belonging to a RtfDocument + * + * @param doc The RtfDocument this RtfInfoGroup belongs to + */ + public RtfInfoGroup(RtfDocument doc) : base(doc) { + infoElements = new ArrayList(); + } + + /** + * Adds an RtfInfoElement to the RtfInfoGroup + * + * @param infoElement The RtfInfoElement to add + */ + public void Add(RtfInfoElement infoElement) { + this.infoElements.Add(infoElement); + } + + /** + * Writes the RTF information group and its elements. + */ + public override void WriteContent(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(INFO_GROUP, 0, INFO_GROUP.Length); + for (int i = 0; i < infoElements.Count; i++) { + RtfInfoElement infoElement = (RtfInfoElement) infoElements[i]; + infoElement.WriteContent(result); + } + + // handle document protection + if (document.GetDocumentSettings().IsDocumentProtected()) { + byte[] t; + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(INFO_PASSWORD, 0, INFO_PASSWORD.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + result.Write(t = document.GetDocumentSettings().GetProtectionHashBytes(), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfPageSetting.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfPageSetting.cs new file mode 100644 index 0000000..b058bd1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfPageSetting.cs @@ -0,0 +1,425 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfPageSetting.cs,v 1.5 2008/05/16 19:30:51 psoares33 Exp $ + * + * + * Copyright 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfPageSetting stores the page size / page margins for a RtfDocument. + * INTERNAL CLASS - NOT TO BE USED DIRECTLY + * + * @version $Id: RtfPageSetting.cs,v 1.5 2008/05/16 19:30:51 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Thomas Bickel (tmb99@inode.at) + */ + public class RtfPageSetting : RtfElement, IRtfExtendedElement { + + /** + * Constant for the page height + */ + private static byte[] PAGE_WIDTH = DocWriter.GetISOBytes("\\paperw"); + /** + * Constant for the page width + */ + private static byte[] PAGE_HEIGHT = DocWriter.GetISOBytes("\\paperh"); + /** + * Constant for the left margin + */ + private static byte[] MARGIN_LEFT = DocWriter.GetISOBytes("\\margl"); + /** + * Constant for the right margin + */ + private static byte[] MARGIN_RIGHT = DocWriter.GetISOBytes("\\margr"); + /** + * Constant for the top margin + */ + private static byte[] MARGIN_TOP = DocWriter.GetISOBytes("\\margt"); + /** + * Constant for the bottom margin + */ + private static byte[] MARGIN_BOTTOM = DocWriter.GetISOBytes("\\margb"); + /** + * Constant for landscape + */ + private static byte[] LANDSCAPE = DocWriter.GetISOBytes("\\lndscpsxn"); + /** + * Constant for the section page width + */ + private static byte[] SECTION_PAGE_WIDTH = DocWriter.GetISOBytes("\\pgwsxn"); + /** + * Constant for the section page height + */ + private static byte[] SECTION_PAGE_HEIGHT = DocWriter.GetISOBytes("\\pghsxn"); + /** + * Constant for the section left margin + */ + private static byte[] SECTION_MARGIN_LEFT = DocWriter.GetISOBytes("\\marglsxn"); + /** + * Constant for the section right margin + */ + private static byte[] SECTION_MARGIN_RIGHT = DocWriter.GetISOBytes("\\margrsxn"); + /** + * Constant for the section top margin + */ + private static byte[] SECTION_MARGIN_TOP = DocWriter.GetISOBytes("\\margtsxn"); + /** + * Constant for the section bottom margin + */ + private static byte[] SECTION_MARGIN_BOTTOM = DocWriter.GetISOBytes("\\margbsxn"); + + /** + * The page width to use + */ + private int pageWidth = 11906; + /** + * The page height to use + */ + private int pageHeight = 16840; + /** + * The left margin to use + */ + private int marginLeft = 1800; + /** + * The right margin to use + */ + private int marginRight = 1800; + /** + * The top margin to use + */ + private int marginTop = 1440; + /** + * The bottom margin to use + */ + private int marginBottom = 1440; + /** + * Whether the page is portrait or landscape + */ + private bool landscape = false; + + /** + * Constructs a new RtfPageSetting object belonging to a RtfDocument. + * + * @param doc The RtfDocument this RtfPageSetting belongs to + */ + public RtfPageSetting(RtfDocument doc) : base(doc) { + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Writes the page size / page margin definition + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + result.Write(PAGE_WIDTH, 0, PAGE_WIDTH.Length); + result.Write(t = IntToByteArray(pageWidth), 0, t.Length); + result.Write(PAGE_HEIGHT, 0, PAGE_HEIGHT.Length); + result.Write(t = IntToByteArray(pageHeight), 0, t.Length); + result.Write(MARGIN_LEFT, 0, MARGIN_LEFT.Length); + result.Write(t = IntToByteArray(marginLeft), 0, t.Length); + result.Write(MARGIN_RIGHT, 0, MARGIN_RIGHT.Length); + result.Write(t = IntToByteArray(marginRight), 0, t.Length); + result.Write(MARGIN_TOP, 0, MARGIN_TOP.Length); + result.Write(t = IntToByteArray(marginTop), 0, t.Length); + result.Write(MARGIN_BOTTOM, 0, MARGIN_BOTTOM.Length); + result.Write(t = IntToByteArray(marginBottom), 0, t.Length); + result.WriteByte((byte)'\n'); + } + + /** + * Writes the definition part for a new section + * + * @return A byte array containing the definition for a new section + */ + public void WriteSectionDefinition(Stream result) { + byte[] t; + if (landscape) { + result.Write(LANDSCAPE, 0, LANDSCAPE.Length); + result.Write(SECTION_PAGE_WIDTH, 0, SECTION_PAGE_WIDTH.Length); + result.Write(t = IntToByteArray(pageWidth), 0, t.Length); + result.Write(SECTION_PAGE_HEIGHT, 0, SECTION_PAGE_HEIGHT.Length); + result.Write(t = IntToByteArray(pageHeight), 0, t.Length); + result.WriteByte((byte)'\n'); + } else { + result.Write(SECTION_PAGE_WIDTH, 0, SECTION_PAGE_WIDTH.Length); + result.Write(t = IntToByteArray(pageWidth), 0, t.Length); + result.Write(SECTION_PAGE_HEIGHT, 0, SECTION_PAGE_HEIGHT.Length); + result.Write(t = IntToByteArray(pageHeight), 0, t.Length); + result.WriteByte((byte)'\n'); + } + result.Write(SECTION_MARGIN_LEFT, 0, SECTION_MARGIN_LEFT.Length); + result.Write(t = IntToByteArray(marginLeft), 0, t.Length); + result.Write(SECTION_MARGIN_RIGHT, 0, SECTION_MARGIN_RIGHT.Length); + result.Write(t = IntToByteArray(marginRight), 0, t.Length); + result.Write(SECTION_MARGIN_TOP, 0, SECTION_MARGIN_TOP.Length); + result.Write(t = IntToByteArray(marginTop), 0, t.Length); + result.Write(SECTION_MARGIN_BOTTOM, 0, SECTION_MARGIN_BOTTOM.Length); + result.Write(t = IntToByteArray(marginBottom), 0, t.Length); + } + + /** + * Gets the bottom margin + * + * @return Returns the bottom margin + */ + public int GetMarginBottom() { + return marginBottom; + } + + /** + * Sets the bottom margin + * + * @param marginBottom The bottom margin to use + */ + public void SetMarginBottom(int marginBottom) { + this.marginBottom = marginBottom; + } + + /** + * Gets the left margin + * + * @return Returns the left margin + */ + public int GetMarginLeft() { + return marginLeft; + } + + /** + * Sets the left margin to use + * + * @param marginLeft The left margin to use + */ + public void SetMarginLeft(int marginLeft) { + this.marginLeft = marginLeft; + } + + /** + * Gets the right margin + * + * @return Returns the right margin + */ + public int GetMarginRight() { + return marginRight; + } + + /** + * Sets the right margin to use + * + * @param marginRight The right margin to use + */ + public void SetMarginRight(int marginRight) { + this.marginRight = marginRight; + } + + /** + * Gets the top margin + * + * @return Returns the top margin + */ + public int GetMarginTop() { + return marginTop; + } + + /** + * Sets the top margin to use + * + * @param marginTop The top margin to use + */ + public void SetMarginTop(int marginTop) { + this.marginTop = marginTop; + } + + /** + * Gets the page height + * + * @return Returns the page height + */ + public int GetPageHeight() { + return pageHeight; + } + + /** + * Sets the page height to use + * + * @param pageHeight The page height to use + */ + public void SetPageHeight(int pageHeight) { + this.pageHeight = pageHeight; + } + + /** + * Gets the page width + * + * @return Returns the page width + */ + public int GetPageWidth() { + return pageWidth; + } + + /** + * Sets the page width to use + * + * @param pageWidth The page width to use + */ + public void SetPageWidth(int pageWidth) { + this.pageWidth = pageWidth; + } + + /** + * Set the page size to use. This method will use guessFormat to try to guess the correct + * page format. If no format could be guessed, the sizes from the pageSize are used and + * the landscape setting is determined by comparing width and height; + * + * @param pageSize The pageSize to use + */ + public void SetPageSize(Rectangle pageSize) { + if (!GuessFormat(pageSize, false)) { + this.pageWidth = (int) (pageSize.Width * TWIPS_FACTOR); + this.pageHeight = (int) (pageSize.Height * TWIPS_FACTOR); + this.landscape = pageWidth > pageHeight; + } + } + + /** + * This method tries to fit the Rectangle pageSize to one of the predefined PageSize rectangles. + * If a match is found the pageWidth and pageHeight will be set according to values determined from files + * generated by MS Word2000 and OpenOffice 641. If no match is found the method will try to match the rotated + * Rectangle by calling itself with the parameter rotate set to true. + * + * @param pageSize the page size for which to guess the correct format + * @param rotate Whether we should try to rotate the size befor guessing the format + * @return True if the format was guessed, false/ otherwise + */ + private bool GuessFormat(Rectangle pageSize, bool rotate) { + if (rotate) { + pageSize = pageSize.Rotate(); + } + if (RectEquals(pageSize, PageSize.A3)) { + pageWidth = 16837; + pageHeight = 23811; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.A4)) { + pageWidth = 11907; + pageHeight = 16840; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.A5)) { + pageWidth = 8391; + pageHeight = 11907; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.A6)) { + pageWidth = 5959; + pageHeight = 8420; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.B4)) { + pageWidth = 14570; + pageHeight = 20636; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.B5)) { + pageWidth = 10319; + pageHeight = 14572; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.HALFLETTER)) { + pageWidth = 7927; + pageHeight = 12247; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.LETTER)) { + pageWidth = 12242; + pageHeight = 15842; + landscape = rotate; + return true; + } + if (RectEquals(pageSize, PageSize.LEGAL)) { + pageWidth = 12252; + pageHeight = 20163; + landscape = rotate; + return true; + } + if (!rotate && GuessFormat(pageSize, true)) { + int x = pageWidth; + pageWidth = pageHeight; + pageHeight = x; + return true; + } + return false; + } + + /** + * This method compares to Rectangles. They are considered equal if width and height are the same + * + * @param rect1 The first Rectangle to compare + * @param rect2 The second Rectangle to compare + * @return True if the Rectangles equal, false otherwise + */ + private static bool RectEquals(Rectangle rect1, Rectangle rect2) { + return (rect1.Width == rect2.Width) && (rect1.Height == rect2.Height); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfProtection.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfProtection.cs new file mode 100644 index 0000000..2e6e2bd --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfProtection.cs @@ -0,0 +1,273 @@ +using System; +/* + * $Id: RtfProtection.cs,v 1.2 2008/05/13 11:25:50 psoares33 Exp $ + * + * + * Copyright 2008 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * RtfProtection + *
      +    * See ECMA Specification for WordprocessingML documentProtection element.
      +    * 
      +    * Reference:
      +    * Standard ECMA-376 1st Edition / December 2006
      +    * Office Open XML File Formats
      +    * 
      + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public sealed class RtfProtection { + /** + * Default for protection level. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int LEVEL_NONE = 0x0000; + /** + * REVPROT + * Mutually exclusive + * This document is protected for revisions. The user can edit the document, + * but revision marking cannot be disabled. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int LEVEL_REVPROT = 0x0001; // protlevel0 + /** + * ANNNOTPROT + * Mutually exclusive + * This document is protected for comments (annotations). + * The user cannot edit the document but can insert comments (annotations). + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int LEVEL_ANNOTPROT = 0x0002; // protlevel1 + /** + * FORMPROT + * Mutually exclusive + * Document is protected for forms. + * see also \allprot (forms controlword) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int LEVEL_FORMPROT = 0x0004; // protlevel2 + /** + * READPROT + * Mutually exclusive but can be combined with ANNOTPROT for backward compatibility + * Document is protected for editing, except areas marked as exceptions by \protstart and\protend + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int LEVEL_READPROT = 0x0008; // protlevel3 + + + /** + * STYLELOCK + * + * The document contains styles and formatting restrictions. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int STYLELOCK = 0x0001; + /** + * STYLELOCKENFORCED + * + * The styles and formatting restrictions are being enforced. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int STYLELOCKENFORCED = 0x0002; + /** + * STYLELOCKBACKCOMP + * + * Style lockdown backward compatibility flag, indicating we emitted protection + * keywords to get documents with styles and formatting restrictions to behave + * in a reasonable way when opened by older versions. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int STYLELOCKBACKCOMP = 0x0004; + /** + * STYLELOCKBACKCOMP + * + * Allow AutoFormat to override styles and formatting restrictions. When style + * protection is on, the user cannot add direct formatting. This setting allows + * AutoFormat actions to apply direct formatting when needed. + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public const int AUTOFMTOVERRIDE = 0x0008; + + + /** + * initialCodeArray Table from ECMA-376 Specification + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static int[] initialCodeArray = { + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3 + }; + + /** + * encryptionMatrix Table from ECMA-376 Specification + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static int[][] encryptionMatrix = { + /* bit1 bit2 bit3 bit4 bit5 bit6 bit7 **bit8 is ignored** */ + /* char 1 */ new int[]{0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4}, + /* char 2 */ new int[]{0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC}, + /* char 3 */ new int[]{0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD}, + /* char 4 */ new int[]{0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C}, + /* char 5 */ new int[]{0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168}, + /* char 6 */ new int[]{0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10}, + /* char 7 */ new int[]{0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC}, + /* char 8 */ new int[]{0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0}, + /* char 9 */ new int[]{0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9}, + /* char 10 */ new int[]{0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A}, + /* char 11 */ new int[]{0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5}, + /* char 12 */ new int[]{0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40}, + /* char 13 */ new int[]{0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0}, + /* char 14 */ new int[]{0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF}, + /* char 15 */ new int[]{0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09} + }; + + /** + * generateHash generates the password hash from a clear text string. + * + * @param pwd Clear text string input + * @return hex encoded password hash + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.1.1 + */ + public static String GenerateHash(String pwd) { + String encryptedPwd="00000000"; + String password = pwd; + + // if there is no password or the length is 0, then skip this and return "00000000" as default + // otherwise process the password + if (password != null && password.Length > 0) { + int hi=0; + int lo=0; + + // Truncate the password to 15 characters. + if (password.Length > 15) { + password = password.Substring(0,15); + } + + // compute key's high-order word + // initialize to table value + hi = initialCodeArray[password.Length-1]; + + int fidx = 0; + int idxR = password.Length-1; + // process each character left to right. + // check each bit and if it is set, xor the hi word with + // the table entry for the position in password and bit position. + for (; fidx= 0; fidx--) { + int ch = password[fidx]; + lo = (((lo >> 14) & 0x001) | (( lo << 1) & 0x7fff)) ^ ch; + } + // finally incorporate the password length into the low word and use value from formula + lo = (((lo >> 14) & 0x001) | (( lo << 1) & 0x7fff)) ^ password.Length ^ 0xCE4B; + + // correct for little-endian - + // Java always uses big-endian. According to tests - RTF wants little-endian but is not documented + string s = lo.ToString("x8"); + encryptedPwd = s.Substring(6,2) + s.Substring(4,2); + s = hi.ToString("x8"); + encryptedPwd += s.Substring(6,2) + s.Substring(4,2); + } + return encryptedPwd; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/RtfProtectionSetting.cs b/iTechSharp/iTextSharp/text/rtf/document/RtfProtectionSetting.cs new file mode 100644 index 0000000..1d0d6b9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/RtfProtectionSetting.cs @@ -0,0 +1,182 @@ +using System; +using System.IO; +using iTextSharp.text.rtf; +using iTextSharp.text; +/* + * $Id: RtfProtectionSetting.cs,v 1.2 2008/05/13 11:25:50 psoares33 Exp $ + * + * + * Copyright 2008 by Howard Shank + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document { + + /** + * The RtfProtectionSetting handles document protection elements + * + * @version $Id: RtfProtectionSetting.cs,v 1.2 2008/05/13 11:25:50 psoares33 Exp $ + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.1.1 + */ + public class RtfProtectionSetting : RtfElement { + /** + * Constant for Form protection controlword + * Mutually exclusive + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#REVPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#ANNOTPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#READPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] FORMPROT = DocWriter.GetISOBytes("\\formprot"); + /** + * Constant for Revision protection controlword + * Mutually exclusive + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#FORMPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#ANNOTPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#READPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] REVPROT = DocWriter.GetISOBytes("\\revprot"); + /** + * Constant for Annotation/Comment protection controlword + * Mutually exclusive + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#FORMPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#REVPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#READPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] ANNOTPROT = DocWriter.GetISOBytes("\\annotprot"); + /** + * Constant for read only rotection controlword + * Mutually exclusive - exception, can be combined with ANNOTPROT + * for backwards compatibility + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#FORMPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#REVPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @see com.lowagie.text.rtf.document.RtfProtectionSetting#ANNOTPROT(com.lowagie.text.rtf.document.RtfProtectionSetting) + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] READPROT = DocWriter.GetISOBytes("\\readprot"); + + /** + * Constant for protlevel controlword + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] PROTLEVEL = DocWriter.GetISOBytes("\\protlevel"); + /** + * Constant for enforceprot controlword + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] ENFORCEPROT = DocWriter.GetISOBytes("\\enforceprot"); + + /** + * Constant for enforceprot controlword. + * Implemented in Microsoft Word 2007. + * + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + private static byte[] READONLYRECOMMENDED = DocWriter.GetISOBytes("\\readonlyrecommended"); + + /** + * Constructs a RtfProtectionSetting belonging to a RtfDocument + * + * @param doc The RtfDocument this RtfProtectionSetting belongs to + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public RtfProtectionSetting(RtfDocument doc) : base(doc) { + } + + /** + * Writes the RTF protection control words + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public override void WriteContent(Stream result) { + } + + /** + * Writes the RTF protection control words + * @since 2.1.1 + * @author Howard Shank (hgshank@yahoo.com) + */ + public virtual void WriteDefinition(Stream result) { + if (document.GetDocumentSettings().IsDocumentProtected()) { + switch (document.GetDocumentSettings().GetProtectionLevelRaw()) { + case RtfProtection.LEVEL_FORMPROT: + result.Write(FORMPROT, 0, FORMPROT.Length); + break; + case RtfProtection.LEVEL_ANNOTPROT: + result.Write(ANNOTPROT, 0, ANNOTPROT.Length); + break; + case RtfProtection.LEVEL_REVPROT: + result.Write(REVPROT, 0, REVPROT.Length); + break; + case RtfProtection.LEVEL_READPROT: + result.Write(ANNOTPROT, 0, ANNOTPROT.Length); + result.Write(READPROT, 0, READPROT.Length); + break; + } + result.Write(ENFORCEPROT, 0, ENFORCEPROT.Length); // assumes one of the above protection keywords was output. + result.WriteByte((byte)'1'); + result.Write(PROTLEVEL, 0, PROTLEVEL.Length); + byte[] t; + result.Write(t = document.GetDocumentSettings().GetProtectionLevelBytes(), 0, t.Length); + } + + if (document.GetDocumentSettings().GetReadOnlyRecommended()) { + result.Write(READONLYRECOMMENDED, 0, READONLYRECOMMENDED.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/output/IRtfDataCache.cs b/iTechSharp/iTextSharp/text/rtf/document/output/IRtfDataCache.cs new file mode 100644 index 0000000..6749eaf --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/output/IRtfDataCache.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +/* + * $Id: IRtfDataCache.cs,v 1.4 2008/05/16 19:30:53 psoares33 Exp $ + * + * + * Copyright 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document.output { + + /** + * The RtfDataCache interface must be implemented by classes wishing to + * act as caches for the rtf document data. + * + * @version $Revision: 1.4 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public interface IRtfDataCache { + /** + * Get the OutputStream that the RtfDocument can write to. + * + * @return The OutputStream the RtfDocument can use. + */ + Stream GetOutputStream(); + /** + * Write the content of the cache into the OutputStream. + * + * @param target The OutputStream to write the content into. + * @throws IOException If an error occurs reading/writing. + */ + void WriteTo(Stream target); + } + + public class RtfDataCache { + /** + * Constant for caching efficently into memory. + */ + public const int CACHE_MEMORY_EFFICIENT = 3; + /** + * Constant for caching into memory. + */ + public const int CACHE_MEMORY = 2; + /** + * Constant for caching to the disk. + */ + public const int CACHE_DISK = 1; + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/output/RtfByteArrayBuffer.cs b/iTechSharp/iTextSharp/text/rtf/document/output/RtfByteArrayBuffer.cs new file mode 100644 index 0000000..b5b60d2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/output/RtfByteArrayBuffer.cs @@ -0,0 +1,306 @@ +using System; +using System.IO; +using System.Collections; +/* + * Copyright 2007 Thomas Bickel + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document.output { + + public class RtfByteArrayBuffer : Stream { + private ArrayList arrays = new ArrayList(); + private byte[] buffer; + private int pos = 0; + private int size = 0; + + public RtfByteArrayBuffer() : this(256) { + } + + /** + * Creates a new buffer with the given initial size. + * + * @param bufferSize desired initial size in bytes + */ + public RtfByteArrayBuffer(int bufferSize) { + if ((bufferSize <= 0) || (bufferSize > 1<<30)) throw(new ArgumentException("bufferSize "+bufferSize)); + + int n = 1<<5; + while(n < bufferSize) { + n <<= 1; + } + buffer = new byte[n]; + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override void Close() { + } + + public override void Flush() { + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] src, int off, int len) { + if(src == null) throw(new ArgumentNullException()); + if((off < 0) || (off > src.Length) || (len < 0) || ((off + len) > src.Length) || ((off + len) < 0)) throw new IndexOutOfRangeException(); + + WriteLoop(src, off, len); + } + + private void WriteLoop(byte[] src, int off, int len) { + while(len > 0) { + int room = buffer.Length - pos; + int n = len > room ? room : len; + System.Array.Copy(src, off, buffer, pos, n); + len -= n; + off += n; + pos += n; + size += n; + if(pos == buffer.Length) FlushBuffer(len); + } + } + + /** + * Writes all bytes available in the given inputstream to this buffer. + * + * @param in + * @return number of bytes written + * @throws IOException + */ + public long Write(Stream inp) { + if (inp == null) throw(new ArgumentNullException()); + long sizeStart = size; + while (true) { + int n = inp.Read(buffer, pos, buffer.Length - pos); + if (n <= 0) break; + pos += n; + size += n; + if(pos == buffer.Length) FlushBuffer(); + } + return(size - sizeStart); + } + + /** + * Appends the given array to this buffer without copying (if possible). + * + * @param a + */ + public void Append(byte[] a) { + if(a == null) throw(new ArgumentNullException()); + if(a.Length == 0) return; + + if(a.Length <= 8) { + Write(a, 0, a.Length); + } else if((a.Length <= 16) && (pos > 0) && ((buffer.Length - pos) > a.Length)) { + Write(a, 0, a.Length); + } else { + FlushBuffer(); + arrays.Add(a); + size += a.Length; + } + } + /** + * Appends all arrays to this buffer without copying (if possible). + * + * @param a + */ + public void Append(byte[][] a) { + if(a == null) throw(new ArgumentNullException()); + + for(int k = 0; k < a.Length; k++) { + Append(a[k]); + } + } + + /** + * Returns the internal list of byte array buffers without copying the buffer contents. + * + * @return an byte aray of buffers + */ + public byte[][] ToArrayArray() + { + FlushBuffer(); + byte[][] a = new byte[arrays.Count][]; + arrays.CopyTo(a); + return a; + } + + /** + * Allocates a new array and copies all data that has been written to this buffer to the newly allocated array. + * + * @return a new byte array + */ + public byte[] ToArray() + { + byte[] r = new byte[size]; + int off = 0; + int n = arrays.Count; + for(int k = 0; k < n; k++) { + byte[] src = (byte[])arrays[k]; + System.Array.Copy(src, 0, r, off, src.Length); + off += src.Length; + } + if(pos > 0) System.Array.Copy(buffer, 0, r, off, pos); + return(r); + } + + /** + * Writes all data that has been written to this buffer to the given output stream. + * + * @param out + * @throws IOException + */ + public void WriteTo(Stream outp) { + if(outp == null) throw(new ArgumentNullException()); + + int n = arrays.Count; + for(int k = 0; k < n; k++) { + byte[] src = (byte[])arrays[k]; + outp.Write(src, 0, src.Length); + } + if(pos > 0) outp.Write(buffer, 0, pos); + } + + public override void WriteByte(byte value) { + buffer[pos] = value; + size++; + if(++pos == buffer.Length) FlushBuffer(); + } + + public override string ToString() { + return("RtfByteArrayBuffer: size="+Size()+" #arrays="+arrays.Count+" pos="+pos); + } + + /** + * Resets this buffer. + */ + public void Reset() { + arrays.Clear(); + pos = 0; + size = 0; + } + + /** + * Returns the number of bytes that have been written to this buffer so far. + * + * @return number of bytes written to this buffer + */ + public long Size() { + return(size); + } + + private void FlushBuffer() { + FlushBuffer(1); + } + + private void FlushBuffer(int reqSize) { + if(reqSize < 0) throw(new ArgumentException()); + + if(pos == 0) return; + + if(pos == buffer.Length) { + //add old buffer, alloc new (possibly larger) buffer + arrays.Add(buffer); + int newSize = buffer.Length; + buffer = null; + int MAX = Math.Max(1, size>>24) << 16; + while(newSize < MAX) { + newSize <<= 1; + if(newSize >= reqSize) break; + } + buffer = new byte[newSize]; + } else { + //copy buffer contents to newly allocated buffer + byte[] c = new byte[pos]; + System.Array.Copy(buffer, 0, c, 0, pos); + arrays.Add(c); + } + pos = 0; + } + } +} diff --git a/iTechSharp/iTextSharp/text/rtf/document/output/RtfDiskCache.cs b/iTechSharp/iTextSharp/text/rtf/document/output/RtfDiskCache.cs new file mode 100644 index 0000000..c81ad3a --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/output/RtfDiskCache.cs @@ -0,0 +1,107 @@ +using System; +using System.IO; +/* + * $Id: RtfDiskCache.cs,v 1.3 2008/05/16 19:30:53 psoares33 Exp $ + * + * + * Copyright 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document.output { + + /** + * The RtfFileCache is a RtfDataCache that uses a temporary file + * to store the rtf document data. Not so fast, but doesn't use any + * memory (just disk space). + * + * @version $Revision: 1.3 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfDiskCache : IRtfDataCache { + + /** + * The BufferedOutputStream that stores the cache data. + */ + private BufferedStream data = null; + /** + * The temporary file to store the data in. + */ + private string tempFile = null; + + /** + * Constructs a RtfFileCache. Creates the temp file. + * + * @throws IOException If the temporary file could not be created. + */ + public RtfDiskCache() { + this.tempFile = Path.GetTempFileName(); + this.data = new BufferedStream(new FileStream(tempFile, FileMode.Create)); + } + + /** + * Gets the BufferedOutputStream to write to. + */ + public Stream GetOutputStream() { + return this.data; + } + + /** + * Writes the content of the temporary file into the Stream. + */ + public void WriteTo(Stream target) { + this.data.Close(); + BufferedStream tempIn = new BufferedStream(new FileStream(this.tempFile, FileMode.Open)); + byte[] buffer = new byte[8192]; + int bytesRead = -1; + while ((bytesRead = tempIn.Read(buffer, 0, buffer.Length)) > 0) { + target.Write(buffer, 0, bytesRead); + } + tempIn.Close(); + File.Delete(this.tempFile); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/output/RtfEfficientMemoryCache.cs b/iTechSharp/iTextSharp/text/rtf/document/output/RtfEfficientMemoryCache.cs new file mode 100644 index 0000000..ea0b05e --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/output/RtfEfficientMemoryCache.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; +/* + * Copyright 2007 by Thomas Bickel + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document.output { + /** + * The RtfEfficientMemoryCache is an RtfDataCache that keeps the whole rtf document + * data in memory. + * More efficient than {@link RtfMemoryCache}. + * + * @version $Id: RtfEfficientMemoryCache.cs,v 1.1 2007/05/26 20:44:49 psoares33 Exp $ + * @author Thomas Bickel (tmb99@inode.at) + */ + public class RtfEfficientMemoryCache : IRtfDataCache { + /** + * The buffer for the rtf document data. + */ + private RtfByteArrayBuffer bab; + + /** + * Constructs a RtfMemoryCache. + */ + public RtfEfficientMemoryCache() { + bab = new RtfByteArrayBuffer(); + } + + /** + * Gets the OutputStream. + */ + public virtual Stream GetOutputStream() { + return(bab); + } + + /** + * Writes the content of the buffer into the OutputStream. + */ + public virtual void WriteTo(Stream target) { + bab.WriteTo(target); + } + } +} diff --git a/iTechSharp/iTextSharp/text/rtf/document/output/RtfMemoryCache.cs b/iTechSharp/iTextSharp/text/rtf/document/output/RtfMemoryCache.cs new file mode 100644 index 0000000..b00e48c --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/output/RtfMemoryCache.cs @@ -0,0 +1,91 @@ +using System; +using System.IO; +/* + * $Id: RtfMemoryCache.cs,v 1.3 2008/05/16 19:30:53 psoares33 Exp $ + * + * + * Copyright 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document.output { + + /** + * The RtfMemoryCache is an RtfDataCache that keeps the whole rtf document + * data in memory. Fast but memory intensive. + * + * @version $Revision: 1.3 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfMemoryCache : IRtfDataCache { + + /** + * The buffer for the rtf document data. + */ + private MemoryStream data = null; + + /** + * Constructs a RtfMemoryCache. + */ + public RtfMemoryCache() { + this.data = new MemoryStream(); + } + + /** + * Gets the MemoryStream. + */ + public Stream GetOutputStream() { + return this.data; + } + + /** + * Writes the content of the MemoryStream into the Stream. + */ + public void WriteTo(Stream target) { + this.data.WriteTo(target); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/document/output/RtfNilOutputStream.cs b/iTechSharp/iTextSharp/text/rtf/document/output/RtfNilOutputStream.cs new file mode 100644 index 0000000..048c27a --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/document/output/RtfNilOutputStream.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; +/* + * Copyright 2007 Thomas Bickel + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.document.output { + + /** + * The RtfNilOutputStream is a dummy output stream that sends all + * bytes to the big byte bucket in the sky. It is used to improve + * speed in those situations where processing is required, but + * the results are not needed. + * + * @version $Id: RtfNilOutputStream.cs,v 1.2 2008/05/16 19:30:53 psoares33 Exp $ + * @author Thomas Bickel (tmb99@inode.at) + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfNilOutputStream : Stream { + private long size = 0; + + public RtfNilOutputStream() { + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override void Close() { + } + + public override void Flush() { + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] src, int off, int len) { + if(src == null) throw(new ArgumentNullException()); + if((off < 0) || (off > src.Length) || (len < 0) || ((off + len) > src.Length) || ((off + len) < 0)) throw new IndexOutOfRangeException(); + + size += len; + } + + public override void WriteByte(byte value) { + ++size; + } + + /** + * Returns the number of bytes that have been written to this buffer so far. + * + * @return number of bytes written to this buffer + */ + public long GetSize() { + return(size); + } + } +} diff --git a/iTechSharp/iTextSharp/text/rtf/field/RtfAnchor.cs b/iTechSharp/iTextSharp/text/rtf/field/RtfAnchor.cs new file mode 100644 index 0000000..e81163a --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/field/RtfAnchor.cs @@ -0,0 +1,111 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf.text; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfAnchor.cs,v 1.7 2008/05/16 19:30:54 psoares33 Exp $ + * + * + * Copyright 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.field { + + /** + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfAnchor : RtfField { + + /** + * Constant for a hyperlink + */ + private static byte[] HYPERLINK = DocWriter.GetISOBytes("HYPERLINK"); + + /** + * The url of this RtfAnchor + */ + private String url = ""; + /** + * The RtfPhrase to display for the url + */ + private new RtfPhrase content = null; + + /** + * Constructs a RtfAnchor based on a RtfField + * + * @param doc The RtfDocument this RtfAnchor belongs to + * @param anchor The Anchor this RtfAnchor is based on + */ + public RtfAnchor(RtfDocument doc, Anchor anchor) : base(doc) { + this.url = anchor.Reference; + this.content = new RtfPhrase(doc, anchor); + } + + /** + * Write the field instructions for this RtfAnchor. Sets the field + * type to HYPERLINK and then writes the url. + * + * @return The field instructions for this RtfAnchor + * @throws IOException + */ + protected override void WriteFieldInstContent(Stream result) { + result.Write(HYPERLINK, 0, HYPERLINK.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + this.document.FilterSpecialChar(result, url, true, true); + } + + /** + * Write the field result for this RtfAnchor. Writes the content + * of the RtfPhrase. + */ + protected override void WriteFieldResultContent(Stream outp) { + content.WriteContent(outp); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/field/RtfField.cs b/iTechSharp/iTextSharp/text/rtf/field/RtfField.cs new file mode 100644 index 0000000..bb4c369 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/field/RtfField.cs @@ -0,0 +1,427 @@ +using System; +using System.IO; +using iTextSharp.text; +using ST = iTextSharp.text.rtf.style; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfField.cs,v 1.7 2008/05/16 19:30:54 psoares33 Exp $ + * + * + * Copyright 2004 by Mark Hall + * Uses code Copyright 2002 + * SMB + * Dirk.Weigenand@smb-tec.com + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.field { + + /** + * The RtfField class is an abstract base class for all rtf field functionality. + * Subclasses only need to implement the two abstract methods writeFieldInstContent + * and writeFieldResultContent. All other field functionality is handled by the + * RtfField class. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Dirk Weigenand + */ + public abstract class RtfField : Chunk, iTextSharp.text.rtf.IRtfBasicElement { + + /** + * Constant for the beginning of a rtf group + */ + public static byte[] OPEN_GROUP = {(byte)'{'}; + /** + * Constant for the end of an rtf group + */ + public static byte[] CLOSE_GROUP = {(byte)'}'}; + /** + * Constant for a delimiter in rtf + */ + public static byte[] DELIMITER = {(byte)' '}; + /** + * Constant for a comma delimiter in rtf + */ + public static byte[] COMMA_DELIMITER = {(byte)';'}; + /** + * The factor to use for translating from iText to rtf measurments + */ + public const double TWIPS_FACTOR = 20; + + /** + * Constant for a rtf field + */ + private static byte[] FIELD = DocWriter.GetISOBytes("\\field"); + /** + * Constant for a dirty field + */ + private static byte[] FIELD_DIRTY = DocWriter.GetISOBytes("\\flddirty"); + /** + * Constant for a private field + */ + private static byte[] FIELD_PRIVATE = DocWriter.GetISOBytes("\\fldpriv"); + /** + * Constant for a locked field + */ + private static byte[] FIELD_LOCKED = DocWriter.GetISOBytes("\\fldlock"); + /** + * Constant for a edited field + */ + private static byte[] FIELD_EDIT = DocWriter.GetISOBytes("\\fldedit"); + /** + * Constant for an alt field + */ + private static byte[] FIELD_ALT = DocWriter.GetISOBytes("\\fldalt"); + /** + * Constant for the field instructions + */ + private static byte[] FIELD_INSTRUCTIONS = DocWriter.GetISOBytes("\\*\\fldinst"); + /** + * Constant for the field result + */ + private static byte[] FIELD_RESULT = DocWriter.GetISOBytes("\\fldrslt"); + + /** + * Is the field dirty + */ + private bool fieldDirty = false; + /** + * Is the field edited + */ + private bool fieldEdit = false; + /** + * Is the field locked + */ + private bool fieldLocked = false; + /** + * Is the field private + */ + private bool fieldPrivate = false; + /** + * Is it an alt field + */ + private bool fieldAlt = false; + /** + * Whether this RtfField is in a table + */ + private bool inTable = false; + /** + * Whether this RtfElement is in a header + */ + private bool inHeader = false; + /** + * The RtfDocument this RtfField belongs to + */ + protected RtfDocument document = null; + /** + * The RtfFont of this RtfField + */ + private new ST.RtfFont font = null; + + /** + * Constructs a RtfField for a RtfDocument. This is not very usefull, + * since the RtfField by itself does not do anything. Use one of the + * subclasses instead. + * + * @param doc The RtfDocument this RtfField belongs to. + */ + protected RtfField(RtfDocument doc) : this(doc, new Font()) { + } + + /** + * Constructs a RtfField for a RtfDocument. This is not very usefull, + * since the RtfField by itself does not do anything. Use one of the + * subclasses instead. + * + * @param doc The RtfDocument this RtfField belongs to. + * @param font The Font this RtfField should use + */ + protected RtfField(RtfDocument doc, Font font) : base("", font) { + this.document = doc; + this.font = new ST.RtfFont(this.document, font); + } + + /** + * Sets the RtfDocument this RtfElement belongs to + * + * @param doc The RtfDocument to use + */ + public void SetRtfDocument(RtfDocument doc) { + this.document = doc; + this.font.SetRtfDocument(this.document); + } + + /** + * Writes the field beginning. Also writes field properties. + * + * @return A byte array with the field beginning. + * @throws IOException + */ + private void WriteFieldBegin(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(FIELD, 0, FIELD.Length); + if (fieldDirty) result.Write(FIELD_DIRTY, 0, FIELD_DIRTY.Length); + if (fieldEdit) result.Write(FIELD_EDIT, 0, FIELD_EDIT.Length); + if (fieldLocked) result.Write(FIELD_LOCKED, 0, FIELD_LOCKED.Length); + if (fieldPrivate) result.Write(FIELD_PRIVATE, 0, FIELD_PRIVATE.Length); + } + + /** + * Writes the beginning of the field instruction area. + * + * @return The beginning of the field instruction area + * @throws IOException + */ + private void WriteFieldInstBegin(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(FIELD_INSTRUCTIONS, 0, FIELD_INSTRUCTIONS.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + } + + /** + * Writes the content of the field instruction area. Override this + * method in your subclasses. + */ + protected abstract void WriteFieldInstContent(Stream oupt); + + /** + * Writes the end of the field instruction area. + */ + private void WriteFieldInstEnd(Stream result) { + if (fieldAlt) { + result.Write(DELIMITER, 0, DELIMITER.Length); + result.Write(FIELD_ALT, 0, FIELD_ALT.Length); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + + /** + * Writes the beginning of the field result area + */ + private void WriteFieldResultBegin(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(FIELD_RESULT, 0, FIELD_RESULT.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + } + + /** + * Writes the content of the pre-calculated field result. Override this + * method in your subclasses. + */ + protected abstract void WriteFieldResultContent(Stream oupt); + + /** + * Writes the end of the field result area + */ + private void WriteFieldResultEnd(Stream result) { + result.Write(DELIMITER, 0, DELIMITER.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + + /** + * Writes the end of the field + */ + private void WriteFieldEnd(Stream result) { + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + + + /** + * Writes the field to the OutputStream. + */ + public virtual void WriteContent(Stream result) { + font.WriteBegin(result); + WriteFieldBegin(result); + WriteFieldInstBegin(result); + WriteFieldInstContent(result); + WriteFieldInstEnd(result); + WriteFieldResultBegin(result); + WriteFieldResultContent(result); + WriteFieldResultEnd(result); + WriteFieldEnd(result); + font.WriteEnd(result); + } + + /** + * Get whether this field is an alt field + * + * @return Returns whether this field is an alt field + */ + public bool IsFieldAlt() { + return fieldAlt; + } + + /** + * Set whether this field is an alt field + * + * @param fieldAlt The value to use + */ + public void SetFieldAlt(bool fieldAlt) { + this.fieldAlt = fieldAlt; + } + + /** + * Get whether this field is dirty + * + * @return Returns whether this field is dirty + */ + public bool IsFieldDirty() { + return fieldDirty; + } + + /** + * Set whether this field is dirty + * + * @param fieldDirty The value to use + */ + public void SetFieldDirty(bool fieldDirty) { + this.fieldDirty = fieldDirty; + } + + /** + * Get whether this field is edited + * + * @return Returns whether this field is edited + */ + public bool IsFieldEdit() { + return fieldEdit; + } + + /** + * Set whether this field is edited. + * + * @param fieldEdit The value to use + */ + public void SetFieldEdit(bool fieldEdit) { + this.fieldEdit = fieldEdit; + } + + /** + * Get whether this field is locked + * + * @return Returns the fieldLocked. + */ + public bool IsFieldLocked() { + return fieldLocked; + } + + /** + * Set whether this field is locked + * @param fieldLocked The value to use + */ + public void SetFieldLocked(bool fieldLocked) { + this.fieldLocked = fieldLocked; + } + + /** + * Get whether this field is private + * + * @return Returns the fieldPrivate. + */ + public bool IsFieldPrivate() { + return fieldPrivate; + } + + /** + * Set whether this field is private + * + * @param fieldPrivate The value to use + */ + public void SetFieldPrivate(bool fieldPrivate) { + this.fieldPrivate = fieldPrivate; + } + + /** + * Sets whether this RtfField is in a table + * + * @param inTable True if this RtfField is in a table, false otherwise + */ + public void SetInTable(bool inTable) { + this.inTable = inTable; + } + + /** + * Gets whether this RtfField is in a table. + * + * @return True if this RtfField is in a table, false otherwise + */ + public bool IsInTable() { + return this.inTable; + } + + /** + * Sets whether this RtfField is in a header + * + * @param inHeader True if this RtfField is in a header, false otherwise + */ + public void SetInHeader(bool inHeader) { + this.inHeader = inHeader; + } + + /** + * Gets whether this RtfField is in a header. + * + * @return True if this RtfField is in a header, false otherwise + */ + public bool IsInHeader() { + return this.inHeader; + } + + /** + * An RtfField is never empty. + */ + public override bool IsEmpty() { + return false; + } + + public override Font Font { + set { + base.Font = value; + font = new ST.RtfFont(document, value); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/field/RtfPageNumber.cs b/iTechSharp/iTextSharp/text/rtf/field/RtfPageNumber.cs new file mode 100644 index 0000000..ea0ded7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/field/RtfPageNumber.cs @@ -0,0 +1,75 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +/* + * Created on Aug 10, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +namespace iTextSharp.text.rtf.field { + + /** + * The RtfPageNumber provides the page number field in rtf documents. + * + * @version $Revision: 1.4 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Steffen.Stundzig@smb-tec.com + */ + public class RtfPageNumber : RtfField { + + /** + * Constant for the page number + */ + private static byte[] PAGE_NUMBER = DocWriter.GetISOBytes("PAGE"); + + /** + * Constructs a RtfPageNumber. This can be added anywhere to add a page number field. + */ + public RtfPageNumber() : base(null) { + } + + /** + * Constructs a RtfPageNumber with a specified Font. This can be added anywhere to + * add a page number field. + * @param font + */ + public RtfPageNumber(Font font) : base(null, font) { + } + + /** + * Constructs a RtfPageNumber object. + * + * @param doc The RtfDocument this RtfPageNumber belongs to + */ + public RtfPageNumber(RtfDocument doc) : base(doc) { + } + + /** + * Constructs a RtfPageNumber object with a specific font. + * + * @param doc The RtfDocument this RtfPageNumber belongs to + * @param font The Font to use + */ + public RtfPageNumber(RtfDocument doc, Font font) : base(doc, font) { + } + + /** + * Writes the field instruction content + * + * @ + */ + protected override void WriteFieldInstContent(Stream oupt) { + oupt.Write(PAGE_NUMBER, 0, PAGE_NUMBER.Length); + } + + /** + * Writes the field result content + * + * @ + */ + protected override void WriteFieldResultContent(Stream oupt) { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/field/RtfTOCEntry.cs b/iTechSharp/iTextSharp/text/rtf/field/RtfTOCEntry.cs new file mode 100644 index 0000000..3fac144 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/field/RtfTOCEntry.cs @@ -0,0 +1,146 @@ +using System; +using System.IO; +using iTextSharp.text; +/* + * $Id: RtfTOCEntry.cs,v 1.6 2008/05/23 17:24:26 psoares33 Exp $ + * + * + * Copyright 2004 by Mark Hall + * Uses code Copyright 2002 + * Steffen.Stundzig@smb-tec.com + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.field { + + /** + * The RtfTOCEntry is used together with the RtfTableOfContents to generate a table of + * contents. Add the RtfTOCEntry in those locations in the document where table of + * contents entries should link to + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Steffen.Stundzig@smb-tec.com + */ + public class RtfTOCEntry : RtfField { + + /** + * Constant for the beginning of hidden text + */ + private static byte[] TEXT_HIDDEN_ON = DocWriter.GetISOBytes("\\v"); + /** + * Constant for the end of hidden text + */ + private static byte[] TEXT_HIDDEN_OFF = DocWriter.GetISOBytes("\\v0"); + /** + * Constant for a TOC entry with page numbers + */ + private static byte[] TOC_ENTRY_PAGE_NUMBER = DocWriter.GetISOBytes("\\tc"); + /** + * Constant for a TOC entry without page numbers + */ + private static byte[] TOC_ENTRY_NO_PAGE_NUMBER = DocWriter.GetISOBytes("\\tcn"); + + /** + * The entry text of this RtfTOCEntry + */ + private String entry = ""; + /** + * Whether to show page numbers in the table of contents + */ + private bool showPageNumber = true; + + /** + * Constructs a RtfTOCEntry with a certain entry text. + * + * @param entry The entry text to display + * @param font The Font to use + */ + public RtfTOCEntry(String entry) : base(null, new Font()) { + if (entry != null) { + this.entry = entry; + } + } + + /** + * Writes the content of the RtfTOCEntry + */ + public override void WriteContent(Stream result) { + result.Write(TEXT_HIDDEN_ON, 0, TEXT_HIDDEN_ON.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + if (this.showPageNumber) { + result.Write(TOC_ENTRY_PAGE_NUMBER, 0, TOC_ENTRY_PAGE_NUMBER.Length); + } else { + result.Write(TOC_ENTRY_NO_PAGE_NUMBER, 0, TOC_ENTRY_NO_PAGE_NUMBER.Length); + } + result.Write(DELIMITER, 0, DELIMITER.Length); + this.document.FilterSpecialChar(result, this.entry, true, false); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(TEXT_HIDDEN_OFF, 0, TEXT_HIDDEN_OFF.Length); + } + + /** + * Sets whether to display a page number in the table of contents, or not + * + * @param showPageNumber Whether to display a page number or not + */ + public void SetShowPageNumber(bool showPageNumber) { + this.showPageNumber = showPageNumber; + } + + /** + * unused + */ + protected override void WriteFieldInstContent(Stream outp) { + } + + /* + * unused + * @see com.lowagie.text.rtf.field.RtfField#writeFieldResultContent(java.io.OutputStream) + */ + protected override void WriteFieldResultContent(Stream outp) { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/field/RtfTableOfContents.cs b/iTechSharp/iTextSharp/text/rtf/field/RtfTableOfContents.cs new file mode 100644 index 0000000..94181e5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/field/RtfTableOfContents.cs @@ -0,0 +1,105 @@ +using System; +using System.IO; +using iTextSharp.text; +/* + * $Id: RtfTableOfContents.cs,v 1.7 2008/05/23 17:24:26 psoares33 Exp $ + * + * + * Copyright 2004 by Mark Hall + * Uses code Copyright 2002 + * Steffen.Stundzig@smb-tec.com + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.field { + + /** + * The RtfTableOfContents together with multiple RtfTOCEntry objects generates a table + * of contents. The table of contents will display no entries in the viewing program + * and the user will have to update it first. A text to inform the user of this is + * displayed instead. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Steffen.Stundzig@smb-tec.com + */ + public class RtfTableOfContents : RtfField { + + /** + * field inst content + */ + private const String FIELD_INST = "TOC \\\\f \\\\h \\\\u \\\\o \"1-5\" "; + /** + * The default text to display + */ + private String defaultText = "Table of Contents - Click to update"; + + /** + * Constructs a RtfTableOfContents. The default text is the text that is displayed + * before the user updates the table of contents + * + * @param defaultText The default text to display + * @param font The Font to use + */ + public RtfTableOfContents(String defaultText) : base(null, new Font()) { + this.defaultText = defaultText; + } + + /** + * Writes the field instruction content + */ + protected override void WriteFieldInstContent(Stream outp) { + byte[] t = DocWriter.GetISOBytes(FIELD_INST); + outp.Write(t, 0, t.Length); + } + + /** + * Writes the field result content + */ + protected override void WriteFieldResultContent(Stream outp) { + document.FilterSpecialChar(outp, defaultText, true, true); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/field/RtfTotalPageNumber.cs b/iTechSharp/iTextSharp/text/rtf/field/RtfTotalPageNumber.cs new file mode 100644 index 0000000..a38b300 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/field/RtfTotalPageNumber.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfTotalPageNumber.cs,v 1.5 2008/05/23 17:24:26 psoares33 Exp $ + * + * + * Copyright 2005 Jose Hurtado jose.hurtado@gft.com + * Parts Copyright 2005 Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.field { + + /** + * The RtfTotalPageNumber provides the total number of pages field in rtf documents. + * + * @version $Version:$ + * @author Jose Hurtado (jose.hurtado@gft.com) + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfTotalPageNumber : RtfField { + + /** + * Constant for arabic total page numbers. + */ + private static byte[] ARABIC_TOTAL_PAGES = DocWriter.GetISOBytes("NUMPAGES \\\\* Arabic"); + + /** + * Constructs a RtfTotalPageNumber. This can be added anywhere to add a total number of pages field. + */ + public RtfTotalPageNumber() : base(null) { + } + + /** + * Constructs a RtfTotalPageNumber with a specified Font. This can be added anywhere + * to add a total number of pages field. + * @param font + */ + public RtfTotalPageNumber(Font font) : base(null, font) { + } + + /** + * Constructs a RtfTotalPageNumber object. + * + * @param doc The RtfDocument this RtfTotalPageNumber belongs to + */ + public RtfTotalPageNumber(RtfDocument doc) : base(doc) { + } + + /** + * Constructs a RtfTotalPageNumber object with a specific font. + * + * @param doc The RtfDocument this RtfTotalPageNumber belongs to + * @param font The Font to use + */ + public RtfTotalPageNumber(RtfDocument doc, Font font) : base(doc, font) { + } + + /** + * Writes the field NUMPAGES instruction with Arabic format: "NUMPAGES \\\\* Arabic". + */ + protected override void WriteFieldInstContent(Stream outp) { + outp.Write(ARABIC_TOTAL_PAGES, 0, ARABIC_TOTAL_PAGES.Length); + } + + /** + * Writes the field result content "1" + */ + protected override void WriteFieldResultContent(Stream outp) { + byte[] t = new byte[]{(byte)'1'}; + outp.Write(t, 0, t.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/graphic/RtfImage.cs b/iTechSharp/iTextSharp/text/rtf/graphic/RtfImage.cs new file mode 100644 index 0000000..ec2edf4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/graphic/RtfImage.cs @@ -0,0 +1,384 @@ +using System; +using System.IO; +using System.Net; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.document.output; +using iTextSharp.text.rtf.text; +using iTextSharp.text.rtf.style; +using iTextSharp.text.pdf.codec.wmf; +/* + * $Id: RtfImage.cs,v 1.11 2008/05/16 19:30:59 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.graphic { + + /** + * The RtfImage contains one image. Supported image types are jpeg, png, wmf, bmp. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Paulo Soares + */ + public class RtfImage : RtfElement { + + /** + * Constant for the shape/picture group + */ + private static byte[] PICTURE_GROUP = DocWriter.GetISOBytes("\\*\\shppict"); + /** + * Constant for a picture + */ + private static byte[] PICTURE = DocWriter.GetISOBytes("\\pict"); + /** + * Constant for a jpeg image + */ + private static byte[] PICTURE_JPEG = DocWriter.GetISOBytes("\\jpegblip"); + /** + * Constant for a png image + */ + private static byte[] PICTURE_PNG = DocWriter.GetISOBytes("\\pngblip"); + /** + * Constant for a wmf image + */ + private static byte[] PICTURE_WMF = DocWriter.GetISOBytes("\\wmetafile8"); + /** + * Constant for the picture width + */ + private static byte[] PICTURE_WIDTH = DocWriter.GetISOBytes("\\picw"); + /** + * Constant for the picture height + */ + private static byte[] PICTURE_HEIGHT = DocWriter.GetISOBytes("\\pich"); + /** + * Constant for the picture width scale + */ + private static byte[] PICTURE_SCALED_WIDTH = DocWriter.GetISOBytes("\\picwgoal"); + /** + * Constant for the picture height scale + */ + private static byte[] PICTURE_SCALED_HEIGHT = DocWriter.GetISOBytes("\\pichgoal"); + /** + * Constant for horizontal picture scaling + */ + private static byte[] PICTURE_SCALE_X = DocWriter.GetISOBytes("\\picscalex"); + /** + * Constant for vertical picture scaling + */ + private static byte[] PICTURE_SCALE_Y = DocWriter.GetISOBytes("\\picscaley"); + /** + * "\bin" constant + */ + private static byte[] PICTURE_BINARY_DATA = DocWriter.GetISOBytes("\\bin"); + /** + * Constant for converting pixels to twips + */ + private const int PIXEL_TWIPS_FACTOR = 15; + + /** + * The type of image this is. + */ + private int imageType; + /** + * Binary image data. + */ + private byte[][] imageData; + /** + * The alignment of this picture + */ + private int alignment = Element.ALIGN_LEFT; + /** + * The width of this picture + */ + private float width = 0; + /** + * The height of this picutre + */ + private float height = 0; + /** + * The intended display width of this picture + */ + private float plainWidth = 0; + /** + * The intended display height of this picture + */ + private float plainHeight = 0; + /** + * Whether this RtfImage is a top level element and should + * be an extra paragraph. + */ + private bool topLevelElement = false; + + /** + * Constructs a RtfImage for an Image. + * + * @param doc The RtfDocument this RtfImage belongs to + * @param image The Image that this RtfImage wraps + * @throws DocumentException If an error occured accessing the image content + */ + public RtfImage(RtfDocument doc, Image image) : base(doc) { + imageType = image.OriginalType; + if (!(imageType == Image.ORIGINAL_JPEG || imageType == Image.ORIGINAL_BMP + || imageType == Image.ORIGINAL_PNG || imageType == Image.ORIGINAL_WMF || imageType == Image.ORIGINAL_GIF)) { + throw new DocumentException("Only BMP, PNG, WMF, GIF and JPEG images are supported by the RTF Writer"); + } + alignment = image.Alignment; + width = image.Width; + height = image.Height; + plainWidth = image.PlainWidth; + plainHeight = image.PlainHeight; + this.imageData = GetImageData(image); + } + + /** + * Extracts the image data from the Image. + * + * @param image The image for which to extract the content + * @return The raw image data, not formated + * @throws DocumentException If an error occurs accessing the image content + */ + private byte[][] GetImageData(Image image) { + int WMF_PLACEABLE_HEADER_SIZE = 22; + RtfByteArrayBuffer bab = new RtfByteArrayBuffer(); + + try { + if (imageType == Image.ORIGINAL_BMP) { + bab.Append(MetaDo.WrapBMP(image)); + } else { + byte[] iod = image.OriginalData; + if (iod == null) { + Stream imageIn = WebRequest.Create(image.Url).GetResponse().GetResponseStream(); + if (imageType == Image.ORIGINAL_WMF) { //remove the placeable header first + for (int k = 0; k < WMF_PLACEABLE_HEADER_SIZE; k++) { + if (imageIn.ReadByte() < 0) throw (new IOException("while removing wmf placeable header")); + } + } + bab.Write(imageIn); + imageIn.Close(); + + } else { + + if (imageType == Image.ORIGINAL_WMF) { + //remove the placeable header + bab.Write(iod, WMF_PLACEABLE_HEADER_SIZE, iod.Length - WMF_PLACEABLE_HEADER_SIZE); + } else { + bab.Append(iod); + } + + } + } + return bab.ToArrayArray(); + } catch (IOException ioe) { + throw new DocumentException(ioe.Message); + } + } + + + /** + * lookup table used for converting bytes to hex chars. + * TODO Should probably be refactored into a helper class + */ + public static byte[] byte2charLUT = new byte[512]; //'0001020304050607 ... fafbfcfdfeff' + static RtfImage() { + char c = '0'; + for (int k = 0; k < 16; k++) { + for (int x = 0; x < 16; x++) { + byte2charLUT[((k*16)+x)*2] = byte2charLUT[(((x*16)+k)*2)+1] = (byte)c; + } + if (++c == ':') c = 'a'; + } + } + /** + * Writes the image data to the given buffer as hex encoded text. + * + * @param binary + * @param bab + * @ + */ + private void WriteImageDataHexEncoded(Stream bab) { + int cnt = 0; + for (int k = 0; k < imageData.Length; k++) { + byte[] chunk = imageData[k]; + for (int x = 0; x < chunk.Length; x++) { + bab.Write(byte2charLUT, (chunk[x]&0xff)*2, 2); + if (++cnt == 64) { + bab.WriteByte((byte)'\n'); + cnt = 0; + } + } + } + if (cnt > 0) bab.WriteByte((byte)'\n'); + } + /** + * Returns the image raw data size in bytes. + * + * @return + */ + private int ImageDataSize() { + int size = 0; + for (int k = 0; k < imageData.Length; k++) { + size += imageData[k].Length; + } + return size; + } + + /** + * Writes the RtfImage content + */ + public override void WriteContent(Stream result) + { + byte[] t; + if (this.topLevelElement) { + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + switch (alignment) { + case Element.ALIGN_LEFT: + result.Write(RtfParagraphStyle.ALIGN_LEFT, 0, RtfParagraphStyle.ALIGN_LEFT.Length); + break; + case Element.ALIGN_RIGHT: + result.Write(RtfParagraphStyle.ALIGN_RIGHT, 0, RtfParagraphStyle.ALIGN_RIGHT.Length); + break; + case Element.ALIGN_CENTER: + result.Write(RtfParagraphStyle.ALIGN_CENTER, 0, RtfParagraphStyle.ALIGN_CENTER.Length); + break; + case Element.ALIGN_JUSTIFIED: + result.Write(RtfParagraphStyle.ALIGN_JUSTIFY, 0, RtfParagraphStyle.ALIGN_JUSTIFY.Length); + break; + } + } + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(PICTURE_GROUP, 0, PICTURE_GROUP.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(PICTURE, 0, PICTURE.Length); + switch (imageType) { + case Image.ORIGINAL_JPEG: + result.Write(PICTURE_JPEG, 0, PICTURE_JPEG.Length); + break; + case Image.ORIGINAL_PNG: + case Image.ORIGINAL_GIF: + result.Write(PICTURE_PNG, 0, PICTURE_PNG.Length); + break; + case Image.ORIGINAL_WMF: + case Image.ORIGINAL_BMP: + result.Write(PICTURE_WMF, 0, PICTURE_WMF.Length); + break; + } + result.Write(PICTURE_WIDTH, 0, PICTURE_WIDTH.Length); + result.Write(t = IntToByteArray((int) width), 0, t.Length); + result.Write(PICTURE_HEIGHT, 0, PICTURE_HEIGHT.Length); + result.Write(t = IntToByteArray((int) height), 0, t.Length); + if (this.document.GetDocumentSettings().IsWriteImageScalingInformation()) { + result.Write(PICTURE_SCALE_X, 0, PICTURE_SCALE_X.Length); + result.Write(t = IntToByteArray((int)(100 * plainWidth / width)), 0, t.Length); + result.Write(PICTURE_SCALE_Y, 0, PICTURE_SCALE_Y.Length); + result.Write(t = IntToByteArray((int)(100 * plainHeight / height)), 0, t.Length); + } + if (this.document.GetDocumentSettings().IsImagePDFConformance()) { + result.Write(PICTURE_SCALED_WIDTH, 0, PICTURE_SCALED_WIDTH.Length); + result.Write(t = IntToByteArray((int) (plainWidth * RtfElement.TWIPS_FACTOR)), 0, t.Length); + result.Write(PICTURE_SCALED_HEIGHT, 0, PICTURE_SCALED_HEIGHT.Length); + result.Write(t = IntToByteArray((int) (plainHeight * RtfElement.TWIPS_FACTOR)), 0, t.Length); + } else { + if (this.width != this.plainWidth || this.imageType == Image.ORIGINAL_BMP) { + result.Write(PICTURE_SCALED_WIDTH, 0, PICTURE_SCALED_WIDTH.Length); + result.Write(t = IntToByteArray((int) (plainWidth * PIXEL_TWIPS_FACTOR)), 0, t.Length); + } + if (this.height != this.plainHeight || this.imageType == Image.ORIGINAL_BMP) { + result.Write(PICTURE_SCALED_HEIGHT, 0, PICTURE_SCALED_HEIGHT.Length); + result.Write(t = IntToByteArray((int) (plainHeight * PIXEL_TWIPS_FACTOR)), 0, t.Length); + } + } + + if (this.document.GetDocumentSettings().IsImageWrittenAsBinary()) { + //binary + result.WriteByte((byte)'\n'); + result.Write(PICTURE_BINARY_DATA, 0, PICTURE_BINARY_DATA.Length); + result.Write(t = IntToByteArray(ImageDataSize()), 0, t.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + if (result is RtfByteArrayBuffer) { + ((RtfByteArrayBuffer)result).Append(imageData); + } else { + for (int k = 0; k < imageData.Length; k++) { + result.Write(imageData[k], 0, imageData[k].Length); + } + } + } else { + //hex encoded + result.Write(DELIMITER, 0, DELIMITER.Length); + result.WriteByte((byte)'\n'); + WriteImageDataHexEncoded(result); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + if (this.topLevelElement) { + result.Write(RtfParagraph.PARAGRAPH, 0, RtfParagraph.PARAGRAPH.Length); + } + result.WriteByte((byte)'\n'); + } + + /** + * Sets the alignment of this RtfImage. Uses the alignments from com.lowagie.text.Element. + * + * @param alignment The alignment to use. + */ + public void SetAlignment(int alignment) { + this.alignment = alignment; + } + + /** + * Set whether this RtfImage should behave like a top level element + * and enclose itself in a paragraph. + * + * @param topLevelElement Whether to behave like a top level element. + */ + public void SetTopLevelElement(bool topLevelElement) { + this.topLevelElement = topLevelElement; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/graphic/RtfShape.cs b/iTechSharp/iTextSharp/text/rtf/graphic/RtfShape.cs new file mode 100644 index 0000000..212da88 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/graphic/RtfShape.cs @@ -0,0 +1,379 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +/** + * $Id: RtfShape.cs,v 1.7 2008/05/23 17:24:27 psoares33 Exp $ + * + * + * Copyright 2006 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.graphic { + + /** + * The RtfShape provides the interface for adding shapes to + * the RTF document. This will only work for Word 97+, older + * Word versions are not supported by this class.

      + * + * Only very simple shapes are directly supported by the RtfShape. + * For more complex shapes you will have to read the RTF + * specification (iText follows the 1.6 specification) and add + * the desired properties via the RtfShapeProperty.

      + * + * One thing to keep in mind is that distances are not expressed + * in the standard iText point, but in EMU where 1 inch = 914400 EMU + * or 1 cm = 360000 EMU. + * + * @version $Revision: 1.7 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfShape : RtfAddableElement { + /** + * Constant for a free form shape. The shape verticies must + * be specified with an array of Point objects in a + * RtfShapeProperty with the name PROPERTY_VERTICIES. + */ + public const int SHAPE_FREEFORM = 0; + /** + * Constant for a rectangle. + */ + public const int SHAPE_RECTANGLE = 1; + /** + * Constant for a rounded rectangle. The roundness is + * set via a RtfShapeProperty with the name PROPERTY_ADJUST_VALUE. + */ + public const int SHAPE_ROUND_RECTANGLE = 2; + /** + * Constant for an ellipse. Use this to create circles. + */ + public const int SHAPE_ELLIPSE = 3; + /** + * Constant for a diamond. + */ + public const int SHAPE_DIAMOND = 4; + /** + * Constant for a isoscelle triangle. + */ + public const int SHAPE_TRIANGLE_ISOSCELES = 5; + /** + * Constant for a right triangle. + */ + public const int SHAPE_TRIANGLE_RIGHT = 6; + /** + * Constant for a parallelogram. + */ + public const int SHAPE_PARALLELOGRAM = 7; + /** + * Constant for a trapezoid. + */ + public const int SHAPE_TRAPEZOID = 8; + /** + * Constant for a hexagon. + */ + public const int SHAPE_HEXAGON = 9; + /** + * Constant for an ocatagon. + */ + public const int SHAPE_OCTAGON = 10; + /** + * Constant for a star. + */ + public const int SHAPE_STAR = 12; + /** + * Constant for an arrow. + */ + public const int SHAPE_ARROW = 13; + /** + * Constant for a thick arrow. + */ + public const int SHAPE_ARROR_THICK = 14; + /** + * Constant for a home plate style shape. + */ + public const int SHAPE_HOME_PLATE = 15; + /** + * Constant for a cube shape. + */ + public const int SHAPE_CUBE = 16; + /** + * Constant for a balloon shape. + */ + public const int SHAPE_BALLOON = 17; + /** + * Constant for a seal shape. + */ + public const int SHAPE_SEAL = 18; + /** + * Constant for an arc shape. + */ + public const int SHAPE_ARC = 19; + /** + * Constant for a line shape. + */ + public const int SHAPE_LINE = 20; + /** + * Constant for a can shape. + */ + public const int SHAPE_CAN = 22; + /** + * Constant for a donut shape. + */ + public const int SHAPE_DONUT = 23; + + /** + * Constant for a Picture Frame. + */ + public const int SHAPE_PICTURE_FRAME = 75; + /** + * Text is not wrapped around the shape. + */ + public const int SHAPE_WRAP_NONE = 0; + /** + * Text is wrapped to the top and bottom. + */ + public const int SHAPE_WRAP_TOP_BOTTOM = 1; + /** + * Text is wrapped on the left and right side. + */ + public const int SHAPE_WRAP_BOTH = 2; + /** + * Text is wrapped on the left side. + */ + public const int SHAPE_WRAP_LEFT = 3; + /** + * Text is wrapped on the right side. + */ + public const int SHAPE_WRAP_RIGHT = 4; + /** + * Text is wrapped on the largest side. + */ + public const int SHAPE_WRAP_LARGEST = 5; + /** + * Text is tightly wrapped on the left and right side. + */ + public const int SHAPE_WRAP_TIGHT_BOTH = 6; + /** + * Text is tightly wrapped on the left side. + */ + public const int SHAPE_WRAP_TIGHT_LEFT = 7; + /** + * Text is tightly wrapped on the right side. + */ + public const int SHAPE_WRAP_TIGHT_RIGHT = 8; + /** + * Text is tightly wrapped on the largest side. + */ + public const int SHAPE_WRAP_TIGHT_LARGEST = 9; + /** + * Text is wrapped through the shape. + */ + public const int SHAPE_WRAP_THROUGH = 10; + + /** + * The shape nr is a random unique id. + */ + private int shapeNr = 0; + /** + * The shape type. + */ + private int type = 0; + /** + * The RtfShapePosition that defines position settings for this RtfShape. + */ + private RtfShapePosition position = null; + /** + * A Hashtable with RtfShapePropertys that define further shape properties. + */ + private Hashtable properties = null; + /** + * The wrapping mode. Defaults to SHAPE_WRAP_NONE; + */ + private int wrapping = SHAPE_WRAP_NONE; + /** + * Text that is contained in the shape. + */ + private String shapeText = ""; + + /** + * Constructs a new RtfShape of a given shape at the given RtfShapePosition. + * + * @param type The type of shape to create. + * @param position The RtfShapePosition to create this RtfShape at. + */ + public RtfShape(int type, RtfShapePosition position) { + this.type = type; + this.position = position; + this.properties = new Hashtable(); + } + + /** + * Sets a property. + * + * @param property The property to set for this RtfShape. + */ + public void SetProperty(RtfShapeProperty property) { + this.properties[property.GetName()] = property; + } + + /** + * Sets the text to display in this RtfShape. + * + * @param shapeText The text to display. + */ + public void SetShapeText(String shapeText) { + this.shapeText = shapeText; + } + + /** + * Set the wrapping mode. + * + * @param wrapping The wrapping mode to use for this RtfShape. + */ + public void SetWrapping(int wrapping) { + this.wrapping = wrapping; + } + + /** + * Writes the RtfShape. Some settings are automatically translated into + * or require other properties and these are set first. + */ + public override void WriteContent(Stream result) { + this.shapeNr = this.doc.GetRandomInt(); + + this.properties["ShapeType"] = new RtfShapeProperty("ShapeType", this.type); + if (this.position.IsShapeBelowText()) { + this.properties["fBehindDocument"] = new RtfShapeProperty("fBehindDocument", true); + } + if (this.inTable) { + this.properties["fLayoutInCell"] = new RtfShapeProperty("fLayoutInCell", true); + } + if (this.properties.ContainsKey("posh")) { + this.position.SetIgnoreXRelative(true); + } + if (this.properties.ContainsKey("posv")) { + this.position.SetIgnoreYRelative(true); + } + + byte[] t; + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + result.Write(t = DocWriter.GetISOBytes("\\shp"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shplid"), 0, t.Length); + result.Write(t = IntToByteArray(this.shapeNr), 0, t.Length); + this.position.WriteContent(result); + switch (this.wrapping) { + case SHAPE_WRAP_NONE: + result.Write(t = DocWriter.GetISOBytes("\\shpwr3"), 0, t.Length); + break; + case SHAPE_WRAP_TOP_BOTTOM: + result.Write(t = DocWriter.GetISOBytes("\\shpwr1"), 0, t.Length); + break; + case SHAPE_WRAP_BOTH: + result.Write(t = DocWriter.GetISOBytes("\\shpwr2"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk0"), 0, t.Length); + break; + case SHAPE_WRAP_LEFT: + result.Write(t = DocWriter.GetISOBytes("\\shpwr2"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk1"), 0, t.Length); + break; + case SHAPE_WRAP_RIGHT: + result.Write(t = DocWriter.GetISOBytes("\\shpwr2"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk2"), 0, t.Length); + break; + case SHAPE_WRAP_LARGEST: + result.Write(t = DocWriter.GetISOBytes("\\shpwr2"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk3"), 0, t.Length); + break; + case SHAPE_WRAP_TIGHT_BOTH: + result.Write(t = DocWriter.GetISOBytes("\\shpwr4"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk0"), 0, t.Length); + break; + case SHAPE_WRAP_TIGHT_LEFT: + result.Write(t = DocWriter.GetISOBytes("\\shpwr4"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk1"), 0, t.Length); + break; + case SHAPE_WRAP_TIGHT_RIGHT: + result.Write(t = DocWriter.GetISOBytes("\\shpwr4"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk2"), 0, t.Length); + break; + case SHAPE_WRAP_TIGHT_LARGEST: + result.Write(t = DocWriter.GetISOBytes("\\shpwr4"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpwrk3"), 0, t.Length); + break; + case SHAPE_WRAP_THROUGH: + result.Write(t = DocWriter.GetISOBytes("\\shpwr5"), 0, t.Length); + break; + default: + result.Write(t = DocWriter.GetISOBytes("\\shpwr3"), 0, t.Length); + break; + } + if (this.inHeader) { + result.Write(t = DocWriter.GetISOBytes("\\shpfhdr1"), 0, t.Length); + } + if (this.doc.GetDocumentSettings().IsOutputDebugLineBreaks()) { + result.WriteByte((byte)'\n'); + } + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + result.Write(t = DocWriter.GetISOBytes("\\*\\shpinst"), 0, t.Length); + foreach (RtfShapeProperty rsp in this.properties.Values) { + rsp.WriteContent(result); + } + if (!this.shapeText.Equals("")) { + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + result.Write(t = DocWriter.GetISOBytes("\\shptxt"), 0, t.Length); + result.Write(RtfElement.DELIMITER, 0, RtfElement.DELIMITER.Length); + result.Write(t = DocWriter.GetISOBytes(this.shapeText), 0, t.Length); + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + } + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + if (this.doc.GetDocumentSettings().IsOutputDebugLineBreaks()) { + result.WriteByte((byte)'\n'); + } + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/graphic/RtfShapePosition.cs b/iTechSharp/iTextSharp/text/rtf/graphic/RtfShapePosition.cs new file mode 100644 index 0000000..37d3ada --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/graphic/RtfShapePosition.cs @@ -0,0 +1,249 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +/** + * $Id: RtfShapePosition.cs,v 1.6 2008/05/23 17:24:27 psoares33 Exp $ + * + * + * Copyright 2006 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.graphic { + + /** + * The RtfShapePosition stores position and ordering + * information for one RtfShape. + * + * @version $Revision: 1.6 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfShapePosition : RtfAddableElement { + /** + * Constant for horizontal positioning relative to the page. + */ + public const int POSITION_X_RELATIVE_PAGE = 0; + /** + * Constant for horizontal positioning relative to the margin. + */ + public const int POSITION_X_RELATIVE_MARGIN = 1; + /** + * Constant for horizontal positioning relative to the column. + */ + public const int POSITION_X_RELATIVE_COLUMN = 2; + /** + * Constant for vertical positioning relative to the page. + */ + public const int POSITION_Y_RELATIVE_PAGE = 0; + /** + * Constant for vertical positioning relative to the margin. + */ + public const int POSITION_Y_RELATIVE_MARGIN = 1; + /** + * Constant for vertical positioning relative to the paragraph. + */ + public const int POSITION_Y_RELATIVE_PARAGRAPH = 2; + + /** + * The top coordinate of this RtfShapePosition. + */ + private int top = 0; + /** + * The left coordinate of this RtfShapePosition. + */ + private int left = 0; + /** + * The right coordinate of this RtfShapePosition. + */ + private int right = 0; + /** + * The bottom coordinate of this RtfShapePosition. + */ + private int bottom = 0; + /** + * The z order of this RtfShapePosition. + */ + private int zOrder = 0; + /** + * The horizontal relative position. + */ + private int xRelativePos = POSITION_X_RELATIVE_PAGE; + /** + * The vertical relative position. + */ + private int yRelativePos = POSITION_Y_RELATIVE_PAGE; + /** + * Whether to ignore the horizontal relative position. + */ + private bool ignoreXRelative = false; + /** + * Whether to ignore the vertical relative position. + */ + private bool ignoreYRelative = false; + /** + * Whether the shape is below the text. + */ + private bool shapeBelowText = false; + + /** + * Constructs a new RtfShapePosition with the four bounding coordinates. + * + * @param top The top coordinate. + * @param left The left coordinate. + * @param right The right coordinate. + * @param bottom The bottom coordinate. + */ + public RtfShapePosition(int top, int left, int right, int bottom) { + this.top = top; + this.left = left; + this.right = right; + this.bottom = bottom; + } + + /** + * Gets whether the shape is below the text. + * + * @return True if the shape is below, false if the text is below. + */ + public bool IsShapeBelowText() { + return shapeBelowText; + } + + /** + * Sets whether the shape is below the text. + * + * @param shapeBelowText True if the shape is below, false if the text is below. + */ + public void SetShapeBelowText(bool shapeBelowText) { + this.shapeBelowText = shapeBelowText; + } + + /** + * Sets the relative horizontal position. Use one of the constants + * provided in this class. + * + * @param relativePos The relative horizontal position to use. + */ + public void SetXRelativePos(int relativePos) { + xRelativePos = relativePos; + } + + /** + * Sets the relative vertical position. Use one of the constants + * provides in this class. + * + * @param relativePos The relative vertical position to use. + */ + public void SetYRelativePos(int relativePos) { + yRelativePos = relativePos; + } + + /** + * Sets the z order to use. + * + * @param order The z order to use. + */ + public void SetZOrder(int order) { + zOrder = order; + } + + /** + * Set whether to ignore the horizontal relative position. + * + * @param ignoreXRelative True to ignore the horizontal relative position, false otherwise. + */ + protected internal void SetIgnoreXRelative(bool ignoreXRelative) { + this.ignoreXRelative = ignoreXRelative; + } + + /** + * Set whether to ignore the vertical relative position. + * + * @param ignoreYRelative True to ignore the vertical relative position, false otherwise. + */ + protected internal void SetIgnoreYRelative(bool ignoreYRelative) { + this.ignoreYRelative = ignoreYRelative; + } + + /** + * Write this RtfShapePosition. + */ + public override void WriteContent(Stream result) { + byte[] t; + result.Write(t = DocWriter.GetISOBytes("\\shpleft"), 0, t.Length); + result.Write(t = IntToByteArray(this.left), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shptop"), 0, t.Length); + result.Write(t = IntToByteArray(this.top), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpright"), 0, t.Length); + result.Write(t = IntToByteArray(this.right), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpbottom"), 0, t.Length); + result.Write(t = IntToByteArray(this.bottom), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\shpz"), 0, t.Length); + result.Write(t = IntToByteArray(this.zOrder), 0, t.Length); + switch(this.xRelativePos) { + case POSITION_X_RELATIVE_PAGE: result.Write(t = DocWriter.GetISOBytes("\\shpbxpage"), 0, t.Length); break; + case POSITION_X_RELATIVE_MARGIN: result.Write(t = DocWriter.GetISOBytes("\\shpbxmargin"), 0, t.Length); break; + case POSITION_X_RELATIVE_COLUMN: result.Write(t = DocWriter.GetISOBytes("\\shpbxcolumn"), 0, t.Length); break; + } + if(this.ignoreXRelative) { + result.Write(t = DocWriter.GetISOBytes("\\shpbxignore"), 0, t.Length); + } + switch(this.yRelativePos) { + case POSITION_Y_RELATIVE_PAGE: result.Write(t = DocWriter.GetISOBytes("\\shpbypage"), 0, t.Length); break; + case POSITION_Y_RELATIVE_MARGIN: result.Write(t = DocWriter.GetISOBytes("\\shpbymargin"), 0, t.Length); break; + case POSITION_Y_RELATIVE_PARAGRAPH: result.Write(t = DocWriter.GetISOBytes("\\shpbypara"), 0, t.Length); break; + } + if(this.ignoreYRelative) { + result.Write(t = DocWriter.GetISOBytes("\\shpbyignore"), 0, t.Length); + } + if(this.shapeBelowText) { + result.Write(t = DocWriter.GetISOBytes("\\shpfblwtxt1"), 0, t.Length); + } else { + result.Write(t = DocWriter.GetISOBytes("\\shpfblwtxt0"), 0, t.Length); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/graphic/RtfShapeProperty.cs b/iTechSharp/iTextSharp/text/rtf/graphic/RtfShapeProperty.cs new file mode 100644 index 0000000..cf2b192 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/graphic/RtfShapeProperty.cs @@ -0,0 +1,356 @@ +using System; +using System.IO; +using System.Drawing; +using iTextSharp.text; +using iTextSharp.text.rtf; +/** + * $Id: RtfShapeProperty.cs,v 1.8 2008/05/23 17:24:27 psoares33 Exp $ + * + * + * Copyright 2006 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.graphic { + + /** + * The RtfShapeProperty stores all shape properties that are + * not handled by the RtfShape and RtfShapePosition.

      + * + * There is a huge selection of properties that can be set. For + * the most important properites there are constants for the + * property name, for all others you must find the correct + * property name in the RTF specification (version 1.6).

      + * + * The following types of property values are supported: + *
        + *
      • long
      • + *
      • double
      • + *
      • bool
      • + *
      • Color
      • + *
      • int[]
      • + *
      • Point[]
      • + *
      + * + * @version $Revision: 1.8 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfShapeProperty : RtfAddableElement { + /** + * Property for defining an image. + */ + public const String PROPERTY_IMAGE = "pib"; + /** + * Property for defining vertices in freeform shapes. Requires a + * Point array as the value. + */ + public const String PROPERTY_VERTICIES = "pVerticies"; + /** + * Property for defining the minimum vertical coordinate that is + * visible. Requires a long value. + */ + public const String PROPERTY_GEO_TOP = "geoTop"; + /** + * Property for defining the minimum horizontal coordinate that is + * visible. Requires a long value. + */ + public const String PROPERTY_GEO_LEFT = "geoLeft"; + /** + * Property for defining the maximum horizontal coordinate that is + * visible. Requires a long value. + */ + public const String PROPERTY_GEO_RIGHT = "geoRight"; + /** + * Property for defining the maximum vertical coordinate that is + * visible. Requires a long value. + */ + public const String PROPERTY_GEO_BOTTOM = "geoBottom"; + /** + * Property for defining that the shape is in a table cell. Requires + * a bool value. + */ + public const String PROPERTY_LAYOUT_IN_CELL = "fLayoutInCell"; + /** + * Property for signalling a vertical flip of the shape. Requires a + * bool value. + */ + public const String PROPERTY_FLIP_V = "fFlipV"; + /** + * Property for signalling a horizontal flip of the shape. Requires a + * bool value. + */ + public const String PROPERTY_FLIP_H = "fFlipH"; + /** + * Property for defining the fill color of the shape. Requires a + * Color value. + */ + public const String PROPERTY_FILL_COLOR = "fillColor"; + /** + * Property for defining the line color of the shape. Requires a + * Color value. + */ + public const String PROPERTY_LINE_COLOR = "lineColor"; + /** + * Property for defining the first adjust handle for shapes. Used + * with the rounded rectangle. Requires a long value. + */ + public const String PROPERTY_ADJUST_VALUE = "adjustValue"; + + /** + * The stored value is a long. + */ + private const int PROPERTY_TYPE_LONG = 1; + /** + * The stored value is bool. + */ + private const int PROPERTY_TYPE_BOOLEAN = 2; + /** + * The stored value is a double. + */ + private const int PROPERTY_TYPE_DOUBLE = 3; + /** + * The stored value is a Color. + */ + private const int PROPERTY_TYPE_COLOR = 4; + /** + * The stored value is either an int or a Point array. + */ + private const int PROPERTY_TYPE_ARRAY = 5; + /** + * The stored value is an Image. + */ + private const int PROPERTY_TYPE_IMAGE = 6; + + /** + * The value type. + */ + private int type = 0; + /** + * The RtfShapeProperty name. + */ + private String name = ""; + /** + * The RtfShapeProperty value. + */ + private Object value = null; + + /** + * Internaly used to create the RtfShape. + * + * @param name The property name to use. + * @param value The property value to use. + */ + private RtfShapeProperty(String name, Object value) { + this.name = name; + this.value = value; + } + + /** + * Constructs a RtfShapeProperty with a long value. + * + * @param name The property name to use. + * @param value The long value to use. + */ + public RtfShapeProperty(String name, long value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_LONG; + } + + /** + * Constructs a RtfShapeProperty with a double value. + * + * @param name The property name to use. + * @param value The double value to use. + */ + public RtfShapeProperty(String name, double value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_DOUBLE; + } + + /** + * Constructs a RtfShapeProperty with a bool value. + * + * @param name The property name to use. + * @param value The bool value to use. + */ + public RtfShapeProperty(String name, bool value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_BOOLEAN; + } + + /** + * Constructs a RtfShapeProperty with a Color value. + * + * @param name The property name to use. + * @param value The Color value to use. + */ + public RtfShapeProperty(String name, Color value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_COLOR; + } + + /** + * Constructs a RtfShapeProperty with an int array value. + * + * @param name The property name to use. + * @param value The int array to use. + */ + public RtfShapeProperty(String name, int[] value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_ARRAY; + } + + /** + * Constructs a RtfShapeProperty with a Point array value. + * + * @param name The property name to use. + * @param value The Point array to use. + */ + public RtfShapeProperty(String name, Point[] value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_ARRAY; + } + + /** + * Constructs a RtfShapeProperty with an Image value. + * + * @param name The property name to use. + * @param value The Image to use. + */ + public RtfShapeProperty(String name, Image value) { + this.name = name; + this.value = value; + this.type = PROPERTY_TYPE_IMAGE; + } + + /** + * Gets the name of this RtfShapeProperty. + * + * @return The name of this RtfShapeProperty. + */ + public String GetName() { + return this.name; + } + + /** + * Write this RtfShapePosition. + */ + public override void WriteContent(Stream result) { + byte[] t; + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + result.Write(t = DocWriter.GetISOBytes("\\sp"), 0, t.Length); + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + result.Write(t = DocWriter.GetISOBytes("\\sn"), 0, t.Length); + result.Write(RtfElement.DELIMITER, 0, RtfElement.DELIMITER.Length); + result.Write(t = DocWriter.GetISOBytes(this.name), 0, t.Length); + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + result.Write(t = DocWriter.GetISOBytes("\\sv"), 0, t.Length); + result.Write(RtfElement.DELIMITER, 0, RtfElement.DELIMITER.Length); + switch (this.type) { + case PROPERTY_TYPE_LONG: + case PROPERTY_TYPE_DOUBLE: + result.Write(t = DocWriter.GetISOBytes(this.value.ToString()), 0, t.Length); + break; + case PROPERTY_TYPE_BOOLEAN: + if ((bool)this.value) { + result.Write(t = DocWriter.GetISOBytes("1"), 0, t.Length); + } else { + result.Write(t = DocWriter.GetISOBytes("0"), 0, t.Length); + } + break; + case PROPERTY_TYPE_COLOR: + Color color = (Color) this.value; + result.Write(t = IntToByteArray(color.R | (color.G << 8) | (color.B << 16)), 0, t.Length); + break; + case PROPERTY_TYPE_ARRAY: + if (this.value is int[]) { + int[] values = (int[]) this.value; + result.Write(t = DocWriter.GetISOBytes("4;"), 0, t.Length); + result.Write(t = IntToByteArray(values.Length), 0, t.Length); + result.Write(RtfElement.COMMA_DELIMITER, 0, RtfElement.COMMA_DELIMITER.Length); + for (int i = 0; i < values.Length; i++) { + result.Write(t = IntToByteArray(values[i]), 0, t.Length); + if (i < values.Length - 1) { + result.Write(RtfElement.COMMA_DELIMITER, 0, RtfElement.COMMA_DELIMITER.Length); + } + } + } else if (this.value is Point[]) { + Point[] values = (Point[]) this.value; + result.Write(t = DocWriter.GetISOBytes("8;"), 0, t.Length); + result.Write(t = IntToByteArray(values.Length), 0, t.Length); + result.Write(RtfElement.COMMA_DELIMITER, 0, RtfElement.COMMA_DELIMITER.Length); + for (int i = 0; i < values.Length; i++) { + result.Write(t = DocWriter.GetISOBytes("("), 0, t.Length); + result.Write(t = IntToByteArray(values[i].X), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes(","), 0, t.Length); + result.Write(t = IntToByteArray(values[i].Y), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes(")"), 0, t.Length); + if (i < values.Length - 1) { + result.Write(RtfElement.COMMA_DELIMITER, 0, RtfElement.COMMA_DELIMITER.Length); + } + } + } + break; + case PROPERTY_TYPE_IMAGE: + Image image = (Image)this.value; + RtfImage img = new RtfImage(this.doc, image); + img.SetTopLevelElement(true); + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + img.WriteContent(result); + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + break; + } + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooter.cs b/iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooter.cs new file mode 100644 index 0000000..22c46d6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooter.cs @@ -0,0 +1,326 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using FD = iTextSharp.text.rtf.field; +/* + * Created on Aug 10, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +namespace iTextSharp.text.rtf.headerfooter { + + /** + * The RtfHeaderFooter represents one header or footer. This class can be used + * directly. + * + * @version $Id: RtfHeaderFooter.cs,v 1.7 2008/05/16 19:30:59 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfHeaderFooter : HeaderFooter, IRtfBasicElement { + + /** + * Constant for the header type + */ + public const int TYPE_HEADER = 1; + /** + * Constant for the footer type + */ + public const int TYPE_FOOTER = 2; + /** + * Constant for displaying the header/footer on the first page + */ + public const int DISPLAY_FIRST_PAGE = 0; + /** + * Constant for displaying the header/footer on all pages + */ + public const int DISPLAY_ALL_PAGES = 1; + /** + * Constant for displaying the header/footer on all left hand pages + */ + public const int DISPLAY_LEFT_PAGES = 2; + /** + * Constant for displaying the header/footer on all right hand pages + */ + public const int DISPLAY_RIGHT_PAGES = 4; + + /** + * Constant for a header on all pages + */ + private static byte[] HEADER_ALL = DocWriter.GetISOBytes("\\header"); + /** + * Constant for a header on the first page + */ + private static byte[] HEADER_FIRST = DocWriter.GetISOBytes("\\headerf"); + /** + * Constant for a header on all left hand pages + */ + private static byte[] HEADER_LEFT = DocWriter.GetISOBytes("\\headerl"); + /** + * Constant for a header on all right hand pages + */ + private static byte[] HEADER_RIGHT = DocWriter.GetISOBytes("\\headerr"); + /** + * Constant for a footer on all pages + */ + private static byte[] FOOTER_ALL = DocWriter.GetISOBytes("\\footer"); + /** + * Constant for a footer on the first page + */ + private static byte[] FOOTER_FIRST = DocWriter.GetISOBytes("\\footerf"); + /** + * Constnat for a footer on the left hand pages + */ + private static byte[] FOOTER_LEFT = DocWriter.GetISOBytes("\\footerl"); + /** + * Constant for a footer on the right hand pages + */ + private static byte[] FOOTER_RIGHT = DocWriter.GetISOBytes("\\footerr"); + + /** + * The RtfDocument this RtfHeaderFooter belongs to + */ + private RtfDocument document = null; + /** + * The content of this RtfHeaderFooter + */ + private Object[] content = null; + /** + * The display type of this RtfHeaderFooter. TYPE_HEADER or TYPE_FOOTER + */ + private int type = TYPE_HEADER; + /** + * The display location of this RtfHeaderFooter. DISPLAY_FIRST_PAGE, + * DISPLAY_LEFT_PAGES, DISPLAY_RIGHT_PAGES or DISPLAY_ALL_PAGES + */ + private int displayAt = DISPLAY_ALL_PAGES; + + /** + * Constructs a RtfHeaderFooter based on a HeaderFooter with a certain type and displayAt + * location. For internal use only. + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param headerFooter The HeaderFooter to base this RtfHeaderFooter on + * @param type The type of RtfHeaderFooter + * @param displayAt The display location of this RtfHeaderFooter + */ + protected internal RtfHeaderFooter(RtfDocument doc, HeaderFooter headerFooter, int type, int displayAt) : base(new Phrase(""), false) { + this.document = doc; + this.type = type; + this.displayAt = displayAt; + Paragraph par = new Paragraph(); + par.Alignment = headerFooter.Alignment; + if (headerFooter.Before != null) { + par.Add(headerFooter.Before); + } + if (headerFooter.IsNumbered()) { + par.Add(new FD.RtfPageNumber(this.document)); + } + if (headerFooter.After != null) { + par.Add(headerFooter.After); + } + try { + this.content = new Object[1]; + if (this.document != null) { + this.content[0] = this.document.GetMapper().MapElement(par)[0]; + ((IRtfBasicElement) this.content[0]).SetInHeader(true); + } else { + this.content[0] = par; + } + } catch (DocumentException) { + } + } + + /** + * Constructs a RtfHeaderFooter as a copy of an existing RtfHeaderFooter. + * For internal use only. + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param headerFooter The RtfHeaderFooter to copy + * @param displayAt The display location of this RtfHeaderFooter + */ + protected internal RtfHeaderFooter(RtfDocument doc, RtfHeaderFooter headerFooter, int displayAt) : base(new Phrase(""), false) { + this.document = doc; + this.content = headerFooter.GetContent(); + this.displayAt = displayAt; + for (int i = 0; i < this.content.Length; i++) { + if (this.content[i] is IElement) { + try { + this.content[i] = this.document.GetMapper().MapElement((IElement) this.content[i])[0]; + } catch (DocumentException) { + } + } + if (this.content[i] is IRtfBasicElement) { + ((IRtfBasicElement) this.content[i]).SetInHeader(true); + } + } + } + + /** + * Constructs a RtfHeaderFooter for a HeaderFooter. + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param headerFooter The HeaderFooter to base this RtfHeaderFooter on + */ + protected internal RtfHeaderFooter(RtfDocument doc, HeaderFooter headerFooter) : base(new Phrase(""), false) { + this.document = doc; + Paragraph par = new Paragraph(); + par.Alignment = headerFooter.Alignment; + if (headerFooter.Before != null) { + par.Add(headerFooter.Before); + } + if (headerFooter.IsNumbered()) { + par.Add(new FD.RtfPageNumber(this.document)); + } + if (headerFooter.After != null) { + par.Add(headerFooter.After); + } + try { + this.content = new Object[1]; + this.content[0] = doc.GetMapper().MapElement(par)[0]; + ((IRtfBasicElement) this.content[0]).SetInHeader(true); + } catch (DocumentException) { + } + } + + /** + * Constructs a RtfHeaderFooter for any Element. + * + * @param element The Element to display as content of this RtfHeaderFooter + */ + public RtfHeaderFooter(IElement element) : this(new IElement[]{element}) { + } + + /** + * Constructs a RtfHeaderFooter for an array of Elements. + * + * @param elements The Elements to display as the content of this RtfHeaderFooter. + */ + public RtfHeaderFooter(IElement[] elements) : base(new Phrase(""), false){ + this.content = new Object[elements.Length]; + for (int i = 0; i < elements.Length; i++) { + this.content[i] = elements[i]; + } + } + + /** + * Sets the RtfDocument this RtfElement belongs to + * + * @param doc The RtfDocument to use + */ + public void SetRtfDocument(RtfDocument doc) { + this.document = doc; + if (this.document != null) { + for (int i = 0; i < this.content.Length; i++) { + try { + if (this.content[i] is Element) { + this.content[i] = this.document.GetMapper().MapElement((IElement) this.content[i])[0]; + ((IRtfBasicElement) this.content[i]).SetInHeader(true); + } else if (this.content[i] is IRtfBasicElement){ + ((IRtfBasicElement) this.content[i]).SetRtfDocument(this.document); + ((IRtfBasicElement) this.content[i]).SetInHeader(true); + } + } catch (DocumentException) { + } + } + } + } + + /** + * Write the content of this RtfHeaderFooter. + */ + public virtual void WriteContent(Stream result) { + result.Write(RtfElement.OPEN_GROUP, 0, RtfElement.OPEN_GROUP.Length); + if (this.type == TYPE_HEADER) { + if (this.displayAt == DISPLAY_ALL_PAGES) { + result.Write(HEADER_ALL, 0, HEADER_ALL.Length); + } else if (this.displayAt == DISPLAY_FIRST_PAGE) { + result.Write(HEADER_FIRST, 0, HEADER_FIRST.Length); + } else if (this.displayAt == DISPLAY_LEFT_PAGES) { + result.Write(HEADER_LEFT, 0, HEADER_LEFT.Length); + } else if (this.displayAt == DISPLAY_RIGHT_PAGES) { + result.Write(HEADER_RIGHT, 0, HEADER_RIGHT.Length); + } + } else { + if (this.displayAt == DISPLAY_ALL_PAGES) { + result.Write(FOOTER_ALL, 0, FOOTER_ALL.Length); + } else if (this.displayAt == DISPLAY_FIRST_PAGE) { + result.Write(FOOTER_FIRST, 0, FOOTER_FIRST.Length); + } else if (this.displayAt == DISPLAY_LEFT_PAGES) { + result.Write(FOOTER_LEFT, 0, FOOTER_LEFT.Length); + } else if (this.displayAt == DISPLAY_RIGHT_PAGES) { + result.Write(FOOTER_RIGHT, 0, FOOTER_RIGHT.Length); + } + } + result.Write(RtfElement.DELIMITER, 0, RtfElement.DELIMITER.Length); + for (int i = 0; i < this.content.Length; i++) { + if (this.content[i] is IRtfBasicElement) { + IRtfBasicElement rbe = (IRtfBasicElement)this.content[i]; + rbe.WriteContent(result); + } + } + result.Write(RtfElement.CLOSE_GROUP, 0, RtfElement.CLOSE_GROUP.Length); + } + + + /** + * Sets the display location of this RtfHeaderFooter + * + * @param displayAt The display location to use. + */ + public void SetDisplayAt(int displayAt) { + this.displayAt = displayAt; + } + + /** + * Sets the type of this RtfHeaderFooter + * + * @param type The type to use. + */ + public void SetType(int type) { + this.type = type; + } + + /** + * Gets the content of this RtfHeaderFooter + * + * @return The content of this RtfHeaderFooter + */ + private Object[] GetContent() { + return this.content; + } + + /** + * Unused + * @param inTable + */ + public void SetInTable(bool inTable) { + } + + /** + * Unused + * @param inHeader + */ + public void SetInHeader(bool inHeader) { + } + + /** + * Set the alignment of this RtfHeaderFooter. Passes the setting + * on to the contained element. + */ + public void SetAlignment(int alignment) { + base.Alignment = alignment; + for (int i = 0; i < this.content.Length; i++) { + if (this.content[i] is Paragraph) { + ((Paragraph) this.content[i]).Alignment = alignment; + } else if (this.content[i] is Table) { + ((Table) this.content[i]).Alignment = alignment; + } else if (this.content[i] is Image) { + ((Image) this.content[i]).Alignment = alignment; + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooterGroup.cs b/iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooterGroup.cs new file mode 100644 index 0000000..0b0f4c0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooterGroup.cs @@ -0,0 +1,377 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * Created on Aug 6, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +namespace iTextSharp.text.rtf.headerfooter { + + /** + * The RtfHeaderFooterGroup holds 0 - 3 RtfHeaderFooters that create a group + * of headers or footers. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfHeaderFooterGroup : HeaderFooter, IRtfBasicElement { + + /** + * This RtfHeaderFooterGroup contains no RtfHeaderFooter objects + */ + private const int MODE_NONE = 0; + /** + * This RtfHeaderFooterGroup contains one RtfHeaderFooter object + */ + private const int MODE_SINGLE = 1; + /** + * This RtfHeaderFooterGroup contains two or three RtfHeaderFooter objects + */ + private const int MODE_MULTIPLE = 2; + + /** + * The current mode of this RtfHeaderFooterGroup. Defaults to MODE_NONE + */ + private int mode = MODE_NONE; + /** + * The current type of this RtfHeaderFooterGroup. Defaults to RtfHeaderFooter.TYPE_HEADER + */ + private int type = RtfHeaderFooter.TYPE_HEADER; + + /** + * The RtfHeaderFooter for all pages + */ + private RtfHeaderFooter headerAll = null; + /** + * The RtfHeaderFooter for the first page + */ + private RtfHeaderFooter headerFirst = null; + /** + * The RtfHeaderFooter for the left hand pages + */ + private RtfHeaderFooter headerLeft = null; + /** + * The RtfHeaderFooter for the right hand pages + */ + private RtfHeaderFooter headerRight = null; + /** + * The RtfDocument this RtfHeaderFooterGroup belongs to + */ + private RtfDocument document = null; + + /** + * Constructs a RtfHeaderGroup to which you add headers/footers using + * via the setHeaderFooter method. + * + */ + public RtfHeaderFooterGroup() : base(new Phrase(""), false) { + this.mode = MODE_NONE; + } + + /** + * Constructs a certain type of RtfHeaderFooterGroup. RtfHeaderFooter.TYPE_HEADER + * and RtfHeaderFooter.TYPE_FOOTER are valid values for type. + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param type The type of RtfHeaderFooterGroup to create + */ + public RtfHeaderFooterGroup(RtfDocument doc, int type) : base(new Phrase(""), false) { + this.document = doc; + this.type = type; + } + + /** + * Constructs a RtfHeaderFooterGroup by copying the content of the original + * RtfHeaderFooterGroup + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param headerFooter The RtfHeaderFooterGroup to copy + * @param type The type of RtfHeaderFooterGroup to create + */ + public RtfHeaderFooterGroup(RtfDocument doc, RtfHeaderFooterGroup headerFooter, int type) : base(new Phrase(""), false) { + this.document = doc; + this.mode = headerFooter.GetMode(); + this.type = type; + if (headerFooter.GetHeaderAll() != null) { + this.headerAll = new RtfHeaderFooter(this.document, headerFooter.GetHeaderAll(), RtfHeaderFooter.DISPLAY_ALL_PAGES); + } + if (headerFooter.GetHeaderFirst() != null) { + this.headerFirst = new RtfHeaderFooter(this.document, headerFooter.GetHeaderFirst(), RtfHeaderFooter.DISPLAY_FIRST_PAGE); + } + if (headerFooter.GetHeaderLeft() != null) { + this.headerLeft = new RtfHeaderFooter(this.document, headerFooter.GetHeaderLeft(), RtfHeaderFooter.DISPLAY_LEFT_PAGES); + } + if (headerFooter.GetHeaderRight() != null) { + this.headerRight = new RtfHeaderFooter(this.document, headerFooter.GetHeaderRight(), RtfHeaderFooter.DISPLAY_RIGHT_PAGES); + } + SetType(this.type); + } + + /** + * Constructs a RtfHeaderFooterGroup for a certain RtfHeaderFooter. + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param headerFooter The RtfHeaderFooter to display + * @param type The typ of RtfHeaderFooterGroup to create + */ + public RtfHeaderFooterGroup(RtfDocument doc, RtfHeaderFooter headerFooter, int type) : base(new Phrase(""), false) { + this.document = doc; + this.type = type; + this.mode = MODE_SINGLE; + headerAll = new RtfHeaderFooter(doc, headerFooter, RtfHeaderFooter.DISPLAY_ALL_PAGES); + headerAll.SetType(this.type); + } + + /** + * Constructs a RtfHeaderGroup for a certain HeaderFooter + * + * @param doc The RtfDocument this RtfHeaderFooter belongs to + * @param headerFooter The HeaderFooter to display + * @param type The typ of RtfHeaderFooterGroup to create + */ + public RtfHeaderFooterGroup(RtfDocument doc, HeaderFooter headerFooter, int type) : base(new Phrase(""), false) { + this.document = doc; + this.type = type; + this.mode = MODE_SINGLE; + headerAll = new RtfHeaderFooter(doc, headerFooter, type, RtfHeaderFooter.DISPLAY_ALL_PAGES); + headerAll.SetType(this.type); + } + + /** + * Sets the RtfDocument this RtfElement belongs to + * + * @param doc The RtfDocument to use + */ + public void SetRtfDocument(RtfDocument doc) { + this.document = doc; + if (headerAll != null) { + headerAll.SetRtfDocument(this.document); + } + if (headerFirst != null) { + headerFirst.SetRtfDocument(this.document); + } + if (headerLeft != null) { + headerLeft.SetRtfDocument(this.document); + } + if (headerRight != null) { + headerRight.SetRtfDocument(this.document); + } + } + + /** + * Write the content of this RtfHeaderFooterGroup. + */ + public virtual void WriteContent(Stream result) { + if (this.mode == MODE_SINGLE) { + headerAll.WriteContent(result); + } else if (this.mode == MODE_MULTIPLE) { + if (headerFirst != null) { + headerFirst.WriteContent(result); + } + if (headerLeft != null) { + headerLeft.WriteContent(result); + } + if (headerRight != null) { + headerRight.WriteContent(result); + } + if (headerAll != null) { + headerAll.WriteContent(result); + } + } + } + + /** + * Set a RtfHeaderFooter to be displayed at a certain position + * + * @param headerFooter The RtfHeaderFooter to display + * @param displayAt The display location to use + */ + public void SetHeaderFooter(RtfHeaderFooter headerFooter, int displayAt) { + this.mode = MODE_MULTIPLE; + headerFooter.SetRtfDocument(this.document); + headerFooter.SetType(this.type); + headerFooter.SetDisplayAt(displayAt); + switch (displayAt) { + case RtfHeaderFooter.DISPLAY_ALL_PAGES: + headerAll = headerFooter; + break; + case RtfHeaderFooter.DISPLAY_FIRST_PAGE: + headerFirst = headerFooter; + break; + case RtfHeaderFooter.DISPLAY_LEFT_PAGES: + headerLeft = headerFooter; + break; + case RtfHeaderFooter.DISPLAY_RIGHT_PAGES: + headerRight = headerFooter; + break; + } + } + + /** + * Set a HeaderFooter to be displayed at a certain position + * + * @param headerFooter The HeaderFooter to set + * @param displayAt The display location to use + */ + public void SetHeaderFooter(HeaderFooter headerFooter, int displayAt) { + this.mode = MODE_MULTIPLE; + switch (displayAt) { + case RtfHeaderFooter.DISPLAY_ALL_PAGES: + headerAll = new RtfHeaderFooter(this.document, headerFooter, this.type, displayAt); + break; + case RtfHeaderFooter.DISPLAY_FIRST_PAGE: + headerFirst = new RtfHeaderFooter(this.document, headerFooter, this.type, displayAt); + break; + case RtfHeaderFooter.DISPLAY_LEFT_PAGES: + headerLeft = new RtfHeaderFooter(this.document, headerFooter, this.type, displayAt); + break; + case RtfHeaderFooter.DISPLAY_RIGHT_PAGES: + headerRight = new RtfHeaderFooter(this.document, headerFooter, this.type, displayAt); + break; + } + } + + /** + * Set that this RtfHeaderFooterGroup should have a title page. If only + * a header / footer for all pages exists, then it will be copied to the + * first page aswell. + */ + public void SetHasTitlePage() { + if (this.mode == MODE_SINGLE) { + this.mode = MODE_MULTIPLE; + headerFirst = new RtfHeaderFooter(this.document, headerAll, RtfHeaderFooter.DISPLAY_FIRST_PAGE); + headerFirst.SetType(this.type); + } + } + + /** + * Set that this RtfHeaderFooterGroup should have facing pages. If only + * a header / footer for all pages exists, then it will be copied to the left + * and right pages aswell. + */ + public void SetHasFacingPages() { + if (this.mode == MODE_SINGLE) { + this.mode = MODE_MULTIPLE; + this.headerLeft = new RtfHeaderFooter(this.document, this.headerAll, RtfHeaderFooter.DISPLAY_LEFT_PAGES); + this.headerLeft.SetType(this.type); + this.headerRight = new RtfHeaderFooter(this.document, this.headerAll, RtfHeaderFooter.DISPLAY_RIGHT_PAGES); + this.headerRight.SetType(this.type); + this.headerAll = null; + } else if (this.mode == MODE_MULTIPLE) { + if (this.headerLeft == null && this.headerAll != null) { + this.headerLeft = new RtfHeaderFooter(this.document, this.headerAll, RtfHeaderFooter.DISPLAY_LEFT_PAGES); + this.headerLeft.SetType(this.type); + } + if (this.headerRight == null && this.headerAll != null) { + this.headerRight = new RtfHeaderFooter(this.document, this.headerAll, RtfHeaderFooter.DISPLAY_RIGHT_PAGES); + this.headerRight.SetType(this.type); + } + this.headerAll = null; + } + } + + /** + * Get whether this RtfHeaderFooterGroup has a titlepage + * + * @return Whether this RtfHeaderFooterGroup has a titlepage + */ + public bool HasTitlePage() { + return (headerFirst != null); + } + + /** + * Get whether this RtfHeaderFooterGroup has facing pages + * + * @return Whether this RtfHeaderFooterGroup has facing pages + */ + public bool HasFacingPages() { + return (headerLeft != null || headerRight != null); + } + + /** + * Unused + * @param inTable + */ + public void SetInTable(bool inTable) { + } + + /** + * Unused + * @param inHeader + */ + public void SetInHeader(bool inHeader) { + } + + /** + * Set the type of this RtfHeaderFooterGroup. RtfHeaderFooter.TYPE_HEADER + * or RtfHeaderFooter.TYPE_FOOTER. Also sets the type for all RtfHeaderFooters + * of this RtfHeaderFooterGroup. + * + * @param type The type to use + */ + public void SetType(int type) { + this.type = type; + if (headerAll != null) { + headerAll.SetType(this.type); + } + if (headerFirst != null) { + headerFirst.SetType(this.type); + } + if (headerLeft != null) { + headerLeft.SetType(this.type); + } + if (headerRight != null) { + headerRight.SetType(this.type); + } + } + + /** + * Gets the mode of this RtfHeaderFooterGroup + * + * @return The mode of this RtfHeaderFooterGroup + */ + protected int GetMode() { + return this.mode; + } + + /** + * Gets the RtfHeaderFooter for all pages + * + * @return The RtfHeaderFooter for all pages + */ + protected RtfHeaderFooter GetHeaderAll() { + return headerAll; + } + + /** + * Gets the RtfHeaderFooter for the title page + * + * @return The RtfHeaderFooter for the title page + */ + protected RtfHeaderFooter GetHeaderFirst() { + return headerFirst; + } + + /** + * Gets the RtfHeaderFooter for all left hand pages + * + * @return The RtfHeaderFooter for all left hand pages + */ + protected RtfHeaderFooter GetHeaderLeft() { + return headerLeft; + } + + /** + * Gets the RtfHeaderFooter for all right hand pages + * + * @return The RtfHeaderFooter for all right hand pages + */ + protected RtfHeaderFooter GetHeaderRight() { + return headerRight; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/list/RtfList.cs b/iTechSharp/iTextSharp/text/rtf/list/RtfList.cs new file mode 100644 index 0000000..fbea7fb --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/list/RtfList.cs @@ -0,0 +1,629 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using ST = iTextSharp.text.rtf.style; +using iTextSharp.text.rtf.text; +using iTextSharp.text.factories; +/* + * $Id: RtfList.cs,v 1.18 2008/05/16 19:31:01 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004, 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the 'GNU LIBRARY GENERAL PUBLIC LICENSE'), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.list { + + /** + * The RtfList stores one List. It also provides the methods to write the + * list declaration and the list data. + * + * @version $Id: RtfList.cs,v 1.18 2008/05/16 19:31:01 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Thomas Bickel (tmb99@inode.at) + * @author Felix Satyaputra (f_satyaputra@yahoo.co.uk) + */ + public class RtfList : RtfElement, IRtfExtendedElement { + + /** + * Constant for list level + */ + private static byte[] LIST_LEVEL = DocWriter.GetISOBytes("\\listlevel"); + /** + * Constant for list level style old + */ + private static byte[] LIST_LEVEL_TYPE = DocWriter.GetISOBytes("\\levelnfc"); + /** + * Constant for list level style new + */ + private static byte[] LIST_LEVEL_TYPE_NEW = DocWriter.GetISOBytes("\\levelnfcn"); + /** + * Constant for list level alignment old + */ + private static byte[] LIST_LEVEL_ALIGNMENT = DocWriter.GetISOBytes("\\leveljc"); + /** + * Constant for list level alignment new + */ + private static byte[] LIST_LEVEL_ALIGNMENT_NEW = DocWriter.GetISOBytes("\\leveljcn"); + /** + * Constant for list level start at + */ + private static byte[] LIST_LEVEL_START_AT = DocWriter.GetISOBytes("\\levelstartat"); + /** + * Constant for list level text + */ + private static byte[] LIST_LEVEL_TEXT = DocWriter.GetISOBytes("\\leveltext"); + /** + * Constant for the beginning of the list level numbered style + */ + private static byte[] LIST_LEVEL_STYLE_NUMBERED_BEGIN = DocWriter.GetISOBytes("\\\'02\\\'"); + /** + * Constant for the end of the list level numbered style + */ + private static byte[] LIST_LEVEL_STYLE_NUMBERED_END = DocWriter.GetISOBytes(".;"); + /** + * Constant for the beginning of the list level bulleted style + */ + private static byte[] LIST_LEVEL_STYLE_BULLETED_BEGIN = DocWriter.GetISOBytes("\\\'01"); + /** + * Constant for the end of the list level bulleted style + */ + private static byte[] LIST_LEVEL_STYLE_BULLETED_END = DocWriter.GetISOBytes(";"); + /** + * Constant for the beginning of the list level numbers + */ + private static byte[] LIST_LEVEL_NUMBERS_BEGIN = DocWriter.GetISOBytes("\\levelnumbers"); + /** + * Constant for the list level numbers + */ + private static byte[] LIST_LEVEL_NUMBERS_NUMBERED = DocWriter.GetISOBytes("\\\'01"); + /** + * Constant for the end of the list level numbers + */ + private static byte[] LIST_LEVEL_NUMBERS_END = DocWriter.GetISOBytes(";"); + /** + * Constant for the first indentation + */ + private static byte[] LIST_LEVEL_FIRST_INDENT = DocWriter.GetISOBytes("\\fi"); + /** + * Constant for the symbol indentation + */ + private static byte[] LIST_LEVEL_SYMBOL_INDENT = DocWriter.GetISOBytes("\\tx"); + /** + * Constant for the list level value + */ + private static byte[] LIST_LEVEL_NUMBER = DocWriter.GetISOBytes("\\ilvl"); + /** + * Constant for a tab character + */ + private static byte[] TAB = DocWriter.GetISOBytes("\\tab"); + /** + * Constant for the old list text + */ + private static byte[] LIST_TEXT = DocWriter.GetISOBytes("\\listtext"); + /** + * Constant for the old list number end + */ + private static byte[] LIST_NUMBER_END = DocWriter.GetISOBytes("."); + + private const int LIST_TYPE_BULLET = 0; + private const int LIST_TYPE_NUMBERED = 1; + private const int LIST_TYPE_UPPER_LETTERS = 2; + private const int LIST_TYPE_LOWER_LETTERS = 3; + private const int LIST_TYPE_UPPER_ROMAN = 4; + private const int LIST_TYPE_LOWER_ROMAN = 5; + + /** + * The subitems of this RtfList + */ + private ArrayList items; + /** + * The level of this RtfList + */ + private int listLevel = 0; + /** + * The first indentation of this RtfList + */ + private int firstIndent = 0; + /** + * The left indentation of this RtfList + */ + private int leftIndent = 0; + /** + * The right indentation of this RtfList + */ + private int rightIndent = 0; + /** + * The symbol indentation of this RtfList + */ + private int symbolIndent = 0; + /** + * The list number of this RtfList + */ + private int listNumber = 1; + /** + * Whether this RtfList is numbered + */ + private int listType = LIST_TYPE_BULLET; + /** + * The number to start counting at + */ + private int listStartAt = 1; + /** + * The RtfFont for numbered lists + */ + private ST.RtfFont fontNumber; + /** + * The RtfFont for bulleted lists + */ + private ST.RtfFont fontBullet; + /** + * The alignment of this RtfList + */ + private int alignment = Element.ALIGN_LEFT; + + /** + * The parent List in multi-level lists. + */ + private RtfList parentList = null; + /** + * The text to use as the bullet character + */ + private String bulletCharacter = "\u00b7"; + + /** + * Constructs a new RtfList for the specified List. + * + * @param doc The RtfDocument this RtfList belongs to + * @param list The List this RtfList is based on + */ + public RtfList(RtfDocument doc, List list) : base(doc) { + + this.listNumber = document.GetDocumentHeader().GetListNumber(this); + + this.items = new ArrayList(); + if (list.SymbolIndent > 0 && list.IndentationLeft > 0) { + this.firstIndent = (int) (list.SymbolIndent * RtfElement.TWIPS_FACTOR * -1); + this.leftIndent = (int) ((list.IndentationLeft + list.SymbolIndent) * RtfElement.TWIPS_FACTOR); + } else if (list.SymbolIndent > 0) { + this.firstIndent = (int) (list.SymbolIndent * RtfElement.TWIPS_FACTOR * -1); + this.leftIndent = (int) (list.SymbolIndent * RtfElement.TWIPS_FACTOR); + } else if (list.IndentationLeft > 0) { + this.firstIndent = 0; + this.leftIndent = (int) (list.IndentationLeft * RtfElement.TWIPS_FACTOR); + } else { + this.firstIndent = 0; + this.leftIndent = 0; + } + this.rightIndent = (int) (list.IndentationRight * RtfElement.TWIPS_FACTOR); + this.symbolIndent = (int) ((list.SymbolIndent + list.IndentationLeft) * RtfElement.TWIPS_FACTOR); + if (list is RomanList) { + if (list.Lowercase) { + this.listType = LIST_TYPE_LOWER_ROMAN; + } else { + this.listType = LIST_TYPE_UPPER_ROMAN; + } + } else if (list.Numbered) { + this.listType = LIST_TYPE_NUMBERED; + } else if (list.Lettered) { + if (list.Lowercase) { + this.listType = LIST_TYPE_LOWER_LETTERS; + } else { + this.listType = LIST_TYPE_UPPER_LETTERS; + } + } + this.listStartAt = list.First; + if(this.listStartAt < 1) { + this.listStartAt = 1; + } + + for (int i = 0; i < list.Items.Count; i++) { + try { + IElement element = (IElement) list.Items[i]; + if (element.Type == Element.CHUNK) { + element = new ListItem((Chunk) element); + } + if (element is ListItem) { + this.alignment = ((ListItem) element).Alignment; + } + IRtfBasicElement[] rtfElements = doc.GetMapper().MapElement(element); + for(int j = 0; j < rtfElements.Length; j++) { + IRtfBasicElement rtfElement = rtfElements[j]; + if (rtfElement is RtfList) { + ((RtfList) rtfElement).SetListNumber(listNumber); + ((RtfList) rtfElement).SetListLevel(listLevel + 1); + ((RtfList) rtfElement).SetParent(this); + } else if (rtfElement is RtfListItem) { + ((RtfListItem) rtfElement).SetParent(this); + ((RtfListItem) rtfElement).InheritListSettings(listNumber, listLevel + 1); + } + items.Add(rtfElement); + } + } catch (DocumentException ) { + } + } + + fontNumber = new ST.RtfFont(document, new Font(Font.TIMES_ROMAN, 10, Font.NORMAL, new Color(0, 0, 0))); + if (list.Symbol != null && list.Symbol.Font != null && !list.Symbol.Content.StartsWith("-") && list.Symbol.Content.Length > 0) { + // only set this to bullet symbol is not default + this.fontBullet = new ST.RtfFont(document, list.Symbol.Font); + this.bulletCharacter = list.Symbol.Content.Substring(0, 1); + } else { + this.fontBullet = new ST.RtfFont(document, new Font(Font.SYMBOL, 10, Font.NORMAL, new Color(0, 0, 0))); + } + } + + /** + * Write the indentation values for this RtfList. + * + * @param result The OutputStream to write to. + * @throws IOException On i/o errors. + */ + private void WriteIndentation(Stream result) { + byte[] t; + result.Write(LIST_LEVEL_FIRST_INDENT, 0, LIST_LEVEL_FIRST_INDENT.Length); + result.Write(t = IntToByteArray(firstIndent), 0, t.Length); + result.Write(ST.RtfParagraphStyle.INDENT_LEFT, 0, ST.RtfParagraphStyle.INDENT_LEFT.Length); + result.Write(t = IntToByteArray(leftIndent), 0, t.Length); + result.Write(ST.RtfParagraphStyle.INDENT_RIGHT, 0, ST.RtfParagraphStyle.INDENT_RIGHT.Length); + result.Write(t = IntToByteArray(rightIndent), 0, t.Length); + } + + /** + * Writes the definition part of this list level + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_LEVEL, 0, LIST_LEVEL.Length); + result.Write(LIST_LEVEL_TYPE, 0, LIST_LEVEL_TYPE.Length); + switch (this.listType) { + case LIST_TYPE_BULLET : result.Write(t = IntToByteArray(23), 0, t.Length); break; + case LIST_TYPE_NUMBERED : result.Write(t = IntToByteArray(0), 0, t.Length); break; + case LIST_TYPE_UPPER_LETTERS : result.Write(t = IntToByteArray(3), 0, t.Length); break; + case LIST_TYPE_LOWER_LETTERS : result.Write(t = IntToByteArray(4), 0, t.Length); break; + case LIST_TYPE_UPPER_ROMAN : result.Write(t = IntToByteArray(1), 0, t.Length); break; + case LIST_TYPE_LOWER_ROMAN : result.Write(t = IntToByteArray(2), 0, t.Length); break; + } + result.Write(LIST_LEVEL_TYPE_NEW, 0, LIST_LEVEL_TYPE_NEW.Length); + switch (this.listType) { + case LIST_TYPE_BULLET : result.Write(t = IntToByteArray(23), 0, t.Length); break; + case LIST_TYPE_NUMBERED : result.Write(t = IntToByteArray(0), 0, t.Length); break; + case LIST_TYPE_UPPER_LETTERS : result.Write(t = IntToByteArray(3), 0, t.Length); break; + case LIST_TYPE_LOWER_LETTERS : result.Write(t = IntToByteArray(4), 0, t.Length); break; + case LIST_TYPE_UPPER_ROMAN : result.Write(t = IntToByteArray(1), 0, t.Length); break; + case LIST_TYPE_LOWER_ROMAN : result.Write(t = IntToByteArray(2), 0, t.Length); break; + } + result.Write(LIST_LEVEL_ALIGNMENT, 0, LIST_LEVEL_ALIGNMENT.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + result.Write(LIST_LEVEL_ALIGNMENT_NEW, 0, LIST_LEVEL_ALIGNMENT_NEW.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + result.Write(LIST_LEVEL_START_AT, 0, LIST_LEVEL_START_AT.Length); + result.Write(t = IntToByteArray(this.listStartAt), 0, t.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_LEVEL_TEXT, 0, LIST_LEVEL_TEXT.Length); + if (this.listType != LIST_TYPE_BULLET) { + result.Write(LIST_LEVEL_STYLE_NUMBERED_BEGIN, 0, LIST_LEVEL_STYLE_NUMBERED_BEGIN.Length); + if (listLevel < 10) { + result.Write(t = IntToByteArray(0), 0, t.Length); + } + result.Write(t = IntToByteArray(listLevel), 0, t.Length); + result.Write(LIST_LEVEL_STYLE_NUMBERED_END, 0, LIST_LEVEL_STYLE_NUMBERED_END.Length); + } else { + result.Write(LIST_LEVEL_STYLE_BULLETED_BEGIN, 0, LIST_LEVEL_STYLE_BULLETED_BEGIN.Length); + this.document.FilterSpecialChar(result, this.bulletCharacter, false, false); + result.Write(LIST_LEVEL_STYLE_BULLETED_END, 0, LIST_LEVEL_STYLE_BULLETED_END.Length); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_LEVEL_NUMBERS_BEGIN, 0, LIST_LEVEL_NUMBERS_BEGIN.Length); + if (this.listType != LIST_TYPE_BULLET) { + result.Write(LIST_LEVEL_NUMBERS_NUMBERED, 0, LIST_LEVEL_NUMBERS_NUMBERED.Length); + } + result.Write(LIST_LEVEL_NUMBERS_END, 0, LIST_LEVEL_NUMBERS_END.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(ST.RtfFontList.FONT_NUMBER, 0, ST.RtfFontList.FONT_NUMBER.Length); + if (this.listType != LIST_TYPE_BULLET) { + result.Write(t = IntToByteArray(fontNumber.GetFontNumber()), 0, t.Length); + } else { + result.Write(t = IntToByteArray(fontBullet.GetFontNumber()), 0, t.Length); + } + WriteIndentation(result); + result.Write(LIST_LEVEL_SYMBOL_INDENT, 0, LIST_LEVEL_SYMBOL_INDENT.Length); + result.Write(t = IntToByteArray(this.leftIndent), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + for (int i = 0; i < items.Count; i++) { + RtfElement rtfElement = (RtfElement) items[i]; + if (rtfElement is RtfList) { + RtfList rl = (RtfList)rtfElement; + rl.WriteDefinition(result); + break; + } else if (rtfElement is RtfListItem) { + RtfListItem rli = (RtfListItem) rtfElement; + if (rli.WriteDefinition(result)) break; + } + } + } + + /** + * Writes the initialisation part of the RtfList + * + * @return A byte array containing the initialisation part + */ + protected internal void WriteListBeginning(Stream result) { + byte[] t; + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + if (this.inTable) { + result.Write(RtfParagraph.IN_TABLE, 0, RtfParagraph.IN_TABLE.Length); + } + switch (this.alignment) { + case Element.ALIGN_LEFT: + result.Write(ST.RtfParagraphStyle.ALIGN_LEFT, 0, ST.RtfParagraphStyle.ALIGN_LEFT.Length); + break; + case Element.ALIGN_RIGHT: + result.Write(ST.RtfParagraphStyle.ALIGN_RIGHT, 0, ST.RtfParagraphStyle.ALIGN_RIGHT.Length); + break; + case Element.ALIGN_CENTER: + result.Write(ST.RtfParagraphStyle.ALIGN_CENTER, 0, ST.RtfParagraphStyle.ALIGN_CENTER.Length); + break; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + result.Write(ST.RtfParagraphStyle.ALIGN_JUSTIFY, 0, ST.RtfParagraphStyle.ALIGN_JUSTIFY.Length); + break; + } + WriteIndentation(result); + result.Write(ST.RtfFont.FONT_SIZE, 0, ST.RtfFont.FONT_SIZE.Length); + result.Write(t = IntToByteArray(fontNumber.GetFontSize() * 2), 0, t.Length); + if (this.symbolIndent > 0) { + result.Write(t = DocWriter.GetISOBytes("\\tx"), 0, t.Length); + result.Write(t = IntToByteArray(this.leftIndent), 0, t.Length); + } + } + + /** + * Writes only the list number and list level number. + * + * @return The list number and list level number of this RtfList. + */ + protected void WriteListNumbers(Stream result) { + byte[] t; + result.Write(RtfListTable.LIST_NUMBER, 0, RtfListTable.LIST_NUMBER.Length); + result.Write(t = IntToByteArray(listNumber), 0, t.Length); + if (listLevel > 0) { + result.Write(LIST_LEVEL_NUMBER, 0, LIST_LEVEL_NUMBER.Length); + result.Write(t = IntToByteArray(listLevel), 0, t.Length); + } + } + + /** + * Writes the content of the RtfList + */ + public override void WriteContent(Stream result) { + if (this.listLevel == 0) { + CorrectIndentation(); + } + byte[] t; + if (!this.inTable) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + } + int itemNr = 0; + for (int i = 0; i < items.Count; i++) { + RtfElement rtfElement = (RtfElement) items[i]; + if (rtfElement is RtfListItem) { + itemNr++; + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_TEXT, 0, LIST_TEXT.Length); + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + if (this.inTable) { + result.Write(RtfParagraph.IN_TABLE, 0, RtfParagraph.IN_TABLE.Length); + } + result.Write(ST.RtfFontList.FONT_NUMBER, 0, ST.RtfFontList.FONT_NUMBER.Length); + if (this.listType != LIST_TYPE_BULLET) { + result.Write(t = IntToByteArray(fontNumber.GetFontNumber()), 0, t.Length); + } else { + result.Write(t = IntToByteArray(fontBullet.GetFontNumber()), 0, t.Length); + } + WriteIndentation(result); + result.Write(DELIMITER, 0, DELIMITER.Length); + if (this.listType != LIST_TYPE_BULLET) { + switch (this.listType) { + case LIST_TYPE_NUMBERED : result.Write(t = IntToByteArray(itemNr), 0, t.Length); break; + case LIST_TYPE_UPPER_LETTERS : result.Write(t = DocWriter.GetISOBytes(RomanAlphabetFactory.GetUpperCaseString(itemNr)), 0, t.Length); break; + case LIST_TYPE_LOWER_LETTERS : result.Write(t = DocWriter.GetISOBytes(RomanAlphabetFactory.GetLowerCaseString(itemNr)), 0, t.Length); break; + case LIST_TYPE_UPPER_ROMAN : result.Write(t = DocWriter.GetISOBytes(RomanNumberFactory.GetUpperCaseString(itemNr)), 0, t.Length); break; + case LIST_TYPE_LOWER_ROMAN : result.Write(t = DocWriter.GetISOBytes(RomanNumberFactory.GetLowerCaseString(itemNr)), 0, t.Length); break; + } + result.Write(LIST_NUMBER_END, 0, LIST_NUMBER_END.Length); + } else { + this.document.FilterSpecialChar(result, this.bulletCharacter, true, false); + } + result.Write(TAB, 0, TAB.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + if (i == 0) { + WriteListBeginning(result); + WriteListNumbers(result); + } + rtfElement.WriteContent(result); + if (i < (items.Count - 1) || !this.inTable || this.listLevel > 0) { + result.Write(RtfParagraph.PARAGRAPH, 0, RtfParagraph.PARAGRAPH.Length); + } + result.WriteByte((byte)'\n'); + } else if (rtfElement is RtfList) { + rtfElement.WriteContent(result); + WriteListBeginning(result); + WriteListNumbers(result); + result.WriteByte((byte)'\n'); + } + } + if (!this.inTable) { + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + } + } + + + /** + * Gets the list level of this RtfList + * + * @return Returns the list level. + */ + public int GetListLevel() { + return listLevel; + } + + /** + * Sets the list level of this RtfList. A list level > 0 will + * unregister this RtfList from the RtfListTable + * + * @param listLevel The list level to set. + */ + public void SetListLevel(int listLevel) { + this.listLevel = listLevel; + if (this.listLevel != 0) { + document.GetDocumentHeader().FreeListNumber(this); + for (int i = 0; i < this.items.Count; i++) { + if (this.items[i] is RtfList) { + ((RtfList) this.items[i]).SetListNumber(this.listNumber); + ((RtfList) this.items[i]).SetListLevel(this.listLevel + 1); + } + } + } else { + this.listNumber = document.GetDocumentHeader().GetListNumber(this); + } + } + + /** + * Sets the parent RtfList of this RtfList + * + * @param parent The parent RtfList to use. + */ + protected internal void SetParent(RtfList parent) { + this.parentList = parent; + } + + /** + * Gets the id of this list + * + * @return Returns the list number. + */ + public int GetListNumber() { + return listNumber; + } + + /** + * Sets the id of this list + * + * @param listNumber The list number to set. + */ + public void SetListNumber(int listNumber) { + this.listNumber = listNumber; + } + + /** + * Sets whether this RtfList is in a table. Sets the correct inTable setting for all + * child elements. + * + * @param inTable True if this RtfList is in a table, false otherwise + */ + public override void SetInTable(bool inTable) { + base.SetInTable(inTable); + for (int i = 0; i < this.items.Count; i++) { + ((IRtfBasicElement) this.items[i]).SetInTable(inTable); + } + } + + /** + * Sets whether this RtfList is in a header. Sets the correct inTable setting for all + * child elements. + * + * @param inHeader True if this RtfList is in a header, false otherwise + */ + public override void SetInHeader(bool inHeader) { + base.SetInHeader(inHeader); + for (int i = 0; i < this.items.Count; i++) { + ((IRtfBasicElement) this.items[i]).SetInHeader(inHeader); + } + } + + /** + * Correct the indentation of this RtfList by adding left/first line indentation + * from the parent RtfList. Also calls correctIndentation on all child RtfLists. + */ + protected internal void CorrectIndentation() { + if (this.parentList != null) { + this.leftIndent = this.leftIndent + this.parentList.GetLeftIndent() + this.parentList.GetFirstIndent(); + } + for (int i = 0; i < this.items.Count; i++) { + if (this.items[i] is RtfList) { + ((RtfList) this.items[i]).CorrectIndentation(); + } else if (this.items[i] is RtfListItem) { + ((RtfListItem) this.items[i]).CorrectIndentation(); + } + } + } + + /** + * Get the left indentation of this RtfList. + * + * @return The left indentation. + */ + private int GetLeftIndent() { + return this.leftIndent; + } + + /** + * Get the first line indentation of this RtfList. + * + * @return The first line indentation. + */ + private int GetFirstIndent() { + return this.firstIndent; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/list/RtfListItem.cs b/iTechSharp/iTextSharp/text/rtf/list/RtfListItem.cs new file mode 100644 index 0000000..52f5f30 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/list/RtfListItem.cs @@ -0,0 +1,187 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.text; +using iTextSharp.text.rtf.style; +/* + * $Id: RtfListItem.cs,v 1.7 2008/05/16 19:31:02 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004, 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.list { + + /** + * The RtfListItem acts as a wrapper for a ListItem. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfListItem : RtfParagraph { + + /** + * The RtfList this RtfListItem belongs to. + */ + private RtfList parentList = null; + /** + * Whether this RtfListItem contains further RtfLists. + */ + private bool containsInnerList = false; + + /** + * Constructs a RtfListItem for a ListItem belonging to a RtfDocument. + * + * @param doc The RtfDocument this RtfListItem belongs to. + * @param listItem The ListItem this RtfListItem is based on. + */ + public RtfListItem(RtfDocument doc, ListItem listItem) : base(doc, listItem) { + } + + /** + * Writes the content of this RtfListItem. + */ + public override void WriteContent(Stream result) { + byte[] t; + if (this.paragraphStyle.GetSpacingBefore() > 0) { + result.Write(RtfParagraphStyle.SPACING_BEFORE, 0, RtfParagraphStyle.SPACING_BEFORE.Length); + result.Write(t = IntToByteArray(paragraphStyle.GetSpacingBefore()), 0, t.Length); + } + if (this.paragraphStyle.GetSpacingAfter() > 0) { + result.Write(RtfParagraphStyle.SPACING_AFTER, 0, RtfParagraphStyle.SPACING_AFTER.Length); + result.Write(t = IntToByteArray(this.paragraphStyle.GetSpacingAfter()), 0, t.Length); + } + for (int i = 0; i < chunks.Count; i++) { + IRtfBasicElement rtfElement = (IRtfBasicElement) chunks[i]; + if (rtfElement is RtfChunk) { + ((RtfChunk) rtfElement).SetSoftLineBreaks(true); + } else if (rtfElement is RtfList) { + result.Write(RtfParagraph.PARAGRAPH, 0, RtfParagraph.PARAGRAPH.Length); + this.containsInnerList = true; + } + rtfElement.WriteContent(result); + if (rtfElement is RtfList) { + this.parentList.WriteListBeginning(result); + result.Write(t = DocWriter.GetISOBytes("\\tab"), 0, t.Length); + } + } + } + + /** + * Writes the definition of the first element in this RtfListItem that is + * an instanceof {@link RtfList} to the given stream.
      + * If this item does not contain a {@link RtfList} element nothing is written + * and the method returns false. + * + * @param out destination stream + * @return true if a RtfList definition was written, false otherwise + * @throws IOException + * @see {@link RtfList#writeDefinition(OutputStream)} + */ + public bool WriteDefinition(Stream outp) { + for (int i = 0; i < chunks.Count; i++) { + IRtfBasicElement rtfElement = (IRtfBasicElement)chunks[i]; + if (rtfElement is RtfList) { + RtfList rl = (RtfList)rtfElement; + rl.WriteDefinition(outp); + return true; + } + } + return false; + } + + /** + * Inherit the list settings from the parent list to RtfLists that + * are contained in this RtfListItem. + * + * @param listNumber The list number to inherit. + * @param listLevel The list level to inherit. + */ + public void InheritListSettings(int listNumber, int listLevel) { + for (int i = 0; i < chunks.Count; i++) { + IRtfBasicElement rtfElement = (IRtfBasicElement) chunks[i]; + if (rtfElement is RtfList) { + ((RtfList) rtfElement).SetListNumber(listNumber); + ((RtfList) rtfElement).SetListLevel(listLevel); + ((RtfList) rtfElement).SetParent(this.parentList); + } + } + } + + /** + * Correct the indentation of RtfLists in this RtfListItem by adding left/first line indentation + * from the parent RtfList. Also calls correctIndentation on all child RtfLists. + */ + protected internal void CorrectIndentation() { + for (int i = 0; i < chunks.Count; i++) { + IRtfBasicElement rtfElement = (IRtfBasicElement) chunks[i]; + if (rtfElement is RtfList) { + ((RtfList) rtfElement).CorrectIndentation(); + } + } + } + + /** + * Set the parent RtfList. + * + * @param parentList The parent RtfList to use. + */ + public void SetParent(RtfList parentList) { + this.parentList = parentList; + } + + /** + * Gets whether this RtfListItem contains further RtfLists. + * + * @return Whether this RtfListItem contains further RtfLists. + */ + public bool IsContainsInnerList() { + return this.containsInnerList; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/list/RtfListTable.cs b/iTechSharp/iTextSharp/text/rtf/list/RtfListTable.cs new file mode 100644 index 0000000..799f8e4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/list/RtfListTable.cs @@ -0,0 +1,198 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfListTable.cs,v 1.6 2008/05/16 19:31:04 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.list { + + /** + * The RtfListTable manages all RtfLists in one RtfDocument. It also generates + * the list and list override tables in the document header. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfListTable : RtfElement, IRtfExtendedElement { + + /** + * Constant for the list number + */ + protected internal static byte[] LIST_NUMBER = DocWriter.GetISOBytes("\\ls"); + /** + * Constant for the list table + */ + private static byte[] LIST_TABLE = DocWriter.GetISOBytes("\\*\\listtable"); + /** + * Constant for the list + */ + private static byte[] LIST = DocWriter.GetISOBytes("\\list"); + /** + * Constant for the list template id + */ + private static byte[] LIST_TEMPLATE_ID = DocWriter.GetISOBytes("\\listtemplateid"); + /** + * Constant for the hybrid list + */ + private static byte[] LIST_HYBRID = DocWriter.GetISOBytes("\\listhybrid"); + /** + * Constant for the list id + */ + private static byte[] LIST_ID = DocWriter.GetISOBytes("\\listid"); + /** + * Constant for the list override table + */ + private static byte[] LIST_OVERRIDE_TABLE = DocWriter.GetISOBytes("\\*\\listoverridetable"); + /** + * Constant for the list override + */ + private static byte[] LIST_OVERRIDE = DocWriter.GetISOBytes("\\listoverride"); + /** + * Constant for the list override count + */ + private static byte[] LIST_OVERRIDE_COUNT = DocWriter.GetISOBytes("\\listoverridecount"); + + /** + * The RtfLists managed by this RtfListTable + */ + private ArrayList lists; + + /** + * Constructs a RtfListTable for a RtfDocument + * + * @param doc The RtfDocument this RtfListTable belongs to + */ + public RtfListTable(RtfDocument doc) : base(doc) { + this.lists = new ArrayList(); + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Writes the list and list override tables. + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + int[] listIds = new int[lists.Count]; + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_TABLE, 0, LIST_TABLE.Length); + result.WriteByte((byte)'\n'); + for (int i = 0; i < lists.Count; i++) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST, 0, LIST.Length); + result.Write(LIST_TEMPLATE_ID, 0, LIST_TEMPLATE_ID.Length); + result.Write(t = IntToByteArray(document.GetRandomInt()), 0, t.Length); + result.Write(LIST_HYBRID, 0, LIST_HYBRID.Length); + result.WriteByte((byte)'\n'); + RtfList rList = (RtfList)lists[i]; + rList.WriteDefinition(result); + result.Write(LIST_ID, 0, LIST_ID.Length); + listIds[i] = document.GetRandomInt(); + result.Write(t = IntToByteArray(listIds[i]), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_OVERRIDE_TABLE, 0, LIST_OVERRIDE_TABLE.Length); + result.WriteByte((byte)'\n'); + for (int i = 0; i < lists.Count; i++) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(LIST_OVERRIDE, 0, LIST_OVERRIDE.Length); + result.Write(LIST_ID, 0, LIST_ID.Length); + result.Write(t = IntToByteArray(listIds[i]), 0, t.Length); + result.Write(LIST_OVERRIDE_COUNT, 0, LIST_OVERRIDE_COUNT.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + result.Write(LIST_NUMBER, 0, LIST_NUMBER.Length); + result.Write(t = IntToByteArray(((RtfList) lists[i]).GetListNumber()), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + + /** + * Gets the id of the specified RtfList. If the RtfList is not yet in the + * list of RtfLists, then it is added. + * + * @param list The RtfList for which to get the id. + * @return The id of the RtfList. + */ + public int GetListNumber(RtfList list) { + if (lists.Contains(list)) { + return lists.IndexOf(list); + } else { + lists.Add(list); + return lists.Count; + } + } + + /** + * Remove a RtfList from the list of RtfLists + * + * @param list The RtfList to remove. + */ + public void FreeListNumber(RtfList list) { + int i = lists.IndexOf(list); + if (i >= 0) { + lists.RemoveAt(i); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/PushbackStream.cs b/iTechSharp/iTextSharp/text/rtf/parser/PushbackStream.cs new file mode 100644 index 0000000..98b1a4e --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/PushbackStream.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; + +namespace iTextSharp.text.rtf.parser { + public class PushbackStream : Stream { + private int buf = -1; + private readonly Stream s; + + public PushbackStream(Stream s) { + this.s = s; + } + + public override bool CanRead + { + get { return s.CanRead; } + } + public override bool CanSeek + { + get { return s.CanSeek; } + } + public override bool CanWrite + { + get { return s.CanWrite; } + } + public override long Length + { + get { return s.Length; } + } + public override long Position + { + get { return s.Position; } + set { s.Position = value; } + } + public override void Close() + { + s.Close(); + } + public override void Flush() + { + s.Flush(); + } + public override long Seek(long offset, SeekOrigin origin) + { + return s.Seek(offset, origin); + } + public override void SetLength(long value) + { + s.SetLength(value); + } + public override void Write(byte[] buffer, int offset, int count) + { + s.Write(buffer, offset, count); + } + public override void WriteByte(byte value) + { + s.WriteByte(value); + } + public override int ReadByte() { + if (buf != -1) { + int tmp = buf; + buf = -1; + return tmp; + } + + return s.ReadByte(); + } + + public override int Read(byte[] buffer, int offset, int count) { + if (buf != -1 && count > 0) { + // TODO Can this case be made more efficient? + buffer[offset] = (byte) buf; + buf = -1; + return 1; + } + + return s.Read(buffer, offset, count); + } + + public virtual void Unread(int b) { + if (buf != -1) + throw new InvalidOperationException("Can only push back one byte"); + + buf = b & 0xFF; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/RtfImportMappings.cs b/iTechSharp/iTextSharp/text/rtf/parser/RtfImportMappings.cs new file mode 100644 index 0000000..2c18f01 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/RtfImportMappings.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections; +using iTextSharp.text; + +/* + * $Id: RtfImportMappings.cs,v 1.3 2008/05/16 19:31:06 psoares33 Exp $ + * + * + * Copyright 2006 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser { + + /** + * The RtfImportMappings make it possible to define font + * and color mappings when using the RtfWriter2.importRtfFragment + * method. This is necessary, because a RTF fragment does not + * contain font or color information, just references to the + * font and color tables.

      + * + * The font mappings are fontNr -> fontName and the color + * mappigns are colorNr -> Color. + * + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Howard Shank (hgshank@yahoo.com) + */ + public class RtfImportMappings { + /** + * The fontNr to fontName mappings. + */ + private Hashtable fontMappings = null; + /** + * The colorNr to Color mappings. + */ + private Hashtable colorMappings = null; + /** + * The listNr to List mappings. + */ + private Hashtable listMappings = null; + /** + * The sytlesheetListNr to Stylesheet mappings. + */ + private Hashtable stylesheetListMappings = null; + + /** + * Constructs a new RtfImportMappings initialising the mappings. + */ + public RtfImportMappings() { + this.fontMappings = new Hashtable(); + this.colorMappings = new Hashtable(); + this.listMappings = new Hashtable(); + this.stylesheetListMappings = new Hashtable(); + } + + /** + * Add a font to the list of mappings. + * + * @param fontNr The font number. + * @param fontName The font name. + */ + public void AddFont(String fontNr, String fontName) { + this.fontMappings[fontNr] = fontName; + } + /** + * Add a color to the list of mappings. + * + * @param colorNr The color number. + * @param color The Color. + */ + public void AddColor(String colorNr, Color color) { + this.colorMappings[colorNr] = color; + } + /** + * Add a List to the list of mappings. + * + * @param listNr The List number. + * @param list The List. + */ + public void AddList(String listNr, Color list) { + this.listMappings[listNr] = list; + } + /** + * Add a Stylesheet List to the list of mappings. + * + * @param stylesheetListNr The Stylesheet List number. + * @param list The StylesheetList. + */ + public void AddStylesheetList(String stylesheetListNr, Color list) { + this.stylesheetListMappings[stylesheetListNr] = list; + } + + /** + * Gets the list of font mappings. String to String. + * + * @return The font mappings. + */ + public Hashtable GetFontMappings() { + return this.fontMappings; + } + + /** + * Gets the list of color mappings. String to Color. + * + * @return The color mappings. + */ + public Hashtable GetColorMappings() { + return this.colorMappings; + } + + /** + * Gets the list of List mappings. + * + * @return The List mappings. + */ + public Hashtable GetListMappings() { + return this.listMappings; + } + + /** + * Gets the list of Stylesheet mappings. . + * + * @return The Stylesheet List mappings. + */ + public Hashtable GetStylesheetListMappings() { + return this.stylesheetListMappings; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/RtfImportMgr.cs b/iTechSharp/iTextSharp/text/rtf/parser/RtfImportMgr.cs new file mode 100644 index 0000000..a263733 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/RtfImportMgr.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.list; +using iTextSharp.text.rtf.style; +/* + * $Id: RtfImportMgr.cs,v 1.3 2008/05/16 19:31:07 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser { + + /** + * The RtfImportHeader stores the docment header information from + * an RTF document that is being imported. Currently font and + * color settings are stored. The RtfImportHeader maintains a mapping + * from font and color numbers from the imported RTF document to + * the RTF document that is the target of the import. This guarantees + * that the merged document has the correct font and color settings. + * It also handles other list based items that need mapping, for example + * stylesheets and lists. + * + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Howard Shank (hgshank@yahoo.com) + */ + public class RtfImportMgr { + //TODO: Add list, stylesheet, info, etc. mappings + /** + * The Hashtable storing the font number mappings. + */ + private Hashtable importFontMapping = null; + /** + * The Hashtable storing the color number mapings. + */ + private Hashtable importColorMapping = null; + /** + * The Hashtable storing the Stylesheet List number mapings. + */ + private Hashtable importStylesheetListMapping = null; + /** + * The Hashtable storing the List number mapings. + */ + private Hashtable importListMapping = null; + /** + * The RtfDocument to get font and color numbers from. + */ + private RtfDocument rtfDoc = null; + /** + * The Document. + * Used for conversions, but not imports. + */ + private Document doc = null; + + + /** + * Constructs a new RtfImportHeader. + * + * @param rtfDoc The RtfDocument to get font and color numbers from. + */ + public RtfImportMgr(RtfDocument rtfDoc, Document doc) { + this.rtfDoc = rtfDoc; + this.doc = doc; + this.importFontMapping = new Hashtable(); + this.importColorMapping = new Hashtable(); + this.importStylesheetListMapping = new Hashtable(); + this.importListMapping = new Hashtable(); + } + + /** + * Imports a font. The font name is looked up in the RtfDocumentHeader and + * then the mapping from original font number to actual font number is added. + * + * @param fontNr The original font number. + * @param fontName The font name to look up. + */ + public bool ImportFont(String fontNr, String fontName) { + RtfFont rtfFont = new RtfFont(fontName); + if (rtfFont != null){ + rtfFont.SetRtfDocument(this.rtfDoc); + this.importFontMapping[fontNr] = this.rtfDoc.GetDocumentHeader().GetFontNumber(rtfFont).ToString(); + return true; + } else { + return false; + } + } + /** + * Imports a font. The font name is looked up in the RtfDocumentHeader and + * then the mapping from original font number to actual font number is added. + * + * @param fontNr The original font number. + * @param fontName The font name to look up. + * @param charset The characterset to use for the font. + */ + public bool ImportFont(String fontNr, String fontName, int charset) { + RtfFont rtfFont = new RtfFont(fontName); + if (charset>= 0) + rtfFont.SetCharset(charset); + if (rtfFont != null){ + rtfFont.SetRtfDocument(this.rtfDoc); + this.importFontMapping[fontNr] = this.rtfDoc.GetDocumentHeader().GetFontNumber(rtfFont).ToString(); + return true; + } else { + return false; + } + } + /** + * Imports a font. The font name is looked up in the RtfDocumentHeader and + * then the mapping from original font number to actual font number is added. + * + * @param fontNr The original font number. + * @param fontName The font name to look up. + * @param charset The characterset to use for the font. + */ + public bool ImportFont(String fontNr, String fontName, String fontFamily, int charset) { + RtfFont rtfFont = new RtfFont(fontName); + + if (charset>= 0) + rtfFont.SetCharset(charset); + if (fontFamily != null && fontFamily.Length > 0) + rtfFont.SetFamily(fontFamily); + if (rtfFont != null){ + rtfFont.SetRtfDocument(this.rtfDoc); + this.importFontMapping[fontNr] = this.rtfDoc.GetDocumentHeader().GetFontNumber(rtfFont).ToString(); + return true; + } else { + return false; + } + } + /** + * Performs the mapping from the original font number to the actual + * font number in the resulting RTF document. If the font number was not + * seen during import (thus no mapping) then 0 is returned, guaranteeing + * that the font number is always valid. + * + * @param fontNr The font number to map. + * @return The mapped font number. + */ + public String MapFontNr(String fontNr) { + if (this.importFontMapping.ContainsKey(fontNr)) { + return (String) this.importFontMapping[fontNr]; + } else { + return "0"; + } + } + + /** + * Imports a color value. The color number for the color defined + * by its red, green and blue values is determined and then the + * resulting mapping is added. + * + * @param colorNr The original color number. + * @param color The color to import. + */ + public void ImportColor(String colorNr, Color color) { + RtfColor rtfColor = new RtfColor(this.rtfDoc, color); + this.importColorMapping[colorNr] = rtfColor.GetColorNumber().ToString(); + } + + /** + * Performs the mapping from the original font number to the actual font + * number used in the RTF document. If the color number was not + * seen during import (thus no mapping) then 0 is returned, guaranteeing + * that the color number is always valid. + * + * @param colorNr The color number to map. + * @return The mapped color number + */ + public String MapColorNr(String colorNr) { + if (this.importColorMapping.ContainsKey(colorNr)) { + return (String) this.importColorMapping[colorNr]; + } else { + return "0"; + } + } + + /** + * Imports a List value. The List number for the List defined + * is determined and then the resulting mapping is added. + */ + public void ImportList(String listNr, List list) { + RtfList rtfList = new RtfList(this.rtfDoc, list); + + //if(rtfList != null){ + //rtfList.SetRtfDocument(this.rtfDoc); + this.importStylesheetListMapping[listNr] = this.rtfDoc.GetDocumentHeader().GetListNumber(rtfList).ToString(); + // return true; + // } else { + // return false; + // } + } + + /** + * Performs the mapping from the original list number to the actual + * list number in the resulting RTF document. If the list number was not + * seen during import (thus no mapping) then 0 is returned, guaranteeing + * that the list number is always valid. + */ + public String MapListNr(String listNr) { + if (this.importListMapping.ContainsKey(listNr)) { + return (String) this.importListMapping[listNr]; + } else { + return "0"; + } + } + + /** + * Imports a stylesheet list value. The stylesheet number for the stylesheet defined + * is determined and then the resulting mapping is added. + */ + public bool ImportStylesheetList(String listNr, List listIn) { + RtfList rtfList = new RtfList(this.rtfDoc, listIn); + + if (rtfList != null){ + rtfList.SetRtfDocument(this.rtfDoc); + //this.importStylesheetListMapping[listNr] = Integer.ToString(this.rtfDoc.GetDocumentHeader().GetRtfParagraphStyle(styleName)(rtfList)); + return true; + } else { + return false; + } + } + /** + * Performs the mapping from the original stylesheet number to the actual + * stylesheet number in the resulting RTF document. If the stylesheet number was not + * seen during import (thus no mapping) then 0 is returned, guaranteeing + * that the stylesheet number is always valid. + */ + public String MapStylesheetListNr(String listNr) { + if (this.importStylesheetListMapping.ContainsKey(listNr)) { + return (String) this.importStylesheetListMapping[listNr]; + } else { + return "0"; + } + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/RtfParser.cs b/iTechSharp/iTextSharp/text/rtf/parser/RtfParser.cs new file mode 100644 index 0000000..f85d509 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/RtfParser.cs @@ -0,0 +1,1457 @@ +using System; +using System.IO; +using System.Collections; +using System.Globalization; +using System.Text; +using iTextSharp.text; +using iTextSharp.text.rtf.direct; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.parser.ctrlwords; +using iTextSharp.text.rtf.parser.destinations; +/* + * $Id: RtfParser.cs,v 1.4 2008/05/16 19:31:08 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser { + + /** + * The RtfParser allows the importing of RTF documents or + * RTF document fragments. The RTF document or fragment is tokenised, + * font and color definitions corrected and then added to + * the document being written. + * + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + + public class RtfParser { + /** + * Debugging flag. + */ + private static bool debugParser = false; // DEBUG Files are unlikely to be read by any reader! + private String logFile = null; + private bool logging = false; + private bool logAppend = false; + + /** + * The iText document to add the RTF document to. + */ + private Document document = null; + /** + * The RtfDocument to add the RTF document or fragment to. + */ + private RtfDocument rtfDoc = null; + /** + * The RtfKeywords that creates and handles keywords that are implemented. + */ + private RtfCtrlWordMgr rtfKeywordMgr = null; + /** + * The RtfImportHeader to store imported font and color mappings in. + */ + private RtfImportMgr importMgr = null; + /** + * The RtfDestinationMgr object to manage destinations. + */ + private RtfDestinationMgr destinationMgr = null; + /** + * Stack for saving states for groups + */ + private Stack stackState = null; + /** + * The current parser state. + */ + private RtfParserState currentState = null; + /** + * The pushback reader to read the input stream. + */ + private PushbackStream pbReader = null; + /** + * Conversion type. Identifies if we are doing in import or a convert. + */ + private int conversionType = TYPE_IMPORT_FULL; + + + /* + * Bitmapping: + * + * 0111 1111 1111 1111 = Unkown state + * 0xxx xxxx xxxx xxxx = In Header + * 1xxx xxxx xxxx xxxx = In Document + * 2xxx xxxx xxxx xxxx = Reserved + * 4xxx xxxx xxxx xxxx = Other + * 8xxx xxxx xxxx xxxx = Errors + */ + + /* + * Header state values + */ + + /** + * Currently the RTF document header is being parsed. + */ + public const int PARSER_IN_HEADER = (0x0 << 28) | 0x000000; + /** + * Currently the RTF charset is being parsed. + */ + public const int PARSER_IN_CHARSET = PARSER_IN_HEADER | 0x000001; + /** + * Currently the RTF deffont is being parsed. + */ + public const int PARSER_IN_DEFFONT = PARSER_IN_HEADER | 0x000002; + /** + * Currently the RTF font table is being parsed. + */ + public const int PARSER_IN_FONT_TABLE = PARSER_IN_HEADER | 0x000003; + /** + * Currently a RTF font table info element is being parsed. + */ + public const int PARSER_IN_FONT_TABLE_INFO = PARSER_IN_HEADER | 0x000004; + /** + * Currently the RTF filetbl is being parsed. + */ + public const int PARSER_IN_FILE_TABLE = PARSER_IN_HEADER | 0x000005; + /** + * Currently the RTF color table is being parsed. + */ + public const int PARSER_IN_COLOR_TABLE = PARSER_IN_HEADER | 0x000006; + /** + * Currently the RTF stylesheet is being parsed. + */ + public const int PARSER_IN_STYLESHEET = PARSER_IN_HEADER | 0x000007; + /** + * Currently the RTF listtables is being parsed. + */ + public const int PARSER_IN_LIST_TABLE = PARSER_IN_HEADER | 0x000008; + /** + * Currently the RTF listtable override is being parsed. + */ + public const int PARSER_IN_LISTOVERRIDE_TABLE = PARSER_IN_HEADER | 0x000009; + /** + * Currently the RTF revtbl is being parsed. + */ + public const int PARSER_IN_REV_TABLE = PARSER_IN_HEADER | 0x00000A; + /** + * Currently the RTF rsidtable is being parsed. + */ + public const int PARSER_IN_RSID_TABLE = PARSER_IN_HEADER | 0x0000B; + /** + * Currently the RTF generator is being parsed. + */ + public const int PARSER_IN_GENERATOR = PARSER_IN_HEADER | 0x00000C; + /** + * Currently the RTF Paragraph group properties Table (word 2002) + */ + public const int PARSER_IN_PARAGRAPH_TABLE = PARSER_IN_HEADER | 0x00000E; + /** + * Currently the RTF Old Properties. + */ + public const int PARSER_IN_OLDCPROPS = PARSER_IN_HEADER | 0x00000F; + /** + * Currently the RTF Old Properties. + */ + public const int PARSER_IN_OLDPPROPS = PARSER_IN_HEADER | 0x000010; + /** + * Currently the RTF Old Properties. + */ + public const int PARSER_IN_OLDTPROPS = PARSER_IN_HEADER | 0x000012; + /** + * Currently the RTF Old Properties. + */ + public const int PARSER_IN_OLDSPROPS = PARSER_IN_HEADER | 0x000013; + /** + * Currently the RTF User Protection Information. + */ + public const int PARSER_IN_PROT_USER_TABLE = PARSER_IN_HEADER | 0x000014; + /** + * Currently the Latent Style and Formatting usage restrictions + */ + public const int PARSER_IN_LATENTSTYLES = PARSER_IN_HEADER | 0x000015; + + public const int PARSER_IN_PARAGRAPH_GROUP_PROPERTIES =PARSER_IN_HEADER | 0x000016; + + /* + * Document state values + */ + + /** + * Currently the RTF document content is being parsed. + */ + public const int PARSER_IN_DOCUMENT = (0x2 << 28 ) | 0x000000; + + /** + * Currently the RTF info group is being parsed. + */ + public const int PARSER_IN_INFO_GROUP = PARSER_IN_DOCUMENT | 0x000001; + + + public const int PARSER_IN_UPR = PARSER_IN_DOCUMENT | 0x000002; + /** + * Currently a shppict control word is being parsed. + */ + public const int PARSER_IN_SHPPICT = PARSER_IN_DOCUMENT | 0x000010; //16 + /** + * Currently a pict control word is being parsed. + */ + public const int PARSER_IN_PICT = PARSER_IN_DOCUMENT | 0x000011; //17 + /** + * Currently a picprop control word is being parsed. + */ + public const int PARSER_IN_PICPROP = PARSER_IN_DOCUMENT | 0x000012; //18 + /** + * Currently a blipuid control word is being parsed. + */ + public const int PARSER_IN_BLIPUID = PARSER_IN_DOCUMENT | 0x000013; //18 + + /* other states */ + /** + * The parser is at the beginning or the end of the file. + */ + public const int PARSER_STARTSTOP = (0x4 << 28)| 0x0001; + /* ERRORS */ + /** + * Currently the parser is in an error state. + */ + public const int PARSER_ERROR = (0x8 << 28) | 0x0000; + /** + * The parser reached the end of the file. + */ + public const int PARSER_ERROR_EOF = PARSER_ERROR | 0x0001; + /** + * Currently the parser is in an unknown state. + */ + public const int PARSER_IN_UNKNOWN = PARSER_ERROR | 0x0FFFFFFF; + + + /** + * Conversion type is unknown + */ + public const int TYPE_UNIDENTIFIED = -1; + /** + * Conversion type is an import. Uses direct content to add everything. + * This is what the original import does. + */ + public const int TYPE_IMPORT_FULL = 0; + /** + * Conversion type is an import of a partial file/fragment. Uses direct content to add everything. + */ + public const int TYPE_IMPORT_FRAGMENT = 1; + /** + * Conversion type is a conversion. This uses the document (not rtfDoc) to add + * all the elements making it a different supported documents depending on the writer used. + */ + public const int TYPE_CONVERT = 2; + + + /** + * Destination is normal. Text is processed. + */ + public const int DESTINATION_NORMAL = 0; + /** + * Destination is skipping. Text is ignored. + */ + public const int DESTINATION_SKIP = 1; + + //////////////////////////////////// TOKENISE VARIABLES /////////////////// + /* + * State flags use 4/28 bitmask. + * First 4 bits (nibble) indicates major state. Used for unknown and error + * Last 28 bits indicates the value; + */ + + /** + * The RtfTokeniser is in its ground state. Any token may follow. + */ + public const int TOKENISER_NORMAL = 0x00000000; + /** + * The last token parsed was a slash. + */ + public const int TOKENISER_SKIP_BYTES = 0x00000001; + /** + * The RtfTokeniser is currently tokenising a control word. + */ + public const int TOKENISER_SKIP_GROUP = 0x00000002; + /** + * The RtfTokeniser is currently reading binary stream. + */ + public const int TOKENISER_BINARY= 0x00000003; + /** + * The RtfTokeniser is currently reading hex data. + */ + public const int TOKENISER_HEX= 0x00000004; + /** + * The RtfTokeniser ignore result + */ + public const int TOKENISER_IGNORE_RESULT= 0x00000005; + /** + * The RtfTokeniser is currently in error state + */ + public const int TOKENISER_STATE_IN_ERROR = unchecked((int)0x80000000); // 1000 0000 0000 0000 0000 0000 0000 0000 + /** + * The RtfTokeniser is currently in an unkown state + */ + public const int TOKENISER_STATE_IN_UNKOWN = unchecked((int)0xFF000000); // 1111 0000 0000 0000 0000 0000 0000 0000 + + /** + * The current group nesting level. + */ + private int groupLevel = 0; + /** + * The current document group nesting level. Used for fragments. + */ + private int docGroupLevel = 0; + /** + * When the tokeniser is Binary. + */ + private long binByteCount = 0; + /** + * When the tokeniser is set to skip bytes, binSkipByteCount is the number of bytes to skip. + */ + private long binSkipByteCount = 0; + /** + * When the tokeniser is set to skip to next group, this is the group indentifier to return to. + */ + private int skipGroupLevel = 0; + + //RTF parser error codes + public const int errOK =0; // Everything's fine! + public const int errStackUnderflow = -1; // Unmatched '}' + public const int errStackOverflow = -2; // Too many '{' -- memory exhausted + public const int errUnmatchedBrace = -3; // RTF ended during an open group. + public const int errInvalidHex = -4; // invalid hex character found in data + public const int errBadTable = -5; // RTF table (sym or prop) invalid + public const int errAssertion = -6; // Assertion failure + public const int errEndOfFile = -7; // End of file reached while reading RTF + public const int errCtrlWordNotFound = -8; // control word was not found + //////////////////////////////////// TOKENISE VARIABLES /////////////////// + + + //////////////////////////////////// STATS VARIABLES /////////////////// + /** + * Total bytes read. + */ + private long byteCount = 0; + /** + * Total control words processed. + * + * Contains both known and unknown. + * + * ctrlWordCount should equal + * ctrlWrodHandlecCount + ctrlWordNotHandledCountctrlWordSkippedCount
      + */ + private long ctrlWordCount = 0; + /** + * Total { encountered as an open group token. + */ + private long openGroupCount = 0; + /** + * Total } encountered as a close group token. + */ + private long closeGroupCount = 0; + /** + * Total clear text characters processed. + */ + private long characterCount = 0; + /** + * Total control words recognized. + */ + private long ctrlWordHandledCount = 0; + /** + * Total control words not handled. + */ + private long ctrlWordNotHandledCount = 0; + /** + * Total control words skipped. + */ + private long ctrlWordSkippedCount = 0; + /** + * Total groups skipped. Includes { and } as a group. + */ + private long groupSkippedCount = 0; + /** + * Start time as a long. + */ + private long startTime = 0; + /** + * Stop time as a long. + */ + private long endTime = 0; + /** + * Start date as a date. + */ + private DateTime startDate; + /** + * End date as a date. + */ + private DateTime endDate; + //////////////////////////////////// STATS VARIABLES /////////////////// + /** + * Last control word and parameter processed. + */ + private RtfCtrlWordData lastCtrlWordParam = null; + + /** The RtfCtrlWordListener. */ + private ArrayList listeners = new ArrayList(); + + /* ********* + * READER * + ***********/ + /** + * Imports a complete RTF document. + * + * @param readerIn + * The Reader to read the RTF document from. + * @param rtfDoc + * The RtfDocument to add the imported document to. + * @throws IOException On I/O errors. + */ + public void ImportRtfDocument(Stream readerIn, RtfDocument rtfDoc) { + if (readerIn == null || rtfDoc == null) return; + this.Init(TYPE_IMPORT_FULL, rtfDoc, readerIn, null); + this.SetCurrentDestination(RtfDestinationMgr.DESTINATION_NULL); + startDate = DateTime.Now; + startTime = startDate.Ticks / 10000L; + this.groupLevel = 0; + try { + this.Tokenise(); + } + catch { + } + endDate = DateTime.Now; + endTime = endDate.Ticks / 10000L; + } + + /** + * Converts an RTF document to an iText document. + * + * Usage: Create a parser object and call this method with the input stream and the iText Document object + * + * @param readerIn + * The Reader to read the RTF file from. + * @param doc + * The iText document that the RTF file is to be added to. + * @throws IOException + * On I/O errors. + */ + public void ConvertRtfDocument(Stream readerIn, Document doc) { + if (readerIn == null || doc == null) return; + this.Init(TYPE_CONVERT, null, readerIn, doc); + this.SetCurrentDestination(RtfDestinationMgr.DESTINATION_DOCUMENT); + startDate = DateTime.Now; + startTime = startDate.Ticks / 10000L; + this.groupLevel = 0; + this.Tokenise(); + endDate = DateTime.Now; + endTime = endDate.Ticks / 10000L; + } + + /** + * Imports an RTF fragment. + * + * @param readerIn + * The Reader to read the RTF fragment from. + * @param rtfDoc + * The RTF document to add the RTF fragment to. + * @param importMappings + * The RtfImportMappings defining font and color mappings for the fragment. + * @throws IOException + * On I/O errors. + */ + public void ImportRtfFragment(Stream readerIn, RtfDocument rtfDoc, RtfImportMappings importMappings) { + //public void ImportRtfFragment2(Reader readerIn, RtfDocument rtfDoc, RtfImportMappings importMappings) throws IOException { + if (readerIn == null || rtfDoc == null || importMappings==null) return; + this.Init(TYPE_IMPORT_FRAGMENT, rtfDoc, readerIn, null); + this.HandleImportMappings(importMappings); + this.SetCurrentDestination(RtfDestinationMgr.DESTINATION_DOCUMENT); + this.groupLevel = 1; + SetParserState(RtfParser.PARSER_IN_DOCUMENT); + startDate = DateTime.Now; + startTime = startDate.Ticks / 10000L; + this.Tokenise(); + endDate = DateTime.Now; + endTime = endDate.Ticks / 10000L; + } + + // listener methods + + /** + * Adds a EventListener to the RtfCtrlWordMgr. + * + * @param listener + * the new EventListener. + */ + public void AddListener(IEventListener listener) { + listeners.Add(listener); + } + + /** + * Removes a EventListener from the RtfCtrlWordMgr. + * + * @param listener + * the EventListener that has to be removed. + */ + public void RemoveListener(IEventListener listener) { + listeners.Remove(listener); + } + + /** + * Initialize the parser object values. + * + * @param type Type of conversion or import + * @param rtfDoc The RtfDocument + * @param readerIn The input stream + * @param doc The iText Document + */ + private void Init(int type, RtfDocument rtfDoc, Stream readerIn, Document doc) { + + Init_stats(); + // initialize reader to a PushbackReader + this.pbReader = Init_Reader(readerIn); + + this.conversionType = type; + this.rtfDoc = rtfDoc; + this.document = doc; + this.currentState = new RtfParserState(); + this.stackState = new Stack(); + this.SetParserState(PARSER_STARTSTOP); + this.importMgr = new RtfImportMgr(this.rtfDoc, this.document); + + // get destination Mgr + this.destinationMgr = RtfDestinationMgr.GetInstance(this); + // set the parser + RtfDestinationMgr.SetParser(this); + + + // DEBUG INFO for timing and memory usage of RtfCtrlWordMgr object + // create multiple new RtfCtrlWordMgr objects to check timing and memory usage + // System.Gc(); + // long endTime = 0; + // Date endDate = null; + // long endFree = 0; + // DecimalFormat df = new DecimalFormat("#,##0"); + // Date startDate = new Date(); + // long startTime = System.CurrentTimeMillis(); + // long startFree = Runtime.GetRuntime().FreeMemory(); + // System.out.Println("1:"); + + this.rtfKeywordMgr = new RtfCtrlWordMgr(this, this.pbReader);/////////DO NOT COMMENT OUT THIS LINE /////////// + + foreach (object listener in listeners) { + if (listener is IRtfCtrlWordListener) { + this.rtfKeywordMgr.AddRtfCtrlWordListener((IRtfCtrlWordListener)listener); + } + } + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // System.out.Println("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // System.out.Println("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // System.out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // System.out.Println("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // System.out.Println("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // System.out.Println("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + // + // System.Gc(); + // System.out.Println("2:"); + // startDate = new Date(); + // startTime = System.CurrentTimeMillis(); + // startFree = Runtime.GetRuntime().FreeMemory(); + // RtfCtrlWordMgr rtfKeywordMgr2 = new RtfCtrlWordMgr(this, this.pbReader); + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // System.out.Println("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // System.out.Println("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // System.out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // System.out.Println("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // System.out.Println("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // System.out.Println("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + // + // System.Gc(); + // System.out.Println("3:"); + // startDate = new Date(); + // startTime = System.CurrentTimeMillis(); + // startFree = Runtime.GetRuntime().FreeMemory(); + // RtfCtrlWordMgr rtfKeywordMgr3 = new RtfCtrlWordMgr(this, this.pbReader); + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // System.out.Println("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // System.out.Println("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // System.out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // System.out.Println("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // System.out.Println("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // System.out.Println("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + // + // System.Gc(); + // System.out.Println("4:"); + // startDate = new Date(); + // startTime = System.CurrentTimeMillis(); + // startFree = Runtime.GetRuntime().FreeMemory(); + // RtfCtrlWordMgr rtfKeywordMgr4 = new RtfCtrlWordMgr(this, this.pbReader); + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // System.out.Println("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // System.out.Println("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // System.out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // System.out.Println("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // System.out.Println("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // System.out.Println("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + // + // System.Gc(); + // System.out.Println("5:"); + // startDate = new Date(); + // startTime = System.CurrentTimeMillis(); + // startFree = Runtime.GetRuntime().FreeMemory(); + // RtfCtrlWordMgr rtfKeywordMgr5 = new RtfCtrlWordMgr(this, this.pbReader); + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // System.out.Println("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // System.out.Println("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // System.out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // System.out.Println("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // System.out.Println("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // System.out.Println("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + // System.Gc(); + // System.out.Println("At ed:"); + // startDate = new Date(); + // startTime = System.CurrentTimeMillis(); + // startFree = Runtime.GetRuntime().FreeMemory(); + // //RtfCtrlWordMgr rtfKeywordMgr6 = new RtfCtrlWordMgr(this, this.pbReader); + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // System.out.Println("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // System.out.Println("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // System.out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // System.out.Println("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // System.out.Println("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // System.out.Println("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + } + /** + * Initialize the statistics values. + */ + protected void Init_stats() { + byteCount = 0; + ctrlWordCount = 0; + openGroupCount = 0; + closeGroupCount = 0; + characterCount = 0; + ctrlWordHandledCount = 0; + ctrlWordNotHandledCount = 0; + ctrlWordSkippedCount = 0; + groupSkippedCount = 0; + startTime = 0; + endTime = 0; + //startDate = null; + //endDate = null; + } + + /** + * Casts the input reader to a PushbackReader or + * creates a new PushbackReader from the Reader passed in. + * The reader is also transformed into a BufferedReader if necessary. + * + * @param readerIn + * The Reader object for the input file. + * @return + * PushbackReader object + */ + private PushbackStream Init_Reader(Stream readerIn) { + if (readerIn is PushbackStream) { + return (PushbackStream)readerIn; + } + + // return the proper reader object to the parser setup + return new PushbackStream(readerIn); + } + + /** + * Imports the mappings defined in the RtfImportMappings into the + * RtfImportHeader of this RtfParser2. + * + * @param importMappings + * The RtfImportMappings to import. + */ + private void HandleImportMappings(RtfImportMappings importMappings) { + foreach (String fontNr in importMappings.GetFontMappings().Keys) { + this.importMgr.ImportFont(fontNr, (String) importMappings.GetFontMappings()[fontNr]); + } + foreach (String colorNr in importMappings.GetColorMappings().Keys) { + this.importMgr.ImportColor(colorNr, (Color) importMappings.GetColorMappings()[colorNr]); + } + foreach (String listNr in importMappings.GetListMappings().Keys) { + this.importMgr.ImportList(listNr, (List) importMappings.GetListMappings()[listNr]); + } + foreach (String stylesheetListNr in importMappings.GetStylesheetListMappings().Keys) { + this.importMgr.ImportStylesheetList(stylesheetListNr, (List) importMappings.GetStylesheetListMappings()[stylesheetListNr]); + } + + } + + + /* ***************************************** + * DOCUMENT CONTROL METHODS + * + * Handles - + * handleOpenGroup: Open groups - '{' + * handleCloseGroup: Close groups - '}' + * handleCtrlWord: Ctrl Words - '\...' + * handleCharacter: Characters - Plain Text, etc. + * + */ + + /** + * Handles open group tokens. ({) + * + * @return errOK if ok, other if an error occurred. + */ + public int HandleOpenGroup() { + int result = errOK; + this.openGroupCount++; // stats + this.groupLevel++; // current group level in tokeniser + this.docGroupLevel++; // current group level in document + if (this.GetTokeniserState() == TOKENISER_SKIP_GROUP) { + this.groupSkippedCount++; + } + + RtfDestination dest = (RtfDestination)this.GetCurrentDestination(); + bool handled = false; + + if (dest != null) { + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: before dest.HandleOpeningSubGroup()"); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: destination=" + dest.ToString()); + } + handled = dest.HandleOpeningSubGroup(); + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: after dest.HandleOpeningSubGroup()"); + } + } + + this.stackState.Push(this.currentState); + this.currentState = new RtfParserState(this.currentState); + // do not set this true until after the state is pushed + // otherwise it inserts a { where one does not belong. + this.currentState.newGroup = true; + dest = (RtfDestination)this.GetCurrentDestination(); + + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: HandleOpenGroup()"); + if (this.lastCtrlWordParam != null) + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: LastCtrlWord=" + this.lastCtrlWordParam.ctrlWord); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: grouplevel=" + groupLevel.ToString()); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: destination=" + dest.ToString()); + } + + if (dest != null) { + handled = dest.HandleOpenGroup(); + } + + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: after dest.HandleOpenGroup(); handled=" + handled.ToString()); + } + + return result; + } + public static void OutputDebug(object doc, int groupLevel, String str) { + Console.Out.WriteLine(str); + if(doc == null) return; + if (groupLevel<0) groupLevel = 0; + String spaces = new String(' ', groupLevel*2); + if(doc is RtfDocument) { + ((RtfDocument)doc).Add(new RtfDirectContent("\n" + spaces + str)); + } + else if(doc is Document) { + try { + ((Document)doc).Add(new RtfDirectContent("\n" + spaces + str)); + } catch (DocumentException) { + } + } + } + /** + * Handles close group tokens. (}) + * + * @return errOK if ok, other if an error occurred. + */ + public int HandleCloseGroup() { + int result = errOK; + this.closeGroupCount++; // stats + + if (this.GetTokeniserState() != TOKENISER_SKIP_GROUP) { + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: HandleCloseGroup()"); + if (this.lastCtrlWordParam != null) + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: LastCtrlWord=" + this.lastCtrlWordParam.ctrlWord); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: grouplevel=" + groupLevel.ToString()); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: destination=" + this.GetCurrentDestination().ToString()); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, ""); + } + RtfDestination dest = (RtfDestination)this.GetCurrentDestination(); + bool handled = false; + + if (dest != null) { + handled = dest.HandleCloseGroup(); + } + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: After dest.HandleCloseGroup(); handled = " + handled.ToString()); + RtfParser.OutputDebug(this.rtfDoc, groupLevel, ""); + } + } + + if (this.stackState.Count >0 ) { + this.currentState = (RtfParserState)this.stackState.Pop(); + } else { + result = errStackUnderflow; + } + + this.docGroupLevel--; + this.groupLevel--; + + if (this.GetTokeniserState() == TOKENISER_SKIP_GROUP && this.groupLevel < this.skipGroupLevel) { + this.SetTokeniserState(TOKENISER_NORMAL); + } + + return result; + } + + + /** + * Handles control word tokens. Depending on the current + * state a control word can lead to a state change. When + * parsing the actual document contents, certain tabled + * values are remapped. i.e. colors, fonts, styles, etc. + * + * @param ctrlWordData The control word to handle. + * @return errOK if ok, other if an error occurred. + */ + public int HandleCtrlWord(RtfCtrlWordData ctrlWordData) { + int result = errOK; + this.ctrlWordCount++; // stats + + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: handleCtrlWord=" + ctrlWordData.ctrlWord); + } + + if (this.GetTokeniserState() == TOKENISER_SKIP_GROUP) { + this.ctrlWordSkippedCount++; + if (debugParser) { + RtfParser.OutputDebug(this.rtfDoc, groupLevel, "DEBUG: SKIPPED"); + } + return result; + } + + // RtfDestination dest = (RtfDestination)this.GetCurrentDestination(); + // bool handled = false; + // if (dest != null) { + // handled = dest.HandleControlWord(ctrlWordData); + // } + + result = this.rtfKeywordMgr.HandleKeyword(ctrlWordData, this.groupLevel); + + if ( result == errOK){ + this.ctrlWordHandledCount++; + } else { + this.ctrlWordNotHandledCount++; + result = errOK; // hack for now. + } + + return result; + } + + /** + * Handles text tokens. These are either handed on to the + * appropriate destination handler. + * + * @param nextChar + * The text token to handle. + * @return errOK if ok, other if an error occurred. + */ + public int HandleCharacter(int nextChar) { + this.characterCount++; // stats + + if (this.GetTokeniserState() == TOKENISER_SKIP_GROUP) { + return errOK; + } + + bool handled = false; + + RtfDestination dest = (RtfDestination)this.GetCurrentDestination(); + if (dest != null) { + handled = dest.HandleCharacter(nextChar); + } + + return errOK; + } + + /** + * Get the state of the parser. + * + * @return + * The current RtfParserState state object. + */ + public RtfParserState GetState(){ + return this.currentState; + } + + /** + * Get the current state of the parser. + * + * @return + * The current state of the parser. + */ + public int GetParserState(){ + return this.currentState.parserState; + } + + /** + * Set the state value of the parser. + * + * @param newState + * The new state for the parser + * @return + * The state of the parser. + */ + public int SetParserState(int newState){ + this.currentState.parserState = newState; + return this.currentState.parserState; + } + + /** + * Get the conversion type. + * + * @return + * The type of the conversion. Import or Convert. + */ + public int GetConversionType() { + return this.conversionType; + } + + /** + * Get the RTF Document object. + * @return + * Returns the object rtfDoc. + */ + public RtfDocument GetRtfDocument() { + return this.rtfDoc; + } + + /** + * Get the Document object. + * @return + * Returns the object rtfDoc. + */ + public Document GetDocument() { + return this.document; + } + + /** + * Get the RtfImportHeader object. + * @return + * Returns the object importHeader. + */ + public RtfImportMgr GetImportManager() { + return importMgr; + } + + + ///////////////////////////////////////////////////////////// + // accessors for destinations + /** + * Set the current destination object for the current state. + * @param dest The destination value to set. + */ + public bool SetCurrentDestination(String destination) { + RtfDestination dest = RtfDestinationMgr.GetDestination(destination); + if (dest != null) { + this.currentState.destination = dest; + return false; + } else { + this.SetTokeniserStateSkipGroup(); + return false; + } + } + /** + * Get the current destination object. + * + * @return The current state destination + */ + public RtfDestination GetCurrentDestination() { + return this.currentState.destination; + } + /** + * Get a destination from the map + * + * @para destination The string destination. + * @return The destination object from the map + */ + public RtfDestination GetDestination(String destination) { + return RtfDestinationMgr.GetDestination(destination); + } + + /** + * Helper method to determine if this is a new group. + * + * @return true if this is a new group, otherwise it returns false. + */ + public bool IsNewGroup() { + return this.currentState.newGroup; + } + /** + * Helper method to set the new group flag + * @param value The bool value to set the flag + * @return The value of newGroup + */ + public bool SetNewGroup(bool value) { + this.currentState.newGroup = value; + return this.currentState.newGroup; + } + + /* ************ + * TOKENISER * + **************/ + + /** + * Read through the input file and parse the data stream into tokens. + * + * @throws IOException on IO error. + */ + public void Tokenise() { + int errorCode = errOK; // error code + int nextChar = 0; + this.SetTokeniserState(TOKENISER_NORMAL); // set initial tokeniser state + + + while((nextChar = this.pbReader.ReadByte()) != -1) { + this.byteCount++; + + if (this.GetTokeniserState() == TOKENISER_BINARY) // if we're parsing binary data, handle it directly + { + if ((errorCode = ParseChar(nextChar)) != errOK) + return; + } else { + switch (nextChar) { + case '{': // scope delimiter - Open + this.HandleOpenGroup(); + break; + case '}': // scope delimiter - Close + this.HandleCloseGroup(); + break; + case '\n': // noise character + case '\r': // noise character + // if (this.IsImport()) { + // this.rtfDoc.Add(new RtfDirectContent(new String(nextChar))); + // } + break; + case '\\': // Control word start delimiter + if (ParseCtrlWord(pbReader) != errOK) { + // TODO: Indicate some type of error + return; + } + break; + default: + if (groupLevel == 0) { // BOMs + break; + } + if (this.GetTokeniserState() == TOKENISER_HEX) { + StringBuilder hexChars = new StringBuilder(); + hexChars.Append(nextChar); + if((nextChar = pbReader.ReadByte()) == -1) { + return; + } + this.byteCount++; + hexChars.Append(nextChar); + try { + nextChar=int.Parse(hexChars.ToString(), NumberStyles.HexNumber); + } catch { + return; + } + this.SetTokeniserState(TOKENISER_NORMAL); + } + if ((errorCode = ParseChar(nextChar)) != errOK) { + return; // some error occurred. we should send a + // real error + } + break; + } // switch (nextChar[0]) + } // end if (this.GetTokeniserState() == TOKENISER_BINARY) + + // if (groupLevel < 1 && this.IsImportFragment()) return; //return errOK; + // if (groupLevel < 0 && this.IsImportFull()) return; //return errStackUnderflow; + // if (groupLevel < 0 && this.IsConvert()) return; //return errStackUnderflow; + + }// end while (reader.Read(nextChar) != -1) + RtfDestination dest = (RtfDestination)this.GetCurrentDestination(); + if (dest != null) { + dest.CloseDestination(); + } + } + + /** + * Process the character and send it to the current destination. + * @param nextChar + * The character to process + * @return + * Returns an error code or errOK if no error. + */ + private int ParseChar(int nextChar) { + // figure out where to put the character + // needs to handle group levels for parsing + // examples + /* + * {\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;} + * {\f7\fswiss\fcharset0\fprq2{\*\panose 020b0604020202030204}Helv{\*\falt Arial};} <- special case!!!! + * {\f5\froman\fcharset0 Tahoma;} + * {\f6\froman\fcharset0 Arial Black;} + * {\info(\author name}{\company company name}} + * ... document text ... + */ + if (this.GetTokeniserState() == TOKENISER_BINARY && --binByteCount <= 0) + this.SetTokeniserStateNormal(); + if (this.GetTokeniserState() == TOKENISER_SKIP_BYTES && --binSkipByteCount <= 0) + this.SetTokeniserStateNormal(); + return this.HandleCharacter(nextChar); + } + + /** + * Parses a keyword and it's parameter if one exists + * @param reader + * This is a pushback reader for file input. + * @return + * Returns an error code or errOK if no error. + * @throws IOException + * Catch any file read problem. + */ + private int ParseCtrlWord(PushbackStream reader) { + int nextChar = 0; + int result = errOK; + + if((nextChar = reader.ReadByte()) == -1) { + return errEndOfFile; + } + this.byteCount++; + + StringBuilder parsedCtrlWord = new StringBuilder(); + StringBuilder parsedParam= new StringBuilder(); + RtfCtrlWordData ctrlWordParam = new RtfCtrlWordData(); + + if (!Char.IsLetterOrDigit((char)nextChar)) { + parsedCtrlWord.Append((char)nextChar); + ctrlWordParam.ctrlWord = parsedCtrlWord.ToString(); + result = this.HandleCtrlWord(ctrlWordParam); + lastCtrlWordParam = ctrlWordParam; + return result; + } + + // for ( ; Character.IsLetter(nextChar[0]); reader.Read(nextChar) ) { + // parsedCtrlWord.Append(nextChar[0]); + // } + do { + parsedCtrlWord.Append((char)nextChar); + //TODO: catch EOF + nextChar = reader.ReadByte(); + this.byteCount++; + } while (Char.IsLetter((char)nextChar)); + + ctrlWordParam.ctrlWord = parsedCtrlWord.ToString(); + + if ((char)nextChar == '-') { + ctrlWordParam.isNeg = true; + if((nextChar = reader.ReadByte()) == -1) { + return errEndOfFile; + } + this.byteCount++; + } + + if (Char.IsDigit((char)nextChar)) { + ctrlWordParam.hasParam = true; + // for ( ; Character.IsDigit(nextChar[0]); reader.Read(nextChar) ) { + // parsedParam.Append(nextChar[0]); + // } + do { + parsedParam.Append((char)nextChar); + //TODO: catch EOF + nextChar = reader.ReadByte(); + this.byteCount++; + } while (Char.IsDigit((char)nextChar)); + + ctrlWordParam.param = parsedParam.ToString(); + } + + // push this character back into the stream + if ((char)nextChar != ' ') { // || this.IsImport() ) { + reader.Unread(nextChar); + } + + if (debugParser) { + // // debug: insrsid6254399 + // if (ctrlWordParam.ctrlWord.Equals("proptype") && ctrlWordParam.param.Equals("30")) { + // System.out.Print("Debug value found\n"); + // } + // if (ctrlWordParam.ctrlWord.Equals("panose") ) { + // System.out.Print("Debug value found\n"); + // } + } + + result = this.HandleCtrlWord(ctrlWordParam); + lastCtrlWordParam = ctrlWordParam; + return result; + + } + + /** + * Set the current state of the tokeniser. + * @param value The new state of the tokeniser. + * @return The state of the tokeniser. + */ + public int SetTokeniserState(int value) { + this.currentState.tokeniserState = value; + return this.currentState.tokeniserState; + } + + /** + * Get the current state of the tokeniser. + * @return The current state of the tokeniser. + */ + public int GetTokeniserState() { + return this.currentState.tokeniserState; + } + + /** + * Gets the current group level + * + * @return + * The current group level value. + */ + public int GetLevel() { + return this.groupLevel; + } + + + /** + * Set the tokeniser state to skip to the end of the group. + * Sets the state to TOKENISER_SKIP_GROUP and skipGroupLevel to the current group level. + */ + public void SetTokeniserStateNormal() { + this.SetTokeniserState(TOKENISER_NORMAL); + } + + /** + * Set the tokeniser state to skip to the end of the group. + * Sets the state to TOKENISER_SKIP_GROUP and skipGroupLevel to the current group level. + */ + public void SetTokeniserStateSkipGroup() { + this.SetTokeniserState(TOKENISER_SKIP_GROUP); + this.skipGroupLevel = this.groupLevel; + } + + /** + * Sets the number of bytes to skip and the state of the tokeniser. + * + * @param numberOfBytesToSkip + * The numbere of bytes to skip in the file. + */ + public void SetTokeniserSkipBytes(long numberOfBytesToSkip) { + this.SetTokeniserState(TOKENISER_SKIP_BYTES); + this.binSkipByteCount = numberOfBytesToSkip; + } + + /** + * Sets the number of binary bytes. + * + * @param binaryCount + * The number of binary bytes. + */ + public void SetTokeniserStateBinary(int binaryCount) { + this.SetTokeniserState(TOKENISER_BINARY); + this.binByteCount = binaryCount; + } + /** + * Sets the number of binary bytes. + * + * @param binaryCount + * The number of binary bytes. + */ + public void SetTokeniserStateBinary(long binaryCount) { + this.SetTokeniserState(TOKENISER_BINARY); + this.binByteCount = binaryCount; + } + /** + * Helper method to determin if conversion is TYPE_CONVERT + * @return true if TYPE_CONVERT, otherwise false + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_CONVERT + */ + public bool IsConvert() { + return (this.GetConversionType() == RtfParser.TYPE_CONVERT); + } + + /** + * Helper method to determin if conversion is TYPE_IMPORT_FULL or TYPE_IMPORT_FRAGMENT + * @return true if TYPE_CONVERT, otherwise false + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_IMPORT_FULL + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_IMPORT_FRAGMENT + */ + public bool IsImport() { + return (IsImportFull() || this.IsImportFragment()); + } + /** + * Helper method to determin if conversion is TYPE_IMPORT_FULL + * @return true if TYPE_CONVERT, otherwise false + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_IMPORT_FULL + */ + public bool IsImportFull() { + return (this.GetConversionType() == RtfParser.TYPE_IMPORT_FULL); + } + /** + * Helper method to determin if conversion is TYPE_IMPORT_FRAGMENT + * @return true if TYPE_CONVERT, otherwise false + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_IMPORT_FRAGMENT + */ + public bool IsImportFragment() { + return (this.GetConversionType() == RtfParser.TYPE_IMPORT_FRAGMENT); + } + /** + * Helper method to indicate if this control word was a \* control word. + * @return true if it was a \* control word, otherwise false + */ + public bool GetExtendedDestination() { + return this.currentState.isExtendedDestination; + } + /** + * Helper method to set the extended control word flag. + * @param value Boolean to set the value to. + * @return isExtendedDestination. + */ + public bool SetExtendedDestination(bool value) { + this.currentState.isExtendedDestination = value; + return this.currentState.isExtendedDestination; + } + + /** + * Get the logfile name. + * + * @return the logFile + */ + public String GetLogFile() { + return logFile; + } + + /** + * Set the logFile name + * + * @param logFile the logFile to set + */ + public void SetLogFile(String logFile) { + this.logFile = logFile; + } + /** + * Set the logFile name + * + * @param logFile the logFile to set + */ + public void SetLogFile(String logFile, bool logAppend) { + this.logFile = logFile; + this.SetLogAppend(logAppend); + } + + /** + * Get flag indicating if logging is on or off. + * + * @return the logging + */ + public bool IsLogging() { + return logging; + } + + /** + * Set flag indicating if logging is on or off + * @param logging true to turn on logging, false to turn off logging. + */ + public void SetLogging(bool logging) { + this.logging = logging; + } + + /** + * @return the logAppend + */ + public bool IsLogAppend() { + return logAppend; + } + + /** + * @param logAppend the logAppend to set + */ + public void SetLogAppend(bool logAppend) { + this.logAppend = logAppend; + } + + /* + * Statistics + * + public void PrintStats(PrintStream out) { + if (out == null) return; + + out.Println(""); + out.Println("Parser statistics:"); + out.Println("Process start date: " + startDate.ToLocaleString()); + out.Println("Process end date : " + endDate.ToLocaleString()); + out.Println(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + out.Println("Total bytes read : " + Long.ToString(byteCount)); + out.Println("Open group count : " + Long.ToString(openGroupCount)); + out.Print("Close group count : " + Long.ToString(closeGroupCount)); + out.Println(" (Groups Skipped): " + Long.ToString(groupSkippedCount)); + out.Print("Control word count: " + Long.ToString(ctrlWordCount)); + out.Print(" - Handled: " + Long.ToString(ctrlWordHandledCount)); + out.Print(" Not Handled: " + Long.ToString(ctrlWordNotHandledCount)); + out.Println(" Skipped: " + Long.ToString(ctrlWordSkippedCount)); + out.Println("Plain text char count: " + Long.ToString(characterCount)); + }*/ + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/RtfParserState.cs b/iTechSharp/iTextSharp/text/rtf/parser/RtfParserState.cs new file mode 100644 index 0000000..a17745e --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/RtfParserState.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text.rtf.parser.ctrlwords; +using iTextSharp.text.rtf.parser.destinations; +using iTextSharp.text.rtf.parser.properties; +/* + * $Id: RtfParserState.cs,v 1.2 2008/05/13 11:25:58 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser { + + /** + * The RtfParserState contains the state information + * for the parser. The current state object is pushed/popped in a stack + * when a group change is made. + * + * When an open group is encountered, the current state is copied and + * then pushed on the top of the stack + * When a close group is encountered, the current state is overwritten with + * the popped value from the top of the stack + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfParserState { + /** + * The parser state. + */ + public int parserState = RtfParser.PARSER_IN_UNKNOWN; + /** + * The tokeniser state. + */ + public int tokeniserState = RtfParser.TOKENISER_STATE_IN_UNKOWN; + /** + * The control word set as the group handler. + */ + public Object groupHandler = null; + /** + * The parsed value for the current group/control word. + */ + public StringBuilder text = null; + /** + * Stack containing control word handlers. There could be multiple + * control words in a group. + */ + public Stack ctrlWordHandlers = null; + /** + * The current control word handler. + */ + public Object ctrlWordHandler = null; + /** + * The current destination. + */ + public RtfDestination destination = null; + /** + * Flag indicating if this is an extended destination \* control word + */ + public bool isExtendedDestination = false; + /** + * Flag to indicate if last token was an open group token '{' + */ + public bool newGroup = false; + + public RtfProperty properties = null; + /** + * Default constructor + * + */ + public RtfParserState() { + this.text = new StringBuilder(); + this.ctrlWordHandlers = new Stack(); + this.properties = new RtfProperty(); + this.destination = RtfDestinationNull.GetInstance(); + this.newGroup = false; + } + /** + * Copy constructor + * @param orig The object to copy + */ + public RtfParserState(RtfParserState orig) { + this.properties = orig.properties; + this.parserState = orig.parserState; + this.tokeniserState = orig.tokeniserState; + this.groupHandler = null; + this.destination = orig.destination; + this.text = new StringBuilder(); + this.ctrlWordHandlers = new Stack(); + this.destination = orig.destination; + this.newGroup = false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/IRtfCtrlWordListener.cs b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/IRtfCtrlWordListener.cs new file mode 100644 index 0000000..fcb100d --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/IRtfCtrlWordListener.cs @@ -0,0 +1,78 @@ +using System; +using iTextSharp.text.rtf.parser; +/* + * $Id: IRtfCtrlWordListener.cs,v 1.2 2008/05/13 11:25:58 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.ctrlwords { + + /** + * RtfCtrlWordListener interface for handling events. + * + * @author Howard Shank (hgshank@yahoo.com) + * + * @since 2.0.8 + */ + public interface IRtfCtrlWordListener : IEventListener { + /** + * + * @return null or modified copy of the ctrlWordData object + */ + RtfCtrlWordData BeforeCtrlWord(RtfCtrlWordData ctrlWordData); + /** + * + * @return null or modified copy of the ctrlWordData object + */ + RtfCtrlWordData OnCtrlWord(RtfCtrlWordData ctrlWordData); + /** + * + * @return null or modified copy of the ctrlWordData object + */ + RtfCtrlWordData AfterCtrlWord(RtfCtrlWordData ctrlWordData); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordData.cs b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordData.cs new file mode 100644 index 0000000..0e5e68f --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordData.cs @@ -0,0 +1,132 @@ +using System; +using iTextSharp.text.rtf.parser.properties; +/* $Id: RtfCtrlWordData.cs,v 1.2 2008/05/13 11:25:58 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.ctrlwords { + + /** + * The control word and parameter information as parsed by the parser. + * Contains the control word, + * Flag indicating if there is a parameter. + * The parameter value as a string. + * Flag indicating the parameter is positive or negative. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfCtrlWordData { + public String prefix = ""; + public String suffix = ""; + /** + * The control word found by the parser + */ + public String ctrlWord = ""; + /** + * Flag indicating if this keyword has a parameter. + */ + public bool hasParam = false; + /** + * The parameter for the control word. + */ + public String param = ""; + /** + * Flag indicating if parameter is positive or negative. + */ + public bool isNeg = false; + /** + * Flag indicating a new group + */ + public bool newGroup = false; + /** + * Flag indicating if this object has been modified. + */ + public bool modified = false; + + public int ctrlWordType = RtfCtrlWordType.UNIDENTIFIED; + public String specialHandler = ""; + + /** + * Return the parameter value as an integer (int) value. + * + * @return + * Returns the parameter value as an int vlaue. + */ + public int IntValue() { + int value; + value = int.Parse(this.param); + if (this.isNeg) value = (-value); + return value; + } + + /** + * Return the parameter value as a long value + * + * @return + * Returns the parameter value as a long value + */ + public long LongValue() { + long value; + value = long.Parse(this.param); + if (this.isNeg) value = (-value); + return value; + } + + public override String ToString() { + String outp = ""; + outp = this.prefix + this.ctrlWord; + if (this.hasParam) { + if (this.isNeg) outp += "-"; + outp += this.param; + } + outp += this.suffix; + return outp; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordHandler.cs b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordHandler.cs new file mode 100644 index 0000000..0dc5a18 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordHandler.cs @@ -0,0 +1,358 @@ +using System; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.destinations; +using iTextSharp.text.rtf.parser.properties; +using iTextSharp.text.rtf.direct; + +/* $Id: RtfCtrlWordHandler.cs,v 1.3 2008/05/13 11:25:58 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.ctrlwords { + + /** + * RtfCtrlWordBase is the base class for all + * control word handlers to extend from. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfCtrlWordHandler { + /** + * Debug flag - internal use + * @since 2.0.8 + */ + private static bool debug = false; + + /** + * Local variable referencing the parser object. + * @since 2.0.8 + */ + protected RtfParser rtfParser = null; + /** + * The control word for this class. + * @since 2.0.8 + */ + protected String ctrlWord = ""; + /** + * The default value for this control word. + * Not all control words use a default parameter value. + * @since 2.0.8 + */ + protected int defaultParameterValue = 0; + /** + * Does this control word use the default value? + * @since 2.0.8 + */ + protected bool passDefaultParameterValue = false; + /** + * Control Word type. Destination, toggle, value, etc. + * @since 2.0.8 + */ + protected int ctrlWordType = RtfCtrlWordType.UNIDENTIFIED; + /** + * Class, property, etc. + * @since 2.0.8 + */ + protected String specialHandler = ""; + /** + * What version of the RTF spec the control word was introduced. + * @since 2.0.8 + */ + protected float rtfVersionSupported = -1.0f; // -1.0 unknown. Each class should override this as implemented. + /** + * The control word as parsed by the parser. + * @since 2.0.8 + */ + protected RtfCtrlWordData ctrlWordData = null; + /** + * String containing the value of "{" or "" (blank) depending on if this is the + * first control word in a group. + * @since 2.0.8 + */ + protected String groupPrefix = ""; + /** + * The prefix for all control words. + * @since 2.0.8 + */ + protected String ctrlWordPrefix = "\\"; + /** + * The prefix for all control words. + * @since 2.0.8 + */ + protected String ctrlWordSuffix = " "; + + /** + * Constructor: + * + * @param rtfParser + * The parser for this control word. + * @param ctrlWord + * The string value of this control word. + * @param defaultParameterValue + * The default value of this control word. Not all control words have values. + * @param passDefaultParameterValue + * Flag indicating if this control word should use the default value. + * @param ctrlWordType + * Indicator of the type of control word this is. DESTINATION|DESTINATION_EX|VALUE|FLAG|TOGGLE|SYMBOL + * @param prefix + * String to prefix the ctrl word with. "\" or "\*\" are the 2 used values. + * @param suffix + * String to add as suffix to the ctrl word. " " and "" are the 2 used values. + * @param specialHandler + * If TOGGLE then the property name as String (propertyGroup.propertyName format ex. "character.bold") + * If FLAG then the property name as String (propertyGroup.propertyName format ex. "character.bold") + * If VALUE then the property name as String (propertyGroup.propertyName format ex. "character.bold") + * If SYMBOL then the character to use for substitution as String + * If DESTINATION|DESTINATION_EX then the RtfDestination class name as String + * + * @since 2.0.8 + */ + public RtfCtrlWordHandler(RtfParser rtfParser, String ctrlWord, int defaultParameterValue, bool passDefaultParameterValue, + int ctrlWordType, String prefix, String suffix, String specialHandler) { + this.rtfParser = rtfParser; + this.ctrlWord = ctrlWord; + this.defaultParameterValue = defaultParameterValue; + this.passDefaultParameterValue = passDefaultParameterValue; + this.ctrlWordType = ctrlWordType; + this.ctrlWordPrefix = prefix; + this.ctrlWordSuffix = suffix; + this.specialHandler = specialHandler; + + if (this.ctrlWordType == RtfCtrlWordType.DESTINATION || this.ctrlWordType == RtfCtrlWordType.DESTINATION_EX){ + if (this.specialHandler == null) { + this.specialHandler = "RtfDestinationNull"; + } + String arg1 = ""; // stylesheet value - S, CS, TS + RtfDestinationMgr.AddDestination(this.ctrlWord, new Object[] { this.specialHandler, arg1 }); + } else { + if (this.ctrlWordType == RtfCtrlWordType.SYMBOL){ + + } else { + if (this.specialHandler == null) { + this.specialHandler = this.ctrlWord; // if null, make the property the name of the ctrl word + } else { + if (this.specialHandler.Length > 1 && this.specialHandler.EndsWith(".")) { + this.specialHandler += this.ctrlWord; // if string length>1 and ends with a period, it's a group. Add ctrlWord + } + } + } + } + } + + /** + * The primary control word handler method. + * Called by the parser once it has a control word and parameter if applicable. + * + * @param ctrlWordDataIn + * The control word and associated parameter if applicable. + * @return + * true or false if the control word was handled. + * @since 2.0.8 + */ + public bool HandleControlword(RtfCtrlWordData ctrlWordDataIn){ + bool result = false; + this.ctrlWordData = ctrlWordDataIn; + RtfDestination dest = null; + bool handled = false; + + this.ctrlWordData.prefix = this.ctrlWordPrefix; + this.ctrlWordData.suffix = this.ctrlWordSuffix; + this.ctrlWordData.newGroup = this.rtfParser.GetState().newGroup; + this.ctrlWordData.ctrlWordType = this.ctrlWordType; + this.ctrlWordData.specialHandler = this.specialHandler; + + if (!this.ctrlWordData.hasParam && this.passDefaultParameterValue) { + this.ctrlWordData.hasParam = true; + this.ctrlWordData.param = this.defaultParameterValue.ToString(); + } + + if (debug) { + PrintDebug("handleKeyword: [" + this.ctrlWordData.ctrlWord + "] param=" + ctrlWordDataIn.param); + RtfParser.OutputDebug(this.rtfParser.GetRtfDocument(), this.rtfParser.GetLevel()+1, "RtfCtrlWordHandler debug Start: " + this.ctrlWordData.ctrlWord + " "); + } + if (this.ctrlWordData.ctrlWord.Equals("*")) { + return true; + } + + if (!BeforeControlWord()) { + return true; + } + + switch (this.ctrlWordType) { + case RtfCtrlWordType.FLAG: + case RtfCtrlWordType.TOGGLE: + case RtfCtrlWordType.VALUE: + dest = (RtfDestination)this.rtfParser.GetCurrentDestination(); + if (dest != null) { + handled = dest.HandleControlWord(this.ctrlWordData); + } + break; + + case RtfCtrlWordType.SYMBOL: + dest = (RtfDestination)this.rtfParser.GetCurrentDestination(); + if (dest != null) { + String data = null; + // if doing an import, then put the control word in the output stream through the character handler + if (this.rtfParser.IsImport()) { + data = this.ctrlWordPrefix + this.ctrlWordData.ctrlWord + this.ctrlWordSuffix; + } + if (this.rtfParser.IsConvert()) { + data = this.specialHandler; + } + + // If there is a substitute character, process the character. + // If no substitute character, then provide special handling in the destination for the ctrl word. + if (data != null) { + foreach (char cc in data.ToCharArray()) { + handled = dest.HandleCharacter((int)cc); + } + } else { + handled = dest.HandleControlWord(this.ctrlWordData); + } + } + break; + + case RtfCtrlWordType.DESTINATION_EX: + case RtfCtrlWordType.DESTINATION: + // set the destination + int x=0; + if(this.ctrlWord == "shppict" || this.ctrlWord == "nonshppict") { + x++; + } + handled = this.rtfParser.SetCurrentDestination(this.ctrlWord); + // let destination handle the ctrl word now. + dest = (RtfDestination)this.rtfParser.GetCurrentDestination(); + if(dest != null) { + if(dest.GetNewTokeniserState() == RtfParser.TOKENISER_IGNORE_RESULT) { + handled = dest.HandleControlWord(this.ctrlWordData); + } + else { + this.rtfParser.SetTokeniserState(dest.GetNewTokeniserState()); + } + } + break; + } + + AfterControlWord(); + + if (debug) { + RtfParser.OutputDebug(this.rtfParser.GetRtfDocument(), this.rtfParser.GetLevel()+1, "RtfCtrlWordHandler debug End: " + this.ctrlWordData.ctrlWord + " "); + } + + return result; + } + + /** + * Pre-processing before the control word. + * + * If return value is true, no further processing will be performed on + * this control word. + * + * @return false = stop processing, true = continue processing + * @since 2.0.8 + */ + //Primary purpose is for \* control word and event handling. + protected bool BeforeControlWord() { + if (debug) PrintDebug("beforeControlWord"); + // TODO: This is where events would be triggered + return true; + } + /** + * Handle the control word. + * + * @return true if control word was handled, false if it was not handled. + * @since 2.0.8 + */ + protected bool OnControlWord() { + if (debug) PrintDebug("onCtrlWord"); + // TODO: This is where events would be triggered + return false; + } + /** + * Post-processing after the control word. + * + * @return false = stop processing, true = continue processing + * @since 2.0.8 + */ + protected bool AfterControlWord() { + if (debug) PrintDebug("afterControlWord"); + // TODO: This is where events would be triggered + return true; + } + + // public String CtrlWordString() { + // //String out = ctrlWordPrefix + this.ctrlWord; + // String out = ""; + // if (this.bExtendedDestination) { + // out += "\\*"; + // } + // out = ctrlWordPrefix + this.ctrlWordData.ctrlWord; + // if (this.ctrlWordData.hasParam) { + // if (this.ctrlWordData.isNeg) out += "-"; + // out += this.ctrlWordData.param; + // } else { + // if (this.passDefaultParameterValue == true) { + // out += Integer.ToString(this.defaultParameterValue); + // } + // } + // out += this.ctrlWordSuffix; + // return out; + // } + + /** + * Debug function to print class/method + * @param txt The String to output. + * @since 2.0.8 + */ + private void PrintDebug(String txt) { + Console.Out.WriteLine(this.GetType().Name + " : " + txt); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMap.cs b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMap.cs new file mode 100644 index 0000000..c729f56 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMap.cs @@ -0,0 +1,1903 @@ +using System; +using System.Collections; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.properties; +/* + * $Id: RtfCtrlWordMap.cs,v 1.2 2008/05/13 11:25:59 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.ctrlwords { + + /** + * RtfCtrlWords handles the creation of the control word wiring. + * It is a class containing the hash map of the control words (key) + * and their associated class (value). + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + internal sealed class RtfCtrlWordMap { + + // 1810 control words in Spec v1.9. might be a few more for other apps that implement + // additional control words such as exchange, outlook, etc. + // 1810/.9(loadfactor) = 2011.111111... + // set approximate initial size to initial count / load factor. + // Hashtable default size is 16. Load Factor .75 + /** + * Control Word Hashtable mapping object. + */ + private Hashtable ctrlWords = new Hashtable(2012, 0.9f); + + /** + * Get the Hashtable object containing the control words. + * Initializes the instance if this is the first instantiation + * of RtfCtrlWords class. + * @since 2.0.8 + */ + public RtfCtrlWordHandler GetCtrlWordHandler(String ctrlWord) { + try { + if (ctrlWords.ContainsKey(ctrlWord)) { + // add 1 to known control words + return (RtfCtrlWordHandler)ctrlWords[ctrlWord]; + } else { + // add 1 to unknown control words + return (RtfCtrlWordHandler)ctrlWords["unknown"]; + } + } catch { + } + return null; + } + + /** + * Constructor + * @param rtfParser The parser object. + * @since 2.0.8 + */ + public RtfCtrlWordMap(RtfParser rtfParser) { + /* + * Parameters: + * RtfParser rtfParser + * String ctrlWord + * int defaultParameterValue + * bool passDefaultParameterValue + * RtfCtrlWordType ctrlWordType + * String prefix + * String suffix + * String specialHandler = + * If TOGGLE then the property name as String + * If FLAG then the property name as String + * If VALUE then the property name as String + * If SYMBOL then the character to use for substitution as String + * If DESTINATION|DESTINATION_EX then the RtfDestination class name as String + */ + //starwriter + ctrlWords["aftnnrlc"] = new RtfCtrlWordHandler(rtfParser, "aftnnrlc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgdsctbl"] = new RtfCtrlWordHandler(rtfParser, "pgdsctbl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["pgdsc"] = new RtfCtrlWordHandler(rtfParser, "pgdsc", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgdscuse"] = new RtfCtrlWordHandler(rtfParser, "pgdscuse", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgdscnxt"] = new RtfCtrlWordHandler(rtfParser, "pgdscnxt", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgdscno"] = new RtfCtrlWordHandler(rtfParser, "pgdsctbl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + + //office + ctrlWords["'"] = new RtfCtrlWordHandler(rtfParser, "'", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "'"); + ctrlWords["*"] = new RtfCtrlWordHandler(rtfParser, "*", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "*"); + ctrlWords["-"] = new RtfCtrlWordHandler(rtfParser, "-", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "-"); + ctrlWords[":"] = new RtfCtrlWordHandler(rtfParser, ":", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", ":"); + ctrlWords["ApplyBrkRules"] = new RtfCtrlWordHandler(rtfParser, "ApplyBrkRules", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null);// "ApplyBrkRules", + ctrlWords["\\"] = new RtfCtrlWordHandler(rtfParser, "\\", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "\\"); + ctrlWords["_"] = new RtfCtrlWordHandler(rtfParser, "_", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "_"); + ctrlWords["ab"] = new RtfCtrlWordHandler(rtfParser, "ab", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null);//"ab", + ctrlWords["absh"] = new RtfCtrlWordHandler(rtfParser, "absh", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null);//"absh", + ctrlWords["abslock"] = new RtfCtrlWordHandler(rtfParser, "abslock", 0, false, RtfCtrlWordType.FLAG, "", " ", null);//"abslock", + ctrlWords["absnoovrlp"] = new RtfCtrlWordHandler(rtfParser, "absnoovrlp", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null);//"absnoovrlp", + ctrlWords["absw"] = new RtfCtrlWordHandler(rtfParser, "absw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null);//"absw", + ctrlWords["acaps"] = new RtfCtrlWordHandler(rtfParser, "acaps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null);//"acaps", + ctrlWords["acccircle"] = new RtfCtrlWordHandler(rtfParser, "acccircle", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null);//"acccircle", + ctrlWords["acccomma"] = new RtfCtrlWordHandler(rtfParser, "acccomma", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["accdot"] = new RtfCtrlWordHandler(rtfParser, "accdot", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["accnone"] = new RtfCtrlWordHandler(rtfParser, "accnone", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["accunderdot"] = new RtfCtrlWordHandler(rtfParser, "accunderdot", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["acf"] = new RtfCtrlWordHandler(rtfParser, "acf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["additive"] = new RtfCtrlWordHandler(rtfParser, "additive", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["adeflang"] = new RtfCtrlWordHandler(rtfParser, "adeflang", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["adjustright"] = new RtfCtrlWordHandler(rtfParser, "adjustright", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["adn"] = new RtfCtrlWordHandler(rtfParser, "adn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["aenddoc"] = new RtfCtrlWordHandler(rtfParser, "aenddoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aendnotes"] = new RtfCtrlWordHandler(rtfParser, "aendnotes", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aexpnd"] = new RtfCtrlWordHandler(rtfParser, "aexpnd", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["af"] = new RtfCtrlWordHandler(rtfParser, "af", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["afelev"] = new RtfCtrlWordHandler(rtfParser, "afelev", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["affixed"] = new RtfCtrlWordHandler(rtfParser, "affixed", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["afs"] = new RtfCtrlWordHandler(rtfParser, "afs", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["aftnbj"] = new RtfCtrlWordHandler(rtfParser, "aftnbj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftncn"] = new RtfCtrlWordHandler(rtfParser, "aftncn", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["aftnnalc"] = new RtfCtrlWordHandler(rtfParser, "aftnnalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnar"] = new RtfCtrlWordHandler(rtfParser, "aftnnar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnauc"] = new RtfCtrlWordHandler(rtfParser, "aftnnauc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnchi"] = new RtfCtrlWordHandler(rtfParser, "aftnnchi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnchosung"] = new RtfCtrlWordHandler(rtfParser, "aftnnchosung", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnncnum"] = new RtfCtrlWordHandler(rtfParser, "aftnncnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnndbar"] = new RtfCtrlWordHandler(rtfParser, "aftnndbar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnndbnum"] = new RtfCtrlWordHandler(rtfParser, "aftnndbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnndbnumd"] = new RtfCtrlWordHandler(rtfParser, "aftnndbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnndbnumk"] = new RtfCtrlWordHandler(rtfParser, "aftnndbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnndbnumt"] = new RtfCtrlWordHandler(rtfParser, "aftnndbnumt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnganada"] = new RtfCtrlWordHandler(rtfParser, "aftnnganada", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnngbnum"] = new RtfCtrlWordHandler(rtfParser, "aftnngbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnngbnumd"] = new RtfCtrlWordHandler(rtfParser, "aftnngbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnngbnumk"] = new RtfCtrlWordHandler(rtfParser, "aftnngbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnngbnuml"] = new RtfCtrlWordHandler(rtfParser, "aftnngbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnrlc"] = new RtfCtrlWordHandler(rtfParser, "aftnnrlc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnruc"] = new RtfCtrlWordHandler(rtfParser, "aftnnruc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnzodiac"] = new RtfCtrlWordHandler(rtfParser, "aftnnzodiac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnzodiacd"] = new RtfCtrlWordHandler(rtfParser, "aftnnzodiacd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnnzodiacl"] = new RtfCtrlWordHandler(rtfParser, "aftnnzodiacl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnrestart"] = new RtfCtrlWordHandler(rtfParser, "aftnrestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnrstcont"] = new RtfCtrlWordHandler(rtfParser, "aftnrstcont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aftnsep"] = new RtfCtrlWordHandler(rtfParser, "aftnsep", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["aftnsepc"] = new RtfCtrlWordHandler(rtfParser, "aftnsepc", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["aftnstart"] = new RtfCtrlWordHandler(rtfParser, "aftnstart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["aftntj"] = new RtfCtrlWordHandler(rtfParser, "aftntj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ai"] = new RtfCtrlWordHandler(rtfParser, "ai", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["alang"] = new RtfCtrlWordHandler(rtfParser, "alang", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["allowfieldendsel"] = new RtfCtrlWordHandler(rtfParser, "allowfieldendsel", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["allprot"] = new RtfCtrlWordHandler(rtfParser, "allprot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["alntblind"] = new RtfCtrlWordHandler(rtfParser, "alntblind", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["alt"] = new RtfCtrlWordHandler(rtfParser, "alt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["animtext"] = new RtfCtrlWordHandler(rtfParser, "animtext", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["annotation"] = new RtfCtrlWordHandler(rtfParser, "annotation", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["annotprot"] = new RtfCtrlWordHandler(rtfParser, "annotprot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ansi"] = new RtfCtrlWordHandler(rtfParser, "ansi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ansicpg"] = new RtfCtrlWordHandler(rtfParser, "ansicpg", 1252, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["aoutl"] = new RtfCtrlWordHandler(rtfParser, "aoutl", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ascaps"] = new RtfCtrlWordHandler(rtfParser, "ascaps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ashad"] = new RtfCtrlWordHandler(rtfParser, "ashad", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["asianbrkrule"] = new RtfCtrlWordHandler(rtfParser, "asianbrkrule", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["aspalpha"] = new RtfCtrlWordHandler(rtfParser, "aspalpha", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["aspnum"] = new RtfCtrlWordHandler(rtfParser, "aspnum", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["astrike"] = new RtfCtrlWordHandler(rtfParser, "astrike", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["atnauthor"] = new RtfCtrlWordHandler(rtfParser, "atnauthor", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atndate"] = new RtfCtrlWordHandler(rtfParser, "atndate", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atnicn"] = new RtfCtrlWordHandler(rtfParser, "atnicn", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atnid"] = new RtfCtrlWordHandler(rtfParser, "atnid", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atnparent"] = new RtfCtrlWordHandler(rtfParser, "atnparent", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atnref"] = new RtfCtrlWordHandler(rtfParser, "atnref", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atntime"] = new RtfCtrlWordHandler(rtfParser, "atntime", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atrfend"] = new RtfCtrlWordHandler(rtfParser, "atrfend", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["atrfstart"] = new RtfCtrlWordHandler(rtfParser, "atrfstart", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["aul"] = new RtfCtrlWordHandler(rtfParser, "aul", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["auld"] = new RtfCtrlWordHandler(rtfParser, "auld", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["auldb"] = new RtfCtrlWordHandler(rtfParser, "auldb", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["aulnone"] = new RtfCtrlWordHandler(rtfParser, "aulnone", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["aulw"] = new RtfCtrlWordHandler(rtfParser, "aulw", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["aup"] = new RtfCtrlWordHandler(rtfParser, "aup", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["author"] = new RtfCtrlWordHandler(rtfParser, "author", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["autofmtoverride"] = new RtfCtrlWordHandler(rtfParser, "autofmtoverride", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["b"] = new RtfCtrlWordHandler(rtfParser, "b", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", RtfProperty.CHARACTER_BOLD); + ctrlWords["background"] = new RtfCtrlWordHandler(rtfParser, "background", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["bdbfhdr"] = new RtfCtrlWordHandler(rtfParser, "bdbfhdr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bdrrlswsix"] = new RtfCtrlWordHandler(rtfParser, "bdrrlswsix", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgbdiag"] = new RtfCtrlWordHandler(rtfParser, "bgbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgcross"] = new RtfCtrlWordHandler(rtfParser, "bgcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdcross"] = new RtfCtrlWordHandler(rtfParser, "bgdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "bgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdkcross"] = new RtfCtrlWordHandler(rtfParser, "bgdkcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdkdcross"] = new RtfCtrlWordHandler(rtfParser, "bgdkdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdkfdiag"] = new RtfCtrlWordHandler(rtfParser, "bgdkfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdkhoriz"] = new RtfCtrlWordHandler(rtfParser, "bgdkhoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgdkvert"] = new RtfCtrlWordHandler(rtfParser, "bgdkvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgfdiag"] = new RtfCtrlWordHandler(rtfParser, "bgfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bghoriz"] = new RtfCtrlWordHandler(rtfParser, "bghoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bgvert"] = new RtfCtrlWordHandler(rtfParser, "bgvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bin"] = new RtfCtrlWordHandler(rtfParser, "bin", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["binfsxn"] = new RtfCtrlWordHandler(rtfParser, "binfsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["binsxn"] = new RtfCtrlWordHandler(rtfParser, "binsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["bkmkcolf"] = new RtfCtrlWordHandler(rtfParser, "bkmkcolf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["bkmkcoll"] = new RtfCtrlWordHandler(rtfParser, "bkmkcoll", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["bkmkend"] = new RtfCtrlWordHandler(rtfParser, "bkmkend", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["bkmkpub"] = new RtfCtrlWordHandler(rtfParser, "bkmkpub", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bkmkstart"] = new RtfCtrlWordHandler(rtfParser, "bkmkstart", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["bliptag"] = new RtfCtrlWordHandler(rtfParser, "bliptag", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["blipuid"] = new RtfCtrlWordHandler(rtfParser, "blipuid", 0, false, RtfCtrlWordType.VALUE, "\\*\\", " ", "RtfDestinationShppict");//"RtfDestinationBlipuid"; + ctrlWords["blipupi"] = new RtfCtrlWordHandler(rtfParser, "blipupi", 0, true, RtfCtrlWordType.VALUE, "\\", " ", "RtfDestinationShppict"); + ctrlWords["blue"] = new RtfCtrlWordHandler(rtfParser, "blue", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["bookfold"] = new RtfCtrlWordHandler(rtfParser, "bookfold", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bookfoldrev"] = new RtfCtrlWordHandler(rtfParser, "bookfoldrev", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["bookfoldsheets"] = new RtfCtrlWordHandler(rtfParser, "bookfoldsheets", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["box"] = new RtfCtrlWordHandler(rtfParser, "box", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrart"] = new RtfCtrlWordHandler(rtfParser, "brdrart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["brdrb"] = new RtfCtrlWordHandler(rtfParser, "brdrb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrbar"] = new RtfCtrlWordHandler(rtfParser, "brdrbar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrbtw"] = new RtfCtrlWordHandler(rtfParser, "brdrbtw", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrcf"] = new RtfCtrlWordHandler(rtfParser, "brdrcf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["brdrdash"] = new RtfCtrlWordHandler(rtfParser, "brdrdash", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrdashd"] = new RtfCtrlWordHandler(rtfParser, "brdrdashd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrdashdd"] = new RtfCtrlWordHandler(rtfParser, "brdrdashdd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrdashdotstr"] = new RtfCtrlWordHandler(rtfParser, "brdrdashdotstr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrdashsm"] = new RtfCtrlWordHandler(rtfParser, "brdrdashsm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrdb"] = new RtfCtrlWordHandler(rtfParser, "brdrdb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrdot"] = new RtfCtrlWordHandler(rtfParser, "brdrdot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdremboss"] = new RtfCtrlWordHandler(rtfParser, "brdremboss", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrengrave"] = new RtfCtrlWordHandler(rtfParser, "brdrengrave", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrframe"] = new RtfCtrlWordHandler(rtfParser, "brdrframe", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrhair"] = new RtfCtrlWordHandler(rtfParser, "brdrhair", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrinset"] = new RtfCtrlWordHandler(rtfParser, "brdrinset", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrl"] = new RtfCtrlWordHandler(rtfParser, "brdrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrnil"] = new RtfCtrlWordHandler(rtfParser, "brdrnil", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrnone"] = new RtfCtrlWordHandler(rtfParser, "brdrnone", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["brdroutset"] = new RtfCtrlWordHandler(rtfParser, "brdroutset", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrr"] = new RtfCtrlWordHandler(rtfParser, "brdrr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrs"] = new RtfCtrlWordHandler(rtfParser, "brdrs", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrsh"] = new RtfCtrlWordHandler(rtfParser, "brdrsh", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrt"] = new RtfCtrlWordHandler(rtfParser, "brdrt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtbl"] = new RtfCtrlWordHandler(rtfParser, "brdrtbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrth"] = new RtfCtrlWordHandler(rtfParser, "brdrth", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrthtnlg"] = new RtfCtrlWordHandler(rtfParser, "brdrthtnlg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrthtnmg"] = new RtfCtrlWordHandler(rtfParser, "brdrthtnmg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrthtnsg"] = new RtfCtrlWordHandler(rtfParser, "brdrthtnsg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtnthlg"] = new RtfCtrlWordHandler(rtfParser, "brdrtnthlg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtnthmg"] = new RtfCtrlWordHandler(rtfParser, "brdrtnthmg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtnthsg"] = new RtfCtrlWordHandler(rtfParser, "brdrtnthsg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtnthtnlg"] = new RtfCtrlWordHandler(rtfParser, "brdrtnthtnlg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtnthtnmg"] = new RtfCtrlWordHandler(rtfParser, "brdrtnthtnmg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtnthtnsg"] = new RtfCtrlWordHandler(rtfParser, "brdrtnthtnsg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrtriple"] = new RtfCtrlWordHandler(rtfParser, "brdrtriple", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrw"] = new RtfCtrlWordHandler(rtfParser, "brdrw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["brdrwavy"] = new RtfCtrlWordHandler(rtfParser, "brdrwavy", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brdrwavydb"] = new RtfCtrlWordHandler(rtfParser, "brdrwavydb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brkfrm"] = new RtfCtrlWordHandler(rtfParser, "brkfrm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["brsp"] = new RtfCtrlWordHandler(rtfParser, "brsp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["bullet"] = new RtfCtrlWordHandler(rtfParser, "bullet", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x149"); + ctrlWords["buptim"] = new RtfCtrlWordHandler(rtfParser, "buptim", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["bxe"] = new RtfCtrlWordHandler(rtfParser, "bxe", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caccentfive"] = new RtfCtrlWordHandler(rtfParser, "caccentfive", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caccentfour"] = new RtfCtrlWordHandler(rtfParser, "caccentfour", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caccentone"] = new RtfCtrlWordHandler(rtfParser, "caccentone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caccentsix"] = new RtfCtrlWordHandler(rtfParser, "caccentsix", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caccentthree"] = new RtfCtrlWordHandler(rtfParser, "caccentthree", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caccenttwo"] = new RtfCtrlWordHandler(rtfParser, "caccenttwo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cachedcolbal"] = new RtfCtrlWordHandler(rtfParser, "cachedcolbal", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["caps"] = new RtfCtrlWordHandler(rtfParser, "caps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["category"] = new RtfCtrlWordHandler(rtfParser, "category", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["cb"] = new RtfCtrlWordHandler(rtfParser, "cb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cbackgroundone"] = new RtfCtrlWordHandler(rtfParser, "cbackgroundone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cbackgroundtwo"] = new RtfCtrlWordHandler(rtfParser, "cbackgroundtwo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cbpat"] = new RtfCtrlWordHandler(rtfParser, "cbpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cchs"] = new RtfCtrlWordHandler(rtfParser, "cchs", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cell"] = new RtfCtrlWordHandler(rtfParser, "cell", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["cellx"] = new RtfCtrlWordHandler(rtfParser, "cellx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cf"] = new RtfCtrlWordHandler(rtfParser, "cf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cfollowedhyperlink"] = new RtfCtrlWordHandler(rtfParser, "cfollowedhyperlink", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cfpat"] = new RtfCtrlWordHandler(rtfParser, "cfpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cgrid"] = new RtfCtrlWordHandler(rtfParser, "cgrid", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["charrsid"] = new RtfCtrlWordHandler(rtfParser, "charrsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["charscalex"] = new RtfCtrlWordHandler(rtfParser, "charscalex", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["chatn"] = new RtfCtrlWordHandler(rtfParser, "chatn", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chbgbdiag"] = new RtfCtrlWordHandler(rtfParser, "chbgbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgcross"] = new RtfCtrlWordHandler(rtfParser, "chbgcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdcross"] = new RtfCtrlWordHandler(rtfParser, "chbgdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "chbgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdkcross"] = new RtfCtrlWordHandler(rtfParser, "chbgdkcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdkdcross"] = new RtfCtrlWordHandler(rtfParser, "chbgdkdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdkfdiag"] = new RtfCtrlWordHandler(rtfParser, "chbgdkfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdkhoriz"] = new RtfCtrlWordHandler(rtfParser, "chbgdkhoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgdkvert"] = new RtfCtrlWordHandler(rtfParser, "chbgdkvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgfdiag"] = new RtfCtrlWordHandler(rtfParser, "chbgfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbghoriz"] = new RtfCtrlWordHandler(rtfParser, "chbghoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbgvert"] = new RtfCtrlWordHandler(rtfParser, "chbgvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chbrdr"] = new RtfCtrlWordHandler(rtfParser, "chbrdr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["chcbpat"] = new RtfCtrlWordHandler(rtfParser, "chcbpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["chcfpat"] = new RtfCtrlWordHandler(rtfParser, "chcfpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["chdate"] = new RtfCtrlWordHandler(rtfParser, "chdate", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chdpa"] = new RtfCtrlWordHandler(rtfParser, "chdpa", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chdpl"] = new RtfCtrlWordHandler(rtfParser, "chdpl", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chftn"] = new RtfCtrlWordHandler(rtfParser, "chftn", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chftnsep"] = new RtfCtrlWordHandler(rtfParser, "chftnsep", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chftnsepc"] = new RtfCtrlWordHandler(rtfParser, "chftnsepc", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chpgn"] = new RtfCtrlWordHandler(rtfParser, "chpgn", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chshdng"] = new RtfCtrlWordHandler(rtfParser, "chshdng", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["chtime"] = new RtfCtrlWordHandler(rtfParser, "chtime", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["chyperlink"] = new RtfCtrlWordHandler(rtfParser, "chyperlink", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clFitText"] = new RtfCtrlWordHandler(rtfParser, "clFitText", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clNoWrap"] = new RtfCtrlWordHandler(rtfParser, "clNoWrap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgbdiag"] = new RtfCtrlWordHandler(rtfParser, "clbgbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgcross"] = new RtfCtrlWordHandler(rtfParser, "clbgcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdcross"] = new RtfCtrlWordHandler(rtfParser, "clbgdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "clbgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdkcross"] = new RtfCtrlWordHandler(rtfParser, "clbgdkcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdkdcross"] = new RtfCtrlWordHandler(rtfParser, "clbgdkdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdkfdiag"] = new RtfCtrlWordHandler(rtfParser, "clbgdkfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdkhor"] = new RtfCtrlWordHandler(rtfParser, "clbgdkhor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgdkvert"] = new RtfCtrlWordHandler(rtfParser, "clbgdkvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgfdiag"] = new RtfCtrlWordHandler(rtfParser, "clbgfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbghoriz"] = new RtfCtrlWordHandler(rtfParser, "clbghoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbgvert"] = new RtfCtrlWordHandler(rtfParser, "clbgvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbrdrb"] = new RtfCtrlWordHandler(rtfParser, "clbrdrb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbrdrl"] = new RtfCtrlWordHandler(rtfParser, "clbrdrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbrdrr"] = new RtfCtrlWordHandler(rtfParser, "clbrdrr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clbrdrt"] = new RtfCtrlWordHandler(rtfParser, "clbrdrt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clcbpat"] = new RtfCtrlWordHandler(rtfParser, "clcbpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clcbpatraw"] = new RtfCtrlWordHandler(rtfParser, "clcbpatraw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clcfpat"] = new RtfCtrlWordHandler(rtfParser, "clcfpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clcfpatraw"] = new RtfCtrlWordHandler(rtfParser, "clcfpatraw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cldel"] = new RtfCtrlWordHandler(rtfParser, "cldel", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cldelauth"] = new RtfCtrlWordHandler(rtfParser, "cldelauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cldeldttm"] = new RtfCtrlWordHandler(rtfParser, "cldeldttm", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cldgll"] = new RtfCtrlWordHandler(rtfParser, "cldgll", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cldglu"] = new RtfCtrlWordHandler(rtfParser, "cldglu", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clftsWidth"] = new RtfCtrlWordHandler(rtfParser, "clftsWidth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clhidemark"] = new RtfCtrlWordHandler(rtfParser, "clhidemark", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clins"] = new RtfCtrlWordHandler(rtfParser, "clins", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clinsauth"] = new RtfCtrlWordHandler(rtfParser, "clinsauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clinsdttm"] = new RtfCtrlWordHandler(rtfParser, "clinsdttm", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clmgf"] = new RtfCtrlWordHandler(rtfParser, "clmgf", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clmrg"] = new RtfCtrlWordHandler(rtfParser, "clmrg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clmrgd"] = new RtfCtrlWordHandler(rtfParser, "clmrgd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clmrgdauth"] = new RtfCtrlWordHandler(rtfParser, "clmrgdauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clmrgddttm"] = new RtfCtrlWordHandler(rtfParser, "clmrgddttm", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clmrgdr"] = new RtfCtrlWordHandler(rtfParser, "clmrgdr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clpadb"] = new RtfCtrlWordHandler(rtfParser, "clpadb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadfb"] = new RtfCtrlWordHandler(rtfParser, "clpadfb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadfl"] = new RtfCtrlWordHandler(rtfParser, "clpadfl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadfr"] = new RtfCtrlWordHandler(rtfParser, "clpadfr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadft"] = new RtfCtrlWordHandler(rtfParser, "clpadft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadl"] = new RtfCtrlWordHandler(rtfParser, "clpadl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadr"] = new RtfCtrlWordHandler(rtfParser, "clpadr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clpadt"] = new RtfCtrlWordHandler(rtfParser, "clpadt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clshdng"] = new RtfCtrlWordHandler(rtfParser, "clshdng", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clshdngraw"] = new RtfCtrlWordHandler(rtfParser, "clshdngraw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["clshdrawnil"] = new RtfCtrlWordHandler(rtfParser, "clshdrawnil", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clsplit"] = new RtfCtrlWordHandler(rtfParser, "clsplit", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clsplitr"] = new RtfCtrlWordHandler(rtfParser, "clsplitr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cltxbtlr"] = new RtfCtrlWordHandler(rtfParser, "cltxbtlr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cltxlrtb"] = new RtfCtrlWordHandler(rtfParser, "cltxlrtb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cltxlrtbv"] = new RtfCtrlWordHandler(rtfParser, "cltxlrtbv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cltxtbrl"] = new RtfCtrlWordHandler(rtfParser, "cltxtbrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cltxtbrlv"] = new RtfCtrlWordHandler(rtfParser, "cltxtbrlv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clvertalb"] = new RtfCtrlWordHandler(rtfParser, "clvertalb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clvertalc"] = new RtfCtrlWordHandler(rtfParser, "clvertalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clvertalt"] = new RtfCtrlWordHandler(rtfParser, "clvertalt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clvmgf"] = new RtfCtrlWordHandler(rtfParser, "clvmgf", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clvmrg"] = new RtfCtrlWordHandler(rtfParser, "clvmrg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["clwWidth"] = new RtfCtrlWordHandler(rtfParser, "clwWidth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cmaindarkone"] = new RtfCtrlWordHandler(rtfParser, "cmaindarkone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cmaindarktwo"] = new RtfCtrlWordHandler(rtfParser, "cmaindarktwo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cmainlightone"] = new RtfCtrlWordHandler(rtfParser, "cmainlightone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cmainlighttwo"] = new RtfCtrlWordHandler(rtfParser, "cmainlighttwo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["collapsed"] = new RtfCtrlWordHandler(rtfParser, "collapsed", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["colno"] = new RtfCtrlWordHandler(rtfParser, "colno", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["colorschememapping"] = new RtfCtrlWordHandler(rtfParser, "colorschememapping", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", null); + ctrlWords["colortbl"] = new RtfCtrlWordHandler(rtfParser, "colortbl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationColorTable"); + ctrlWords["cols"] = new RtfCtrlWordHandler(rtfParser, "cols", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["colsr"] = new RtfCtrlWordHandler(rtfParser, "colsr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["colsx"] = new RtfCtrlWordHandler(rtfParser, "colsx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["column"] = new RtfCtrlWordHandler(rtfParser, "column", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["colw"] = new RtfCtrlWordHandler(rtfParser, "colw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["comment"] = new RtfCtrlWordHandler(rtfParser, "comment", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["company"] = new RtfCtrlWordHandler(rtfParser, "company", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["contextualspace"] = new RtfCtrlWordHandler(rtfParser, "contextualspace", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cpg"] = new RtfCtrlWordHandler(rtfParser, "cpg", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["crauth"] = new RtfCtrlWordHandler(rtfParser, "crauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["crdate"] = new RtfCtrlWordHandler(rtfParser, "crdate", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["creatim"] = new RtfCtrlWordHandler(rtfParser, "creatim", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["cs"] = new RtfCtrlWordHandler(rtfParser, "cs", 0, true, RtfCtrlWordType.VALUE, "\\*\\", " ", null); + ctrlWords["cshade"] = new RtfCtrlWordHandler(rtfParser, "cshade", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ctextone"] = new RtfCtrlWordHandler(rtfParser, "ctextone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ctexttwo"] = new RtfCtrlWordHandler(rtfParser, "ctexttwo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ctint"] = new RtfCtrlWordHandler(rtfParser, "ctint", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ctrl"] = new RtfCtrlWordHandler(rtfParser, "ctrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["cts"] = new RtfCtrlWordHandler(rtfParser, "cts", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cufi"] = new RtfCtrlWordHandler(rtfParser, "cufi", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["culi"] = new RtfCtrlWordHandler(rtfParser, "culi", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["curi"] = new RtfCtrlWordHandler(rtfParser, "curi", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["cvmme"] = new RtfCtrlWordHandler(rtfParser, "cvmme", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["datafield"] = new RtfCtrlWordHandler(rtfParser, "datafield", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["datastore"] = new RtfCtrlWordHandler(rtfParser, "datastore", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["date"] = new RtfCtrlWordHandler(rtfParser, "date", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dbch"] = new RtfCtrlWordHandler(rtfParser, "dbch", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["defchp"] = new RtfCtrlWordHandler(rtfParser, "defchp", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["deff"] = new RtfCtrlWordHandler(rtfParser, "deff", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["defformat"] = new RtfCtrlWordHandler(rtfParser, "defformat", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["deflang"] = new RtfCtrlWordHandler(rtfParser, "deflang", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["deflangfe"] = new RtfCtrlWordHandler(rtfParser, "deflangfe", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["defpap"] = new RtfCtrlWordHandler(rtfParser, "defpap", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["defshp"] = new RtfCtrlWordHandler(rtfParser, "defshp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["deftab"] = new RtfCtrlWordHandler(rtfParser, "deftab", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["deleted"] = new RtfCtrlWordHandler(rtfParser, "deleted", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["delrsid"] = new RtfCtrlWordHandler(rtfParser, "delrsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrauth"] = new RtfCtrlWordHandler(rtfParser, "dfrauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrdate"] = new RtfCtrlWordHandler(rtfParser, "dfrdate", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrmtxtx"] = new RtfCtrlWordHandler(rtfParser, "dfrmtxtx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrmtxty"] = new RtfCtrlWordHandler(rtfParser, "dfrmtxty", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrstart"] = new RtfCtrlWordHandler(rtfParser, "dfrstart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrstop"] = new RtfCtrlWordHandler(rtfParser, "dfrstop", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dfrxst"] = new RtfCtrlWordHandler(rtfParser, "dfrxst", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dghorigin"] = new RtfCtrlWordHandler(rtfParser, "dghorigin", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dghshow"] = new RtfCtrlWordHandler(rtfParser, "dghshow", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dghspace"] = new RtfCtrlWordHandler(rtfParser, "dghspace", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dgmargin"] = new RtfCtrlWordHandler(rtfParser, "dgmargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dgsnap"] = new RtfCtrlWordHandler(rtfParser, "dgsnap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dgvorigin"] = new RtfCtrlWordHandler(rtfParser, "dgvorigin", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dgvshow"] = new RtfCtrlWordHandler(rtfParser, "dgvshow", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dgvspace"] = new RtfCtrlWordHandler(rtfParser, "dgvspace", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dibitmap"] = new RtfCtrlWordHandler(rtfParser, "dibitmap", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dn"] = new RtfCtrlWordHandler(rtfParser, "dn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dntblnsbdb"] = new RtfCtrlWordHandler(rtfParser, "dntblnsbdb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["do"] = new RtfCtrlWordHandler(rtfParser, "do", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["dobxcolumn"] = new RtfCtrlWordHandler(rtfParser, "dobxcolumn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dobxmargin"] = new RtfCtrlWordHandler(rtfParser, "dobxmargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dobxpage"] = new RtfCtrlWordHandler(rtfParser, "dobxpage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dobymargin"] = new RtfCtrlWordHandler(rtfParser, "dobymargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dobypage"] = new RtfCtrlWordHandler(rtfParser, "dobypage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dobypara"] = new RtfCtrlWordHandler(rtfParser, "dobypara", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["doccomm"] = new RtfCtrlWordHandler(rtfParser, "doccomm", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["doctemp"] = new RtfCtrlWordHandler(rtfParser, "doctemp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["doctype"] = new RtfCtrlWordHandler(rtfParser, "doctype", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["docvar"] = new RtfCtrlWordHandler(rtfParser, "docvar", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["dodhgt"] = new RtfCtrlWordHandler(rtfParser, "dodhgt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dolock"] = new RtfCtrlWordHandler(rtfParser, "dolock", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["donotembedlingdata"] = new RtfCtrlWordHandler(rtfParser, "donotembedlingdata", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["donotembedsysfont"] = new RtfCtrlWordHandler(rtfParser, "donotembedsysfont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["donotshowcomments"] = new RtfCtrlWordHandler(rtfParser, "donotshowcomments", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["donotshowinsdel"] = new RtfCtrlWordHandler(rtfParser, "donotshowinsdel", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["donotshowmarkup"] = new RtfCtrlWordHandler(rtfParser, "donotshowmarkup", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["donotshowprops"] = new RtfCtrlWordHandler(rtfParser, "donotshowprops", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpaendhol"] = new RtfCtrlWordHandler(rtfParser, "dpaendhol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpaendl"] = new RtfCtrlWordHandler(rtfParser, "dpaendl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpaendsol"] = new RtfCtrlWordHandler(rtfParser, "dpaendsol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpaendw"] = new RtfCtrlWordHandler(rtfParser, "dpaendw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dparc"] = new RtfCtrlWordHandler(rtfParser, "dparc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dparcflipx"] = new RtfCtrlWordHandler(rtfParser, "dparcflipx", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dparcflipy"] = new RtfCtrlWordHandler(rtfParser, "dparcflipy", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpastarthol"] = new RtfCtrlWordHandler(rtfParser, "dpastarthol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpastartl"] = new RtfCtrlWordHandler(rtfParser, "dpastartl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpastartsol"] = new RtfCtrlWordHandler(rtfParser, "dpastartsol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpastartw"] = new RtfCtrlWordHandler(rtfParser, "dpastartw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpcallout"] = new RtfCtrlWordHandler(rtfParser, "dpcallout", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcoa"] = new RtfCtrlWordHandler(rtfParser, "dpcoa", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpcoaccent"] = new RtfCtrlWordHandler(rtfParser, "dpcoaccent", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcobestfit"] = new RtfCtrlWordHandler(rtfParser, "dpcobestfit", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcoborder"] = new RtfCtrlWordHandler(rtfParser, "dpcoborder", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcodabs"] = new RtfCtrlWordHandler(rtfParser, "dpcodabs", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpcodbottom"] = new RtfCtrlWordHandler(rtfParser, "dpcodbottom", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcodcenter"] = new RtfCtrlWordHandler(rtfParser, "dpcodcenter", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcodescent"] = new RtfCtrlWordHandler(rtfParser, "dpcodescent", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpcodtop"] = new RtfCtrlWordHandler(rtfParser, "dpcodtop", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcolength"] = new RtfCtrlWordHandler(rtfParser, "dpcolength", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpcominusx"] = new RtfCtrlWordHandler(rtfParser, "dpcominusx", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcominusy"] = new RtfCtrlWordHandler(rtfParser, "dpcominusy", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcooffset"] = new RtfCtrlWordHandler(rtfParser, "dpcooffset", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpcosmarta"] = new RtfCtrlWordHandler(rtfParser, "dpcosmarta", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcotdouble"] = new RtfCtrlWordHandler(rtfParser, "dpcotdouble", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcotright"] = new RtfCtrlWordHandler(rtfParser, "dpcotright", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcotsingle"] = new RtfCtrlWordHandler(rtfParser, "dpcotsingle", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcottriple"] = new RtfCtrlWordHandler(rtfParser, "dpcottriple", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpcount"] = new RtfCtrlWordHandler(rtfParser, "dpcount", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpellipse"] = new RtfCtrlWordHandler(rtfParser, "dpellipse", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpendgroup"] = new RtfCtrlWordHandler(rtfParser, "dpendgroup", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpfillbgcb"] = new RtfCtrlWordHandler(rtfParser, "dpfillbgcb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillbgcg"] = new RtfCtrlWordHandler(rtfParser, "dpfillbgcg", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillbgcr"] = new RtfCtrlWordHandler(rtfParser, "dpfillbgcr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillbggray"] = new RtfCtrlWordHandler(rtfParser, "dpfillbggray", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillbgpal"] = new RtfCtrlWordHandler(rtfParser, "dpfillbgpal", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpfillfgcb"] = new RtfCtrlWordHandler(rtfParser, "dpfillfgcb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillfgcg"] = new RtfCtrlWordHandler(rtfParser, "dpfillfgcg", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillfgcr"] = new RtfCtrlWordHandler(rtfParser, "dpfillfgcr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillfggray"] = new RtfCtrlWordHandler(rtfParser, "dpfillfggray", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpfillfgpal"] = new RtfCtrlWordHandler(rtfParser, "dpfillfgpal", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpfillpat"] = new RtfCtrlWordHandler(rtfParser, "dpfillpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpgroup"] = new RtfCtrlWordHandler(rtfParser, "dpgroup", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpline"] = new RtfCtrlWordHandler(rtfParser, "dpline", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinecob"] = new RtfCtrlWordHandler(rtfParser, "dplinecob", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dplinecog"] = new RtfCtrlWordHandler(rtfParser, "dplinecog", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dplinecor"] = new RtfCtrlWordHandler(rtfParser, "dplinecor", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dplinedado"] = new RtfCtrlWordHandler(rtfParser, "dplinedado", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinedadodo"] = new RtfCtrlWordHandler(rtfParser, "dplinedadodo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinedash"] = new RtfCtrlWordHandler(rtfParser, "dplinedash", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinedot"] = new RtfCtrlWordHandler(rtfParser, "dplinedot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinegray"] = new RtfCtrlWordHandler(rtfParser, "dplinegray", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dplinehollow"] = new RtfCtrlWordHandler(rtfParser, "dplinehollow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinepal"] = new RtfCtrlWordHandler(rtfParser, "dplinepal", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinesolid"] = new RtfCtrlWordHandler(rtfParser, "dplinesolid", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dplinew"] = new RtfCtrlWordHandler(rtfParser, "dplinew", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dppolycount"] = new RtfCtrlWordHandler(rtfParser, "dppolycount", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dppolygon"] = new RtfCtrlWordHandler(rtfParser, "dppolygon", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dppolyline"] = new RtfCtrlWordHandler(rtfParser, "dppolyline", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpptx"] = new RtfCtrlWordHandler(rtfParser, "dpptx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dppty"] = new RtfCtrlWordHandler(rtfParser, "dppty", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dprect"] = new RtfCtrlWordHandler(rtfParser, "dprect", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dproundr"] = new RtfCtrlWordHandler(rtfParser, "dproundr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpshadow"] = new RtfCtrlWordHandler(rtfParser, "dpshadow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpshadx"] = new RtfCtrlWordHandler(rtfParser, "dpshadx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpshady"] = new RtfCtrlWordHandler(rtfParser, "dpshady", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dptxbtlr"] = new RtfCtrlWordHandler(rtfParser, "dptxbtlr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dptxbx"] = new RtfCtrlWordHandler(rtfParser, "dptxbx", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dptxbxmar"] = new RtfCtrlWordHandler(rtfParser, "dptxbxmar", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dptxbxtext"] = new RtfCtrlWordHandler(rtfParser, "dptxbxtext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", null); + ctrlWords["dptxlrtb"] = new RtfCtrlWordHandler(rtfParser, "dptxlrtb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dptxlrtbv"] = new RtfCtrlWordHandler(rtfParser, "dptxlrtbv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dptxtbrl"] = new RtfCtrlWordHandler(rtfParser, "dptxtbrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dptxtbrlv"] = new RtfCtrlWordHandler(rtfParser, "dptxtbrlv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["dpx"] = new RtfCtrlWordHandler(rtfParser, "dpx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpxsize"] = new RtfCtrlWordHandler(rtfParser, "dpxsize", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpy"] = new RtfCtrlWordHandler(rtfParser, "dpy", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dpysize"] = new RtfCtrlWordHandler(rtfParser, "dpysize", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dropcapli"] = new RtfCtrlWordHandler(rtfParser, "dropcapli", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dropcapt"] = new RtfCtrlWordHandler(rtfParser, "dropcapt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ds"] = new RtfCtrlWordHandler(rtfParser, "ds", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dxfrtext"] = new RtfCtrlWordHandler(rtfParser, "dxfrtext", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["dy"] = new RtfCtrlWordHandler(rtfParser, "dy", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ebcend"] = new RtfCtrlWordHandler(rtfParser, "ebcend", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", null); + ctrlWords["ebcstart"] = new RtfCtrlWordHandler(rtfParser, "ebcstart", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", null); + ctrlWords["edmins"] = new RtfCtrlWordHandler(rtfParser, "edmins", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["embo"] = new RtfCtrlWordHandler(rtfParser, "embo", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["emdash"] = new RtfCtrlWordHandler(rtfParser, "emdash", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x151"); + ctrlWords["emfblip"] = new RtfCtrlWordHandler(rtfParser, "emfblip", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["emspace"] = new RtfCtrlWordHandler(rtfParser, "emspace", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["endash"] = new RtfCtrlWordHandler(rtfParser, "endash", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x150"); + ctrlWords["enddoc"] = new RtfCtrlWordHandler(rtfParser, "enddoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["endnhere"] = new RtfCtrlWordHandler(rtfParser, "endnhere", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["endnotes"] = new RtfCtrlWordHandler(rtfParser, "endnotes", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["enforceprot"] = new RtfCtrlWordHandler(rtfParser, "enforceprot", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["enspace"] = new RtfCtrlWordHandler(rtfParser, "enspace", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["expnd"] = new RtfCtrlWordHandler(rtfParser, "expnd", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["expndtw"] = new RtfCtrlWordHandler(rtfParser, "expndtw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["expshrtn"] = new RtfCtrlWordHandler(rtfParser, "expshrtn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["f"] = new RtfCtrlWordHandler(rtfParser, "f", 0, true, RtfCtrlWordType.VALUE, "\\", " ", RtfProperty.CHARACTER_FONT); + ctrlWords["faauto"] = new RtfCtrlWordHandler(rtfParser, "faauto", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["facenter"] = new RtfCtrlWordHandler(rtfParser, "facenter", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["facingp"] = new RtfCtrlWordHandler(rtfParser, "facingp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["factoidname"] = new RtfCtrlWordHandler(rtfParser, "factoidname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", null); + ctrlWords["fafixed"] = new RtfCtrlWordHandler(rtfParser, "fafixed", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fahang"] = new RtfCtrlWordHandler(rtfParser, "fahang", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["falt"] = new RtfCtrlWordHandler(rtfParser, "falt", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationFontTable"); //"RtfDestinationAlternateFont"; + ctrlWords["faroman"] = new RtfCtrlWordHandler(rtfParser, "faroman", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["favar"] = new RtfCtrlWordHandler(rtfParser, "favar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fbias"] = new RtfCtrlWordHandler(rtfParser, "fbias", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fbidi"] = new RtfCtrlWordHandler(rtfParser, "fbidi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fbimajor"] = new RtfCtrlWordHandler(rtfParser, "fbimajor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fbiminor"] = new RtfCtrlWordHandler(rtfParser, "fbiminor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fchars"] = new RtfCtrlWordHandler(rtfParser, "fchars", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", null); + ctrlWords["fcharset"] = new RtfCtrlWordHandler(rtfParser, "fcharset", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fdbmajor"] = new RtfCtrlWordHandler(rtfParser, "fdbmajor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fdbminor"] = new RtfCtrlWordHandler(rtfParser, "fdbminor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fdecor"] = new RtfCtrlWordHandler(rtfParser, "fdecor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["felnbrelev"] = new RtfCtrlWordHandler(rtfParser, "felnbrelev", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fet"] = new RtfCtrlWordHandler(rtfParser, "fet", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fetch"] = new RtfCtrlWordHandler(rtfParser, "fetch", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ffdefres"] = new RtfCtrlWordHandler(rtfParser, "ffdefres", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffdeftext"] = new RtfCtrlWordHandler(rtfParser, "ffdeftext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ffentrymcr"] = new RtfCtrlWordHandler(rtfParser, "ffentrymcr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ffexitmcr"] = new RtfCtrlWordHandler(rtfParser, "ffexitmcr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ffformat"] = new RtfCtrlWordHandler(rtfParser, "ffformat", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ffhaslistbox"] = new RtfCtrlWordHandler(rtfParser, "ffhaslistbox", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffhelptext"] = new RtfCtrlWordHandler(rtfParser, "ffhelptext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ffhps"] = new RtfCtrlWordHandler(rtfParser, "ffhps", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffl"] = new RtfCtrlWordHandler(rtfParser, "ffl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ffmaxlen"] = new RtfCtrlWordHandler(rtfParser, "ffmaxlen", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffname"] = new RtfCtrlWordHandler(rtfParser, "ffname", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["ffownhelp"] = new RtfCtrlWordHandler(rtfParser, "ffownhelp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffownstat"] = new RtfCtrlWordHandler(rtfParser, "ffownstat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffprot"] = new RtfCtrlWordHandler(rtfParser, "ffprot", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffrecalc"] = new RtfCtrlWordHandler(rtfParser, "ffrecalc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffres"] = new RtfCtrlWordHandler(rtfParser, "ffres", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffsize"] = new RtfCtrlWordHandler(rtfParser, "ffsize", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ffstattext"] = new RtfCtrlWordHandler(rtfParser, "ffstattext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["fftype"] = new RtfCtrlWordHandler(rtfParser, "fftype", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fftypetxt"] = new RtfCtrlWordHandler(rtfParser, "fftypetxt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fhimajor"] = new RtfCtrlWordHandler(rtfParser, "fhimajor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fhiminor"] = new RtfCtrlWordHandler(rtfParser, "fhiminor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fi"] = new RtfCtrlWordHandler(rtfParser, "fi", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fid"] = new RtfCtrlWordHandler(rtfParser, "fid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["field"] = new RtfCtrlWordHandler(rtfParser, "field", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["file"] = new RtfCtrlWordHandler(rtfParser, "file", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["filetbl"] = new RtfCtrlWordHandler(rtfParser, "filetbl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["fittext"] = new RtfCtrlWordHandler(rtfParser, "fittext", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fjgothic"] = new RtfCtrlWordHandler(rtfParser, "fjgothic", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fjminchou"] = new RtfCtrlWordHandler(rtfParser, "fjminchou", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fldalt"] = new RtfCtrlWordHandler(rtfParser, "fldalt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["flddirty"] = new RtfCtrlWordHandler(rtfParser, "flddirty", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fldedit"] = new RtfCtrlWordHandler(rtfParser, "fldedit", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fldinst"] = new RtfCtrlWordHandler(rtfParser, "fldinst", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["fldlock"] = new RtfCtrlWordHandler(rtfParser, "fldlock", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fldpriv"] = new RtfCtrlWordHandler(rtfParser, "fldpriv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fldrslt"] = new RtfCtrlWordHandler(rtfParser, "fldrslt", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["fldtype"] = new RtfCtrlWordHandler(rtfParser, "fldtype", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["flomajor"] = new RtfCtrlWordHandler(rtfParser, "flomajor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["flominor"] = new RtfCtrlWordHandler(rtfParser, "flominor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fmodern"] = new RtfCtrlWordHandler(rtfParser, "fmodern", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fn"] = new RtfCtrlWordHandler(rtfParser, "fn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fname"] = new RtfCtrlWordHandler(rtfParser, "fname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["fnetwork"] = new RtfCtrlWordHandler(rtfParser, "fnetwork", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fnil"] = new RtfCtrlWordHandler(rtfParser, "fnil", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fnonfilesys"] = new RtfCtrlWordHandler(rtfParser, "fnonfilesys", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fontemb"] = new RtfCtrlWordHandler(rtfParser, "fontemb", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["fontfile"] = new RtfCtrlWordHandler(rtfParser, "fontfile", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["fonttbl"] = new RtfCtrlWordHandler(rtfParser, "fonttbl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationFontTable"); + ctrlWords["footer"] = new RtfCtrlWordHandler(rtfParser, "footer", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["footerf"] = new RtfCtrlWordHandler(rtfParser, "footerf", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["footerl"] = new RtfCtrlWordHandler(rtfParser, "footerl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", null); + ctrlWords["footerr"] = new RtfCtrlWordHandler(rtfParser, "footerr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["footery"] = new RtfCtrlWordHandler(rtfParser, "footery", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["footnote"] = new RtfCtrlWordHandler(rtfParser, "footnote", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["forceupgrade"] = new RtfCtrlWordHandler(rtfParser, "forceupgrade", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["formdisp"] = new RtfCtrlWordHandler(rtfParser, "formdisp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["formfield"] = new RtfCtrlWordHandler(rtfParser, "formfield", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["formprot"] = new RtfCtrlWordHandler(rtfParser, "formprot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["formshade"] = new RtfCtrlWordHandler(rtfParser, "formshade", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fosnum"] = new RtfCtrlWordHandler(rtfParser, "fosnum", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fprq"] = new RtfCtrlWordHandler(rtfParser, "fprq", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fracwidth"] = new RtfCtrlWordHandler(rtfParser, "fracwidth", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["frelative"] = new RtfCtrlWordHandler(rtfParser, "frelative", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["frmtxbtlr"] = new RtfCtrlWordHandler(rtfParser, "frmtxbtlr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["frmtxlrtb"] = new RtfCtrlWordHandler(rtfParser, "frmtxlrtb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["frmtxlrtbv"] = new RtfCtrlWordHandler(rtfParser, "frmtxlrtbv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["frmtxtbrl"] = new RtfCtrlWordHandler(rtfParser, "frmtxtbrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["frmtxtbrlv"] = new RtfCtrlWordHandler(rtfParser, "frmtxtbrlv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["froman"] = new RtfCtrlWordHandler(rtfParser, "froman", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fromhtml"] = new RtfCtrlWordHandler(rtfParser, "fromhtml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fromtext"] = new RtfCtrlWordHandler(rtfParser, "fromtext", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fs"] = new RtfCtrlWordHandler(rtfParser, "fs", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["fscript"] = new RtfCtrlWordHandler(rtfParser, "fscript", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fswiss"] = new RtfCtrlWordHandler(rtfParser, "fswiss", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftech"] = new RtfCtrlWordHandler(rtfParser, "ftech", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnalt"] = new RtfCtrlWordHandler(rtfParser, "ftnalt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnbj"] = new RtfCtrlWordHandler(rtfParser, "ftnbj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftncn"] = new RtfCtrlWordHandler(rtfParser, "ftncn", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ftnil"] = new RtfCtrlWordHandler(rtfParser, "ftnil", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnlytwnine"] = new RtfCtrlWordHandler(rtfParser, "ftnlytwnine", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnalc"] = new RtfCtrlWordHandler(rtfParser, "ftnnalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnar"] = new RtfCtrlWordHandler(rtfParser, "ftnnar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnauc"] = new RtfCtrlWordHandler(rtfParser, "ftnnauc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnchi"] = new RtfCtrlWordHandler(rtfParser, "ftnnchi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnchosung"] = new RtfCtrlWordHandler(rtfParser, "ftnnchosung", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnncnum"] = new RtfCtrlWordHandler(rtfParser, "ftnncnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnndbar"] = new RtfCtrlWordHandler(rtfParser, "ftnndbar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnndbnum"] = new RtfCtrlWordHandler(rtfParser, "ftnndbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnndbnumd"] = new RtfCtrlWordHandler(rtfParser, "ftnndbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnndbnumk"] = new RtfCtrlWordHandler(rtfParser, "ftnndbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnndbnumt"] = new RtfCtrlWordHandler(rtfParser, "ftnndbnumt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnganada"] = new RtfCtrlWordHandler(rtfParser, "ftnnganada", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnngbnum"] = new RtfCtrlWordHandler(rtfParser, "ftnngbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnngbnumd"] = new RtfCtrlWordHandler(rtfParser, "ftnngbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnngbnumk"] = new RtfCtrlWordHandler(rtfParser, "ftnngbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnngbnuml"] = new RtfCtrlWordHandler(rtfParser, "ftnngbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnrlc"] = new RtfCtrlWordHandler(rtfParser, "ftnnrlc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnruc"] = new RtfCtrlWordHandler(rtfParser, "ftnnruc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnzodiac"] = new RtfCtrlWordHandler(rtfParser, "ftnnzodiac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnzodiacd"] = new RtfCtrlWordHandler(rtfParser, "ftnnzodiacd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnnzodiacl"] = new RtfCtrlWordHandler(rtfParser, "ftnnzodiacl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnrestart"] = new RtfCtrlWordHandler(rtfParser, "ftnrestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnrstcont"] = new RtfCtrlWordHandler(rtfParser, "ftnrstcont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnrstpg"] = new RtfCtrlWordHandler(rtfParser, "ftnrstpg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ftnsep"] = new RtfCtrlWordHandler(rtfParser, "ftnsep", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["ftnsepc"] = new RtfCtrlWordHandler(rtfParser, "ftnsepc", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["ftnstart"] = new RtfCtrlWordHandler(rtfParser, "ftnstart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ftntj"] = new RtfCtrlWordHandler(rtfParser, "ftntj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fttruetype"] = new RtfCtrlWordHandler(rtfParser, "fttruetype", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fvaliddos"] = new RtfCtrlWordHandler(rtfParser, "fvaliddos", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fvalidhpfs"] = new RtfCtrlWordHandler(rtfParser, "fvalidhpfs", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fvalidmac"] = new RtfCtrlWordHandler(rtfParser, "fvalidmac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["fvalidntfs"] = new RtfCtrlWordHandler(rtfParser, "fvalidntfs", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["g"] = new RtfCtrlWordHandler(rtfParser, "g", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["gcw"] = new RtfCtrlWordHandler(rtfParser, "gcw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["generator"] = new RtfCtrlWordHandler(rtfParser, "generator", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["green"] = new RtfCtrlWordHandler(rtfParser, "green", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["gridtbl"] = new RtfCtrlWordHandler(rtfParser, "gridtbl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["gutter"] = new RtfCtrlWordHandler(rtfParser, "gutter", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["gutterprl"] = new RtfCtrlWordHandler(rtfParser, "gutterprl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["guttersxn"] = new RtfCtrlWordHandler(rtfParser, "guttersxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["header"] = new RtfCtrlWordHandler(rtfParser, "header", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["headerf"] = new RtfCtrlWordHandler(rtfParser, "headerf", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["headerl"] = new RtfCtrlWordHandler(rtfParser, "headerl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["headerr"] = new RtfCtrlWordHandler(rtfParser, "headerr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["headery"] = new RtfCtrlWordHandler(rtfParser, "headery", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hich"] = new RtfCtrlWordHandler(rtfParser, "hich", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["highlight"] = new RtfCtrlWordHandler(rtfParser, "highlight", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hlfr"] = new RtfCtrlWordHandler(rtfParser, "hlfr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hlinkbase"] = new RtfCtrlWordHandler(rtfParser, "hlinkbase", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hlloc"] = new RtfCtrlWordHandler(rtfParser, "hlloc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hlsrc"] = new RtfCtrlWordHandler(rtfParser, "hlsrc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["horzdoc"] = new RtfCtrlWordHandler(rtfParser, "horzdoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["horzsect"] = new RtfCtrlWordHandler(rtfParser, "horzsect", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["horzvert"] = new RtfCtrlWordHandler(rtfParser, "horzvert", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hr"] = new RtfCtrlWordHandler(rtfParser, "hr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hsv"] = new RtfCtrlWordHandler(rtfParser, "hsv", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["htmautsp"] = new RtfCtrlWordHandler(rtfParser, "htmautsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["htmlbase"] = new RtfCtrlWordHandler(rtfParser, "htmlbase", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["htmlrtf"] = new RtfCtrlWordHandler(rtfParser, "htmlrtf", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["htmltag"] = new RtfCtrlWordHandler(rtfParser, "htmltag", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["hwelev"] = new RtfCtrlWordHandler(rtfParser, "hwelev", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["hyphauto"] = new RtfCtrlWordHandler(rtfParser, "hyphauto", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["hyphcaps"] = new RtfCtrlWordHandler(rtfParser, "hyphcaps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["hyphconsec"] = new RtfCtrlWordHandler(rtfParser, "hyphconsec", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hyphhotz"] = new RtfCtrlWordHandler(rtfParser, "hyphhotz", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["hyphpar"] = new RtfCtrlWordHandler(rtfParser, "hyphpar", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["i"] = new RtfCtrlWordHandler(rtfParser, "i", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["id"] = new RtfCtrlWordHandler(rtfParser, "id", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ignoremixedcontent"] = new RtfCtrlWordHandler(rtfParser, "ignoremixedcontent", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ilfomacatclnup"] = new RtfCtrlWordHandler(rtfParser, "ilfomacatclnup", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ilvl"] = new RtfCtrlWordHandler(rtfParser, "ilvl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["impr"] = new RtfCtrlWordHandler(rtfParser, "impr", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["indmirror"] = new RtfCtrlWordHandler(rtfParser, "indmirror", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["indrlsweleven"] = new RtfCtrlWordHandler(rtfParser, "indrlsweleven", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["info"] = new RtfCtrlWordHandler(rtfParser, "info", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["insrsid"] = new RtfCtrlWordHandler(rtfParser, "insrsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["intbl"] = new RtfCtrlWordHandler(rtfParser, "intbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ipgp"] = new RtfCtrlWordHandler(rtfParser, "ipgp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["irow"] = new RtfCtrlWordHandler(rtfParser, "irow", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["irowband"] = new RtfCtrlWordHandler(rtfParser, "irowband", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["itap"] = new RtfCtrlWordHandler(rtfParser, "itap", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ixe"] = new RtfCtrlWordHandler(rtfParser, "ixe", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["jclisttab"] = new RtfCtrlWordHandler(rtfParser, "jclisttab", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["jcompress"] = new RtfCtrlWordHandler(rtfParser, "jcompress", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["jexpand"] = new RtfCtrlWordHandler(rtfParser, "jexpand", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["jis"] = new RtfCtrlWordHandler(rtfParser, "jis", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["jpegblip"] = new RtfCtrlWordHandler(rtfParser, "jpegblip", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["jsksu"] = new RtfCtrlWordHandler(rtfParser, "jsksu", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["keep"] = new RtfCtrlWordHandler(rtfParser, "keep", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["keepn"] = new RtfCtrlWordHandler(rtfParser, "keepn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["kerning"] = new RtfCtrlWordHandler(rtfParser, "kerning", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["keycode"] = new RtfCtrlWordHandler(rtfParser, "keycode", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["keywords"] = new RtfCtrlWordHandler(rtfParser, "keywords", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["krnprsnet"] = new RtfCtrlWordHandler(rtfParser, "krnprsnet", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ksulang"] = new RtfCtrlWordHandler(rtfParser, "ksulang", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["landscape"] = new RtfCtrlWordHandler(rtfParser, "landscape", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lang"] = new RtfCtrlWordHandler(rtfParser, "lang", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["langfe"] = new RtfCtrlWordHandler(rtfParser, "langfe", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["langfenp"] = new RtfCtrlWordHandler(rtfParser, "langfenp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["langnp"] = new RtfCtrlWordHandler(rtfParser, "langnp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lastrow"] = new RtfCtrlWordHandler(rtfParser, "lastrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["latentstyles"] = new RtfCtrlWordHandler(rtfParser, "latentstyles", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["lbr"] = new RtfCtrlWordHandler(rtfParser, "lbr", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["lchars"] = new RtfCtrlWordHandler(rtfParser, "lchars", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["ldblquote"] = new RtfCtrlWordHandler(rtfParser, "ldblquote", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x147"); + ctrlWords["level"] = new RtfCtrlWordHandler(rtfParser, "level", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelfollow"] = new RtfCtrlWordHandler(rtfParser, "levelfollow", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelindent"] = new RtfCtrlWordHandler(rtfParser, "levelindent", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["leveljc"] = new RtfCtrlWordHandler(rtfParser, "leveljc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["leveljcn"] = new RtfCtrlWordHandler(rtfParser, "leveljcn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levellegal"] = new RtfCtrlWordHandler(rtfParser, "levellegal", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelnfc"] = new RtfCtrlWordHandler(rtfParser, "levelnfc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelnfcn"] = new RtfCtrlWordHandler(rtfParser, "levelnfcn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelnorestart"] = new RtfCtrlWordHandler(rtfParser, "levelnorestart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelnumbers"] = new RtfCtrlWordHandler(rtfParser, "levelnumbers", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["levelold"] = new RtfCtrlWordHandler(rtfParser, "levelold", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelpicture"] = new RtfCtrlWordHandler(rtfParser, "levelpicture", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelprev"] = new RtfCtrlWordHandler(rtfParser, "levelprev", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelprevspace"] = new RtfCtrlWordHandler(rtfParser, "levelprevspace", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelspace"] = new RtfCtrlWordHandler(rtfParser, "levelspace", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["levelstartat"] = new RtfCtrlWordHandler(rtfParser, "levelstartat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["leveltemplateid"] = new RtfCtrlWordHandler(rtfParser, "leveltemplateid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["leveltext"] = new RtfCtrlWordHandler(rtfParser, "leveltext", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["li"] = new RtfCtrlWordHandler(rtfParser, "li", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lin"] = new RtfCtrlWordHandler(rtfParser, "lin", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["line"] = new RtfCtrlWordHandler(rtfParser, "line", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["linebetcol"] = new RtfCtrlWordHandler(rtfParser, "linebetcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["linecont"] = new RtfCtrlWordHandler(rtfParser, "linecont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["linemod"] = new RtfCtrlWordHandler(rtfParser, "linemod", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lineppage"] = new RtfCtrlWordHandler(rtfParser, "lineppage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["linerestart"] = new RtfCtrlWordHandler(rtfParser, "linerestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["linestart"] = new RtfCtrlWordHandler(rtfParser, "linestart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["linestarts"] = new RtfCtrlWordHandler(rtfParser, "linestarts", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["linex"] = new RtfCtrlWordHandler(rtfParser, "linex", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["linkself"] = new RtfCtrlWordHandler(rtfParser, "linkself", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["linkstyles"] = new RtfCtrlWordHandler(rtfParser, "linkstyles", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["linktoquery"] = new RtfCtrlWordHandler(rtfParser, "linktoquery", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["linkval"] = new RtfCtrlWordHandler(rtfParser, "linkval", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lisa"] = new RtfCtrlWordHandler(rtfParser, "lisa", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lisb"] = new RtfCtrlWordHandler(rtfParser, "lisb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["list"] = new RtfCtrlWordHandler(rtfParser, "list", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listhybrid"] = new RtfCtrlWordHandler(rtfParser, "listhybrid", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["listid"] = new RtfCtrlWordHandler(rtfParser, "listid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listname"] = new RtfCtrlWordHandler(rtfParser, "listname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["listoverride"] = new RtfCtrlWordHandler(rtfParser, "listoverride", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["listoverridecount"] = new RtfCtrlWordHandler(rtfParser, "listoverridecount", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listoverrideformat"] = new RtfCtrlWordHandler(rtfParser, "listoverrideformat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listoverridestart"] = new RtfCtrlWordHandler(rtfParser, "listoverridestart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listoverridestartat"] = new RtfCtrlWordHandler(rtfParser, "listoverridestartat", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["listoverridetable"] = new RtfCtrlWordHandler(rtfParser, "listoverridetable", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationNull"); + ctrlWords["listpicture"] = new RtfCtrlWordHandler(rtfParser, "listpicture", 0, true, RtfCtrlWordType.DESTINATION, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["listrestarthdn"] = new RtfCtrlWordHandler(rtfParser, "listrestarthdn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listsimple"] = new RtfCtrlWordHandler(rtfParser, "listsimple", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["liststyleid"] = new RtfCtrlWordHandler(rtfParser, "liststyleid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["liststylename"] = new RtfCtrlWordHandler(rtfParser, "liststylename", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listtable"] = new RtfCtrlWordHandler(rtfParser, "listtable", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationListTable"); + ctrlWords["listtemplateid"] = new RtfCtrlWordHandler(rtfParser, "listtemplateid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["listtext"] = new RtfCtrlWordHandler(rtfParser, "listtext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["lnbrkrule"] = new RtfCtrlWordHandler(rtfParser, "lnbrkrule", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lndscpsxn"] = new RtfCtrlWordHandler(rtfParser, "lndscpsxn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lnongrid"] = new RtfCtrlWordHandler(rtfParser, "lnongrid", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["loch"] = new RtfCtrlWordHandler(rtfParser, "loch", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lquote"] = new RtfCtrlWordHandler(rtfParser, "lquote", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x145"); + ctrlWords["ls"] = new RtfCtrlWordHandler(rtfParser, "ls", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdlocked"] = new RtfCtrlWordHandler(rtfParser, "lsdlocked", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdlockeddef"] = new RtfCtrlWordHandler(rtfParser, "lsdlockeddef", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdlockedexcept"] = new RtfCtrlWordHandler(rtfParser, "lsdlockedexcept", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["lsdpriority"] = new RtfCtrlWordHandler(rtfParser, "lsdpriority", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdprioritydef"] = new RtfCtrlWordHandler(rtfParser, "lsdprioritydef", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdqformat"] = new RtfCtrlWordHandler(rtfParser, "lsdqformat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdqformatdef"] = new RtfCtrlWordHandler(rtfParser, "lsdqformatdef", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdsemihidden"] = new RtfCtrlWordHandler(rtfParser, "lsdsemihidden", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdsemihiddendef"] = new RtfCtrlWordHandler(rtfParser, "lsdsemihiddendef", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdstimax"] = new RtfCtrlWordHandler(rtfParser, "lsdstimax", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdunhideused"] = new RtfCtrlWordHandler(rtfParser, "lsdunhideused", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["lsdunhideuseddef"] = new RtfCtrlWordHandler(rtfParser, "lsdunhideuseddef", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ltrch"] = new RtfCtrlWordHandler(rtfParser, "ltrch", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ltrdoc"] = new RtfCtrlWordHandler(rtfParser, "ltrdoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ltrmark"] = new RtfCtrlWordHandler(rtfParser, "ltrmark", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["ltrpar"] = new RtfCtrlWordHandler(rtfParser, "ltrpar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ltrrow"] = new RtfCtrlWordHandler(rtfParser, "ltrrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ltrsect"] = new RtfCtrlWordHandler(rtfParser, "ltrsect", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lvltentative"] = new RtfCtrlWordHandler(rtfParser, "lvltentative", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lytcalctblwd"] = new RtfCtrlWordHandler(rtfParser, "lytcalctblwd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lytexcttp"] = new RtfCtrlWordHandler(rtfParser, "lytexcttp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lytprtmet"] = new RtfCtrlWordHandler(rtfParser, "lytprtmet", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["lyttblrtgr"] = new RtfCtrlWordHandler(rtfParser, "lyttblrtgr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mac"] = new RtfCtrlWordHandler(rtfParser, "mac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["macc"] = new RtfCtrlWordHandler(rtfParser, "macc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["maccpr"] = new RtfCtrlWordHandler(rtfParser, "maccpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["macpict"] = new RtfCtrlWordHandler(rtfParser, "macpict", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mailmerge"] = new RtfCtrlWordHandler(rtfParser, "mailmerge", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["makebackup"] = new RtfCtrlWordHandler(rtfParser, "makebackup", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["maln"] = new RtfCtrlWordHandler(rtfParser, "maln", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["malnscr"] = new RtfCtrlWordHandler(rtfParser, "malnscr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["manager"] = new RtfCtrlWordHandler(rtfParser, "manager", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["margb"] = new RtfCtrlWordHandler(rtfParser, "margb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margbsxn"] = new RtfCtrlWordHandler(rtfParser, "margbsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margl"] = new RtfCtrlWordHandler(rtfParser, "margl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["marglsxn"] = new RtfCtrlWordHandler(rtfParser, "marglsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margmirror"] = new RtfCtrlWordHandler(rtfParser, "margmirror", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["margmirsxn"] = new RtfCtrlWordHandler(rtfParser, "margmirsxn", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margpr"] = new RtfCtrlWordHandler(rtfParser, "margpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["margr"] = new RtfCtrlWordHandler(rtfParser, "margr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margrsxn"] = new RtfCtrlWordHandler(rtfParser, "margrsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margsz"] = new RtfCtrlWordHandler(rtfParser, "margsz", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margt"] = new RtfCtrlWordHandler(rtfParser, "margt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["margtsxn"] = new RtfCtrlWordHandler(rtfParser, "margtsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mbar"] = new RtfCtrlWordHandler(rtfParser, "mbar", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mbarpr"] = new RtfCtrlWordHandler(rtfParser, "mbarpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mbasejc"] = new RtfCtrlWordHandler(rtfParser, "mbasejc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mbegchr"] = new RtfCtrlWordHandler(rtfParser, "mbegchr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mborderbox"] = new RtfCtrlWordHandler(rtfParser, "mborderbox", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mborderboxpr"] = new RtfCtrlWordHandler(rtfParser, "mborderboxpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mbox"] = new RtfCtrlWordHandler(rtfParser, "mbox", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mboxpr"] = new RtfCtrlWordHandler(rtfParser, "mboxpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mbrk"] = new RtfCtrlWordHandler(rtfParser, "mbrk", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mbrkbin"] = new RtfCtrlWordHandler(rtfParser, "mbrkbin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mbrkbinsub"] = new RtfCtrlWordHandler(rtfParser, "mbrkbinsub", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mcgp"] = new RtfCtrlWordHandler(rtfParser, "mcgp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mcgprule"] = new RtfCtrlWordHandler(rtfParser, "mcgprule", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mchr"] = new RtfCtrlWordHandler(rtfParser, "mchr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mcount"] = new RtfCtrlWordHandler(rtfParser, "mcount", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mcsp"] = new RtfCtrlWordHandler(rtfParser, "mcsp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mctrlpr"] = new RtfCtrlWordHandler(rtfParser, "mctrlpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["md"] = new RtfCtrlWordHandler(rtfParser, "md", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mdefjc"] = new RtfCtrlWordHandler(rtfParser, "mdefjc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mdeg"] = new RtfCtrlWordHandler(rtfParser, "mdeg", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mdeghide"] = new RtfCtrlWordHandler(rtfParser, "mdeghide", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mden"] = new RtfCtrlWordHandler(rtfParser, "mden", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mdiff"] = new RtfCtrlWordHandler(rtfParser, "mdiff", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mdispdef"] = new RtfCtrlWordHandler(rtfParser, "mdispdef", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mdpr"] = new RtfCtrlWordHandler(rtfParser, "mdpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["me"] = new RtfCtrlWordHandler(rtfParser, "me", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mendchr"] = new RtfCtrlWordHandler(rtfParser, "mendchr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["meqarr"] = new RtfCtrlWordHandler(rtfParser, "meqarr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["meqarrpr"] = new RtfCtrlWordHandler(rtfParser, "meqarrpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mf"] = new RtfCtrlWordHandler(rtfParser, "mf", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mfname"] = new RtfCtrlWordHandler(rtfParser, "mfname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mfpr"] = new RtfCtrlWordHandler(rtfParser, "mfpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mfunc"] = new RtfCtrlWordHandler(rtfParser, "mfunc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mfuncpr"] = new RtfCtrlWordHandler(rtfParser, "mfuncpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mgroupchr"] = new RtfCtrlWordHandler(rtfParser, "mgroupchr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mgroupchrpr"] = new RtfCtrlWordHandler(rtfParser, "mgroupchrpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mgrow"] = new RtfCtrlWordHandler(rtfParser, "mgrow", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mhidebot"] = new RtfCtrlWordHandler(rtfParser, "mhidebot", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mhideleft"] = new RtfCtrlWordHandler(rtfParser, "mhideleft", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mhideright"] = new RtfCtrlWordHandler(rtfParser, "mhideright", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mhidetop"] = new RtfCtrlWordHandler(rtfParser, "mhidetop", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mhtmltag"] = new RtfCtrlWordHandler(rtfParser, "mhtmltag", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["min"] = new RtfCtrlWordHandler(rtfParser, "min", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mintersp"] = new RtfCtrlWordHandler(rtfParser, "mintersp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mintlim"] = new RtfCtrlWordHandler(rtfParser, "mintlim", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mintrasp"] = new RtfCtrlWordHandler(rtfParser, "mintrasp", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mjc"] = new RtfCtrlWordHandler(rtfParser, "mjc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlim"] = new RtfCtrlWordHandler(rtfParser, "mlim", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlimloc"] = new RtfCtrlWordHandler(rtfParser, "mlimloc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlimlow"] = new RtfCtrlWordHandler(rtfParser, "mlimlow", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlimlowpr"] = new RtfCtrlWordHandler(rtfParser, "mlimlowpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlimupp"] = new RtfCtrlWordHandler(rtfParser, "mlimupp", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlimupppr"] = new RtfCtrlWordHandler(rtfParser, "mlimupppr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mlit"] = new RtfCtrlWordHandler(rtfParser, "mlit", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mlmargin"] = new RtfCtrlWordHandler(rtfParser, "mlmargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mm"] = new RtfCtrlWordHandler(rtfParser, "mm", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmaddfieldname"] = new RtfCtrlWordHandler(rtfParser, "mmaddfieldname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmath"] = new RtfCtrlWordHandler(rtfParser, "mmath", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmathfont"] = new RtfCtrlWordHandler(rtfParser, "mmathfont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmathpara"] = new RtfCtrlWordHandler(rtfParser, "mmathpara", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmathpict"] = new RtfCtrlWordHandler(rtfParser, "mmathpict", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmathpr"] = new RtfCtrlWordHandler(rtfParser, "mmathpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmattach"] = new RtfCtrlWordHandler(rtfParser, "mmattach", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmaxdist"] = new RtfCtrlWordHandler(rtfParser, "mmaxdist", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmblanklines"] = new RtfCtrlWordHandler(rtfParser, "mmblanklines", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmblanklinks"] = new RtfCtrlWordHandler(rtfParser, "mmblanklinks", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmc"] = new RtfCtrlWordHandler(rtfParser, "mmc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmcjc"] = new RtfCtrlWordHandler(rtfParser, "mmcjc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmconnectstrdata"] = new RtfCtrlWordHandler(rtfParser, "mmconnectstrdata", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", null); + ctrlWords["mmcpr"] = new RtfCtrlWordHandler(rtfParser, "mmcpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmcs"] = new RtfCtrlWordHandler(rtfParser, "mmcs", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmdatasource"] = new RtfCtrlWordHandler(rtfParser, "mmdatasource", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmdatatypeaccess"] = new RtfCtrlWordHandler(rtfParser, "mmdatatypeaccess", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdatatypeexcel"] = new RtfCtrlWordHandler(rtfParser, "mmdatatypeexcel", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdatatypefile"] = new RtfCtrlWordHandler(rtfParser, "mmdatatypefile", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdatatypeodbc"] = new RtfCtrlWordHandler(rtfParser, "mmdatatypeodbc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdatatypeodso"] = new RtfCtrlWordHandler(rtfParser, "mmdatatypeodso", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdatatypeqt"] = new RtfCtrlWordHandler(rtfParser, "mmdatatypeqt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdefaultStructuredQueryLanguage"] = new RtfCtrlWordHandler(rtfParser, "mmdefaultStructuredQueryLanguage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdestemail"] = new RtfCtrlWordHandler(rtfParser, "mmdestemail", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdestfax"] = new RtfCtrlWordHandler(rtfParser, "mmdestfax", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdestnewdoc"] = new RtfCtrlWordHandler(rtfParser, "mmdestnewdoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmdestprinter"] = new RtfCtrlWordHandler(rtfParser, "mmdestprinter", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmerrors"] = new RtfCtrlWordHandler(rtfParser, "mmerrors", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmfttypeaddress"] = new RtfCtrlWordHandler(rtfParser, "mmfttypeaddress", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmfttypebarcode"] = new RtfCtrlWordHandler(rtfParser, "mmfttypebarcode", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmfttypedbcolumn"] = new RtfCtrlWordHandler(rtfParser, "mmfttypedbcolumn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmfttypemapped"] = new RtfCtrlWordHandler(rtfParser, "mmfttypemapped", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmfttypenull"] = new RtfCtrlWordHandler(rtfParser, "mmfttypenull", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmfttypesalutation"] = new RtfCtrlWordHandler(rtfParser, "mmfttypesalutation", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmheadersource"] = new RtfCtrlWordHandler(rtfParser, "mmheadersource", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmjdsotype"] = new RtfCtrlWordHandler(rtfParser, "mmjdsotype", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmlinktoquery"] = new RtfCtrlWordHandler(rtfParser, "mmlinktoquery", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmmailsubject"] = new RtfCtrlWordHandler(rtfParser, "mmmailsubject", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmmaintypecatalog"] = new RtfCtrlWordHandler(rtfParser, "mmmaintypecatalog", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmmaintypeemail"] = new RtfCtrlWordHandler(rtfParser, "mmmaintypeemail", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmmaintypeenvelopes"] = new RtfCtrlWordHandler(rtfParser, "mmmaintypeenvelopes", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmmaintypefax"] = new RtfCtrlWordHandler(rtfParser, "mmmaintypefax", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmmaintypelabels"] = new RtfCtrlWordHandler(rtfParser, "mmmaintypelabels", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmmaintypeletters"] = new RtfCtrlWordHandler(rtfParser, "mmmaintypeletters", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mmodso"] = new RtfCtrlWordHandler(rtfParser, "mmodso", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsoactive"] = new RtfCtrlWordHandler(rtfParser, "mmodsoactive", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsocoldelim"] = new RtfCtrlWordHandler(rtfParser, "mmodsocoldelim", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsocolumn"] = new RtfCtrlWordHandler(rtfParser, "mmodsocolumn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsodynaddr"] = new RtfCtrlWordHandler(rtfParser, "mmodsodynaddr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsofhdr"] = new RtfCtrlWordHandler(rtfParser, "mmodsofhdr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsofilter"] = new RtfCtrlWordHandler(rtfParser, "mmodsofilter", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsofldmpdata"] = new RtfCtrlWordHandler(rtfParser, "mmodsofldmpdata", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsofmcolumn"] = new RtfCtrlWordHandler(rtfParser, "mmodsofmcolumn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsohash"] = new RtfCtrlWordHandler(rtfParser, "mmodsohash", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsolid"] = new RtfCtrlWordHandler(rtfParser, "mmodsolid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmodsomappedname"] = new RtfCtrlWordHandler(rtfParser, "mmodsomappedname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsoname"] = new RtfCtrlWordHandler(rtfParser, "mmodsoname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", null); + ctrlWords["mmodsorecipdata"] = new RtfCtrlWordHandler(rtfParser, "mmodsorecipdata", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsosort"] = new RtfCtrlWordHandler(rtfParser, "mmodsosort", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsosrc"] = new RtfCtrlWordHandler(rtfParser, "mmodsosrc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsotable"] = new RtfCtrlWordHandler(rtfParser, "mmodsotable", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsoudldata"] = new RtfCtrlWordHandler(rtfParser, "mmodsoudldata", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mmodsouniquetag"] = new RtfCtrlWordHandler(rtfParser, "mmodsouniquetag", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmpr"] = new RtfCtrlWordHandler(rtfParser, "mmpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmquery"] = new RtfCtrlWordHandler(rtfParser, "mmquery", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmr"] = new RtfCtrlWordHandler(rtfParser, "mmr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mmreccur"] = new RtfCtrlWordHandler(rtfParser, "mmreccur", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mmshowdata"] = new RtfCtrlWordHandler(rtfParser, "mmshowdata", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mnary"] = new RtfCtrlWordHandler(rtfParser, "mnary", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mnarylim"] = new RtfCtrlWordHandler(rtfParser, "mnarylim", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mnarypr"] = new RtfCtrlWordHandler(rtfParser, "mnarypr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mnobreak"] = new RtfCtrlWordHandler(rtfParser, "mnobreak", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mnor"] = new RtfCtrlWordHandler(rtfParser, "mnor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mnum"] = new RtfCtrlWordHandler(rtfParser, "mnum", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mo"] = new RtfCtrlWordHandler(rtfParser, "mo", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mobjdist"] = new RtfCtrlWordHandler(rtfParser, "mobjdist", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["momath"] = new RtfCtrlWordHandler(rtfParser, "momath", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["momathpara"] = new RtfCtrlWordHandler(rtfParser, "momathpara", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["momathparapr"] = new RtfCtrlWordHandler(rtfParser, "momathparapr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mopemu"] = new RtfCtrlWordHandler(rtfParser, "mopemu", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mphant"] = new RtfCtrlWordHandler(rtfParser, "mphant", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mphantpr"] = new RtfCtrlWordHandler(rtfParser, "mphantpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mplchide"] = new RtfCtrlWordHandler(rtfParser, "mplchide", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mpos"] = new RtfCtrlWordHandler(rtfParser, "mpos", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mpostsp"] = new RtfCtrlWordHandler(rtfParser, "mpostsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mpresp"] = new RtfCtrlWordHandler(rtfParser, "mpresp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mr"] = new RtfCtrlWordHandler(rtfParser, "mr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mrad"] = new RtfCtrlWordHandler(rtfParser, "mrad", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mradpr"] = new RtfCtrlWordHandler(rtfParser, "mradpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mrmargin"] = new RtfCtrlWordHandler(rtfParser, "mrmargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mrpr"] = new RtfCtrlWordHandler(rtfParser, "mrpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mrsp"] = new RtfCtrlWordHandler(rtfParser, "mrsp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mrsprule"] = new RtfCtrlWordHandler(rtfParser, "mrsprule", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mscr"] = new RtfCtrlWordHandler(rtfParser, "mscr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["msepchr"] = new RtfCtrlWordHandler(rtfParser, "msepchr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mshow"] = new RtfCtrlWordHandler(rtfParser, "mshow", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mshp"] = new RtfCtrlWordHandler(rtfParser, "mshp", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msize"] = new RtfCtrlWordHandler(rtfParser, "msize", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msmallfrac"] = new RtfCtrlWordHandler(rtfParser, "msmallfrac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["msmcap"] = new RtfCtrlWordHandler(rtfParser, "msmcap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mspre"] = new RtfCtrlWordHandler(rtfParser, "mspre", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msprepr"] = new RtfCtrlWordHandler(rtfParser, "msprepr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mssub"] = new RtfCtrlWordHandler(rtfParser, "mssub", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mssubpr"] = new RtfCtrlWordHandler(rtfParser, "mssubpr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mssubsup"] = new RtfCtrlWordHandler(rtfParser, "mssubsup", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mssubsuppr"] = new RtfCtrlWordHandler(rtfParser, "mssubsuppr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mssup"] = new RtfCtrlWordHandler(rtfParser, "mssup", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mssuppr"] = new RtfCtrlWordHandler(rtfParser, "mssuppr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mstrikebltr"] = new RtfCtrlWordHandler(rtfParser, "mstrikebltr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mstrikeh"] = new RtfCtrlWordHandler(rtfParser, "mstrikeh", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mstriketlbr"] = new RtfCtrlWordHandler(rtfParser, "mstriketlbr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mstrikev"] = new RtfCtrlWordHandler(rtfParser, "mstrikev", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msty"] = new RtfCtrlWordHandler(rtfParser, "msty", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["msub"] = new RtfCtrlWordHandler(rtfParser, "msub", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msubhide"] = new RtfCtrlWordHandler(rtfParser, "msubhide", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msup"] = new RtfCtrlWordHandler(rtfParser, "msup", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["msuphide"] = new RtfCtrlWordHandler(rtfParser, "msuphide", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mt"] = new RtfCtrlWordHandler(rtfParser, "mt", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mtext"] = new RtfCtrlWordHandler(rtfParser, "mtext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mtransp"] = new RtfCtrlWordHandler(rtfParser, "mtransp", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mtype"] = new RtfCtrlWordHandler(rtfParser, "mtype", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mvauth"] = new RtfCtrlWordHandler(rtfParser, "mvauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mvdate"] = new RtfCtrlWordHandler(rtfParser, "mvdate", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mvertjc"] = new RtfCtrlWordHandler(rtfParser, "mvertjc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mvf"] = new RtfCtrlWordHandler(rtfParser, "mvf", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mvfmf"] = new RtfCtrlWordHandler(rtfParser, "mvfmf", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mvfml"] = new RtfCtrlWordHandler(rtfParser, "mvfml", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mvt"] = new RtfCtrlWordHandler(rtfParser, "mvt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mvtof"] = new RtfCtrlWordHandler(rtfParser, "mvtof", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mvtol"] = new RtfCtrlWordHandler(rtfParser, "mvtol", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["mwrapindent"] = new RtfCtrlWordHandler(rtfParser, "mwrapindent", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mwrapindet"] = new RtfCtrlWordHandler(rtfParser, "mwrapindet", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["mwrapright"] = new RtfCtrlWordHandler(rtfParser, "mwrapright", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["mzeroasc"] = new RtfCtrlWordHandler(rtfParser, "mzeroasc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mzerodesc"] = new RtfCtrlWordHandler(rtfParser, "mzerodesc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["mzerowid"] = new RtfCtrlWordHandler(rtfParser, "mzerowid", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["nestcell"] = new RtfCtrlWordHandler(rtfParser, "nestcell", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["nestrow"] = new RtfCtrlWordHandler(rtfParser, "nestrow", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["nesttableprops"] = new RtfCtrlWordHandler(rtfParser, "nesttableprops", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["newtblstyruls"] = new RtfCtrlWordHandler(rtfParser, "newtblstyruls", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nextfile"] = new RtfCtrlWordHandler(rtfParser, "nextfile", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["noafcnsttbl"] = new RtfCtrlWordHandler(rtfParser, "noafcnsttbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nobrkwrptbl"] = new RtfCtrlWordHandler(rtfParser, "nobrkwrptbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nocolbal"] = new RtfCtrlWordHandler(rtfParser, "nocolbal", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nocompatoptions"] = new RtfCtrlWordHandler(rtfParser, "nocompatoptions", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nocwrap"] = new RtfCtrlWordHandler(rtfParser, "nocwrap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nocxsptable"] = new RtfCtrlWordHandler(rtfParser, "nocxsptable", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noextrasprl"] = new RtfCtrlWordHandler(rtfParser, "noextrasprl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nofchars"] = new RtfCtrlWordHandler(rtfParser, "nofchars", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["nofcharsws"] = new RtfCtrlWordHandler(rtfParser, "nofcharsws", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["nofeaturethrottle"] = new RtfCtrlWordHandler(rtfParser, "nofeaturethrottle", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nofpages"] = new RtfCtrlWordHandler(rtfParser, "nofpages", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["nofwords"] = new RtfCtrlWordHandler(rtfParser, "nofwords", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["nogrowautofit"] = new RtfCtrlWordHandler(rtfParser, "nogrowautofit", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noindnmbrts"] = new RtfCtrlWordHandler(rtfParser, "noindnmbrts", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nojkernpunct"] = new RtfCtrlWordHandler(rtfParser, "nojkernpunct", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nolead"] = new RtfCtrlWordHandler(rtfParser, "nolead", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noline"] = new RtfCtrlWordHandler(rtfParser, "noline", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nolnhtadjtbl"] = new RtfCtrlWordHandler(rtfParser, "nolnhtadjtbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nonesttables"] = new RtfCtrlWordHandler(rtfParser, "nonesttables", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["nonshppict"] = new RtfCtrlWordHandler(rtfParser, "nonshppict", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["nooverflow"] = new RtfCtrlWordHandler(rtfParser, "nooverflow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noproof"] = new RtfCtrlWordHandler(rtfParser, "noproof", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noqfpromote"] = new RtfCtrlWordHandler(rtfParser, "noqfpromote", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nosectexpand"] = new RtfCtrlWordHandler(rtfParser, "nosectexpand", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nosnaplinegrid"] = new RtfCtrlWordHandler(rtfParser, "nosnaplinegrid", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nospaceforul"] = new RtfCtrlWordHandler(rtfParser, "nospaceforul", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nosupersub"] = new RtfCtrlWordHandler(rtfParser, "nosupersub", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["notabind"] = new RtfCtrlWordHandler(rtfParser, "notabind", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["notbrkcnstfrctbl"] = new RtfCtrlWordHandler(rtfParser, "notbrkcnstfrctbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["notcvasp"] = new RtfCtrlWordHandler(rtfParser, "notcvasp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["notvatxbx"] = new RtfCtrlWordHandler(rtfParser, "notvatxbx", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nouicompat"] = new RtfCtrlWordHandler(rtfParser, "nouicompat", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noultrlspc"] = new RtfCtrlWordHandler(rtfParser, "noultrlspc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nowidctlpar"] = new RtfCtrlWordHandler(rtfParser, "nowidctlpar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nowrap"] = new RtfCtrlWordHandler(rtfParser, "nowrap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["nowwrap"] = new RtfCtrlWordHandler(rtfParser, "nowwrap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["noxlattoyen"] = new RtfCtrlWordHandler(rtfParser, "noxlattoyen", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objalias"] = new RtfCtrlWordHandler(rtfParser, "objalias", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["objalign"] = new RtfCtrlWordHandler(rtfParser, "objalign", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objattph"] = new RtfCtrlWordHandler(rtfParser, "objattph", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objautlink"] = new RtfCtrlWordHandler(rtfParser, "objautlink", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objclass"] = new RtfCtrlWordHandler(rtfParser, "objclass", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["objcropb"] = new RtfCtrlWordHandler(rtfParser, "objcropb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objcropl"] = new RtfCtrlWordHandler(rtfParser, "objcropl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objcropr"] = new RtfCtrlWordHandler(rtfParser, "objcropr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objcropt"] = new RtfCtrlWordHandler(rtfParser, "objcropt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objdata"] = new RtfCtrlWordHandler(rtfParser, "objdata", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["object"] = new RtfCtrlWordHandler(rtfParser, "object", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["objemb"] = new RtfCtrlWordHandler(rtfParser, "objemb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objh"] = new RtfCtrlWordHandler(rtfParser, "objh", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objhtml"] = new RtfCtrlWordHandler(rtfParser, "objhtml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objicemb"] = new RtfCtrlWordHandler(rtfParser, "objicemb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objlink"] = new RtfCtrlWordHandler(rtfParser, "objlink", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objlock"] = new RtfCtrlWordHandler(rtfParser, "objlock", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objname"] = new RtfCtrlWordHandler(rtfParser, "objname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["objocx"] = new RtfCtrlWordHandler(rtfParser, "objocx", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objpub"] = new RtfCtrlWordHandler(rtfParser, "objpub", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objscalex"] = new RtfCtrlWordHandler(rtfParser, "objscalex", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objscaley"] = new RtfCtrlWordHandler(rtfParser, "objscaley", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objsect"] = new RtfCtrlWordHandler(rtfParser, "objsect", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["objsetsize"] = new RtfCtrlWordHandler(rtfParser, "objsetsize", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objsub"] = new RtfCtrlWordHandler(rtfParser, "objsub", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objtime"] = new RtfCtrlWordHandler(rtfParser, "objtime", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["objtransy"] = new RtfCtrlWordHandler(rtfParser, "objtransy", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["objupdate"] = new RtfCtrlWordHandler(rtfParser, "objupdate", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["objw"] = new RtfCtrlWordHandler(rtfParser, "objw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["oldas"] = new RtfCtrlWordHandler(rtfParser, "oldas", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["oldcprops"] = new RtfCtrlWordHandler(rtfParser, "oldcprops", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["oldlinewrap"] = new RtfCtrlWordHandler(rtfParser, "oldlinewrap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["oldpprops"] = new RtfCtrlWordHandler(rtfParser, "oldpprops", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["oldsprops"] = new RtfCtrlWordHandler(rtfParser, "oldsprops", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["oldtprops"] = new RtfCtrlWordHandler(rtfParser, "oldtprops", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["oleclsid"] = new RtfCtrlWordHandler(rtfParser, "oleclsid", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["operator"] = new RtfCtrlWordHandler(rtfParser, "operator", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["otblrul"] = new RtfCtrlWordHandler(rtfParser, "otblrul", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["outl"] = new RtfCtrlWordHandler(rtfParser, "outl", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["outlinelevel"] = new RtfCtrlWordHandler(rtfParser, "outlinelevel", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["overlay"] = new RtfCtrlWordHandler(rtfParser, "overlay", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["page"] = new RtfCtrlWordHandler(rtfParser, "page", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["pagebb"] = new RtfCtrlWordHandler(rtfParser, "pagebb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["panose"] = new RtfCtrlWordHandler(rtfParser, "panose", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationNull"); + ctrlWords["paperh"] = new RtfCtrlWordHandler(rtfParser, "paperh", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["paperw"] = new RtfCtrlWordHandler(rtfParser, "paperw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["par"] = new RtfCtrlWordHandler(rtfParser, "par", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\n"); + ctrlWords["pararsid"] = new RtfCtrlWordHandler(rtfParser, "pararsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pard"] = new RtfCtrlWordHandler(rtfParser, "pard", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["passwordhash"] = new RtfCtrlWordHandler(rtfParser, "passwordhash", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["pc"] = new RtfCtrlWordHandler(rtfParser, "pc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pca"] = new RtfCtrlWordHandler(rtfParser, "pca", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdrb"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdrfoot"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrfoot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdrhead"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrhead", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdrl"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdropt"] = new RtfCtrlWordHandler(rtfParser, "pgbrdropt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgbrdrr"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdrsnap"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrsnap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgbrdrt"] = new RtfCtrlWordHandler(rtfParser, "pgbrdrt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pghsxn"] = new RtfCtrlWordHandler(rtfParser, "pghsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgnbidia"] = new RtfCtrlWordHandler(rtfParser, "pgnbidia", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnbidib"] = new RtfCtrlWordHandler(rtfParser, "pgnbidib", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnchosung"] = new RtfCtrlWordHandler(rtfParser, "pgnchosung", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgncnum"] = new RtfCtrlWordHandler(rtfParser, "pgncnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgncont"] = new RtfCtrlWordHandler(rtfParser, "pgncont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgndbnum"] = new RtfCtrlWordHandler(rtfParser, "pgndbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgndbnumd"] = new RtfCtrlWordHandler(rtfParser, "pgndbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgndbnumk"] = new RtfCtrlWordHandler(rtfParser, "pgndbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgndbnumt"] = new RtfCtrlWordHandler(rtfParser, "pgndbnumt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgndec"] = new RtfCtrlWordHandler(rtfParser, "pgndec", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgndecd"] = new RtfCtrlWordHandler(rtfParser, "pgndecd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnganada"] = new RtfCtrlWordHandler(rtfParser, "pgnganada", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgngbnum"] = new RtfCtrlWordHandler(rtfParser, "pgngbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgngbnumd"] = new RtfCtrlWordHandler(rtfParser, "pgngbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgngbnumk"] = new RtfCtrlWordHandler(rtfParser, "pgngbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgngbnuml"] = new RtfCtrlWordHandler(rtfParser, "pgngbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhindia"] = new RtfCtrlWordHandler(rtfParser, "pgnhindia", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhindib"] = new RtfCtrlWordHandler(rtfParser, "pgnhindib", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhindic"] = new RtfCtrlWordHandler(rtfParser, "pgnhindic", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhindid"] = new RtfCtrlWordHandler(rtfParser, "pgnhindid", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhn"] = new RtfCtrlWordHandler(rtfParser, "pgnhn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgnhnsc"] = new RtfCtrlWordHandler(rtfParser, "pgnhnsc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhnsh"] = new RtfCtrlWordHandler(rtfParser, "pgnhnsh", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhnsm"] = new RtfCtrlWordHandler(rtfParser, "pgnhnsm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhnsn"] = new RtfCtrlWordHandler(rtfParser, "pgnhnsn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnhnsp"] = new RtfCtrlWordHandler(rtfParser, "pgnhnsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnid"] = new RtfCtrlWordHandler(rtfParser, "pgnid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgnlcltr"] = new RtfCtrlWordHandler(rtfParser, "pgnlcltr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnlcrm"] = new RtfCtrlWordHandler(rtfParser, "pgnlcrm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnrestart"] = new RtfCtrlWordHandler(rtfParser, "pgnrestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnstart"] = new RtfCtrlWordHandler(rtfParser, "pgnstart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgnstarts"] = new RtfCtrlWordHandler(rtfParser, "pgnstarts", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgnthaia"] = new RtfCtrlWordHandler(rtfParser, "pgnthaia", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnthaib"] = new RtfCtrlWordHandler(rtfParser, "pgnthaib", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnthaic"] = new RtfCtrlWordHandler(rtfParser, "pgnthaic", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnucltr"] = new RtfCtrlWordHandler(rtfParser, "pgnucltr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnucrm"] = new RtfCtrlWordHandler(rtfParser, "pgnucrm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnvieta"] = new RtfCtrlWordHandler(rtfParser, "pgnvieta", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnx"] = new RtfCtrlWordHandler(rtfParser, "pgnx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgny"] = new RtfCtrlWordHandler(rtfParser, "pgny", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pgnzodiac"] = new RtfCtrlWordHandler(rtfParser, "pgnzodiac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnzodiacd"] = new RtfCtrlWordHandler(rtfParser, "pgnzodiacd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgnzodiacl"] = new RtfCtrlWordHandler(rtfParser, "pgnzodiacl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pgp"] = new RtfCtrlWordHandler(rtfParser, "pgp", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["pgptbl"] = new RtfCtrlWordHandler(rtfParser, "pgptbl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationNull"); + ctrlWords["pgwsxn"] = new RtfCtrlWordHandler(rtfParser, "pgwsxn", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["phcol"] = new RtfCtrlWordHandler(rtfParser, "phcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["phmrg"] = new RtfCtrlWordHandler(rtfParser, "phmrg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["phnthaia"] = new RtfCtrlWordHandler(rtfParser, "phnthaia", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["phpg"] = new RtfCtrlWordHandler(rtfParser, "phpg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["picbmp"] = new RtfCtrlWordHandler(rtfParser, "picbmp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["picbpp"] = new RtfCtrlWordHandler(rtfParser, "picbpp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["piccropb"] = new RtfCtrlWordHandler(rtfParser, "piccropb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["piccropl"] = new RtfCtrlWordHandler(rtfParser, "piccropl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["piccropr"] = new RtfCtrlWordHandler(rtfParser, "piccropr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["piccropt"] = new RtfCtrlWordHandler(rtfParser, "piccropt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pich"] = new RtfCtrlWordHandler(rtfParser, "pich", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pichgoal"] = new RtfCtrlWordHandler(rtfParser, "pichgoal", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["picprop"] = new RtfCtrlWordHandler(rtfParser, "picprop", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationShppict" ); + ctrlWords["picscaled"] = new RtfCtrlWordHandler(rtfParser, "picscaled", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["picscalex"] = new RtfCtrlWordHandler(rtfParser, "picscalex", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["picscaley"] = new RtfCtrlWordHandler(rtfParser, "picscaley", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pict"] = new RtfCtrlWordHandler(rtfParser, "pict", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationShppict" ); + ctrlWords["picw"] = new RtfCtrlWordHandler(rtfParser, "picw", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["picwgoal"] = new RtfCtrlWordHandler(rtfParser, "picwgoal", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pindtabqc"] = new RtfCtrlWordHandler(rtfParser, "pindtabqc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pindtabql"] = new RtfCtrlWordHandler(rtfParser, "pindtabql", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pindtabqr"] = new RtfCtrlWordHandler(rtfParser, "pindtabqr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["plain"] = new RtfCtrlWordHandler(rtfParser, "plain", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pmartabqc"] = new RtfCtrlWordHandler(rtfParser, "pmartabqc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pmartabql"] = new RtfCtrlWordHandler(rtfParser, "pmartabql", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pmartabqr"] = new RtfCtrlWordHandler(rtfParser, "pmartabqr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pmmetafile"] = new RtfCtrlWordHandler(rtfParser, "pmmetafile", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pn"] = new RtfCtrlWordHandler(rtfParser, "pn", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["pnacross"] = new RtfCtrlWordHandler(rtfParser, "pnacross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnaiu"] = new RtfCtrlWordHandler(rtfParser, "pnaiu", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnaiud"] = new RtfCtrlWordHandler(rtfParser, "pnaiud", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnaiueo"] = new RtfCtrlWordHandler(rtfParser, "pnaiueo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnaiueod"] = new RtfCtrlWordHandler(rtfParser, "pnaiueod", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnb"] = new RtfCtrlWordHandler(rtfParser, "pnb", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["pnbidia"] = new RtfCtrlWordHandler(rtfParser, "pnbidia", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnbidib"] = new RtfCtrlWordHandler(rtfParser, "pnbidib", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pncaps"] = new RtfCtrlWordHandler(rtfParser, "pncaps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["pncard"] = new RtfCtrlWordHandler(rtfParser, "pncard", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pncf"] = new RtfCtrlWordHandler(rtfParser, "pncf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnchosung"] = new RtfCtrlWordHandler(rtfParser, "pnchosung", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pncnum"] = new RtfCtrlWordHandler(rtfParser, "pncnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndbnum"] = new RtfCtrlWordHandler(rtfParser, "pndbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndbnumd"] = new RtfCtrlWordHandler(rtfParser, "pndbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndbnumk"] = new RtfCtrlWordHandler(rtfParser, "pndbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndbnuml"] = new RtfCtrlWordHandler(rtfParser, "pndbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndbnumt"] = new RtfCtrlWordHandler(rtfParser, "pndbnumt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndec"] = new RtfCtrlWordHandler(rtfParser, "pndec", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pndecd"] = new RtfCtrlWordHandler(rtfParser, "pndecd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnf"] = new RtfCtrlWordHandler(rtfParser, "pnf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnfs"] = new RtfCtrlWordHandler(rtfParser, "pnfs", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnganada"] = new RtfCtrlWordHandler(rtfParser, "pnganada", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pngblip"] = new RtfCtrlWordHandler(rtfParser, "pngblip", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pngbnum"] = new RtfCtrlWordHandler(rtfParser, "pngbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pngbnumd"] = new RtfCtrlWordHandler(rtfParser, "pngbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pngbnumk"] = new RtfCtrlWordHandler(rtfParser, "pngbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pngbnuml"] = new RtfCtrlWordHandler(rtfParser, "pngbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnhang"] = new RtfCtrlWordHandler(rtfParser, "pnhang", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pni"] = new RtfCtrlWordHandler(rtfParser, "pni", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["pnindent"] = new RtfCtrlWordHandler(rtfParser, "pnindent", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pniroha"] = new RtfCtrlWordHandler(rtfParser, "pniroha", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnirohad"] = new RtfCtrlWordHandler(rtfParser, "pnirohad", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnlcltr"] = new RtfCtrlWordHandler(rtfParser, "pnlcltr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnlcrm"] = new RtfCtrlWordHandler(rtfParser, "pnlcrm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnlvl"] = new RtfCtrlWordHandler(rtfParser, "pnlvl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnlvlblt"] = new RtfCtrlWordHandler(rtfParser, "pnlvlblt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnlvlbody"] = new RtfCtrlWordHandler(rtfParser, "pnlvlbody", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnlvlcont"] = new RtfCtrlWordHandler(rtfParser, "pnlvlcont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnnumonce"] = new RtfCtrlWordHandler(rtfParser, "pnnumonce", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnord"] = new RtfCtrlWordHandler(rtfParser, "pnord", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnordt"] = new RtfCtrlWordHandler(rtfParser, "pnordt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnprev"] = new RtfCtrlWordHandler(rtfParser, "pnprev", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnqc"] = new RtfCtrlWordHandler(rtfParser, "pnqc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnql"] = new RtfCtrlWordHandler(rtfParser, "pnql", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnqr"] = new RtfCtrlWordHandler(rtfParser, "pnqr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnrauth"] = new RtfCtrlWordHandler(rtfParser, "pnrauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrdate"] = new RtfCtrlWordHandler(rtfParser, "pnrdate", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrestart"] = new RtfCtrlWordHandler(rtfParser, "pnrestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnrnfc"] = new RtfCtrlWordHandler(rtfParser, "pnrnfc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrnot"] = new RtfCtrlWordHandler(rtfParser, "pnrnot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnrpnbr"] = new RtfCtrlWordHandler(rtfParser, "pnrpnbr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrrgb"] = new RtfCtrlWordHandler(rtfParser, "pnrrgb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrstart"] = new RtfCtrlWordHandler(rtfParser, "pnrstart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrstop"] = new RtfCtrlWordHandler(rtfParser, "pnrstop", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnrxst"] = new RtfCtrlWordHandler(rtfParser, "pnrxst", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnscaps"] = new RtfCtrlWordHandler(rtfParser, "pnscaps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["pnseclvl"] = new RtfCtrlWordHandler(rtfParser, "pnseclvl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["pnsp"] = new RtfCtrlWordHandler(rtfParser, "pnsp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnstart"] = new RtfCtrlWordHandler(rtfParser, "pnstart", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["pnstrike"] = new RtfCtrlWordHandler(rtfParser, "pnstrike", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["pntext"] = new RtfCtrlWordHandler(rtfParser, "pntext", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["pntxta"] = new RtfCtrlWordHandler(rtfParser, "pntxta", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["pntxtb"] = new RtfCtrlWordHandler(rtfParser, "pntxtb", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["pnucltr"] = new RtfCtrlWordHandler(rtfParser, "pnucltr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnucrm"] = new RtfCtrlWordHandler(rtfParser, "pnucrm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnul"] = new RtfCtrlWordHandler(rtfParser, "pnul", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["pnuld"] = new RtfCtrlWordHandler(rtfParser, "pnuld", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnuldash"] = new RtfCtrlWordHandler(rtfParser, "pnuldash", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnuldashd"] = new RtfCtrlWordHandler(rtfParser, "pnuldashd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnuldashdd"] = new RtfCtrlWordHandler(rtfParser, "pnuldashdd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnuldb"] = new RtfCtrlWordHandler(rtfParser, "pnuldb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnulhair"] = new RtfCtrlWordHandler(rtfParser, "pnulhair", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnulnone"] = new RtfCtrlWordHandler(rtfParser, "pnulnone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnulth"] = new RtfCtrlWordHandler(rtfParser, "pnulth", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnulw"] = new RtfCtrlWordHandler(rtfParser, "pnulw", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnulwave"] = new RtfCtrlWordHandler(rtfParser, "pnulwave", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnzodiac"] = new RtfCtrlWordHandler(rtfParser, "pnzodiac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnzodiacd"] = new RtfCtrlWordHandler(rtfParser, "pnzodiacd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pnzodiacl"] = new RtfCtrlWordHandler(rtfParser, "pnzodiacl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posnegx"] = new RtfCtrlWordHandler(rtfParser, "posnegx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["posnegy"] = new RtfCtrlWordHandler(rtfParser, "posnegy", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["posx"] = new RtfCtrlWordHandler(rtfParser, "posx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["posxc"] = new RtfCtrlWordHandler(rtfParser, "posxc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posxi"] = new RtfCtrlWordHandler(rtfParser, "posxi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posxl"] = new RtfCtrlWordHandler(rtfParser, "posxl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posxo"] = new RtfCtrlWordHandler(rtfParser, "posxo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posxr"] = new RtfCtrlWordHandler(rtfParser, "posxr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posy"] = new RtfCtrlWordHandler(rtfParser, "posy", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["posyb"] = new RtfCtrlWordHandler(rtfParser, "posyb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posyc"] = new RtfCtrlWordHandler(rtfParser, "posyc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posyil"] = new RtfCtrlWordHandler(rtfParser, "posyil", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posyin"] = new RtfCtrlWordHandler(rtfParser, "posyin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posyout"] = new RtfCtrlWordHandler(rtfParser, "posyout", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["posyt"] = new RtfCtrlWordHandler(rtfParser, "posyt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["prcolbl"] = new RtfCtrlWordHandler(rtfParser, "prcolbl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["printdata"] = new RtfCtrlWordHandler(rtfParser, "printdata", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["printim"] = new RtfCtrlWordHandler(rtfParser, "printim", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["private"] = new RtfCtrlWordHandler(rtfParser, "private", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["propname"] = new RtfCtrlWordHandler(rtfParser, "propname", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["proptype"] = new RtfCtrlWordHandler(rtfParser, "proptype", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["protend"] = new RtfCtrlWordHandler(rtfParser, "protend", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["protlevel"] = new RtfCtrlWordHandler(rtfParser, "protlevel", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["protstart"] = new RtfCtrlWordHandler(rtfParser, "protstart", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["protusertbl"] = new RtfCtrlWordHandler(rtfParser, "protusertbl", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["psover"] = new RtfCtrlWordHandler(rtfParser, "psover", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["psz"] = new RtfCtrlWordHandler(rtfParser, "psz", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ptabldot"] = new RtfCtrlWordHandler(rtfParser, "ptabldot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ptablmdot"] = new RtfCtrlWordHandler(rtfParser, "ptablmdot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ptablminus"] = new RtfCtrlWordHandler(rtfParser, "ptablminus", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ptablnone"] = new RtfCtrlWordHandler(rtfParser, "ptablnone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ptabluscore"] = new RtfCtrlWordHandler(rtfParser, "ptabluscore", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pubauto"] = new RtfCtrlWordHandler(rtfParser, "pubauto", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pvmrg"] = new RtfCtrlWordHandler(rtfParser, "pvmrg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pvpara"] = new RtfCtrlWordHandler(rtfParser, "pvpara", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pvpg"] = new RtfCtrlWordHandler(rtfParser, "pvpg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["pwd"] = new RtfCtrlWordHandler(rtfParser, "pwd", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["pxe"] = new RtfCtrlWordHandler(rtfParser, "pxe", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["qc"] = new RtfCtrlWordHandler(rtfParser, "qc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["qd"] = new RtfCtrlWordHandler(rtfParser, "qd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["qj"] = new RtfCtrlWordHandler(rtfParser, "qj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["qk"] = new RtfCtrlWordHandler(rtfParser, "qk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ql"] = new RtfCtrlWordHandler(rtfParser, "ql", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["qmspace"] = new RtfCtrlWordHandler(rtfParser, "qmspace", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["qr"] = new RtfCtrlWordHandler(rtfParser, "qr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["qt"] = new RtfCtrlWordHandler(rtfParser, "qt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawbgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "rawbgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgbdiag"] = new RtfCtrlWordHandler(rtfParser, "rawclbgbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgcross"] = new RtfCtrlWordHandler(rtfParser, "rawclbgcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdcross"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdkcross"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdkcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdkdcross"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdkdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdkfdiag"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdkfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdkhor"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdkhor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgdkvert"] = new RtfCtrlWordHandler(rtfParser, "rawclbgdkvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgfdiag"] = new RtfCtrlWordHandler(rtfParser, "rawclbgfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbghoriz"] = new RtfCtrlWordHandler(rtfParser, "rawclbghoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rawclbgvert"] = new RtfCtrlWordHandler(rtfParser, "rawclbgvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rdblquote"] = new RtfCtrlWordHandler(rtfParser, "rdblquote", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x148"); + ctrlWords["readonlyrecommended"] = new RtfCtrlWordHandler(rtfParser, "readonlyrecommended", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["readprot"] = new RtfCtrlWordHandler(rtfParser, "readprot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["red"] = new RtfCtrlWordHandler(rtfParser, "red", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["relyonvml"] = new RtfCtrlWordHandler(rtfParser, "relyonvml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rempersonalinfo"] = new RtfCtrlWordHandler(rtfParser, "rempersonalinfo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["result"] = new RtfCtrlWordHandler(rtfParser, "result", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["revauth"] = new RtfCtrlWordHandler(rtfParser, "revauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["revauthdel"] = new RtfCtrlWordHandler(rtfParser, "revauthdel", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["revbar"] = new RtfCtrlWordHandler(rtfParser, "revbar", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["revdttm"] = new RtfCtrlWordHandler(rtfParser, "revdttm", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["revdttmdel"] = new RtfCtrlWordHandler(rtfParser, "revdttmdel", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["revised"] = new RtfCtrlWordHandler(rtfParser, "revised", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["revisions"] = new RtfCtrlWordHandler(rtfParser, "revisions", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["revprop"] = new RtfCtrlWordHandler(rtfParser, "revprop", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["revprot"] = new RtfCtrlWordHandler(rtfParser, "revprot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["revtbl"] = new RtfCtrlWordHandler(rtfParser, "revtbl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationNull"); + ctrlWords["revtim"] = new RtfCtrlWordHandler(rtfParser, "revtim", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationNull"); + ctrlWords["ri"] = new RtfCtrlWordHandler(rtfParser, "ri", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["rin"] = new RtfCtrlWordHandler(rtfParser, "rin", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["row"] = new RtfCtrlWordHandler(rtfParser, "row", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["rquote"] = new RtfCtrlWordHandler(rtfParser, "rquote", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", "\0x146"); + ctrlWords["rsid"] = new RtfCtrlWordHandler(rtfParser, "rsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["rsidroot"] = new RtfCtrlWordHandler(rtfParser, "rsidroot", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["rsidtbl"] = new RtfCtrlWordHandler(rtfParser, "rsidtbl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationNull"); + ctrlWords["rsltbmp"] = new RtfCtrlWordHandler(rtfParser, "rsltbmp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rslthtml"] = new RtfCtrlWordHandler(rtfParser, "rslthtml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rsltmerge"] = new RtfCtrlWordHandler(rtfParser, "rsltmerge", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rsltpict"] = new RtfCtrlWordHandler(rtfParser, "rsltpict", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rsltrtf"] = new RtfCtrlWordHandler(rtfParser, "rsltrtf", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rslttxt"] = new RtfCtrlWordHandler(rtfParser, "rslttxt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rtf"] = new RtfCtrlWordHandler(rtfParser, "rtf", 1, true, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["rtlch"] = new RtfCtrlWordHandler(rtfParser, "rtlch", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rtldoc"] = new RtfCtrlWordHandler(rtfParser, "rtldoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rtlgutter"] = new RtfCtrlWordHandler(rtfParser, "rtlgutter", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rtlmark"] = new RtfCtrlWordHandler(rtfParser, "rtlmark", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["rtlpar"] = new RtfCtrlWordHandler(rtfParser, "rtlpar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rtlrow"] = new RtfCtrlWordHandler(rtfParser, "rtlrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rtlsect"] = new RtfCtrlWordHandler(rtfParser, "rtlsect", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["rxe"] = new RtfCtrlWordHandler(rtfParser, "rxe", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["s"] = new RtfCtrlWordHandler(rtfParser, "s", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sa"] = new RtfCtrlWordHandler(rtfParser, "sa", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["saauto"] = new RtfCtrlWordHandler(rtfParser, "saauto", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["saftnnalc"] = new RtfCtrlWordHandler(rtfParser, "saftnnalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnar"] = new RtfCtrlWordHandler(rtfParser, "saftnnar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnauc"] = new RtfCtrlWordHandler(rtfParser, "saftnnauc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnchi"] = new RtfCtrlWordHandler(rtfParser, "saftnnchi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnchosung"] = new RtfCtrlWordHandler(rtfParser, "saftnnchosung", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnncnum"] = new RtfCtrlWordHandler(rtfParser, "saftnncnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnndbar"] = new RtfCtrlWordHandler(rtfParser, "saftnndbar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnndbnum"] = new RtfCtrlWordHandler(rtfParser, "saftnndbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnndbnumd"] = new RtfCtrlWordHandler(rtfParser, "saftnndbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnndbnumk"] = new RtfCtrlWordHandler(rtfParser, "saftnndbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnndbnumt"] = new RtfCtrlWordHandler(rtfParser, "saftnndbnumt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnganada"] = new RtfCtrlWordHandler(rtfParser, "saftnnganada", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnngbnum"] = new RtfCtrlWordHandler(rtfParser, "saftnngbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnngbnumd"] = new RtfCtrlWordHandler(rtfParser, "saftnngbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnngbnumk"] = new RtfCtrlWordHandler(rtfParser, "saftnngbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnngbnuml"] = new RtfCtrlWordHandler(rtfParser, "saftnngbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnrlc"] = new RtfCtrlWordHandler(rtfParser, "saftnnrlc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnruc"] = new RtfCtrlWordHandler(rtfParser, "saftnnruc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnzodiac"] = new RtfCtrlWordHandler(rtfParser, "saftnnzodiac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnzodiacd"] = new RtfCtrlWordHandler(rtfParser, "saftnnzodiacd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnnzodiacl"] = new RtfCtrlWordHandler(rtfParser, "saftnnzodiacl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnrestart"] = new RtfCtrlWordHandler(rtfParser, "saftnrestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnrstcont"] = new RtfCtrlWordHandler(rtfParser, "saftnrstcont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saftnstart"] = new RtfCtrlWordHandler(rtfParser, "saftnstart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sautoupd"] = new RtfCtrlWordHandler(rtfParser, "sautoupd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saveinvalidxml"] = new RtfCtrlWordHandler(rtfParser, "saveinvalidxml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["saveprevpict"] = new RtfCtrlWordHandler(rtfParser, "saveprevpict", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sb"] = new RtfCtrlWordHandler(rtfParser, "sb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sbasedon"] = new RtfCtrlWordHandler(rtfParser, "sbasedon", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sbauto"] = new RtfCtrlWordHandler(rtfParser, "sbauto", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["sbkcol"] = new RtfCtrlWordHandler(rtfParser, "sbkcol", RtfProperty.SBK_COLUMN, false, RtfCtrlWordType.FLAG, "\\", " ", RtfProperty.SECTION_BREAK_TYPE); + ctrlWords["sbkeven"] = new RtfCtrlWordHandler(rtfParser, "sbkeven", RtfProperty.SBK_EVEN, false, RtfCtrlWordType.FLAG, "\\", " ", RtfProperty.SECTION_BREAK_TYPE); + ctrlWords["sbknone"] = new RtfCtrlWordHandler(rtfParser, "sbknone", RtfProperty.SBK_NONE, false, RtfCtrlWordType.FLAG, "\\", " ", RtfProperty.SECTION_BREAK_TYPE); + ctrlWords["sbkodd"] = new RtfCtrlWordHandler(rtfParser, "sbkodd", RtfProperty.SBK_ODD, false, RtfCtrlWordType.FLAG, "\\", " ", RtfProperty.SECTION_BREAK_TYPE); + ctrlWords["sbkpage"] = new RtfCtrlWordHandler(rtfParser, "sbkpage", RtfProperty.SBK_PAGE, false, RtfCtrlWordType.FLAG, "\\", " ", RtfProperty.SECTION_BREAK_TYPE); + ctrlWords["sbys"] = new RtfCtrlWordHandler(rtfParser, "sbys", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["scaps"] = new RtfCtrlWordHandler(rtfParser, "scaps", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["scompose"] = new RtfCtrlWordHandler(rtfParser, "scompose", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sec"] = new RtfCtrlWordHandler(rtfParser, "sec", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sect"] = new RtfCtrlWordHandler(rtfParser, "sect", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["sectd"] = new RtfCtrlWordHandler(rtfParser, "sectd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sectdefaultcl"] = new RtfCtrlWordHandler(rtfParser, "sectdefaultcl", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectexpand"] = new RtfCtrlWordHandler(rtfParser, "sectexpand", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectlinegrid"] = new RtfCtrlWordHandler(rtfParser, "sectlinegrid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectnum"] = new RtfCtrlWordHandler(rtfParser, "sectnum", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["sectrsid"] = new RtfCtrlWordHandler(rtfParser, "sectrsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectspecifycl"] = new RtfCtrlWordHandler(rtfParser, "sectspecifycl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectspecifygen"] = new RtfCtrlWordHandler(rtfParser, "sectspecifygen", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectspecifyl"] = new RtfCtrlWordHandler(rtfParser, "sectspecifyl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sectunlocked"] = new RtfCtrlWordHandler(rtfParser, "sectunlocked", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnbj"] = new RtfCtrlWordHandler(rtfParser, "sftnbj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnalc"] = new RtfCtrlWordHandler(rtfParser, "sftnnalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnar"] = new RtfCtrlWordHandler(rtfParser, "sftnnar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnauc"] = new RtfCtrlWordHandler(rtfParser, "sftnnauc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnchi"] = new RtfCtrlWordHandler(rtfParser, "sftnnchi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnchosung"] = new RtfCtrlWordHandler(rtfParser, "sftnnchosung", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnncnum"] = new RtfCtrlWordHandler(rtfParser, "sftnncnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnndbar"] = new RtfCtrlWordHandler(rtfParser, "sftnndbar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnndbnum"] = new RtfCtrlWordHandler(rtfParser, "sftnndbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnndbnumd"] = new RtfCtrlWordHandler(rtfParser, "sftnndbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnndbnumk"] = new RtfCtrlWordHandler(rtfParser, "sftnndbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnndbnumt"] = new RtfCtrlWordHandler(rtfParser, "sftnndbnumt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnganada"] = new RtfCtrlWordHandler(rtfParser, "sftnnganada", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnngbnum"] = new RtfCtrlWordHandler(rtfParser, "sftnngbnum", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnngbnumd"] = new RtfCtrlWordHandler(rtfParser, "sftnngbnumd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnngbnumk"] = new RtfCtrlWordHandler(rtfParser, "sftnngbnumk", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnngbnuml"] = new RtfCtrlWordHandler(rtfParser, "sftnngbnuml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnrlc"] = new RtfCtrlWordHandler(rtfParser, "sftnnrlc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnruc"] = new RtfCtrlWordHandler(rtfParser, "sftnnruc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnzodiac"] = new RtfCtrlWordHandler(rtfParser, "sftnnzodiac", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnzodiacd"] = new RtfCtrlWordHandler(rtfParser, "sftnnzodiacd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnnzodiacl"] = new RtfCtrlWordHandler(rtfParser, "sftnnzodiacl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnrestart"] = new RtfCtrlWordHandler(rtfParser, "sftnrestart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnrstcont"] = new RtfCtrlWordHandler(rtfParser, "sftnrstcont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnrstpg"] = new RtfCtrlWordHandler(rtfParser, "sftnrstpg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftnstart"] = new RtfCtrlWordHandler(rtfParser, "sftnstart", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sftntj"] = new RtfCtrlWordHandler(rtfParser, "sftntj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shad"] = new RtfCtrlWordHandler(rtfParser, "shad", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["shading"] = new RtfCtrlWordHandler(rtfParser, "shading", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shidden"] = new RtfCtrlWordHandler(rtfParser, "shidden", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shift"] = new RtfCtrlWordHandler(rtfParser, "shift", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["showplaceholdtext"] = new RtfCtrlWordHandler(rtfParser, "showplaceholdtext", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["showxmlerrors"] = new RtfCtrlWordHandler(rtfParser, "showxmlerrors", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shp"] = new RtfCtrlWordHandler(rtfParser, "shp", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["shpbottom"] = new RtfCtrlWordHandler(rtfParser, "shpbottom", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpbxcolumn"] = new RtfCtrlWordHandler(rtfParser, "shpbxcolumn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbxignore"] = new RtfCtrlWordHandler(rtfParser, "shpbxignore", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbxmargin"] = new RtfCtrlWordHandler(rtfParser, "shpbxmargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbxpage"] = new RtfCtrlWordHandler(rtfParser, "shpbxpage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbyignore"] = new RtfCtrlWordHandler(rtfParser, "shpbyignore", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbymargin"] = new RtfCtrlWordHandler(rtfParser, "shpbymargin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbypage"] = new RtfCtrlWordHandler(rtfParser, "shpbypage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpbypara"] = new RtfCtrlWordHandler(rtfParser, "shpbypara", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shpfblwtxt"] = new RtfCtrlWordHandler(rtfParser, "shpfblwtxt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpfhdr"] = new RtfCtrlWordHandler(rtfParser, "shpfhdr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpgrp"] = new RtfCtrlWordHandler(rtfParser, "shpgrp", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpinst"] = new RtfCtrlWordHandler(rtfParser, "shpinst", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["shpleft"] = new RtfCtrlWordHandler(rtfParser, "shpleft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shplid"] = new RtfCtrlWordHandler(rtfParser, "shplid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shplockanchor"] = new RtfCtrlWordHandler(rtfParser, "shplockanchor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["shppict"] = new RtfCtrlWordHandler(rtfParser, "shppict", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationShppict" );//"RtfDestinationShppict"; + ctrlWords["shpright"] = new RtfCtrlWordHandler(rtfParser, "shpright", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shprslt"] = new RtfCtrlWordHandler(rtfParser, "shprslt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shptop"] = new RtfCtrlWordHandler(rtfParser, "shptop", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shptxt"] = new RtfCtrlWordHandler(rtfParser, "shptxt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpwr"] = new RtfCtrlWordHandler(rtfParser, "shpwr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpwrk"] = new RtfCtrlWordHandler(rtfParser, "shpwrk", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["shpz"] = new RtfCtrlWordHandler(rtfParser, "shpz", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sl"] = new RtfCtrlWordHandler(rtfParser, "sl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["slink"] = new RtfCtrlWordHandler(rtfParser, "slink", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["slmult"] = new RtfCtrlWordHandler(rtfParser, "slmult", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["slocked"] = new RtfCtrlWordHandler(rtfParser, "slocked", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sn"] = new RtfCtrlWordHandler(rtfParser, "sn", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["snapgridtocell"] = new RtfCtrlWordHandler(rtfParser, "snapgridtocell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["snaptogridincell"] = new RtfCtrlWordHandler(rtfParser, "snaptogridincell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["snext"] = new RtfCtrlWordHandler(rtfParser, "snext", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["softcol"] = new RtfCtrlWordHandler(rtfParser, "softcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["softlheight"] = new RtfCtrlWordHandler(rtfParser, "softlheight", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["softline"] = new RtfCtrlWordHandler(rtfParser, "softline", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["softpage"] = new RtfCtrlWordHandler(rtfParser, "softpage", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sp"] = new RtfCtrlWordHandler(rtfParser, "sp", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["spersonal"] = new RtfCtrlWordHandler(rtfParser, "spersonal", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["spltpgpar"] = new RtfCtrlWordHandler(rtfParser, "spltpgpar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["splytwnine"] = new RtfCtrlWordHandler(rtfParser, "splytwnine", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["spp"] = new RtfCtrlWordHandler(rtfParser, "spp", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["spriority"] = new RtfCtrlWordHandler(rtfParser, "spriority", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sprsbsp"] = new RtfCtrlWordHandler(rtfParser, "sprsbsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sprslnsp"] = new RtfCtrlWordHandler(rtfParser, "sprslnsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sprsspbf"] = new RtfCtrlWordHandler(rtfParser, "sprsspbf", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sprstsm"] = new RtfCtrlWordHandler(rtfParser, "sprstsm", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sprstsp"] = new RtfCtrlWordHandler(rtfParser, "sprstsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["spv"] = new RtfCtrlWordHandler(rtfParser, "spv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sqformat"] = new RtfCtrlWordHandler(rtfParser, "sqformat", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sreply"] = new RtfCtrlWordHandler(rtfParser, "sreply", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ssemihidden"] = new RtfCtrlWordHandler(rtfParser, "ssemihidden", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["staticval"] = new RtfCtrlWordHandler(rtfParser, "staticval", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["stextflow"] = new RtfCtrlWordHandler(rtfParser, "stextflow", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["strike"] = new RtfCtrlWordHandler(rtfParser, "strike", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["striked1"] = new RtfCtrlWordHandler(rtfParser, "striked1", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["stshfbi"] = new RtfCtrlWordHandler(rtfParser, "stshfbi", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["stshfdbch"] = new RtfCtrlWordHandler(rtfParser, "stshfdbch", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["stshfhich"] = new RtfCtrlWordHandler(rtfParser, "stshfhich", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["stshfloch"] = new RtfCtrlWordHandler(rtfParser, "stshfloch", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["stylelock"] = new RtfCtrlWordHandler(rtfParser, "stylelock", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["stylelockbackcomp"] = new RtfCtrlWordHandler(rtfParser, "stylelockbackcomp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["stylelockenforced"] = new RtfCtrlWordHandler(rtfParser, "stylelockenforced", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["stylelockqfset"] = new RtfCtrlWordHandler(rtfParser, "stylelockqfset", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["stylelocktheme"] = new RtfCtrlWordHandler(rtfParser, "stylelocktheme", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["stylesheet"] = new RtfCtrlWordHandler(rtfParser, "stylesheet", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationStylesheetTable"); + ctrlWords["stylesortmethod"] = new RtfCtrlWordHandler(rtfParser, "stylesortmethod", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["styrsid"] = new RtfCtrlWordHandler(rtfParser, "styrsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["sub"] = new RtfCtrlWordHandler(rtfParser, "sub", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["subdocument"] = new RtfCtrlWordHandler(rtfParser, "subdocument", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["subfontbysize"] = new RtfCtrlWordHandler(rtfParser, "subfontbysize", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["subject"] = new RtfCtrlWordHandler(rtfParser, "subject", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["sunhideused"] = new RtfCtrlWordHandler(rtfParser, "sunhideused", 0, true, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["super"] = new RtfCtrlWordHandler(rtfParser, "super", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["sv"] = new RtfCtrlWordHandler(rtfParser, "sv", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["svb"] = new RtfCtrlWordHandler(rtfParser, "svb", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["swpbdr"] = new RtfCtrlWordHandler(rtfParser, "swpbdr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tab"] = new RtfCtrlWordHandler(rtfParser, "tab", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["tabsnoovrlp"] = new RtfCtrlWordHandler(rtfParser, "tabsnoovrlp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["taprtl"] = new RtfCtrlWordHandler(rtfParser, "taprtl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tb"] = new RtfCtrlWordHandler(rtfParser, "tb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tblind"] = new RtfCtrlWordHandler(rtfParser, "tblind", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tblindtype"] = new RtfCtrlWordHandler(rtfParser, "tblindtype", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tbllkbestfit"] = new RtfCtrlWordHandler(rtfParser, "tbllkbestfit", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllkborder"] = new RtfCtrlWordHandler(rtfParser, "tbllkborder", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllkcolor"] = new RtfCtrlWordHandler(rtfParser, "tbllkcolor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllkfont"] = new RtfCtrlWordHandler(rtfParser, "tbllkfont", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllkhdrcols"] = new RtfCtrlWordHandler(rtfParser, "tbllkhdrcols", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllkhdrrows"] = new RtfCtrlWordHandler(rtfParser, "tbllkhdrrows", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllklastcol"] = new RtfCtrlWordHandler(rtfParser, "tbllklastcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllklastrow"] = new RtfCtrlWordHandler(rtfParser, "tbllklastrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllknocolband"] = new RtfCtrlWordHandler(rtfParser, "tbllknocolband", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllknorowband"] = new RtfCtrlWordHandler(rtfParser, "tbllknorowband", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tbllkshading"] = new RtfCtrlWordHandler(rtfParser, "tbllkshading", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tblrsid"] = new RtfCtrlWordHandler(rtfParser, "tblrsid", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tc"] = new RtfCtrlWordHandler(rtfParser, "tc", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["tcelld"] = new RtfCtrlWordHandler(rtfParser, "tcelld", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tcf"] = new RtfCtrlWordHandler(rtfParser, "tcf", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tcl"] = new RtfCtrlWordHandler(rtfParser, "tcl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tcn"] = new RtfCtrlWordHandler(rtfParser, "tcn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tdfrmtxtBottom"] = new RtfCtrlWordHandler(rtfParser, "tdfrmtxtBottom", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tdfrmtxtLeft"] = new RtfCtrlWordHandler(rtfParser, "tdfrmtxtLeft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tdfrmtxtRight"] = new RtfCtrlWordHandler(rtfParser, "tdfrmtxtRight", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tdfrmtxtTop"] = new RtfCtrlWordHandler(rtfParser, "tdfrmtxtTop", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["template"] = new RtfCtrlWordHandler(rtfParser, "template", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["themedata"] = new RtfCtrlWordHandler(rtfParser, "themedata", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["themelang"] = new RtfCtrlWordHandler(rtfParser, "themelang", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["themelangcs"] = new RtfCtrlWordHandler(rtfParser, "themelangcs", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["themelangfe"] = new RtfCtrlWordHandler(rtfParser, "themelangfe", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["time"] = new RtfCtrlWordHandler(rtfParser, "time", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["title"] = new RtfCtrlWordHandler(rtfParser, "title", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationInfo"); + ctrlWords["titlepg"] = new RtfCtrlWordHandler(rtfParser, "titlepg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tldot"] = new RtfCtrlWordHandler(rtfParser, "tldot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tleq"] = new RtfCtrlWordHandler(rtfParser, "tleq", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tlhyph"] = new RtfCtrlWordHandler(rtfParser, "tlhyph", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tlmdot"] = new RtfCtrlWordHandler(rtfParser, "tlmdot", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tlth"] = new RtfCtrlWordHandler(rtfParser, "tlth", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tlul"] = new RtfCtrlWordHandler(rtfParser, "tlul", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["toplinepunct"] = new RtfCtrlWordHandler(rtfParser, "toplinepunct", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tphcol"] = new RtfCtrlWordHandler(rtfParser, "tphcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tphmrg"] = new RtfCtrlWordHandler(rtfParser, "tphmrg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tphpg"] = new RtfCtrlWordHandler(rtfParser, "tphpg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposnegx"] = new RtfCtrlWordHandler(rtfParser, "tposnegx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tposnegy"] = new RtfCtrlWordHandler(rtfParser, "tposnegy", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tposx"] = new RtfCtrlWordHandler(rtfParser, "tposx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tposxc"] = new RtfCtrlWordHandler(rtfParser, "tposxc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposxi"] = new RtfCtrlWordHandler(rtfParser, "tposxi", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposxl"] = new RtfCtrlWordHandler(rtfParser, "tposxl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposxo"] = new RtfCtrlWordHandler(rtfParser, "tposxo", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposxr"] = new RtfCtrlWordHandler(rtfParser, "tposxr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposy"] = new RtfCtrlWordHandler(rtfParser, "tposy", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyb"] = new RtfCtrlWordHandler(rtfParser, "tposyb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyc"] = new RtfCtrlWordHandler(rtfParser, "tposyc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyil"] = new RtfCtrlWordHandler(rtfParser, "tposyil", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyin"] = new RtfCtrlWordHandler(rtfParser, "tposyin", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyout"] = new RtfCtrlWordHandler(rtfParser, "tposyout", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyoutv"] = new RtfCtrlWordHandler(rtfParser, "tposyoutv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tposyt"] = new RtfCtrlWordHandler(rtfParser, "tposyt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tpvmrg"] = new RtfCtrlWordHandler(rtfParser, "tpvmrg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tpvpara"] = new RtfCtrlWordHandler(rtfParser, "tpvpara", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tpvpg"] = new RtfCtrlWordHandler(rtfParser, "tpvpg", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tqc"] = new RtfCtrlWordHandler(rtfParser, "tqc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tqdec"] = new RtfCtrlWordHandler(rtfParser, "tqdec", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tqr"] = new RtfCtrlWordHandler(rtfParser, "tqr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trackformatting"] = new RtfCtrlWordHandler(rtfParser, "trackformatting", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trackmoves"] = new RtfCtrlWordHandler(rtfParser, "trackmoves", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["transmf"] = new RtfCtrlWordHandler(rtfParser, "transmf", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trauth"] = new RtfCtrlWordHandler(rtfParser, "trauth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trautofit"] = new RtfCtrlWordHandler(rtfParser, "trautofit", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["trbgbdiag"] = new RtfCtrlWordHandler(rtfParser, "trbgbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgcross"] = new RtfCtrlWordHandler(rtfParser, "trbgcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdcross"] = new RtfCtrlWordHandler(rtfParser, "trbgdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "trbgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdkcross"] = new RtfCtrlWordHandler(rtfParser, "trbgdkcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdkdcross"] = new RtfCtrlWordHandler(rtfParser, "trbgdkdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdkfdiag"] = new RtfCtrlWordHandler(rtfParser, "trbgdkfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdkhor"] = new RtfCtrlWordHandler(rtfParser, "trbgdkhor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgdkvert"] = new RtfCtrlWordHandler(rtfParser, "trbgdkvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgfdiag"] = new RtfCtrlWordHandler(rtfParser, "trbgfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbghoriz"] = new RtfCtrlWordHandler(rtfParser, "trbghoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbgvert"] = new RtfCtrlWordHandler(rtfParser, "trbgvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbrdrb"] = new RtfCtrlWordHandler(rtfParser, "trbrdrb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbrdrh"] = new RtfCtrlWordHandler(rtfParser, "trbrdrh", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbrdrl"] = new RtfCtrlWordHandler(rtfParser, "trbrdrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbrdrr"] = new RtfCtrlWordHandler(rtfParser, "trbrdrr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbrdrt"] = new RtfCtrlWordHandler(rtfParser, "trbrdrt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trbrdrv"] = new RtfCtrlWordHandler(rtfParser, "trbrdrv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trcbpat"] = new RtfCtrlWordHandler(rtfParser, "trcbpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trcfpat"] = new RtfCtrlWordHandler(rtfParser, "trcfpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trdate"] = new RtfCtrlWordHandler(rtfParser, "trdate", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trftsWidth"] = new RtfCtrlWordHandler(rtfParser, "trftsWidth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trftsWidthA"] = new RtfCtrlWordHandler(rtfParser, "trftsWidthA", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trftsWidthB"] = new RtfCtrlWordHandler(rtfParser, "trftsWidthB", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trgaph"] = new RtfCtrlWordHandler(rtfParser, "trgaph", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trhdr"] = new RtfCtrlWordHandler(rtfParser, "trhdr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trkeep"] = new RtfCtrlWordHandler(rtfParser, "trkeep", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trkeepfollow"] = new RtfCtrlWordHandler(rtfParser, "trkeepfollow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trleft"] = new RtfCtrlWordHandler(rtfParser, "trleft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trowd"] = new RtfCtrlWordHandler(rtfParser, "trowd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trpaddb"] = new RtfCtrlWordHandler(rtfParser, "trpaddb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddfb"] = new RtfCtrlWordHandler(rtfParser, "trpaddfb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddfl"] = new RtfCtrlWordHandler(rtfParser, "trpaddfl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddfr"] = new RtfCtrlWordHandler(rtfParser, "trpaddfr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddft"] = new RtfCtrlWordHandler(rtfParser, "trpaddft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddl"] = new RtfCtrlWordHandler(rtfParser, "trpaddl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddr"] = new RtfCtrlWordHandler(rtfParser, "trpaddr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpaddt"] = new RtfCtrlWordHandler(rtfParser, "trpaddt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trpat"] = new RtfCtrlWordHandler(rtfParser, "trpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trqc"] = new RtfCtrlWordHandler(rtfParser, "trqc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trql"] = new RtfCtrlWordHandler(rtfParser, "trql", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trqr"] = new RtfCtrlWordHandler(rtfParser, "trqr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trrh"] = new RtfCtrlWordHandler(rtfParser, "trrh", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trshdng"] = new RtfCtrlWordHandler(rtfParser, "trshdng", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdb"] = new RtfCtrlWordHandler(rtfParser, "trspdb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdfb"] = new RtfCtrlWordHandler(rtfParser, "trspdfb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdfl"] = new RtfCtrlWordHandler(rtfParser, "trspdfl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdfr"] = new RtfCtrlWordHandler(rtfParser, "trspdfr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdft"] = new RtfCtrlWordHandler(rtfParser, "trspdft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdl"] = new RtfCtrlWordHandler(rtfParser, "trspdl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdr"] = new RtfCtrlWordHandler(rtfParser, "trspdr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trspdt"] = new RtfCtrlWordHandler(rtfParser, "trspdt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["truncatefontheight"] = new RtfCtrlWordHandler(rtfParser, "truncatefontheight", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["truncex"] = new RtfCtrlWordHandler(rtfParser, "truncex", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["trwWidth"] = new RtfCtrlWordHandler(rtfParser, "trwWidth", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trwWidthA"] = new RtfCtrlWordHandler(rtfParser, "trwWidthA", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["trwWidthB"] = new RtfCtrlWordHandler(rtfParser, "trwWidthB", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ts"] = new RtfCtrlWordHandler(rtfParser, "ts", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tsbgbdiag"] = new RtfCtrlWordHandler(rtfParser, "tsbgbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgcross"] = new RtfCtrlWordHandler(rtfParser, "tsbgcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdcross"] = new RtfCtrlWordHandler(rtfParser, "tsbgdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdkbdiag"] = new RtfCtrlWordHandler(rtfParser, "tsbgdkbdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdkcross"] = new RtfCtrlWordHandler(rtfParser, "tsbgdkcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdkdcross"] = new RtfCtrlWordHandler(rtfParser, "tsbgdkdcross", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdkfdiag"] = new RtfCtrlWordHandler(rtfParser, "tsbgdkfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdkhor"] = new RtfCtrlWordHandler(rtfParser, "tsbgdkhor", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgdkvert"] = new RtfCtrlWordHandler(rtfParser, "tsbgdkvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgfdiag"] = new RtfCtrlWordHandler(rtfParser, "tsbgfdiag", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbghoriz"] = new RtfCtrlWordHandler(rtfParser, "tsbghoriz", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbgvert"] = new RtfCtrlWordHandler(rtfParser, "tsbgvert", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrb"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrdgl"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrdgl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrdgr"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrdgr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrh"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrh", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrl"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrr"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrt"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsbrdrv"] = new RtfCtrlWordHandler(rtfParser, "tsbrdrv", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscbandhorzeven"] = new RtfCtrlWordHandler(rtfParser, "tscbandhorzeven", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscbandhorzodd"] = new RtfCtrlWordHandler(rtfParser, "tscbandhorzodd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscbandsh"] = new RtfCtrlWordHandler(rtfParser, "tscbandsh", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscbandsv"] = new RtfCtrlWordHandler(rtfParser, "tscbandsv", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscbandverteven"] = new RtfCtrlWordHandler(rtfParser, "tscbandverteven", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscbandvertodd"] = new RtfCtrlWordHandler(rtfParser, "tscbandvertodd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscellcbpat"] = new RtfCtrlWordHandler(rtfParser, "tscellcbpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellcfpat"] = new RtfCtrlWordHandler(rtfParser, "tscellcfpat", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddb"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddfb"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddfb", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddfl"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddfl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddfr"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddfr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddft"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddft", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddl"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddl", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddr"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpaddt"] = new RtfCtrlWordHandler(rtfParser, "tscellpaddt", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellpct"] = new RtfCtrlWordHandler(rtfParser, "tscellpct", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["tscellwidth"] = new RtfCtrlWordHandler(rtfParser, "tscellwidth", 0, true, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscellwidthfts"] = new RtfCtrlWordHandler(rtfParser, "tscellwidthfts", 0, true, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscfirstcol"] = new RtfCtrlWordHandler(rtfParser, "tscfirstcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscfirstrow"] = new RtfCtrlWordHandler(rtfParser, "tscfirstrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsclastcol"] = new RtfCtrlWordHandler(rtfParser, "tsclastcol", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsclastrow"] = new RtfCtrlWordHandler(rtfParser, "tsclastrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscnecell"] = new RtfCtrlWordHandler(rtfParser, "tscnecell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscnwcell"] = new RtfCtrlWordHandler(rtfParser, "tscnwcell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscsecell"] = new RtfCtrlWordHandler(rtfParser, "tscsecell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tscswcell"] = new RtfCtrlWordHandler(rtfParser, "tscswcell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsd"] = new RtfCtrlWordHandler(rtfParser, "tsd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsnowrap"] = new RtfCtrlWordHandler(rtfParser, "tsnowrap", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsrowd"] = new RtfCtrlWordHandler(rtfParser, "tsrowd", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsvertalb"] = new RtfCtrlWordHandler(rtfParser, "tsvertalb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsvertalc"] = new RtfCtrlWordHandler(rtfParser, "tsvertalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tsvertalt"] = new RtfCtrlWordHandler(rtfParser, "tsvertalt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["twoonone"] = new RtfCtrlWordHandler(rtfParser, "twoonone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["tx"] = new RtfCtrlWordHandler(rtfParser, "tx", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["txbxtwalways"] = new RtfCtrlWordHandler(rtfParser, "txbxtwalways", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["txbxtwfirst"] = new RtfCtrlWordHandler(rtfParser, "txbxtwfirst", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["txbxtwfirstlast"] = new RtfCtrlWordHandler(rtfParser, "txbxtwfirstlast", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["txbxtwlast"] = new RtfCtrlWordHandler(rtfParser, "txbxtwlast", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["txbxtwno"] = new RtfCtrlWordHandler(rtfParser, "txbxtwno", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["txe"] = new RtfCtrlWordHandler(rtfParser, "txe", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["u"] = new RtfCtrlWordHandler(rtfParser, "u", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["uc"] = new RtfCtrlWordHandler(rtfParser, "uc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["ud"] = new RtfCtrlWordHandler(rtfParser, "ud", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["ul"] = new RtfCtrlWordHandler(rtfParser, "ul", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulc"] = new RtfCtrlWordHandler(rtfParser, "ulc", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["uld"] = new RtfCtrlWordHandler(rtfParser, "uld", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["uldash"] = new RtfCtrlWordHandler(rtfParser, "uldash", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["uldashd"] = new RtfCtrlWordHandler(rtfParser, "uldashd", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["uldashdd"] = new RtfCtrlWordHandler(rtfParser, "uldashdd", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["uldb"] = new RtfCtrlWordHandler(rtfParser, "uldb", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulhair"] = new RtfCtrlWordHandler(rtfParser, "ulhair", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulhwave"] = new RtfCtrlWordHandler(rtfParser, "ulhwave", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulldash"] = new RtfCtrlWordHandler(rtfParser, "ulldash", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulnone"] = new RtfCtrlWordHandler(rtfParser, "ulnone", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ulth"] = new RtfCtrlWordHandler(rtfParser, "ulth", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulthd"] = new RtfCtrlWordHandler(rtfParser, "ulthd", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulthdash"] = new RtfCtrlWordHandler(rtfParser, "ulthdash", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulthdashd"] = new RtfCtrlWordHandler(rtfParser, "ulthdashd", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulthdashdd"] = new RtfCtrlWordHandler(rtfParser, "ulthdashdd", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulthldash"] = new RtfCtrlWordHandler(rtfParser, "ulthldash", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ululdbwave"] = new RtfCtrlWordHandler(rtfParser, "ululdbwave", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["ulw"] = new RtfCtrlWordHandler(rtfParser, "ulw", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["ulwave"] = new RtfCtrlWordHandler(rtfParser, "ulwave", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["up"] = new RtfCtrlWordHandler(rtfParser, "up", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["upr"] = new RtfCtrlWordHandler(rtfParser, "upr", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["urtf"] = new RtfCtrlWordHandler(rtfParser, "urtf", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["useltbaln"] = new RtfCtrlWordHandler(rtfParser, "useltbaln", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["usenormstyforlist"] = new RtfCtrlWordHandler(rtfParser, "usenormstyforlist", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["userprops"] = new RtfCtrlWordHandler(rtfParser, "userprops", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", null); + ctrlWords["usexform"] = new RtfCtrlWordHandler(rtfParser, "usexform", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["utinl"] = new RtfCtrlWordHandler(rtfParser, "utinl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["v"] = new RtfCtrlWordHandler(rtfParser, "v", 0, false, RtfCtrlWordType.TOGGLE, "\\", " ", null); + ctrlWords["validatexml"] = new RtfCtrlWordHandler(rtfParser, "validatexml", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["vern"] = new RtfCtrlWordHandler(rtfParser, "vern", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["version"] = new RtfCtrlWordHandler(rtfParser, "version", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["vertalb"] = new RtfCtrlWordHandler(rtfParser, "vertalb", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["vertalc"] = new RtfCtrlWordHandler(rtfParser, "vertalc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["vertalj"] = new RtfCtrlWordHandler(rtfParser, "vertalj", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["vertalt"] = new RtfCtrlWordHandler(rtfParser, "vertalt", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["vertdoc"] = new RtfCtrlWordHandler(rtfParser, "vertdoc", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["vertsect"] = new RtfCtrlWordHandler(rtfParser, "vertsect", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["viewbksp"] = new RtfCtrlWordHandler(rtfParser, "viewbksp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["viewkind"] = new RtfCtrlWordHandler(rtfParser, "viewkind", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["viewnobound"] = new RtfCtrlWordHandler(rtfParser, "viewnobound", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["viewscale"] = new RtfCtrlWordHandler(rtfParser, "viewscale", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["viewzk"] = new RtfCtrlWordHandler(rtfParser, "viewzk", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["wbitmap"] = new RtfCtrlWordHandler(rtfParser, "wbitmap", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["wbmbitspixel"] = new RtfCtrlWordHandler(rtfParser, "wbmbitspixel", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["wbmplanes"] = new RtfCtrlWordHandler(rtfParser, "wbmplanes", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["wbmwidthbytes"] = new RtfCtrlWordHandler(rtfParser, "wbmwidthbytes", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["webhidden"] = new RtfCtrlWordHandler(rtfParser, "webhidden", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wgrffmtfilter"] = new RtfCtrlWordHandler(rtfParser, "wgrffmtfilter", 0, false, RtfCtrlWordType.VALUE, "\\*\\", " ", null); + ctrlWords["widctlpar"] = new RtfCtrlWordHandler(rtfParser, "widctlpar", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["widowctrl"] = new RtfCtrlWordHandler(rtfParser, "widowctrl", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["windowcaption"] = new RtfCtrlWordHandler(rtfParser, "windowcaption", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["wmetafile"] = new RtfCtrlWordHandler(rtfParser, "wmetafile", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["wpeqn"] = new RtfCtrlWordHandler(rtfParser, "wpeqn", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wpjst"] = new RtfCtrlWordHandler(rtfParser, "wpjst", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wpsp"] = new RtfCtrlWordHandler(rtfParser, "wpsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wptab"] = new RtfCtrlWordHandler(rtfParser, "wptab", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wraparound"] = new RtfCtrlWordHandler(rtfParser, "wraparound", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wrapdefault"] = new RtfCtrlWordHandler(rtfParser, "wrapdefault", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wrapthrough"] = new RtfCtrlWordHandler(rtfParser, "wrapthrough", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wraptight"] = new RtfCtrlWordHandler(rtfParser, "wraptight", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["wraptrsp"] = new RtfCtrlWordHandler(rtfParser, "wraptrsp", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["writereservhash"] = new RtfCtrlWordHandler(rtfParser, "writereservhash", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", null); + ctrlWords["wrppunct"] = new RtfCtrlWordHandler(rtfParser, "wrppunct", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["xe"] = new RtfCtrlWordHandler(rtfParser, "xe", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["xef"] = new RtfCtrlWordHandler(rtfParser, "xef", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["xform"] = new RtfCtrlWordHandler(rtfParser, "xform", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlattr"] = new RtfCtrlWordHandler(rtfParser, "xmlattr", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["xmlattrname"] = new RtfCtrlWordHandler(rtfParser, "xmlattrname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlattrns"] = new RtfCtrlWordHandler(rtfParser, "xmlattrns", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["xmlattrvalue"] = new RtfCtrlWordHandler(rtfParser, "xmlattrvalue", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlclose"] = new RtfCtrlWordHandler(rtfParser, "xmlclose", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlname"] = new RtfCtrlWordHandler(rtfParser, "xmlname", 0, false, RtfCtrlWordType.DESTINATION, "\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlns"] = new RtfCtrlWordHandler(rtfParser, "xmlns", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["xmlnstbl"] = new RtfCtrlWordHandler(rtfParser, "xmlnstbl", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlopen"] = new RtfCtrlWordHandler(rtfParser, "xmlopen", 0, false, RtfCtrlWordType.DESTINATION_EX, "\\*\\", " ", "RtfDestinationDocument"); + ctrlWords["xmlsdttcell"] = new RtfCtrlWordHandler(rtfParser, "xmlsdttcell", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["xmlsdttpara"] = new RtfCtrlWordHandler(rtfParser, "xmlsdttpara", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["xmlsdttregular"] = new RtfCtrlWordHandler(rtfParser, "xmlsdttregular", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["xmlsdttrow"] = new RtfCtrlWordHandler(rtfParser, "xmlsdttrow", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["xmlsdttunknown"] = new RtfCtrlWordHandler(rtfParser, "xmlsdttunknown", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["yr"] = new RtfCtrlWordHandler(rtfParser, "yr", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["yts"] = new RtfCtrlWordHandler(rtfParser, "yts", 0, true, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["yxe"] = new RtfCtrlWordHandler(rtfParser, "yxe", 0, false, RtfCtrlWordType.FLAG, "\\", " ", null); + ctrlWords["zwbo"] = new RtfCtrlWordHandler(rtfParser, "zwbo", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["zwj"] = new RtfCtrlWordHandler(rtfParser, "zwj", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["zwnbo"] = new RtfCtrlWordHandler(rtfParser, "zwnbo", 0, false, RtfCtrlWordType.SYMBOL, "\\", " ", null); + ctrlWords["zwnj"] = new RtfCtrlWordHandler(rtfParser, "zwnj", 0, false, RtfCtrlWordType.VALUE, "\\", " ", null); + ctrlWords["{"] = new RtfCtrlWordHandler(rtfParser, "{", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "{"); + ctrlWords["|"] = new RtfCtrlWordHandler(rtfParser, "|", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "|"); + ctrlWords["}"] = new RtfCtrlWordHandler(rtfParser, "}", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "}"); + ctrlWords["~"] = new RtfCtrlWordHandler(rtfParser, "~", 0, false, RtfCtrlWordType.SYMBOL, "\\", "", "~"); + ctrlWords["unknown"] = new RtfCtrlWordHandler(rtfParser, "unknown", 0,false, RtfCtrlWordType.UNIDENTIFIED, "\\", " ", null); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMgr.cs b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMgr.cs new file mode 100644 index 0000000..7461c9f --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMgr.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections; +using iTextSharp.text.rtf.parser; +/* + * $Id: RtfCtrlWordMgr.cs,v 1.2 2008/05/13 11:25:59 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.ctrlwords { + + /** + * RtfCtrlWordMgr handles the dispatching of control words from + * the table of known control words. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public sealed class RtfCtrlWordMgr { + public static bool debug = false; + public static bool debugFound = false; + public static bool debugNotFound = true; + private PushbackStream reader = null; + private RtfParser rtfParser = null; + private RtfCtrlWordMap ctrlWordMap = null; + + /** The RtfCtrlWordListener. */ + private ArrayList listeners = new ArrayList(); + + // // TIMING DEBUG INFO + // private long endTime = 0; + // private Date endDate = null; + // private long endFree = 0; + // private DecimalFormat df = new DecimalFormat("#,##0"); + // private Date startDate = new Date(); + // private long startTime = System.CurrentTimeMillis(); + // private long startFree = Runtime.GetRuntime().FreeMemory(); + + /** + * Constructor + * @param rtfParser The parser object this manager works with. + * @param reader the PushbackReader from the tokeniser. + */ + public RtfCtrlWordMgr(RtfParser rtfParser, PushbackStream reader) { + this.rtfParser = rtfParser; // set the parser + this.reader = reader; // set the reader value + ctrlWordMap = new RtfCtrlWordMap(rtfParser); + + // // TIMING DEBUG INFO + // endFree = Runtime.GetRuntime().FreeMemory(); + // endTime = System.CurrentTimeMillis(); + // endDate = new Date(); + // Console.Out.WriteLine("RtfCtrlWordMgr start date: " + startDate.ToLocaleString()); + // Console.Out.WriteLine("RtfCtrlWordMgr end date : " + endDate.ToLocaleString()); + // Console.Out.WriteLine(" Elapsed time : " + Long.ToString(endTime - startTime) + " milliseconds."); + // Console.Out.WriteLine("Begin Constructor RtfCtrlWordMgr , free mem is " + df.Format(startFree / 1024) + "k"); + // Console.Out.WriteLine("End Constructor RtfCtrlWordMgr , free mem is " + df.Format(endFree / 1024) + "k"); + // Console.Out.WriteLine("RtfCtrlWordMgr used approximately " + df.Format((startFree - endFree) / 1024) + "k"); + } + + /** + * Internal to control word manager class. + * + * @param ctrlWordData The RtfCtrlWordData object with control word and param + * @param groupLevel The current document group parsing level + * @return errOK if ok, otherwise an error code. + */ + public int HandleKeyword(RtfCtrlWordData ctrlWordData, int groupLevel) { + //TODO: May be used for event handling. + int result = RtfParser.errOK; + + // Call before handler event here + BeforeCtrlWord(ctrlWordData); + + result = DispatchKeyword(ctrlWordData, groupLevel); + + // call after handler event here + AfterCtrlWord(ctrlWordData); + + return result; + } + + /** + * Dispatch the token to the correct control word handling object. + * + * @param ctrlWordData The RtfCtrlWordData object with control word and param + * @param groupLevel The current document group parsing level + * @return errOK if ok, otherwise an error code. + */ + private int DispatchKeyword(RtfCtrlWordData ctrlWordData, int groupLevel) { + int result = RtfParser.errOK; + if (ctrlWordData != null) { + RtfCtrlWordHandler ctrlWord = ctrlWordMap.GetCtrlWordHandler(ctrlWordData.ctrlWord); + if (ctrlWord != null) { + ctrlWord.HandleControlword(ctrlWordData); + if (debug && debugFound) { + Console.Out.WriteLine("Keyword found:" + + " New:" + ctrlWordData.ctrlWord + + " Param:" + ctrlWordData.param + + " bParam=" + ctrlWordData.hasParam.ToString()); + } + } else { + result = RtfParser.errCtrlWordNotFound; + //result = RtfParser2.errAssertion; + if (debug && debugNotFound) { + Console.Out.WriteLine("Keyword unknown:" + + " New:" + ctrlWordData.ctrlWord + + " Param:" + ctrlWordData.param + + " bParam=" + ctrlWordData.hasParam.ToString()); + } + } + } + return result; + } + + + // listener methods + + /** + * Adds a RtfCtrlWordListener to the RtfCtrlWordMgr. + * + * @param listener + * the new RtfCtrlWordListener. + */ + public void AddRtfCtrlWordListener(IRtfCtrlWordListener listener) { + listeners.Add(listener); + } + + /** + * Removes a RtfCtrlWordListener from the RtfCtrlWordMgr. + * + * @param listener + * the RtfCtrlWordListener that has to be removed. + */ + public void RemoveRtfCtrlWordListener(IRtfCtrlWordListener listener) { + listeners.Remove(listener); + } + + private bool BeforeCtrlWord(RtfCtrlWordData ctrlWordData) { + foreach (IRtfCtrlWordListener listener in listeners) { + listener.BeforeCtrlWord(ctrlWordData); + } + return true; + } + + private bool OnCtrlWord(RtfCtrlWordData ctrlWordData) { + foreach (IRtfCtrlWordListener listener in listeners) { + listener.OnCtrlWord(ctrlWordData); + } + return true; + } + + private bool AfterCtrlWord(RtfCtrlWordData ctrlWordData) { + foreach (IRtfCtrlWordListener listener in listeners) { + listener.AfterCtrlWord(ctrlWordData); + } + return true; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordType.cs b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordType.cs new file mode 100644 index 0000000..d78f6d3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordType.cs @@ -0,0 +1,97 @@ +using System; + +/* $Id: RtfCtrlWordType.cs,v 1.2 2008/05/13 11:25:59 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.ctrlwords { + /** + * RtfCtrlWordType indicates the type of control word. + * + * RTF control words are divided up into: + * Destination, Flag, Value, Toggle, Symbol. + * + * Destination: The current destination for values and text to be sent. + * Flag: 0/1 value types. Represents true/false, on/off value types. + * Toggle: Flips a Flag value on/off. + * Value: an Integer value data type. (Exception: Some control words this is a long data value type) + * Symbol: Special RTF characters such as \{, \} and others. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public sealed class RtfCtrlWordType { + /** + * Control word is unidentified. + */ + public const int UNIDENTIFIED = -1; + /** + * Control word is a destination. + */ + public const int DESTINATION = 0; + /** + * Control word is a newer destination. + */ + public const int DESTINATION_EX = 1; + /** + * Control word is a flag. + */ + public const int FLAG = 2; + /** + * Control word is a value. + */ + public const int VALUE = 3; + /** + * Control word is a flag toggle. + */ + public const int TOGGLE = 4; + /** + * Control word is a special symbol. + */ + public const int SYMBOL = 5; + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/IRtfDestinationListener.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/IRtfDestinationListener.cs new file mode 100644 index 0000000..4438dce --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/IRtfDestinationListener.cs @@ -0,0 +1,98 @@ +using System; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: IRtfDestinationListener.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationListener interface for handling events. + * + * @author Howard Shank (hgshank@yahoo.com) + * + * @since 2.0.8 + */ + public interface IRtfDestinationListener : IEventListener { + /** + * + */ + RtfCtrlWordData BeforeCtrlWord(RtfCtrlWordData ctrlWordData); + /** + * + */ + RtfCtrlWordData OnCtrlWord(RtfCtrlWordData ctrlWordData); + /** + * + */ + RtfCtrlWordData AfterCtrlWord(RtfCtrlWordData ctrlWordData); + /** + * + */ + int BeforeCharacter(int ch); + /** + * + */ + int OnCharacter(int ch); + /** + * + */ + int AfterCharacter(int ch); + /** + * + * @return + */ + bool OnOpenGroup(); + /** + * + * @return + */ + bool OnCloseGroup(); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestination.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestination.cs new file mode 100644 index 0000000..305208f --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestination.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestination.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestination is the base class for destinations according + * to the RTF Specification. All destinations must extend from this class. + * + * @author Howard Shank (hgshank@yahoo.com + * + * @since 2.0.8 + */ + public abstract class RtfDestination { + /** Parser object */ + protected RtfParser rtfParser = null; + + /** Is data in destination modified? */ + protected bool modified = false; + + /** The last control word handled by this destination */ + protected RtfCtrlWordData lastCtrlWord = null; + + /** The RtfDestinationListener. */ + private static ArrayList listeners = new ArrayList(); + + /** + * Constructor. + */ + public RtfDestination() { + rtfParser = null; + } + /** + * Constructor + * @param parser RtfParser object. + */ + public RtfDestination(RtfParser parser) { + this.rtfParser = parser; + } + /** + * Set the parser to use with the RtfDestination object. + * + * @param parser The RtfParser object. + */ + public virtual void SetParser(RtfParser parser) { + if (this.rtfParser != null && this.rtfParser.Equals(parser)) return; + this.rtfParser = parser; + } + /** + * Clean up when destination is closed. + * @return true if handled, false if not handled + */ + public abstract bool CloseDestination(); + /** + * Handle a new subgroup contained within this group + * @return true if handled, false if not handled + */ + public abstract bool HandleOpeningSubGroup(); + /** + * Clean up when group is closed. + * @return true if handled, false if not handled + */ + public abstract bool HandleCloseGroup(); + + /** + * Setup when group is opened. + * @return true if handled, false if not handled + */ + public abstract bool HandleOpenGroup(); + /** + * Handle text for this destination + * @return true if handled, false if not handled + */ + public abstract bool HandleCharacter(int ch); + /** + * Handle control word for this destination + * @param ctrlWordData The control word and parameter information object + * @return true if handled, false if not handled + */ + public abstract bool HandleControlWord(RtfCtrlWordData ctrlWordData); + /** + * Method to set this object to the default values. Must be implemented in child class. + */ + public abstract void SetToDefaults(); + + /** + * Method to indicate if data in this destination has changed. + * @return true if modified, false if not modified. + */ + public bool IsModified() { + return modified; + } + + // listener methods + + /** + * Adds a RtfDestinationListener to the RtfDestinationMgr. + * + * @param listener + * the new RtfDestinationListener. + */ + public bool AddListener(IRtfDestinationListener listener) { + listeners.Add(listener); + return true; + } + + /** + * Removes a RtfDestinationListener from the RtfDestinationMgr. + * + * @param listener + * the RtfCtrlWordListener that has to be removed. + */ + public bool RemoveListener(IRtfDestinationListener listener) { + int i = listeners.IndexOf(listener); + if (i >= 0) { + listeners.RemoveAt(i); + return true; + } + return false; + } + + protected RtfCtrlWordData BeforeCtrlWord(RtfCtrlWordData ctrlWordData) { + foreach (IRtfDestinationListener listener in listeners) { + listener.BeforeCtrlWord(ctrlWordData); + } + return null; + } + /** + * + */ + protected RtfCtrlWordData OnCtrlWord(RtfCtrlWordData ctrlWordData){ + foreach (IRtfDestinationListener listener in listeners) { + listener.OnCtrlWord(ctrlWordData); + } + return null; + } + + /** + * + */ + protected RtfCtrlWordData AfterCtrlWord(RtfCtrlWordData ctrlWordData){ + foreach (IRtfDestinationListener listener in listeners) { + listener.AfterCtrlWord(ctrlWordData); + } + return null; + } + + /** + * + */ + protected int BeforeCharacter(int ch){ + foreach (IRtfDestinationListener listener in listeners) { + listener.BeforeCharacter(ch); + } + return 0; + } + + /** + * + */ + protected int OnCharacter(int ch){ + foreach (IRtfDestinationListener listener in listeners) { + listener.OnCharacter(ch); + } + return 0; + } + + /** + * + */ + protected int AfterCharacter(int ch){ + foreach (IRtfDestinationListener listener in listeners) { + listener.AfterCharacter(ch); + } + return 0; + } + + /** + * + * @return + */ + protected bool OnOpenGroup(){ + foreach (IRtfDestinationListener listener in listeners) { + listener.OnOpenGroup(); + } + return true; + } + + /** + * + * @return + */ + protected bool OnCloseGroup(){ + foreach (IRtfDestinationListener listener in listeners) { + listener.OnCloseGroup(); + } + return true; + } + + public virtual int GetNewTokeniserState() { + return RtfParser.TOKENISER_IGNORE_RESULT; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationColorTable.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationColorTable.cs new file mode 100644 index 0000000..e192269 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationColorTable.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +using iTextSharp.text.rtf.parser.enumerations; +/* + * $Id: RtfDestinationColorTable.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationColorTable handles data destined for the color table destination + * + * @author Howard Shank (hgshank@yahoo.com) + * + * @since 2.0.8 + */ + public class RtfDestinationColorTable : RtfDestination { + + /** + * The RtfImportHeader to add color mappings to. + */ + private RtfImportMgr importHeader = null; + /** + * The number of the current color being parsed. + */ + private int colorNr = 0; + /** + * The red component of the current color being parsed. + */ + private int red = -1; + /** + * The green component of the current color being parsed. + */ + private int green = -1; + /** + * The blue component of the current color being parsed. + */ + private int blue = -1; + /* + * Color themes - Introduced Word 2007 + */ + /** + * Specifies the tint when specifying a theme color. + * RTF control word ctint + * + * 0 - 255: 0 = full Tint(white), 255 = no tint. + * Default value: 255 + * + * If tint is specified and is less than 255, cshade must equal 255. + * ctint/cshade are mutually exclusive + * + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#cshade + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#themeColor + */ + private int ctint = 255; + /** + * Specifies the shade when specifying a theme color. + * RTF control word cshade + * + * 0 - 255: 0 = full Shade(black), 255 = no shade. + * Default value: 255 + * + * If shade is specified and is less than 255, ctint must equal 255. + * cshade/ctint are mutually exclusive + * + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#ctint + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#themeColor + */ + private int cshade = 255; + /** + * Specifies the use of a theme color. + * + * @see com.lowagie.text.rtf.parser.enumerations.RtfColorThemes + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#ctint + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#cshade + */ + private int themeColor = RtfColorThemes.THEME_UNDEFINED; + /** + * Color map object for conversions + */ + private Hashtable colorMap = null; + + /** + * Constructor. + */ + public RtfDestinationColorTable() : base(null) { + colorMap = new Hashtable(); + this.colorNr = 0; + } + + /** + * Constructs a new RtfColorTableParser. + * + * @param importHeader The RtfImportHeader to add the color mappings to. + */ + public RtfDestinationColorTable(RtfParser parser) : base(parser) { + colorMap = new Hashtable(); + this.colorNr = 0; + this.importHeader = parser.GetImportManager(); + this.SetToDefaults(); + } + + public override void SetParser(RtfParser parser) { + this.rtfParser = parser; + colorMap = new Hashtable(); + this.colorNr = 0; + this.importHeader = parser.GetImportManager(); + this.SetToDefaults(); + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + return true; + } + + public override bool CloseDestination() { + return true; + } + + public override bool HandleCloseGroup() { + ProcessColor(); + return true; + } + public override bool HandleOpenGroup() { + return true; + } + + public override bool HandleCharacter(int ch) { + // color elements end with a semicolon (;) + if ((char)ch == ';') { + this.ProcessColor(); + } + return true; + } + + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + if (ctrlWordData.ctrlWord.Equals("blue")) this.SetBlue(ctrlWordData.IntValue()); + if (ctrlWordData.ctrlWord.Equals("red")) this.SetRed(ctrlWordData.IntValue()); + if (ctrlWordData.ctrlWord.Equals("green")) this.SetGreen(ctrlWordData.IntValue()); + if (ctrlWordData.ctrlWord.Equals("cshade")) this.SetShade(ctrlWordData.IntValue()); + if (ctrlWordData.ctrlWord.Equals("ctint")) this.SetTint(ctrlWordData.IntValue()); + //if(ctrlWordData.ctrlWord.Equals("cmaindarkone")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("cmainlightone")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("cmaindarktwo")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("cmainlighttwo")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("caccentone")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("caccenttwo")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("caccentthree")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("caccentfour")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("caccentfive")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("caccentsix")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("chyperlink")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("cfollowedhyperlink")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("cbackgroundone")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("ctextone")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("cbacgroundtwo")) this.SetThemeColor(ctrlWordData.ctrlWord); + //if(ctrlWordData.ctrlWord.Equals("ctexttwo")) this.SetThemeColor(ctrlWordData.ctrlWord); + return true; + } + + /** + * Set default values. + */ + public override void SetToDefaults() { + this.red = -1; + this.green = -1; + this.blue = -1; + this.ctint = 255; + this.cshade = 255; + this.themeColor = RtfColorThemes.THEME_UNDEFINED; + // do not reset colorNr + } + /** + * Processes the color triplet parsed from the document. + * Add it to the import mapping so colors can be mapped when encountered + * in the RTF import or conversion. + */ + private void ProcessColor() { + if (red != -1 && green != -1 && blue != -1) { + if (this.rtfParser.IsImport()) { + this.importHeader.ImportColor(this.colorNr.ToString(), new Color(this.red, this.green, this.blue)); + } + + if (this.rtfParser.IsConvert()) { + colorMap[this.colorNr.ToString()] = new Color(this.red, this.green, this.blue); + } + } + this.SetToDefaults(); + this.colorNr++; + } + /** + * Set the red color to value. + * @param value Value to set red to. + */ + private void SetRed(int value) { + if (value >= 0 && value <= 255) { + this.red = value; + } + } + /** + * Set the green color value. + * @param value Value to set green to. + */ + private void SetGreen(int value) { + if (value >= 0 && value <= 255) { + this.green = value; + } + } + /** + * Set the blue color value. + * @param value Value to set blue to. + */ + private void SetBlue(int value) { + if (value >= 0 && value <= 255) { + this.blue = value; + } + } + /** + * Set the tint value + * @param value Value to set the tint to + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#ctint + */ + private void SetTint(int value) { + if (value >= 0 && value <= 255) { + this.ctint = value; + if (value >= 0 && value <255) { + this.cshade = 255; + } + } + } + /** + * Set the shade value + * @param value Value to set the shade to + * @see com.lowagie.text.rtf.parser.destinations.RtfDestinationColorTable#cshade + */ + private void SetShade(int value) { + if (value >= 0 && value <= 255) { + this.cshade = value; + if (value >= 0 && value <255) { + this.ctint = 255; + } + } + } + /** + * Set the theme color value. + * @param value Value to set the theme color to + * @see com.lowagie.text.rtf.parser.enumerations.RtfColorThemes + */ + private void SetThemeColor(int value) { + if (value >= RtfColorThemes.THEME_UNDEFINED && value <= RtfColorThemes.THEME_MAX) { + this.themeColor = value; + } else { + this.themeColor = RtfColorThemes.THEME_UNDEFINED; + } + } + + // conversion functions + /** + * Get the Color object that is mapped to the key. + * @param key The map number. + * *@return Color object from the map. null if key does not exist. + */ + public Color GetColor(String key) { + return (Color)colorMap[key]; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationDocument.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationDocument.cs new file mode 100644 index 0000000..a39f75f --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationDocument.cs @@ -0,0 +1,592 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.direct; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +using iTextSharp.text.rtf.parser.properties; +/* + * $Id: RtfDestinationDocument.cs,v 1.4 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.destinations { + /** + * RtfDestinationDocument handles data destined for the document destination + * + * @author Howard Shank (hgshank@yahoo.com) + * + */ + public sealed class RtfDestinationDocument : RtfDestination, IRtfPropertyListener { + + + /** + * The RtfDocument object. + * + * @see com.lowagie.text.rtf.document.RtfDocument + */ + private RtfDocument rtfDoc = null; + + /** + * The iText Document object. + * + * @see com.lowagie.text.Document + */ + private Document doc = null; + + private StringBuilder buffer = null; + /** + * Indicates the parser action. Import or Conversion. + * + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_UNIDENTIFIED + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_CONVERT + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_IMPORT_FRAGMENT + * @see com.lowagie.text.rtf.direct.RtfParser#TYPE_IMPORT_FULL + */ + private int conversionType = 0; + + + /** + * Indicates the current table level being processed + */ + private int tableLevel = 0; + + private static ArrayList IMPORT_IGNORED_CTRLWORDS = new ArrayList(new string[]{ + "rtf", + "ansicpg", + "deff", + "ansi", + "mac", + "pca", + "pc", + "stshfdbch", + "stshfloch", + "stshfhich", + "stshfbi", + "deflang", + "deflangfe", + "adeflang", + "adeflangfe" + } + ); + private static ArrayList CONVERT_IGNORED_CTRLWORDS = new ArrayList(new string[]{"rtf"}); + + private Paragraph iTextParagraph = null; + + public RtfDestinationDocument() : base(null) { + } + /** + * Constructs a new RtfDestinationDocument using + * the parameters to initialize the object. + * @param rtfDoc The RtfDocument this works with. + * @param doc The iText Document this works with. + * @param type The type of conversion being done. + */ + public RtfDestinationDocument(RtfParser parser) : base (parser){ + this.rtfDoc = parser.GetRtfDocument(); + this.doc = parser.GetDocument(); + this.conversionType = parser.GetConversionType(); + SetToDefaults(); + if (this.rtfParser.IsConvert()) { + this.rtfParser.GetState().properties.AddRtfPropertyListener(this); + } + } + + public override void SetParser(RtfParser parser) { + this.rtfParser = parser; + this.rtfDoc = parser.GetRtfDocument(); + this.doc = parser.GetDocument(); + this.conversionType = parser.GetConversionType(); + SetToDefaults(); + if (this.rtfParser.IsConvert()) { + this.rtfParser.GetState().properties.AddRtfPropertyListener(this); + } + } + + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + */ + public override bool CloseDestination() { + if (this.rtfParser.IsImport()) { + if (this.buffer.Length>0) { + WriteBuffer(); + } + } + + this.rtfParser.GetState().properties.RemoveRtfPropertyListener(this); + + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + */ + public override bool HandleOpenGroup() { + this.OnOpenGroup(); // event handler + + if (this.rtfParser.IsImport()) { + } + if (this.rtfParser.IsConvert()) { + if (this.iTextParagraph == null) this.iTextParagraph = new Paragraph(); + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + if (this.rtfParser.IsImport()) { + if (this.buffer.Length>0) { + WriteBuffer(); + } + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + */ + public override bool HandleCloseGroup() { + this.OnCloseGroup(); // event handler + + if (this.rtfParser.IsImport()) { + if (this.buffer.Length>0) { + WriteBuffer(); + } + WriteText("}"); + } + if (this.rtfParser.IsConvert()) { + if (this.buffer.Length > 0 && this.iTextParagraph == null) { + this.iTextParagraph = new Paragraph(); + } + if (this.buffer.Length > 0 ) { + Chunk chunk = new Chunk(); + chunk.Append(this.buffer.ToString()); + this.iTextParagraph.Add(chunk); + } + if (this.iTextParagraph != null) { + AddParagraphToDocument(); + } + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(int) + */ + public override bool HandleCharacter(int ch) { + bool result = true; + this.OnCharacter(ch); // event handler + + if (this.rtfParser.IsImport()) { + if (buffer.Length > 254) { + this.WriteBuffer(); + } + buffer.Append((char)ch); + } + if (this.rtfParser.IsConvert()) { + buffer.Append((char)ch); + } + return result; + } + + + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + bool result = false; + this.OnCtrlWord(ctrlWordData); // event handler + + if (this.rtfParser.IsImport()) { + // map font information + if (ctrlWordData.ctrlWord.Equals("f")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapFontNr(ctrlWordData.param);} + + // map color information + //colors + if (ctrlWordData.ctrlWord.Equals("cb")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + if (ctrlWordData.ctrlWord.Equals("cf")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + //cells + if (ctrlWordData.ctrlWord.Equals("clcbpat")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + if (ctrlWordData.ctrlWord.Equals("clcbpatraw")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + if (ctrlWordData.ctrlWord.Equals("clcfpat")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + if (ctrlWordData.ctrlWord.Equals("clcfpatraw")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + //table rows + if (ctrlWordData.ctrlWord.Equals("trcfpat")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + if (ctrlWordData.ctrlWord.Equals("trcbpat")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + //paragraph border + if (ctrlWordData.ctrlWord.Equals("brdrcf")) { ctrlWordData.param = this.rtfParser.GetImportManager().MapColorNr(ctrlWordData.param);} + } + + + + if (this.rtfParser.IsConvert()) { + if (ctrlWordData.ctrlWord.Equals("par")) { AddParagraphToDocument(); } + // Set Font + if (ctrlWordData.ctrlWord.Equals("f")) {} + + // color information + //colors + if (ctrlWordData.ctrlWord.Equals("cb")) {} + if (ctrlWordData.ctrlWord.Equals("cf")) {} + //cells + if (ctrlWordData.ctrlWord.Equals("clcbpat")) {} + if (ctrlWordData.ctrlWord.Equals("clcbpatraw")) {} + if (ctrlWordData.ctrlWord.Equals("clcfpat")) {} + if (ctrlWordData.ctrlWord.Equals("clcfpatraw")) {} + //table rows + if (ctrlWordData.ctrlWord.Equals("trcfpat")) {} + if (ctrlWordData.ctrlWord.Equals("trcbpat")) {} + //paragraph border + if (ctrlWordData.ctrlWord.Equals("brdrcf")) {} + + /* TABLES */ + if (ctrlWordData.ctrlWord.Equals("trowd")) /*Beginning of row*/ { tableLevel++;} + if (ctrlWordData.ctrlWord.Equals("cell")) /*End of Cell Denotes the end of a table cell*/ { + // String ctl = ctrlWordData.ctrlWord; + // System.out.Print("cell found"); + } + if (ctrlWordData.ctrlWord.Equals("row")) /*End of row*/ { tableLevel++;} + if (ctrlWordData.ctrlWord.Equals("lastrow")) /*Last row of the table*/ {} + if (ctrlWordData.ctrlWord.Equals("row")) /*End of row*/ { tableLevel++;} + if (ctrlWordData.ctrlWord.Equals("irow")) /*param is the row index of this row.*/ {} + if (ctrlWordData.ctrlWord.Equals("irowband")) /*param is the row index of the row, adjusted to account for header rows. A header row has a value of -1.*/ {} + if (ctrlWordData.ctrlWord.Equals("tcelld")) /*Sets table cell defaults*/ {} + if (ctrlWordData.ctrlWord.Equals("nestcell")) /*Denotes the end of a nested cell.*/ {} + if (ctrlWordData.ctrlWord.Equals("nestrow")) /*Denotes the end of a nested row*/ {} + if (ctrlWordData.ctrlWord.Equals("nesttableprops")) /*Defines the properties of a nested table. This is a destination control word*/ {} + if (ctrlWordData.ctrlWord.Equals("nonesttables")) /*Contains text for readers that do not understand nested tables. This destination should be ignored by readers that support nested tables.*/ {} + if (ctrlWordData.ctrlWord.Equals("trgaph")) /*Half the space between the cells of a table row in twips.*/ {} + if (ctrlWordData.ctrlWord.Equals("cellx")) /*param Defines the right boundary of a table cell, including its half of the space between cells.*/ {} + if (ctrlWordData.ctrlWord.Equals("clmgf")) /*The first cell in a range of table cells to be merged.*/ {} + if (ctrlWordData.ctrlWord.Equals("clmrg")) /*Contents of the table cell are merged with those of the preceding cell*/ {} + if (ctrlWordData.ctrlWord.Equals("clvmgf")) /*The first cell in a range of table cells to be vertically merged.*/ {} + if (ctrlWordData.ctrlWord.Equals("clvmrg")) /*Contents of the table cell are vertically merged with those of the preceding cell*/ {} + /* TABLE: table row revision tracking */ + if (ctrlWordData.ctrlWord.Equals("trauth")) /*With revision tracking enabled, this control word identifies the author of changes to a table row's properties. N refers to a value in the revision table*/ {} + if (ctrlWordData.ctrlWord.Equals("trdate")) /*With revision tracking enabled, this control word identifies the date of a revision*/ {} + /* TABLE: Autoformatting flags */ + if (ctrlWordData.ctrlWord.Equals("tbllkborder")) /*Flag sets table autoformat to format borders*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllkshading")) /*Flag sets table autoformat to affect shading.*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllkfont")) /*Flag sets table autoformat to affect font*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllkcolor")) /*Flag sets table autoformat to affect color*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllkbestfit")) /*Flag sets table autoformat to apply best fit*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllkhdrrows")) /*Flag sets table autoformat to format the first (header) row*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllklastrow")) /*Flag sets table autoformat to format the last row.*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllkhdrcols")) /*Flag sets table autoformat to format the first (header) column*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllklastcol")) /*Flag sets table autoformat to format the last column*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllknorowband")) /*Specifies row banding conditional formatting shall not be applied*/ {} + if (ctrlWordData.ctrlWord.Equals("tbllknocolband")) /*Specifies column banding conditional formatting shall not be applied.*/ {} + /* TABLE: Row Formatting */ + if (ctrlWordData.ctrlWord.Equals("taprtl")) /*Table direction is right to left*/ {} + if (ctrlWordData.ctrlWord.Equals("trautofit")) /*param = AutoFit: + 0 No AutoFit (default). + 1 AutoFit is on for the row. Overridden by \clwWidthN and \trwWidthN in any table row. + */ {} + if (ctrlWordData.ctrlWord.Equals("trhdr")) /*Table row header. This row should appear at the top of every page on which the current table appears*/ {} + if (ctrlWordData.ctrlWord.Equals("trkeep")) /*Keep table row together. This row cannot be split by a page break. This property is assumed to be off unless the control word is present*/ {} + if (ctrlWordData.ctrlWord.Equals("trkeepfollow")) /*Keep row in the same page as the following row.*/ {} + if (ctrlWordData.ctrlWord.Equals("trleft")) /*Position in twips of the leftmost edge of the table with respect to the left edge of its column.*/ {} + if (ctrlWordData.ctrlWord.Equals("trqc")) /*Centers a table row with respect to its containing column.*/ {} + if (ctrlWordData.ctrlWord.Equals("trql")) /*Left-justifies a table row with respect to its containing column.*/ {} + if (ctrlWordData.ctrlWord.Equals("trqr")) /*Right-justifies a table row with respect to its containing column*/ {} + if (ctrlWordData.ctrlWord.Equals("trrh")) /*Height of a table row in twips. When 0, the height is sufficient for all the text in the line; when positive, the height is guaranteed to be at least the specified height; when negative, the absolute value of the height is used, regardless of the height of the text in the line*/ {} + if (ctrlWordData.ctrlWord.Equals("trpaddb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddt")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddfb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddfl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddfr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpaddft")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdt")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdfl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdft")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdfb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trspdfr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trwWidth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trftsWidth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trwWidthB")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trftsWidthB")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trftsWidthB")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trwWidthA")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trftsWidthA")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tblind")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tblindtype")) /* */ {} + /*TABLE: Row shading and Background Colors*/ + if (ctrlWordData.ctrlWord.Equals("trcbpat")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trcfpat")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trpat")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trshdng")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgbdiag")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgcross")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdcross")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdkbdiag")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdkcross")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdkdcross")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdkfdiag")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdkhor")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgdkvert")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgfdiag")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbghoriz")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbgvert")) /* */ {} + /* TABLE: Cell Formatting*/ + if (ctrlWordData.ctrlWord.Equals("clFitText")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clNoWrap")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadt")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadfl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadft")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadfb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clpadfr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clwWidth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clftsWidth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clhidemark")) /* */ {} + /* TABLE: Compared Table Cells */ + if (ctrlWordData.ctrlWord.Equals("clins")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("cldel")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clmrgd")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clmrgdr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clsplit")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clsplitr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clinsauth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clinsdttm")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("cldelauth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("cldeldttm")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clmrgdauth")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clmrgddttm")) /* */ {} + /*TABLE: Position Wrapped Tables (The following properties must be the same for all rows in the table.)*/ + if (ctrlWordData.ctrlWord.Equals("tdfrmtxtLeft")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tdfrmtxtRight")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tdfrmtxtTop")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tdfrmtxtBottom")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tabsnoovrlp")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tphcol")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tphmrg")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tphpg")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposnegx")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposnegy")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposx")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposxc")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposxi")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposxl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposxo")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposxr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposy")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposyb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposyc")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposyil")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposyin")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposyout")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tposyt")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tpvmrg")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tpvpara")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("tpvpg")) /* */ {} + /* TABLE: Bidirectional Controls */ + if (ctrlWordData.ctrlWord.Equals("rtlrow")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("ltrrow")) /* */ {} + /* TABLE: Row Borders */ + if (ctrlWordData.ctrlWord.Equals("trbrdrt")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbrdrl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbrdrb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbrdrr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbrdrh")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("trbrdrv")) /* */ {} + /* TABLE: Cell Borders */ + if (ctrlWordData.ctrlWord.Equals("brdrnil")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clbrdrb")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clbrdrt")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clbrdrl")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("clbrdrr")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("cldglu")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("cldgll")) /* */ {} + if (ctrlWordData.ctrlWord.Equals("")) /* */ {} + } + if (ctrlWordData.ctrlWordType == RtfCtrlWordType.TOGGLE) { + this.rtfParser.GetState().properties.ToggleProperty(ctrlWordData);//ctrlWordData.specialHandler); + } + + if (ctrlWordData.ctrlWordType == RtfCtrlWordType.FLAG || + ctrlWordData.ctrlWordType == RtfCtrlWordType.VALUE) { + this.rtfParser.GetState().properties.SetProperty(ctrlWordData);//ctrlWordData.specialHandler, ctrlWordData.param); + } + + switch (conversionType) { + case RtfParser.TYPE_IMPORT_FULL: + if (!IMPORT_IGNORED_CTRLWORDS.Contains(ctrlWordData.ctrlWord)) { + WriteBuffer(); + WriteText(ctrlWordData.ToString()); + } + result = true; + break; + case RtfParser.TYPE_IMPORT_FRAGMENT: + if (!IMPORT_IGNORED_CTRLWORDS.Contains(ctrlWordData.ctrlWord)) { + WriteBuffer(); + WriteText(ctrlWordData.ToString()); + } + result = true; + break; + case RtfParser.TYPE_CONVERT: + if (IMPORT_IGNORED_CTRLWORDS.Contains(ctrlWordData.ctrlWord) == false) { + } + result = true; + break; + default: // error because is should be an import or convert + result = false; + break; + } + + + + + return result; + } + /** + * Write the accumulated buffer to the destination. + * Used for direct content + */ + private void WriteBuffer() { + WriteText(this.buffer.ToString()); + SetToDefaults(); + } + /** + * Write the string value to the destiation. + * Used for direct content + * @param value + */ + private void WriteText(String value) { + if (this.rtfParser.IsNewGroup()) { + this.rtfDoc.Add(new RtfDirectContent("{")); + this.rtfParser.SetNewGroup(false); + } + if (value.Length > 0) { + this.rtfDoc.Add(new RtfDirectContent(value)); + } + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#setDefaults() + */ + public override void SetToDefaults() { + this.buffer = new StringBuilder(); + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.properties.RtfPropertyListener#afterChange(java.lang.String) + */ + public void AfterPropertyChange(String propertyName) { + if (propertyName.StartsWith(RtfProperty.CHARACTER)) { + } else { + if (propertyName.StartsWith(RtfProperty.PARAGRAPH)) { + } else { + if (propertyName.StartsWith(RtfProperty.SECTION)) { + } else { + if (propertyName.StartsWith(RtfProperty.DOCUMENT)) { + + } + } + } + } + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.properties.RtfPropertyListener#beforeChange(java.lang.String) + */ + public void BeforePropertyChange(String propertyName) { + // do we have any text to do anything with? + // if not, then just return without action. + if (this.buffer.Length == 0) return; + + if (propertyName.StartsWith(RtfProperty.CHARACTER)) { + // this is a character change, + // add a new chunck to the current paragraph using current character settings. + Chunk chunk = new Chunk(); + chunk.Append(this.buffer.ToString()); + this.buffer = new StringBuilder(255); + Hashtable charProperties = this.rtfParser.GetState().properties.GetProperties(RtfProperty.CHARACTER); + String defFont = (String)charProperties[RtfProperty.CHARACTER_FONT]; + if (defFont == null) defFont = "0"; + RtfDestinationFontTable fontTable = (RtfDestinationFontTable)this.rtfParser.GetDestination("fonttbl"); + Font currFont = fontTable.GetFont(defFont); + int fs = Font.NORMAL; + if (charProperties.ContainsKey(RtfProperty.CHARACTER_BOLD)) fs |= Font.BOLD; + if (charProperties.ContainsKey(RtfProperty.CHARACTER_ITALIC)) fs |= Font.ITALIC; + if (charProperties.ContainsKey(RtfProperty.CHARACTER_UNDERLINE)) fs |= Font.UNDERLINE; + Font useFont = FontFactory.GetFont(currFont.Familyname, 12, fs, new Color(0,0,0)); + + + chunk.Font = useFont; + if (iTextParagraph == null) this.iTextParagraph = new Paragraph(); + this.iTextParagraph.Add(chunk); + + } else { + if (propertyName.StartsWith(RtfProperty.PARAGRAPH)) { + // this is a paragraph change. what do we do? + } else { + if (propertyName.StartsWith(RtfProperty.SECTION)) { + + } else { + if (propertyName.StartsWith(RtfProperty.DOCUMENT)) { + + } + } + } + } + } + + private void AddParagraphToDocument() { + if (this.iTextParagraph != null) { + try { + this.rtfParser.GetDocument().Add(this.iTextParagraph); + } catch { + } + this.iTextParagraph = null; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationFontTable.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationFontTable.cs new file mode 100644 index 0000000..0e563e0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationFontTable.cs @@ -0,0 +1,600 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text; +using iTextSharp.text.rtf.direct; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationFontTable.cs,v 1.4 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationFontTable handles data destined for the font table destination + * + * @author Howard Shank (hgshank@yahoo.com) + * + * @since 2.0.8 + */ + public sealed class RtfDestinationFontTable : RtfDestination { + /** + * The RtfImportHeader to add font mappings to. + */ + private RtfImportMgr importHeader = null; + /** + * The theme (Office 2007) + */ + private String themeFont = ""; + /** + * The number of the font being parsed. + */ + private String fontNr = ""; + /** + * The family of the font being parsed. + */ + private String fontFamily = ""; + /** + * The \charset value + */ + private String charset = ""; + private const String CHARSET_DEFAULT = "0"; + /** + * The \fprq + */ + private int fprq = 0; + /** + * The \*\panose font matching value if primary font is not available. + */ + private String panose = ""; + /** + * The \*\fname + */ + //private String nontaggedname = ""; + /** + * The name of the font being parsed. + */ + private String fontName = ""; + /** + * The \falt alternate font if primary font is not available. + */ + private String falt = ""; + /** + * The \falt alternate font if primary font is not available. + */ + //private String fontemb = ""; + /** + * The \falt alternate font if primary font is not available. + */ + //private String fontType = ""; + /** + * The \falt alternate font if primary font is not available. + */ + //private String fontFile = ""; + /** + * The \falt alternate font if primary font is not available. + */ + //private String fontFileCpg = ""; + /** + * The \fbias value + */ + private int fbias = 0; + /** + * The \cpg value + */ + private String cpg = ""; + /** + * The \fnil, \fttruetype value + */ + private String trueType = ""; + + /** + * state flag to handle different parsing of a font element + */ + private int state = 0; + /* state values */ + /** Normal */ + private const int SETTING_NORMAL = 0; + /** \falt */ + private const int SETTING_ALTERNATE = 1; + /** \fname */ + private const int SETTING_FONTNAME = 2; + /** \panose */ + private const int SETTING_PANOSE = 3; + /** \fontemb */ + private const int SETTING_FONT_EMBED = 4; + /** \ffile */ + private const int SETTING_FONT_FILE = 5; + + /** + * Convert font mapping to FontFactory font objects. + */ + private Hashtable fontMap = null; + + /** + * Constructor + */ + public RtfDestinationFontTable() : base(null) { + } + /** + * Constructs a new RtfFontTableParser. + * + * @param importHeader The RtfImportHeader to add font mappings to. + * + * @since 2.0.8 + */ + public RtfDestinationFontTable(RtfParser parser) : base(parser) { + this.Init(true); + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#setParser(com.lowagie.text.rtf.parser.RtfParser) + * + * @since 2.0.8 + */ + public override void SetParser(RtfParser parser) { + if (this.rtfParser != null && this.rtfParser.Equals(parser)) return; + this.rtfParser = parser; + this.Init(true); + } + /** + * Initialize the object. + * + * @param importFonts true to import the fonts into the FontFactory, false do not load fonts + * + * @since 2.0.8 + */ + private void Init(bool importFonts) { + fontMap = new Hashtable(); + if (this.rtfParser != null) { + this.importHeader = this.rtfParser.GetImportManager(); + } + this.SetToDefaults(); + if (importFonts) { + ImportSystemFonts(); + } + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + * + * @since 2.0.8 + */ + public override bool HandleOpeningSubGroup() { + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + * + * @since 2.0.8 + */ + public override bool CloseDestination() { + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + * + * @since 2.0.8 + */ + public override bool HandleCloseGroup() { + if (this.state == SETTING_NORMAL) { + ProcessFont(); + } + this.state = SETTING_NORMAL; + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + * + * @since 2.0.8 + */ + public override bool HandleOpenGroup() { + + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(char[]) + * + * @since 2.0.8 + */ + public override bool HandleCharacter(int ch) { + switch (this.state) { + case SETTING_NORMAL: + this.fontName += (char)ch; + break; + case SETTING_ALTERNATE: + this.falt += (char)ch; + break; + case SETTING_PANOSE: + this.panose += (char)ch; + break; + case SETTING_FONT_EMBED: + break; + case SETTING_FONT_FILE: + break; + case SETTING_FONTNAME: + break; + + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleControlWord(com.lowagie.text.rtf.parser.ctrlwords.RtfCtrlWordData) + * + * @since 2.0.8 + */ + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + bool result = true; + // just let fonttbl fall through and set last ctrl word object. + + if (ctrlWordData.ctrlWord.Equals("f")) { this.SetFontNumber(ctrlWordData.param); result=true;} + if (ctrlWordData.ctrlWord.Equals("fcharset")) { this.SetCharset(ctrlWordData.param); result=true; } + + // font families + if (ctrlWordData.ctrlWord.Equals("fnil")) { this.SetFontFamily("roman"); result=true; } + if (ctrlWordData.ctrlWord.Equals("froman")) { this.SetFontFamily("roman"); result=true; } + if (ctrlWordData.ctrlWord.Equals("fswiss")) { this.SetFontFamily("swiss"); result=true; } + if (ctrlWordData.ctrlWord.Equals("fmodern")) { this.SetFontFamily("modern"); result=true; } + if (ctrlWordData.ctrlWord.Equals("fscript")) { this.SetFontFamily("script"); result=true; } + if (ctrlWordData.ctrlWord.Equals("fdecor")) { this.SetFontFamily("decor"); result=true; } + if (ctrlWordData.ctrlWord.Equals("ftech")) { this.SetFontFamily("tech"); result=true; } + if (ctrlWordData.ctrlWord.Equals("fbidi")) { this.SetFontFamily("bidi"); result=true; } + // pitch + if (ctrlWordData.ctrlWord.Equals("fprq")) { this.SetPitch(ctrlWordData.param); result=true; } + // bias + if (ctrlWordData.ctrlWord.Equals("fbias")) { this.SetBias(ctrlWordData.param); result=true; } + // theme font information + if (ctrlWordData.ctrlWord.Equals("flomajor")) { this.SetThemeFont("flomajor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fhimajor")) { this.SetThemeFont("fhimajor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fdbmajor")) { this.SetThemeFont("fdbmajor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fbimajor")) { this.SetThemeFont("fbimajor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("flominor")) { this.SetThemeFont("flominor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fhiminor")) { this.SetThemeFont("fhiminor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fdbminor")) { this.SetThemeFont("fdbminor"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fbiminor")) { this.SetThemeFont("fbiminor"); result= true; } + + // panose + if (ctrlWordData.ctrlWord.Equals("panose")) {state = SETTING_PANOSE; result = true; } + + // \*\fname + // #PCDATA + if (ctrlWordData.ctrlWord.Equals("fname")) {state = SETTING_FONTNAME; result = true; } + + // \*\falt + if (ctrlWordData.ctrlWord.Equals("falt")) { state = SETTING_ALTERNATE; result = true; } + + // \*\fontemb + if (ctrlWordData.ctrlWord.Equals("fontemb")) { state = SETTING_FONT_EMBED; result = true; } + + // font type + if (ctrlWordData.ctrlWord.Equals("ftnil")) { this.SetTrueType("ftnil"); result= true; } + if (ctrlWordData.ctrlWord.Equals("fttruetype")) { this.SetTrueType("fttruetype"); result= true; } + + // \*\fontfile + if (ctrlWordData.ctrlWord.Equals("fontemb")) { state = SETTING_FONT_FILE; result = true; } + + // codepage + if (ctrlWordData.ctrlWord.Equals("cpg")) { this.SetCodePage(ctrlWordData.param); result= true; } + + this.lastCtrlWord = ctrlWordData; + return result; + } + /** + * Set the code page + * @param value The code page value + * + * @since 2.0.8 + */ + public void SetCodePage(String value) { + this.cpg = value; + } + /** + * Set the TrueTtype type + * @param value The type + * + * @since 2.0.8 + */ + public void SetTrueType(String value) { + this.trueType = value; + } + /** + * Set the font pitch + * @param value Pitch value + * + * @since 2.0.8 + */ + public void SetPitch(String value) { + this.fprq = int.Parse(value); + } + /** + * Set the font bias + * @param value Bias value + * + * @since 2.0.8 + */ + public void SetBias(String value) { + this.fbias = int.Parse(value); + } + /** + * Set the font theme + * + * @param themeFont Theme value + * + * @since 2.0.8 + */ + public void SetThemeFont(String themeFont) { + this.themeFont = themeFont; + } + /** + * Set the font name to the parsed value. + * + * @param fontName The font name. + * + * @since 2.0.8 + */ + public void SetFontName(String fontName) { + this.fontName = fontName; + } + /** + * Set the font family to the parsed value. + * + * @param fontFamily The font family. + * + * @since 2.0.8 + */ + public void SetFontFamily(String fontFamily) { + this.fontFamily = fontFamily; + } + /** + * Set the font number to the parsed value. + * This is used for mapping fonts to the new font numbers + * + * @param fontNr The font number. + * + * @since 2.0.8 + */ + public void SetFontNumber(String fontNr) { + this.fontNr = fontNr; + } + /** + * Set the alternate font name. + * + * @param fontAlternate The falt font value + * + * @since 2.0.8 + */ + public void SetFontAlternate(String fontAlternate) { + this.falt = fontAlternate; + } + /** + * Set the character-set to the parsed value. + * + * @param charset The charset value + * + * @since 2.0.8 + */ + public void SetCharset(String charset) { + if (charset.Length == 0) { + charset = "0"; + } + this.charset = charset; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#setDefaults() + * + * @since 2.0.8 + */ + public override void SetToDefaults() { + this.themeFont = ""; + this.fontNr = ""; + this.fontName = ""; + this.fontFamily = ""; + + this.charset = ""; + this.fprq = 0; + this.panose = ""; + //this.nontaggedname = ""; + this.falt = ""; + //this.fontemb = ""; + //this.fontType = ""; + //this.fontFile = ""; + //this.fontFileCpg = ""; + this.fbias = 0; + this.cpg = ""; + this.trueType = ""; + this.state = SETTING_NORMAL; + } + /** + * Process the font information that was parsed from the input. + * + * @since 2.0.8 + */ + private void ProcessFont() { + this.fontName = this.fontName.Trim(); + if (fontName.Length == 0) return; + if (fontNr.Length == 0) return; + + if (fontName.Length>0 && fontName.IndexOf(';') >= 0) { + fontName = fontName.Substring(0,fontName.IndexOf(';')); + } + + if (this.rtfParser.IsImport()) { + //TODO: If primary font fails, use the alternate + //TODO: Problem: RtfFont defaults family to \froman and doesn't allow any other family. + // if you set the family, it changes the font name and not the family in the Font.java class. + + // if (this.fontFamily.Length() > 0) { + // if (this.importHeader.ImportFont(this.fontNr, this.fontName, this.fontFamily, Integer.ParseInt(this.charset)) == false) { + // if (this.falt.Length() > 0) { + // this.importHeader.ImportFont(this.fontNr, this.falt, this.fontFamily, Integer.ParseInt(this.charset)); + // } + // } + // } else { + if (!this.importHeader.ImportFont(this.fontNr, this.fontName, int.Parse(this.charset==""?CHARSET_DEFAULT:this.charset))) { + if (this.falt.Length > 0) { + this.importHeader.ImportFont(this.fontNr, this.falt, int.Parse(this.charset==""?CHARSET_DEFAULT:this.charset)); + } + } + // } + } + if (this.rtfParser.IsConvert()) { + // This could probably be written as a better font matching function + + String fName = this.fontName; // work variable for trimming name if needed. + Font f1 = Createfont(fName); + if (f1.BaseFont == null && this.falt.Length>0) + f1 = Createfont(this.falt); + + if (f1.BaseFont == null) { + // Did not find a font, let's try a substring of the first name. + if (FontFactory.COURIER.IndexOf(fName) > -1 ) { + f1 = FontFactory.GetFont(FontFactory.COURIER); + } else if (FontFactory.HELVETICA.IndexOf(fName) > -1 ) { + f1 = FontFactory.GetFont(FontFactory.HELVETICA); + } else if (FontFactory.TIMES.IndexOf(fName) > -1 ) { + f1 = FontFactory.GetFont(FontFactory.TIMES); + } else if (FontFactory.SYMBOL.IndexOf(fName) > -1 ) { + f1 = FontFactory.GetFont(FontFactory.SYMBOL); + } else if (FontFactory.ZAPFDINGBATS.IndexOf(fName) > -1 ) { + f1 = FontFactory.GetFont(FontFactory.ZAPFDINGBATS); + } else { + // we did not find a matching font in any form. + // default to HELVETICA for now. + f1 = FontFactory.GetFont(FontFactory.HELVETICA); + } + } + fontMap[this.fontNr] = f1; + //System.out.Println(f1.GetFamilyname()); + } + this.SetToDefaults(); + } + /** + * Create a font via the FontFactory + * + * @param fontName The font name to create + * @return The created Font object + * + * @since 2.0.8 + */ + private Font Createfont(String fontName) { + Font f1 = null; + int pos=-1; + do { + f1 = FontFactory.GetFont(fontName); + + if (f1.BaseFont != null) break; // found a font, exit the do/while + + pos = fontName.LastIndexOf(' '); // find the last space + if (pos>0) { + fontName = fontName.Substring(0, pos ); // truncate it to the last space + } + } while (pos>0); + return f1; + } + /** + * Get a Font object from the font map object + * + * @param key The font number to get + * @return The mapped Font object. + * + * @since 2.0.8 + */ + public Font GetFont(String key) { + return (Font) fontMap[key]; + } + /** + * Load system fonts into the static FontFactory object + * + * @since 2.0.8 + */ + private void ImportSystemFonts() { + FontFactory.RegisterDirectories(); + } + + /** + * Utility method to load the environment variables. + * + * @return Properties object with environment variable information + * @throws Throwable + * + * @since 2.0.8 + */ +// private Properties GetEnvironmentVariables() { +// Properties environmentVariables = new Properties(); +// String operatingSystem = System.GetProperty("os.name").ToLowerCase(); +// Runtime runtime = Runtime.GetRuntime(); +// Process process = null; +// if (operatingSystem.IndexOf("windows 95") > -1 +// || operatingSystem.IndexOf("windows 98") > -1 +// || operatingSystem.IndexOf("me") > -1) { +// process = runtime.Exec("command.com /c set"); +// } else if ((operatingSystem.IndexOf("nt") > -1) +// || (operatingSystem.IndexOf("windows 2000") > -1) +// || (operatingSystem.IndexOf("windows xp") > -1) +// || (operatingSystem.IndexOf("windows 2003") > -1)) { +// process = runtime.Exec("cmd.exe /c set"); +// } else { +// process = runtime.Exec("env"); +// } +// BufferedReader environmentStream = new BufferedReader(new InputStreamReader(process.GetInputStream())); +// String inputLine = ""; +// int idx = -1; +// while ((inputLine = environmentStream.ReadLine()) != null) { +// idx = inputLine.IndexOf('='); +// environmentVariables.SetProperty(inputLine.Substring(0, idx), +// inputLine.Substring(idx + 1)); +// } +// return environmentVariables; +// } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationInfo.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationInfo.cs new file mode 100644 index 0000000..ce5de0c --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationInfo.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationInfo.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationInfo handles data destined for the info destination + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfDestinationInfo : RtfDestination { + private String elementName = ""; + private String text = ""; + + + public RtfDestinationInfo() : base(null) { + } + /** + * Constructs a new RtfDestinationInfo. + * + * @param parser The RtfParser object. + */ + public RtfDestinationInfo(RtfParser parser, String elementname) : base(parser) { + SetToDefaults(); + this.elementName = elementname; + } + public override void SetParser(RtfParser parser) { + this.rtfParser = parser; + this.SetToDefaults(); + } + public void SetElementName(String value) { + this.elementName = value; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + */ + public override bool CloseDestination() { + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + */ + public override bool HandleCloseGroup() { + if (this.text.Length > 0) { + Document doc = this.rtfParser.GetDocument(); + if (doc != null) { + if (this.elementName.Equals("author")){ + doc.AddAuthor(this.text); + } + if (this.elementName.Equals("title")){ + doc.AddTitle(this.text); + } + if (this.elementName.Equals("subject")){ + doc.AddSubject(this.text); + } + } else { + RtfDocument rtfDoc = this.rtfParser.GetRtfDocument(); + if (rtfDoc != null) { + if (this.elementName.Equals("author")){ + Meta meta = new Meta(this.elementName, this.text); + RtfInfoElement elem = new RtfInfoElement(rtfDoc, meta); + rtfDoc.GetDocumentHeader().AddInfoElement(elem); + } + if (this.elementName.Equals("title")){ + Meta meta = new Meta(this.elementName, this.text); + RtfInfoElement elem = new RtfInfoElement(rtfDoc, meta); + rtfDoc.GetDocumentHeader().AddInfoElement(elem); + } + if (this.elementName.Equals("subject")){ + Meta meta = new Meta(this.elementName, this.text); + RtfInfoElement elem = new RtfInfoElement(rtfDoc, meta); + rtfDoc.GetDocumentHeader().AddInfoElement(elem); + } + } + } + this.SetToDefaults(); + } + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + */ + public override bool HandleOpenGroup() { + + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(char[]) + */ + public override bool HandleCharacter(int ch) { + this.text += (char)ch; + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleControlWord(com.lowagie.text.rtf.parser.ctrlwords.RtfCtrlWordData) + */ + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + elementName = ctrlWordData.ctrlWord; + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#setToDefaults() + */ + public override void SetToDefaults() { + this.text = ""; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationListTable.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationListTable.cs new file mode 100644 index 0000000..e326646 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationListTable.cs @@ -0,0 +1,130 @@ +using System; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationListTable.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationListTable handles data destined for the List Table destination + * + * @author Howard Shank (hgshank@yahoo.com) + * + */ + public class RtfDestinationListTable : RtfDestination { + /** + * The RtfImportHeader to add List mappings to. + */ + private RtfImportMgr importHeader = null; + + public RtfDestinationListTable() : base(null) { + } + + public RtfDestinationListTable(RtfParser parser) : base(parser) { + this.importHeader = parser.GetImportManager(); + } + + public override void SetParser(RtfParser parser) { + this.rtfParser = parser; + this.importHeader = parser.GetImportManager(); + this.SetToDefaults(); + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + */ + public override bool CloseDestination() { + // TODO Auto-generated method stub + return true; + } + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + bool result = true; + return result; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + */ + public override bool HandleCloseGroup() { + // TODO Auto-generated method stub + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + */ + public override bool HandleOpenGroup() { + // TODO Auto-generated method stub + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(int) + */ + public override bool HandleCharacter(int ch) { + // TODO Auto-generated method stub + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#setToDefaults() + */ + public override void SetToDefaults() { + // TODO Auto-generated method stub + + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationMgr.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationMgr.cs new file mode 100644 index 0000000..40cc288 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationMgr.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections; +using System.Reflection; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationMgr.cs,v 1.4 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationMgr manages destination objects for the parser + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public sealed class RtfDestinationMgr { + /* + * Destinations + */ + private static RtfDestinationMgr instance = null; + + /** + * CtrlWord <-> Destination map object. + * + * Maps control words to their destinations objects. + * Null destination is a special destination used for + * discarding unwanted data. This is primarily used when + * skipping groups, binary data or unwanted/unknown data. + */ + private static Hashtable destinations = new Hashtable(300, 0.95f); + /** + * Destination objects. + * There is only one of each destination. + */ + private static Hashtable destinationObjects = new Hashtable(10, 0.95f); + + private static bool ignoreUnknownDestinations = false; + + private static RtfParser rtfParser = null; + + /** + * String representation of null destination. + */ + public const String DESTINATION_NULL = "null"; + /** + * String representation of document destination. + */ + public const String DESTINATION_DOCUMENT = "document"; + + /** + * Hidden default constructor becuase + */ + private RtfDestinationMgr() { + } + + public static void SetParser(RtfParser parser) { + rtfParser = parser; + } + public static RtfDestinationMgr GetInstance() { + lock(destinations) { + if (instance == null) { + instance = new RtfDestinationMgr(); + // 2 required destinations for all documents + RtfDestinationMgr.AddDestination(RtfDestinationMgr.DESTINATION_DOCUMENT, new Object[] { "RtfDestinationDocument", "" } ); + RtfDestinationMgr.AddDestination(RtfDestinationMgr.DESTINATION_NULL, new Object[] { "RtfDestinationNull", "" } ); + } + return instance; + } + } + public static RtfDestinationMgr GetInstance(RtfParser parser) { + lock(destinations) { + RtfDestinationMgr.SetParser(parser); + if (instance == null) { + instance = new RtfDestinationMgr(); + // 2 required destinations for all documents + RtfDestinationMgr.AddDestination(RtfDestinationMgr.DESTINATION_DOCUMENT, new Object[] { "RtfDestinationDocument", "" } ); + RtfDestinationMgr.AddDestination(RtfDestinationMgr.DESTINATION_NULL, new Object[] { "RtfDestinationNull", "" } ); + } + return instance; + } + } + + public static RtfDestination GetDestination(String destination) { + RtfDestination dest = null; + if (destinations.ContainsKey(destination)) { + dest = (RtfDestination)destinations[destination]; + } else { + if (ignoreUnknownDestinations) { + dest = (RtfDestination)destinations[DESTINATION_NULL]; + } else { + dest = (RtfDestination)destinations[DESTINATION_DOCUMENT]; + } + } + dest.SetParser(RtfDestinationMgr.rtfParser); + return dest; + } + + public static bool AddDestination(String destination, Object[] args) { + if (destinations.ContainsKey(destination)) { + return true; + } + + String thisClass = "iTextSharp.text.rtf.parser.destinations." + (String)args[0]; + + if (thisClass.IndexOf("RtfDestinationNull") >= 0) { + destinations[destination] = RtfDestinationNull.GetInstance(); + return true; + } + + Type value = null; + + try { + value = Type.GetType(thisClass); + } catch { + return false; + } + if (value == null) + return false; + + RtfDestination c = null; + + if (destinationObjects.ContainsKey(value.Name)) { + c = (RtfDestination)destinationObjects[value.Name]; + } else { + try { + c = (RtfDestination)value.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null).Invoke(null); + } catch { + return false; + } + } + + c.SetParser(rtfParser); + + if (value.Equals(typeof(RtfDestinationInfo))) { + ((RtfDestinationInfo)c).SetElementName(destination); + } + + if (value.Equals(typeof(RtfDestinationStylesheetTable))) { + ((RtfDestinationStylesheetTable)c).SetElementName(destination); + ((RtfDestinationStylesheetTable)c).SetType((String)args[1]); + } + + destinations[destination] = c; + destinationObjects[value.Name] = c; + return true; + } + + // listener methods + + /** + * Adds a RtfDestinationListener to the appropriate RtfDestination. + * + * @param destination the destination string for the listener + * @param listener + * the new RtfDestinationListener. + */ + public static bool AddListener(String destination, IRtfDestinationListener listener) { + RtfDestination dest = GetDestination(destination); + if (dest != null) { + return dest.AddListener(listener); + } + return false; + } + + /** + * Removes a RtfDestinationListener from the appropriate RtfDestination. + * + * @param destination the destination string for the listener + * @param listener + * the RtfCtrlWordListener that has to be removed. + */ + public static bool RemoveListener(String destination, IRtfDestinationListener listener) { + RtfDestination dest = GetDestination(destination); + if (dest != null) { + return dest.RemoveListener(listener); + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationNull.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationNull.cs new file mode 100644 index 0000000..3a74d6a --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationNull.cs @@ -0,0 +1,147 @@ +using System; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationNull.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationNull is for discarded entries. They go nowhere. + * If a control word destination is unknown or ignored, this is the destination + * that should be set. + * + * All methods return true indicating they were handled. + * + * This is a unique destination in that it is a singleton. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public sealed class RtfDestinationNull : RtfDestination { + private static RtfDestinationNull instance = new RtfDestinationNull(); + /** + * Constructs a new RtfDestinationNull. + * + * This constructor is hidden for internal use only. + */ + private RtfDestinationNull() : base() { + } + /** + * Constructs a new RtfDestinationNull. + * + * This constructor is hidden for internal use only. + * + * @param parser Unused value + */ + private RtfDestinationNull(RtfParser parser) : base(null) { + } + /** + * Get the singleton instance of RtfDestinationNull object. + */ + static public RtfDestinationNull GetInstance() { + return instance; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#setDefaults() + */ + public override void SetToDefaults() { + } + + // Interface definitions + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + */ + public override bool CloseDestination() { + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + */ + public override bool HandleCloseGroup() { + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + */ + public override bool HandleOpenGroup() { + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(int) + */ + public override bool HandleCharacter(int ch) { + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleControlWord(com.lowagie.text.rtf.parser.ctrlwords.RtfCtrlWordData) + */ + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + return true; + } + + public static String GetName() { + return typeof(RtfDestinationNull).Name; + } + + public override int GetNewTokeniserState() { + return RtfParser.TOKENISER_SKIP_GROUP; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationShppict.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationShppict.cs new file mode 100644 index 0000000..695f8e7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationShppict.cs @@ -0,0 +1,488 @@ +using System; +using System.IO; +using System.Text; +using System.Globalization; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.rtf.direct; +using iTextSharp.text.rtf.graphic; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationShppict.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationShppict handles data destined for picture destinations + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfDestinationShppict : RtfDestination { + private ByteBuffer data = null; + + private StringBuilder hexChars = new StringBuilder(0); + private StringBuilder buffer = new StringBuilder(); + + /* picttype */ + private int pictureType = Image.ORIGINAL_NONE; + public const int ORIGINAL_NONE = 0; + public const int ORIGINAL_GIF = 3; + public const int ORIGINAL_TIFF = 5; + public const int ORIGINAL_PS = 7; + + // emfblip - EMF (nhanced metafile) - NOT HANDLED + // pngblip int ORIGINAL_PNG = 2; + // jpegblip Image.ORIGINAL_JPEG = 1; ORIGINAL_JPEG2000 = 8; + + // shppict - Destination + // nonshpict - Destination - SKIP THIS + // macpict - Mac QuickDraw- NOT HANDLED + // pmmetafileN - OS/2 Metafile - NOT HANDLED + // N * Meaning + // 0x0004 PU_ARBITRARY + // 0x0008 PU_PELS + // 0x000C PU_LOMETRIC + // 0x0010 PU_HIMETRIC + // 0x0014 PU_LOENGLISH + // 0x0018 PU_HIENGLISH + // 0x001C PU_TWIPS + //private int pmmetafile = 0; + // wmetafileN Image.RIGINAL_WMF = 6; + // N * Type + // 1 = MM_TEXT + // 2 = M_LOMETRIC + // 3 = MM_HIMETRIC + // 4 = MM_LOENGLISH + // 5 = MM_HIENGLISH + // 6 = MM_TWIPS + // 7 = MM_ISOTROPIC + // 8 = MM_ANISOTROPIC + // dibitmapN - DIB - Convert to BMP? + // wbitmapN Image.ORIGINAL_BMP = 4; + + /* bitapinfo */ + // wbmbitspixelN - number of bits per pixel - 1 monochrome, 4 16 color, 8 256 color, 24 RGB - Default 1 + //private int bitsPerPixel = 1; + // wbmplanesN - number of color planes - must be 1 + //private int planes = 1; + // wbmwidthbytesN - number of bytes in each raster line + //private int widthBytes = 0; + + + + /* pictsize */ + // picwN Ext field if the picture is a Windows metafile; picture width in pixels if the picture is a bitmap or + // from quickdraw + private long width = 0; + // pichN + private long height = 0; + // picwgoalN + private long desiredWidth = 0; + // picgoalN + private long desiredHeight = 0; + // picscalexN + private int scaleX = 100; + // picscaleyN + private int scaleY = 100; + // picscaled - macpict setting + //private bool scaled = false; + // picprop + //private bool inlinePicture = false; + // defshp + //private bool wordArt = false; + // piccroptN + private int cropTop = 0; + // piccropbN + private int cropBottom = 0; + // piccroplN + private int cropLeft = 0; + // piccroprN + private int cropRight = 0; + + /* metafileinfo */ + // picbmp + //private bool bitmap = false; + //picbppN - Valid 1,4,8,24 + //private int bbp = 1; + + /* data */ + // binN + // 0 = HEX, 1 = BINARY + public const int FORMAT_HEXADECIMAL = 0; + public const int FORMAT_BINARY = 1; + private int dataFormat = FORMAT_HEXADECIMAL; + private long binaryLength = 0; + // blipupiN + //private int unitsPerInch = 0; + // bliptagN + //private String tag = ""; + private const int NORMAL = 0; + private const int BLIPUID = 1; + + //private int state = NORMAL; + /** + * Constant for converting pixels to twips + */ + private const int PIXEL_TWIPS_FACTOR = 15; + + private MemoryStream dataOS = null; + + public RtfDestinationShppict() : base(null) { + this.pictureType = pictureType; //get rid of a warning + } + + /** + * Constructs a new RtfDestinationShppict. + */ + public RtfDestinationShppict(RtfParser parser) : base(parser) { + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + */ + public override bool CloseDestination() { + if (this.rtfParser.IsImport()) { + if (this.buffer.Length>0) { + WriteBuffer(); + } + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + */ + public override bool HandleCloseGroup() { + this.OnCloseGroup(); // event handler + + if (this.rtfParser.IsImport()) { + if (this.buffer.Length>0) { + WriteBuffer(); + } + if (dataOS != null) { + AddImage(); + dataOS = null; + } + this.WriteText("}"); + return true; + } + if (this.rtfParser.IsConvert()) { + } + return true; + } + + private bool AddImage() { + Image img = null; + try { + img = Image.GetInstance(dataOS.ToArray()); + } catch { + } +// if (img != null) { +// FileOutputStream out =null; +// try { +// out = new FileOutputStream("c:\\test.png"); +// out.Write(img.GetOriginalData()); +// out.Close(); +// } catch (FileNotFoundException e1) { +// // TODO Auto-generated catch block +// e1.PrintStackTrace(); +// } catch (IOException e1) { +// // TODO Auto-generated catch block +// e1.PrintStackTrace(); +// } + + if (img != null) { + img.ScaleAbsolute((float)this.desiredWidth/PIXEL_TWIPS_FACTOR, (float)this.desiredHeight/PIXEL_TWIPS_FACTOR); + img.ScaleAbsolute((float)this.width/PIXEL_TWIPS_FACTOR, (float)this.height/PIXEL_TWIPS_FACTOR); + img.ScalePercent((float)this.scaleX, this.scaleY); + + try { + if (this.rtfParser.IsImport()) { + RtfDocument rtfDoc = this.rtfParser.GetRtfDocument(); + RtfImage rtfImage = new RtfImage(rtfDoc, img); + rtfDoc.Add(rtfImage); + } + if (this.rtfParser.IsConvert()) { + this.rtfParser.GetDocument().Add(img); + } + } catch { + } + } + dataFormat = FORMAT_HEXADECIMAL; + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + */ + public override bool HandleOpenGroup() { + this.OnOpenGroup(); // event handler + + if (this.rtfParser.IsImport()) { + } + if (this.rtfParser.IsConvert()) { + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + if (this.rtfParser.IsImport()) { + if (this.buffer.Length>0) { + WriteBuffer(); + } + } + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(int) + */ + public override bool HandleCharacter(int ch) { + + if (this.rtfParser.IsImport()) { + if (buffer.Length > 254) + WriteBuffer(); + } + if (data == null) data = new ByteBuffer(); + switch (dataFormat) { + case FORMAT_HEXADECIMAL: + hexChars.Append(ch); + if (hexChars.Length == 2) { + try { + data.Append((char)int.Parse(hexChars.ToString(), NumberStyles.HexNumber)); + } catch { + } + hexChars = new StringBuilder(); + } + break; + case FORMAT_BINARY: + if (dataOS == null) { + dataOS = new MemoryStream(); + } + // HGS - FIX ME IF PROBLEM! + dataOS.WriteByte((byte)ch); + // PNG signature should be. + // (decimal) 137 80 78 71 13 10 26 10 + // (hexadecimal) 89 50 4e 47 0d 0a 1a 0a + // (ASCII C notation) \211 P N G \r \n \032 \n + + binaryLength--; + if (binaryLength == 0) { dataFormat = FORMAT_HEXADECIMAL; } + break; + } + + return true; + } + + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + bool result = false; + bool skipCtrlWord = false; + if (this.rtfParser.IsImport()) { + skipCtrlWord = true; + if (ctrlWordData.ctrlWord.Equals("shppict")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("nonshppict")) { // never gets here because this is a destination set to null + skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true; + } + if (ctrlWordData.ctrlWord.Equals("blipuid")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picprop")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("pict")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("emfblip")) { result = true; pictureType = Image.ORIGINAL_NONE;} + if (ctrlWordData.ctrlWord.Equals("pngblip")) { result = true; pictureType = Image.ORIGINAL_PNG;} + if (ctrlWordData.ctrlWord.Equals("jepgblip")) { result = true; pictureType = Image.ORIGINAL_JPEG;} + if (ctrlWordData.ctrlWord.Equals("macpict")) { result = true; pictureType = Image.ORIGINAL_NONE;} + if (ctrlWordData.ctrlWord.Equals("pmmetafile")) { result = true; pictureType = Image.ORIGINAL_NONE;} + if (ctrlWordData.ctrlWord.Equals("wmetafile")) { result = true; pictureType = Image.ORIGINAL_WMF;} + if (ctrlWordData.ctrlWord.Equals("dibitmap")) { result = true; pictureType = Image.ORIGINAL_NONE;} + if (ctrlWordData.ctrlWord.Equals("wbitmap")) { result = true; pictureType = Image.ORIGINAL_BMP;} + /* bitmap information */ + if (ctrlWordData.ctrlWord.Equals("wbmbitspixel")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("wbmplanes")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("wbmwidthbytes")) { result = true;} + /* picture size, scaling and cropping */ + if (ctrlWordData.ctrlWord.Equals("picw")) { this.width = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("pich")) { this.height = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picwgoal")) { this.desiredWidth = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("pichgoal")) { this.desiredHeight = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picscalex")) { this.scaleX = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picscaley")) { this.scaleY = ctrlWordData.IntValue();result = true;} + if (ctrlWordData.ctrlWord.Equals("picscaled")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("picprop")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("defshp")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropt")) { this.cropTop = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropb")) { this.cropBottom = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropl")) { this.cropLeft = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropr")) { this.cropRight = ctrlWordData.IntValue(); result = true;} + /* metafile information */ + if (ctrlWordData.ctrlWord.Equals("picbmp")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("picbpp")) { result = true;} + /* picture data */ + if (ctrlWordData.ctrlWord.Equals("bin")) { + this.dataFormat = FORMAT_BINARY; + // set length to param + this.binaryLength = ctrlWordData.LongValue(); + this.rtfParser.SetTokeniserStateBinary(binaryLength); + result = true; + } + if (ctrlWordData.ctrlWord.Equals("blipupi")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("blipuid")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("bliptag")) { result = true;} + } + if (this.rtfParser.IsConvert()) { + if (ctrlWordData.ctrlWord.Equals("shppict")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("nonshppict")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("blipuid")) { result = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("pict")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("emfblip")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("pngblip")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("jepgblip")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("macpict")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("pmmetafile")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("wmetafile")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("dibitmap")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("wbitmap")) { result = true;} + /* bitmap information */ + if (ctrlWordData.ctrlWord.Equals("wbmbitspixel")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("wbmplanes")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("wbmwidthbytes")) { result = true;} + /* picture size, scaling and cropping */ + if (ctrlWordData.ctrlWord.Equals("picw")) { this.width = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("pich")) { this.height = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picwgoal")) { this.desiredWidth = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("pichgoal")) { this.desiredHeight = ctrlWordData.LongValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picscalex")) { this.scaleX = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("picscaley")) { this.scaleY = ctrlWordData.IntValue();result = true;} + if (ctrlWordData.ctrlWord.Equals("picscaled")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("picprop")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("defshp")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropt")) { this.cropTop = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropb")) { this.cropBottom = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropl")) { this.cropLeft = ctrlWordData.IntValue(); result = true;} + if (ctrlWordData.ctrlWord.Equals("piccropr")) { this.cropRight = ctrlWordData.IntValue(); result = true;} + /* metafile information */ + if (ctrlWordData.ctrlWord.Equals("picbmp")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("picbpp")) { result = true;} + /* picture data */ + if(ctrlWordData.ctrlWord.Equals("bin")) { + dataFormat = FORMAT_BINARY; result = true; + } + if (ctrlWordData.ctrlWord.Equals("blipupi")) { result = true;} + if (ctrlWordData.ctrlWord.Equals("blipuid")) { skipCtrlWord = true; this.rtfParser.SetTokeniserStateSkipGroup(); result = true;} + if (ctrlWordData.ctrlWord.Equals("bliptag")) { result = true;} + + } + if (!skipCtrlWord) { + switch (this.rtfParser.GetConversionType()) { + case RtfParser.TYPE_IMPORT_FULL: + WriteBuffer(); + WriteText(ctrlWordData.ToString()); + result = true; + break; + case RtfParser.TYPE_IMPORT_FRAGMENT: + WriteBuffer(); + WriteText(ctrlWordData.ToString()); + result = true; + break; + case RtfParser.TYPE_CONVERT: + result = true; + break; + default: // error because is should be an import or convert + result = false; + break; + } + } + return result; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#setDefaults() + */ + public override void SetToDefaults() { + + this.buffer = new StringBuilder(); + this.data = null; + this.width = 0; + this.height = 0; + this.desiredWidth = 0; + this.desiredHeight = 0; + this.scaleX = 100; + this.scaleY = 100; + //this.scaled = false; + //this.inlinePicture = false; + //this.wordArt = false; + this.cropTop = 0; + this.cropBottom = 0; + this.cropLeft = 0; + this.cropRight = 0; + //this.bitmap = false; + //this.bbp = 1; + this.dataFormat = FORMAT_HEXADECIMAL; + this.binaryLength = 0; + //this.unitsPerInch = 0; + //this.tag = ""; + } + + private void WriteBuffer() { + WriteText(this.buffer.ToString()); + } + private void WriteText(String value) { + if (this.rtfParser.GetState().newGroup) { + this.rtfParser.GetRtfDocument().Add(new RtfDirectContent("{")); + this.rtfParser.GetState().newGroup = false; + } + if (value.Length > 0) { + this.rtfParser.GetRtfDocument().Add(new RtfDirectContent(value)); + } + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationStylesheetTable.cs b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationStylesheetTable.cs new file mode 100644 index 0000000..eaa5b4a --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationStylesheetTable.cs @@ -0,0 +1,585 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.rtf.style; +using iTextSharp.text.rtf.parser; +using iTextSharp.text.rtf.parser.ctrlwords; +/* + * $Id: RtfDestinationStylesheetTable.cs,v 1.2 2008/05/13 11:26:00 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.parser.destinations { + + /** + * RtfDestinationStylesheetTable handles data destined for the + * Stylesheet Table destination + * + * @author Howard Shank (hgshank@yahoo.com) + * + */ + public class RtfDestinationStylesheetTable : RtfDestination { + private String styleName = ""; + /** + * RtfParagraphStyle object for setting styleshee values + * as they are parsed from the input. + */ + //private RtfParagraphStyle rtfParagraphStyle = null; + + private String elementName = ""; + + /** + * RTF Style number from stylesheet table. + */ + private int styleNr = 0; + + /** + * What kind of style is this, Paragraph or Character or Table + */ + private int styleType = RtfStyleTypes.PARAGRAPH; + + // Alignment + /** + * Alignment - page 85 + * \qc, \qj, \ql, \qr, \qd, \qkN, \qt + */ + private int alignment = Element.ALIGN_LEFT; + /** + * Percentage of line occupied by Kashida justification (0 � low, 10 � medium, 20 � high). + * \qkN + */ + private int justificationPercentage = 0; + + // Indentation + /** + * First line indentation. + */ + private int firstLineIndent = 0; + /** + * Left indentation + */ + private int leftIndent = 0; + /** + * Right indentation + */ + private int rightIndent = 0; + /** + * Automatically adjust right indentation when docunent grid is defined + */ + private int adustRightIndent = 0; + /** + * Mirror indents? + */ + private int mirrorIndent = 0; + + // Document Foratting Properties + /** + * Override orphan/widow control. + */ + private int overrideWidowControl = -1; + + // Asian Typography + /** + * auto spacing betwee DBC and English + */ + private int AutoSpaceBetweenDBCEnglish = 0; + /** + * auto spacing betwee DBC and numbers + */ + private int AutoSpaceBetweenDBCNumbers = 0; + /** + * No Character wrapping + */ + private int noCharacterWrapping = 0; + /** + * No Word wrapping + */ + private int noWordWrapping = 0; + /** + * No overflow period and comma + */ + private int noOverflowPeriodComma = 0; + + + + ////////////////////////////////////////////////////// + /** + * The RtfImportHeader to add color mappings to. + */ + private RtfImportMgr importHeader = null; + private String type = ""; + + public RtfDestinationStylesheetTable() : base(null) { + } + + public RtfDestinationStylesheetTable(RtfParser parser, String type) : base(parser){ + this.importHeader = parser.GetImportManager(); + this.type = type; + } + public override void SetParser(RtfParser parser) { + this.rtfParser = parser; + this.importHeader = parser.GetImportManager(); + } + public void SetType(String value) { + this.type = value; + } + public void SetElementName(String value) { + this.elementName = value; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#handleOpenNewGroup() + */ + public override bool HandleOpeningSubGroup() { + // TODO Auto-generated method stub + return false; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#closeDestination() + */ + public override bool CloseDestination() { + + return true; + } + + public override bool HandleControlWord(RtfCtrlWordData ctrlWordData) { + bool result = true; + this.OnCtrlWord(ctrlWordData); // event handler + + if (this.rtfParser.IsImport()) { + // information + if (ctrlWordData.ctrlWord.Equals("s")) { } + if (ctrlWordData.ctrlWord.Equals("cs")) {} + if (ctrlWordData.ctrlWord.Equals("ds")) {} + if (ctrlWordData.ctrlWord.Equals("ts")) {} + if (ctrlWordData.ctrlWord.Equals("tsrowd")) {} + + if (ctrlWordData.ctrlWord.Equals("keycode")) {} + if (ctrlWordData.ctrlWord.Equals("shift")) { } + if (ctrlWordData.ctrlWord.Equals("ctrl")) { } + if (ctrlWordData.ctrlWord.Equals("alt")) { } + //cells + if (ctrlWordData.ctrlWord.Equals("fn")) { } + if (ctrlWordData.ctrlWord.Equals("additive")) { } + if (ctrlWordData.ctrlWord.Equals("sbasedon")) { } + if (ctrlWordData.ctrlWord.Equals("snext")) { } + if (ctrlWordData.ctrlWord.Equals("sautoupd")) { } + if (ctrlWordData.ctrlWord.Equals("shidden")) { } + if (ctrlWordData.ctrlWord.Equals("slink")) { } + if (ctrlWordData.ctrlWord.Equals("slocked")) { } + if (ctrlWordData.ctrlWord.Equals("spersonal")) { } + if (ctrlWordData.ctrlWord.Equals("scompose")) { } + if (ctrlWordData.ctrlWord.Equals("sreply")) { } + /* FORMATTING */ + // brdrdef/parfmt/apoctl/tabdef/shading/chrfmt + + + + if (ctrlWordData.ctrlWord.Equals("styrsid")) { } + if (ctrlWordData.ctrlWord.Equals("ssemihidden")) { } + if (ctrlWordData.ctrlWord.Equals("sqformat")) { } + if (ctrlWordData.ctrlWord.Equals("spriority")) { } + if (ctrlWordData.ctrlWord.Equals("sunhideused")) { } + + /* TABLE STYLES */ + if (ctrlWordData.ctrlWord.Equals("tscellwidth")) { } + if (ctrlWordData.ctrlWord.Equals("tscellwidthfts")) { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddt")) { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddl")) { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddr")) { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddb")) { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddft"))/*0-auto, 3-twips*/ { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddfl"))/*0-auto, 3-twips*/ { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddfr"))/*0-auto, 3-twips*/ { } + if (ctrlWordData.ctrlWord.Equals("tscellpaddfb"))/*0-auto, 3-twips*/ { } + if (ctrlWordData.ctrlWord.Equals("tsvertalt")) { } + if (ctrlWordData.ctrlWord.Equals("tsvertalc")) { } + if (ctrlWordData.ctrlWord.Equals("tsvertalb")) { } + if (ctrlWordData.ctrlWord.Equals("tsnowrap")) { } + if (ctrlWordData.ctrlWord.Equals("tscellcfpat")) { } + if (ctrlWordData.ctrlWord.Equals("tscellcbpat")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgbdiag")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgfdiag")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgcross")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgdcross")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgdkcross ")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgdkdcross")) { } + if (ctrlWordData.ctrlWord.Equals("tsbghoriz")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgvert")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgdkhor")) { } + if (ctrlWordData.ctrlWord.Equals("tsbgdkvert")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrt")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrb")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrl")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrr")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrh")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrv")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrdgl")) { } + if (ctrlWordData.ctrlWord.Equals("tsbrdrdgr")) { } + if (ctrlWordData.ctrlWord.Equals("tscbandsh")) { } + if (ctrlWordData.ctrlWord.Equals("tscbandsv")) { } + } + if (ctrlWordData.ctrlWordType == RtfCtrlWordType.FLAG || + ctrlWordData.ctrlWordType == RtfCtrlWordType.TOGGLE || + ctrlWordData.ctrlWordType == RtfCtrlWordType.VALUE) { + this.rtfParser.GetState().properties.SetProperty(ctrlWordData); + } + + switch (this.rtfParser.GetConversionType()) { + case RtfParser.TYPE_IMPORT_FULL: + result = true; + break; + case RtfParser.TYPE_IMPORT_FRAGMENT: + result = true; + break; + case RtfParser.TYPE_CONVERT: + result = true; + break; + default: // error because is should be an import or convert + result = false; + break; + } + return result; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupEnd() + */ + public override bool HandleCloseGroup() { + + return true; + } + + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleGroupStart() + */ + public override bool HandleOpenGroup() { + + return true; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.direct.RtfDestination#handleCharacter(int) + */ + public override bool HandleCharacter(int ch) { + styleName += (char)ch; + return true; + } + + public void CreateNewStyle() { + //public RtfParagraphStyle(String styleName, String fontName, int fontSize, int fontStyle, Color fontColor) + //this.rtfParagraphStyle = new RtfParagraphStyle(); + } + + /** + * Set the justification percentage from parsed value. + * @param percent The justification percentage + * @return The justification percentage + */ + public int SetJustificationPercentage(int percent) { + this.justificationPercentage = percent; + return this.justificationPercentage; + } + /** + * Get the justification percentage. + * @return The justification percentage value. + */ + public int GetJustificationPercentage() { + return this.justificationPercentage; + } + /** + * Set the alignment value from the parsed value. + * @param alignment The alignment value. + * @return The alignment value. + */ + public int SetAlignment(int alignment) { + this.alignment = alignment; + return this.alignment; + } + /** + * Get the alignment value. + * @return The alignment value. + */ + public int GetAlignment() { + return this.alignment; + } + /** + * Get the first line indent value. + * + * @return the firstLineIndent + */ + public int GetFirstLineIndent() { + return firstLineIndent; + } + /** + * Set the first line indent value. + * @param firstLineIndent the firstLineIndent to set + */ + public void SetFirstLineIndent(int firstLineIndent) { + this.firstLineIndent = firstLineIndent; + } + /** + * Get the left indent value + * @return the left indent + */ + public int GetIndent() { + return leftIndent; + } + /** + * Set the left indent value from the value parsed. + * @param indent the left indent value. + */ + public void SetIndent(int indent) { + this.leftIndent = indent; + } + /** + * Get the right indent adjustment value + * @return the adustRightIndent value + */ + public int GetAdustRightIndent() { + return adustRightIndent; + } + /** + * Set the right indent adjustment value + * @param adustRightIndent the adustRightIndent to set + */ + public void SetAdustRightIndent(int adustRightIndent) { + this.adustRightIndent = adustRightIndent; + } + /** + * Get the left indent value + * @return the leftIndent + */ + public int GetLeftIndent() { + return leftIndent; + } + /** + * Set the left indent value + * @param leftIndent the leftIndent to set + */ + public void SetLeftIndent(int leftIndent) { + this.leftIndent = leftIndent; + } + /** + * Get the value indicating if document has mirrored indents. + * + * @return the mirrorIndent + */ + public int GetMirrorIndent() { + return mirrorIndent; + } + /** + * Set the mirrored indent value from the parsed value. + * + * @param mirrorIndent the mirrorIndent to set + */ + public void SetMirrorIndent(int mirrorIndent) { + this.mirrorIndent = mirrorIndent; + } + /** + * Get the right indent value. + * + * @return the rightIndent + */ + public int GetRightIndent() { + return rightIndent; + } + /** + * Set the right indent value. + * + * @param rightIndent the rightIndent to set + */ + public void SetRightIndent(int rightIndent) { + this.rightIndent = rightIndent; + } + /** + * Get the ovirride widow control value. + * + * @return the overrideWidowControl + */ + public int GetOverrideWidowControl() { + return overrideWidowControl; + } + /** + * Set the override widow control. + * + * @param overrideWidowControl the overrideWidowControl to set + */ + public void SetOverrideWidowControl(int overrideWidowControl) { + this.overrideWidowControl = overrideWidowControl; + } + /** + * Get the auto space between DBC and English indicator. + * + * @return the autoSpaceBetweenDBCEnglish + */ + public int GetAutoSpaceBetweenDBCEnglish() { + return AutoSpaceBetweenDBCEnglish; + } + /** + * Set the auto space between DBC and English indicator. + * + * @param autoSpaceBetweenDBCEnglish the autoSpaceBetweenDBCEnglish to set + */ + public void SetAutoSpaceBetweenDBCEnglish(int autoSpaceBetweenDBCEnglish) { + AutoSpaceBetweenDBCEnglish = autoSpaceBetweenDBCEnglish; + } + /** + * Get the auto space between DBC and Numbers indicator. + * @return the autoSpaceBetweenDBCNumbers + */ + public int GetAutoSpaceBetweenDBCNumbers() { + return AutoSpaceBetweenDBCNumbers; + } + /** + * Set the auto space between DBC and Numbers indicator. + * @param autoSpaceBetweenDBCNumbers the autoSpaceBetweenDBCNumbers to set + */ + public void SetAutoSpaceBetweenDBCNumbers(int autoSpaceBetweenDBCNumbers) { + AutoSpaceBetweenDBCNumbers = autoSpaceBetweenDBCNumbers; + } + /** + * Get no character wrapping indicator. + * + * @return the noCharacterWrapping + */ + public int GetNoCharacterWrapping() { + return noCharacterWrapping; + } + /** + * Set the no character wrapping indicator from parsed value + * + * @param noCharacterWrapping the noCharacterWrapping to set + */ + public void SetNoCharacterWrapping(int noCharacterWrapping) { + this.noCharacterWrapping = noCharacterWrapping; + } + /** + * Get the no overflow period comma indicator. + * + * @return the noOverflowPeriodComma + */ + public int GetNoOverflowPeriodComma() { + return noOverflowPeriodComma; + } + /** + * Set the no overflow period comma indicator from the parsed value. + * + * @param noOverflowPeriodComma the noOverflowPeriodComma to set + */ + public void SetNoOverflowPeriodComma(int noOverflowPeriodComma) { + this.noOverflowPeriodComma = noOverflowPeriodComma; + } + /** + * Get the no word wrapping indicator. + * + * @return the noWordWrapping + */ + public int GetNoWordWrapping() { + return noWordWrapping; + } + /** + * Set the no word wrapping indicator from the parsed value. + * + * @param noWordWrapping the noWordWrapping to set + */ + public void SetNoWordWrapping(int noWordWrapping) { + this.noWordWrapping = noWordWrapping; + } + /** + * Get this style number. + * + * @return the styleNr + */ + public int GetStyleNr() { + return styleNr; + } + /** + * Set this style number from the parsed value. + * + * @param styleNr the styleNr to set + */ + public void SetStyleNr(int styleNr) { + this.styleNr = styleNr; + } + /** + * Get this style type. + * For example Style, Character Style, etc. + * + * @return the styleType + */ + public int GetStyleType() { + return styleType; + } + /** + * Set the style type. + * + * @param styleType the styleType to set + */ + public void SetStyleType(int styleType) { + this.styleType = styleType; + } + /* (non-Javadoc) + * @see com.lowagie.text.rtf.parser.destinations.RtfDestination#setToDefaults() + */ + public override void SetToDefaults() { + styleName = ""; + styleNr = 0; + alignment = Element.ALIGN_LEFT; + justificationPercentage = 0; + firstLineIndent = 0; + leftIndent = 0; + rightIndent = 0; + adustRightIndent = 0; + mirrorIndent = 0; + overrideWidowControl = -1; + AutoSpaceBetweenDBCEnglish = 0; + AutoSpaceBetweenDBCNumbers = 0; + noCharacterWrapping = 0; + noWordWrapping = 0; + noOverflowPeriodComma = 0; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/enumerations/RtfColorThemes.cs b/iTechSharp/iTextSharp/text/rtf/parser/enumerations/RtfColorThemes.cs new file mode 100644 index 0000000..ef238cf --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/enumerations/RtfColorThemes.cs @@ -0,0 +1,29 @@ +namespace iTextSharp.text.rtf.parser.enumerations { + + /** + * Specifies the color theme values for use in Color Tables. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public sealed class RtfColorThemes { + public const int THEME_UNDEFINED = -1; + public const int THEME_MAINDARKONE = 0; + public const int THEME_MAINDARKTWO = 1; + public const int THEME_MAINLIGHTONE = 2; + public const int THEME_MAINLIGHTTWO = 3; + public const int THEME_ACCENTONE = 4; + public const int THEME_ACCENTTWO = 5; + public const int THEME_ACCENTTHREE = 6; + public const int THEME_ACCENTFOUR = 7; + public const int THEME_ACCENTFIVE = 8; + public const int THEME_ACCENTSIX = 9; + public const int THEME_HYPERLINK = 10; + public const int THEME_FOLLOWEDHYPERLINK = 11; + public const int THEME_BACKGROUNDONE = 12; + public const int THEME_TEXTONE = 13; + public const int THEME_BACKGROUNDTWO = 14; + public const int THEME_TEXTTWO = 15; + public const int THEME_MAX = 15; + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfParserException.cs b/iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfParserException.cs new file mode 100644 index 0000000..88d9111 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfParserException.cs @@ -0,0 +1,87 @@ +using System; +/* + * $Id: RtfParserException.cs,v 1.2 2008/05/13 11:26:02 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.exceptions { + + /* + * Signals that an error has occurred in a RtfParser. + */ + /** + * RtfParserException is the exception object thrown by + * the parser + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfParserException : Exception { + /** + * Creates a RtfParserException object. + * @param ex an exception that has to be turned into a RtfParserException + */ + public RtfParserException(Exception ex) : base("", ex) { + } + + // constructors + + /** + * Constructs a RtfParserException whithout a message. + */ + public RtfParserException() : base() { + } + + /** + * Constructs a RtfParserException with a message. + * + * @param message a message describing the exception + */ + public RtfParserException(String message) : base(message) { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfUnknownCtrlWordException.cs b/iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfUnknownCtrlWordException.cs new file mode 100644 index 0000000..c1c3a65 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfUnknownCtrlWordException.cs @@ -0,0 +1,15 @@ +using System; + +namespace iTextSharp.text.rtf.parser.exceptions { + + public class RtfUnknownCtrlWordException : RtfParserException { + + // constructors + + /** + * Constructs a RtfParserException whithout a message. + */ + public RtfUnknownCtrlWordException() : base("Unknown control word.") { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/properties/IRtfPropertyListener.cs b/iTechSharp/iTextSharp/text/rtf/parser/properties/IRtfPropertyListener.cs new file mode 100644 index 0000000..c35d399 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/properties/IRtfPropertyListener.cs @@ -0,0 +1,71 @@ +using System; +using iTextSharp.text.rtf.parser; +/* + * $Id: IRtfPropertyListener.cs,v 1.2 2008/05/13 11:26:03 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.properties { + + /** + * RtfPropertyListener interface for handling events. + * + * @author Howard Shank (hgshank@yahoo.com) + * + * @since 2.0.8 + */ + public interface IRtfPropertyListener : IEventListener { + /** + * + */ + void BeforePropertyChange(String propertyName); + /** + * + */ + void AfterPropertyChange(String propertyName); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/parser/properties/RtfCtrlWordPropertyType.cs b/iTechSharp/iTextSharp/text/rtf/parser/properties/RtfCtrlWordPropertyType.cs new file mode 100644 index 0000000..8654dba --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/properties/RtfCtrlWordPropertyType.cs @@ -0,0 +1,58 @@ +/* $Id: RtfCtrlWordPropertyType.cs,v 1.3 2008/05/13 11:26:03 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.properties { + + public class RtfCtrlWordPropertyType { + public const int UNIDENTIFIED = -1; + public const int PROPERTY = 0; + public const int CHARACTER = 1; + public const int SPECIAL = 2; + public const int DESTINATION = 3; + } +} diff --git a/iTechSharp/iTextSharp/text/rtf/parser/properties/RtfProperty.cs b/iTechSharp/iTextSharp/text/rtf/parser/properties/RtfProperty.cs new file mode 100644 index 0000000..c604a5b --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/parser/properties/RtfProperty.cs @@ -0,0 +1,575 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf.parser.ctrlwords; + +/* $Id: RtfProperty.cs,v 1.3 2008/05/13 11:26:03 psoares33 Exp $ + * + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.rtf.parser.properties { + + /** + * RtfProperty handles document, paragraph, etc. property values + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public class RtfProperty { + public const int OFF = 0; + public const int ON = 1; + + /* property groups */ + public const String COLOR = "color."; + public const String CHARACTER = "character."; + public const String PARAGRAPH = "paragraph."; + public const String SECTION = "section."; + public const String DOCUMENT = "document."; + + /* color properties */ + public const String COLOR_FG = COLOR + "fg"; //Color Object + public const String COLOR_BG = COLOR + "bg"; //Color Object + + /* character properties */ + public const String CHARACTER_BOLD = CHARACTER + "bold"; + public const String CHARACTER_UNDERLINE = CHARACTER + "underline"; + public const String CHARACTER_ITALIC = CHARACTER + "italic"; + public const String CHARACTER_SIZE = CHARACTER + "size"; + public const String CHARACTER_FONT = CHARACTER + "font"; + public const String CHARACTER_STYLE = CHARACTER + "style"; + + /* paragraph properties */ + /** Justify left */ + public const int JUSTIFY_LEFT = 0; + /** Justify right */ + public const int JUSTIFY_RIGHT = 1; + /** Justify center */ + public const int JUSTIFY_CENTER = 2; + /** Justify full */ + public const int JUSTIFY_FULL = 3; + + public const String PARAGRAPH_INDENT_LEFT = PARAGRAPH + "indentLeft"; // twips + public const String PARAGRAPH_INDENT_RIGHT = PARAGRAPH + "indentRight"; // twips + public const String PARAGRAPH_INDENT_FIRST_LINE = PARAGRAPH + "indentFirstLine"; // twips + public const String PARAGRAPH_JUSTIFICATION = PARAGRAPH + "justification"; + + public const String PARAGRAPH_BORDER = PARAGRAPH + "border"; + public const String PARAGRAPH_BORDER_CELL = PARAGRAPH + "borderCell"; + + /** possible border settting */ + public const int PARAGRAPH_BORDER_NIL = 0; + /** possible border settting */ + public const int PARAGRAPH_BORDER_BOTTOM = 1; + /** possible border settting */ + public const int PARAGRAPH_BORDER_TOP = 2; + /** possible border settting */ + public const int PARAGRAPH_BORDER_LEFT = 4; + /** possible border settting */ + public const int PARAGRAPH_BORDER_RIGHT = 8; + /** possible border settting */ + public const int PARAGRAPH_BORDER_DIAGONAL_UL_LR = 16; + /** possible border settting */ + public const int PARAGRAPH_BORDER_DIAGONAL_UR_LL = 32; + /** possible border settting */ + public const int PARAGRAPH_BORDER_TABLE_HORIZONTAL = 64; + /** possible border settting */ + public const int PARAGRAPH_BORDER_TABLE_VERTICAL = 128; + + /* section properties */ + /** Decimal number format */ + public const int PGN_DECIMAL = 0; + /** Uppercase Roman Numeral */ + public const int PGN_ROMAN_NUMERAL_UPPERCASE = 1; + /** Lowercase Roman Numeral */ + public const int PGN_ROMAN_NUMERAL_LOWERCASE = 2; + /** Uppercase Letter */ + public const int PGN_LETTER_UPPERCASE = 3; + /** Lowercase Letter */ + public const int PGN_LETTER_LOWERCASE = 4; + /** Section Break None */ + public const int SBK_NONE = 0; + /** Section Break Column break */ + public const int SBK_COLUMN = 1; + /** Section Break Even page break */ + public const int SBK_EVEN = 2; + /** Section Break Odd page break */ + public const int SBK_ODD = 3; + /** Section Break Page break */ + public const int SBK_PAGE = 4; + + public const String SECTION_NUMBER_OF_COLUMNS = SECTION + "numberOfColumns"; + public const String SECTION_BREAK_TYPE = SECTION + "SectionBreakType"; + public const String SECTION_PAGE_NUMBER_POSITION_X = SECTION + "pageNumberPositionX"; + public const String SECTION_PAGE_NUMBER_POSITION_Y = SECTION + "pageNumberPositionY"; + public const String SECTION_PAGE_NUMBER_FORMAT = SECTION + "pageNumberFormat"; + + /* document properties */ + /** Portrait orientation */ + public const String PAGE_PORTRAIT = "0"; + /** Landscape orientation */ + public const String PAGE_LANDSCAPE = "1"; + + public const String DOCUMENT_PAGE_WIDTH_TWIPS = DOCUMENT + "pageWidthTwips"; + public const String DOCUMENT_PAGE_HEIGHT_TWIPS = DOCUMENT + "pageHeightTwips"; + public const String DOCUMENT_MARGIN_LEFT_TWIPS = DOCUMENT + "marginLeftTwips"; + public const String DOCUMENT_MARGIN_TOP_TWIPS = DOCUMENT + "marginTopTwips"; + public const String DOCUMENT_MARGIN_RIGHT_TWIPS = DOCUMENT + "marginRightTwips"; + public const String DOCUMENT_MARGIN_BOTTOM_TWIPS = DOCUMENT + "marginBottomTwips"; + public const String DOCUMENT_PAGE_NUMBER_START = DOCUMENT + "pageNumberStart"; + public const String DOCUMENT_ENABLE_FACING_PAGES = DOCUMENT + "enableFacingPages"; + public const String DOCUMENT_PAGE_ORIENTATION = DOCUMENT + "pageOrientation"; + public const String DOCUMENT_DEFAULT_FONT_NUMER = DOCUMENT + "defaultFontNumber"; + + /** Properties for this RtfProperty object */ + protected Hashtable properties = new Hashtable(); + + private bool modifiedCharacter = false; + private bool modifiedParagraph = false; + private bool modifiedSection = false; + private bool modifiedDocument = false; + + + /** The RtfPropertyListener. */ + private ArrayList listeners = new ArrayList(); + /** + * Set all property objects to default values. + * @since 2.0.8 + */ + public void SetToDefault() { + SetToDefault(COLOR); + SetToDefault(CHARACTER); + SetToDefault(PARAGRAPH); + SetToDefault(SECTION); + SetToDefault(DOCUMENT); + } + /** + * Set individual property group to default values. + * @param propertyGroup String name of the property group to set to default. + * @since 2.0.8 + */ + public void SetToDefault(String propertyGroup) { + if (COLOR.Equals(propertyGroup)) { + SetProperty(COLOR_FG, new Color(0,0,0)); + SetProperty(COLOR_BG, new Color(255,255,255)); + return; + } + if (CHARACTER.Equals(propertyGroup)) { + SetProperty(CHARACTER_BOLD, 0); + SetProperty(CHARACTER_UNDERLINE, 0); + SetProperty(CHARACTER_ITALIC, 0); + SetProperty(CHARACTER_SIZE, 24);// 1/2 pt sizes + SetProperty(CHARACTER_FONT, 0); + return; + } + if (PARAGRAPH.Equals(propertyGroup)) { + SetProperty(PARAGRAPH_INDENT_LEFT, 0); + SetProperty(PARAGRAPH_INDENT_RIGHT, 0); + SetProperty(PARAGRAPH_INDENT_FIRST_LINE, 0); + SetProperty(PARAGRAPH_JUSTIFICATION, JUSTIFY_LEFT); + SetProperty(PARAGRAPH_BORDER, PARAGRAPH_BORDER_NIL); + SetProperty(PARAGRAPH_BORDER_CELL, PARAGRAPH_BORDER_NIL); + return; + } + if (SECTION.Equals(propertyGroup)) { + SetProperty(SECTION_NUMBER_OF_COLUMNS, 0); + SetProperty(SECTION_BREAK_TYPE, SBK_NONE); + SetProperty(SECTION_PAGE_NUMBER_POSITION_X, 0); + SetProperty(SECTION_PAGE_NUMBER_POSITION_Y, 0); + SetProperty(SECTION_PAGE_NUMBER_FORMAT, PGN_DECIMAL); + return; + } + if (DOCUMENT.Equals(propertyGroup)) { + SetProperty(DOCUMENT_PAGE_WIDTH_TWIPS, 12240); + SetProperty(DOCUMENT_PAGE_HEIGHT_TWIPS, 15480); + SetProperty(DOCUMENT_MARGIN_LEFT_TWIPS, 1800); + SetProperty(DOCUMENT_MARGIN_TOP_TWIPS, 1440); + SetProperty(DOCUMENT_MARGIN_RIGHT_TWIPS, 1800); + SetProperty(DOCUMENT_MARGIN_BOTTOM_TWIPS, 1440); + SetProperty(DOCUMENT_PAGE_NUMBER_START, 1); + SetProperty(DOCUMENT_ENABLE_FACING_PAGES, 1); + SetProperty(DOCUMENT_PAGE_ORIENTATION, PAGE_PORTRAIT); + SetProperty(DOCUMENT_DEFAULT_FONT_NUMER, 0); + return; + } + } + + + /** + * Toggle the value of the property identified by the RtfCtrlWordData.specialHandler parameter. + * Toggle values are assumed to be integer values per the RTF spec with a value of 0=off or 1=on. + * + * @param ctrlWordData The property name to set + * @return true for handled or false if propertyName is null or blank + */ + public bool ToggleProperty(RtfCtrlWordData ctrlWordData) { //String propertyName) { + + String propertyName = ctrlWordData.specialHandler; + + if (propertyName == null || propertyName.Length == 0) return false; + + Object propertyValue = GetProperty(propertyName); + if (propertyValue == null) { + propertyValue = RtfProperty.ON; + } else { + if (propertyValue is int) { + int value = (int)propertyValue; + if (value != 0) { + RemoveProperty(propertyName); + } + return true; + } else { + if (propertyValue is long) { + long value = (long)propertyValue; + if (value != 0) { + RemoveProperty(propertyName); + } + return true; + } + } + } + SetProperty(propertyName, propertyValue); + return true; + } + /** + * Set the value of the property identified by the parameter. + * + * @param ctrlWordData The controlword with the name to set + * @return true for handled or false if propertyName or propertyValue is null + */ + public bool SetProperty(RtfCtrlWordData ctrlWordData) { //String propertyName, Object propertyValueNew) { + String propertyName = ctrlWordData.specialHandler; + Object propertyValueNew = ctrlWordData.param; + // depending on the control word, set mulitiple or reset settings, etc. + //if pard then reset settings + // + SetProperty(propertyName, propertyValueNew); + return true; + } + /** + * Set the value of the property identified by the parameter. + * + * @param propertyName The property name to set + * @param propertyValueNew The object to set the property value to + * @return true for handled or false if propertyName or propertyValue is null + */ + private bool SetProperty(String propertyName, Object propertyValueNew) { + if (propertyName == null || propertyValueNew == null) return false; + + Object propertyValueOld = GetProperty(propertyName); + if (propertyValueOld is int && propertyValueNew is int) { + int valueOld = (int)propertyValueOld; + int valueNew = (int)propertyValueNew; + if (valueOld==valueNew) return true; + } else { + if (propertyValueOld is long && propertyValueNew is long) { + long valueOld = (long)propertyValueOld; + long valueNew = (long)propertyValueNew; + if (valueOld==valueNew) return true; + } + } + BeforeChange(propertyName); + properties[propertyName] = propertyValueNew; + AfterChange(propertyName); + SetModified(propertyName, true); + return true; + } + /** + * Set the value of the property identified by the parameter. + * + * @param propertyName The property name to set + * @param propertyValue The object to set the property value to + * @return true for handled or false if propertyName is null + */ + private bool SetProperty(String propertyName, int propertyValueNew) { + if (propertyName == null) return false; + Object propertyValueOld = GetProperty(propertyName); + if (propertyValueOld is int) { + int valueOld = (int)propertyValueOld; + if (valueOld==propertyValueNew) return true; + } + BeforeChange(propertyName); + properties[propertyName] = propertyValueNew; + AfterChange(propertyName); + SetModified(propertyName, true); + return true; + } + /** + * Add the value of the property identified by the parameter. + * + * @param propertyName The property name to set + * @param propertyValue The object to set the property value to + * @return true for handled or false if propertyName is null + */ + private bool AddToProperty(String propertyName, int propertyValue) { + if (propertyName == null) return false; + int value = (int)properties[propertyName]; + if ((value | propertyValue) == value) return true; + value |= propertyValue; + BeforeChange(propertyName); + properties[propertyName] = value; + AfterChange(propertyName); + SetModified(propertyName, true); + return true; + } + /** + * Set the value of the property identified by the parameter. + * + * @param propertyName The property name to set + * @param propertyValue The object to set the property value to + * @return true for handled or false if propertyName is null + */ + private bool SetProperty(String propertyName, long propertyValueNew) { + if (propertyName == null) return false; + Object propertyValueOld = GetProperty(propertyName); + if (propertyValueOld is long) { + long valueOld = (long)propertyValueOld; + if (valueOld==propertyValueNew) return true; + } + BeforeChange(propertyName); + properties[propertyName] = propertyValueNew; + AfterChange(propertyName); + SetModified(propertyName, true); + return true; + } + /** + * Add the value of the property identified by the parameter. + * + * @param propertyName The property name to set + * @param propertyValue The object to set the property value to + * @return true for handled or false if propertyName is null + */ + private bool AddToProperty(String propertyName, long propertyValue) { + if (propertyName == null) return false; + long value = (long)properties[propertyName]; + if ((value | propertyValue) == value) return true; + value |= propertyValue; + BeforeChange(propertyName); + properties[propertyName] = value; + AfterChange(propertyName); + SetModified(propertyName, true); + return true; + } + private bool RemoveProperty(String propertyName) { + if (propertyName == null) return false; + if (properties.ContainsKey(propertyName)) { + BeforeChange(propertyName); + properties.Remove(propertyName); + AfterChange(propertyName); + SetModified(propertyName, true); + } + return true; + } + /** + * Get the value of the property identified by the parameter. + * + * @param propertyName String containing the property name to get + * @return Property Object requested or null if not found in map. + */ + public Object GetProperty(String propertyName) { + return properties[propertyName]; + } + /** + * Get a group of properties. + * + * @param propertyGroup The group name to obtain. + * @return Properties object with requested values. + */ + public Hashtable GetProperties(String propertyGroup) { + Hashtable props = new Hashtable(); + if (properties.Count != 0) { + //properties.get + foreach (String key in properties.Keys) { + if (key.StartsWith(propertyGroup)) { + props[key] = properties[key]; + } + } + } + return props; + } + + /** + * @return the modified + */ + public bool IsModified() { + return modifiedCharacter || modifiedParagraph || modifiedSection || modifiedDocument; + } + /** + * @param propertyName the propertyName that is modified + * @param modified the modified to set + */ + public void SetModified(String propertyName, bool modified) { + if (propertyName.StartsWith(CHARACTER)) { + this.SetModifiedCharacter(modified); + } else { + if (propertyName.StartsWith(PARAGRAPH)) { + this.SetModifiedParagraph(modified); + } else { + if (propertyName.StartsWith(SECTION)) { + this.SetModifiedSection(modified); + } else { + if (propertyName.StartsWith(DOCUMENT)) { + this.SetModifiedDocument(modified); + } + } + } + } + } + /** + * @return the modifiedCharacter + */ + public bool IsModifiedCharacter() { + return modifiedCharacter; + } + /** + * @param modifiedCharacter the modifiedCharacter to set + */ + public void SetModifiedCharacter(bool modifiedCharacter) { + this.modifiedCharacter = modifiedCharacter; + } + /** + * @return the modifiedParagraph + */ + public bool IsModifiedParagraph() { + return modifiedParagraph; + } + /** + * @param modifiedParagraph the modifiedParagraph to set + */ + public void SetModifiedParagraph(bool modifiedParagraph) { + this.modifiedParagraph = modifiedParagraph; + } + /** + * @return the modifiedSection + */ + public bool IsModifiedSection() { + return modifiedSection; + } + /** + * @param modifiedSection the modifiedSection to set + */ + public void SetModifiedSection(bool modifiedSection) { + this.modifiedSection = modifiedSection; + } + /** + * @return the modifiedDocument + */ + public bool IsModifiedDocument() { + return modifiedDocument; + } + /** + * @param modifiedDocument the modifiedDocument to set + */ + public void SetModifiedDocument(bool modifiedDocument) { + this.modifiedDocument = modifiedDocument; + } + + /** + * Adds a RtfPropertyListener to the RtfProperty. + * + * @param listener + * the new RtfPropertyListener. + */ + public void AddRtfPropertyListener(IRtfPropertyListener listener) { + listeners.Add(listener); + } + /** + * Removes a RtfPropertyListener from the RtfProperty. + * + * @param listener + * the new RtfPropertyListener. + */ + public void RemoveRtfPropertyListener(IRtfPropertyListener listener) { + listeners.Remove(listener); + } + + public void BeforeChange(String propertyName) { + // call listener for all + foreach (IRtfPropertyListener listener in listeners) { + listener.BeforePropertyChange(propertyName); + } + + if (propertyName.StartsWith(CHARACTER)) { + // call listener for character chane + } else { + if (propertyName.StartsWith(PARAGRAPH)) { + // call listener for paragraph change + } else { + if (propertyName.StartsWith(SECTION)) { + // call listener for section change + } else { + if (propertyName.StartsWith(DOCUMENT)) { + // call listener for document change + } + } + } + } + } + + public void AfterChange(String propertyName) { + // call listener for all + foreach (IRtfPropertyListener listener in listeners) { + listener.AfterPropertyChange(propertyName); + } + + if (propertyName.StartsWith(CHARACTER)) { + // call listener for character chane + } else { + if (propertyName.StartsWith(PARAGRAPH)) { + // call listener for paragraph change + } else { + if (propertyName.StartsWith(SECTION)) { + // call listener for section change + } else { + if (propertyName.StartsWith(DOCUMENT)) { + // call listener for document change + } + } + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfColor.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfColor.cs new file mode 100644 index 0000000..c942e99 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfColor.cs @@ -0,0 +1,285 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfColor.cs,v 1.6 2008/05/16 19:31:10 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.style { + + /** + * The RtfColor stores one rtf color value for a rtf document + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfColor : RtfElement, IRtfExtendedElement { + + /** + * Constant for RED value + */ + private static byte[] COLOR_RED = DocWriter.GetISOBytes("\\red"); + /** + * Constant for GREEN value + */ + private static byte[] COLOR_GREEN = DocWriter.GetISOBytes("\\green"); + /** + * Constant for BLUE value + */ + private static byte[] COLOR_BLUE = DocWriter.GetISOBytes("\\blue"); + /** + * Constant for the end of one color entry + */ + private const byte COLON = (byte) ';'; + /** + * Constant for the number of the colour in the list of colours + */ + private static byte[] COLOR_NUMBER = DocWriter.GetISOBytes("\\cf"); + + /** + * The number of the colour in the list of colours + */ + private int colorNumber = 0; + /** + * The red value + */ + private int red = 0; + /** + * The green value + */ + private int green = 0; + /** + * The blue value + */ + private int blue = 0; + + /** + * Constructor only for use when initializing the RtfColorList + * + * @param doc The RtfDocument this RtfColor belongs to + * @param red The red value to use + * @param green The green value to use + * @param blue The blue value to use + * @param colorNumber The number of the colour in the colour list + */ + protected internal RtfColor(RtfDocument doc, int red, int green, int blue, int colorNumber) : base(doc) { + this.red = red; + this.blue = blue; + this.green = green; + this.colorNumber = colorNumber; + } + + /** + * Constructs a RtfColor as a clone of an existing RtfColor + * + * @param doc The RtfDocument this RtfColor belongs to + * @param col The RtfColor to use as a base + */ + public RtfColor(RtfDocument doc, RtfColor col) : base(doc) { + if (col != null) { + this.red = col.GetRed(); + this.green = col.GetGreen(); + this.blue = col.GetBlue(); + } + if (this.document != null) { + this.colorNumber = this.document.GetDocumentHeader().GetColorNumber(this); + } + } + + /** + * Constructs a RtfColor based on the Color + * + * @param doc The RtfDocument this RtfColor belongs to + * @param col The Color to base this RtfColor on + */ + public RtfColor(RtfDocument doc, Color col) : base(doc) { + if (col != null) { + this.red = col.R; + this.blue = col.B; + this.green = col.G; + } + if (this.document != null) { + this.colorNumber = this.document.GetDocumentHeader().GetColorNumber(this); + } + } + + /** + * Constructs a RtfColor based on the red/green/blue values + * + * @param doc The RtfDocument this RtfColor belongs to + * @param red The red value to use + * @param green The green value to use + * @param blue The blue value to use + */ + public RtfColor(RtfDocument doc, int red, int green, int blue) : base(doc) { + this.red = red; + this.blue = blue; + this.green = green; + if (this.document != null) { + this.colorNumber = this.document.GetDocumentHeader().GetColorNumber(this); + } + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Write the definition part of this RtfColor. + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + result.Write(COLOR_RED, 0, COLOR_RED.Length); + result.Write(t = IntToByteArray(red), 0, t.Length); + result.Write(COLOR_GREEN, 0, COLOR_GREEN.Length); + result.Write(t = IntToByteArray(green), 0, t.Length); + result.Write(COLOR_BLUE, 0, COLOR_BLUE.Length); + result.Write(t = IntToByteArray(blue), 0, t.Length); + result.WriteByte(COLON); + } + + /** + * Writes the beginning of this RtfColor + * + */ + public void WriteBegin(Stream result) { + byte[] t; + try { + result.Write(COLOR_NUMBER, 0, COLOR_NUMBER.Length); + result.Write(t = IntToByteArray(colorNumber), 0, t.Length); + } catch (IOException) { + } + } + + /** + * Unused + * + */ + public void WriteEnd(Stream result) { + } + + /** + * Tests if this RtfColor is equal to another RtfColor. + * + * @param obj another RtfColor + * @return True if red, green and blue values of the two colours match, + * false otherwise. + */ + public override bool Equals(Object obj) { + if (!(obj is RtfColor)) { + return false; + } + RtfColor color = (RtfColor) obj; + return (this.red == color.GetRed() && this.green == color.GetGreen() && this.blue == color.GetBlue()); + } + + /** + * Returns the hash code of this RtfColor. The hash code is + * an integer with the lowest three bytes containing the values + * of red, green and blue. + * + * @return The hash code of this RtfColor + */ + public override int GetHashCode() { + return (this.red << 16) | (this.green << 8) | this.blue; + } + + /** + * Get the blue value of this RtfColor + * + * @return The blue value + */ + public int GetBlue() { + return blue; + } + + /** + * Get the green value of this RtfColor + * + * @return The green value + */ + public int GetGreen() { + return green; + } + + /** + * Get the red value of this RtfColor + * + * @return The red value + */ + public int GetRed() { + return red; + } + + /** + * Gets the number of this RtfColor in the list of colours + * + * @return Returns the colorNumber. + */ + public int GetColorNumber() { + return colorNumber; + } + + /** + * Sets the RtfDocument this RtfColor belongs to + * + * @param doc The RtfDocument to use + */ + public override void SetRtfDocument(RtfDocument doc) { + base.SetRtfDocument(doc); + if (document != null) { + this.colorNumber = document.GetDocumentHeader().GetColorNumber(this); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfColorList.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfColorList.cs new file mode 100644 index 0000000..5852cad --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfColorList.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfColorList.cs,v 1.5 2008/05/16 19:31:11 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.style { + + /** + * The RtfColorList stores all colours that appear in the document. Black + * and White are always added + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfColorList : RtfElement, IRtfExtendedElement { + + /** + * Constant for the beginning of the colour table + */ + private static byte[] COLOR_TABLE = DocWriter.GetISOBytes("\\colortbl"); + + /** + * ArrayList containing all colours of this RtfColorList + */ + ArrayList colorList = new ArrayList(); + + /** + * Constructs a new RtfColorList for the RtfDocument. Will add the default + * black and white colours. + * + * @param doc The RtfDocument this RtfColorList belongs to + */ + public RtfColorList(RtfDocument doc) : base(doc) { + colorList.Add(new RtfColor(doc, 0, 0, 0, 0)); + colorList.Add(new RtfColor(doc, 255, 255, 255, 1)); + } + + /** + * Returns the index of the given RtfColor in the colour list. If the RtfColor + * is not in the list of colours, then it is added. + * + * @param color The RtfColor for which to get the index + * @return The index of the RtfColor + */ + public int GetColorNumber(RtfColor color) { + int colorIndex = -1; + for (int i = 0; i < colorList.Count; i++) { + if (colorList[i].Equals(color)) { + colorIndex = i; + } + } + if (colorIndex == -1) { + colorIndex = colorList.Count; + colorList.Add(color); + } + return colorIndex; + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Write the definition part of the colour list. Calls the writeDefinition + * methods of the RtfColors in the colour list. + */ + public virtual void WriteDefinition(Stream result) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(COLOR_TABLE, 0, COLOR_TABLE.Length); + for (int i = 0; i < colorList.Count; i++) { + RtfColor color = (RtfColor) colorList[i]; + color.WriteDefinition(result); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfFont.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfFont.cs new file mode 100644 index 0000000..55e3e5e --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfFont.cs @@ -0,0 +1,730 @@ +using System; +using System.IO; +using System.util; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfFont.cs,v 1.13 2008/05/16 19:31:11 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.style { + + /** + * The RtfFont class stores one font for an rtf document. It extends Font, + * so can be set as a font, to allow adding of fonts with arbitrary names. + * BaseFont fontname handling contributed by Craig Fleming. Various fixes + * Renaud Michel, Werner Daehn. + * + * Version: $Id: RtfFont.cs,v 1.13 2008/05/16 19:31:11 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Craig Fleming (rythos@rhana.dhs.org) + * @author Renaud Michel (r.michel@immedia.be) + * @author Werner Daehn (Werner.Daehn@BusinessObjects.com) + * @author Lidong Liu (tmslld@gmail.com) + */ + public class RtfFont : Font, IRtfExtendedElement { + /** + * Constant for the font family to use ("froman") + */ + private static byte[] FONT_FAMILY = DocWriter.GetISOBytes("\\froman"); + /** + * Constant for the charset + */ + private static byte[] FONT_CHARSET = DocWriter.GetISOBytes("\\fcharset"); + /** + * Constant for the font size + */ + public static byte[] FONT_SIZE = DocWriter.GetISOBytes("\\fs"); + /** + * Constant for the bold flag + */ + private static byte[] FONT_BOLD = DocWriter.GetISOBytes("\\b"); + /** + * Constant for the italic flag + */ + private static byte[] FONT_ITALIC = DocWriter.GetISOBytes("\\i"); + /** + * Constant for the underline flag + */ + private static byte[] FONT_UNDERLINE = DocWriter.GetISOBytes("\\ul"); + /** + * Constant for the strikethrough flag + */ + private static byte[] FONT_STRIKETHROUGH = DocWriter.GetISOBytes("\\strike"); + /** + * Constant for the double strikethrough flag + */ + private static byte[] FONT_DOUBLE_STRIKETHROUGH = DocWriter.GetISOBytes("\\striked"); + /** + * Constant for the shadow flag + */ + private static byte[] FONT_SHADOW = DocWriter.GetISOBytes("\\shad"); + /** + * Constant for the outline flag + */ + private static byte[] FONT_OUTLINE = DocWriter.GetISOBytes("\\outl"); + /** + * Constant for the embossed flag + */ + private static byte[] FONT_EMBOSSED = DocWriter.GetISOBytes("\\embo"); + /** + * Constant for the engraved flag + */ + private static byte[] FONT_ENGRAVED = DocWriter.GetISOBytes("\\impr"); + /** + * Constant for hidden text flag + */ + private static byte[] FONT_HIDDEN = DocWriter.GetISOBytes("\\v"); + + /** + * Constant for a plain font + */ + public const int STYLE_NONE = 0; + /** + * Constant for a bold font + */ + public const int STYLE_BOLD = 1; + /** + * Constant for an italic font + */ + public const int STYLE_ITALIC = 2; + /** + * Constant for an underlined font + */ + public const int STYLE_UNDERLINE = 4; + /** + * Constant for a strikethrough font + */ + public const int STYLE_STRIKETHROUGH = 8; + /** + * Constant for a double strikethrough font + */ + public const int STYLE_DOUBLE_STRIKETHROUGH = 16; + /** + * Constant for a shadowed font + */ + public const int STYLE_SHADOW = 32; + /** + * Constant for an outlined font + */ + public const int STYLE_OUTLINE = 64; + /** + * Constant for an embossed font + */ + public const int STYLE_EMBOSSED = 128; + /** + * Constant for an engraved font + */ + public const int STYLE_ENGRAVED = 256; + /** + * Constant for a font that hides the actual text. + */ + public const int STYLE_HIDDEN = 512; + + /** + * The font name. Defaults to "Times New Roman" + */ + private String fontName = "Times New Roman"; + /** + * The font size. Defaults to 10 + */ + private int fontSize = 10; + /** + * The font style. Defaults to STYLE_NONE + */ + private int fontStyle = STYLE_NONE; + /** + * The number of this font + */ + private int fontNumber = 0; + /** + * The colour of this font + */ + private RtfColor color = null; + /** + * The character set to use for this font + */ + private int charset = 0; + /** + * The RtfDocument this RtfFont belongs to. + */ + protected RtfDocument document = null; + + /** + * Constructs a RtfFont with the given font name and all other properties + * at their default values. + * + * @param fontName The font name to use + */ + public RtfFont(String fontName) : base(Font.UNDEFINED, Font.UNDEFINED, Font.UNDEFINED, null) { + this.fontName = fontName; + } + + /** + * Constructs a RtfFont with the given font name and font size and all other + * properties at their default values. + * + * @param fontName The font name to use + * @param size The font size to use + */ + public RtfFont(String fontName, float size) : base(Font.UNDEFINED, size, Font.UNDEFINED, null) { + this.fontName = fontName; + } + + /** + * Constructs a RtfFont with the given font name, font size and font style and the + * default color. + * + * @param fontName The font name to use + * @param size The font size to use + * @param style The font style to use + */ + public RtfFont(String fontName, float size, int style) : base(Font.UNDEFINED, size, style, null) { + this.fontName = fontName; + } + + /** + * Constructs a RtfFont with the given font name, font size, font style and + * color. + * + * @param fontName The font name to use + * @param size the font size to use + * @param style The font style to use + * @param color The font color to use + */ + public RtfFont(String fontName, float size, int style, Color color) : base(Font.UNDEFINED, size, style, color) { + this.fontName = fontName; + } + + /** + * Constructs a RtfFont with the given font name, font size, font style, colour + * and charset. This can be used when generating non latin-1 text. + * + * @param fontName The font name to use + * @param size the font size to use + * @param style The font style to use + * @param color The font color to use + * @param charset The charset of the font content + */ + public RtfFont(String fontName, float size, int style, Color color, int charset) : this(fontName, size, style, color){ + this.charset = charset; + } + + /** + * Special constructor for the default font + * + * @param doc The RtfDocument this font appears in + * @param fontNumber The id of this font + */ + protected internal RtfFont(RtfDocument doc, int fontNumber) { + this.document = doc; + this.fontNumber = fontNumber; + color = new RtfColor(doc, 0, 0, 0); + } + + /** + * Constructs a RtfFont from a com.lowagie.text.Font + * @param doc The RtfDocument this font appears in + * @param font The Font to use as a base + */ + public RtfFont(RtfDocument doc, Font font) { + this.document = doc; + if (font != null) { + if (font is RtfFont) { + this.fontName = ((RtfFont) font).GetFontName(); + this.charset = ((RtfFont) font).GetCharset(); + } else { + SetToDefaultFamily(font.Familyname); + } + if (font.BaseFont != null) { + String[][] fontNames = font.BaseFont.FullFontName; + for (int i = 0; i < fontNames.Length; i++) { + if (fontNames[i][2].Equals("0")) { + this.fontName = fontNames[i][3]; + break; + } else if (fontNames[i][2].Equals("1033") || fontNames[i][2].Equals("")) { + this.fontName = fontNames[i][3]; + } + } + } + Size = font.Size; + SetStyle(font.Style); + Color = font.Color; + } + if (Util.EqualsIgnoreCase(this.fontName, "unknown")) { + return; + } + + if (document != null) { + SetRtfDocument(document); + } + } + + /** + * Writes the font definition + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + result.Write(FONT_FAMILY, 0, FONT_FAMILY.Length); + result.Write(FONT_CHARSET, 0, FONT_CHARSET.Length); + result.Write(t = IntToByteArray(charset), 0, t.Length); + result.Write(RtfElement.DELIMITER, 0, RtfElement.DELIMITER.Length); + document.FilterSpecialChar(result, fontName, true, false); + } + + /** + * Writes the font beginning + * + * @return A byte array with the font start data + */ + public virtual void WriteBegin(Stream result) { + byte[] t; + if(this.fontNumber != Font.UNDEFINED) { + result.Write(RtfFontList.FONT_NUMBER, 0, RtfFontList.FONT_NUMBER.Length); + result.Write(t = IntToByteArray(fontNumber), 0, t.Length); + } + if(this.fontSize != Font.UNDEFINED) { + result.Write(FONT_SIZE, 0, FONT_SIZE.Length); + result.Write(t = IntToByteArray(fontSize * 2), 0, t.Length); + } + if (this.fontStyle != UNDEFINED) { + if ((fontStyle & STYLE_BOLD) == STYLE_BOLD) { + result.Write(FONT_BOLD, 0, FONT_BOLD.Length); + } + if ((fontStyle & STYLE_ITALIC) == STYLE_ITALIC) { + result.Write(FONT_ITALIC, 0, FONT_ITALIC.Length); + } + if ((fontStyle & STYLE_UNDERLINE) == STYLE_UNDERLINE) { + result.Write(FONT_UNDERLINE, 0, FONT_UNDERLINE.Length); + } + if ((fontStyle & STYLE_STRIKETHROUGH) == STYLE_STRIKETHROUGH) { + result.Write(FONT_STRIKETHROUGH, 0, FONT_STRIKETHROUGH.Length); + } + if ((fontStyle & STYLE_HIDDEN) == STYLE_HIDDEN) { + result.Write(FONT_HIDDEN, 0, FONT_HIDDEN.Length); + } + if ((fontStyle & STYLE_DOUBLE_STRIKETHROUGH) == STYLE_DOUBLE_STRIKETHROUGH) { + result.Write(FONT_DOUBLE_STRIKETHROUGH, 0, FONT_DOUBLE_STRIKETHROUGH.Length); + result.Write(t = IntToByteArray(1), 0, t.Length); + } + if ((fontStyle & STYLE_SHADOW) == STYLE_SHADOW) { + result.Write(FONT_SHADOW, 0, FONT_SHADOW.Length); + } + if ((fontStyle & STYLE_OUTLINE) == STYLE_OUTLINE) { + result.Write(FONT_OUTLINE, 0, FONT_OUTLINE.Length); + } + if ((fontStyle & STYLE_EMBOSSED) == STYLE_EMBOSSED) { + result.Write(FONT_EMBOSSED, 0, FONT_EMBOSSED.Length); + } + if ((fontStyle & STYLE_ENGRAVED) == STYLE_ENGRAVED) { + result.Write(FONT_ENGRAVED, 0, FONT_ENGRAVED.Length); + } + } + if(color != null) { + color.WriteBegin(result); + } + } + + /** + * Write the font end + * + */ + public virtual void WriteEnd(Stream result) { + byte[] t; + if (this.fontStyle != UNDEFINED) { + if ((fontStyle & STYLE_BOLD) == STYLE_BOLD) { + result.Write(FONT_BOLD, 0, FONT_BOLD.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_ITALIC) == STYLE_ITALIC) { + result.Write(FONT_ITALIC, 0, FONT_ITALIC.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_UNDERLINE) == STYLE_UNDERLINE) { + result.Write(FONT_UNDERLINE, 0, FONT_UNDERLINE.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_STRIKETHROUGH) == STYLE_STRIKETHROUGH) { + result.Write(FONT_STRIKETHROUGH, 0, FONT_STRIKETHROUGH.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_HIDDEN) == STYLE_HIDDEN) { + result.Write(FONT_HIDDEN, 0, FONT_HIDDEN.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_DOUBLE_STRIKETHROUGH) == STYLE_DOUBLE_STRIKETHROUGH) { + result.Write(FONT_DOUBLE_STRIKETHROUGH, 0, FONT_DOUBLE_STRIKETHROUGH.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_SHADOW) == STYLE_SHADOW) { + result.Write(FONT_SHADOW, 0, FONT_SHADOW.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_OUTLINE) == STYLE_OUTLINE) { + result.Write(FONT_OUTLINE, 0, FONT_OUTLINE.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_EMBOSSED) == STYLE_EMBOSSED) { + result.Write(FONT_EMBOSSED, 0, FONT_EMBOSSED.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + if ((fontStyle & STYLE_ENGRAVED) == STYLE_ENGRAVED) { + result.Write(FONT_ENGRAVED, 0, FONT_ENGRAVED.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + } + } + } + + /** + * unused + */ + public virtual void WriteContent(Stream outp) { + } + + /** + * Tests for equality of RtfFonts. RtfFonts are equal if their fontName, + * fontSize, fontStyle and fontSuperSubscript are equal + * + * @param obj The RtfFont to compare with this RtfFont + * @return True if the RtfFonts are equal, false otherwise + */ + public override bool Equals(Object obj) { + if (!(obj is RtfFont)) { + return false; + } + RtfFont font = (RtfFont) obj; + bool result = true; + result = result & this.fontName.Equals(font.GetFontName()); + return result; + } + + /** + * Returns the hash code of this RtfFont. The hash code is the hash code of the + * string containing the font name + font size + "-" + the font style + "-" + the + * font super/supscript value. + * + * @return The hash code of this RtfFont + */ + public override int GetHashCode() { + return (this.fontName + this.fontSize + "-" + this.fontStyle).GetHashCode(); + } + + /** + * Gets the font name of this RtfFont + * + * @return The font name + */ + public String GetFontName() { + return this.fontName; + } + + /** + * Sets the font name of this RtfFont. + * + * @param fontName The font name to use + */ + public virtual void SetFontName(String fontName) { + this.fontName = fontName; + if(document != null) { + this.fontNumber = document.GetDocumentHeader().GetFontNumber(this); + } + } + /** + * @see com.lowagie.text.Font#getFamilyname() + */ + public override String Familyname { + get { + return this.fontName; + } + } + + /** + * @see com.lowagie.text.Font#setFamily(String) + */ + public override void SetFamily(String family){ + base.SetFamily(family); + SetToDefaultFamily(family); + } + + /** + * Sets the correct font name from the family name. + * + * @param familyname The family name to set the name to. + */ + private void SetToDefaultFamily(String familyname){ + switch (Font.GetFamilyIndex(familyname)) { + case Font.COURIER: + this.fontName = "Courier"; + break; + case Font.HELVETICA: + this.fontName = "Arial"; + break; + case Font.SYMBOL: + this.fontName = "Symbol"; + this.charset = 2; + break; + case Font.TIMES_ROMAN: + this.fontName = "Times New Roman"; + break; + case Font.ZAPFDINGBATS: + this.fontName = "Windings"; + break; + default: + this.fontName = familyname; + break; + } + } + + /** + * Gets the font size of this RtfFont + * + * @return The font size + */ + public int GetFontSize() { + return this.fontSize; + } + + /** + * @see com.lowagie.text.Font#setSize(float) + */ + public override float Size { + set { + base.Size = value; + this.fontSize = (int)Size; + } + } + + /** + * Gets the font style of this RtfFont + * + * @return The font style + */ + public int GetFontStyle() { + return this.fontStyle; + } + + /** + * @see com.lowagie.text.Font#setStyle(int) + */ + public override void SetStyle(int style){ + base.SetStyle(style); + this.fontStyle = Style; + } + + /** + * @see com.lowagie.text.Font#setStyle(String) + */ + public override void SetStyle(String style) { + base.SetStyle(style); + fontStyle = Style; + } + + /** + * Gets the charset used for constructing this RtfFont. + * + * @return The charset of this RtfFont. + */ + public int GetCharset() { + return charset; + } + + /** + * Sets the charset used for constructing this RtfFont. + * + * @param charset The charset to use. + */ + public void SetCharset(int charset) { + this.charset = charset; + } + + /** + * Gets the font number of this RtfFont + * + * @return The font number + */ + public int GetFontNumber() { + return fontNumber; + } + + /** + * Sets the RtfDocument this RtfFont belongs to + * + * @param doc The RtfDocument to use + */ + public void SetRtfDocument(RtfDocument doc) { + this.document = doc; + if (document != null) { + this.fontNumber = document.GetDocumentHeader().GetFontNumber(this); + } + if (this.color != null) { + this.color.SetRtfDocument(this.document); + } + } + + /** + * Unused + * @param inTable + */ + public void SetInTable(bool inTable) { + } + + /** + * Unused + * @param inHeader + */ + public void SetInHeader(bool inHeader) { + } + + /** + * @see com.lowagie.text.Font#setColor(Color) + */ + public override Color Color { + set { + base.Color = value; + if(value != null) { + this.color = new RtfColor(document, value); + } else { + this.color = null; + } + } + } + + /** + * @see com.lowagie.text.Font#setColor(int, int, int) + */ + public override void SetColor(int red, int green, int blue) { + base.SetColor(red,green,blue); + this.color = new RtfColor(document, red, green, blue); + } + + /** + * Transforms an integer into its String representation and then returns the bytes + * of that string. + * + * @param i The integer to convert + * @return A byte array representing the integer + */ + protected byte[] IntToByteArray(int i) { + return DocWriter.GetISOBytes(i.ToString()); + } + + /** + * Replaces the attributes that are equal to null with + * the attributes of a given font. + * + * @param font The surrounding font + * @return A RtfFont + */ + public override Font Difference(Font font) { + String dFamilyname = font.Familyname; + if (dFamilyname == null || dFamilyname.Trim().Equals("") || Util.EqualsIgnoreCase(dFamilyname.Trim(), "unknown")) { + dFamilyname = this.fontName; + } + + float dSize = font.Size; + if (dSize == Font.UNDEFINED) { + dSize = this.Size; + } + + int dStyle = Font.UNDEFINED; + if (this.Style != Font.UNDEFINED && font.Style != Font.UNDEFINED) { + dStyle = this.Style | font.Style; + } else if (this.Style != Font.UNDEFINED) { + dStyle = this.Style; + } else if (font.Style != Font.UNDEFINED) { + dStyle = font.Style; + } + + Color dColor = font.Color; + if (dColor == null) { + dColor = this.Color; + } + + int dCharset = this.charset; + if(font is RtfFont) { + dCharset = ((RtfFont)font).GetCharset(); + } + + return new RtfFont(dFamilyname, dSize, dStyle, dColor, dCharset); + } + + /** + * The RtfFont is never a standard font. + * + * @since 2.1.0 + */ + public override bool IsStandardFont() { + return false; + } + + /** + * Compares this RtfFont to either a {@link com.lowagie.text.Font} or + * an RtfFont. + * + * @since 2.1.0 + */ + public override int CompareTo(Object obj) { + if (obj == null) { + return -1; + } + if(obj is RtfFont) { + if(this.GetFontName().CompareTo(((RtfFont) obj).GetFontName()) != 0) { + return 1; + } else { + return base.CompareTo(obj); + } + } else if (obj is Font) { + return base.CompareTo(obj); + } else { + return -3; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfFontList.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfFontList.cs new file mode 100644 index 0000000..6dd8901 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfFontList.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfFontList.cs,v 1.6 2008/05/16 19:31:12 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.style { + + /** + * The RtfFontList stores the list of fonts used in the rtf document. It also + * has methods for writing this list to the document + * + * Version: $Id: RtfFontList.cs,v 1.6 2008/05/16 19:31:12 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfFontList : RtfElement, IRtfExtendedElement { + + /** + * Constant for the default font + */ + private static byte[] DEFAULT_FONT = DocWriter.GetISOBytes("\\deff"); + /** + * Constant for the font table + */ + private static byte[] FONT_TABLE = DocWriter.GetISOBytes("\\fonttbl"); + /** + * Constant for the font number + */ + public static byte[] FONT_NUMBER = DocWriter.GetISOBytes("\\f"); + + /** + * The list of fonts + */ + private ArrayList fontList = new ArrayList(); + + /** + * Creates a RtfFontList + * + * @param doc The RtfDocument this RtfFontList belongs to + */ + public RtfFontList(RtfDocument doc) : base(doc) { + fontList.Add(new RtfFont(document, 0)); + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Gets the index of the font in the list of fonts. If the font does not + * exist in the list, it is added. + * + * @param font The font to get the id for + * @return The index of the font + */ + public int GetFontNumber(RtfFont font) { + if(font is RtfParagraphStyle) { + font = new RtfFont(this.document, (RtfParagraphStyle) font); + } + int fontIndex = -1; + for (int i = 0; i < fontList.Count; i++) { + if (fontList[i].Equals(font)) { + fontIndex = i; + } + } + if (fontIndex == -1) { + fontIndex = fontList.Count; + fontList.Add(font); + } + return fontIndex; + } + + /** + * Writes the definition of the font list + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + result.Write(DEFAULT_FONT, 0, DEFAULT_FONT.Length); + result.Write(t = IntToByteArray(0), 0, t.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(FONT_TABLE, 0, FONT_TABLE.Length); + for (int i = 0; i < fontList.Count; i++) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(FONT_NUMBER, 0, FONT_NUMBER.Length); + result.Write(t = IntToByteArray(i), 0, t.Length); + RtfFont rf = (RtfFont) fontList[i]; + rf.WriteDefinition(result); + result.Write(COMMA_DELIMITER, 0, COMMA_DELIMITER.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.WriteByte((byte)'\n'); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfParagraphStyle.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfParagraphStyle.cs new file mode 100644 index 0000000..0bd9966 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfParagraphStyle.cs @@ -0,0 +1,675 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.text; + +namespace iTextSharp.text.rtf.style { + + /** + * The RtfParagraphStyle stores all style/formatting attributes of a RtfParagraph. + * Additionally it also supports the style name system available in RTF. The RtfParagraphStyle + * is a Font and can thus be used as such. To use the stylesheet functionality + * it needs to be set as the font of a Paragraph. Otherwise it will work like a + * RtfFont. It also supports inheritance of styles. + * + * @version $Revision: 1.8 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfParagraphStyle : RtfFont { + + /** + * Constant for left alignment + */ + public static byte[] ALIGN_LEFT = DocWriter.GetISOBytes("\\ql"); + /** + * Constant for right alignment + */ + public static byte[] ALIGN_RIGHT = DocWriter.GetISOBytes("\\qr"); + /** + * Constant for center alignment + */ + public static byte[] ALIGN_CENTER = DocWriter.GetISOBytes("\\qc"); + /** + * Constant for justified alignment + */ + public static byte[] ALIGN_JUSTIFY = DocWriter.GetISOBytes("\\qj"); + /** + * Constant for the first line indentation + */ + public static byte[] FIRST_LINE_INDENT = DocWriter.GetISOBytes("\\fi"); + /** + * Constant for left indentation + */ + public static byte[] INDENT_LEFT = DocWriter.GetISOBytes("\\li"); + /** + * Constant for right indentation + */ + public static byte[] INDENT_RIGHT = DocWriter.GetISOBytes("\\ri"); + /** + * Constant for keeping the paragraph together on one page + */ + public static byte[] KEEP_TOGETHER = DocWriter.GetISOBytes("\\keep"); + /** + * Constant for keeping the paragraph toghether with the next one on one page + */ + public static byte[] KEEP_TOGETHER_WITH_NEXT = DocWriter.GetISOBytes("\\keepn"); + /** + * Constant for the space after the paragraph. + */ + public static byte[] SPACING_AFTER = DocWriter.GetISOBytes("\\sa"); + /** + * Constant for the space before the paragraph. + */ + public static byte[] SPACING_BEFORE = DocWriter.GetISOBytes("\\sb"); + + /** + * The NORMAL/STANDARD style. + */ + public static RtfParagraphStyle STYLE_NORMAL = new RtfParagraphStyle("Normal", "Arial", 12, Font.NORMAL, Color.BLACK); + /** + * The style for level 1 headings. + */ + public static RtfParagraphStyle STYLE_HEADING_1 = new RtfParagraphStyle("heading 1", "Normal"); + /** + * The style for level 2 headings. + */ + public static RtfParagraphStyle STYLE_HEADING_2 = new RtfParagraphStyle("heading 2", "Normal"); + /** + * The style for level 3 headings. + */ + public static RtfParagraphStyle STYLE_HEADING_3 = new RtfParagraphStyle("heading 3", "Normal"); + + /** + * Initialises the properties of the styles. + */ + static RtfParagraphStyle() { + STYLE_HEADING_1.Size = 16; + STYLE_HEADING_1.SetStyle(Font.BOLD); + STYLE_HEADING_2.Size = 14; + STYLE_HEADING_2.SetStyle(Font.BOLDITALIC); + STYLE_HEADING_3.Size = 13; + STYLE_HEADING_3.SetStyle(Font.BOLD); + } + + /** + * No modification has taken place when compared to the RtfParagraphStyle this RtfParagraphStyle + * is based on. These modification markers are used to determine what needs to be + * inherited and what not from the parent RtfParagraphStyle. + */ + private const int MODIFIED_NONE = 0; + /** + * The alignment has been modified. + */ + private const int MODIFIED_ALIGNMENT = 1; + /** + * The left indentation has been modified. + */ + private const int MODIFIED_INDENT_LEFT = 2; + /** + * The right indentation has been modified. + */ + private const int MODIFIED_INDENT_RIGHT = 4; + /** + * The spacing before a paragraph has been modified. + */ + private const int MODIFIED_SPACING_BEFORE = 8; + /** + * The spacing after a paragraph has been modified. + */ + private const int MODIFIED_SPACING_AFTER = 16; + /** + * The font name has been modified. + */ + private const int MODIFIED_FONT_NAME = 32; + /** + * The font style has been modified. + */ + private const int MODIFIED_FONT_SIZE = 64; + /** + * The font size has been modified. + */ + private const int MODIFIED_FONT_STYLE = 128; + /** + * The font colour has been modified. + */ + private const int MODIFIED_FONT_COLOR = 256; + /** + * The line leading has been modified. + */ + private const int MODIFIED_LINE_LEADING = 512; + /** + * The paragraph keep together setting has been modified. + */ + private const int MODIFIED_KEEP_TOGETHER = 1024; + /** + * The paragraph keep together with next setting has been modified. + */ + private const int MODIFIED_KEEP_TOGETHER_WITH_NEXT = 2048; + + /** + * The alignment of the paragraph. + */ + private int alignment = Element.ALIGN_LEFT; + /** + * The indentation for the first line + */ + private int firstLineIndent = 0; + /** + * The left indentation of the paragraph. + */ + private int indentLeft = 0; + /** + * The right indentation of the paragraph. + */ + private int indentRight = 0; + /** + * The spacing before a paragraph. + */ + private int spacingBefore = 0; + /** + * The spacing after a paragraph. + */ + private int spacingAfter = 0; + /** + * The line leading of the paragraph. + */ + private int lineLeading = 0; + /** + * Whether this RtfParagraph must stay on one page. + */ + private bool keepTogether = false; + /** + * Whether this RtfParagraph must stay on the same page as the next paragraph. + */ + private bool keepTogetherWithNext = false; + /** + * The name of this RtfParagraphStyle. + */ + private String styleName = ""; + /** + * The name of the RtfParagraphStyle this RtfParagraphStyle is based on. + */ + private String basedOnName = null; + /** + * The RtfParagraphStyle this RtfParagraphStyle is based on. + */ + private RtfParagraphStyle baseStyle = null; + /** + * Which properties have been modified when compared to the base style. + */ + private int modified = MODIFIED_NONE; + /** + * The number of this RtfParagraphStyle in the stylesheet list. + */ + private int styleNumber = -1; + + /** + * Constructs a new RtfParagraphStyle with the given attributes. + * + * @param styleName The name of this RtfParagraphStyle. + * @param fontName The name of the font to use for this RtfParagraphStyle. + * @param fontSize The size of the font to use for this RtfParagraphStyle. + * @param fontStyle The style of the font to use for this RtfParagraphStyle. + * @param fontColor The colour of the font to use for this RtfParagraphStyle. + */ + public RtfParagraphStyle(String styleName, String fontName, int fontSize, int fontStyle, Color fontColor) : base(null, new RtfFont(fontName, fontSize, fontStyle, fontColor)) { + this.styleName = styleName; + } + + /** + * Constructs a new RtfParagraphStyle that is based on an existing RtfParagraphStyle. + * + * @param styleName The name of this RtfParagraphStyle. + * @param basedOnName The name of the RtfParagraphStyle this RtfParagraphStyle is based on. + */ + public RtfParagraphStyle(String styleName, String basedOnName) : base(null, new Font()) { + this.styleName = styleName; + this.basedOnName = basedOnName; + } + + /** + * Constructs a RtfParagraphStyle from another RtfParagraphStyle. + * + * INTERNAL USE ONLY + * + * @param doc The RtfDocument this RtfParagraphStyle belongs to. + * @param style The RtfParagraphStyle to copy settings from. + */ + public RtfParagraphStyle(RtfDocument doc, RtfParagraphStyle style) : base(doc, style) { + this.document = doc; + this.styleName = style.GetStyleName(); + this.alignment = style.GetAlignment(); + this.firstLineIndent = (int)(style.GetFirstLineIndent() * RtfElement.TWIPS_FACTOR); + this.indentLeft = (int) (style.GetIndentLeft() * RtfElement.TWIPS_FACTOR); + this.indentRight = (int) (style.GetIndentRight() * RtfElement.TWIPS_FACTOR); + this.spacingBefore = (int) (style.GetSpacingBefore() * RtfElement.TWIPS_FACTOR); + this.spacingAfter = (int) (style.GetSpacingAfter() * RtfElement.TWIPS_FACTOR); + this.lineLeading = (int) (style.GetLineLeading() * RtfElement.TWIPS_FACTOR); + this.keepTogether = style.GetKeepTogether(); + this.keepTogetherWithNext = style.GetKeepTogetherWithNext(); + this.basedOnName = style.basedOnName; + this.modified = style.modified; + this.styleNumber = style.GetStyleNumber(); + + if (this.document != null) { + SetRtfDocument(this.document); + } + } + + /** + * Gets the name of this RtfParagraphStyle. + * + * @return The name of this RtfParagraphStyle. + */ + public String GetStyleName() { + return this.styleName; + } + + /** + * Gets the name of the RtfParagraphStyle this RtfParagraphStyle is based on. + * + * @return The name of the base RtfParagraphStyle. + */ + public String GetBasedOnName() { + return this.basedOnName; + } + + /** + * Gets the alignment of this RtfParagraphStyle. + * + * @return The alignment of this RtfParagraphStyle. + */ + public int GetAlignment() { + return this.alignment; + } + + /** + * Sets the alignment of this RtfParagraphStyle. + * + * @param alignment The alignment to use. + */ + public void SetAlignment(int alignment) { + this.modified = this.modified | MODIFIED_ALIGNMENT; + this.alignment = alignment; + } + + /** + * Gets the first line indentation of this RtfParagraphStyle. + * + * @return The first line indentation of this RtfParagraphStyle. + */ + public int GetFirstLineIndent() { + return this.firstLineIndent; + } + + /** + * Sets the first line indententation of this RtfParagraphStyle. It + * is relative to the left indentation. + * + * @param firstLineIndent The first line indentation to use. + */ + public void SetFirstLineIndent(int firstLineIndent) { + this.firstLineIndent = firstLineIndent; + } + + /** + * Gets the left indentation of this RtfParagraphStyle. + * + * @return The left indentation of this RtfParagraphStyle. + */ + public int GetIndentLeft() { + return this.indentLeft; + } + + /** + * Sets the left indentation of this RtfParagraphStyle. + * + * @param indentLeft The left indentation to use. + */ + public void SetIndentLeft(int indentLeft) { + this.modified = this.modified | MODIFIED_INDENT_LEFT; + this.indentLeft = indentLeft; + } + + /** + * Gets the right indentation of this RtfParagraphStyle. + * + * @return The right indentation of this RtfParagraphStyle. + */ + public int GetIndentRight() { + return this.indentRight; + } + + /** + * Sets the right indentation of this RtfParagraphStyle. + * + * @param indentRight The right indentation to use. + */ + public void SetIndentRight(int indentRight) { + this.modified = this.modified | MODIFIED_INDENT_RIGHT; + this.indentRight = indentRight; + } + + /** + * Gets the space before the paragraph of this RtfParagraphStyle.. + * + * @return The space before the paragraph. + */ + public int GetSpacingBefore() { + return this.spacingBefore; + } + + /** + * Sets the space before the paragraph of this RtfParagraphStyle. + * + * @param spacingBefore The space before to use. + */ + public void SetSpacingBefore(int spacingBefore) { + this.modified = this.modified | MODIFIED_SPACING_BEFORE; + this.spacingBefore = spacingBefore; + } + + /** + * Gets the space after the paragraph of this RtfParagraphStyle. + * + * @return The space after the paragraph. + */ + public int GetSpacingAfter() { + return this.spacingAfter; + } + + /** + * Sets the space after the paragraph of this RtfParagraphStyle. + * + * @param spacingAfter The space after to use. + */ + public void SetSpacingAfter(int spacingAfter) { + this.modified = this.modified | MODIFIED_SPACING_AFTER; + this.spacingAfter = spacingAfter; + } + + /** + * Sets the font name of this RtfParagraphStyle. + * + * @param fontName The font name to use + */ + public override void SetFontName(String fontName) { + this.modified = this.modified | MODIFIED_FONT_NAME; + base.SetFontName(fontName); + } + + /** + * Sets the font size of this RtfParagraphStyle. + * + * @param fontSize The font size to use. + */ + public override float Size { + set { + this.modified = this.modified | MODIFIED_FONT_SIZE; + base.Size = value; + } + } + + /** + * Sets the font style of this RtfParagraphStyle. + * + * @param fontStyle The font style to use. + */ + public override void SetStyle(int fontStyle) { + this.modified = this.modified | MODIFIED_FONT_STYLE; + base.SetStyle(fontStyle); + } + + /** + * Sets the colour of this RtfParagraphStyle. + * + * @param color The Color to use. + */ + public void SetColor(Color color) { + this.modified = this.modified | MODIFIED_FONT_COLOR; + base.Color = color; + } + + /** + * Gets the line leading of this RtfParagraphStyle. + * + * @return The line leading of this RtfParagraphStyle. + */ + public int GetLineLeading() { + return this.lineLeading; + } + + /** + * Sets the line leading of this RtfParagraphStyle. + * + * @param lineLeading The line leading to use. + */ + public void SetLineLeading(int lineLeading) { + this.lineLeading = lineLeading; + this.modified = this.modified | MODIFIED_LINE_LEADING; + } + + /** + * Gets whether the lines in the paragraph should be kept together in + * this RtfParagraphStyle. + * + * @return Whether the lines in the paragraph should be kept together. + */ + public bool GetKeepTogether() { + return this.keepTogether; + } + + /** + * Sets whether the lines in the paragraph should be kept together in + * this RtfParagraphStyle. + * + * @param keepTogether Whether the lines in the paragraph should be kept together. + */ + public void SetKeepTogether(bool keepTogether) { + this.keepTogether = keepTogether; + this.modified = this.modified | MODIFIED_KEEP_TOGETHER; + } + + /** + * Gets whether the paragraph should be kept toggether with the next in + * this RtfParagraphStyle. + * + * @return Whether the paragraph should be kept together with the next. + */ + public bool GetKeepTogetherWithNext() { + return this.keepTogetherWithNext; + } + + /** + * Sets whether the paragraph should be kept together with the next in + * this RtfParagraphStyle. + * + * @param keepTogetherWithNext Whether the paragraph should be kept together with the next. + */ + public void SetKeepTogetherWithNext(bool keepTogetherWithNext) { + this.keepTogetherWithNext = keepTogetherWithNext; + this.modified = this.modified | MODIFIED_KEEP_TOGETHER_WITH_NEXT; + } + + /** + * Handles the inheritance of paragraph style settings. All settings that + * have not been modified will be inherited from the base RtfParagraphStyle. + * If this RtfParagraphStyle is not based on another one, then nothing happens. + */ + public void HandleInheritance() { + if (this.basedOnName != null && this.document.GetDocumentHeader().GetRtfParagraphStyle(this.basedOnName) != null) { + this.baseStyle = this.document.GetDocumentHeader().GetRtfParagraphStyle(this.basedOnName); + this.baseStyle.HandleInheritance(); + if (!((this.modified & MODIFIED_ALIGNMENT) == MODIFIED_ALIGNMENT)) { + this.alignment = this.baseStyle.GetAlignment(); + } + if (!((this.modified & MODIFIED_INDENT_LEFT) == MODIFIED_INDENT_LEFT)) { + this.indentLeft = this.baseStyle.GetIndentLeft(); + } + if (!((this.modified & MODIFIED_INDENT_RIGHT) == MODIFIED_INDENT_RIGHT)) { + this.indentRight = this.baseStyle.GetIndentRight(); + } + if (!((this.modified & MODIFIED_SPACING_BEFORE) == MODIFIED_SPACING_BEFORE)) { + this.spacingBefore = this.baseStyle.GetSpacingBefore(); + } + if (!((this.modified & MODIFIED_SPACING_AFTER) == MODIFIED_SPACING_AFTER)) { + this.spacingAfter = this.baseStyle.GetSpacingAfter(); + } + if (!((this.modified & MODIFIED_FONT_NAME) == MODIFIED_FONT_NAME)) { + SetFontName(this.baseStyle.GetFontName()); + } + if (!((this.modified & MODIFIED_FONT_SIZE) == MODIFIED_FONT_SIZE)) { + Size = this.baseStyle.GetFontSize(); + } + if (!((this.modified & MODIFIED_FONT_STYLE) == MODIFIED_FONT_STYLE)) { + SetStyle(this.baseStyle.GetFontStyle()); + } + if (!((this.modified & MODIFIED_FONT_COLOR) == MODIFIED_FONT_COLOR)) { + SetColor(this.baseStyle.Color); + } + if (!((this.modified & MODIFIED_LINE_LEADING) == MODIFIED_LINE_LEADING)) { + SetLineLeading(this.baseStyle.GetLineLeading()); + } + if (!((this.modified & MODIFIED_KEEP_TOGETHER) == MODIFIED_KEEP_TOGETHER)) { + SetKeepTogether(this.baseStyle.GetKeepTogether()); + } + if (!((this.modified & MODIFIED_KEEP_TOGETHER_WITH_NEXT) == MODIFIED_KEEP_TOGETHER_WITH_NEXT)) { + SetKeepTogetherWithNext(this.baseStyle.GetKeepTogetherWithNext()); + } + } + } + + /** + * Writes the settings of this RtfParagraphStyle. + * + */ + private void WriteParagraphSettings(Stream result) { + byte[] t; + if (this.keepTogether) { + result.Write(t = RtfParagraphStyle.KEEP_TOGETHER, 0, t.Length); + } + if (this.keepTogetherWithNext) { + result.Write(t = RtfParagraphStyle.KEEP_TOGETHER_WITH_NEXT, 0, t.Length); + } + switch (alignment) { + case Element.ALIGN_LEFT: + result.Write(t = RtfParagraphStyle.ALIGN_LEFT, 0, t.Length); + break; + case Element.ALIGN_RIGHT: + result.Write(t = RtfParagraphStyle.ALIGN_RIGHT, 0, t.Length); + break; + case Element.ALIGN_CENTER: + result.Write(t = RtfParagraphStyle.ALIGN_CENTER, 0, t.Length); + break; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + result.Write(t = RtfParagraphStyle.ALIGN_JUSTIFY, 0, t.Length); + break; + } + result.Write(t = FIRST_LINE_INDENT, 0, t.Length); + result.Write(t = IntToByteArray(this.firstLineIndent), 0, t.Length); + result.Write(t = RtfParagraphStyle.INDENT_LEFT, 0, t.Length); + result.Write(t = IntToByteArray(indentLeft), 0, t.Length); + result.Write(t = RtfParagraphStyle.INDENT_RIGHT, 0, t.Length); + result.Write(t = IntToByteArray(indentRight), 0, t.Length); + if (this.spacingBefore > 0) { + result.Write(t = RtfParagraphStyle.SPACING_BEFORE, 0, t.Length); + result.Write(t = IntToByteArray(this.spacingBefore), 0, t.Length); + } + if (this.spacingAfter > 0) { + result.Write(t = RtfParagraphStyle.SPACING_AFTER, 0, t.Length); + result.Write(t = IntToByteArray(this.spacingAfter), 0, t.Length); + } + if (this.lineLeading > 0) { + result.Write(t = RtfParagraph.LINE_SPACING, 0, t.Length); + result.Write(t = IntToByteArray(this.lineLeading), 0, t.Length); + } + } + + /** + * Writes the definition of this RtfParagraphStyle for the stylesheet list. + */ + public override void WriteDefinition(Stream result) { + byte[] t; + result.Write(t = DocWriter.GetISOBytes("{"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\style"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\s"), 0, t.Length); + result.Write(t = IntToByteArray(this.styleNumber), 0, t.Length); + result.Write(t = RtfElement.DELIMITER, 0, t.Length); + WriteParagraphSettings(result); + base.WriteBegin(result); + result.Write(t = RtfElement.DELIMITER, 0, t.Length); + result.Write(t = DocWriter.GetISOBytes(this.styleName), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes(";"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("}"), 0, t.Length); + if (this.document.GetDocumentSettings().IsOutputDebugLineBreaks()) { + result.WriteByte((byte)'\n'); + } + } + + /** + * Writes the start information of this RtfParagraphStyle. + * + * @param result The OutputStream to write to. + * @throws IOException On i/o errors. + */ + public override void WriteBegin(Stream result) { + byte[] t; + result.Write(t = DocWriter.GetISOBytes("\\s"), 0, t.Length); + result.Write(t = IntToByteArray(this.styleNumber), 0, t.Length); + WriteParagraphSettings(result); + } + + /** + * Unused + */ + public override void WriteEnd(Stream result) { + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Tests whether two RtfParagraphStyles are equal. Equality + * is determined via the name. + */ + public override bool Equals(Object o) { + if (!(o is RtfParagraphStyle)) { + return false; + } + RtfParagraphStyle paragraphStyle = (RtfParagraphStyle) o; + bool result = this.GetStyleName().Equals(paragraphStyle.GetStyleName()); + return result; + } + + /** + * Gets the hash code of this RtfParagraphStyle. + */ + public override int GetHashCode() { + return this.styleName.GetHashCode(); + } + + /** + * Gets the number of this RtfParagraphStyle in the stylesheet list. + * + * @return The number of this RtfParagraphStyle in the stylesheet list. + */ + private int GetStyleNumber() { + return this.styleNumber; + } + + /** + * Sets the number of this RtfParagraphStyle in the stylesheet list. + * + * @param styleNumber The number to use. + */ + protected internal void SetStyleNumber(int styleNumber) { + this.styleNumber = styleNumber; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfStyleTypes.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfStyleTypes.cs new file mode 100644 index 0000000..7ca93ff --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfStyleTypes.cs @@ -0,0 +1,81 @@ +using System; +/* + * $Id: RtfStyleTypes.cs,v 1.1 2008/02/14 14:52:32 psoares33 Exp $ + * + * Copyright 2007 by Howard Shank (hgshank@yahoo.com) + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.style { + /** + * RtfStyleTypes contains the different types of Stylesheet entries + * that exist in RTF. + * + * @author Howard Shank (hgshank@yahoo.com) + * @since 2.0.8 + */ + public sealed class RtfStyleTypes { + /** + * Indicates paragraph style. + */ + public const int PARAGRAPH = 0; + /** + * Indicates character style. + */ + public const int CHARACTER = 0; + /** + * Indicates section style. + */ + public const int SECTION = 2; + /** + * Indicates Table style. + */ + public const int TABLE = 3; + /** + * Indicates table definition style. + */ + public const int TABLE_STYLE_DEFINITION = 4; + } +} diff --git a/iTechSharp/iTextSharp/text/rtf/style/RtfStylesheetList.cs b/iTechSharp/iTextSharp/text/rtf/style/RtfStylesheetList.cs new file mode 100644 index 0000000..e4be54e --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/style/RtfStylesheetList.cs @@ -0,0 +1,110 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; + +namespace iTextSharp.text.rtf.style { + + /** + * The RtfStylesheetList stores the RtfParagraphStyles that are used in the document. + * + * @version $Revision: 1.5 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfStylesheetList : RtfElement, IRtfExtendedElement { + + /** + * The Hashtable containing the RtfParagraphStyles. + */ + private Hashtable styleMap = null; + /** + * Whether the default settings have been loaded. + */ + private bool defaultsLoaded = false; + + /** + * Constructs a new RtfStylesheetList for the RtfDocument. + * + * @param doc The RtfDocument this RtfStylesheetList belongs to. + */ + public RtfStylesheetList(RtfDocument doc) : base(doc) { + this.styleMap = new Hashtable(); + } + + /** + * unused + */ + public override void WriteContent(Stream outp) { + } + + /** + * Register a RtfParagraphStyle with this RtfStylesheetList. + * + * @param rtfParagraphStyle The RtfParagraphStyle to add. + */ + public void RegisterParagraphStyle(RtfParagraphStyle rtfParagraphStyle) { + RtfParagraphStyle tempStyle = new RtfParagraphStyle(this.document, rtfParagraphStyle); + tempStyle.HandleInheritance(); + tempStyle.SetStyleNumber(this.styleMap.Count); + this.styleMap[tempStyle.GetStyleName()] = tempStyle; + } + + /** + * Registers all default styles. If styles with the given name have already been registered, + * then they are NOT overwritten. + */ + private void RegisterDefaultStyles() { + defaultsLoaded = true; + if (!this.styleMap.ContainsKey(RtfParagraphStyle.STYLE_NORMAL.GetStyleName())) { + RegisterParagraphStyle(RtfParagraphStyle.STYLE_NORMAL); + } + if (!this.styleMap.ContainsKey(RtfParagraphStyle.STYLE_HEADING_1.GetStyleName())) { + RegisterParagraphStyle(RtfParagraphStyle.STYLE_HEADING_1); + } + if (!this.styleMap.ContainsKey(RtfParagraphStyle.STYLE_HEADING_2.GetStyleName())) { + RegisterParagraphStyle(RtfParagraphStyle.STYLE_HEADING_2); + } + if (!this.styleMap.ContainsKey(RtfParagraphStyle.STYLE_HEADING_3.GetStyleName())) { + RegisterParagraphStyle(RtfParagraphStyle.STYLE_HEADING_3); + } + } + + /** + * Gets the RtfParagraphStyle with the given name. Makes sure that the defaults + * have been loaded. + * + * @param styleName The name of the RtfParagraphStyle to get. + * @return The RtfParagraphStyle with the given name or null. + */ + public RtfParagraphStyle GetRtfParagraphStyle(String styleName) { + if (!defaultsLoaded) { + RegisterDefaultStyles(); + } + if (this.styleMap.ContainsKey(styleName)) { + return (RtfParagraphStyle) this.styleMap[styleName]; + } else { + return null; + } + } + + /** + * Writes the definition of the stylesheet list. + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + result.Write(t = DocWriter.GetISOBytes("{"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\stylesheet"), 0, t.Length); + result.Write(t = RtfElement.DELIMITER, 0, t.Length); + if (this.document.GetDocumentSettings().IsOutputDebugLineBreaks()) { + result.Write(t = DocWriter.GetISOBytes("\n"), 0, t.Length); + } + foreach (RtfParagraphStyle rps in this.styleMap.Values) + rps.WriteDefinition(result); + result.Write(t = DocWriter.GetISOBytes("}"), 0, t.Length); + if (this.document.GetDocumentSettings().IsOutputDebugLineBreaks()) { + result.WriteByte((byte)'\n'); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/table/RtfBorder.cs b/iTechSharp/iTextSharp/text/rtf/table/RtfBorder.cs new file mode 100644 index 0000000..1179ce2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/table/RtfBorder.cs @@ -0,0 +1,561 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.style; +/* + * $Id: RtfBorder.cs,v 1.6 2008/05/16 19:31:18 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.table { + + /** + * The RtfBorder handle one row or cell border. + * INTERNAL USE ONLY + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Unknown + */ + public class RtfBorder : RtfElement { + + /** + * Constant for the left row border + */ + protected internal static byte[] ROW_BORDER_LEFT = DocWriter.GetISOBytes("\\trbrdrl"); + /** + * Constant for the top row border + */ + protected internal static byte[] ROW_BORDER_TOP = DocWriter.GetISOBytes("\\trbrdrt"); + /** + * Constant for the right row border + */ + protected internal static byte[] ROW_BORDER_RIGHT = DocWriter.GetISOBytes("\\trbrdrr"); + /** + * Constant for the bottom row border + */ + protected internal static byte[] ROW_BORDER_BOTTOM = DocWriter.GetISOBytes("\\trbrdrb"); + /** + * Constant for the horizontal line + */ + protected internal static byte[] ROW_BORDER_HORIZONTAL = DocWriter.GetISOBytes("\\trbrdrh"); + /** + * Constant for the vertical line + */ + protected internal static byte[] ROW_BORDER_VERTICAL = DocWriter.GetISOBytes("\\trbrdrv"); + /** + * Constant for the left cell border + */ + protected internal static byte[] CELL_BORDER_LEFT = DocWriter.GetISOBytes("\\clbrdrl"); + /** + * Constant for the top cell border + */ + protected internal static byte[] CELL_BORDER_TOP = DocWriter.GetISOBytes("\\clbrdrt"); + /** + * Constant for the right cell border + */ + protected internal static byte[] CELL_BORDER_RIGHT = DocWriter.GetISOBytes("\\clbrdrr"); + /** + * Constant for the bottom cell border + */ + protected internal static byte[] CELL_BORDER_BOTTOM = DocWriter.GetISOBytes("\\clbrdrb"); + /** + * Constant for the border width + */ + protected internal static byte[] BORDER_WIDTH = DocWriter.GetISOBytes("\\brdrw"); + /** + * Constant for the border colour number + */ + protected internal static byte[] BORDER_COLOR_NUMBER = DocWriter.GetISOBytes("\\brdrcf"); + /** + * Constant for the single border style + */ + protected internal static byte[] BORDER_STYLE_SINGLE = DocWriter.GetISOBytes("\\brdrs"); + /** + * Constant for the double thick border style + */ + protected internal static byte[] BORDER_STYLE_DOUBLE_THICK = DocWriter.GetISOBytes("\\brdrth"); + /** + * Constant for the shadowed border style + */ + protected internal static byte[] BORDER_STYLE_SHADOWED = DocWriter.GetISOBytes("\\brdrsh"); + /** + * Constant for the dotted border style + */ + protected internal static byte[] BORDER_STYLE_DOTTED = DocWriter.GetISOBytes("\\brdrdot"); + /** + * Constant for the dashed border style + */ + protected internal static byte[] BORDER_STYLE_DASHED = DocWriter.GetISOBytes("\\brdrdash"); + /** + * Constant for the hairline border style + */ + protected internal static byte[] BORDER_STYLE_HAIRLINE = DocWriter.GetISOBytes("\\brdrhair"); + /** + * Constant for the double border style + */ + protected internal static byte[] BORDER_STYLE_DOUBLE = DocWriter.GetISOBytes("\\brdrdb"); + /** + * Constant for the dot dash border style + */ + protected internal static byte[] BORDER_STYLE_DOT_DASH = DocWriter.GetISOBytes("\\brdrdashd"); + /** + * Constant for the dot dot dash border style + */ + protected internal static byte[] BORDER_STYLE_DOT_DOT_DASH = DocWriter.GetISOBytes("\\brdrdashdd"); + /** + * Constant for the triple border style + */ + protected internal static byte[] BORDER_STYLE_TRIPLE = DocWriter.GetISOBytes("\\brdrtriple"); + /** + * Constant for the thick thin border style + */ + protected internal static byte[] BORDER_STYLE_THICK_THIN = DocWriter.GetISOBytes("\\brdrtnthsg"); + /** + * Constant for the thin thick border style + */ + protected internal static byte[] BORDER_STYLE_THIN_THICK = DocWriter.GetISOBytes("\\brdrthtnsg"); + /** + * Constant for the thin thick thin border style + */ + protected internal static byte[] BORDER_STYLE_THIN_THICK_THIN = DocWriter.GetISOBytes("\\brdrtnthtnsg"); + /** + * Constant for the thick thin medium border style + */ + protected internal static byte[] BORDER_STYLE_THICK_THIN_MED = DocWriter.GetISOBytes("\\brdrtnthmg"); + /** + * Constant for the thin thick medium border style + */ + protected internal static byte[] BORDER_STYLE_THIN_THICK_MED = DocWriter.GetISOBytes("\\brdrthtnmg"); + /** + * Constant for the thin thick thin medium border style + */ + protected internal static byte[] BORDER_STYLE_THIN_THICK_THIN_MED = DocWriter.GetISOBytes("\\brdrtnthtnmg"); + /** + * Constant for the thick thin large border style + */ + protected internal static byte[] BORDER_STYLE_THICK_THIN_LARGE = DocWriter.GetISOBytes("\\brdrtnthlg"); + /** + * Constant for the thin thick large border style + */ + protected internal static byte[] BORDER_STYLE_THIN_THICK_LARGE = DocWriter.GetISOBytes("\\brdrthtnlg"); + /** + * Constant for the thin thick thin large border style + */ + protected internal static byte[] BORDER_STYLE_THIN_THICK_THIN_LARGE = DocWriter.GetISOBytes("\\brdrtnthtnlg"); + /** + * Constant for the wavy border style + */ + protected internal static byte[] BORDER_STYLE_WAVY = DocWriter.GetISOBytes("\\brdrwavy"); + /** + * Constant for the double wavy border style + */ + protected internal static byte[] BORDER_STYLE_DOUBLE_WAVY = DocWriter.GetISOBytes("\\brdrwavydb"); + /** + * Constant for the striped border style + */ + protected internal static byte[] BORDER_STYLE_STRIPED = DocWriter.GetISOBytes("\\brdrdashdotstr"); + /** + * Constant for the embossed border style + */ + protected internal static byte[] BORDER_STYLE_EMBOSS = DocWriter.GetISOBytes("\\brdremboss"); + /** + * Constant for the engraved border style + */ + protected internal static byte[] BORDER_STYLE_ENGRAVE = DocWriter.GetISOBytes("\\brdrengrave"); + + /** + * Constant for a row border + */ + protected internal const int ROW_BORDER = 1; + /** + * Constant for a cell border + */ + protected internal const int CELL_BORDER = 2; + + /** + * This border is no border :-) + */ + protected internal const int NO_BORDER = 0; + /** + * Constant for a left border + */ + protected internal const int LEFT_BORDER = 1; + /** + * Constant for a top border + */ + protected internal const int TOP_BORDER = 2; + /** + * Constant for a right border + */ + protected internal const int RIGHT_BORDER = 4; + /** + * Constant for a bottom border + */ + protected internal const int BOTTOM_BORDER = 8; + /** + * Constant for a box (left, top, right, bottom) border + */ + protected internal const int BOX_BORDER = 15; + /** + * Constant for a vertical line + */ + protected internal const int VERTICAL_BORDER = 16; + /** + * Constant for a horizontal line + */ + protected internal const int HORIZONTAL_BORDER = 32; + + /** + * Constant for a border with no border + */ + public const int BORDER_NONE = 0; + /** + * Constant for a single border + */ + public const int BORDER_SINGLE = 1; + /** + * Constant for a double thick border + */ + public const int BORDER_DOUBLE_THICK = 2; + /** + * Constant for a shadowed border + */ + public const int BORDER_SHADOWED = 3; + /** + * Constant for a dotted border + */ + public const int BORDER_DOTTED = 4; + /** + * Constant for a dashed border + */ + public const int BORDER_DASHED = 5; + /** + * Constant for a hairline border + */ + public const int BORDER_HAIRLINE = 6; + /** + * Constant for a double border + */ + public const int BORDER_DOUBLE = 7; + /** + * Constant for a dot dash border + */ + public const int BORDER_DOT_DASH = 8; + /** + * Constant for a dot dot dash border + */ + public const int BORDER_DOT_DOT_DASH = 9; + /** + * Constant for a triple border + */ + public const int BORDER_TRIPLE = 10; + /** + * Constant for a thick thin border + */ + public const int BORDER_THICK_THIN = 11; + /** + * Constant for a thin thick border + */ + public const int BORDER_THIN_THICK = 12; + /** + * Constant for a thin thick thin border + */ + public const int BORDER_THIN_THICK_THIN = 13; + /** + * Constant for a thick thin medium border + */ + public const int BORDER_THICK_THIN_MED = 14; + /** + * Constant for a thin thick medium border + */ + public const int BORDER_THIN_THICK_MED = 15; + /** + * Constant for a thin thick thin medium border + */ + public const int BORDER_THIN_THICK_THIN_MED = 16; + /** + * Constant for a thick thin large border + */ + public const int BORDER_THICK_THIN_LARGE = 17; + /** + * Constant for a thin thick large border + */ + public const int BORDER_THIN_THICK_LARGE = 18; + /** + * Constant for a thin thick thin large border + */ + public const int BORDER_THIN_THICK_THIN_LARGE = 19; + /** + * Constant for a wavy border + */ + public const int BORDER_WAVY = 20; + /** + * Constant for a double wavy border + */ + public const int BORDER_DOUBLE_WAVY = 21; + /** + * Constant for a striped border + */ + public const int BORDER_STRIPED = 22; + /** + * Constant for an embossed border + */ + public const int BORDER_EMBOSS = 23; + /** + * Constant for an engraved border + */ + public const int BORDER_ENGRAVE = 24; + + /** + * The type of this RtfBorder + */ + private int borderType = ROW_BORDER; + /** + * The position of this RtfBorder + */ + private int borderPosition = NO_BORDER; + /** + * The style of this RtfBorder + */ + private int borderStyle = BORDER_NONE; + /** + * The width of this RtfBorder + */ + private int borderWidth = 20; + /** + * The colour of this RtfBorder + */ + private RtfColor borderColor = null; + + /** + * Makes a copy of the given RtfBorder + * + * @param doc The RtfDocument this RtfBorder belongs to + * @param borderType The border type of this RtfBorder + * @param border The RtfBorder to copy + */ + protected internal RtfBorder(RtfDocument doc, int borderType, RtfBorder border) : base(doc) { + this.borderType = borderType; + this.borderPosition = border.GetBorderPosition(); + this.borderStyle = border.GetBorderStyle(); + this.borderWidth = border.GetBorderWidth(); + this.borderColor = new RtfColor(this.document, border.GetBorderColor()); + } + + /** + * Constructs a RtfBorder + * + * @param doc The RtfDocument this RtfBorder belongs to + * @param borderType The type of border this RtfBorder is + * @param borderPosition The position of this RtfBorder + * @param borderStyle The style of this RtfBorder + * @param borderWidth The width of this RtfBorder + * @param borderColor The colour of this RtfBorder + */ + protected internal RtfBorder(RtfDocument doc, int borderType, int borderPosition, int borderStyle, float borderWidth, Color borderColor) : base(doc) { + this.borderType = borderType; + this.borderPosition = borderPosition; + this.borderStyle = borderStyle; + this.borderWidth = (int) Math.Min((borderWidth * TWIPS_FACTOR), 75); + if (this.borderWidth == 0) { + this.borderStyle = BORDER_NONE; + } + if (borderColor == null) { + this.borderColor = new RtfColor(this.document, new Color(0, 0, 0)); + } else { + this.borderColor = new RtfColor(this.document, borderColor); + } + } + + /** + * Writes the RtfBorder settings + */ + public override void WriteContent(Stream result) { + if (this.borderStyle == BORDER_NONE || this.borderPosition == NO_BORDER || this.borderWidth == 0) { + return; + } + byte[] t; + if (this.borderType == ROW_BORDER) { + switch (this.borderPosition) { + case LEFT_BORDER: + result.Write(ROW_BORDER_LEFT, 0, ROW_BORDER_LEFT.Length); + break; + case TOP_BORDER: + result.Write(ROW_BORDER_TOP, 0, ROW_BORDER_TOP.Length); + break; + case RIGHT_BORDER: + result.Write(ROW_BORDER_RIGHT, 0, ROW_BORDER_RIGHT.Length); + break; + case BOTTOM_BORDER: + result.Write(ROW_BORDER_BOTTOM, 0, ROW_BORDER_BOTTOM.Length); + break; + case HORIZONTAL_BORDER: + result.Write(ROW_BORDER_HORIZONTAL, 0, ROW_BORDER_HORIZONTAL.Length); + break; + case VERTICAL_BORDER: + result.Write(ROW_BORDER_VERTICAL, 0, ROW_BORDER_VERTICAL.Length); + break; + default: + return; + } + result.Write(t = WriteBorderStyle(), 0, t.Length); + result.Write(BORDER_WIDTH, 0, BORDER_WIDTH.Length); + result.Write(t = IntToByteArray(this.borderWidth), 0, t.Length); + result.Write(BORDER_COLOR_NUMBER, 0, BORDER_COLOR_NUMBER.Length); + result.Write(t = IntToByteArray(this.borderColor.GetColorNumber()), 0, t.Length); + result.WriteByte((byte)'\n'); + } else if (this.borderType == CELL_BORDER) { + switch (this.borderPosition) { + case LEFT_BORDER: + result.Write(CELL_BORDER_LEFT, 0, CELL_BORDER_LEFT.Length); + break; + case TOP_BORDER: + result.Write(CELL_BORDER_TOP, 0, CELL_BORDER_TOP.Length); + break; + case RIGHT_BORDER: + result.Write(CELL_BORDER_RIGHT, 0, CELL_BORDER_RIGHT.Length); + break; + case BOTTOM_BORDER: + result.Write(CELL_BORDER_BOTTOM, 0, CELL_BORDER_BOTTOM.Length); + break; + default: + return; + } + result.Write(t = WriteBorderStyle(), 0, t.Length); + result.Write(BORDER_WIDTH, 0, BORDER_WIDTH.Length); + result.Write(t = IntToByteArray(this.borderWidth), 0, t.Length); + result.Write(BORDER_COLOR_NUMBER, 0, BORDER_COLOR_NUMBER.Length); + result.Write(t = IntToByteArray(this.borderColor.GetColorNumber()), 0, t.Length); + result.WriteByte((byte)'\n'); + } + } + + /** + * Writes the style of this RtfBorder + * + * @return A byte array containing the style of this RtfBorder + */ + private byte[] WriteBorderStyle() { + switch (this.borderStyle) { + case BORDER_NONE : return new byte[0]; + case BORDER_SINGLE : return BORDER_STYLE_SINGLE; + case BORDER_DOUBLE_THICK : return BORDER_STYLE_DOUBLE_THICK; + case BORDER_SHADOWED : return BORDER_STYLE_SHADOWED; + case BORDER_DOTTED : return BORDER_STYLE_DOTTED; + case BORDER_DASHED : return BORDER_STYLE_DASHED; + case BORDER_HAIRLINE : return BORDER_STYLE_HAIRLINE; + case BORDER_DOUBLE : return BORDER_STYLE_DOUBLE; + case BORDER_DOT_DASH : return BORDER_STYLE_DOT_DASH; + case BORDER_DOT_DOT_DASH : return BORDER_STYLE_DOT_DOT_DASH; + case BORDER_TRIPLE : return BORDER_STYLE_TRIPLE; + case BORDER_THICK_THIN : return BORDER_STYLE_THICK_THIN; + case BORDER_THIN_THICK : return BORDER_STYLE_THIN_THICK; + case BORDER_THIN_THICK_THIN : return BORDER_STYLE_THIN_THICK_THIN; + case BORDER_THICK_THIN_MED : return BORDER_STYLE_THICK_THIN_MED; + case BORDER_THIN_THICK_MED : return BORDER_STYLE_THIN_THICK_MED; + case BORDER_THIN_THICK_THIN_MED : return BORDER_STYLE_THIN_THICK_THIN_MED; + case BORDER_THICK_THIN_LARGE : return BORDER_STYLE_THICK_THIN_LARGE; + case BORDER_THIN_THICK_LARGE : return BORDER_STYLE_THIN_THICK_LARGE; + case BORDER_THIN_THICK_THIN_LARGE : return BORDER_STYLE_THIN_THICK_THIN_LARGE; + case BORDER_WAVY : return BORDER_STYLE_WAVY; + case BORDER_DOUBLE_WAVY : return BORDER_STYLE_DOUBLE_WAVY; + case BORDER_STRIPED : return BORDER_STYLE_STRIPED; + case BORDER_EMBOSS : return BORDER_STYLE_EMBOSS; + case BORDER_ENGRAVE : return BORDER_STYLE_ENGRAVE; + default : return BORDER_STYLE_SINGLE; + } + } + + /** + * Gets the colour of this RtfBorder + * + * @return Returns RtfColor of this RtfBorder + */ + protected RtfColor GetBorderColor() { + return borderColor; + } + + /** + * Gets the position of this RtfBorder + * @return Returns the position of this RtfBorder + */ + protected int GetBorderPosition() { + return borderPosition; + } + + /** + * Gets the style of this RtfBorder + * + * @return Returns the style of this RtfBorder + */ + protected int GetBorderStyle() { + return borderStyle; + } + + /** + * Gets the type of this RtfBorder + * + * @return Returns the type of this RtfBorder + */ + protected int GetBorderType() { + return borderType; + } + + /** + * Gets the width of this RtfBorder + * + * @return Returns the width of this RtfBorder + */ + protected int GetBorderWidth() { + return borderWidth; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/table/RtfBorderGroup.cs b/iTechSharp/iTextSharp/text/rtf/table/RtfBorderGroup.cs new file mode 100644 index 0000000..d3a7f5d --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/table/RtfBorderGroup.cs @@ -0,0 +1,213 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfBorderGroup.cs,v 1.5 2008/05/16 19:31:18 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.table { + + /** + * The RtfBorderGroup represents a collection of RtfBorders to use in a RtfCell + * or RtfTable. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfBorderGroup : RtfElement { + /** + * The type of borders this RtfBorderGroup contains. + * RtfBorder.ROW_BORDER or RtfBorder.CELL_BORDER + */ + private int borderType = RtfBorder.ROW_BORDER; + /** + * The borders in this RtfBorderGroup + */ + private Hashtable borders = null; + + /** + * Constructs an empty RtfBorderGroup. + */ + public RtfBorderGroup() : base(null) { + this.borders = new Hashtable(); + } + + /** + * Constructs a RtfBorderGroup with on border style for multiple borders. + * + * @param bordersToAdd The borders to add (Rectangle.LEFT, Rectangle.RIGHT, Rectangle.TOP, Rectangle.BOTTOM, Rectangle.BOX) + * @param borderStyle The style of border to add (from RtfBorder) + * @param borderWidth The border width to use + * @param borderColor The border color to use + */ + public RtfBorderGroup(int bordersToAdd, int borderStyle, float borderWidth, Color borderColor) : base(null) { + this.borders = new Hashtable(); + AddBorder(bordersToAdd, borderStyle, borderWidth, borderColor); + } + + /** + * Constructs a RtfBorderGroup based on another RtfBorderGroup. + * + * @param doc The RtfDocument this RtfBorderGroup belongs to + * @param borderType The type of borders this RtfBorderGroup contains + * @param borderGroup The RtfBorderGroup to use as a base + */ + protected internal RtfBorderGroup(RtfDocument doc, int borderType, RtfBorderGroup borderGroup) : base(doc) { + this.borders = new Hashtable(); + this.borderType = borderType; + if (borderGroup != null) { + foreach (DictionaryEntry entry in borderGroup.GetBorders()) { + int borderPos = (int)entry.Key; + RtfBorder border = (RtfBorder)entry.Value; + this.borders[borderPos] = new RtfBorder(this.document, this.borderType, border); + } + } + } + + /** + * Constructs a RtfBorderGroup with certain borders + * + * @param doc The RtfDocument this RtfBorderGroup belongs to + * @param borderType The type of borders this RtfBorderGroup contains + * @param bordersToUse The borders to add (Rectangle.LEFT, Rectangle.RIGHT, Rectangle.TOP, Rectangle.BOTTOM, Rectangle.BOX) + * @param borderWidth The border width to use + * @param borderColor The border color to use + */ + protected internal RtfBorderGroup(RtfDocument doc, int borderType, int bordersToUse, float borderWidth, Color borderColor) : base(doc) { + this.borderType = borderType; + this.borders = new Hashtable(); + AddBorder(bordersToUse, RtfBorder.BORDER_SINGLE, borderWidth, borderColor); + } + + /** + * Sets a border in the Hashtable of borders + * + * @param borderPosition The position of this RtfBorder + * @param borderStyle The type of borders this RtfBorderGroup contains + * @param borderWidth The border width to use + * @param borderColor The border color to use + */ + private void SetBorder(int borderPosition, int borderStyle, float borderWidth, Color borderColor) { + RtfBorder border = new RtfBorder(this.document, this.borderType, borderPosition, borderStyle, borderWidth, borderColor); + this.borders[borderPosition] = border; + } + + /** + * Adds borders to the RtfBorderGroup + * + * @param bordersToAdd The borders to add (Rectangle.LEFT, Rectangle.RIGHT, Rectangle.TOP, Rectangle.BOTTOM, Rectangle.BOX) + * @param borderStyle The style of border to add (from RtfBorder) + * @param borderWidth The border width to use + * @param borderColor The border color to use + */ + public void AddBorder(int bordersToAdd, int borderStyle, float borderWidth, Color borderColor) { + if ((bordersToAdd & Rectangle.LEFT_BORDER) == Rectangle.LEFT_BORDER) { + SetBorder(RtfBorder.LEFT_BORDER, borderStyle, borderWidth, borderColor); + } + if ((bordersToAdd & Rectangle.TOP_BORDER) == Rectangle.TOP_BORDER) { + SetBorder(RtfBorder.TOP_BORDER, borderStyle, borderWidth, borderColor); + } + if ((bordersToAdd & Rectangle.RIGHT_BORDER) == Rectangle.RIGHT_BORDER) { + SetBorder(RtfBorder.RIGHT_BORDER, borderStyle, borderWidth, borderColor); + } + if ((bordersToAdd & Rectangle.BOTTOM_BORDER) == Rectangle.BOTTOM_BORDER) { + SetBorder(RtfBorder.BOTTOM_BORDER, borderStyle, borderWidth, borderColor); + } + if ((bordersToAdd & Rectangle.BOX) == Rectangle.BOX && this.borderType == RtfBorder.ROW_BORDER) { + SetBorder(RtfBorder.VERTICAL_BORDER, borderStyle, borderWidth, borderColor); + SetBorder(RtfBorder.HORIZONTAL_BORDER, borderStyle, borderWidth, borderColor); + } + } + + /** + * Removes borders from the list of borders + * + * @param bordersToRemove The borders to remove (from Rectangle) + */ + public void RemoveBorder(int bordersToRemove) { + if ((bordersToRemove & Rectangle.LEFT_BORDER) == Rectangle.LEFT_BORDER) { + this.borders.Remove(RtfBorder.LEFT_BORDER); + } + if ((bordersToRemove & Rectangle.TOP_BORDER) == Rectangle.TOP_BORDER) { + this.borders.Remove(RtfBorder.TOP_BORDER); + } + if ((bordersToRemove & Rectangle.RIGHT_BORDER) == Rectangle.RIGHT_BORDER) { + this.borders.Remove(RtfBorder.RIGHT_BORDER); + } + if ((bordersToRemove & Rectangle.BOTTOM_BORDER) == Rectangle.BOTTOM_BORDER) { + this.borders.Remove(RtfBorder.BOTTOM_BORDER); + } + if ((bordersToRemove & Rectangle.BOX) == Rectangle.BOX && this.borderType == RtfBorder.ROW_BORDER) { + this.borders.Remove(RtfBorder.VERTICAL_BORDER); + this.borders.Remove(RtfBorder.HORIZONTAL_BORDER); + } + } + + /** + * Writes the borders of this RtfBorderGroup + */ + public override void WriteContent(Stream result) { + foreach (RtfBorder rb in this.borders.Values) { + rb.WriteContent(result); + } + } + + /** + * Gets the RtfBorders of this RtfBorderGroup + * + * @return The RtfBorders of this RtfBorderGroup + */ + protected internal Hashtable GetBorders() { + return this.borders; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/table/RtfCell.cs b/iTechSharp/iTextSharp/text/rtf/table/RtfCell.cs new file mode 100644 index 0000000..f597586 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/table/RtfCell.cs @@ -0,0 +1,493 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.style; +using iTextSharp.text.rtf.text; +/* + * $Id: RtfCell.cs,v 1.14 2008/05/16 19:31:18 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.table { + + /** + * The RtfCell wraps a Cell, but can also be added directly to a Table. + * The RtfCell is an extension of Cell, that supports a multitude of different + * borderstyles. + * + * @version $Id: RtfCell.cs,v 1.14 2008/05/16 19:31:18 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Steffen Stundzig + * @author Benoit WIART + * @see com.lowagie.text.rtf.table.RtfBorder + */ + public class RtfCell : Cell, IRtfExtendedElement { + + /** + * This cell is not merged + */ + private const int MERGE_NONE = 0; + /** + * This cell is the parent cell of a vertical merge operation + */ + private const int MERGE_VERT_PARENT = 1; + /** + * This cell is a child cell of a vertical merge operation + */ + private const int MERGE_VERT_CHILD = 2; + + /** + * The parent RtfRow of this RtfCell + */ + private RtfRow parentRow = null; + /** + * The content of this RtfCell + */ + private ArrayList content = null; + /** + * The right margin of this RtfCell + */ + private int cellRight = 0; + /** + * The width of this RtfCell + */ + private int cellWidth = 0; + /** + * The borders of this RtfCell + */ + private RtfBorderGroup borders = null; + /** + * The background color of this RtfCell + */ + private new RtfColor backgroundColor = null; + /** + * The padding of this RtfCell + */ + private int cellPadding = 0; + /** + * The merge type of this RtfCell + */ + private int mergeType = MERGE_NONE; + /** + * The RtfDocument this RtfCell belongs to + */ + private RtfDocument document = null; + /** + * Whether this RtfCell is in a header + */ + private bool inHeader = false; + /** + * Whether this RtfCell is a placeholder for a removed table cell. + */ + private bool deleted = false; + + /** + * Constructs an empty RtfCell + */ + public RtfCell() : base() { + this.borders = new RtfBorderGroup(); + verticalAlignment = Element.ALIGN_MIDDLE; + } + + /** + * Constructs a RtfCell based upon a String + * + * @param content The String to base the RtfCell on + */ + public RtfCell(String content) : base(content) { + this.borders = new RtfBorderGroup(); + verticalAlignment = Element.ALIGN_MIDDLE; + } + + /** + * Constructs a RtfCell based upon an Element + * + * @param element The Element to base the RtfCell on + * @throws BadElementException If the Element is not valid + */ + public RtfCell(IElement element) : base(element) { + this.borders = new RtfBorderGroup(); + verticalAlignment = Element.ALIGN_MIDDLE; + } + + /** + * Constructs a deleted RtfCell. + * + * @param deleted Whether this RtfCell is actually deleted. + */ + protected internal RtfCell(bool deleted) : base() { + this.deleted = deleted; + verticalAlignment = Element.ALIGN_MIDDLE; + } + + /** + * Constructs a RtfCell based on a Cell. + * + * @param doc The RtfDocument this RtfCell belongs to + * @param row The RtfRow this RtfCell lies in + * @param cell The Cell to base this RtfCell on + */ + protected internal RtfCell(RtfDocument doc, RtfRow row, Cell cell) { + this.document = doc; + this.parentRow = row; + ImportCell(cell); + } + + /** + * Imports the Cell properties into the RtfCell + * + * @param cell The Cell to import + */ + private void ImportCell(Cell cell) { + this.content = new ArrayList(); + + if (cell == null) { + this.borders = new RtfBorderGroup(this.document, RtfBorder.CELL_BORDER, this.parentRow.GetParentTable().GetBorders()); + return; + } + + this.colspan = cell.Colspan; + this.rowspan = cell.Rowspan; + if (cell.Rowspan > 1) { + this.mergeType = MERGE_VERT_PARENT; + } + if (cell is RtfCell) { + this.borders = new RtfBorderGroup(this.document, RtfBorder.CELL_BORDER, ((RtfCell) cell).GetBorders()); + } else { + this.borders = new RtfBorderGroup(this.document, RtfBorder.CELL_BORDER, cell.Border, cell.BorderWidth, cell.BorderColor); + } + this.verticalAlignment = cell.VerticalAlignment; + if (cell.BackgroundColor == null) { + this.backgroundColor = new RtfColor(this.document, 255, 255, 255); + } else { + this.backgroundColor = new RtfColor(this.document, cell.BackgroundColor); + } + + this.cellPadding = (int) this.parentRow.GetParentTable().GetCellPadding(); + + Paragraph container = null; + foreach (IElement element in cell.Elements) { + try { + // should we wrap it in a paragraph + if (!(element is Paragraph) && !(element is List)) { + if (container != null) { + container.Add(element); + } else { + container = new Paragraph(); + container.Alignment = cell.HorizontalAlignment; + container.Add(element); + } + } else { + if (container != null) { + IRtfBasicElement[] rtfElements = this.document.GetMapper().MapElement(container); + for(int i = 0; i < rtfElements.Length; i++) { + rtfElements[i].SetInTable(true); + this.content.Add(rtfElements[i]); + } + container = null; + } + // if horizontal alignment is undefined overwrite + // with that of enclosing cell + if (element is Paragraph && ((Paragraph) element).Alignment == Element.ALIGN_UNDEFINED) { + ((Paragraph) element).Alignment = cell.HorizontalAlignment; + } + + IRtfBasicElement[] rtfElements2 = this.document.GetMapper().MapElement(element); + for(int i = 0; i < rtfElements2.Length; i++) { + rtfElements2[i].SetInTable(true); + this.content.Add(rtfElements2[i]); + } + } + } catch (DocumentException) { + } + } + if (container != null) { + try { + IRtfBasicElement[] rtfElements = this.document.GetMapper().MapElement(container); + for(int i = 0; i < rtfElements.Length; i++) { + rtfElements[i].SetInTable(true); + this.content.Add(rtfElements[i]); + } + } catch (DocumentException) { + } + } + } + + /** + * Write the cell definition part of this RtfCell + * + * @return A byte array with the cell definition + */ + public virtual void WriteDefinition(Stream result) { + byte[] t; + if (this.mergeType == MERGE_VERT_PARENT) { + result.Write(t = DocWriter.GetISOBytes("\\clvmgf"), 0, t.Length); + } else if (this.mergeType == MERGE_VERT_CHILD) { + result.Write(t = DocWriter.GetISOBytes("\\clvmrg"), 0, t.Length); + } + switch (verticalAlignment) { + case Element.ALIGN_BOTTOM: + result.Write(t = DocWriter.GetISOBytes("\\clvertalb"), 0, t.Length); + break; + case Element.ALIGN_CENTER: + case Element.ALIGN_MIDDLE: + result.Write(t = DocWriter.GetISOBytes("\\clvertalc"), 0, t.Length); + break; + case Element.ALIGN_TOP: + result.Write(t = DocWriter.GetISOBytes("\\clvertalt"), 0, t.Length); + break; + } + this.borders.WriteContent(result); + + if (this.backgroundColor != null) { + result.Write(t = DocWriter.GetISOBytes("\\clcbpat"), 0, t.Length); + result.Write(t = IntToByteArray(this.backgroundColor.GetColorNumber()), 0, t.Length); + } + result.WriteByte((byte)'\n'); + + result.Write(t = DocWriter.GetISOBytes("\\clftsWidth3"), 0, t.Length); + result.WriteByte((byte)'\n'); + + result.Write(t = DocWriter.GetISOBytes("\\clwWidth"), 0, t.Length); + result.Write(t = IntToByteArray(this.cellWidth), 0, t.Length); + result.WriteByte((byte)'\n'); + + if (this.cellPadding > 0) { + result.Write(t = DocWriter.GetISOBytes("\\clpadl"), 0, t.Length); + result.Write(t = IntToByteArray(this.cellPadding / 2), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadt"), 0, t.Length); + result.Write(t = IntToByteArray(this.cellPadding / 2), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadr"), 0, t.Length); + result.Write(t = IntToByteArray(this.cellPadding / 2), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadb"), 0, t.Length); + result.Write(t = IntToByteArray(this.cellPadding / 2), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadfl3"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadft3"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadfr3"), 0, t.Length); + result.Write(t = DocWriter.GetISOBytes("\\clpadfb3"), 0, t.Length); + } + result.Write(t = DocWriter.GetISOBytes("\\cellx"), 0, t.Length); + result.Write(t = IntToByteArray(this.cellRight), 0, t.Length); + } + + /** + * Write the content of this RtfCell + */ + public virtual void WriteContent(Stream result) { + byte[] t; + if (this.content.Count == 0) { + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + if (this.parentRow.GetParentTable().GetTableFitToPage()) { + result.Write(RtfParagraphStyle.KEEP_TOGETHER_WITH_NEXT, 0, RtfParagraphStyle.KEEP_TOGETHER_WITH_NEXT.Length); + } + result.Write(RtfParagraph.IN_TABLE, 0, RtfParagraph.IN_TABLE.Length); + } else { + for (int i = 0; i < this.content.Count; i++) { + IRtfBasicElement rtfElement = (IRtfBasicElement) this.content[i]; + if (rtfElement is RtfParagraph) { + ((RtfParagraph) rtfElement).SetKeepTogetherWithNext(this.parentRow.GetParentTable().GetTableFitToPage()); + } + rtfElement.WriteContent(result); + if (rtfElement is RtfParagraph && i < (this.content.Count - 1)) { + result.Write(RtfParagraph.PARAGRAPH, 0, RtfParagraph.PARAGRAPH.Length); + } + } + } + result.Write(t = DocWriter.GetISOBytes("\\cell"), 0, t.Length); + } + + /** + * Sets the right margin of this cell. Used in merge operations + * + * @param cellRight The right margin to use + */ + protected internal void SetCellRight(int cellRight) { + this.cellRight = cellRight; + } + + /** + * Gets the right margin of this RtfCell + * + * @return The right margin of this RtfCell. + */ + protected internal int GetCellRight() { + return this.cellRight; + } + + /** + * Sets the cell width of this RtfCell. Used in merge operations. + * + * @param cellWidth The cell width to use + */ + protected internal void SetCellWidth(int cellWidth) { + this.cellWidth = cellWidth; + } + + /** + * Gets the cell width of this RtfCell + * + * @return The cell width of this RtfCell + */ + protected internal int GetCellWidth() { + return this.cellWidth; + } + + /** + * Gets the cell padding of this RtfCell + * + * @return The cell padding of this RtfCell + */ + protected internal int GetCellpadding() { + return this.cellPadding; + } + + /** + * Gets the borders of this RtfCell + * + * @return The borders of this RtfCell + */ + protected internal RtfBorderGroup GetBorders() { + return this.borders; + } + + /** + * Set the borders of this RtfCell + * + * @param borderGroup The RtfBorderGroup to use as borders + */ + public void SetBorders(RtfBorderGroup borderGroup) { + this.borders = new RtfBorderGroup(this.document, RtfBorder.CELL_BORDER, borderGroup); + } + + /** + * Get the background color of this RtfCell + * + * @return The background color of this RtfCell + */ + protected internal RtfColor GetRtfBackgroundColor() { + return this.backgroundColor; + } + + /** + * Merge this cell into the parent cell. + * + * @param mergeParent The RtfCell to merge with + */ + protected internal void SetCellMergeChild(RtfCell mergeParent) { + this.mergeType = MERGE_VERT_CHILD; + this.cellWidth = mergeParent.GetCellWidth(); + this.cellRight = mergeParent.GetCellRight(); + this.cellPadding = mergeParent.GetCellpadding(); + this.borders = mergeParent.GetBorders(); + this.verticalAlignment = mergeParent.VerticalAlignment; + this.backgroundColor = mergeParent.GetRtfBackgroundColor(); + } + + /** + * Sets the RtfDocument this RtfCell belongs to + * + * @param doc The RtfDocument to use + */ + public void SetRtfDocument(RtfDocument doc) { + this.document = doc; + } + + /** + * Unused + * @param inTable + */ + public void SetInTable(bool inTable) { + } + + /** + * Sets whether this RtfCell is in a header + * + * @param inHeader True if this RtfCell is in a header, false otherwise + */ + public void SetInHeader(bool inHeader) { + this.inHeader = inHeader; + for (int i = 0; i < this.content.Count; i++) { + ((IRtfBasicElement) this.content[i]).SetInHeader(inHeader); + } + } + + /** + * Gets whether this RtfCell is in a header + * + * @return True if this RtfCell is in a header, false otherwise + */ + public bool IsInHeader() { + return this.inHeader; + } + + /** + * Transforms an integer into its String representation and then returns the bytes + * of that string. + * + * @param i The integer to convert + * @return A byte array representing the integer + */ + private byte[] IntToByteArray(int i) { + return DocWriter.GetISOBytes(i.ToString()); + } + + /** + * Checks whether this RtfCell is a placeholder for + * a table cell that has been removed due to col/row spanning. + * + * @return True if this RtfCell is deleted, false otherwise. + */ + public bool IsDeleted() { + return this.deleted; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/table/RtfRow.cs b/iTechSharp/iTextSharp/text/rtf/table/RtfRow.cs new file mode 100644 index 0000000..8c41d6c --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/table/RtfRow.cs @@ -0,0 +1,377 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfRow.cs,v 1.10 2008/05/16 19:31:19 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004, 2005 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.table { + + /** + * The RtfRow wraps one Row for a RtfTable. + * INTERNAL USE ONLY + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Steffen Stundzig + * @author Lorenz Maierhofer + */ + public class RtfRow : RtfElement { + + /** + * Constant for the RtfRow beginning + */ + private static byte[] ROW_BEGIN = DocWriter.GetISOBytes("\\trowd"); + /** + * Constant for the RtfRow width style + */ + private static byte[] ROW_WIDTH_STYLE = DocWriter.GetISOBytes("\\trftsWidth3"); + /** + * Constant for the RtfRow width + */ + private static byte[] ROW_WIDTH = DocWriter.GetISOBytes("\\trwWidth"); + /** + * Constant to specify that this RtfRow are not to be broken across pages + */ + private static byte[] ROW_KEEP_TOGETHER = DocWriter.GetISOBytes("\\trkeep"); + /** + * Constant to specify that this is a header RtfRow + */ + private static byte[] ROW_HEADER_ROW = DocWriter.GetISOBytes("\\trhdr"); + /** + * Constant for left alignment of this RtfRow + */ + private static byte[] ROW_ALIGN_LEFT = DocWriter.GetISOBytes("\\trql"); + /** + * Constant for right alignment of this RtfRow + */ + private static byte[] ROW_ALIGN_RIGHT = DocWriter.GetISOBytes("\\trqr"); + /** + * Constant for center alignment of this RtfRow + */ + private static byte[] ROW_ALIGN_CENTER = DocWriter.GetISOBytes("\\trqc"); + /** + * Constant for justified alignment of this RtfRow + */ + private static byte[] ROW_ALIGN_JUSTIFIED = DocWriter.GetISOBytes("\\trqj"); + /** + * Constant for the graph style of this RtfRow + */ + private static byte[] ROW_GRAPH = DocWriter.GetISOBytes("\\trgaph10"); + /** + * Constant for the cell left spacing + */ + private static byte[] ROW_CELL_SPACING_LEFT = DocWriter.GetISOBytes("\\trspdl"); + /** + * Constant for the cell top spacing + */ + private static byte[] ROW_CELL_SPACING_TOP = DocWriter.GetISOBytes("\\trspdt"); + /** + * Constant for the cell right spacing + */ + private static byte[] ROW_CELL_SPACING_RIGHT = DocWriter.GetISOBytes("\\trspdr"); + /** + * Constant for the cell bottom spacing + */ + private static byte[] ROW_CELL_SPACING_BOTTOM = DocWriter.GetISOBytes("\\trspdb"); + /** + * Constant for the cell left spacing style + */ + private static byte[] ROW_CELL_SPACING_LEFT_STYLE = DocWriter.GetISOBytes("\\trspdfl3"); + /** + * Constant for the cell top spacing style + */ + private static byte[] ROW_CELL_SPACING_TOP_STYLE = DocWriter.GetISOBytes("\\trspdft3"); + /** + * Constant for the cell right spacing style + */ + private static byte[] ROW_CELL_SPACING_RIGHT_STYLE = DocWriter.GetISOBytes("\\trspdfr3"); + /** + * Constant for the cell bottom spacing style + */ + private static byte[] ROW_CELL_SPACING_BOTTOM_STYLE = DocWriter.GetISOBytes("\\trspdfb3"); + /** + * Constant for the cell left padding + */ + private static byte[] ROW_CELL_PADDING_LEFT = DocWriter.GetISOBytes("\\trpaddl"); + /** + * Constant for the cell right padding + */ + private static byte[] ROW_CELL_PADDING_RIGHT = DocWriter.GetISOBytes("\\trpaddr"); + /** + * Constant for the cell left padding style + */ + private static byte[] ROW_CELL_PADDING_LEFT_STYLE = DocWriter.GetISOBytes("\\trpaddfl3"); + /** + * Constant for the cell right padding style + */ + private static byte[] ROW_CELL_PADDING_RIGHT_STYLE = DocWriter.GetISOBytes("\\trpaddfr3"); + /** + * Constant for the end of a row + */ + private static byte[] ROW_END = DocWriter.GetISOBytes("\\row"); + + /** + * The RtfTable this RtfRow belongs to + */ + private RtfTable parentTable = null; + /** + * The cells of this RtfRow + */ + private ArrayList cells = null; + /** + * The width of this row + */ + private int width = 0; + /** + * The row number + */ + private int rowNumber = 0; + + /** + * Constructs a RtfRow for a Row. + * + * @param doc The RtfDocument this RtfRow belongs to + * @param rtfTable The RtfTable this RtfRow belongs to + * @param row The Row this RtfRow is based on + * @param rowNumber The number of this row + */ + protected internal RtfRow(RtfDocument doc, RtfTable rtfTable, Row row, int rowNumber) : base(doc) { + this.parentTable = rtfTable; + this.rowNumber = rowNumber; + ImportRow(row); + } + + /** + * Imports a Row and copies all settings + * + * @param row The Row to import + */ + private void ImportRow(Row row) { + this.cells = new ArrayList(); + this.width = this.document.GetDocumentHeader().GetPageSetting().GetPageWidth() - this.document.GetDocumentHeader().GetPageSetting().GetMarginLeft() - this.document.GetDocumentHeader().GetPageSetting().GetMarginRight(); + this.width = (int) (this.width * this.parentTable.GetTableWidthPercent() / 100); + + int cellRight = 0; + int cellWidth = 0; + for (int i = 0; i < row.Columns; i++) { + cellWidth = (int) (this.width * this.parentTable.GetProportionalWidths()[i] / 100); + cellRight = cellRight + cellWidth; + + Cell cell = (Cell) row.GetCell(i); + RtfCell rtfCell = new RtfCell(this.document, this, cell); + rtfCell.SetCellRight(cellRight); + rtfCell.SetCellWidth(cellWidth); + this.cells.Add(rtfCell); + } + } + + /** + * Performs a second pass over all cells to handle cell row/column spanning. + */ + protected internal void HandleCellSpanning() { + RtfCell deletedCell = new RtfCell(true); + for (int i = 0; i < this.cells.Count; i++) { + RtfCell rtfCell = (RtfCell) this.cells[i]; + if (rtfCell.Colspan > 1) { + int cSpan = rtfCell.Colspan; + for (int j = i + 1; j < i + cSpan; j++) { + if (j < this.cells.Count) { + RtfCell rtfCellMerge = (RtfCell) this.cells[j]; + rtfCell.SetCellRight(rtfCell.GetCellRight() + rtfCellMerge.GetCellWidth()); + rtfCell.SetCellWidth(rtfCell.GetCellWidth() + rtfCellMerge.GetCellWidth()); + this.cells[j] = deletedCell; + } + } + } + if (rtfCell.Rowspan > 1) { + ArrayList rows = this.parentTable.GetRows(); + for (int j = 1; j < rtfCell.Rowspan; j++) { + RtfRow mergeRow = (RtfRow) rows[this.rowNumber + j]; + if (this.rowNumber + j < rows.Count) { + RtfCell rtfCellMerge = (RtfCell) mergeRow.GetCells()[i]; + rtfCellMerge.SetCellMergeChild(rtfCell); + } + if (rtfCell.Colspan > 1) { + int cSpan = rtfCell.Colspan; + for (int k = i + 1; k < i + cSpan; k++) { + if (k < mergeRow.GetCells().Count) { + mergeRow.GetCells()[k] = deletedCell; + } + } + } + } + } + } + } + + /** + * Cleans the deleted RtfCells from the total RtfCells. + */ + protected internal void CleanRow() { + int i = 0; + while (i < this.cells.Count) { + if (((RtfCell) this.cells[i]).IsDeleted()) { + this.cells.RemoveAt(i); + } else { + i++; + } + } + } + + /** + * Writes the row definition/settings. + * + * @param result The OutputStream to write the definitions to. + */ + private void WriteRowDefinition(Stream result) { + byte[] t; + result.Write(ROW_BEGIN, 0, ROW_BEGIN.Length); + result.WriteByte((byte)'\n'); + result.Write(ROW_WIDTH_STYLE, 0, ROW_WIDTH_STYLE.Length); + result.Write(ROW_WIDTH, 0, ROW_WIDTH.Length); + result.Write(t = IntToByteArray(this.width), 0, t.Length); + if (this.parentTable.GetCellsFitToPage()) { + result.Write(ROW_KEEP_TOGETHER, 0, ROW_KEEP_TOGETHER.Length); + } + if (this.rowNumber <= this.parentTable.GetHeaderRows()) { + result.Write(ROW_HEADER_ROW, 0, ROW_HEADER_ROW.Length); + } + switch (this.parentTable.GetAlignment()) { + case Element.ALIGN_LEFT: + result.Write(ROW_ALIGN_LEFT, 0, ROW_ALIGN_LEFT.Length); + break; + case Element.ALIGN_RIGHT: + result.Write(ROW_ALIGN_RIGHT, 0, ROW_ALIGN_RIGHT.Length); + break; + case Element.ALIGN_CENTER: + result.Write(ROW_ALIGN_CENTER, 0, ROW_ALIGN_CENTER.Length); + break; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + result.Write(ROW_ALIGN_JUSTIFIED, 0, ROW_ALIGN_JUSTIFIED.Length); + break; + } + result.Write(ROW_GRAPH, 0, ROW_GRAPH.Length); + + this.parentTable.GetBorders().WriteContent(result); + + if (this.parentTable.GetCellSpacing() > 0) { + result.Write(ROW_CELL_SPACING_LEFT, 0, ROW_CELL_SPACING_LEFT.Length); + result.Write(t = IntToByteArray((int) (this.parentTable.GetCellSpacing() / 2)), 0, t.Length); + result.Write(ROW_CELL_SPACING_LEFT_STYLE, 0, ROW_CELL_SPACING_LEFT_STYLE.Length); + result.Write(ROW_CELL_SPACING_TOP, 0, ROW_CELL_SPACING_TOP.Length); + result.Write(t = IntToByteArray((int) (this.parentTable.GetCellSpacing() / 2)), 0, t.Length); + result.Write(ROW_CELL_SPACING_TOP_STYLE, 0, ROW_CELL_SPACING_TOP_STYLE.Length); + result.Write(ROW_CELL_SPACING_RIGHT, 0, ROW_CELL_SPACING_RIGHT.Length); + result.Write(t = IntToByteArray((int) (this.parentTable.GetCellSpacing() / 2)), 0, t.Length); + result.Write(ROW_CELL_SPACING_RIGHT_STYLE, 0, ROW_CELL_SPACING_RIGHT_STYLE.Length); + result.Write(ROW_CELL_SPACING_BOTTOM, 0, ROW_CELL_SPACING_BOTTOM.Length); + result.Write(t = IntToByteArray((int) (this.parentTable.GetCellSpacing() / 2)), 0, t.Length); + result.Write(ROW_CELL_SPACING_BOTTOM_STYLE, 0, ROW_CELL_SPACING_BOTTOM_STYLE.Length); + } + + result.Write(ROW_CELL_PADDING_LEFT, 0, ROW_CELL_PADDING_LEFT.Length); + result.Write(t = IntToByteArray((int) (this.parentTable.GetCellPadding() / 2)), 0, t.Length); + result.Write(ROW_CELL_PADDING_RIGHT, 0, ROW_CELL_PADDING_RIGHT.Length); + result.Write(t = IntToByteArray((int) (this.parentTable.GetCellPadding() / 2)), 0, t.Length); + result.Write(ROW_CELL_PADDING_LEFT_STYLE, 0, ROW_CELL_PADDING_LEFT_STYLE.Length); + result.Write(ROW_CELL_PADDING_RIGHT_STYLE, 0, ROW_CELL_PADDING_RIGHT_STYLE.Length); + + result.WriteByte((byte)'\n'); + + for (int i = 0; i < this.cells.Count; i++) { + RtfCell rtfCell = (RtfCell) this.cells[i]; + rtfCell.WriteDefinition(result); + } + } + + /** + * Writes the content of this RtfRow + */ + public override void WriteContent(Stream result) { + WriteRowDefinition(result); + + for (int i = 0; i < this.cells.Count; i++) { + RtfCell rtfCell = (RtfCell) this.cells[i]; + rtfCell.WriteContent(result); + } + + result.Write(DELIMITER, 0, DELIMITER.Length); + + if (this.document.GetDocumentSettings().IsOutputTableRowDefinitionAfter()) { + WriteRowDefinition(result); + } + + result.Write(ROW_END, 0, ROW_END.Length); + result.WriteByte((byte)'\n'); + } + + /** + * Gets the parent RtfTable of this RtfRow + * + * @return The parent RtfTable of this RtfRow + */ + protected internal RtfTable GetParentTable() { + return this.parentTable; + } + + /** + * Gets the cells of this RtfRow + * + * @return The cells of this RtfRow + */ + protected internal ArrayList GetCells() { + return this.cells; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/table/RtfTable.cs b/iTechSharp/iTextSharp/text/rtf/table/RtfTable.cs new file mode 100644 index 0000000..f6a8589 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/table/RtfTable.cs @@ -0,0 +1,271 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.text; +using iTextSharp.text.rtf.style; +/* + * $Id: RtfTable.cs,v 1.9 2008/05/23 17:24:29 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.table { + + /** + * The RtfTable wraps a Table. + * INTERNAL USE ONLY + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + * @author Steffen Stundzig + * @author Benoit WIART + */ + public class RtfTable : RtfElement { + + /** + * The rows of this RtfTable + */ + private ArrayList rows = null; + /** + * The percentage of the page width that this RtfTable covers + */ + private float tableWidthPercent = 80; + /** + * An array with the proportional widths of the cells in each row + */ + private float[] proportionalWidths = null; + /** + * The cell padding + */ + private float cellPadding = 0; + /** + * The cell spacing + */ + private float cellSpacing = 0; + /** + * The border style of this RtfTable + */ + private RtfBorderGroup borders = null; + /** + * The alignment of this RtfTable + */ + private int alignment = Element.ALIGN_CENTER; + /** + * Whether the cells in this RtfTable must fit in a page + */ + private bool cellsFitToPage = false; + /** + * Whether the whole RtfTable must fit in a page + */ + private bool tableFitToPage = false; + /** + * The number of header rows in this RtfTable + */ + private int headerRows = 0; + /** + * The offset from the previous text + */ + private int offset = -1; + + /** + * Constructs a RtfTable based on a Table for a RtfDocument. + * + * @param doc The RtfDocument this RtfTable belongs to + * @param table The Table that this RtfTable wraps + */ + public RtfTable(RtfDocument doc, Table table) : base(doc) { + table.Complete(); + ImportTable(table); + } + + /** + * Imports the rows and settings from the Table into this + * RtfTable. + * + * @param table The source Table + */ + private void ImportTable(Table table) { + this.rows = new ArrayList(); + this.tableWidthPercent = table.Width; + this.proportionalWidths = table.ProportionalWidths; + this.cellPadding = (float) (table.Cellpadding * TWIPS_FACTOR); + this.cellSpacing = (float) (table.Cellspacing * TWIPS_FACTOR); + this.borders = new RtfBorderGroup(this.document, RtfBorder.ROW_BORDER, table.Border, table.BorderWidth, table.BorderColor); + this.alignment = table.Alignment; + + int i = 0; + foreach (Row row in table) { + this.rows.Add(new RtfRow(this.document, this, row, i)); + i++; + } + for (i = 0; i < this.rows.Count; i++) { + ((RtfRow) this.rows[i]).HandleCellSpanning(); + ((RtfRow) this.rows[i]).CleanRow(); + } + this.headerRows = table.LastHeaderRow; + this.cellsFitToPage = table.CellsFitPage; + this.tableFitToPage = table.TableFitsPage; + if (!float.IsNaN(table.Offset)) { + this.offset = (int) (table.Offset * 2); + } + } + + /** + * Writes the content of this RtfTable + */ + public override void WriteContent(Stream result) { + if (!inHeader) { + if(this.offset != -1) { + result.Write(RtfFont.FONT_SIZE, 0, RtfFont.FONT_SIZE.Length); + byte[] t; + result.Write(t = IntToByteArray(this.offset), 0, t.Length); + } + result.Write(RtfParagraph.PARAGRAPH, 0, RtfParagraph.PARAGRAPH.Length); + } + + for (int i = 0; i < this.rows.Count; i++) { + RtfElement re = (RtfElement)this.rows[i]; + re.WriteContent(result); + } + + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + } + + /** + * Gets the alignment of this RtfTable + * + * @return The alignment of this RtfTable. + */ + protected internal int GetAlignment() { + return alignment; + } + + /** + * Gets the borders of this RtfTable + * + * @return The borders of this RtfTable. + */ + protected internal RtfBorderGroup GetBorders() { + return this.borders; + } + + /** + * Gets the cell padding of this RtfTable + * + * @return The cell padding of this RtfTable. + */ + protected internal float GetCellPadding() { + return cellPadding; + } + + /** + * Gets the cell spacing of this RtfTable + * + * @return The cell spacing of this RtfTable. + */ + protected internal float GetCellSpacing() { + return cellSpacing; + } + + /** + * Gets the proportional cell widths of this RtfTable + * + * @return The proportional widths of this RtfTable. + */ + protected internal float[] GetProportionalWidths() { + return (float[]) proportionalWidths.Clone(); + } + + /** + * Gets the percentage of the page width this RtfTable covers + * + * @return The percentage of the page width. + */ + protected internal float GetTableWidthPercent() { + return tableWidthPercent; + } + + /** + * Gets the rows of this RtfTable + * + * @return The rows of this RtfTable + */ + protected internal ArrayList GetRows() { + return this.rows; + } + + /** + * Gets the cellsFitToPage setting of this RtfTable. + * + * @return The cellsFitToPage setting of this RtfTable. + */ + protected internal bool GetCellsFitToPage() { + return this.cellsFitToPage; + } + + /** + * Gets the tableFitToPage setting of this RtfTable. + * + * @return The tableFitToPage setting of this RtfTable. + */ + protected internal bool GetTableFitToPage() { + return this.tableFitToPage; + } + + /** + * Gets the number of header rows of this RtfTable + * + * @return The number of header rows + */ + protected internal int GetHeaderRows() { + return this.headerRows; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfAnnotation.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfAnnotation.cs new file mode 100644 index 0000000..f495ffa --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfAnnotation.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfAnnotation.cs,v 1.5 2008/05/16 19:31:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfAnnotation provides support for adding Annotations to the rtf document. + * Only simple Annotations with Title / Content are supported. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfAnnotation : RtfElement { + + /** + * Constant for the id of the annotation + */ + private static byte[] ANNOTATION_ID = DocWriter.GetISOBytes("\\*\\atnid"); + /** + * Constant for the author of the annotation + */ + private static byte[] ANNOTATION_AUTHOR = DocWriter.GetISOBytes("\\*\\atnauthor"); + /** + * Constant for the actual annotation + */ + private static byte[] ANNOTATION = DocWriter.GetISOBytes("\\*\\annotation"); + + /** + * The title of this RtfAnnotation + */ + private String title = ""; + /** + * The content of this RtfAnnotation + */ + private String content = ""; + + /** + * Constructs a RtfAnnotation based on an Annotation. + * + * @param doc The RtfDocument this RtfAnnotation belongs to + * @param annotation The Annotation this RtfAnnotation is based off + */ + public RtfAnnotation(RtfDocument doc, Annotation annotation) : base(doc) { + title = annotation.Title; + content = annotation.Content; + } + + /** + * Writes the content of the RtfAnnotation + */ + public override void WriteContent(Stream result) { + byte[] t; + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(ANNOTATION_ID, 0, ANNOTATION_ID.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + result.Write(t = IntToByteArray(document.GetRandomInt()), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(ANNOTATION_AUTHOR, 0, ANNOTATION_AUTHOR.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + result.Write(t = DocWriter.GetISOBytes(title), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + result.Write(ANNOTATION, 0, ANNOTATION.Length); + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + result.Write(DELIMITER, 0, DELIMITER.Length); + result.Write(t = DocWriter.GetISOBytes(content), 0, t.Length); + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfChapter.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfChapter.cs new file mode 100644 index 0000000..2d17d54 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfChapter.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * $Id: RtfChapter.cs,v 1.7 2008/05/16 19:31:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfChapter wraps a Chapter element. + * INTERNAL CLASS + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfChapter : RtfSection { + + /** + * Constructs a RtfChapter for a given Chapter + * + * @param doc The RtfDocument this RtfChapter belongs to + * @param chapter The Chapter this RtfChapter is based on + */ + public RtfChapter(RtfDocument doc, Chapter chapter) : base(doc, chapter) { + } + + /** + * Writes the RtfChapter and its contents + */ + public override void WriteContent(Stream result) { + byte[] t; + if (this.document.GetLastElementWritten() != null && !(this.document.GetLastElementWritten() is RtfChapter)) { + result.Write(t = DocWriter.GetISOBytes("\\page"), 0, t.Length); + } + result.Write(t = DocWriter.GetISOBytes("\\sectd"), 0, t.Length); + document.GetDocumentHeader().WriteSectionDefinition(result); + if (this.title != null) { + this.title.WriteContent(result); + } + for (int i = 0; i < items.Count; i++) { + IRtfBasicElement rbe = (IRtfBasicElement)items[i]; + rbe.WriteContent(result); + } + result.Write(t = DocWriter.GetISOBytes("\\sect"), 0, t.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfChunk.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfChunk.cs new file mode 100644 index 0000000..256b9f3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfChunk.cs @@ -0,0 +1,191 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.style; +using ST = iTextSharp.text.rtf.style; +/* + * $Id: RtfChunk.cs,v 1.7 2008/05/16 19:31:24 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfChunk contains one piece of text. The smallest text element available + * in iText. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfChunk : RtfElement { + + /** + * Constant for the subscript flag + */ + private static byte[] FONT_SUBSCRIPT = DocWriter.GetISOBytes("\\sub"); + /** + * Constant for the superscript flag + */ + private static byte[] FONT_SUPERSCRIPT = DocWriter.GetISOBytes("\\super"); + /** + * Constant for the end of sub / superscript flag + */ + private static byte[] FONT_END_SUPER_SUBSCRIPT = DocWriter.GetISOBytes("\\nosupersub"); + /** + * Constant for background colour. + */ + private static byte[] BACKGROUND_COLOR = DocWriter.GetISOBytes("\\chcbpat"); + + /** + * The font of this RtfChunk + */ + private ST.RtfFont font = null; + /** + * The actual content of this RtfChunk + */ + private String content = ""; + /** + * Whether to use soft line breaks instead of hard ones. + */ + private bool softLineBreaks = false; + /** + * The super / subscript of this RtfChunk + */ + private float superSubScript = 0; + /** + * An optional background colour. + */ + private RtfColor background = null; + + /** + * Constructs a RtfChunk based on the content of a Chunk + * + * @param doc The RtfDocument that this Chunk belongs to + * @param chunk The Chunk that this RtfChunk is based on + */ + public RtfChunk(RtfDocument doc, Chunk chunk) : base(doc) { + + if (chunk == null) { + return; + } + + if (chunk.Attributes != null && chunk.Attributes[Chunk.SUBSUPSCRIPT] != null) { + this.superSubScript = (float)chunk.Attributes[Chunk.SUBSUPSCRIPT]; + } + if (chunk.Attributes != null && chunk.Attributes[Chunk.BACKGROUND] != null) { + this.background = new RtfColor(this.document, (Color) ((Object[]) chunk.Attributes[Chunk.BACKGROUND])[0]); + } + font = new ST.RtfFont(doc, chunk.Font); + content = chunk.Content; + } + + /** + * Writes the content of this RtfChunk. First the font information + * is written, then the content, and then more font information + */ + public override void WriteContent(Stream result) { + byte[] t; + if (this.background != null) { + result.Write(OPEN_GROUP, 0, OPEN_GROUP.Length); + } + + font.WriteBegin(result); + if (superSubScript < 0) { + result.Write(FONT_SUBSCRIPT, 0, FONT_SUBSCRIPT.Length); + } else if (superSubScript > 0) { + result.Write(FONT_SUPERSCRIPT, 0, FONT_SUPERSCRIPT.Length); + } + if (this.background != null) { + result.Write(BACKGROUND_COLOR, 0, BACKGROUND_COLOR.Length); + result.Write(t = IntToByteArray(this.background.GetColorNumber()), 0, t.Length); + } + result.Write(DELIMITER, 0, DELIMITER.Length); + + document.FilterSpecialChar(result, content, false, softLineBreaks || this.document.GetDocumentSettings().IsAlwaysGenerateSoftLinebreaks()); + + if (superSubScript != 0) { + result.Write(FONT_END_SUPER_SUBSCRIPT, 0, FONT_END_SUPER_SUBSCRIPT.Length); + } + font.WriteEnd(result); + + if (this.background != null) { + result.Write(CLOSE_GROUP, 0, CLOSE_GROUP.Length); + } + } + + /** + * Sets the RtfDocument this RtfChunk belongs to. + * + * @param doc The RtfDocument to use + */ + public override void SetRtfDocument(RtfDocument doc) { + base.SetRtfDocument(doc); + this.font.SetRtfDocument(this.document); + } + + /** + * Sets whether to use soft line breaks instead of default hard ones. + * + * @param softLineBreaks whether to use soft line breaks instead of default hard ones. + */ + public void SetSoftLineBreaks(bool softLineBreaks) { + this.softLineBreaks = softLineBreaks; + } + + /** + * Gets whether to use soft line breaks instead of default hard ones. + * + * @return whether to use soft line breaks instead of default hard ones. + */ + public bool GetSoftLineBreaks() { + return this.softLineBreaks; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfNewPage.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfNewPage.cs new file mode 100644 index 0000000..9f35919 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfNewPage.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +/* + * Created on Aug 12, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +namespace iTextSharp.text.rtf.text { + + + /** + * The RtfNewPage creates a new page. INTERNAL CLASS + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfNewPage : RtfElement { + + /** + * Constant for a new page + */ + public static byte[] NEW_PAGE = DocWriter.GetISOBytes("\\page"); + + /** + * Constructs a RtfNewPage + * + * @param doc The RtfDocument this RtfNewPage belongs to + */ + public RtfNewPage(RtfDocument doc) : base(doc) { + } + + /** + * Writes a new page + */ + public override void WriteContent(Stream result) { + result.Write(NEW_PAGE, 0, NEW_PAGE.Length); + result.Write(RtfParagraph.PARAGRAPH_DEFAULTS, 0, RtfParagraph.PARAGRAPH_DEFAULTS.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfParagraph.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfParagraph.cs new file mode 100644 index 0000000..235feff --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfParagraph.cs @@ -0,0 +1,196 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.graphic; +using ST = iTextSharp.text.rtf.style; +/* + * $Id: RtfParagraph.cs,v 1.11 2008/05/16 19:31:24 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfParagraph is an extension of the RtfPhrase that adds alignment and + * indentation properties. It wraps a Paragraph. + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfParagraph : RtfPhrase { + + /** + * Constant for the end of a paragraph + */ + public static byte[] PARAGRAPH = DocWriter.GetISOBytes("\\par"); + /** + * An optional RtfParagraphStyle to use for styling. + */ + protected ST.RtfParagraphStyle paragraphStyle = null; + + /** + * Constructs a RtfParagraph belonging to a RtfDocument based on a Paragraph. + * + * @param doc The RtfDocument this RtfParagraph belongs to + * @param paragraph The Paragraph that this RtfParagraph is based on + */ + public RtfParagraph(RtfDocument doc, Paragraph paragraph) : base(doc) { + ST.RtfFont baseFont = null; + if (paragraph.Font is ST.RtfParagraphStyle) { + this.paragraphStyle = this.document.GetDocumentHeader().GetRtfParagraphStyle(((ST.RtfParagraphStyle) paragraph.Font).GetStyleName()); + baseFont = this.paragraphStyle; + } else { + baseFont = new ST.RtfFont(this.document, paragraph.Font); + this.paragraphStyle = new ST.RtfParagraphStyle(this.document, this.document.GetDocumentHeader().GetRtfParagraphStyle("Normal")); + this.paragraphStyle.SetAlignment(paragraph.Alignment); + this.paragraphStyle.SetFirstLineIndent((int) (paragraph.FirstLineIndent * RtfElement.TWIPS_FACTOR)); + this.paragraphStyle.SetIndentLeft((int) (paragraph.IndentationLeft * RtfElement.TWIPS_FACTOR)); + this.paragraphStyle.SetIndentRight((int) (paragraph.IndentationRight * RtfElement.TWIPS_FACTOR)); + this.paragraphStyle.SetSpacingBefore((int) (paragraph.SpacingBefore * RtfElement.TWIPS_FACTOR)); + this.paragraphStyle.SetSpacingAfter((int) (paragraph.SpacingAfter * RtfElement.TWIPS_FACTOR)); + if (paragraph.HasLeading()) { + this.paragraphStyle.SetLineLeading((int) (paragraph.Leading * RtfElement.TWIPS_FACTOR)); + } + this.paragraphStyle.SetKeepTogether(paragraph.KeepTogether); + } + + for (int i = 0; i < paragraph.Count; i++) { + IElement chunk = (IElement) paragraph[i]; + if (chunk is Chunk) { + ((Chunk) chunk).Font = baseFont.Difference(((Chunk) chunk).Font); + } else if (chunk is RtfImage) { + ((RtfImage) chunks[i]).SetAlignment(this.paragraphStyle.GetAlignment()); + } + try { + IRtfBasicElement[] rtfElements = doc.GetMapper().MapElement(chunk); + for(int j = 0; j < rtfElements.Length; j++) { + chunks.Add(rtfElements[j]); + } + } catch (DocumentException) { + } + } + } + + /** + * Set whether this RtfParagraph must stay on the same page as the next one. + * + * @param keepTogetherWithNext Whether this RtfParagraph must keep together with the next. + */ + public void SetKeepTogetherWithNext(bool keepTogetherWithNext) { + this.paragraphStyle.SetKeepTogetherWithNext(keepTogetherWithNext); + } + + /** + * Writes the content of this RtfParagraph. First paragraph specific data is written + * and then the RtfChunks of this RtfParagraph are added. + */ + public override void WriteContent(Stream result) { + result.Write(PARAGRAPH_DEFAULTS, 0, PARAGRAPH_DEFAULTS.Length); + result.Write(PLAIN, 0, PLAIN.Length); + if (inTable) { + result.Write(IN_TABLE, 0, IN_TABLE.Length); + } + if(this.paragraphStyle != null) { + this.paragraphStyle.WriteBegin(result); + } + result.Write(PLAIN, 0, PLAIN.Length); + for (int i = 0; i < chunks.Count; i++) { + IRtfBasicElement rbe = (IRtfBasicElement)chunks[i]; + rbe.WriteContent(result); + } + if(this.paragraphStyle != null) { + this.paragraphStyle.WriteEnd(result); + } + if (!inTable) { + result.Write(PARAGRAPH, 0, PARAGRAPH.Length); + } + if(this.document.GetDocumentSettings().IsOutputDebugLineBreaks()) { + result.WriteByte((byte)'\n'); + } + } + + /** + * Gets the left indentation of this RtfParagraph. + * + * @return The left indentation. + */ + public int GetIndentLeft() { + return this.paragraphStyle.GetIndentLeft(); + } + + /** + * Sets the left indentation of this RtfParagraph. + * + * @param indentLeft The left indentation to use. + */ + public void SetIndentLeft(int indentLeft) { + this.paragraphStyle.SetIndentLeft(indentLeft); + } + + /** + * Gets the right indentation of this RtfParagraph. + * + * @return The right indentation. + */ + public int GetIndentRight() { + return this.paragraphStyle.GetIndentRight(); + } + + /** + * Sets the right indentation of this RtfParagraph. + * + * @param indentRight The right indentation to use. + */ + public void SetIndentRight(int indentRight) { + this.paragraphStyle.SetIndentRight(indentRight); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfPhrase.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfPhrase.cs new file mode 100644 index 0000000..081fc85 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfPhrase.cs @@ -0,0 +1,198 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.style; +using ST = iTextSharp.text.rtf.style; + +/* + * $Id: RtfPhrase.cs,v 1.10 2008/05/16 19:31:24 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfPhrase contains multiple RtfChunks + * + * @version $Id: RtfPhrase.cs,v 1.10 2008/05/16 19:31:24 psoares33 Exp $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfPhrase : RtfElement { + + /** + * Constant for the resetting of the paragraph defaults + */ + public static byte[] PARAGRAPH_DEFAULTS = DocWriter.GetISOBytes("\\pard"); + /** + * Constant for resetting of font settings to their defaults + */ + public static byte[] PLAIN = DocWriter.GetISOBytes("\\plain"); + /** + * Constant for phrase in a table indication + */ + public static byte[] IN_TABLE = DocWriter.GetISOBytes("\\intbl"); + /** + * Constant for the line spacing. + */ + public static byte[] LINE_SPACING = DocWriter.GetISOBytes("\\sl"); + + /** + * ArrayList containing the RtfChunks of this RtfPhrase + */ + protected ArrayList chunks = new ArrayList(); + /** + * The height of each line. + */ + private int lineLeading = 0; + + /** + * A basically empty constructor that is used by the RtfParagraph. + * + * @param doc The RtfDocument this RtfPhrase belongs to. + */ + protected internal RtfPhrase(RtfDocument doc) : base(doc) { + } + + /** + * Constructs a new RtfPhrase for the RtfDocument with the given Phrase + * + * @param doc The RtfDocument this RtfPhrase belongs to + * @param phrase The Phrase this RtfPhrase is based on + */ + public RtfPhrase(RtfDocument doc, Phrase phrase) : base(doc) { + + if (phrase == null) { + return; + } + + if (phrase.HasLeading()) { + this.lineLeading = (int) (phrase.Leading * TWIPS_FACTOR); + } else { + this.lineLeading = 0; + } + + ST.RtfFont phraseFont = new ST.RtfFont(null, phrase.Font); + for (int i = 0; i < phrase.Count; i++) { + IElement chunk = (IElement) phrase[i]; + if (chunk is Chunk) { + ((Chunk) chunk).Font = phraseFont.Difference(((Chunk) chunk).Font); + } + try { + IRtfBasicElement[] rtfElements = doc.GetMapper().MapElement(chunk); + for (int j = 0; j < rtfElements.Length; j++) { + chunks.Add(rtfElements[j]); + } + } catch (DocumentException) { + } + } + } + + /** + * Write the content of this RtfPhrase. First resets to the paragraph defaults + * then if the RtfPhrase is in a RtfCell a marker for this is written and finally + * the RtfChunks of this RtfPhrase are written. + */ + public override void WriteContent(Stream result) { + byte[] t; + result.Write(PARAGRAPH_DEFAULTS, 0, PARAGRAPH_DEFAULTS.Length); + result.Write(PLAIN, 0, PLAIN.Length); + if (inTable) { + result.Write(IN_TABLE, 0, IN_TABLE.Length); + } + if (this.lineLeading > 0) { + result.Write(LINE_SPACING, 0, LINE_SPACING.Length); + result.Write(t = IntToByteArray(this.lineLeading), 0, t.Length); + } + foreach (IRtfBasicElement rbe in chunks) { + rbe.WriteContent(result); + } + } + + /** + * Sets whether this RtfPhrase is in a table. Sets the correct inTable setting for all + * child elements. + * + * @param inTable True if this RtfPhrase is in a table, false otherwise + */ + public override void SetInTable(bool inTable) { + base.SetInTable(inTable); + for (int i = 0; i < this.chunks.Count; i++) { + ((IRtfBasicElement) this.chunks[i]).SetInTable(inTable); + } + } + + /** + * Sets whether this RtfPhrase is in a header. Sets the correct inTable setting for all + * child elements. + * + * @param inHeader True if this RtfPhrase is in a header, false otherwise + */ + public override void SetInHeader(bool inHeader) { + base.SetInHeader(inHeader); + for (int i = 0; i < this.chunks.Count; i++) { + ((IRtfBasicElement) this.chunks[i]).SetInHeader(inHeader); + } + } + + /** + * Sets the RtfDocument this RtfPhrase belongs to. Also sets the RtfDocument for all child + * elements. + * + * @param doc The RtfDocument to use + */ + public override void SetRtfDocument(RtfDocument doc) { + base.SetRtfDocument(doc); + for (int i = 0; i < this.chunks.Count; i++) { + ((IRtfBasicElement) this.chunks[i]).SetRtfDocument(this.document); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfSection.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfSection.cs new file mode 100644 index 0000000..e6c2f9d --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfSection.cs @@ -0,0 +1,183 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; +using iTextSharp.text; +using iTextSharp.text.rtf.document; +using iTextSharp.text.rtf.field; +using FD = iTextSharp.text.rtf.field; +using iTextSharp.text.rtf; +/* + * $Id: RtfSection.cs,v 1.9 2008/05/16 19:31:24 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfSection wraps a Section element. + * INTERNAL CLASS + * + * @version $Version:$ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfSection : RtfElement { + + /** + * The title paragraph of this RtfSection + */ + protected RtfParagraph title = null; + /** + * The sub-items of this RtfSection + */ + protected ArrayList items = null; + + /** + * Constructs a RtfSection for a given Section. If the autogenerateTOCEntries + * property of the RtfDocument is set and the title is not empty then a TOC entry + * is generated for the title. + * + * @param doc The RtfDocument this RtfSection belongs to + * @param section The Section this RtfSection is based on + */ + public RtfSection(RtfDocument doc, Section section) : base(doc) { + items = new ArrayList(); + try { + if (section.Title != null) { + this.title = (RtfParagraph) doc.GetMapper().MapElement(section.Title)[0]; + } + if (document.GetAutogenerateTOCEntries()) { + StringBuilder titleText = new StringBuilder(); + foreach (IElement element in section.Title) { + if (element.Type == Element.CHUNK) { + titleText.Append(((Chunk) element).Content); + } + } + if (titleText.ToString().Trim().Length > 0) { + FD.RtfTOCEntry tocEntry = new FD.RtfTOCEntry(titleText.ToString()); + tocEntry.SetRtfDocument(this.document); + this.items.Add(tocEntry); + } + } + foreach (IElement element in section) { + IRtfBasicElement[] rtfElements = doc.GetMapper().MapElement(element); + for (int i = 0; i < rtfElements.Length; i++) { + if (rtfElements[i] != null) { + items.Add(rtfElements[i]); + } + } + } + UpdateIndentation(section.IndentationLeft, section.IndentationRight, section.Indentation); + } catch (DocumentException) { + } + } + + /** + * Write this RtfSection and its contents + */ + public override void WriteContent(Stream result) { + result.Write(RtfParagraph.PARAGRAPH, 0, RtfParagraph.PARAGRAPH.Length); + if (this.title != null) { + this.title.WriteContent(result); + } + foreach (IRtfBasicElement rbe in items) { + rbe.WriteContent(result); + } + } + + /** + * Sets whether this RtfSection is in a table. Sets the correct inTable setting for all + * child elements. + * + * @param inTable True if this RtfSection is in a table, false otherwise + */ + public override void SetInTable(bool inTable) { + base.SetInTable(inTable); + for (int i = 0; i < this.items.Count; i++) { + ((IRtfBasicElement) this.items[i]).SetInTable(inTable); + } + } + + /** + * Sets whether this RtfSection is in a header. Sets the correct inTable setting for all + * child elements. + * + * @param inHeader True if this RtfSection is in a header, false otherwise + */ + public override void SetInHeader(bool inHeader) { + base.SetInHeader(inHeader); + for (int i = 0; i < this.items.Count; i++) { + ((IRtfBasicElement) this.items[i]).SetInHeader(inHeader); + } + } + + /** + * Updates the left, right and content indentation of all RtfParagraph and RtfSection + * elements that this RtfSection contains. + * + * @param indentLeft The left indentation to add. + * @param indentRight The right indentation to add. + * @param indentContent The content indentation to add. + */ + private void UpdateIndentation(float indentLeft, float indentRight, float indentContent) { + if(this.title != null) { + this.title.SetIndentLeft((int) (this.title.GetIndentLeft() + indentLeft * RtfElement.TWIPS_FACTOR)); + this.title.SetIndentRight((int) (this.title.GetIndentRight() + indentRight * RtfElement.TWIPS_FACTOR)); + } + for(int i = 0; i < this.items.Count; i++) { + IRtfBasicElement rtfElement = (IRtfBasicElement) this.items[i]; + if(rtfElement is RtfSection) { + ((RtfSection) rtfElement).UpdateIndentation(indentLeft + indentContent, indentRight, 0); + } else if(rtfElement is RtfParagraph) { + ((RtfParagraph) rtfElement).SetIndentLeft((int) (((RtfParagraph) rtfElement).GetIndentLeft() + (indentLeft + indentContent) * RtfElement.TWIPS_FACTOR)); + ((RtfParagraph) rtfElement).SetIndentRight((int) (((RtfParagraph) rtfElement).GetIndentRight() + indentRight * RtfElement.TWIPS_FACTOR)); + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfTab.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfTab.cs new file mode 100644 index 0000000..1f5a196 --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfTab.cs @@ -0,0 +1,135 @@ +using System; +using System.IO; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfTab.cs,v 1.5 2008/05/23 17:24:29 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * Co-Developer of the code is Mark Hall. Portions created by the Co-Developer are + * Copyright (C) 2006 by Mark Hall. All Rights Reserved + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfTab encapsulates a tab position and tab type in a paragraph. + * To add tabs to a paragraph construct new RtfTab objects with the desired + * tab position and alignment and then add them to the paragraph. In the actual + * text the tabs are then defined as standard \t characters.

      + * + * RtfTab tab = new RtfTab(300, RtfTab.TAB_LEFT_ALIGN);
      + * Paragraph para = new Paragraph();
      + * para.Add(tab);
      + * para.Add("This paragraph has a\ttab defined.");
      + * + * @version $Revision: 1.5 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfTab : RtfAddableElement { + + /** + * A tab where the text is left aligned. + */ + public const int TAB_LEFT_ALIGN = 0; + /** + * A tab where the text is centre aligned. + */ + public const int TAB_CENTER_ALIGN = 1; + /** + * A tab where the text is right aligned. + */ + public const int TAB_RIGHT_ALIGN = 2; + /** + * A tab where the text is aligned on the decimal character. Which + * character that is depends on the language settings of the viewer. + */ + public const int TAB_DECIMAL_ALIGN = 3; + + /** + * The tab position in twips. + */ + private int position = 0; + /** + * The tab alignment. + */ + private int type = TAB_LEFT_ALIGN; + + /** + * Constructs a new RtfTab with the given position and type. The position + * is in standard iText points. The type is one of the tab alignment + * constants defined in the RtfTab. + * + * @param position The position of the tab in points. + * @param type The tab type constant. + */ + public RtfTab(float position, int type) { + this.position = (int) Math.Round(position * RtfElement.TWIPS_FACTOR); + switch (type) { + case TAB_LEFT_ALIGN: this.type = TAB_LEFT_ALIGN; break; + case TAB_CENTER_ALIGN: this.type = TAB_CENTER_ALIGN; break; + case TAB_RIGHT_ALIGN: this.type = TAB_RIGHT_ALIGN; break; + case TAB_DECIMAL_ALIGN: this.type = TAB_DECIMAL_ALIGN; break; + default: this.type = TAB_LEFT_ALIGN; break; + } + } + + /** + * Writes the tab settings. + */ + public override void WriteContent(Stream result) { + byte[] t; + switch (this.type) { + case TAB_CENTER_ALIGN: result.Write(t = DocWriter.GetISOBytes("\\tqc"), 0, t.Length); break; + case TAB_RIGHT_ALIGN: result.Write(t = DocWriter.GetISOBytes("\\tqr"), 0, t.Length); break; + case TAB_DECIMAL_ALIGN: result.Write(t = DocWriter.GetISOBytes("\\tqdec"), 0, t.Length); break; + } + result.Write(t = DocWriter.GetISOBytes("\\tx"), 0, t.Length); + result.Write(t = IntToByteArray(this.position), 0, t.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/rtf/text/RtfTabGroup.cs b/iTechSharp/iTextSharp/text/rtf/text/RtfTabGroup.cs new file mode 100644 index 0000000..c51689d --- /dev/null +++ b/iTechSharp/iTextSharp/text/rtf/text/RtfTabGroup.cs @@ -0,0 +1,121 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.rtf; +/* + * $Id: RtfTabGroup.cs,v 1.5 2008/05/23 17:24:29 psoares33 Exp $ + * + * + * Copyright 2001, 2002, 2003, 2004 by Mark Hall + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * Co-Developer of the code is Mark Hall. Portions created by the Co-Developer are + * Copyright (C) 2006 by Mark Hall. All Rights Reserved + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.rtf.text { + + /** + * The RtfTabGroup is a convenience class if the same tabs are to be added + * to multiple paragraphs.

      + * + * RtfTabGroup tabs = new RtfTabGroup();
      + * tabs.Add(new RtfTab(70, RtfTab.TAB_LEFT_ALIGN));
      + * tabs.Add(new RtfTab(160, RtfTab.TAB_CENTER_ALIGN));
      + * tabs.Add(new RtfTab(250, RtfTab.TAB_DECIMAL_ALIGN));
      + * tabs.Add(new RtfTab(500, RtfTab.TAB_RIGHT_ALIGN));
      + * Paragraph para = new Paragraph();
      + * para.Add(tabs);
      + * para.Add("\tLeft aligned\tCentre aligned\t12,45\tRight aligned");
      + * + * @version $Revision: 1.5 $ + * @author Mark Hall (Mark.Hall@mail.room3b.eu) + */ + public class RtfTabGroup : RtfAddableElement { + /** + * The tabs to add. + */ + private ArrayList tabs = null; + + /** + * Constructs an empty RtfTabGroup. + */ + public RtfTabGroup() { + this.tabs = new ArrayList(); + } + + /** + * Constructs a RtfTabGroup with a set of tabs. + * + * @param tabs An ArrayList with the RtfTabs to group in this RtfTabGroup. + */ + public RtfTabGroup(ArrayList tabs) { + this.tabs = new ArrayList(); + for (int i = 0; i < tabs.Count; i++) { + if (tabs[i] is RtfTab) { + this.tabs.Add(tabs[i]); + } + } + } + + /** + * Adds a RtfTab to the list of grouped tabs. + * + * @param tab The RtfTab to add. + */ + public void Add(RtfTab tab) { + this.tabs.Add(tab); + } + + /** + * Combines the tab output form all grouped tabs. + */ + public override void WriteContent(Stream result) { + foreach (RtfTab rt in tabs) { + rt.WriteContent(result); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/ITextHandler.cs b/iTechSharp/iTextSharp/text/xml/ITextHandler.cs new file mode 100644 index 0000000..eb7d80c --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/ITextHandler.cs @@ -0,0 +1,872 @@ +using System; +using System.Collections; +using System.util; +using System.Text; +using System.Xml; + +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.draw; +using iTextSharp.text.xml.simpleparser; +using iTextSharp.text.html; +using iTextSharp.text.factories; + +/* + * $Id: ITextHandler.cs,v 1.21 2008/05/13 11:26:11 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml { + + /// + /// The iTextHandler-class maps several XHTML-tags to iText-objects. + /// + public class ITextHandler : ParserBase { + + /// This is the resulting document. + protected IDocListener document; + + /// This is a Stack of objects, waiting to be added to the document. + protected Stack stack; + + /// Counts the number of chapters in this document. + protected int chapters = 0; + + /// This is the current chunk to which characters can be added. + protected Chunk currentChunk = null; + + /// This is the current chunk to which characters can be added. + protected bool ignore = false; + + /// This is a flag that can be set, if you want to open and close the Document-object yourself. + protected bool controlOpenClose = true; + + /** current margin of a page. */ + float topMargin = 36; + + /** current margin of a page. */ + float rightMargin = 36; + + /** current margin of a page. */ + float leftMargin = 36; + + /** current margin of a page. */ + float bottomMargin = 36; + + /// + /// Constructs a new iTextHandler that will translate all the events + /// triggered by the parser to actions on the Document-object. + /// + /// this is the document on which events must be triggered + public ITextHandler(IDocListener document) : base() { + this.document = document; + stack = new Stack(); + } + + protected Hashtable myTags; + + /** + * @param document + * @param myTags + * @throws DocumentException + * @throws IOException + */ + public ITextHandler(IDocListener document, HtmlTagMap myTags) : this(document) { + this.myTags = myTags; + } + + /** + * @param document + * @param myTags + * @param bf + * @throws DocumentException + * @throws IOException + */ + public ITextHandler(IDocListener document, HtmlTagMap myTags, BaseFont bf) : this(document, myTags) { + this.bf = bf; + } + + /** + * @param document + * @param myTags + * @throws DocumentException + * @throws IOException + */ + public ITextHandler(IDocListener document, Hashtable myTags) : this(document) { + this.myTags = myTags; + } + + /// + /// Sets the parameter that allows you to enable/disable the control over the Document.Open() and Document.Close() method. + /// + /// + /// If you set this parameter to true (= default), the parser will open the Document object when the start-root-tag is encountered + /// and close it when the end-root-tag is met. If you set it to false, you have to open and close the Document object + /// yourself. + /// + /// set this to false if you plan to open/close the Document yourself + public void SetControlOpenClose(bool controlOpenClose) { + this.controlOpenClose = controlOpenClose; + } + + /// + /// This method gets called when a start tag is encountered. + /// + /// + /// + /// the name of the tag that is encountered + /// the list of attributes + public override void StartElement(String uri, String lname, String name, Hashtable attrs) { + + Properties attributes = new Properties(); + if (attrs != null) { + foreach (string key in attrs.Keys) { + attributes.Add(key, (string)attrs[key]); + } + } + HandleStartingTags(name, attributes); + } + + /// + /// This method deals with the starting tags. + /// + /// the name of the tag + /// the list of attributes + public void HandleStartingTags(String name, Properties attributes) { + //System.err.Println("Start: " + name); + if (ignore || ElementTags.IGNORE.Equals(name)) { + ignore = true; + return; + } + + // maybe there is some meaningful data that wasn't between tags + if (currentChunk != null) { + ITextElementArray current; + try { + current = (ITextElementArray) stack.Pop(); + } + catch { + if (bf == null) { + current = new Paragraph("", new Font()); + } + else { + current = new Paragraph("", new Font(this.bf)); + } + } + current.Add(currentChunk); + stack.Push(current); + currentChunk = null; + } + + // registerfont + if (name.Equals("registerfont")) { + FontFactory.Register(attributes); + } + + // header + if (ElementTags.HEADER.Equals(name)) { + stack.Push(new HeaderFooter(attributes)); + return; + } + + // footer + if (ElementTags.FOOTER.Equals(name)) { + stack.Push(new HeaderFooter(attributes)); + return; + } + + // before + if (name.Equals("before")) { + HeaderFooter tmp = (HeaderFooter)stack.Pop(); + + tmp.Before = ElementFactory.GetPhrase(attributes); + stack.Push(tmp); + return; + } + + // after + if (name.Equals("after")) { + HeaderFooter tmp = (HeaderFooter)stack.Pop(); + + tmp.After = ElementFactory.GetPhrase(attributes); + stack.Push(tmp); + return; + } + + // chunks + if (ElementTags.CHUNK.Equals(name)) { + currentChunk = ElementFactory.GetChunk(attributes); + if (bf != null) { + currentChunk.Font = new Font(this.bf); + } + return; + } + + // symbols + if (ElementTags.ENTITY.Equals(name)) { + Font f = new Font(); + if (currentChunk != null) { + HandleEndingTags(ElementTags.CHUNK); + f = currentChunk.Font; + } + currentChunk = EntitiesToSymbol.Get(attributes[ElementTags.ID], f); + return; + } + + // phrases + if (ElementTags.PHRASE.Equals(name)) { + stack.Push(ElementFactory.GetPhrase(attributes)); + return; + } + + // anchors + if (ElementTags.ANCHOR.Equals(name)) { + stack.Push(ElementFactory.GetAnchor(attributes)); + return; + } + + // paragraphs and titles + if (ElementTags.PARAGRAPH.Equals(name) || ElementTags.TITLE.Equals(name)) { + stack.Push(ElementFactory.GetParagraph(attributes)); + return; + } + + // lists + if (ElementTags.LIST.Equals(name)) { + stack.Push(ElementFactory.GetList(attributes)); + return; + } + + // listitems + if (ElementTags.LISTITEM.Equals(name)) { + stack.Push(ElementFactory.GetListItem(attributes)); + return; + } + + // cells + if (ElementTags.CELL.Equals(name)) { + stack.Push(ElementFactory.GetCell(attributes)); + return; + } + + // tables + if (ElementTags.TABLE.Equals(name)) { + Table table = ElementFactory.GetTable(attributes); + float[] widths = table.ProportionalWidths; + for (int i = 0; i < widths.Length; i++) { + if (widths[i] == 0) { + widths[i] = 100.0f / (float)widths.Length; + } + } + try { + table.Widths = widths; + } + catch (BadElementException bee) { + // this shouldn't happen + throw new Exception("", bee); + } + stack.Push(table); + return; + } + + // sections + if (ElementTags.SECTION.Equals(name)) { + IElement previous = (IElement) stack.Pop(); + Section section; + section = ElementFactory.GetSection((Section) previous, attributes); + stack.Push(previous); + stack.Push(section); + return; + } + + // chapters + if (ElementTags.CHAPTER.Equals(name)) { + stack.Push(ElementFactory.GetChapter(attributes)); + return; + } + + // images + if (ElementTags.IMAGE.Equals(name)) { + try { + Image img = ElementFactory.GetImage(attributes); + try { + AddImage(img); + return; + } + catch { + // if there is no element on the stack, the Image is added to the document + try { + document.Add(img); + } + catch (DocumentException de) { + throw new Exception("", de); + } + return; + } + } + catch (Exception e) { + throw new Exception("", e); + } + } + + // annotations + if (ElementTags.ANNOTATION.Equals(name)) { + Annotation annotation = ElementFactory.GetAnnotation(attributes); + ITextElementArray current; + try { + try { + current = (ITextElementArray) stack.Pop(); + try { + current.Add(annotation); + } + catch { + document.Add(annotation); + } + stack.Push(current); + } + catch { + document.Add(annotation); + } + return; + } + catch (DocumentException de) { + throw de; + } + } + + // newlines + if (IsNewline(name)) { + ITextElementArray current; + try { + current = (ITextElementArray) stack.Pop(); + current.Add(Chunk.NEWLINE); + stack.Push(current); + } + catch { + if (currentChunk == null) { + try { + document.Add(Chunk.NEWLINE); + } + catch (DocumentException de) { + throw de; + } + } + else { + currentChunk.Append("\n"); + } + } + return; + } + + // newpage + if (IsNewpage(name)) { + ITextElementArray current; + try { + current = (ITextElementArray) stack.Pop(); + Chunk newPage = new Chunk(""); + newPage.SetNewPage(); + if (bf != null) { + newPage.Font = new Font(this.bf); + } + current.Add(newPage); + stack.Push(current); + } + catch { + document.NewPage(); + } + return; + } + + if (ElementTags.HORIZONTALRULE.Equals(name)) { + ITextElementArray current; + LineSeparator hr = new LineSeparator(1.0f, 100.0f, null, Element.ALIGN_CENTER, 0); + try { + current = (ITextElementArray)stack.Pop(); + current.Add(hr); + stack.Push(current); + } catch (InvalidOperationException) { + document.Add(hr); + } + return; + } + + // documentroot + if (IsDocumentRoot(name)) { + String value; + // pagesize and orientation specific code suggested by Samuel Gabriel + // Updated by Ricardo Coutinho. Only use if set in html! + Rectangle pageSize = null; + String orientation = null; + foreach (string key in attributes.Keys) { + value = attributes[key]; + // margin specific code suggested by Reza Nasiri + if (Util.EqualsIgnoreCase(ElementTags.LEFT, key)) + leftMargin = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + if (Util.EqualsIgnoreCase(ElementTags.RIGHT, key)) + rightMargin = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + if (Util.EqualsIgnoreCase(ElementTags.TOP, key)) + topMargin = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + if (Util.EqualsIgnoreCase(ElementTags.BOTTOM, key)) + bottomMargin = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + if (ElementTags.PAGE_SIZE.Equals(key)) { + pageSize = (Rectangle)typeof(PageSize).GetField(value).GetValue(null); + } else if (ElementTags.ORIENTATION.Equals(key)) { + if ("landscape".Equals(value)) { + orientation = "landscape"; + } + } else { + document.Add(new Meta(key, value)); + } + } + if (pageSize != null) { + if ("landscape".Equals(orientation)) { + pageSize = pageSize.Rotate(); + } + document.SetPageSize(pageSize); + } + document.SetMargins(leftMargin, rightMargin, topMargin, + bottomMargin); + if (controlOpenClose) + document.Open(); + } + } + + protected internal void AddImage(Image img) { + // if there is an element on the stack... + Object current = stack.Pop(); + // ...and it's a Chapter or a Section, the Image can be + // added directly + if (current is Chapter + || current is Section + || current is Cell) { + ((ITextElementArray) current).Add(img); + stack.Push(current); + return; + } + // ...if not, we need to to a lot of stuff + else { + Stack newStack = new Stack(); + while (!(current is Chapter + || current is Section || current is Cell)) { + newStack.Push(current); + if (current is Anchor) { + img.Annotation = new Annotation(0, 0, 0, + 0, ((Anchor) current).Reference); + } + current = stack.Pop(); + } + ((ITextElementArray) current).Add(img); + stack.Push(current); + while (newStack.Count != 0) { + stack.Push(newStack.Pop()); + } + return; + } + } + + /// + /// This method gets called when ignorable white space encountered. + /// + /// an array of characters + /// the start position in the array + /// the number of characters to read from the array + public void IgnorableWhitespace(char[] ch, int start, int length) { + // do nothing: we handle white space ourselves in the characters method + } + + /// + /// This method gets called when characters are encountered. + /// + /// an array of characters + /// the start position in the array + /// the number of characters to read from the array + public override void Characters(string content, int start, int length) { + + if (ignore) return; + + if (content.Trim().Length == 0 && content.IndexOf(' ') < 0) { + return; + } + + StringBuilder buf = new StringBuilder(); + int len = content.Length; + char character; + bool newline = false; + for (int i = 0; i < len; i++) { + switch (character = content[i]) { + case ' ': + if (!newline) { + buf.Append(character); + } + break; + case '\n': + if (i > 0) { + newline = true; + buf.Append(' '); + } + break; + case '\r': + break; + case '\t': + break; + default: + newline = false; + buf.Append(character); + break; + } + } + + string tmp = buf.ToString(); + string rline = new String('\r', 1); + string nline = new String('\n', 1); + string tline = new String('\t', 1); + tmp = tmp.Replace("\\n", nline); + tmp = tmp.Replace("\\t", tline); + tmp = tmp.Replace("\\r", rline); + + if (currentChunk == null) { + if (bf == null) { + currentChunk = new Chunk(buf.ToString()); + } + else { + currentChunk = new Chunk(buf.ToString(), new Font(this.bf)); + } + } else { + currentChunk.Append(buf.ToString()); + } + } + + private BaseFont bf = null; + + public BaseFont DefaultFont { + set { + bf = value; + } + get { + return bf; + } + } + + /// + /// This method gets called when an end tag is encountered. + /// + /// + /// + /// the name of the tag that ends + public override void EndElement(String uri, String lname, String name) { + HandleEndingTags(name); + } + + /// + /// This method deals with the starting tags. + /// + /// the name of the tag + public void HandleEndingTags(String name) { + + //System.err.Println("Stop: " + name); + + if (ElementTags.IGNORE.Equals(name)) { + ignore = false; + return; + } + if (ignore) return; + // tags that don't have any content + if (IsNewpage(name) || ElementTags.ANNOTATION.Equals(name) || ElementTags.IMAGE.Equals(name) || IsNewline(name)) { + return; + } + + try { + // titles of sections and chapters + if (ElementTags.TITLE.Equals(name)) { + Paragraph current = (Paragraph) stack.Pop(); + if (currentChunk != null) { + current.Add(currentChunk); + currentChunk = null; + } + Section previous = (Section) stack.Pop(); + previous.Title = current; + stack.Push(previous); + return; + } + + // all other endtags + if (currentChunk != null) { + ITextElementArray current; + try { + current = (ITextElementArray) stack.Pop(); + } + catch { + current = new Paragraph(); + } + current.Add(currentChunk); + stack.Push(current); + currentChunk = null; + } + + // chunks + if (ElementTags.CHUNK.Equals(name)) { + return; + } + + // phrases, anchors, lists, tables + if (ElementTags.PHRASE.Equals(name) || ElementTags.ANCHOR.Equals(name) || ElementTags.LIST.Equals(name) + || ElementTags.PARAGRAPH.Equals(name)) { + IElement current = (IElement) stack.Pop(); + try { + ITextElementArray previous = (ITextElementArray) stack.Pop(); + previous.Add(current); + stack.Push(previous); + } + catch { + document.Add(current); + } + return; + } + + // listitems + if (ElementTags.LISTITEM.Equals(name)) { + ListItem listItem = (ListItem) stack.Pop(); + List list = (List) stack.Pop(); + list.Add(listItem); + stack.Push(list); + } + + // tables + if (ElementTags.TABLE.Equals(name)) { + Table table = (Table) stack.Pop(); + try { + ITextElementArray previous = (ITextElementArray) stack.Pop(); + previous.Add(table); + stack.Push(previous); + } + catch { + document.Add(table); + } + return; + } + + // rows + if (ElementTags.ROW.Equals(name)) { + ArrayList cells = new ArrayList(); + int columns = 0; + Table table; + Cell cell; + while (true) { + IElement element = (IElement) stack.Pop(); + if (element.Type == Element.CELL) { + cell = (Cell) element; + columns += cell.Colspan; + cells.Add(cell); + } + else { + table = (Table) element; + break; + } + } + if (table.Columns < columns) { + table.AddColumns(columns - table.Columns); + } + cells.Reverse(0, cells.Count); + String width; + float[] cellWidths = new float[columns]; + bool[] cellNulls = new bool[columns]; + for (int i = 0; i < columns; i++) { + cellWidths[i] = 0; + cellNulls[i] = true; + } + float total = 0; + int j = 0; + foreach (Cell c in cells) { + cell = c; + width = cell.GetWidthAsString(); + if (cell.Width == 0) { + if (cell.Colspan == 1 && cellWidths[j] == 0) { + try { + cellWidths[j] = 100f / columns; + total += cellWidths[j]; + } + catch { + // empty on purpose + } + } + else if (cell.Colspan == 1) { + cellNulls[j] = false; + } + } + else if (cell.Colspan == 1 && width.EndsWith("%")) { + try { + cellWidths[j] = float.Parse(width.Substring(0, width.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + total += cellWidths[j]; + } + catch { + // empty on purpose + } + } + j += cell.Colspan; + table.AddCell(cell); + } + float[] widths = table.ProportionalWidths; + if (widths.Length == columns) { + float left = 0.0f; + for (int i = 0; i < columns; i++) { + if (cellNulls[i] && widths[i] != 0) { + left += widths[i]; + cellWidths[i] = widths[i]; + } + } + if (100.0 >= total) { + for (int i = 0; i < widths.Length; i++) { + if (cellWidths[i] == 0 && widths[i] != 0) { + cellWidths[i] = (widths[i] / left) * (100.0f - total); + } + } + } + table.Widths = cellWidths; + } + stack.Push(table); + } + + // registerfont + if (name.Equals("registerfont")) { + return; + } + + // header + if (ElementTags.HEADER.Equals(name)) { + document.Header = (HeaderFooter)stack.Pop(); + return; + } + + // footer + if (ElementTags.FOOTER.Equals(name)) { + document.Footer = (HeaderFooter)stack.Pop(); + return; + } + + // before + if (name.Equals("before")) { + return; + } + + // after + if (name.Equals("after")) { + return; + } + + // cells + if (ElementTags.CELL.Equals(name)) { + return; + } + + // sections + if (ElementTags.SECTION.Equals(name)) { + stack.Pop(); + return; + } + + // chapters + if (ElementTags.CHAPTER.Equals(name)) { + document.Add((IElement) stack.Pop()); + return; + } + + // the documentroot + if (IsDocumentRoot(name)) { + try { + while (true) { + IElement element = (IElement) stack.Pop(); + try { + ITextElementArray previous = (ITextElementArray) stack.Pop(); + previous.Add(element); + stack.Push(previous); + } + catch { + document.Add(element); + } + } + } + catch { + // empty on purpose + } + if (controlOpenClose) document.Close(); + return; + } + } + catch (DocumentException de) { + throw de; + } + } + + /// + /// Checks if a certain tag corresponds with the newpage-tag. + /// + /// a presumed tagname + /// true or false + private bool IsNewpage(String tag) { + return ElementTags.NEWPAGE.Equals(tag); + } + + /// + /// Checks if a certain tag corresponds with the newpage-tag. + /// + /// a presumed tagname + /// true or false + private bool IsNewline(String tag) { + return ElementTags.NEWLINE.Equals(tag); + } + + /// + /// Checks if a certain tag corresponds with the roottag. + /// + /// a presumed tagname + /// true if tag equals itext, false otherwise. + protected bool IsDocumentRoot(String tag) { + return ElementTags.ITEXT.Equals(tag); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/ITextmyHandler.cs b/iTechSharp/iTextSharp/text/xml/ITextmyHandler.cs new file mode 100644 index 0000000..8ebc622 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/ITextmyHandler.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text; + +/* + * $Id: ITextmyHandler.cs,v 1.5 2008/05/13 11:26:12 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml { + + /// + /// The iTextmyHandler-class maps several XHTML-tags to iText-objects. + /// + public class ITextmyHandler : ITextHandler { + + /// + /// Constructs a new iTextHandler that will translate all the events + /// triggered by the parser to actions on the Document-object. + /// + /// this is the document on which events must be triggered + /// a map of tags + public ITextmyHandler(IDocListener document, Hashtable myTags) : base(document, myTags) { + } + + /// + /// This method gets called when a start tag is encountered. + /// + /// + /// + /// the name of the tag that is encountered + /// the list of attributes + public override void StartElement(String uri, String lname, String name, Hashtable attrs) { + if (myTags.ContainsKey(name)) { + XmlPeer peer = (XmlPeer) myTags[name]; + HandleStartingTags(peer.Tag, peer.GetAttributes(attrs)); + } + else { + Properties attributes = new Properties(); + if (attrs != null) { + foreach (string key in attrs.Keys) { + attributes.Add(key, (string)attrs[key]); + } + } + HandleStartingTags(name, attributes); + } + } + + /// + /// This method gets called when an end tag is encountered. + /// + /// + /// + /// the name of the tag that ends + public override void EndElement(String uri, String lname, String name) { + if (myTags.ContainsKey(name)) { + XmlPeer peer = (XmlPeer) myTags[name]; + HandleEndingTags(peer.Tag); + } + else { + HandleEndingTags(name); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/ParserBase.cs b/iTechSharp/iTextSharp/text/xml/ParserBase.cs new file mode 100644 index 0000000..ed4048c --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/ParserBase.cs @@ -0,0 +1,99 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; + +namespace iTextSharp.text.xml +{ + /// + /// The ParserBase-class provides XML document parsing. + /// + public abstract class ParserBase + { + public void Parse(XmlDocument xDoc) { + string xml = xDoc.OuterXml; + StringReader stringReader = new StringReader(xml); + XmlTextReader reader = new XmlTextReader(stringReader); + this.Parse(reader); + } + + public void Parse(XmlTextReader reader) { + try { + while (reader.Read()) { + switch (reader.NodeType) { + case XmlNodeType.Element: + string namespaceURI = reader.NamespaceURI; + string name = reader.Name; + bool isEmpty = reader.IsEmptyElement; + Hashtable attributes = new Hashtable(); + if (reader.HasAttributes) { + for (int i = 0; i < reader.AttributeCount; i++) { + reader.MoveToAttribute(i); + attributes.Add(reader.Name,reader.Value); + } + } + this.StartElement(namespaceURI, name, name, attributes); + if (isEmpty) { + EndElement(namespaceURI, + name, name); + } + break; + case XmlNodeType.EndElement: + EndElement(reader.NamespaceURI, + reader.Name, reader.Name); + break; + case XmlNodeType.Text: + Characters(reader.Value, 0, reader.Value.Length); + break; + // There are many other types of nodes, but + // we are not interested in them + case XmlNodeType.Whitespace: + Characters(reader.Value, 0, reader.Value.Length); + break; + } + } + } catch (XmlException e) { + Console.WriteLine(e.Message); + } finally { + if (reader != null) { + reader.Close(); + } + } + } + + /// + /// Begins the process of processing an XML document + /// + /// the XML document to parse + public void Parse(string url) { + XmlTextReader reader = null; + reader = new XmlTextReader(url); + this.Parse(reader); + } + + /// + /// This method gets called when a start tag is encountered. + /// + /// + /// + /// the name of the tag that is encountered + /// the list of attributes + public abstract void StartElement(String uri, String lname, String name, Hashtable attrs); + + /// + /// This method gets called when an end tag is encountered. + /// + /// + /// + /// the name of the tag that ends + public abstract void EndElement(String uri, String lname, String name); + + /// + /// This method gets called when characters are encountered. + /// + /// an array of characters + /// the start position in the array + /// the number of characters to read from the array + public abstract void Characters(string content, int start, int length); + } +} diff --git a/iTechSharp/iTextSharp/text/xml/TagMap.cs b/iTechSharp/iTextSharp/text/xml/TagMap.cs new file mode 100644 index 0000000..9e74108 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/TagMap.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.util; + +using iTextSharp.text; + +/* + * $Id: TagMap.cs,v 1.3 2008/05/13 11:26:12 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml { + + /// + /// The TagMap-class maps several XHTML-tags to iText-objects. + /// + public class TagMap : Hashtable { + + class AttributeHandler : ParserBase { + + /// This is a tag + public const string TAG = "tag"; + + /// This is a tag + public const string ATTRIBUTE = "attribute"; + + /// This is an attribute + public const string NAME = "name"; + + /// This is an attribute + public const string ALIAS = "alias"; + + /// This is an attribute + public const string VALUE = "value"; + + /// This is an attribute + public const string CONTENT = "content"; + + /// This is the tagmap using the AttributeHandler + private Hashtable tagMap; + + /// This is the current peer. + private XmlPeer currentPeer; + + /// + /// Constructs a new SAXiTextHandler that will translate all the events + /// triggered by the parser to actions on the Document-object. + /// + /// A Hashtable containing XmlPeer-objects + public AttributeHandler(Hashtable tagMap) { + this.tagMap = tagMap; + } + + /// + /// This method gets called when a start tag is encountered. + /// + /// the name of the tag that is encountered + /// + /// + /// the list of attributes + public override void StartElement(String tag, String lname, String n, Hashtable attrs) { + String name = (string)attrs[NAME]; + String alias = (string)attrs[ALIAS]; + String value = (string)attrs[VALUE]; + if (name != null) { + if (TAG.Equals(lname)) { + currentPeer = new XmlPeer(name, alias); + } + else if (ATTRIBUTE.Equals(lname)) { + if (alias != null) { + currentPeer.AddAlias(name, alias); + } + if (value != null) { + currentPeer.AddValue(name, value); + } + } + } + value = (string)attrs[CONTENT]; + if (value != null) { + currentPeer.Content = value; + } + } + + /// + /// This method gets called when ignorable white space encountered. + /// + /// an array of characters + /// the start position in the array + /// the number of characters to read from the array + public void IgnorableWhitespace(char[] ch, int start, int length) { + // do nothing + } + + /// + /// This method gets called when characters are encountered. + /// + /// an array of characters + /// the start position in the array + /// the number of characters to read from the array + public override void Characters(string content, int start, int length) { + // do nothing + } + + /// + /// This method gets called when an end tag is encountered. + /// + /// the name of the tag that ends + /// + /// + public override void EndElement(String tag, String lname, String name) { + if (TAG.Equals(lname)) + tagMap.Add(currentPeer.Alias, currentPeer); + } + } + + /// + /// Constructs a Tagmap object + /// + /// the file of tags to parse + public TagMap(String tagfile) { + try { + Init(tagfile); + } catch (Exception e) { + throw e; + } + } + + /// + /// Constructs a Tagmap object + /// + /// the file of tags to parse + public TagMap(XmlDocument xTagfile) { + try { + Init(xTagfile); + } catch (Exception e) { + throw e; + } + } + + /// + /// Parses the xml document + /// + /// + protected void Init(XmlDocument xTagfile) { + try { + AttributeHandler a = new AttributeHandler(this); + a.Parse(xTagfile); + } + catch (Exception e) { + throw e; + } + } + + /// + /// Parses the xml document + /// + /// + protected void Init(string tagfile) { + try { + AttributeHandler a = new AttributeHandler(this); + a.Parse(tagfile); + } + catch (Exception e) { + throw e; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/XmlParser.cs b/iTechSharp/iTextSharp/text/xml/XmlParser.cs new file mode 100644 index 0000000..75ba9ef --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/XmlParser.cs @@ -0,0 +1,245 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: XmlParser.cs,v 1.5 2008/05/13 11:26:12 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml { + + /// + /// This class can be used to parse an XML file. + /// + public class XmlParser { + + /// This is the instance of the parser. + protected ITextHandler parser; + + /// + /// Constructs an XmlParser. + /// + public XmlParser() { + } + + /// + /// Parses a given file. + /// + /// + /// + public virtual void Go(IDocListener document, XmlDocument xDoc) { + parser = new ITextHandler(document); + parser.Parse(xDoc); + } + + /// + /// Parses a given file. + /// + /// + /// + public virtual void Go(IDocListener document, String file) { + parser = new ITextHandler(document); + parser.Parse(file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + public virtual void Go(IDocListener document, XmlTextReader reader) { + parser = new ITextHandler(document); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public virtual void Go(IDocListener document, XmlDocument xDoc, XmlDocument xTagmap) { + parser = new ITextmyHandler(document, new TagMap(xTagmap)); + parser.Parse(xDoc); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public virtual void Go(IDocListener document, XmlTextReader reader, String tagmap) { + parser = new ITextmyHandler(document, new TagMap(tagmap)); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public virtual void Go(IDocListener document, String file, String tagmap) { + parser = new ITextmyHandler(document, new TagMap(tagmap)); + parser.Parse(file); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public virtual void Go(IDocListener document, String file, Hashtable tagmap) { + parser = new ITextmyHandler(document, tagmap); + parser.Parse(file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public virtual void Go(IDocListener document, XmlTextReader reader, Hashtable tagmap) { + parser = new ITextmyHandler(document, tagmap); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + public static void Parse(IDocListener document, XmlDocument xDoc) { + XmlParser p = new XmlParser(); + p.Go(document, xDoc); + } + + /// + /// Parses a given file. + /// + /// + /// + public static void Parse(IDocListener document, String file) { + XmlParser p = new XmlParser(); + p.Go(document, file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + public static void Parse(IDocListener document, XmlTextReader reader) { + XmlParser p = new XmlParser(); + p.Go(document, reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public static void Parse(IDocListener document, XmlDocument xDoc, XmlDocument xTagmap) { + XmlParser p = new XmlParser(); + p.Go(document, xDoc, xTagmap); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public static void Parse(IDocListener document, String file, String tagmap) { + XmlParser p = new XmlParser(); + p.Go(document, file, tagmap); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public static void Parse(IDocListener document, String file, Hashtable tagmap) { + XmlParser p = new XmlParser(); + p.Go(document, file, tagmap); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public static void Parse(IDocListener document, XmlTextReader reader, String tagmap) { + XmlParser p = new XmlParser(); + p.Go(document, reader, tagmap); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public static void Parse(IDocListener document, XmlTextReader reader, Hashtable tagmap) { + XmlParser p = new XmlParser(); + p.Go(document, reader, tagmap); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/XmlPeer.cs b/iTechSharp/iTextSharp/text/xml/XmlPeer.cs new file mode 100644 index 0000000..50fdfc5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/XmlPeer.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text; + +/* + * $Id: XmlPeer.cs,v 1.5 2008/05/13 11:26:12 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml { + + /// + /// This interface is implemented by the peer of all the iText objects. + /// + public class XmlPeer { + + /// This is the name of the alias. + protected String tagname; + + /// This is the name of the alias. + protected String customTagname; + + /// This is the Map that contains the aliases of the attributes. + protected Properties attributeAliases = new Properties(); + + /// This is the Map that contains the default values of the attributes. + protected Properties attributeValues = new Properties(); + + /// This is String that contains the default content of the attributes. + protected String defaultContent = null; + + /// + /// Creates a XmlPeer. + /// + /// + /// + public XmlPeer(String name, String alias) { + this.tagname = name; + this.customTagname = alias; + } + + /// + /// Gets the tagname of the peer. + /// + /// the tagname of the peer + public String Tag { + get { + return tagname; + } + } + + /// + /// Gets the alias of the peer. + /// + /// the alias of the peer + public String Alias { + get { + return customTagname; + } + } + + /// Gets the list of attributes of the peer. + public virtual Properties GetAttributes(Hashtable attrs) { + Properties attributes = new Properties(); + attributes.AddAll(attributeValues); + if (defaultContent != null) { + attributes.Add(ElementTags.ITEXT, defaultContent); + } + if (attrs != null) { + foreach (string key in attrs.Keys) { + attributes.Add(GetName(key), (string)attrs[key]); + } + } + return attributes; + } + + /// + /// Sets an alias for an attribute. + /// + /// the iText tagname + /// the custom tagname + public virtual void AddAlias(String name, String alias) { + attributeAliases.Add(alias, name); + } + + /// + /// Sets a value for an attribute. + /// + /// the iText tagname + /// the default value for this tag + public void AddValue(String name, String value) { + attributeValues.Add(name, value); + } + + /// + /// Sets the default content. + /// + /// the default content + public string Content { + set { + this.defaultContent = value; + } + } + + /// + /// Returns the iText attribute name. + /// + /// the custom attribute name + /// the iText attribute name + public String GetName(String name) { + String value; + if ((value = attributeAliases[name]) != null) { + return value; + } + return name; + } + + /// + /// Returns the default values. + /// + /// the default values + public Properties DefaultValues { + get { + return attributeValues; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToSymbol.cs b/iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToSymbol.cs new file mode 100644 index 0000000..118e6c6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToSymbol.cs @@ -0,0 +1,381 @@ +using System; +using System.Collections; +using iTextSharp.text; +/* + * $Id: EntitiesToSymbol.cs,v 1.3 2008/05/13 11:26:14 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.simpleparser { + + /** + * This class contains entities that can be used in an entity tag. + */ + + public class EntitiesToSymbol { + + /** + * This is a map that contains all possible id values of the entity tag + * that can be translated to a character in font Symbol. + */ + public static readonly Hashtable map; + + static EntitiesToSymbol() { + map = new Hashtable(); + map["169"] = (char)227; + map["172"] = (char)216; + map["174"] = (char)210; + map["177"] = (char)177; + map["215"] = (char)180; + map["247"] = (char)184; + map["8230"] = (char)188; + map["8242"] = (char)162; + map["8243"] = (char)178; + map["8260"] = (char)164; + map["8364"] = (char)240; + map["8465"] = (char)193; + map["8472"] = (char)195; + map["8476"] = (char)194; + map["8482"] = (char)212; + map["8501"] = (char)192; + map["8592"] = (char)172; + map["8593"] = (char)173; + map["8594"] = (char)174; + map["8595"] = (char)175; + map["8596"] = (char)171; + map["8629"] = (char)191; + map["8656"] = (char)220; + map["8657"] = (char)221; + map["8658"] = (char)222; + map["8659"] = (char)223; + map["8660"] = (char)219; + map["8704"] = (char)34; + map["8706"] = (char)182; + map["8707"] = (char)36; + map["8709"] = (char)198; + map["8711"] = (char)209; + map["8712"] = (char)206; + map["8713"] = (char)207; + map["8717"] = (char)39; + map["8719"] = (char)213; + map["8721"] = (char)229; + map["8722"] = (char)45; + map["8727"] = (char)42; + map["8729"] = (char)183; + map["8730"] = (char)214; + map["8733"] = (char)181; + map["8734"] = (char)165; + map["8736"] = (char)208; + map["8743"] = (char)217; + map["8744"] = (char)218; + map["8745"] = (char)199; + map["8746"] = (char)200; + map["8747"] = (char)242; + map["8756"] = (char)92; + map["8764"] = (char)126; + map["8773"] = (char)64; + map["8776"] = (char)187; + map["8800"] = (char)185; + map["8801"] = (char)186; + map["8804"] = (char)163; + map["8805"] = (char)179; + map["8834"] = (char)204; + map["8835"] = (char)201; + map["8836"] = (char)203; + map["8838"] = (char)205; + map["8839"] = (char)202; + map["8853"] = (char)197; + map["8855"] = (char)196; + map["8869"] = (char)94; + map["8901"] = (char)215; + map["8992"] = (char)243; + map["8993"] = (char)245; + map["9001"] = (char)225; + map["9002"] = (char)241; + map["913"] = (char)65; + map["914"] = (char)66; + map["915"] = (char)71; + map["916"] = (char)68; + map["917"] = (char)69; + map["918"] = (char)90; + map["919"] = (char)72; + map["920"] = (char)81; + map["921"] = (char)73; + map["922"] = (char)75; + map["923"] = (char)76; + map["924"] = (char)77; + map["925"] = (char)78; + map["926"] = (char)88; + map["927"] = (char)79; + map["928"] = (char)80; + map["929"] = (char)82; + map["931"] = (char)83; + map["932"] = (char)84; + map["933"] = (char)85; + map["934"] = (char)70; + map["935"] = (char)67; + map["936"] = (char)89; + map["937"] = (char)87; + map["945"] = (char)97; + map["946"] = (char)98; + map["947"] = (char)103; + map["948"] = (char)100; + map["949"] = (char)101; + map["950"] = (char)122; + map["951"] = (char)104; + map["952"] = (char)113; + map["953"] = (char)105; + map["954"] = (char)107; + map["955"] = (char)108; + map["956"] = (char)109; + map["957"] = (char)110; + map["958"] = (char)120; + map["959"] = (char)111; + map["960"] = (char)112; + map["961"] = (char)114; + map["962"] = (char)86; + map["963"] = (char)115; + map["964"] = (char)116; + map["965"] = (char)117; + map["966"] = (char)102; + map["967"] = (char)99; + map["9674"] = (char)224; + map["968"] = (char)121; + map["969"] = (char)119; + map["977"] = (char)74; + map["978"] = (char)161; + map["981"] = (char)106; + map["982"] = (char)118; + map["9824"] = (char)170; + map["9827"] = (char)167; + map["9829"] = (char)169; + map["9830"] = (char)168; + map["Alpha"] = (char)65; + map["Beta"] = (char)66; + map["Chi"] = (char)67; + map["Delta"] = (char)68; + map["Epsilon"] = (char)69; + map["Eta"] = (char)72; + map["Gamma"] = (char)71; + map["Iota"] = (char)73; + map["Kappa"] = (char)75; + map["Lambda"] = (char)76; + map["Mu"] = (char)77; + map["Nu"] = (char)78; + map["Omega"] = (char)87; + map["Omicron"] = (char)79; + map["Phi"] = (char)70; + map["Pi"] = (char)80; + map["Prime"] = (char)178; + map["Psi"] = (char)89; + map["Rho"] = (char)82; + map["Sigma"] = (char)83; + map["Tau"] = (char)84; + map["Theta"] = (char)81; + map["Upsilon"] = (char)85; + map["Xi"] = (char)88; + map["Zeta"] = (char)90; + map["alefsym"] = (char)192; + map["alpha"] = (char)97; + map["and"] = (char)217; + map["ang"] = (char)208; + map["asymp"] = (char)187; + map["beta"] = (char)98; + map["cap"] = (char)199; + map["chi"] = (char)99; + map["clubs"] = (char)167; + map["cong"] = (char)64; + map["copy"] = (char)211; + map["crarr"] = (char)191; + map["cup"] = (char)200; + map["dArr"] = (char)223; + map["darr"] = (char)175; + map["delta"] = (char)100; + map["diams"] = (char)168; + map["divide"] = (char)184; + map["empty"] = (char)198; + map["epsilon"] = (char)101; + map["equiv"] = (char)186; + map["eta"] = (char)104; + map["euro"] = (char)240; + map["exist"] = (char)36; + map["forall"] = (char)34; + map["frasl"] = (char)164; + map["gamma"] = (char)103; + map["ge"] = (char)179; + map["hArr"] = (char)219; + map["harr"] = (char)171; + map["hearts"] = (char)169; + map["hellip"] = (char)188; + map["horizontal arrow extender"] = (char)190; + map["image"] = (char)193; + map["infin"] = (char)165; + map["int"] = (char)242; + map["iota"] = (char)105; + map["isin"] = (char)206; + map["kappa"] = (char)107; + map["lArr"] = (char)220; + map["lambda"] = (char)108; + map["lang"] = (char)225; + map["large brace extender"] = (char)239; + map["large integral extender"] = (char)244; + map["large left brace (bottom)"] = (char)238; + map["large left brace (middle)"] = (char)237; + map["large left brace (top)"] = (char)236; + map["large left bracket (bottom)"] = (char)235; + map["large left bracket (extender)"] = (char)234; + map["large left bracket (top)"] = (char)233; + map["large left parenthesis (bottom)"] = (char)232; + map["large left parenthesis (extender)"] = (char)231; + map["large left parenthesis (top)"] = (char)230; + map["large right brace (bottom)"] = (char)254; + map["large right brace (middle)"] = (char)253; + map["large right brace (top)"] = (char)252; + map["large right bracket (bottom)"] = (char)251; + map["large right bracket (extender)"] = (char)250; + map["large right bracket (top)"] = (char)249; + map["large right parenthesis (bottom)"] = (char)248; + map["large right parenthesis (extender)"] = (char)247; + map["large right parenthesis (top)"] = (char)246; + map["larr"] = (char)172; + map["le"] = (char)163; + map["lowast"] = (char)42; + map["loz"] = (char)224; + map["minus"] = (char)45; + map["mu"] = (char)109; + map["nabla"] = (char)209; + map["ne"] = (char)185; + map["not"] = (char)216; + map["notin"] = (char)207; + map["nsub"] = (char)203; + map["nu"] = (char)110; + map["omega"] = (char)119; + map["omicron"] = (char)111; + map["oplus"] = (char)197; + map["or"] = (char)218; + map["otimes"] = (char)196; + map["part"] = (char)182; + map["perp"] = (char)94; + map["phi"] = (char)102; + map["pi"] = (char)112; + map["piv"] = (char)118; + map["plusmn"] = (char)177; + map["prime"] = (char)162; + map["prod"] = (char)213; + map["prop"] = (char)181; + map["psi"] = (char)121; + map["rArr"] = (char)222; + map["radic"] = (char)214; + map["radical extender"] = (char)96; + map["rang"] = (char)241; + map["rarr"] = (char)174; + map["real"] = (char)194; + map["reg"] = (char)210; + map["rho"] = (char)114; + map["sdot"] = (char)215; + map["sigma"] = (char)115; + map["sigmaf"] = (char)86; + map["sim"] = (char)126; + map["spades"] = (char)170; + map["sub"] = (char)204; + map["sube"] = (char)205; + map["sum"] = (char)229; + map["sup"] = (char)201; + map["supe"] = (char)202; + map["tau"] = (char)116; + map["there4"] = (char)92; + map["theta"] = (char)113; + map["thetasym"] = (char)74; + map["times"] = (char)180; + map["trade"] = (char)212; + map["uArr"] = (char)221; + map["uarr"] = (char)173; + map["upsih"] = (char)161; + map["upsilon"] = (char)117; + map["vertical arrow extender"] = (char)189; + map["weierp"] = (char)195; + map["xi"] = (char)120; + map["zeta"] = (char)122; + } + + /** + * Gets a chunk with a symbol character. + * @param e a symbol value (see Entities class: alfa is greek alfa,...) + * @param font the font if the symbol isn't found (otherwise Font.SYMBOL) + * @return a Chunk + */ + + public static Chunk Get(String e, Font font) { + char s = GetCorrespondingSymbol(e); + if (s == '\0') { + try { + return new Chunk("" + (char)int.Parse(e), font); + } + catch (Exception) { + return new Chunk(e, font); + } + } + Font symbol = new Font(Font.SYMBOL, font.Size, font.Style, font.Color); + return new Chunk(s.ToString(), symbol); + } + + /** + * Looks for the corresponding symbol in the font Symbol. + * + * @param name the name of the entity + * @return the corresponding character in font Symbol + */ + + public static char GetCorrespondingSymbol(String name) { + if (map.ContainsKey(name)) + return (char)map[name]; + else + return '\0'; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToUnicode.cs b/iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToUnicode.cs new file mode 100644 index 0000000..1c0394e --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToUnicode.cs @@ -0,0 +1,442 @@ +using System; +using System.Collections; +using System.Text; +using System.Globalization; +/* + * $Id: EntitiesToUnicode.cs,v 1.3 2008/05/13 11:26:14 psoares33 Exp $ + * + * + * Copyright 2003-2007 Paulo Soares and Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.simpleparser { + + /** + * This class contains entities that can be used in an entity tag. + */ + + public class EntitiesToUnicode { + + /** + * This is a map that contains the names of entities and their unicode value. + */ + public static readonly Hashtable map = new Hashtable(); + + static EntitiesToUnicode() { + map["nbsp"] = '\u00a0'; // no-break space = non-breaking space, U+00A0 ISOnum + map["iexcl"] = '\u00a1'; // inverted exclamation mark, U+00A1 ISOnum + map["cent"] = '\u00a2'; // cent sign, U+00A2 ISOnum + map["pound"] = '\u00a3'; // pound sign, U+00A3 ISOnum + map["curren"] = '\u00a4'; // currency sign, U+00A4 ISOnum + map["yen"] = '\u00a5'; // yen sign = yuan sign, U+00A5 ISOnum + map["brvbar"] = '\u00a6'; // broken bar = broken vertical bar, U+00A6 ISOnum + map["sect"] = '\u00a7'; // section sign, U+00A7 ISOnum + map["uml"] = '\u00a8'; // diaeresis = spacing diaeresis, U+00A8 ISOdia + map["copy"] = '\u00a9'; // copyright sign, U+00A9 ISOnum + map["ordf"] = '\u00aa'; // feminine ordinal indicator, U+00AA ISOnum + map["laquo"] = '\u00ab'; // left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum + map["not"] = '\u00ac'; // not sign, U+00AC ISOnum + map["shy"] = '\u00ad'; // soft hyphen = discretionary hyphen, U+00AD ISOnum + map["reg"] = '\u00ae'; // registered sign = registered trade mark sign, U+00AE ISOnum + map["macr"] = '\u00af'; // macron = spacing macron = overline = APL overbar, U+00AF ISOdia + map["deg"] = '\u00b0'; // degree sign, U+00B0 ISOnum + map["plusmn"] = '\u00b1'; // plus-minus sign = plus-or-minus sign, U+00B1 ISOnum + map["sup2"] = '\u00b2'; // superscript two = superscript digit two = squared, U+00B2 ISOnum + map["sup3"] = '\u00b3'; // superscript three = superscript digit three = cubed, U+00B3 ISOnum + map["acute"] = '\u00b4'; // acute accent = spacing acute, U+00B4 ISOdia + map["micro"] = '\u00b5'; // micro sign, U+00B5 ISOnum + map["para"] = '\u00b6'; // pilcrow sign = paragraph sign, U+00B6 ISOnum + map["middot"] = '\u00b7'; // middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum + map["cedil"] = '\u00b8'; // cedilla = spacing cedilla, U+00B8 ISOdia + map["sup1"] = '\u00b9'; // superscript one = superscript digit one, U+00B9 ISOnum + map["ordm"] = '\u00ba'; // masculine ordinal indicator, U+00BA ISOnum + map["raquo"] = '\u00bb'; // right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum + map["frac14"] = '\u00bc'; // vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum + map["frac12"] = '\u00bd'; // vulgar fraction one half = fraction one half, U+00BD ISOnum + map["frac34"] = '\u00be'; // vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum + map["iquest"] = '\u00bf'; // inverted question mark = turned question mark, U+00BF ISOnum + map["Agrave"] = '\u00c0'; // latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1 + map["Aacute"] = '\u00c1'; // latin capital letter A with acute, U+00C1 ISOlat1 + map["Acirc"] = '\u00c2'; // latin capital letter A with circumflex, U+00C2 ISOlat1 + map["Atilde"] = '\u00c3'; // latin capital letter A with tilde, U+00C3 ISOlat1 + map["Auml"] = '\u00c4'; // latin capital letter A with diaeresis, U+00C4 ISOlat1 + map["Aring"] = '\u00c5'; // latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1 + map["AElig"] = '\u00c6'; // latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 + map["Ccedil"] = '\u00c7'; // latin capital letter C with cedilla, U+00C7 ISOlat1 + map["Egrave"] = '\u00c8'; // latin capital letter E with grave, U+00C8 ISOlat1 + map["Eacute"] = '\u00c9'; // latin capital letter E with acute, U+00C9 ISOlat1 + map["Ecirc"] = '\u00ca'; // latin capital letter E with circumflex, U+00CA ISOlat1 + map["Euml"] = '\u00cb'; // latin capital letter E with diaeresis, U+00CB ISOlat1 + map["Igrave"] = '\u00cc'; // latin capital letter I with grave, U+00CC ISOlat1 + map["Iacute"] = '\u00cd'; // latin capital letter I with acute, U+00CD ISOlat1 + map["Icirc"] = '\u00ce'; // latin capital letter I with circumflex, U+00CE ISOlat1 + map["Iuml"] = '\u00cf'; // latin capital letter I with diaeresis, U+00CF ISOlat1 + map["ETH"] = '\u00d0'; // latin capital letter ETH, U+00D0 ISOlat1 + map["Ntilde"] = '\u00d1'; // latin capital letter N with tilde, U+00D1 ISOlat1 + map["Ograve"] = '\u00d2'; // latin capital letter O with grave, U+00D2 ISOlat1 + map["Oacute"] = '\u00d3'; // latin capital letter O with acute, U+00D3 ISOlat1 + map["Ocirc"] = '\u00d4'; // latin capital letter O with circumflex, U+00D4 ISOlat1 + map["Otilde"] = '\u00d5'; // latin capital letter O with tilde, U+00D5 ISOlat1 + map["Ouml"] = '\u00d6'; // latin capital letter O with diaeresis, U+00D6 ISOlat1 + map["times"] = '\u00d7'; // multiplication sign, U+00D7 ISOnum + map["Oslash"] = '\u00d8'; // latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1 + map["Ugrave"] = '\u00d9'; // latin capital letter U with grave, U+00D9 ISOlat1 + map["Uacute"] = '\u00da'; // latin capital letter U with acute, U+00DA ISOlat1 + map["Ucirc"] = '\u00db'; // latin capital letter U with circumflex, U+00DB ISOlat1 + map["Uuml"] = '\u00dc'; // latin capital letter U with diaeresis, U+00DC ISOlat1 + map["Yacute"] = '\u00dd'; // latin capital letter Y with acute, U+00DD ISOlat1 + map["THORN"] = '\u00de'; // latin capital letter THORN, U+00DE ISOlat1 + map["szlig"] = '\u00df'; // latin small letter sharp s = ess-zed, U+00DF ISOlat1 + map["agrave"] = '\u00e0'; // latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1 + map["aacute"] = '\u00e1'; // latin small letter a with acute, U+00E1 ISOlat1 + map["acirc"] = '\u00e2'; // latin small letter a with circumflex, U+00E2 ISOlat1 + map["atilde"] = '\u00e3'; // latin small letter a with tilde, U+00E3 ISOlat1 + map["auml"] = '\u00e4'; // latin small letter a with diaeresis, U+00E4 ISOlat1 + map["aring"] = '\u00e5'; // latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1 + map["aelig"] = '\u00e6'; // latin small letter ae = latin small ligature ae, U+00E6 ISOlat1 + map["ccedil"] = '\u00e7'; // latin small letter c with cedilla, U+00E7 ISOlat1 + map["egrave"] = '\u00e8'; // latin small letter e with grave, U+00E8 ISOlat1 + map["eacute"] = '\u00e9'; // latin small letter e with acute, U+00E9 ISOlat1 + map["ecirc"] = '\u00ea'; // latin small letter e with circumflex, U+00EA ISOlat1 + map["euml"] = '\u00eb'; // latin small letter e with diaeresis, U+00EB ISOlat1 + map["igrave"] = '\u00ec'; // latin small letter i with grave, U+00EC ISOlat1 + map["iacute"] = '\u00ed'; // latin small letter i with acute, U+00ED ISOlat1 + map["icirc"] = '\u00ee'; // latin small letter i with circumflex, U+00EE ISOlat1 + map["iuml"] = '\u00ef'; // latin small letter i with diaeresis, U+00EF ISOlat1 + map["eth"] = '\u00f0'; // latin small letter eth, U+00F0 ISOlat1 + map["ntilde"] = '\u00f1'; // latin small letter n with tilde, U+00F1 ISOlat1 + map["ograve"] = '\u00f2'; // latin small letter o with grave, U+00F2 ISOlat1 + map["oacute"] = '\u00f3'; // latin small letter o with acute, U+00F3 ISOlat1 + map["ocirc"] = '\u00f4'; // latin small letter o with circumflex, U+00F4 ISOlat1 + map["otilde"] = '\u00f5'; // latin small letter o with tilde, U+00F5 ISOlat1 + map["ouml"] = '\u00f6'; // latin small letter o with diaeresis, U+00F6 ISOlat1 + map["divide"] = '\u00f7'; // division sign, U+00F7 ISOnum + map["oslash"] = '\u00f8'; // latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1 + map["ugrave"] = '\u00f9'; // latin small letter u with grave, U+00F9 ISOlat1 + map["uacute"] = '\u00fa'; // latin small letter u with acute, U+00FA ISOlat1 + map["ucirc"] = '\u00fb'; // latin small letter u with circumflex, U+00FB ISOlat1 + map["uuml"] = '\u00fc'; // latin small letter u with diaeresis, U+00FC ISOlat1 + map["yacute"] = '\u00fd'; // latin small letter y with acute, U+00FD ISOlat1 + map["thorn"] = '\u00fe'; // latin small letter thorn, U+00FE ISOlat1 + map["yuml"] = '\u00ff'; // latin small letter y with diaeresis, U+00FF ISOlat1 + // Latin Extended-B + map["fnof"] = '\u0192'; // latin small f with hook = function = florin, U+0192 ISOtech + // Greek + map["Alpha"] = '\u0391'; // greek capital letter alpha, U+0391 + map["Beta"] = '\u0392'; // greek capital letter beta, U+0392 + map["Gamma"] = '\u0393'; // greek capital letter gamma, U+0393 ISOgrk3 + map["Delta"] = '\u0394'; // greek capital letter delta, U+0394 ISOgrk3 + map["Epsilon"] = '\u0395'; // greek capital letter epsilon, U+0395 + map["Zeta"] = '\u0396'; // greek capital letter zeta, U+0396 + map["Eta"] = '\u0397'; // greek capital letter eta, U+0397 + map["Theta"] = '\u0398'; // greek capital letter theta, U+0398 ISOgrk3 + map["Iota"] = '\u0399'; // greek capital letter iota, U+0399 + map["Kappa"] = '\u039a'; // greek capital letter kappa, U+039A + map["Lambda"] = '\u039b'; // greek capital letter lambda, U+039B ISOgrk3 + map["Mu"] = '\u039c'; // greek capital letter mu, U+039C + map["Nu"] = '\u039d'; // greek capital letter nu, U+039D + map["Xi"] = '\u039e'; // greek capital letter xi, U+039E ISOgrk3 + map["Omicron"] = '\u039f'; // greek capital letter omicron, U+039F + map["Pi"] = '\u03a0'; // greek capital letter pi, U+03A0 ISOgrk3 + map["Rho"] = '\u03a1'; // greek capital letter rho, U+03A1 + // there is no Sigmaf, and no U+03A2 character either + map["Sigma"] = '\u03a3'; // greek capital letter sigma, U+03A3 ISOgrk3 + map["Tau"] = '\u03a4'; // greek capital letter tau, U+03A4 + map["Upsilon"] = '\u03a5'; // greek capital letter upsilon, U+03A5 ISOgrk3 + map["Phi"] = '\u03a6'; // greek capital letter phi, U+03A6 ISOgrk3 + map["Chi"] = '\u03a7'; // greek capital letter chi, U+03A7 + map["Psi"] = '\u03a8'; // greek capital letter psi, U+03A8 ISOgrk3 + map["Omega"] = '\u03a9'; // greek capital letter omega, U+03A9 ISOgrk3 + map["alpha"] = '\u03b1'; // greek small letter alpha, U+03B1 ISOgrk3 + map["beta"] = '\u03b2'; // greek small letter beta, U+03B2 ISOgrk3 + map["gamma"] = '\u03b3'; // greek small letter gamma, U+03B3 ISOgrk3 + map["delta"] = '\u03b4'; // greek small letter delta, U+03B4 ISOgrk3 + map["epsilon"] = '\u03b5'; // greek small letter epsilon, U+03B5 ISOgrk3 + map["zeta"] = '\u03b6'; // greek small letter zeta, U+03B6 ISOgrk3 + map["eta"] = '\u03b7'; // greek small letter eta, U+03B7 ISOgrk3 + map["theta"] = '\u03b8'; // greek small letter theta, U+03B8 ISOgrk3 + map["iota"] = '\u03b9'; // greek small letter iota, U+03B9 ISOgrk3 + map["kappa"] = '\u03ba'; // greek small letter kappa, U+03BA ISOgrk3 + map["lambda"] = '\u03bb'; // greek small letter lambda, U+03BB ISOgrk3 + map["mu"] = '\u03bc'; // greek small letter mu, U+03BC ISOgrk3 + map["nu"] = '\u03bd'; // greek small letter nu, U+03BD ISOgrk3 + map["xi"] = '\u03be'; // greek small letter xi, U+03BE ISOgrk3 + map["omicron"] = '\u03bf'; // greek small letter omicron, U+03BF NEW + map["pi"] = '\u03c0'; // greek small letter pi, U+03C0 ISOgrk3 + map["rho"] = '\u03c1'; // greek small letter rho, U+03C1 ISOgrk3 + map["sigmaf"] = '\u03c2'; // greek small letter final sigma, U+03C2 ISOgrk3 + map["sigma"] = '\u03c3'; // greek small letter sigma, U+03C3 ISOgrk3 + map["tau"] = '\u03c4'; // greek small letter tau, U+03C4 ISOgrk3 + map["upsilon"] = '\u03c5'; // greek small letter upsilon, U+03C5 ISOgrk3 + map["phi"] = '\u03c6'; // greek small letter phi, U+03C6 ISOgrk3 + map["chi"] = '\u03c7'; // greek small letter chi, U+03C7 ISOgrk3 + map["psi"] = '\u03c8'; // greek small letter psi, U+03C8 ISOgrk3 + map["omega"] = '\u03c9'; // greek small letter omega, U+03C9 ISOgrk3 + map["thetasym"] = '\u03d1'; // greek small letter theta symbol, U+03D1 NEW + map["upsih"] = '\u03d2'; // greek upsilon with hook symbol, U+03D2 NEW + map["piv"] = '\u03d6'; // greek pi symbol, U+03D6 ISOgrk3 + // General Punctuation + map["bull"] = '\u2022'; // bullet = black small circle, U+2022 ISOpub + // bullet is NOT the same as bullet operator, U+2219 + map["hellip"] = '\u2026'; // horizontal ellipsis = three dot leader, U+2026 ISOpub + map["prime"] = '\u2032'; // prime = minutes = feet, U+2032 ISOtech + map["Prime"] = '\u2033'; // double prime = seconds = inches, U+2033 ISOtech + map["oline"] = '\u203e'; // overline = spacing overscore, U+203E NEW + map["frasl"] = '\u2044'; // fraction slash, U+2044 NEW + // Letterlike Symbols + map["weierp"] = '\u2118'; // script capital P = power set = Weierstrass p, U+2118 ISOamso + map["image"] = '\u2111'; // blackletter capital I = imaginary part, U+2111 ISOamso + map["real"] = '\u211c'; // blackletter capital R = real part symbol, U+211C ISOamso + map["trade"] = '\u2122'; // trade mark sign, U+2122 ISOnum + map["alefsym"] = '\u2135'; // alef symbol = first transfinite cardinal, U+2135 NEW + // alef symbol is NOT the same as hebrew letter alef, + // U+05D0 although the same glyph could be used to depict both characters + // Arrows + map["larr"] = '\u2190'; // leftwards arrow, U+2190 ISOnum + map["uarr"] = '\u2191'; // upwards arrow, U+2191 ISOnum + map["rarr"] = '\u2192'; // rightwards arrow, U+2192 ISOnum + map["darr"] = '\u2193'; // downwards arrow, U+2193 ISOnum + map["harr"] = '\u2194'; // left right arrow, U+2194 ISOamsa + map["crarr"] = '\u21b5'; // downwards arrow with corner leftwards = carriage return, U+21B5 NEW + map["lArr"] = '\u21d0'; // leftwards double arrow, U+21D0 ISOtech + // ISO 10646 does not say that lArr is the same as the 'is implied by' arrow + // but also does not have any other character for that function. So ? lArr can + // be used for 'is implied by' as ISOtech suggests + map["uArr"] = '\u21d1'; // upwards double arrow, U+21D1 ISOamsa + map["rArr"] = '\u21d2'; // rightwards double arrow, U+21D2 ISOtech + // ISO 10646 does not say this is the 'implies' character but does not have + // another character with this function so ? + // rArr can be used for 'implies' as ISOtech suggests + map["dArr"] = '\u21d3'; // downwards double arrow, U+21D3 ISOamsa + map["hArr"] = '\u21d4'; // left right double arrow, U+21D4 ISOamsa + // Mathematical Operators + map["forall"] = '\u2200'; // for all, U+2200 ISOtech + map["part"] = '\u2202'; // partial differential, U+2202 ISOtech + map["exist"] = '\u2203'; // there exists, U+2203 ISOtech + map["empty"] = '\u2205'; // empty set = null set = diameter, U+2205 ISOamso + map["nabla"] = '\u2207'; // nabla = backward difference, U+2207 ISOtech + map["isin"] = '\u2208'; // element of, U+2208 ISOtech + map["notin"] = '\u2209'; // not an element of, U+2209 ISOtech + map["ni"] = '\u220b'; // contains as member, U+220B ISOtech + // should there be a more memorable name than 'ni'? + map["prod"] = '\u220f'; // n-ary product = product sign, U+220F ISOamsb + // prod is NOT the same character as U+03A0 'greek capital letter pi' though + // the same glyph might be used for both + map["sum"] = '\u2211'; // n-ary sumation, U+2211 ISOamsb + // sum is NOT the same character as U+03A3 'greek capital letter sigma' + // though the same glyph might be used for both + map["minus"] = '\u2212'; // minus sign, U+2212 ISOtech + map["lowast"] = '\u2217'; // asterisk operator, U+2217 ISOtech + map["radic"] = '\u221a'; // square root = radical sign, U+221A ISOtech + map["prop"] = '\u221d'; // proportional to, U+221D ISOtech + map["infin"] = '\u221e'; // infinity, U+221E ISOtech + map["ang"] = '\u2220'; // angle, U+2220 ISOamso + map["and"] = '\u2227'; // logical and = wedge, U+2227 ISOtech + map["or"] = '\u2228'; // logical or = vee, U+2228 ISOtech + map["cap"] = '\u2229'; // intersection = cap, U+2229 ISOtech + map["cup"] = '\u222a'; // union = cup, U+222A ISOtech + map["int"] = '\u222b'; // integral, U+222B ISOtech + map["there4"] = '\u2234'; // therefore, U+2234 ISOtech + map["sim"] = '\u223c'; // tilde operator = varies with = similar to, U+223C ISOtech + // tilde operator is NOT the same character as the tilde, U+007E, + // although the same glyph might be used to represent both + map["cong"] = '\u2245'; // approximately equal to, U+2245 ISOtech + map["asymp"] = '\u2248'; // almost equal to = asymptotic to, U+2248 ISOamsr + map["ne"] = '\u2260'; // not equal to, U+2260 ISOtech + map["equiv"] = '\u2261'; // identical to, U+2261 ISOtech + map["le"] = '\u2264'; // less-than or equal to, U+2264 ISOtech + map["ge"] = '\u2265'; // greater-than or equal to, U+2265 ISOtech + map["sub"] = '\u2282'; // subset of, U+2282 ISOtech + map["sup"] = '\u2283'; // superset of, U+2283 ISOtech + // note that nsup, 'not a superset of, U+2283' is not covered by the Symbol + // font encoding and is not included. Should it be, for symmetry? + // It is in ISOamsn + map["nsub"] = '\u2284'; // not a subset of, U+2284 ISOamsn + map["sube"] = '\u2286'; // subset of or equal to, U+2286 ISOtech + map["supe"] = '\u2287'; // superset of or equal to, U+2287 ISOtech + map["oplus"] = '\u2295'; // circled plus = direct sum, U+2295 ISOamsb + map["otimes"] = '\u2297'; // circled times = vector product, U+2297 ISOamsb + map["perp"] = '\u22a5'; // up tack = orthogonal to = perpendicular, U+22A5 ISOtech + map["sdot"] = '\u22c5'; // dot operator, U+22C5 ISOamsb + // dot operator is NOT the same character as U+00B7 middle dot + // Miscellaneous Technical + map["lceil"] = '\u2308'; // left ceiling = apl upstile, U+2308 ISOamsc + map["rceil"] = '\u2309'; // right ceiling, U+2309 ISOamsc + map["lfloor"] = '\u230a'; // left floor = apl downstile, U+230A ISOamsc + map["rfloor"] = '\u230b'; // right floor, U+230B ISOamsc + map["lang"] = '\u2329'; // left-pointing angle bracket = bra, U+2329 ISOtech + // lang is NOT the same character as U+003C 'less than' + // or U+2039 'single left-pointing angle quotation mark' + map["rang"] = '\u232a'; // right-pointing angle bracket = ket, U+232A ISOtech + // rang is NOT the same character as U+003E 'greater than' + // or U+203A 'single right-pointing angle quotation mark' + // Geometric Shapes + map["loz"] = '\u25ca'; // lozenge, U+25CA ISOpub + // Miscellaneous Symbols + map["spades"] = '\u2660'; // black spade suit, U+2660 ISOpub + // black here seems to mean filled as opposed to hollow + map["clubs"] = '\u2663'; // black club suit = shamrock, U+2663 ISOpub + map["hearts"] = '\u2665'; // black heart suit = valentine, U+2665 ISOpub + map["diams"] = '\u2666'; // black diamond suit, U+2666 ISOpub + // C0 Controls and Basic Latin + map["quot"] = '\u0022'; // quotation mark = APL quote, U+0022 ISOnum + map["amp"] = '\u0026'; // ampersand, U+0026 ISOnum + map["apos"] = '\''; + map["lt"] = '\u003c'; // less-than sign, U+003C ISOnum + map["gt"] = '\u003e'; // greater-than sign, U+003E ISOnum + // Latin Extended-A + map["OElig"] = '\u0152'; // latin capital ligature OE, U+0152 ISOlat2 + map["oelig"] = '\u0153'; // latin small ligature oe, U+0153 ISOlat2 + // ligature is a misnomer, this is a separate character in some languages + map["Scaron"] = '\u0160'; // latin capital letter S with caron, U+0160 ISOlat2 + map["scaron"] = '\u0161'; // latin small letter s with caron, U+0161 ISOlat2 + map["Yuml"] = '\u0178'; // latin capital letter Y with diaeresis, U+0178 ISOlat2 + // Spacing Modifier Letters + map["circ"] = '\u02c6'; // modifier letter circumflex accent, U+02C6 ISOpub + map["tilde"] = '\u02dc'; // small tilde, U+02DC ISOdia + // General Punctuation + map["ensp"] = '\u2002'; // en space, U+2002 ISOpub + map["emsp"] = '\u2003'; // em space, U+2003 ISOpub + map["thinsp"] = '\u2009'; // thin space, U+2009 ISOpub + map["zwnj"] = '\u200c'; // zero width non-joiner, U+200C NEW RFC 2070 + map["zwj"] = '\u200d'; // zero width joiner, U+200D NEW RFC 2070 + map["lrm"] = '\u200e'; // left-to-right mark, U+200E NEW RFC 2070 + map["rlm"] = '\u200f'; // right-to-left mark, U+200F NEW RFC 2070 + map["ndash"] = '\u2013'; // en dash, U+2013 ISOpub + map["mdash"] = '\u2014'; // em dash, U+2014 ISOpub + map["lsquo"] = '\u2018'; // left single quotation mark, U+2018 ISOnum + map["rsquo"] = '\u2019'; // right single quotation mark, U+2019 ISOnum + map["sbquo"] = '\u201a'; // single low-9 quotation mark, U+201A NEW + map["ldquo"] = '\u201c'; // left double quotation mark, U+201C ISOnum + map["rdquo"] = '\u201d'; // right double quotation mark, U+201D ISOnum + map["bdquo"] = '\u201e'; // double low-9 quotation mark, U+201E NEW + map["dagger"] = '\u2020'; // dagger, U+2020 ISOpub + map["Dagger"] = '\u2021'; // double dagger, U+2021 ISOpub + map["permil"] = '\u2030'; // per mille sign, U+2030 ISOtech + map["lsaquo"] = '\u2039'; // single left-pointing angle quotation mark, U+2039 ISO proposed + // lsaquo is proposed but not yet ISO standardized + map["rsaquo"] = '\u203a'; // single right-pointing angle quotation mark, U+203A ISO proposed + // rsaquo is proposed but not yet ISO standardized + map["euro"] = '\u20ac'; // euro sign, U+20AC NEW + } + + + /** + * Translates an entity to a unicode character. + * + * @param name the name of the entity + * @return the corresponding unicode character + */ + public static char DecodeEntity(String name) { + if (name.StartsWith("#x")) { + try { + return (char)int.Parse(name.Substring(2), NumberStyles.AllowHexSpecifier); + } + catch { + return '\0'; + } + } + if (name.StartsWith("#")) { + try { + return (char)int.Parse(name.Substring(1)); + } + catch { + return '\0'; + } + } + object c = map[name]; + if (c == null) + return '\0'; + else + return (char)c; + } + + /** + * Translates a String with entities (&...;) to a String without entities, + * replacing the entity with the right (unicode) character. + */ + public static String DecodeString(String s) { + int pos_amp = s.IndexOf('&'); + if (pos_amp == -1) return s; + + int pos_sc; + int pos_a; + StringBuilder buf = new StringBuilder(s.Substring(0, pos_amp)); + char replace; + while (true) { + pos_sc = s.IndexOf(';', pos_amp); + if (pos_sc == -1) { + buf.Append(s.Substring(pos_amp)); + return buf.ToString(); + } + pos_a = s.IndexOf('&', pos_amp + 1); + while (pos_a != -1 && pos_a < pos_sc) { + buf.Append(s.Substring(pos_amp, pos_a - pos_amp)); + pos_amp = pos_a; + pos_a = s.IndexOf('&', pos_amp + 1); + } + replace = DecodeEntity(s.Substring(pos_amp + 1, pos_sc - (pos_amp + 1))); + if (s.Length < pos_sc + 1) { + return buf.ToString(); + } + if (replace == '\0') { + buf.Append(s.Substring(pos_amp, pos_sc + 1 - pos_amp)); + } + else { + buf.Append(replace); + } + pos_amp = s.IndexOf('&', pos_sc); + if (pos_amp == -1) { + buf.Append(s.Substring(pos_sc + 1)); + return buf.ToString(); + } + else { + buf.Append(s.Substring(pos_sc + 1, pos_amp - (pos_sc + 1))); + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandler.cs b/iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandler.cs new file mode 100644 index 0000000..68216b2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandler.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.simpleparser { + /** + * The handler for the events fired by SimpleXMLParser. + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface ISimpleXMLDocHandler { + /** + * Called when a start tag is found. + * @param tag the tag name + * @param h the tag's attributes + */ + void StartElement(String tag, Hashtable h); + /** + * Called when an end tag is found. + * @param tag the tag name + */ + void EndElement(String tag); + /** + * Called when the document starts to be parsed. + */ + void StartDocument(); + /** + * Called after the document is parsed. + */ + void EndDocument(); + /** + * Called when a text element is found. + * @param str the text element, probably a fragment. + */ + void Text(String str); + } +} diff --git a/iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandlerComment.cs b/iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandlerComment.cs new file mode 100644 index 0000000..e4042e7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandlerComment.cs @@ -0,0 +1,61 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.simpleparser { + /** + * The handler for the events fired by SimpleXMLParser. + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface ISimpleXMLDocHandlerComment { + /** + * Called when a comment is found. + * @param text the comment text + */ + void Comment(String text); + } +} diff --git a/iTechSharp/iTextSharp/text/xml/simpleparser/IanaEncodings.cs b/iTechSharp/iTextSharp/text/xml/simpleparser/IanaEncodings.cs new file mode 100644 index 0000000..c4fda86 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/simpleparser/IanaEncodings.cs @@ -0,0 +1,551 @@ +using System; +using System.Collections; +using System.Text; +/* + * $Id: IanaEncodings.cs,v 1.4 2008/05/13 11:26:14 psoares33 Exp $ + * + * + * Copyright 2003-2007 Paulo Soares and Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * The values used in this class are based on class org.apache.xercis.util.EncodingMap + * http://svn.apache.org/viewvc/xerces/java/trunk/src/org/apache/xerces/util/EncodingMap.java?view=markup + * This class was originally published under the following license: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace iTextSharp.text.xml.simpleparser { + + /** + * Translates a IANA encoding name to a Java encoding. + */ + + public class IanaEncodings { + + /** The object that maps IANA to Java encodings. */ + private static readonly Hashtable map = new Hashtable(); + + static IanaEncodings() { + // add IANA to .NET encoding mappings. + map["CP037"] = 37; + map["CSIBM037"] = 37; + map["EBCDIC-CP-CA"] = 37; + map["EBCDIC-CP-NL"] = 37; + map["EBCDIC-CP-US"] = 37; + map["EBCDIC-CP-WT"] = 37; + map["IBM037"] = 37; + map["CP437"] = 437; + map["CSPC8CODEPAGE437"] = 437; + map["IBM437"] = 437; + map["CP500"] = 500; + map["CSIBM500"] = 500; + map["EBCDIC-CP-BE"] = 500; + map["EBCDIC-CP-CH"] = 500; + map["IBM500"] = 500; + map["ASMO-708"] = 708; + map["DOS-720"] = 720; + map["IBM737"] = 737; + map["IBM775"] = 775; + map["CP850"] = 850; + map["IBM850"] = 850; + map["CP852"] = 852; + map["IBM852"] = 852; + map["CP855"] = 855; + map["IBM855"] = 855; + map["CP857"] = 857; + map["IBM857"] = 857; + map["CCSID00858"] = 858; + map["CP00858"] = 858; + map["CP858"] = 858; + map["IBM00858"] = 858; + map["PC-MULTILINGUAL-850+EURO"] = 858; + map["CP860"] = 860; + map["IBM860"] = 860; + map["CP861"] = 861; + map["IBM861"] = 861; + map["CP862"] = 862; + map["DOS-862"] = 862; + map["IBM862"] = 862; + map["CP863"] = 863; + map["IBM863"] = 863; + map["CP864"] = 864; + map["IBM864"] = 864; + map["CP865"] = 865; + map["IBM865"] = 865; + map["CP866"] = 866; + map["IBM866"] = 866; + map["CP869"] = 869; + map["IBM869"] = 869; + map["CP870"] = 870; + map["CSIBM870"] = 870; + map["EBCDIC-CP-ROECE"] = 870; + map["EBCDIC-CP-YU"] = 870; + map["IBM870"] = 870; + map["DOS-874"] = 874; + map["ISO-8859-11"] = 874; + map["MS874"] = 874; + map["TIS620"] = 874; + map["TIS-620"] = 874; + map["WINDOWS-874"] = 874; + map["CP875"] = 875; + map["CSSHIFTJIS"] = 932; + map["CSWINDOWS31J"] = 932; + map["MS932"] = 932; + map["MS_KANJI"] = 932; + map["SHIFT-JIS"] = 932; + map["SHIFT_JIS"] = 932; + map["SJIS"] = 932; + map["X-MS-CP932"] = 932; + map["X-SJIS"] = 932; + map["CHINESE"] = 936; + map["CN-GB"] = 936; + map["CSGB2312"] = 936; + map["CSGB231280"] = 936; + map["CSISO58GB231280"] = 936; + map["GB2312"] = 936; + map["GB2312-80"] = 936; + map["GB231280"] = 936; + map["GB_2312-80"] = 936; + map["GBK"] = 936; + map["ISO-IR-58"] = 936; + map["MS936"] = 936; + map["CSKSC56011987"] = 949; + map["ISO-IR-149"] = 949; + map["KOREAN"] = 949; + map["KS-C-5601"] = 949; + map["KS-C5601"] = 949; + map["KS_C_5601"] = 949; + map["KS_C_5601-1987"] = 949; + map["KS_C_5601-1989"] = 949; + map["KS_C_5601_1987"] = 949; + map["KSC5601"] = 949; + map["KSC_5601"] = 949; + map["MS949"] = 949; + map["BIG5"] = 950; + map["BIG5-HKSCS"] = 950; + map["CN-BIG5"] = 950; + map["CSBIG5"] = 950; + map["MS950"] = 950; + map["X-X-BIG5"] = 950; + map["CP1026"] = 1026; + map["CSIBM1026"] = 1026; + map["IBM1026"] = 1026; + map["IBM01047"] = 1047; + map["CCSID01140"] = 1140; + map["CP01140"] = 1140; + map["EBCDIC-US-37+EURO"] = 1140; + map["IBM01140"] = 1140; + map["CCSID01141"] = 1141; + map["CP01141"] = 1141; + map["EBCDIC-DE-273+EURO"] = 1141; + map["IBM01141"] = 1141; + map["CCSID01142"] = 1142; + map["CP01142"] = 1142; + map["EBCDIC-DK-277+EURO"] = 1142; + map["EBCDIC-NO-277+EURO"] = 1142; + map["IBM01142"] = 1142; + map["CCSID01143"] = 1143; + map["CP01143"] = 1143; + map["EBCDIC-FI-278+EURO"] = 1143; + map["EBCDIC-SE-278+EURO"] = 1143; + map["IBM01143"] = 1143; + map["CCSID01144"] = 1144; + map["CP01144"] = 1144; + map["EBCDIC-IT-280+EURO"] = 1144; + map["IBM01144"] = 1144; + map["CCSID01145"] = 1145; + map["CP01145"] = 1145; + map["EBCDIC-ES-284+EURO"] = 1145; + map["IBM01145"] = 1145; + map["CCSID01146"] = 1146; + map["CP01146"] = 1146; + map["EBCDIC-GB-285+EURO"] = 1146; + map["IBM01146"] = 1146; + map["CCSID01147"] = 1147; + map["CP01147"] = 1147; + map["EBCDIC-FR-297+EURO"] = 1147; + map["IBM01147"] = 1147; + map["CCSID01148"] = 1148; + map["CP01148"] = 1148; + map["EBCDIC-INTERNATIONAL-500+EURO"] = 1148; + map["IBM01148"] = 1148; + map["CCSID01149"] = 1149; + map["CP01149"] = 1149; + map["EBCDIC-IS-871+EURO"] = 1149; + map["IBM01149"] = 1149; + map["ISO-10646-UCS-2"] = 1200; + map["UCS-2"] = 1200; + map["UNICODE"] = 1200; + map["UTF-16"] = 1200; + map["UTF-16LE"] = 1200; + map["UNICODELITTLEUNMARKED"] = 1200; + map["UNICODELITTLE"] = 1200; + map["UNICODEFFFE"] = 1201; + map["UTF-16BE"] = 1201; + map["UNICODEBIGUNMARKED"] = 1201; + map["UNICODEBIG"] = 1201; + map["CP1250"] = 1250; + map["WINDOWS-1250"] = 1250; + map["X-CP1250"] = 1250; + map["CP1251"] = 1251; + map["WINDOWS-1251"] = 1251; + map["X-CP1251"] = 1251; + map["CP1252"] = 1252; + map["WINDOWS-1252"] = 1252; + map["X-ANSI"] = 1252; + map["CP1253"] = 1253; + map["WINDOWS-1253"] = 1253; + map["CP1254"] = 1254; + map["WINDOWS-1254"] = 1254; + map["CP1255"] = 1255; + map["WINDOWS-1255"] = 1255; + map["CP1256"] = 1256; + map["WINDOWS-1256"] = 1256; + map["CP1257"] = 1257; + map["WINDOWS-1257"] = 1257; + map["CP1258"] = 1258; + map["WINDOWS-1258"] = 1258; + map["JOHAB"] = 1361; + map["MACINTOSH"] = 10000; + map["MACROMAN"] = 10000; + map["X-MAC-JAPANESE"] = 10001; + map["X-MAC-CHINESETRAD"] = 10002; + map["X-MAC-KOREAN"] = 10003; + map["MACARABIC"] = 10004; + map["X-MAC-ARABIC"] = 10004; + map["MACHEBREW"] = 10005; + map["X-MAC-HEBREW"] = 10005; + map["MACGREEK"] = 10006; + map["X-MAC-GREEK"] = 10006; + map["MACCYRILLIC"] = 10007; + map["X-MAC-CYRILLIC"] = 10007; + map["X-MAC-CHINESESIMP"] = 10008; + map["MACROMANIA"] = 10010; + map["MACROMANIAN"] = 10010; + map["X-MAC-ROMANIAN"] = 10010; + map["MACUKRAINE"] = 10017; + map["MACUKRAINIAN"] = 10017; + map["X-MAC-UKRAINIAN"] = 10017; + map["MACTHAI"] = 10021; + map["X-MAC-THAI"] = 10021; + map["MACCENTRALEUROPE"] = 10029; + map["X-MAC-CE"] = 10029; + map["MACICELANDIC"] = 10079; + map["MACICELAND"] = 10079; + map["X-MAC-ICELANDIC"] = 10079; + map["MACTURKISH"] = 10081; + map["X-MAC-TURKISH"] = 10081; + map["MACCROATIAN"] = 10082; + map["X-MAC-CROATIAN"] = 10082; + map["X-CHINESE-CNS"] = 20000; + map["X-CP20001"] = 20001; + map["X-CHINESE-ETEN"] = 20002; + map["X-CP20003"] = 20003; + map["X-CP20004"] = 20004; + map["X-CP20005"] = 20005; + map["IRV"] = 20105; + map["X-IA5"] = 20105; + map["DIN_66003"] = 20106; + map["GERMAN"] = 20106; + map["X-IA5-GERMAN"] = 20106; + map["SEN_850200_B"] = 20107; + map["SWEDISH"] = 20107; + map["X-IA5-SWEDISH"] = 20107; + map["NORWEGIAN"] = 20108; + map["NS_4551-1"] = 20108; + map["X-IA5-NORWEGIAN"] = 20108; + map["ANSI_X3.4-1968"] = 20127; + map["ANSI_X3.4-1986"] = 20127; + map["ASCII"] = 20127; + map["CP367"] = 20127; + map["CSASCII"] = 20127; + map["IBM367"] = 20127; + map["ISO-IR-6"] = 20127; + map["ISO646-US"] = 20127; + map["ISO_646.IRV:1991"] = 20127; + map["US"] = 20127; + map["US-ASCII"] = 20127; + map["X-CP20261"] = 20261; + map["X-CP20269"] = 20269; + map["CP273"] = 20273; + map["CSIBM273"] = 20273; + map["IBM273"] = 20273; + map["CSIBM277"] = 20277; + map["EBCDIC-CP-DK"] = 20277; + map["EBCDIC-CP-NO"] = 20277; + map["IBM277"] = 20277; + map["CP278"] = 20278; + map["CSIBM278"] = 20278; + map["EBCDIC-CP-FI"] = 20278; + map["EBCDIC-CP-SE"] = 20278; + map["IBM278"] = 20278; + map["CP280"] = 20280; + map["CSIBM280"] = 20280; + map["EBCDIC-CP-IT"] = 20280; + map["IBM280"] = 20280; + map["CP284"] = 20284; + map["CSIBM284"] = 20284; + map["EBCDIC-CP-ES"] = 20284; + map["IBM284"] = 20284; + map["CP285"] = 20285; + map["CSIBM285"] = 20285; + map["EBCDIC-CP-GB"] = 20285; + map["IBM285"] = 20285; + map["CP290"] = 20290; + map["CSIBM290"] = 20290; + map["EBCDIC-JP-KANA"] = 20290; + map["IBM290"] = 20290; + map["CP297"] = 20297; + map["CSIBM297"] = 20297; + map["EBCDIC-CP-FR"] = 20297; + map["IBM297"] = 20297; + map["CP420"] = 20420; + map["CSIBM420"] = 20420; + map["EBCDIC-CP-AR1"] = 20420; + map["IBM420"] = 20420; + map["CP423"] = 20423; + map["CSIBM423"] = 20423; + map["EBCDIC-CP-GR"] = 20423; + map["IBM423"] = 20423; + map["CP424"] = 20424; + map["CSIBM424"] = 20424; + map["EBCDIC-CP-HE"] = 20424; + map["IBM424"] = 20424; + map["X-EBCDIC-KOREANEXTENDED"] = 20833; + map["CSIBMTHAI"] = 20838; + map["IBM-THAI"] = 20838; + map["CSKOI8R"] = 20866; + map["KOI"] = 20866; + map["KOI8"] = 20866; + map["KOI8-R"] = 20866; + map["KOI8R"] = 20866; + map["CP871"] = 20871; + map["CSIBM871"] = 20871; + map["EBCDIC-CP-IS"] = 20871; + map["IBM871"] = 20871; + map["CP880"] = 20880; + map["CSIBM880"] = 20880; + map["EBCDIC-CYRILLIC"] = 20880; + map["IBM880"] = 20880; + map["CP905"] = 20905; + map["CSIBM905"] = 20905; + map["EBCDIC-CP-TR"] = 20905; + map["IBM905"] = 20905; + map["CCSID00924"] = 20924; + map["CP00924"] = 20924; + map["EBCDIC-LATIN9--EURO"] = 20924; + map["IBM00924"] = 20924; + map["X-CP20936"] = 20936; + map["X-CP20949"] = 20949; + map["CP1025"] = 21025; + map["X-CP21027"] = 21027; + map["KOI8-RU"] = 21866; + map["KOI8-U"] = 21866; + map["CP819"] = 28591; + map["CSISOLATIN1"] = 28591; + map["IBM819"] = 28591; + map["ISO-8859-1"] = 28591; + map["ISO-IR-100"] = 28591; + map["ISO8859-1"] = 28591; + map["ISO_8859-1"] = 28591; + map["ISO_8859-1:1987"] = 28591; + map["L1"] = 28591; + map["LATIN1"] = 28591; + map["CSISOLATIN2"] = 28592; + map["ISO-8859-2"] = 28592; + map["ISO-IR-101"] = 28592; + map["ISO8859-2"] = 28592; + map["ISO_8859-2"] = 28592; + map["ISO_8859-2:1987"] = 28592; + map["L2"] = 28592; + map["LATIN2"] = 28592; + map["CSISOLATIN3"] = 28593; + map["ISO-8859-3"] = 28593; + map["ISO-IR-109"] = 28593; + map["ISO_8859-3"] = 28593; + map["ISO_8859-3:1988"] = 28593; + map["L3"] = 28593; + map["LATIN3"] = 28593; + map["CSISOLATIN4"] = 28594; + map["ISO-8859-4"] = 28594; + map["ISO-IR-110"] = 28594; + map["ISO_8859-4"] = 28594; + map["ISO_8859-4:1988"] = 28594; + map["L4"] = 28594; + map["LATIN4"] = 28594; + map["CSISOLATINCYRILLIC"] = 28595; + map["CYRILLIC"] = 28595; + map["ISO-8859-5"] = 28595; + map["ISO-IR-144"] = 28595; + map["ISO_8859-5"] = 28595; + map["ISO_8859-5:1988"] = 28595; + map["ARABIC"] = 28596; + map["CSISOLATINARABIC"] = 28596; + map["ECMA-114"] = 28596; + map["ISO-8859-6"] = 28596; + map["ISO-IR-127"] = 28596; + map["ISO_8859-6"] = 28596; + map["ISO_8859-6:1987"] = 28596; + map["CSISOLATINGREEK"] = 28597; + map["ECMA-118"] = 28597; + map["ELOT_928"] = 28597; + map["GREEK"] = 28597; + map["GREEK8"] = 28597; + map["ISO-8859-7"] = 28597; + map["ISO-IR-126"] = 28597; + map["ISO_8859-7"] = 28597; + map["ISO_8859-7:1987"] = 28597; + map["CSISOLATINHEBREW"] = 28598; + map["HEBREW"] = 28598; + map["ISO-8859-8"] = 28598; + map["ISO-IR-138"] = 28598; + map["ISO_8859-8"] = 28598; + map["ISO_8859-8:1988"] = 28598; + map["LOGICAL"] = 28598; + map["VISUAL"] = 28598; + map["CSISOLATIN5"] = 28599; + map["ISO-8859-9"] = 28599; + map["ISO-IR-148"] = 28599; + map["ISO_8859-9"] = 28599; + map["ISO_8859-9:1989"] = 28599; + map["L5"] = 28599; + map["LATIN5"] = 28599; + map["ISO-8859-13"] = 28603; + map["CSISOLATIN9"] = 28605; + map["ISO-8859-15"] = 28605; + map["ISO_8859-15"] = 28605; + map["L9"] = 28605; + map["LATIN9"] = 28605; + map["X-EUROPA"] = 29001; + map["ISO-8859-8-I"] = 38598; + map["ISO-2022-JP"] = 50220; + map["CSISO2022JP"] = 50221; + map["CSISO2022KR"] = 50225; + map["ISO-2022-KR"] = 50225; + map["ISO-2022-KR-7"] = 50225; + map["ISO-2022-KR-7BIT"] = 50225; + map["CP50227"] = 50227; + map["X-CP50227"] = 50227; + map["CP930"] = 50930; + map["X-EBCDIC-JAPANESEANDUSCANADA"] = 50931; + map["CP933"] = 50933; + map["CP935"] = 50935; + map["CP937"] = 50937; + map["CP939"] = 50939; + map["CSEUCPKDFMTJAPANESE"] = 51932; + map["EUC-JP"] = 51932; + map["EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE"] = 51932; + map["ISO-2022-JPEUC"] = 51932; + map["X-EUC"] = 51932; + map["X-EUC-JP"] = 51932; + map["EUC-CN"] = 51936; + map["X-EUC-CN"] = 51936; + map["CSEUCKR"] = 51949; + map["EUC-KR"] = 51949; + map["ISO-2022-KR-8"] = 51949; + map["ISO-2022-KR-8BIT"] = 51949; + map["HZ-GB-2312"] = 52936; + map["GB18030"] = 54936; + map["X-ISCII-DE"] = 57002; + map["X-ISCII-BE"] = 57003; + map["X-ISCII-TA"] = 57004; + map["X-ISCII-TE"] = 57005; + map["X-ISCII-AS"] = 57006; + map["X-ISCII-OR"] = 57007; + map["X-ISCII-KA"] = 57008; + map["X-ISCII-MA"] = 57009; + map["X-ISCII-GU"] = 57010; + map["X-ISCII-PA"] = 57011; + map["CSUNICODE11UTF7"] = 65000; + map["UNICODE-1-1-UTF-7"] = 65000; + map["UNICODE-2-0-UTF-7"] = 65000; + map["UTF-7"] = 65000; + map["X-UNICODE-1-1-UTF-7"] = 65000; + map["X-UNICODE-2-0-UTF-7"] = 65000; + map["UNICODE-1-1-UTF-8"] = 65001; + map["UNICODE-2-0-UTF-8"] = 65001; + map["UTF-8"] = 65001; + map["X-UNICODE-1-1-UTF-8"] = 65001; + map["X-UNICODE-2-0-UTF-8"] = 65001; + } + + public static int GetEncodingNumber(string name) { + object n = map[name.ToUpper(System.Globalization.CultureInfo.InvariantCulture)]; + if (n == null) + return 0; + return (int)n; + } + + public static Encoding GetEncodingEncoding(string name) { + String nameU = name.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + if (nameU.Equals("UNICODEBIGUNMARKED")) + return new UnicodeEncoding(true, false); + if (nameU.Equals("UNICODEBIG")) + return new UnicodeEncoding(true, true); + if (nameU.Equals("UNICODELITTLEUNMARKED")) + return new UnicodeEncoding(false, false); + if (nameU.Equals("UNICODELITTLE")) + return new UnicodeEncoding(false, true); + if (map.ContainsKey(nameU)) + return Encoding.GetEncoding((int)map[nameU]); + else + return Encoding.GetEncoding(name); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/simpleparser/SimpleXMLParser.cs b/iTechSharp/iTextSharp/text/xml/simpleparser/SimpleXMLParser.cs new file mode 100644 index 0000000..93ac6db --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/simpleparser/SimpleXMLParser.cs @@ -0,0 +1,740 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * The code to recognize the encoding in this class and in the convenience class IanaEncodings was taken from Apache Xerces published under the following license: + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Part of this code is based on the Quick-and-Dirty XML parser by Steven Brandt. + * The code for the Quick-and-Dirty parser was published in JavaWorld (java tip 128). + * Steven Brandt and JavaWorld gave permission to use the code for free. + * (Bruno Lowagie and Paulo Soares chose to use it under the MPL/LGPL in + * conformance with the rest of the code). + * The original code can be found on this url: http://www.javaworld.com/javatips/jw-javatip128_p.html. + * It was substantially refactored by Bruno Lowagie. + * + * The method 'private static String getEncodingName(byte[] b4)' was found + * in org.apache.xerces.impl.XMLEntityManager, originaly published by the + * Apache Software Foundation under the Apache Software License; now being + * used in iText under the MPL. + */ + +namespace iTextSharp.text.xml.simpleparser { + /** + * A simple XML and HTML parser. This parser is, like the SAX parser, + * an event based parser, but with much less functionality. + *

      + * The parser can: + *

      + *

        + *
      • It recognizes the encoding used + *
      • It recognizes all the elements' start tags and end tags + *
      • It lists attributes, where attribute values can be enclosed in single or double quotes + *
      • It recognizes the <[CDATA[ ... ]]> construct + *
      • It recognizes the standard entities: &amp;, &lt;, &gt;, &quot;, and &apos;, as well as numeric entities + *
      • It maps lines ending in \r\n and \r to \n on input, in accordance with the XML Specification, Section 2.11 + *
      + *

      + * The code is based on + * http://www.javaworld.com/javaworld/javatips/javatip128/ with some extra + * code from XERCES to recognize the encoding. + */ + public sealed class SimpleXMLParser { + /** possible states */ + private const int UNKNOWN = 0; + private const int TEXT = 1; + private const int TAG_ENCOUNTERED = 2; + private const int EXAMIN_TAG = 3; + private const int TAG_EXAMINED = 4; + private const int IN_CLOSETAG = 5; + private const int SINGLE_TAG = 6; + private const int CDATA = 7; + private const int COMMENT = 8; + private const int PI = 9; + private const int ENTITY = 10; + private const int QUOTE = 11; + private const int ATTRIBUTE_KEY = 12; + private const int ATTRIBUTE_EQUAL = 13; + private const int ATTRIBUTE_VALUE = 14; + + /** the state stack */ + internal Stack stack; + /** The current character. */ + internal int character = 0; + /** The previous character. */ + internal int previousCharacter = -1; + /** the line we are currently reading */ + internal int lines = 1; + /** the column where the current character occurs */ + internal int columns = 0; + /** was the last character equivalent to a newline? */ + internal bool eol = false; + /** the current state */ + internal int state; + /** Are we parsing HTML? */ + internal bool html; + /** current text (whatever is encountered between tags) */ + internal StringBuilder text = new StringBuilder(); + /** current entity (whatever is encountered between & and ;) */ + internal StringBuilder entity = new StringBuilder(); + /** current tagname */ + internal String tag = null; + /** current attributes */ + internal Hashtable attributes = null; + /** The handler to which we are going to forward document content */ + internal ISimpleXMLDocHandler doc; + /** The handler to which we are going to forward comments. */ + internal ISimpleXMLDocHandlerComment comment; + /** Keeps track of the number of tags that are open. */ + internal int nested = 0; + /** the quote character that was used to open the quote. */ + internal int quoteCharacter = '"'; + /** the attribute key. */ + internal String attributekey = null; + /** the attribute value. */ + internal String attributevalue = null; + + /** + * Creates a Simple XML parser object. + * Call Go(BufferedReader) immediately after creation. + */ + private SimpleXMLParser(ISimpleXMLDocHandler doc, ISimpleXMLDocHandlerComment comment, bool html) { + this.doc = doc; + this.comment = comment; + this.html = html; + stack = new Stack(); + state = html ? TEXT : UNKNOWN; + } + + /** + * Does the actual parsing. Perform this immediately + * after creating the parser object. + */ + private void Go(TextReader reader) { + doc.StartDocument(); + while (true) { + // read a new character + if (previousCharacter == -1) { + character = reader.Read(); + } + // or re-examin the previous character + else { + character = previousCharacter; + previousCharacter = -1; + } + + // the end of the file was reached + if (character == -1) { + if (html) { + if (html && state == TEXT) + Flush(); + doc.EndDocument(); + } else { + ThrowException("Missing end tag"); + } + return; + } + + // dealing with \n and \r + if (character == '\n' && eol) { + eol = false; + continue; + } else if (eol) { + eol = false; + } else if (character == '\n') { + lines++; + columns = 0; + } else if (character == '\r') { + eol = true; + character = '\n'; + lines++; + columns = 0; + } else { + columns++; + } + + switch (state) { + // we are in an unknown state before there's actual content + case UNKNOWN: + if (character == '<') { + SaveState(TEXT); + state = TAG_ENCOUNTERED; + } + break; + // we can encounter any content + case TEXT: + if (character == '<') { + Flush(); + SaveState(state); + state = TAG_ENCOUNTERED; + } else if (character == '&') { + SaveState(state); + entity.Length = 0; + state = ENTITY; + } else + text.Append((char)character); + break; + // we have just seen a < and are wondering what we are looking at + // , , , etc. + case TAG_ENCOUNTERED: + InitTag(); + if (character == '/') { + state = IN_CLOSETAG; + } else if (character == '?') { + RestoreState(); + state = PI; + } else { + text.Append((char)character); + state = EXAMIN_TAG; + } + break; + // we are processing something like this . + // It could still be a or something. + case EXAMIN_TAG: + if (character == '>') { + DoTag(); + ProcessTag(true); + InitTag(); + state = RestoreState(); + } else if (character == '/') { + state = SINGLE_TAG; + } else if (character == '-' && text.ToString().Equals("!-")) { + Flush(); + state = COMMENT; + } else if (character == '[' && text.ToString().Equals("![CDATA")) { + Flush(); + state = CDATA; + } else if (character == 'E' && text.ToString().Equals("!DOCTYP")) { + Flush(); + state = PI; + } else if (char.IsWhiteSpace((char)character)) { + DoTag(); + state = TAG_EXAMINED; + } else { + text.Append((char)character); + } + break; + // we know the name of the tag now. + case TAG_EXAMINED: + if (character == '>') { + ProcessTag(true); + InitTag(); + state = RestoreState(); + } else if (character == '/') { + state = SINGLE_TAG; + } else if (char.IsWhiteSpace((char)character)) { + // empty + } else { + text.Append((char)character); + state = ATTRIBUTE_KEY; + } + break; + + // we are processing a closing tag: e.g. + case IN_CLOSETAG: + if (character == '>') { + DoTag(); + ProcessTag(false); + if (!html && nested==0) return; + state = RestoreState(); + } else { + if (!char.IsWhiteSpace((char)character)) + text.Append((char)character); + } + break; + + // we have just seen something like this: . + case SINGLE_TAG: + if (character != '>') + ThrowException("Expected > for tag: <"+tag+"/>"); + DoTag(); + ProcessTag(true); + ProcessTag(false); + InitTag(); + if (!html && nested==0) { + doc.EndDocument(); + return; + } + state = RestoreState(); + break; + + // we are processing CDATA + case CDATA: + if (character == '>' + && text.ToString().EndsWith("]]")) { + text.Length = text.Length - 2; + Flush(); + state = RestoreState(); + } else + text.Append((char)character); + break; + + // we are processing a comment. We are inside + // the looking for the -->. + case COMMENT: + if (character == '>' + && text.ToString().EndsWith("--")) { + text.Length = text.Length - 2; + Flush(); + state = RestoreState(); + } else + text.Append((char)character); + break; + + // We are inside one of these or one of these + case PI: + if (character == '>') { + state = RestoreState(); + if (state == TEXT) state = UNKNOWN; + } + break; + + // we are processing an entity, e.g. <, », etc. + case ENTITY: + if (character == ';') { + state = RestoreState(); + String cent = entity.ToString(); + entity.Length = 0; + char ce = EntitiesToUnicode.DecodeEntity(cent); + if (ce == '\0') + text.Append('&').Append(cent).Append(';'); + else + text.Append(ce); + } else if ((character != '#' && (character < '0' || character > '9') && (character < 'a' || character > 'z') + && (character < 'A' || character > 'Z')) || entity.Length >= 7) { + state = RestoreState(); + previousCharacter = character; + text.Append('&').Append(entity.ToString()); + entity.Length = 0; + } + else { + entity.Append((char)character); + } + break; + // We are processing the quoted right-hand side of an element's attribute. + case QUOTE: + if (html && quoteCharacter == ' ' && character == '>') { + Flush(); + ProcessTag(true); + InitTag(); + state = RestoreState(); + } + else if (html && quoteCharacter == ' ' && char.IsWhiteSpace((char)character)) { + Flush(); + state = TAG_EXAMINED; + } + else if (html && quoteCharacter == ' ') { + text.Append((char)character); + } + else if (character == quoteCharacter) { + Flush(); + state = TAG_EXAMINED; + } else if (" \r\n\u0009".IndexOf((char)character)>=0) { + text.Append(' '); + } else if (character == '&') { + SaveState(state); + state = ENTITY; + entity.Length = 0; + } else { + text.Append((char)character); + } + break; + + case ATTRIBUTE_KEY: + if (char.IsWhiteSpace((char)character)) { + Flush(); + state = ATTRIBUTE_EQUAL; + } else if (character == '=') { + Flush(); + state = ATTRIBUTE_VALUE; + } else if (html && character == '>') { + text.Length = 0; + ProcessTag(true); + InitTag(); + state = RestoreState(); + } else { + text.Append((char)character); + } + break; + + case ATTRIBUTE_EQUAL: + if (character == '=') { + state = ATTRIBUTE_VALUE; + } else if (char.IsWhiteSpace((char)character)) { + // empty + } else if (html && character == '>') { + text.Length = 0; + ProcessTag(true); + InitTag(); + state = RestoreState(); + } else if (html && character == '/') { + Flush(); + state = SINGLE_TAG; + } else if (html) { + Flush(); + text.Append((char)character); + state = ATTRIBUTE_KEY; + } else { + ThrowException("Error in attribute processing."); + } + break; + + case ATTRIBUTE_VALUE: + if (character == '"' || character == '\'') { + quoteCharacter = character; + state = QUOTE; + } else if (char.IsWhiteSpace((char)character)) { + // empty + } else if (html && character == '>') { + Flush(); + ProcessTag(true); + InitTag(); + state = RestoreState(); + } else if (html) { + text.Append((char)character); + quoteCharacter = ' '; + state = QUOTE; + } else { + ThrowException("Error in attribute processing"); + } + break; + } + } + } + + /** + * Gets a state from the stack + * @return the previous state + */ + private int RestoreState() { + if (stack.Count != 0) + return (int)stack.Pop(); + else + return UNKNOWN; + } + /** + * Adds a state to the stack. + * @param s a state to add to the stack + */ + private void SaveState(int s) { + stack.Push(s); + } + /** + * Flushes the text that is currently in the buffer. + * The text can be ignored, added to the document + * as content or as comment,... depending on the current state. + */ + private void Flush() { + switch (state){ + case TEXT: + case CDATA: + if (text.Length > 0) { + doc.Text(text.ToString()); + } + break; + case COMMENT: + if (comment != null) { + comment.Comment(text.ToString()); + } + break; + case ATTRIBUTE_KEY: + attributekey = text.ToString(); + if (html) + attributekey = attributekey.ToLower(CultureInfo.InvariantCulture); + break; + case QUOTE: + case ATTRIBUTE_VALUE: + attributevalue = text.ToString(); + attributes[attributekey] = attributevalue; + break; + default: + // do nothing + break; + } + text.Length = 0; + } + /** + * Initialized the tag name and attributes. + */ + private void InitTag() { + tag = null; + attributes = new Hashtable(); + } + /** Sets the name of the tag. */ + private void DoTag() { + if (tag == null) + tag = text.ToString(); + if (html) + tag = tag.ToLower(CultureInfo.InvariantCulture); + text.Length = 0; + } + /** + * processes the tag. + * @param start if true we are dealing with a tag that has just been opened; if false we are closing a tag. + */ + private void ProcessTag(bool start) { + if (start) { + nested++; + doc.StartElement(tag,attributes); + } + else { + nested--; + doc.EndElement(tag); + } + } + /** Throws an exception */ + private void ThrowException(String s) { + throw new IOException(s+" near line " + lines + ", column " + columns); + } + + /** + * Parses the XML document firing the events to the handler. + * @param doc the document handler + * @param r the document. The encoding is already resolved. The reader is not closed + * @throws IOException on error + */ + public static void Parse(ISimpleXMLDocHandler doc, ISimpleXMLDocHandlerComment comment, TextReader r, bool html) { + SimpleXMLParser parser = new SimpleXMLParser(doc, comment, html); + parser.Go(r); + } + + /** + * Parses the XML document firing the events to the handler. + * @param doc the document handler + * @param in the document. The encoding is deduced from the stream. The stream is not closed + * @throws IOException on error + */ + public static void Parse(ISimpleXMLDocHandler doc, Stream inp) { + byte[] b4 = new byte[4]; + int count = inp.Read(b4, 0, b4.Length); + if (count != 4) + throw new IOException("Insufficient length."); + String encoding = GetEncodingName(b4); + String decl = null; + if (encoding.Equals("UTF-8")) { + StringBuilder sb = new StringBuilder(); + int c; + while ((c = inp.ReadByte()) != -1) { + if (c == '>') + break; + sb.Append((char)c); + } + decl = sb.ToString(); + } + else if (encoding.Equals("CP037")) { + MemoryStream bi = new MemoryStream(); + int c; + while ((c = inp.ReadByte()) != -1) { + if (c == 0x6e) // that's '>' in ebcdic + break; + bi.WriteByte((byte)c); + } + decl = Encoding.GetEncoding(37).GetString(bi.ToArray());//cp037 ebcdic + } + if (decl != null) { + decl = GetDeclaredEncoding(decl); + if (decl != null) + encoding = decl; + } + Parse(doc, new StreamReader(inp, IanaEncodings.GetEncodingEncoding(encoding))); + } + + private static String GetDeclaredEncoding(String decl) { + if (decl == null) + return null; + int idx = decl.IndexOf("encoding"); + if (idx < 0) + return null; + int idx1 = decl.IndexOf('"', idx); + int idx2 = decl.IndexOf('\'', idx); + if (idx1 == idx2) + return null; + if ((idx1 < 0 && idx2 > 0) || (idx2 > 0 && idx2 < idx1)) { + int idx3 = decl.IndexOf('\'', idx2 + 1); + if (idx3 < 0) + return null; + return decl.Substring(idx2 + 1, idx3 - (idx2 + 1)); + } + if ((idx2 < 0 && idx1 > 0) || (idx1 > 0 && idx1 < idx2)) { + int idx3 = decl.IndexOf('"', idx1 + 1); + if (idx3 < 0) + return null; + return decl.Substring(idx1 + 1, idx3 - (idx1 + 1)); + } + return null; + } + + public static void Parse(ISimpleXMLDocHandler doc, TextReader r) { + Parse(doc, null, r, false); + } + + /** + * Escapes a string with the appropriated XML codes. + * @param s the string to be escaped + * @param onlyASCII codes above 127 will always be escaped with &#nn; if true + * @return the escaped string + */ + public static String EscapeXML(String s, bool onlyASCII) { + char[] cc = s.ToCharArray(); + int len = cc.Length; + StringBuilder sb = new StringBuilder(); + for (int k = 0; k < len; ++k) { + int c = cc[k]; + switch (c) { + case '<': + sb.Append("<"); + break; + case '>': + sb.Append(">"); + break; + case '&': + sb.Append("&"); + break; + case '"': + sb.Append("""); + break; + case '\'': + sb.Append("'"); + break; + default: + if (onlyASCII && c > 127) + sb.Append("&#").Append(c).Append(';'); + else + sb.Append((char)c); + break; + } + } + return sb.ToString(); + } + + /** + * Returns the IANA encoding name that is auto-detected from + * the bytes specified, with the endian-ness of that encoding where appropriate. + * (method found in org.apache.xerces.impl.XMLEntityManager, originaly published + * by the Apache Software Foundation under the Apache Software License; now being + * used in iText under the MPL) + * @param b4 The first four bytes of the input. + * @return an IANA-encoding string + */ + private static String GetEncodingName(byte[] b4) { + // UTF-16, with BOM + int b0 = b4[0] & 0xFF; + int b1 = b4[1] & 0xFF; + if (b0 == 0xFE && b1 == 0xFF) { + // UTF-16, big-endian + return "UTF-16BE"; + } + if (b0 == 0xFF && b1 == 0xFE) { + // UTF-16, little-endian + return "UTF-16LE"; + } + + // UTF-8 with a BOM + int b2 = b4[2] & 0xFF; + if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { + return "UTF-8"; + } + + // other encodings + int b3 = b4[3] & 0xFF; + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { + // UCS-4, big endian (1234) + return "ISO-10646-UCS-4"; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { + // UCS-4, little endian (4321) + return "ISO-10646-UCS-4"; + } + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { + // UCS-4, unusual octet order (2143) + // REVISIT: What should this be? + return "ISO-10646-UCS-4"; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { + // UCS-4, unusual octect order (3412) + // REVISIT: What should this be? + return "ISO-10646-UCS-4"; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { + // UTF-16, big-endian, no BOM + // (or could turn out to be UCS-2... + // REVISIT: What should this be? + return "UTF-16BE"; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { + // UTF-16, little-endian, no BOM + // (or could turn out to be UCS-2... + return "UTF-16LE"; + } + if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { + // EBCDIC + // a la xerces1, return CP037 instead of EBCDIC here + return "CP037"; + } + + // default encoding + return "UTF-8"; + } + } +} diff --git a/iTechSharp/iTextSharp/text/xml/xmp/DublinCoreSchema.cs b/iTechSharp/iTextSharp/text/xml/xmp/DublinCoreSchema.cs new file mode 100644 index 0000000..ebfc82b --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/DublinCoreSchema.cs @@ -0,0 +1,185 @@ +using System; +/* + * $Id: DublinCoreSchema.cs,v 1.3 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * An implementation of an XmpSchema. + */ + public class DublinCoreSchema : XmpSchema { + + /** default namespace identifier*/ + public const String DEFAULT_XPATH_ID = "dc"; + /** default namespace uri*/ + public const String DEFAULT_XPATH_URI = "http://purl.org/dc/elements/1.1/"; + /** External Contributors to the resource (other than the authors). */ + public const String CONTRIBUTOR = "dc:contributor"; + /** The extent or scope of the resource. */ + public const String COVERAGE = "dc:coverage"; + /** The authors of the resource (listed in order of precedence, if significant). */ + public const String CREATOR = "dc:creator"; + /** Date(s) that something interesting happened to the resource. */ + public const String DATE = "dc:date"; + /** A textual description of the content of the resource. Multiple values may be present for different languages. */ + public const String DESCRIPTION = "dc:description"; + /** The file format used when saving the resource. Tools and applications should set this property to the save format of the data. It may include appropriate qualifiers. */ + public const String FORMAT = "dc:format"; + /** Unique identifier of the resource. */ + public const String IDENTIFIER = "dc:identifier"; + /** An unordered array specifying the languages used in the resource. */ + public const String LANGUAGE = "dc:language"; + /** Publishers. */ + public const String PUBLISHER = "dc:publisher"; + /** Relationships to other documents. */ + public const String RELATION = "dc:relation"; + /** Informal rights statement, selected by language. */ + public const String RIGHTS = "dc:rights"; + /** Unique identifier of the work from which this resource was derived. */ + public const String SOURCE = "dc:source"; + /** An unordered array of descriptive phrases or keywords that specify the topic of the content of the resource. */ + public const String SUBJECT = "dc:subject"; + /** The title of the document, or the name given to the resource. Typically, it will be a name by which the resource is formally known. */ + public const String TITLE = "dc:title"; + /** A document type; for example, novel, poem, or working paper. */ + public const String TYPE = "dc:type"; + + /** + * @param shorthand + * @throws IOException + */ + public DublinCoreSchema() : base("xmlns:" + DEFAULT_XPATH_ID + "=\"" + DEFAULT_XPATH_URI + "\"") { + this[FORMAT] = "application/pdf"; + } + + /** + * Adds a title. + * @param title + */ + public void AddTitle(String title) { + this[TITLE] = title; + } + + /** + * Adds a description. + * @param desc + */ + public void AddDescription(String desc) { + this[DESCRIPTION] = desc; + } + + /** + * Adds a subject. + * @param subject + */ + public void AddSubject(String subject) { + XmpArray array = new XmpArray(XmpArray.UNORDERED); + array.Add(subject); + SetProperty(SUBJECT, array); + } + + + /** + * Adds a subject. + * @param subject array of subjects + */ + public void addSubject(String[] subject) { + XmpArray array = new XmpArray(XmpArray.UNORDERED); + for (int i = 0; i < subject.Length; i++) { + array.Add(subject[i]); + } + SetProperty(SUBJECT, array); + } + + /** + * Adds a single author. + * @param author + */ + public void AddAuthor(String author) { + XmpArray array = new XmpArray(XmpArray.ORDERED); + array.Add(author); + SetProperty(CREATOR, array); + } + + /** + * Adds an array of authors. + * @param author + */ + public void AddAuthor(String[] author) { + XmpArray array = new XmpArray(XmpArray.ORDERED); + for (int i = 0; i < author.Length; i++) { + array.Add(author[i]); + } + SetProperty(CREATOR, array); + } + + /** + * Adds a single publisher. + * @param publisher + */ + public void AddPublisher(String publisher) { + XmpArray array = new XmpArray(XmpArray.ORDERED); + array.Add(publisher); + SetProperty(PUBLISHER, array); + } + + /** + * Adds an array of publishers. + * @param publisher + */ + public void AddPublisher(String[] publisher) { + XmpArray array = new XmpArray(XmpArray.ORDERED); + for (int i = 0; i < publisher.Length; i++) { + array.Add(publisher[i]); + } + SetProperty(PUBLISHER, array); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/EncodingNoPreamble.cs b/iTechSharp/iTextSharp/text/xml/xmp/EncodingNoPreamble.cs new file mode 100644 index 0000000..3aa75d8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/EncodingNoPreamble.cs @@ -0,0 +1,163 @@ +using System; +using System.Text; +/* + * $Id: EncodingNoPreamble.cs,v 1.2 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2007 Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + ///

      + /// A wrapper for an Encoding to suppress the preamble. + /// + public class EncodingNoPreamble : Encoding { + + private Encoding encoding; + private static byte[] emptyPreamble = new byte[0]; + + public EncodingNoPreamble(Encoding encoding) { + this.encoding = encoding; + } + + public override int GetByteCount(char[] chars, int index, int count) { + return encoding.GetByteCount(chars, index, count); + } + + public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { + return encoding.GetBytes(chars, charIndex, charCount, bytes, byteIndex); + } + + public override int GetCharCount(byte[] bytes, int index, int count) { + return encoding.GetCharCount(bytes, index, count); + } + + public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { + return encoding.GetChars(bytes, byteIndex, byteCount, chars, charIndex); + } + + public override int GetMaxByteCount(int charCount) { + return encoding.GetMaxByteCount(charCount); + } + + public override int GetMaxCharCount(int byteCount) { + return encoding.GetMaxCharCount(byteCount); + } + + public override string BodyName { + get { + return encoding.BodyName; + } + } + + public override int CodePage { + get { + return encoding.CodePage; + } + } + + public override string EncodingName { + get { + return encoding.EncodingName; + } + } + + public override string HeaderName { + get { + return encoding.HeaderName; + } + } + + public override bool IsBrowserDisplay { + get { + return encoding.IsBrowserDisplay; + } + } + + public override bool IsBrowserSave { + get { + return encoding.IsBrowserSave; + } + } + + public override bool IsMailNewsDisplay { + get { + return encoding.IsMailNewsDisplay; + } + } + + public override bool IsMailNewsSave { + get { + return encoding.IsMailNewsSave; + } + } + + public override string WebName { + get { + return encoding.WebName; + } + } + + public override int WindowsCodePage { + get { + return encoding.WindowsCodePage; + } + } + + public override Decoder GetDecoder() { + return encoding.GetDecoder (); + } + + public override Encoder GetEncoder() { + return encoding.GetEncoder (); + } + + public override byte[] GetPreamble() { + return emptyPreamble; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/LangAlt.cs b/iTechSharp/iTextSharp/text/xml/xmp/LangAlt.cs new file mode 100644 index 0000000..d312c1f --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/LangAlt.cs @@ -0,0 +1,100 @@ +using System; +using System.Text; +using System.util; + +/* + * $Id: LangAlt.cs,v 1.3 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2007 by Armin Haberling + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + public class LangAlt : Properties { + + /** Key for the default language. */ + public const String DEFAULT = "x-default"; + + /** Creates a Properties object that stores languages for use in an XmpSchema */ + public LangAlt(String defaultValue) { + AddLanguage(DEFAULT, defaultValue); + } + + /** Creates a Properties object that stores languages for use in an XmpSchema */ + public LangAlt() { + } + + /** + * Add a language. + */ + public void AddLanguage(String language, String value) { + this[language] = XmpSchema.Escape(value); + } + + /** + * Process a property. + */ + protected internal void Process(StringBuilder buf, String lang) { + buf.Append(""); + buf.Append(this[lang]); + buf.Append(""); + } + + /** + * Creates a String that can be used in an XmpSchema. + */ + public override String ToString() { + StringBuilder sb = new StringBuilder(); + sb.Append(""); + foreach (String s in this.Keys) + Process(sb, s); + sb.Append(""); + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/PdfA1Schema.cs b/iTechSharp/iTextSharp/text/xml/xmp/PdfA1Schema.cs new file mode 100644 index 0000000..b36429d --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/PdfA1Schema.cs @@ -0,0 +1,92 @@ +using System; + +/* + * $Id: PdfA1Schema.cs,v 1.3 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2007 Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * An implementation of an XmpSchema. + */ + public class PdfA1Schema : XmpSchema { + + /** default namespace identifier*/ + public const String DEFAULT_XPATH_ID = "pdfaid"; + /** default namespace uri*/ + public const String DEFAULT_XPATH_URI = "http://www.aiim.org/pdfa/ns/id/"; + /** Part, always 1. */ + public const String PART = "pdfaid:part"; + /** Conformance, A or B. */ + public const String CONFORMANCE = "pdfaid:conformance"; + + /** + * @throws IOException + */ + public PdfA1Schema() : base("xmlns:" + DEFAULT_XPATH_ID + "=\"" + DEFAULT_XPATH_URI + "\"") { + AddPart("1"); + } + + /** + * Adds part. + * @param part + */ + public void AddPart(String part) { + this[PART] = part; + } + + /** + * Adds the conformance. + * @param conformance + */ + public void AddConformance(String conformance) { + this[CONFORMANCE] = conformance; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/PdfSchema.cs b/iTechSharp/iTextSharp/text/xml/xmp/PdfSchema.cs new file mode 100644 index 0000000..fc8c877 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/PdfSchema.cs @@ -0,0 +1,104 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfSchema.cs,v 1.3 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * An implementation of an XmpSchema. + */ + public class PdfSchema : XmpSchema { + + /** default namespace identifier*/ + public const String DEFAULT_XPATH_ID = "pdf"; + /** default namespace uri*/ + public const String DEFAULT_XPATH_URI = "http://ns.adobe.com/pdf/1.3/"; + /** Keywords. */ + public const String KEYWORDS = "pdf:Keywords"; + /** The PDF file version (for example: 1.0, 1.3, and so on). */ + public const String VERSION = "pdf:PDFVersion"; + /** The Producer. */ + public const String PRODUCER = "pdf:Producer"; + + /** + * @throws IOException + */ + public PdfSchema() : base("xmlns:" + DEFAULT_XPATH_ID + "=\"" + DEFAULT_XPATH_URI + "\"") { + AddProducer(Document.Version); + } + + /** + * Adds keywords. + * @param keywords + */ + public void AddKeywords(String keywords) { + this[KEYWORDS] = keywords; + } + + /** + * Adds the producer. + * @param producer + */ + public void AddProducer(String producer) { + this[PRODUCER] = producer; + } + + /** + * Adds the version. + * @param version + */ + public void AddVersion(String version) { + this[VERSION] = version; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/XmpArray.cs b/iTechSharp/iTextSharp/text/xml/xmp/XmpArray.cs new file mode 100644 index 0000000..a9c9fb8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/XmpArray.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections; +using System.Text; +/* + * $Id: XmpArray.cs,v 1.3 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * StringBuilder to construct an XMP array. + */ + public class XmpArray : ArrayList { + + /** An array that is unordered. */ + public const String UNORDERED = "rdf:Bag"; + /** An array that is ordered. */ + public const String ORDERED = "rdf:Seq"; + /** An array with alternatives. */ + public const String ALTERNATIVE = "rdf:Alt"; + + /** the type of array. */ + protected String type; + + /** + * Creates an XmpArray. + * @param type the type of array: UNORDERED, ORDERED or ALTERNATIVE. + */ + public XmpArray(String type) { + this.type = type; + } + + /** + * Returns the String representation of the XmpArray. + * @return a String representation + */ + public override String ToString() { + StringBuilder buf = new StringBuilder("<"); + buf.Append(type); + buf.Append('>'); + foreach (String s in this) { + buf.Append(""); + buf.Append(XmpSchema.Escape(s)); + buf.Append(""); + } + buf.Append("'); + return buf.ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/XmpBasicSchema.cs b/iTechSharp/iTextSharp/text/xml/xmp/XmpBasicSchema.cs new file mode 100644 index 0000000..e33bc3e --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/XmpBasicSchema.cs @@ -0,0 +1,139 @@ +using System; +/* + * $Id: XmpBasicSchema.cs,v 1.4 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * An implementation of an XmpSchema. + */ + public class XmpBasicSchema : XmpSchema { + + /** default namespace identifier*/ + public const String DEFAULT_XPATH_ID = "xmp"; + /** default namespace uri*/ + public const String DEFAULT_XPATH_URI = "http://ns.adobe.com/xap/1.0/"; + /** An unordered array specifying properties that were edited outside the authoring application. Each item should contain a single namespace and XPath separated by one ASCII space (U+0020). */ + public const String ADVISORY = "xmp:Advisory"; + /** The base URL for relative URLs in the document content. If this document contains Internet links, and those links are relative, they are relative to this base URL. This property provides a standard way for embedded relative URLs to be interpreted by tools. Web authoring tools should set the value based on their notion of where URLs will be interpreted. */ + public const String BASEURL = "xmp:BaseURL"; + /** The date and time the resource was originally created. */ + public const String CREATEDATE = "xmp:CreateDate"; + /** The name of the first known tool used to create the resource. If history is present in the metadata, this value should be equivalent to that of xmpMM:History’s softwareAgent property. */ + public const String CREATORTOOL = "xmp:CreatorTool"; + /** An unordered array of text strings that unambiguously identify the resource within a given context. */ + public const String IDENTIFIER = "xmp:Identifier"; + /** The date and time that any metadata for this resource was last changed. */ + public const String METADATADATE = "xmp:MetadataDate"; + /** The date and time the resource was last modified. */ + public const String MODIFYDATE = "xmp:ModifyDate"; + /** A short informal name for the resource. */ + public const String NICKNAME = "xmp:Nickname"; + /** An alternative array of thumbnail images for a file, which can differ in characteristics such as size or image encoding. */ + public const String THUMBNAILS = "xmp:Thumbnails"; + + /** + * @param shorthand + * @throws IOException + */ + public XmpBasicSchema() : base("xmlns:" + DEFAULT_XPATH_ID + "=\"" + DEFAULT_XPATH_URI + "\"") { + } + + /** + * Adds the creatortool. + * @param creator + */ + public void AddCreatorTool(String creator) { + this[CREATORTOOL] = creator; + } + + /** + * Adds the creation date. + * @param date + */ + public void AddCreateDate(String date) { + this[CREATEDATE] = date; + } + + /** + * Adds the modification date. + * @param date + */ + public void AddModDate(String date) { + this[MODIFYDATE] = date; + } + + /** + * Adds the meta data date. + * @param date + */ + public void AddMetaDataDate(String date) { + this[METADATADATE] = date; + } + + /** Adds the identifier. + * @param id + */ + public void AddIdentifiers(String[] id) { + XmpArray array = new XmpArray(XmpArray.UNORDERED); + for (int i = 0; i < id.Length; i++) { + array.Add(id[i]); + } + SetProperty(IDENTIFIER, array); + } + + /** Adds the nickname. + * @param name + */ + public void AddNickname(String name) { + this[NICKNAME] = name; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/XmpMMSchema.cs b/iTechSharp/iTextSharp/text/xml/xmp/XmpMMSchema.cs new file mode 100644 index 0000000..c48c3db --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/XmpMMSchema.cs @@ -0,0 +1,94 @@ +using System; +/* + * $Id: XmpMMSchema.cs,v 1.3 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * An implementation of an XmpSchema. + */ + public class XmpMMSchema : XmpSchema { + + /** default namespace identifier*/ + public const String DEFAULT_XPATH_ID = "xmpMM"; + /** default namespace uri*/ + public const String DEFAULT_XPATH_URI = "http://ns.adobe.com/xap/1.0/mm/"; + /** A reference to the original document from which this one is derived. It is a minimal reference; missing components can be assumed to be unchanged. For example, a new version might only need to specify the instance ID and version number of the previous version, or a rendition might only need to specify the instance ID and rendition class of the original. */ + public const String DERIVEDFROM = "xmpMM:DerivedFrom"; + /** The common identifier for all versions and renditions of a document. */ + public const String DOCUMENTID = "xmpMM:DocumentID"; + /** An ordered array of high-level user actions that resulted in this resource. It is intended to give human readers a general indication of the steps taken to make the changes from the previous version to this one. The list should be at an abstract level; it is not intended to be an exhaustive keystroke or other detailed history. */ + public const String HISTORY = "xmpMM:History"; + /** A reference to the document as it was prior to becoming managed. It is set when a managed document is introduced to an asset management system that does not currently own it. It may or may not include references to different management systems. */ + public const String MANAGEDFROM = "xmpMM:ManagedFrom"; + /** The name of the asset management system that manages this resource. */ + public const String MANAGER = "xmpMM:Manager"; + /** A URI identifying the managed resource to the asset management system; the presence of this property is the formal indication that this resource is managed. The form and content of this URI is private to the asset management system. */ + public const String MANAGETO = "xmpMM:ManageTo"; + /** A URI that can be used to access information about the managed resource through a web browser. It might require a custom browser plugin. */ + public const String MANAGEUI = "xmpMM:ManageUI"; + /** Specifies a particular variant of the asset management system. The format of this property is private to the specific asset management system. */ + public const String MANAGERVARIANT = "xmpMM:ManagerVariant"; + /** The rendition class name for this resource.*/ + public const String RENDITIONCLASS = "xmpMM:RenditionClass"; + /** Can be used to provide additional rendition parameters that are too complex or verbose to encode in xmpMM: RenditionClass. */ + public const String RENDITIONPARAMS = "xmpMM:RenditionParams"; + /** The document version identifier for this resource. */ + public const String VERSIONID = "xmpMM:VersionID"; + /** The version history associated with this resource.*/ + public const String VERSIONS = "xmpMM:Versions"; + + /** + * @throws IOException + */ + public XmpMMSchema() : base("xmlns:" + DEFAULT_XPATH_ID + "=\"" + DEFAULT_XPATH_URI + "\"") { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/XmpSchema.cs b/iTechSharp/iTextSharp/text/xml/xmp/XmpSchema.cs new file mode 100644 index 0000000..df84d76 --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/XmpSchema.cs @@ -0,0 +1,165 @@ +using System; +using System.Text; +using System.util; +/* + * $Id: XmpSchema.cs,v 1.5 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * Abstract superclass of the XmpSchemas supported by iText. + */ + public abstract class XmpSchema : Properties { + /** the namesspace */ + protected String xmlns; + + /** Constructs an XMP schema. + * @param xmlns + */ + public XmpSchema(String xmlns) : base() { + this.xmlns = xmlns; + } + /** + * The String representation of the contents. + * @return a String representation. + */ + public override String ToString() { + StringBuilder buf = new StringBuilder(); + foreach (object key in Keys) { + Process(buf, key); + } + return buf.ToString(); + } + /** + * Processes a property + * @param buf + * @param p + */ + protected void Process(StringBuilder buf, Object p) { + buf.Append('<'); + buf.Append(p); + buf.Append('>'); + buf.Append(this[p.ToString()]); + buf.Append("'); + } + + /** + * @return Returns the xmlns. + */ + public String Xmlns { + get { + return xmlns; + } + } + + /** + * @param key + * @param value + * @return the previous property (null if there wasn't one) + */ + public void AddProperty(String key, String value) { + this[key] = value; + } + + public override string this[string key] { + set { + base[key] = Escape(value); + } + } + + public void SetProperty(string key, XmpArray value) { + base[key] = value.ToString(); + } + + /** + * @see java.util.Properties#setProperty(java.lang.String, java.lang.String) + * + * @param key + * @param value + * @return the previous property (null if there wasn't one) + */ + public void SetProperty(String key, LangAlt value) { + base[key] = value.ToString(); + } + + /** + * @param content + * @return + */ + public static String Escape(String content) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < content.Length; i++) { + switch (content[i]) { + case '<': + buf.Append("<"); + break; + case '>': + buf.Append(">"); + break; + case '\'': + buf.Append("'"); + break; + case '\"': + buf.Append("""); + break; + case '&': + buf.Append("&"); + break; + default: + buf.Append(content[i]); + break; + } + } + return buf.ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/xml/xmp/XmpWriter.cs b/iTechSharp/iTextSharp/text/xml/xmp/XmpWriter.cs new file mode 100644 index 0000000..b48797c --- /dev/null +++ b/iTechSharp/iTextSharp/text/xml/xmp/XmpWriter.cs @@ -0,0 +1,276 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.pdf; +using iTextSharp.text.xml.simpleparser; +/* + * $Id: XmpWriter.cs,v 1.10 2008/05/13 11:26:16 psoares33 Exp $ + * + * + * Copyright 2005 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.xml.xmp { + + /** + * With this class you can create an Xmp Stream that can be used for adding + * Metadata to a PDF Dictionary. Remark that this class doesn't cover the + * complete XMP specification. + */ + public class XmpWriter { + + /** A possible charset for the XMP. */ + public const String UTF8 = "UTF-8"; + /** A possible charset for the XMP. */ + public const String UTF16 = "UTF-16"; + /** A possible charset for the XMP. */ + public const String UTF16BE = "UTF-16BE"; + /** A possible charset for the XMP. */ + public const String UTF16LE = "UTF-16LE"; + + /** String used to fill the extra space. */ + public const String EXTRASPACE = " \n"; + + /** You can add some extra space in the XMP packet; 1 unit in this variable represents 100 spaces and a newline. */ + protected int extraSpace; + + /** The writer to which you can write bytes for the XMP stream. */ + protected StreamWriter writer; + + /** The about string that goes into the rdf:Description tags. */ + protected String about; + + /** The end attribute. */ + protected char end = 'w'; + + /** + * Creates an XmpWriter. + * @param os + * @param utfEncoding + * @param extraSpace + * @throws IOException + */ + public XmpWriter(Stream os, string utfEncoding, int extraSpace) { + this.extraSpace = extraSpace; + writer = new StreamWriter(os, new EncodingNoPreamble(IanaEncodings.GetEncodingEncoding(utfEncoding))); + writer.Write("\n"); + writer.Write("\n"); + writer.Write("\n"); + about = ""; + } + + /** + * Creates an XmpWriter. + * @param os + * @throws IOException + */ + public XmpWriter(Stream os) : this(os, UTF8, 20) { + } + + /** Sets the XMP to read-only */ + public void SetReadOnly() { + end = 'r'; + } + + /** + * @param about The about to set. + */ + public String About { + set { + this.about = value; + } + } + + /** + * Adds an rdf:Description. + * @param xmlns + * @param content + * @throws IOException + */ + public void AddRdfDescription(String xmlns, String content) { + writer.Write(""); + writer.Write(content); + writer.Write("\n"); + } + + /** + * Adds an rdf:Description. + * @param s + * @throws IOException + */ + public void AddRdfDescription(XmpSchema s) { + writer.Write(""); + writer.Write(s.ToString()); + writer.Write("\n"); + } + + /** + * Flushes and closes the XmpWriter. + * @throws IOException + */ + public void Close() { + writer.Write(""); + writer.Write("\n"); + for (int i = 0; i < extraSpace; i++) { + writer.Write(EXTRASPACE); + } + writer.Write(""); + writer.Flush(); + writer.Close(); + } + + /** + * @param os + * @param info + * @throws IOException + */ + public XmpWriter(Stream os, PdfDictionary info, int PdfXConformance) : this(os) { + if (info != null) { + DublinCoreSchema dc = new DublinCoreSchema(); + PdfSchema p = new PdfSchema(); + XmpBasicSchema basic = new XmpBasicSchema(); + PdfObject obj; + foreach (PdfName key in info.Keys) { + obj = info.Get(key); + if (obj == null) + continue; + if (PdfName.TITLE.Equals(key)) { + dc.AddTitle(((PdfString)obj).ToUnicodeString()); + } + if (PdfName.AUTHOR.Equals(key)) { + dc.AddAuthor(((PdfString)obj).ToUnicodeString()); + } + if (PdfName.SUBJECT.Equals(key)) { + dc.AddSubject(((PdfString)obj).ToUnicodeString()); + dc.AddDescription(((PdfString)obj).ToUnicodeString()); + } + if (PdfName.KEYWORDS.Equals(key)) { + p.AddKeywords(((PdfString)obj).ToUnicodeString()); + } + if (PdfName.CREATOR.Equals(key)) { + basic.AddCreatorTool(((PdfString)obj).ToUnicodeString()); + } + if (PdfName.PRODUCER.Equals(key)) { + p.AddProducer(((PdfString)obj).ToUnicodeString()); + } + if (PdfName.CREATIONDATE.Equals(key)) { + basic.AddCreateDate(((PdfDate)obj).GetW3CDate()); + } + if (PdfName.MODDATE.Equals(key)) { + basic.AddModDate(((PdfDate)obj).GetW3CDate()); + } + } + if (dc.Count > 0) AddRdfDescription(dc); + if (p.Count > 0) AddRdfDescription(p); + if (basic.Count > 0) AddRdfDescription(basic); + if (PdfXConformance == PdfWriter.PDFA1A || PdfXConformance == PdfWriter.PDFA1B) { + PdfA1Schema a1 = new PdfA1Schema(); + if (PdfXConformance == PdfWriter.PDFA1A) + a1.AddConformance("A"); + else + a1.AddConformance("B"); + AddRdfDescription(a1); + } + } + } + + /** + * @param os + * @param info + * @throws IOException + */ + public XmpWriter(Stream os, Hashtable info) : this(os) { + if (info != null) { + DublinCoreSchema dc = new DublinCoreSchema(); + PdfSchema p = new PdfSchema(); + XmpBasicSchema basic = new XmpBasicSchema(); + String value; + foreach (DictionaryEntry entry in info) { + String key = (String)entry.Key; + value = (String)entry.Value; + if (value == null) + continue; + if ("Title".Equals(key)) { + dc.AddTitle(value); + } + if ("Author".Equals(key)) { + dc.AddAuthor(value); + } + if ("Subject".Equals(key)) { + dc.AddSubject(value); + dc.AddDescription(value); + } + if ("Keywords".Equals(key)) { + p.AddKeywords(value); + } + if ("Creator".Equals(key)) { + basic.AddCreatorTool(value); + } + if ("Producer".Equals(key)) { + p.AddProducer(value); + } + if ("CreationDate".Equals(key)) { + basic.AddCreateDate(PdfDate.GetW3CDate(value)); + } + if ("ModDate".Equals(key)) { + basic.AddModDate(PdfDate.GetW3CDate(value)); + } + } + if (dc.Count > 0) AddRdfDescription(dc); + if (p.Count > 0) AddRdfDescription(p); + if (basic.Count > 0) AddRdfDescription(basic); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/itextsharp.csproj b/iTechSharp/itextsharp.csproj new file mode 100644 index 0000000..519fc20 --- /dev/null +++ b/iTechSharp/itextsharp.csproj @@ -0,0 +1,6789 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iTechSharp/itextsharp.dll b/iTechSharp/itextsharp.dll new file mode 100644 index 0000000..30cee99 Binary files /dev/null and b/iTechSharp/itextsharp.dll differ diff --git a/iTechSharp/itextsharp.sln b/iTechSharp/itextsharp.sln new file mode 100644 index 0000000..45be374 --- /dev/null +++ b/iTechSharp/itextsharp.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "itextsharp", "itextsharp.csproj", "{84C4FDD9-3ED7-453B-B9DA-B3ED52CB071C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {84C4FDD9-3ED7-453B-B9DA-B3ED52CB071C}.Debug.ActiveCfg = Debug|.NET + {84C4FDD9-3ED7-453B-B9DA-B3ED52CB071C}.Debug.Build.0 = Debug|.NET + {84C4FDD9-3ED7-453B-B9DA-B3ED52CB071C}.Release.ActiveCfg = Release|.NET + {84C4FDD9-3ED7-453B-B9DA-B3ED52CB071C}.Release.Build.0 = Release|.NET + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/iTechSharp/itextsharp.snk b/iTechSharp/itextsharp.snk new file mode 100644 index 0000000..8bc63ac Binary files /dev/null and b/iTechSharp/itextsharp.snk differ diff --git a/iTechSharp/srcbc/asn1/ASN1Generator.cs b/iTechSharp/srcbc/asn1/ASN1Generator.cs new file mode 100644 index 0000000..e560517 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1Generator.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public abstract class Asn1Generator + { + private Stream _out; + + protected Asn1Generator( + Stream outStream) + { + _out = outStream; + } + + protected Stream Out + { + get { return _out; } + } + + public abstract void AddObject(Asn1Encodable obj); + + public abstract Stream GetRawOutputStream(); + + public abstract void Close(); + } +} diff --git a/iTechSharp/srcbc/asn1/ASN1ObjectParser.cs b/iTechSharp/srcbc/asn1/ASN1ObjectParser.cs new file mode 100644 index 0000000..4fd72bc --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1ObjectParser.cs @@ -0,0 +1,10 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + [Obsolete("Will be removed")] + public class Asn1ObjectParser + { + } +} diff --git a/iTechSharp/srcbc/asn1/ASN1OctetStringParser.cs b/iTechSharp/srcbc/asn1/ASN1OctetStringParser.cs new file mode 100644 index 0000000..5815aa4 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1OctetStringParser.cs @@ -0,0 +1,10 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public interface Asn1OctetStringParser + : IAsn1Convertible + { + Stream GetOctetStream(); + } +} diff --git a/iTechSharp/srcbc/asn1/ASN1SequenceParser.cs b/iTechSharp/srcbc/asn1/ASN1SequenceParser.cs new file mode 100644 index 0000000..9e88ac7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1SequenceParser.cs @@ -0,0 +1,8 @@ +namespace Org.BouncyCastle.Asn1 +{ + public interface Asn1SequenceParser + : IAsn1Convertible + { + IAsn1Convertible ReadObject(); + } +} diff --git a/iTechSharp/srcbc/asn1/ASN1SetParser.cs b/iTechSharp/srcbc/asn1/ASN1SetParser.cs new file mode 100644 index 0000000..d1b9c64 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1SetParser.cs @@ -0,0 +1,8 @@ +namespace Org.BouncyCastle.Asn1 +{ + public interface Asn1SetParser + : IAsn1Convertible + { + IAsn1Convertible ReadObject(); + } +} diff --git a/iTechSharp/srcbc/asn1/ASN1StreamParser.cs b/iTechSharp/srcbc/asn1/ASN1StreamParser.cs new file mode 100644 index 0000000..cd020c9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1StreamParser.cs @@ -0,0 +1,154 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class Asn1StreamParser + { + private readonly Stream _in; + private readonly int _limit; + + public Asn1StreamParser( + Stream inStream) + : this(inStream, int.MaxValue) + { + } + + public Asn1StreamParser( + Stream inStream, + int limit) + { + if (!inStream.CanRead) + throw new ArgumentException("Expected stream to be readable", "inStream"); + + this._in = inStream; + this._limit = limit; + } + + public Asn1StreamParser( + byte[] encoding) + : this(new MemoryStream(encoding, false), encoding.Length) + { + } + + public virtual IAsn1Convertible ReadObject() + { + int tag = _in.ReadByte(); + if (tag == -1) + return null; + + // turn of looking for "00" while we resolve the tag + Set00Check(false); + + // + // calculate tag number + // + int tagNo = 0; + if ((tag & Asn1Tags.Tagged) != 0 || (tag & Asn1Tags.Application) != 0) + { + tagNo = Asn1InputStream.ReadTagNumber(_in, tag); + } + + bool isConstructed = (tag & Asn1Tags.Constructed) != 0; + int baseTagNo = tag & ~Asn1Tags.Constructed; + + // + // calculate length + // + int length = Asn1InputStream.ReadLength(_in, _limit); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + throw new IOException("indefinite length primitive encoding encountered"); + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in); + + if ((tag & Asn1Tags.Tagged) != 0) + { + return new BerTaggedObjectParser(tag, tagNo, indIn); + } + + Asn1StreamParser sp = new Asn1StreamParser(indIn); + + // TODO There are other tags that may be constructed (e.g. BitString) + switch (baseTagNo) + { + case Asn1Tags.OctetString: + return new BerOctetStringParser(sp); + case Asn1Tags.Sequence: + return new BerSequenceParser(sp); + case Asn1Tags.Set: + return new BerSetParser(sp); + default: + throw new IOException("unknown BER object encountered"); + } + } + else + { + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); + + if ((tag & Asn1Tags.Application) != 0) + { + return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray()); + } + + if ((tag & Asn1Tags.Tagged) != 0) + { + return new BerTaggedObjectParser(tag, tagNo, defIn); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BitString) + switch (baseTagNo) + { + case Asn1Tags.OctetString: + // + // yes, people actually do this... + // + return new BerOctetStringParser(new Asn1StreamParser(defIn)); + case Asn1Tags.Sequence: + return new DerSequenceParser(new Asn1StreamParser(defIn)); + case Asn1Tags.Set: + return new DerSetParser(new Asn1StreamParser(defIn)); + default: + // TODO Add DerUnknownTagParser class? + return new DerUnknownTag(tag, defIn.ToArray()); + } + } + + // Some primitive encodings can be handled by parsers too... + switch (baseTagNo) + { + case Asn1Tags.OctetString: + return new DerOctetStringParser(defIn); + } + + return Asn1InputStream.CreatePrimitiveDerObject(tag, defIn.ToArray()); + } + } + + private void Set00Check( + bool enabled) + { + if (_in is IndefiniteLengthInputStream) + { + ((IndefiniteLengthInputStream) _in).SetEofOn00(enabled); + } + } + + internal Asn1EncodableVector ReadVector() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + IAsn1Convertible obj; + while ((obj = ReadObject()) != null) + { + v.Add(obj.ToAsn1Object()); + } + + return v; + } + } +} diff --git a/iTechSharp/srcbc/asn1/ASN1TaggedObjectParser.cs b/iTechSharp/srcbc/asn1/ASN1TaggedObjectParser.cs new file mode 100644 index 0000000..32327a2 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ASN1TaggedObjectParser.cs @@ -0,0 +1,10 @@ +namespace Org.BouncyCastle.Asn1 +{ + public interface Asn1TaggedObjectParser + : IAsn1Convertible + { + int TagNo { get; } + + IAsn1Convertible GetObjectParser(int tag, bool isExplicit); + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1Encodable.cs b/iTechSharp/srcbc/asn1/Asn1Encodable.cs new file mode 100644 index 0000000..e3dd9a1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1Encodable.cs @@ -0,0 +1,78 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public abstract class Asn1Encodable + : IAsn1Convertible + { + public const string Der = "DER"; + public const string Ber = "BER"; + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + Asn1OutputStream aOut = new Asn1OutputStream(bOut); + + aOut.WriteObject(this); + + return bOut.ToArray(); + } + + public byte[] GetEncoded( + string encoding) + { + if (encoding.Equals(Der)) + { + MemoryStream bOut = new MemoryStream(); + DerOutputStream dOut = new DerOutputStream(bOut); + + dOut.WriteObject(this); + + return bOut.ToArray(); + } + + return GetEncoded(); + } + + /** + * Return the DER encoding of the object, null if the DER encoding can not be made. + * + * @return a DER byte array, null otherwise. + */ + public byte[] GetDerEncoded() + { + try + { + return GetEncoded(Der); + } + catch (IOException) + { + return null; + } + } + + public sealed override int GetHashCode() + { + return ToAsn1Object().CallAsn1GetHashCode(); + } + + public sealed override bool Equals( + object obj) + { + if (obj == this) + return true; + + IAsn1Convertible other = obj as IAsn1Convertible; + + if (other == null) + return false; + + Asn1Object o1 = ToAsn1Object(); + Asn1Object o2 = other.ToAsn1Object(); + + return o1 == o2 || o1.CallAsn1Equals(o2); + } + + public abstract Asn1Object ToAsn1Object(); + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1EncodableVector.cs b/iTechSharp/srcbc/asn1/Asn1EncodableVector.cs new file mode 100644 index 0000000..bd3390d --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1EncodableVector.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1 +{ + public class Asn1EncodableVector + : IEnumerable + { + private ArrayList v = new ArrayList(); + + public static Asn1EncodableVector FromEnumerable( + IEnumerable e) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + foreach (Asn1Encodable obj in e) + { + v.Add(obj); + } + return v; + } + +// public Asn1EncodableVector() +// { +// } + + public Asn1EncodableVector( + params Asn1Encodable[] v) + { + Add(v); + } + +// public void Add( +// Asn1Encodable obj) +// { +// v.Add(obj); +// } + + public void Add( + params Asn1Encodable[] objs) + { + foreach (Asn1Encodable obj in objs) + { + v.Add(obj); + } + } + + public Asn1Encodable this[ + int index] + { + get { return (Asn1Encodable) v[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public Asn1Encodable Get( + int index) + { + return this[index]; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return v.Count; } + } + + public int Count + { + get { return v.Count; } + } + + public IEnumerator GetEnumerator() + { + return v.GetEnumerator(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1InputStream.cs b/iTechSharp/srcbc/asn1/Asn1InputStream.cs new file mode 100644 index 0000000..16aa3c0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1InputStream.cs @@ -0,0 +1,307 @@ +using System; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * a general purpose ASN.1 decoder - note: this class differs from the + * others in that it returns null after it has read the last object in + * the stream. If an ASN.1 Null is encountered a Der/BER Null object is + * returned. + */ + public class Asn1InputStream + : FilterStream + { + private readonly int limit; + + public Asn1InputStream( + Stream inputStream) + : this(inputStream, int.MaxValue) + { + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit. + * + * @param input stream containing ASN.1 encoded data. + * @param limit maximum size of a DER encoded object. + */ + public Asn1InputStream( + Stream inputStream, + int limit) + : base(inputStream) + { + this.limit = limit; + } + + /** + * Create an ASN1InputStream based on the input byte array. The length of DER objects in + * the stream is automatically limited to the length of the input array. + * + * @param input array containing ASN.1 encoded data. + */ + public Asn1InputStream( + byte[] input) + : this(new MemoryStream(input, false), input.Length) + { + } + + internal Asn1EncodableVector BuildEncodableVector() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + Asn1Object o; + while ((o = ReadObject()) != null) + { + v.Add(o); + } + + return v; + } + + internal virtual Asn1EncodableVector BuildDerEncodableVector( + DefiniteLengthInputStream dIn) + { + return new Asn1InputStream(dIn).BuildEncodableVector(); + } + + internal virtual DerSequence CreateDerSequence( + DefiniteLengthInputStream dIn) + { + return DerSequence.FromVector(BuildDerEncodableVector(dIn)); + } + + internal virtual DerSet CreateDerSet( + DefiniteLengthInputStream dIn) + { + return DerSet.FromVector(BuildDerEncodableVector(dIn), false); + } + + public Asn1Object ReadObject() + { + int tag = ReadByte(); + if (tag <= 0) + { + if (tag == 0) + throw new IOException("unexpected end-of-contents marker"); + + return null; + } + + // + // calculate tag number + // + int tagNo = 0; + if ((tag & Asn1Tags.Tagged) != 0 || (tag & Asn1Tags.Application) != 0) + { + tagNo = ReadTagNumber(this, tag); + } + + bool isConstructed = (tag & Asn1Tags.Constructed) != 0; + int baseTagNo = tag & ~Asn1Tags.Constructed; + + // + // calculate length + // + int length = ReadLength(this, limit); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + throw new IOException("indefinite length primitive encoding encountered"); + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this); + + if ((tag & Asn1Tags.Tagged) != 0) + { + return new BerTaggedObjectParser(tag, tagNo, indIn).ToAsn1Object(); + } + + Asn1StreamParser sp = new Asn1StreamParser(indIn); + + // TODO There are other tags that may be constructed (e.g. BitString) + switch (baseTagNo) + { + case Asn1Tags.OctetString: + return new BerOctetStringParser(sp).ToAsn1Object(); + case Asn1Tags.Sequence: + return new BerSequenceParser(sp).ToAsn1Object(); + case Asn1Tags.Set: + return new BerSetParser(sp).ToAsn1Object(); + default: + throw new IOException("unknown BER object encountered"); + } + } + else + { + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length); + + if ((tag & Asn1Tags.Application) != 0) + { + return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray()); + } + + if ((tag & Asn1Tags.Tagged) != 0) + { + return new BerTaggedObjectParser(tag, tagNo, defIn).ToAsn1Object(); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BitString) + switch (baseTagNo) + { + case Asn1Tags.OctetString: + // + // yes, people actually do this... + // + return new BerOctetString(BuildDerEncodableVector(defIn)); + case Asn1Tags.Sequence: + return CreateDerSequence(defIn); + case Asn1Tags.Set: + return CreateDerSet(defIn); + default: + return new DerUnknownTag(tag, defIn.ToArray()); + } + } + + return CreatePrimitiveDerObject(tag, defIn.ToArray()); + } + } + + internal static int ReadTagNumber( + Stream s, + int tag) + { + int tagNo = tag & 0x1f; + + // + // with tagged object tag number is bottom 5 bits, or stored at the start of the content + // + if (tagNo == 0x1f) + { + tagNo = 0; + + int b = s.ReadByte(); + + // X.690-0207 8.1.2.4.2 + // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." + if ((b & 0x7f) == 0) // Note: -1 will pass + { + throw new IOException("corrupted stream - invalid high tag number found"); + } + + while ((b >= 0) && ((b & 0x80) != 0)) + { + tagNo |= (b & 0x7f); + tagNo <<= 7; + b = s.ReadByte(); + } + + if (b < 0) + throw new EndOfStreamException("EOF found inside tag value."); + + tagNo |= (b & 0x7f); + } + + return tagNo; + } + + internal static int ReadLength( + Stream s, + int limit) + { + int length = s.ReadByte(); + if (length < 0) + throw new EndOfStreamException("EOF found when length expected"); + + if (length == 0x80) + return -1; // indefinite-length encoding + + if (length > 127) + { + int size = length & 0x7f; + + if (size > 4) + throw new IOException("DER length more than 4 bytes"); + + length = 0; + for (int i = 0; i < size; i++) + { + int next = s.ReadByte(); + + if (next < 0) + throw new EndOfStreamException("EOF found reading length"); + + length = (length << 8) + next; + } + + if (length < 0) + throw new IOException("Corrupted stream - negative length found"); + + if (length >= limit) // after all we must have read at least 1 byte + throw new IOException("Corrupted stream - out of bounds length found"); + } + + return length; + } + + internal static Asn1Object CreatePrimitiveDerObject( + int tag, + byte[] bytes) + { + Debug.Assert((tag & (Asn1Tags.Application | Asn1Tags.Constructed | Asn1Tags.Tagged)) == 0); + + switch (tag) + { + case Asn1Tags.BitString: + { + int padBits = bytes[0]; + byte[] data = new byte[bytes.Length - 1]; + Array.Copy(bytes, 1, data, 0, bytes.Length - 1); + return new DerBitString(data, padBits); + } + case Asn1Tags.BmpString: + return new DerBmpString(bytes); + case Asn1Tags.Boolean: + return new DerBoolean(bytes); + case Asn1Tags.Enumerated: + return new DerEnumerated(bytes); + case Asn1Tags.GeneralizedTime: + return new DerGeneralizedTime(bytes); + case Asn1Tags.GeneralString: + return new DerGeneralString(bytes); + case Asn1Tags.IA5String: + return new DerIA5String(bytes); + case Asn1Tags.Integer: + return new DerInteger(bytes); + case Asn1Tags.Null: + return DerNull.Instance; // actual content is ignored (enforce 0 length?) + case Asn1Tags.NumericString: + return new DerNumericString(bytes); + case Asn1Tags.ObjectIdentifier: + return new DerObjectIdentifier(bytes); + case Asn1Tags.OctetString: + return new DerOctetString(bytes); + case Asn1Tags.PrintableString: + return new DerPrintableString(bytes); + case Asn1Tags.T61String: + return new DerT61String(bytes); + case Asn1Tags.UniversalString: + return new DerUniversalString(bytes); + case Asn1Tags.UtcTime: + return new DerUtcTime(bytes); + case Asn1Tags.Utf8String: + return new DerUtf8String(bytes); + case Asn1Tags.VisibleString: + return new DerVisibleString(bytes); + default: + return new DerUnknownTag(tag, bytes); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1Null.cs b/iTechSharp/srcbc/asn1/Asn1Null.cs new file mode 100644 index 0000000..d54019f --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1Null.cs @@ -0,0 +1,18 @@ +namespace Org.BouncyCastle.Asn1 +{ + /** + * A Null object. + */ + public abstract class Asn1Null + : Asn1Object + { + internal Asn1Null() + { + } + + public override string ToString() + { + return "NULL"; + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1Object.cs b/iTechSharp/srcbc/asn1/Asn1Object.cs new file mode 100644 index 0000000..9254f22 --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1Object.cs @@ -0,0 +1,48 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public abstract class Asn1Object + : Asn1Encodable + { + /// Create a base ASN.1 object from a byte array. + /// The byte array to parse. + /// The base ASN.1 object represented by the byte array. + /// If there is a problem parsing the data. + public static Asn1Object FromByteArray( + byte[] data) + { + return new Asn1InputStream(data).ReadObject(); + } + + /// Read a base ASN.1 object from a stream. + /// The stream to parse. + /// The base ASN.1 object represented by the byte array. + /// If there is a problem parsing the data. + public static Asn1Object FromStream( + Stream inStr) + { + return new Asn1InputStream(inStr).ReadObject(); + } + + public sealed override Asn1Object ToAsn1Object() + { + return this; + } + + internal abstract void Encode(DerOutputStream derOut); + + protected abstract bool Asn1Equals(Asn1Object asn1Object); + protected abstract int Asn1GetHashCode(); + + internal bool CallAsn1Equals(Asn1Object obj) + { + return Asn1Equals(obj); + } + + internal int CallAsn1GetHashCode() + { + return Asn1GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1OctetString.cs b/iTechSharp/srcbc/asn1/Asn1OctetString.cs new file mode 100644 index 0000000..39299fc --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1OctetString.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1 +{ + public abstract class Asn1OctetString + : Asn1Object, Asn1OctetStringParser + { + internal byte[] str; + + /** + * return an Octet string from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static Asn1OctetString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * return an Octet string from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static Asn1OctetString GetInstance( + object obj) + { + if (obj == null || obj is Asn1OctetString) + { + return (Asn1OctetString)obj; + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + if (obj is Asn1Sequence) + { + ArrayList v = new ArrayList(); + + foreach (object o in ((Asn1Sequence) obj)) + { + v.Add(o); + } + + return new BerOctetString(v); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * @param string the octets making up the octet string. + */ + internal Asn1OctetString( + byte[] str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + internal Asn1OctetString( + Asn1Encodable obj) + { + try + { + this.str = obj.GetDerEncoded(); + } + catch (IOException e) + { + throw new ArgumentException("Error processing object : " + e.ToString()); + } + } + + public Stream GetOctetStream() + { + return new MemoryStream(str, false); + } + + public Asn1OctetStringParser Parser + { + get { return this; } + } + + public virtual byte[] GetOctets() + { + return str; + } + + protected override int Asn1GetHashCode() + { + return Arrays.GetHashCode(GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerOctetString other = asn1Object as DerOctetString; + + if (other == null) + return false; + + return Arrays.AreEqual(GetOctets(), other.GetOctets()); + } + + public override string ToString() + { + byte[] hex = Hex.Encode(str); + return "#" + Encoding.ASCII.GetString(hex, 0, hex.Length); + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1OutputStream.cs b/iTechSharp/srcbc/asn1/Asn1OutputStream.cs new file mode 100644 index 0000000..39c8b1e --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1OutputStream.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class Asn1OutputStream + : DerOutputStream + { + public Asn1OutputStream(Stream os) : base(os) + { + } + + [Obsolete("Use version taking an Asn1Encodable arg instead")] + public override void WriteObject( + object obj) + { + if (obj == null) + { + WriteNull(); + } + else if (obj is Asn1Object) + { + ((Asn1Object)obj).Encode(this); + } + else if (obj is Asn1Encodable) + { + ((Asn1Encodable)obj).ToAsn1Object().Encode(this); + } + else + { + throw new IOException("object not Asn1Encodable"); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1Sequence.cs b/iTechSharp/srcbc/asn1/Asn1Sequence.cs new file mode 100644 index 0000000..a4dbbae --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1Sequence.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1 +{ + public abstract class Asn1Sequence + : Asn1Object, IEnumerable + { + private readonly ArrayList seq; + + /** + * return an Asn1Sequence from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static Asn1Sequence GetInstance( + object obj) + { + if (obj == null || obj is Asn1Sequence) + { + return (Asn1Sequence)obj; + } + + throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + /** + * Return an ASN1 sequence from a tagged object. There is a special + * case here, if an object appears to have been explicitly tagged on + * reading but we were expecting it to be implicitly tagged in the + * normal course of events it indicates that we lost the surrounding + * sequence - so we need to add it back (this will happen if the tagged + * object is a sequence that contains other sequences). If you are + * dealing with implicitly tagged sequences you really should + * be using this method. + * + * @param obj the tagged object. + * @param explicitly true if the object is meant to be explicitly tagged, + * false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static Asn1Sequence GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + Asn1Object inner = obj.GetObject(); + + if (explicitly) + { + if (!obj.IsExplicit()) + throw new ArgumentException("object implicit - explicit expected."); + + return (Asn1Sequence) inner; + } + + // + // constructed object which appears to be explicitly tagged + // when it should be implicit means we have to add the + // surrounding sequence. + // + if (obj.IsExplicit()) + { + if (obj is BerTaggedObject) + { + return new BerSequence(inner); + } + + return new DerSequence(inner); + } + + if (inner is Asn1Sequence) + { + return (Asn1Sequence) inner; + } + + throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + protected internal Asn1Sequence( + int capacity) + { + seq = new ArrayList(capacity); + } + + public virtual IEnumerator GetEnumerator() + { + return seq.GetEnumerator(); + } + + [Obsolete("Use GetEnumerator() instead")] + public IEnumerator GetObjects() + { + return GetEnumerator(); + } + + private class Asn1SequenceParserImpl + : Asn1SequenceParser + { + private readonly Asn1Sequence outer; + private readonly int max; + private int index; + + public Asn1SequenceParserImpl( + Asn1Sequence outer) + { + this.outer = outer; + this.max = outer.Count; + } + + public IAsn1Convertible ReadObject() + { + if (index == max) + return null; + + Asn1Encodable obj = outer[index++]; + + if (obj is Asn1Sequence) + return ((Asn1Sequence)obj).Parser; + + if (obj is Asn1Set) + return ((Asn1Set)obj).Parser; + + // NB: Asn1OctetString implements Asn1OctetStringParser directly +// if (obj is Asn1OctetString) +// return ((Asn1OctetString)obj).Parser; + + return obj; + } + + public Asn1Object ToAsn1Object() + { + return outer; + } + } + + public virtual Asn1SequenceParser Parser + { + get { return new Asn1SequenceParserImpl(this); } + } + + /** + * return the object at the sequence position indicated by index. + * + * @param index the sequence number (starting at zero) of the object + * @return the object at the sequence position indicated by index. + */ + public virtual Asn1Encodable this[int index] + { + get { return (Asn1Encodable) seq[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public Asn1Encodable GetObjectAt( + int index) + { + return this[index]; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return Count; } + } + + public virtual int Count + { + get { return seq.Count; } + } + + protected override int Asn1GetHashCode() + { + int hc = Count; + + foreach (object o in this) + { + hc *= 17; + if (o != null) + { + hc ^= o.GetHashCode(); + } + } + + return hc; + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + Asn1Sequence other = asn1Object as Asn1Sequence; + + if (other == null) + return false; + + if (Count != other.Count) + { + return false; + } + + IEnumerator s1 = GetEnumerator(); + IEnumerator s2 = other.GetEnumerator(); + + while (s1.MoveNext() && s2.MoveNext()) + { +// if (!Platform.Equals(s1.Current, s2.Current)) + Asn1Object o1 = ((Asn1Encodable) s1.Current).ToAsn1Object(); + + if (!o1.Equals(s2.Current)) + { + return false; + } + } + + return true; + } + + protected internal void AddObject( + Asn1Encodable obj) + { + seq.Add(obj); + } + + public override string ToString() + { + return CollectionUtilities.ToString(seq); + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1Set.cs b/iTechSharp/srcbc/asn1/Asn1Set.cs new file mode 100644 index 0000000..06d457e --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1Set.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1 +{ + abstract public class Asn1Set + : Asn1Object, IEnumerable + { + private readonly ArrayList _set; + + /** + * return an ASN1Set from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static Asn1Set GetInstance( + object obj) + { + if (obj == null || obj is Asn1Set) + { + return (Asn1Set)obj; + } + + throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + /** + * Return an ASN1 set from a tagged object. There is a special + * case here, if an object appears to have been explicitly tagged on + * reading but we were expecting it to be implicitly tagged in the + * normal course of events it indicates that we lost the surrounding + * set - so we need to add it back (this will happen if the tagged + * object is a sequence that contains other sequences). If you are + * dealing with implicitly tagged sets you really should + * be using this method. + * + * @param obj the tagged object. + * @param explicitly true if the object is meant to be explicitly tagged + * false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static Asn1Set GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + Asn1Object inner = obj.GetObject(); + + if (explicitly) + { + if (!obj.IsExplicit()) + throw new ArgumentException("object implicit - explicit expected."); + + return (Asn1Set) inner; + } + + // + // constructed object which appears to be explicitly tagged + // and it's really implicit means we have to add the + // surrounding sequence. + // + if (obj.IsExplicit()) + { + return new DerSet(inner); + } + + if (inner is Asn1Set) + { + return (Asn1Set) inner; + } + + // + // in this case the parser returns a sequence, convert it + // into a set. + // + if (inner is Asn1Sequence) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + Asn1Sequence s = (Asn1Sequence) inner; + + foreach (Asn1Encodable ae in s) + { + v.Add(ae); + } + + // TODO Should be able to construct set directly from sequence? + return new DerSet(v, false); + } + + throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + protected internal Asn1Set( + int capacity) + { + _set = new ArrayList(capacity); + } + + public virtual IEnumerator GetEnumerator() + { + return _set.GetEnumerator(); + } + + [Obsolete("Use GetEnumerator() instead")] + public IEnumerator GetObjects() + { + return GetEnumerator(); + } + + /** + * return the object at the set position indicated by index. + * + * @param index the set number (starting at zero) of the object + * @return the object at the set position indicated by index. + */ + public virtual Asn1Encodable this[int index] + { + get { return (Asn1Encodable) _set[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public Asn1Encodable GetObjectAt( + int index) + { + return this[index]; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return Count; } + } + + public virtual int Count + { + get { return _set.Count; } + } + + private class Asn1SetParserImpl + : Asn1SetParser + { + private readonly Asn1Set outer; + private readonly int max; + private int index; + + public Asn1SetParserImpl( + Asn1Set outer) + { + this.outer = outer; + this.max = outer.Count; + } + + public IAsn1Convertible ReadObject() + { + if (index == max) + return null; + + Asn1Encodable obj = outer[index++]; + if (obj is Asn1Sequence) + return ((Asn1Sequence)obj).Parser; + + if (obj is Asn1Set) + return ((Asn1Set)obj).Parser; + + // NB: Asn1OctetString implements Asn1OctetStringParser directly +// if (obj is Asn1OctetString) +// return ((Asn1OctetString)obj).Parser; + + return obj; + } + + public virtual Asn1Object ToAsn1Object() + { + return outer; + } + } + + public Asn1SetParser Parser + { + get { return new Asn1SetParserImpl(this); } + } + + protected override int Asn1GetHashCode() + { + int hc = Count; + + foreach (object o in this) + { + hc *= 17; + if (o != null) + { + hc ^= o.GetHashCode(); + } + } + + return hc; + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + Asn1Set other = asn1Object as Asn1Set; + + if (other == null) + return false; + + if (Count != other.Count) + { + return false; + } + + IEnumerator s1 = GetEnumerator(); + IEnumerator s2 = other.GetEnumerator(); + + while (s1.MoveNext() && s2.MoveNext()) + { +// if (!Platform.Equals(s1.Current, s2.Current)) + Asn1Object o1 = ((Asn1Encodable) s1.Current).ToAsn1Object(); + + if (!o1.Equals(s2.Current)) + { + return false; + } + } + + return true; + } + + /** + * return true if a <= b (arrays are assumed padded with zeros). + */ + private bool LessThanOrEqual( + byte[] a, + byte[] b) + { + int cmpLen = System.Math.Min(a.Length, b.Length); + + for (int i = 0; i < cmpLen; ++i) + { + byte l = a[i]; + byte r = b[i]; + + if (l != r) + { + return r > l ? true : false; + } + } + + return a.Length <= b.Length; + } + + protected internal void Sort() + { + if (_set.Count > 1) + { + bool swapped = true; + int lastSwap = _set.Count - 1; + + while (swapped) + { + int index = 0; + int swapIndex = 0; + byte[] a = ((Asn1Encodable) _set[0]).GetEncoded(); + + swapped = false; + + while (index != lastSwap) + { + byte[] b = ((Asn1Encodable) _set[index + 1]).GetEncoded(); + + if (LessThanOrEqual(a, b)) + { + a = b; + } + else + { + object o = _set[index]; + _set[index] = _set[index + 1]; + _set[index + 1] = o; + + swapped = true; + swapIndex = index; + } + + index++; + } + + lastSwap = swapIndex; + } + } + } + + protected internal void AddObject( + Asn1Encodable obj) + { + _set.Add(obj); + } + + public override string ToString() + { + return CollectionUtilities.ToString(_set); + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1TaggedObject.cs b/iTechSharp/srcbc/asn1/Asn1TaggedObject.cs new file mode 100644 index 0000000..e0cfced --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1TaggedObject.cs @@ -0,0 +1,177 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ + public abstract class Asn1TaggedObject + : Asn1Object, Asn1TaggedObjectParser + { + internal int tagNo; +// internal bool empty; + internal bool explicitly = true; + internal Asn1Encodable obj; + + static public Asn1TaggedObject GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + if (explicitly) + { + return (Asn1TaggedObject) obj.GetObject(); + } + + throw new ArgumentException("implicitly tagged tagged object"); + } + + static public Asn1TaggedObject GetInstance( + object obj) + { + if (obj == null || obj is Asn1TaggedObject) + { + return (Asn1TaggedObject) obj; + } + + throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + /** + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + protected Asn1TaggedObject( + int tagNo, + Asn1Encodable obj) + { + this.explicitly = true; + this.tagNo = tagNo; + this.obj = obj; + } + + /** + * @param explicitly true if the object is explicitly tagged. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + protected Asn1TaggedObject( + bool explicitly, + int tagNo, + Asn1Encodable obj) + { + this.explicitly = explicitly; + this.tagNo = tagNo; + this.obj = obj; + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + Asn1TaggedObject other = asn1Object as Asn1TaggedObject; + + if (other == null) + return false; + + return this.tagNo == other.tagNo +// && this.empty == other.empty + && this.explicitly == other.explicitly // TODO Should this be part of equality? + && Platform.Equals(GetObject(), other.GetObject()); + } + + protected override int Asn1GetHashCode() + { + int code = tagNo.GetHashCode(); + + // TODO: actually this is wrong - the problem is that a re-encoded + // object may end up with a different hashCode due to implicit + // tagging. As implicit tagging is ambiguous if a sequence is involved + // it seems the only correct method for both equals and hashCode is to + // compare the encodings... +// code ^= explicitly.GetHashCode(); + + if (obj != null) + { + code ^= obj.GetHashCode(); + } + + return code; + } + + public int TagNo + { + get { return tagNo; } + } + + /** + * return whether or not the object may be explicitly tagged. + *

      + * Note: if the object has been read from an input stream, the only + * time you can be sure if isExplicit is returning the true state of + * affairs is if it returns false. An implicitly tagged object may appear + * to be explicitly tagged, so you need to understand the context under + * which the reading was done as well, see GetObject below.

      + */ + public bool IsExplicit() + { + return explicitly; + } + + public bool IsEmpty() + { + return false; //empty; + } + + /** + * return whatever was following the tag. + *

      + * Note: tagged objects are generally context dependent if you're + * trying to extract a tagged object you should be going via the + * appropriate GetInstance method.

      + */ + public Asn1Object GetObject() + { + if (obj != null) + { + return obj.ToAsn1Object(); + } + + return null; + } + + /** + * Return the object held in this tagged object as a parser assuming it has + * the type of the passed in tag. If the object doesn't have a parser + * associated with it, the base object is returned. + */ + public IAsn1Convertible GetObjectParser( + int tag, + bool isExplicit) + { + switch (tag) + { + case Asn1Tags.Set: + return Asn1Set.GetInstance(this, isExplicit).Parser; + case Asn1Tags.Sequence: + return Asn1Sequence.GetInstance(this, isExplicit).Parser; + case Asn1Tags.OctetString: + return Asn1OctetString.GetInstance(this, isExplicit).Parser; + } + + if (isExplicit) + { + return GetObject(); + } + + throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag); + } + + public override string ToString() + { + return "[" + tagNo + "]" + obj; + } + } +} diff --git a/iTechSharp/srcbc/asn1/Asn1Tags.cs b/iTechSharp/srcbc/asn1/Asn1Tags.cs new file mode 100644 index 0000000..32ac6bc --- /dev/null +++ b/iTechSharp/srcbc/asn1/Asn1Tags.cs @@ -0,0 +1,36 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class Asn1Tags + { + public const int Boolean = 0x01; + public const int Integer = 0x02; + public const int BitString = 0x03; + public const int OctetString = 0x04; + public const int Null = 0x05; + public const int ObjectIdentifier = 0x06; + public const int External = 0x08; + public const int Enumerated = 0x0a; + public const int Sequence = 0x10; + public const int SequenceOf = 0x10; // for completeness + public const int Set = 0x11; + public const int SetOf = 0x11; // for completeness + + public const int NumericString = 0x12; + public const int PrintableString = 0x13; + public const int T61String = 0x14; + public const int VideotexString = 0x15; + public const int IA5String = 0x16; + public const int UtcTime = 0x17; + public const int GeneralizedTime = 0x18; + public const int GraphicString = 0x19; + public const int VisibleString = 0x1a; + public const int GeneralString = 0x1b; + public const int UniversalString = 0x1c; + public const int BmpString = 0x1e; + public const int Utf8String = 0x0c; + + public const int Constructed = 0x20; + public const int Application = 0x40; + public const int Tagged = 0x80; + } +} diff --git a/iTechSharp/srcbc/asn1/BERGenerator.cs b/iTechSharp/srcbc/asn1/BERGenerator.cs new file mode 100644 index 0000000..271572c --- /dev/null +++ b/iTechSharp/srcbc/asn1/BERGenerator.cs @@ -0,0 +1,102 @@ +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerGenerator + : Asn1Generator + { + private bool _tagged = false; + private bool _isExplicit; + private int _tagNo; + + protected BerGenerator( + Stream outStream) + : base(outStream) + { + } + + public BerGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream) + { + _tagged = true; + _isExplicit = isExplicit; + _tagNo = tagNo; + } + + public override void AddObject( + Asn1Encodable obj) + { + new BerOutputStream(Out).WriteObject(obj); + } + + public override Stream GetRawOutputStream() + { + return Out; + } + + public override void Close() + { + WriteBerEnd(); + } + + private void WriteHdr( + int tag) + { + Out.WriteByte((byte) tag); + Out.WriteByte(0x80); + } + + protected void WriteBerHeader( + int tag) + { + if (_tagged) + { + int tagNum = _tagNo | Asn1Tags.Tagged; + + if (_isExplicit) + { + WriteHdr(tagNum | Asn1Tags.Constructed); + WriteHdr(tag); + } + else + { + if ((tag & Asn1Tags.Constructed) != 0) + { + WriteHdr(tagNum | Asn1Tags.Constructed); + } + else + { + WriteHdr(tagNum); + } + } + } + else + { + WriteHdr(tag); + } + } + + protected void WriteBerBody( + Stream contentStream) + { + Streams.PipeAll(contentStream, Out); + } + + protected void WriteBerEnd() + { + Out.WriteByte(0x00); + Out.WriteByte(0x00); + + if (_tagged && _isExplicit) // write extra end for tag header + { + Out.WriteByte(0x00); + Out.WriteByte(0x00); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BEROctetStringGenerator.cs b/iTechSharp/srcbc/asn1/BEROctetStringGenerator.cs new file mode 100644 index 0000000..7468a6b --- /dev/null +++ b/iTechSharp/srcbc/asn1/BEROctetStringGenerator.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerOctetStringGenerator + : BerGenerator + { + public BerOctetStringGenerator(Stream outStream) + : base(outStream) + { + WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString); + } + + public BerOctetStringGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream, tagNo, isExplicit) + { + WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString); + } + + public Stream GetOctetOutputStream() + { + return GetOctetOutputStream(new byte[1000]); // limit for CER encoding. + } + + public Stream GetOctetOutputStream( + int bufSize) + { + return bufSize < 1 + ? GetOctetOutputStream() + : GetOctetOutputStream(new byte[bufSize]); + } + + public Stream GetOctetOutputStream( + byte[] buf) + { + return new BufferedBerOctetStream(this, buf); + } + + private class BufferedBerOctetStream + : BaseOutputStream + { + private byte[] _buf; + private int _off; + private readonly BerOctetStringGenerator _gen; + private readonly DerOutputStream _derOut; + + internal BufferedBerOctetStream( + BerOctetStringGenerator gen, + byte[] buf) + { + _gen = gen; + _buf = buf; + _off = 0; + _derOut = new DerOutputStream(_gen.Out); + } + + public override void WriteByte( + byte b) + { + _buf[_off++] = b; + + if (_off == _buf.Length) + { + DerOctetString.Encode(_derOut, _buf, 0, _off); + _off = 0; + } + } + + public override void Write( + byte[] buf, + int offset, + int len) + { + while (len > 0) + { + int numToCopy = System.Math.Min(len, _buf.Length - _off); + + if (numToCopy == _buf.Length) + { + DerOctetString.Encode(_derOut, buf, offset, numToCopy); + } + else + { + Array.Copy(buf, offset, _buf, _off, numToCopy); + + _off += numToCopy; + if (_off < _buf.Length) + break; + + DerOctetString.Encode(_derOut, _buf, 0, _off); + _off = 0; + } + + offset += numToCopy; + len -= numToCopy; + } + } + + public override void Close() + { + if (_off != 0) + { + DerOctetString.Encode(_derOut, _buf, 0, _off); + } + + _gen.WriteBerEnd(); + base.Close(); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BEROctetStringParser.cs b/iTechSharp/srcbc/asn1/BEROctetStringParser.cs new file mode 100644 index 0000000..4972d6b --- /dev/null +++ b/iTechSharp/srcbc/asn1/BEROctetStringParser.cs @@ -0,0 +1,36 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerOctetStringParser + : Asn1OctetStringParser + { + private readonly Asn1StreamParser _parser; + + internal BerOctetStringParser( + Asn1StreamParser parser) + { + _parser = parser; + } + + public Stream GetOctetStream() + { + return new ConstructedOctetStream(_parser); + } + + public Asn1Object ToAsn1Object() + { + try + { + return new BerOctetString(Streams.ReadAll(GetOctetStream())); + } + catch (IOException e) + { + throw new InvalidOperationException("IOException converting stream to byte array: " + e.Message, e); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BERSequenceGenerator.cs b/iTechSharp/srcbc/asn1/BERSequenceGenerator.cs new file mode 100644 index 0000000..5ea2c9b --- /dev/null +++ b/iTechSharp/srcbc/asn1/BERSequenceGenerator.cs @@ -0,0 +1,24 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerSequenceGenerator + : BerGenerator + { + public BerSequenceGenerator( + Stream outStream) + : base(outStream) + { + WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence); + } + + public BerSequenceGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream, tagNo, isExplicit) + { + WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence); + } + } +} diff --git a/iTechSharp/srcbc/asn1/BERSequenceParser.cs b/iTechSharp/srcbc/asn1/BERSequenceParser.cs new file mode 100644 index 0000000..8474b8d --- /dev/null +++ b/iTechSharp/srcbc/asn1/BERSequenceParser.cs @@ -0,0 +1,24 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class BerSequenceParser + : Asn1SequenceParser + { + private readonly Asn1StreamParser _parser; + + internal BerSequenceParser( + Asn1StreamParser parser) + { + this._parser = parser; + } + + public IAsn1Convertible ReadObject() + { + return _parser.ReadObject(); + } + + public Asn1Object ToAsn1Object() + { + return new BerSequence(_parser.ReadVector()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/BERSetGenerator.cs b/iTechSharp/srcbc/asn1/BERSetGenerator.cs new file mode 100644 index 0000000..72b1f90 --- /dev/null +++ b/iTechSharp/srcbc/asn1/BERSetGenerator.cs @@ -0,0 +1,24 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerSetGenerator + : BerGenerator + { + public BerSetGenerator( + Stream outStream) + : base(outStream) + { + WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set); + } + + public BerSetGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream, tagNo, isExplicit) + { + WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set); + } + } +} diff --git a/iTechSharp/srcbc/asn1/BERSetParser.cs b/iTechSharp/srcbc/asn1/BERSetParser.cs new file mode 100644 index 0000000..aa9ccbc --- /dev/null +++ b/iTechSharp/srcbc/asn1/BERSetParser.cs @@ -0,0 +1,24 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class BerSetParser + : Asn1SetParser + { + private readonly Asn1StreamParser _parser; + + internal BerSetParser( + Asn1StreamParser parser) + { + this._parser = parser; + } + + public IAsn1Convertible ReadObject() + { + return _parser.ReadObject(); + } + + public Asn1Object ToAsn1Object() + { + return new BerSet(_parser.ReadVector(), false); + } + } +} diff --git a/iTechSharp/srcbc/asn1/BERTaggedObjectParser.cs b/iTechSharp/srcbc/asn1/BERTaggedObjectParser.cs new file mode 100644 index 0000000..0c86f42 --- /dev/null +++ b/iTechSharp/srcbc/asn1/BERTaggedObjectParser.cs @@ -0,0 +1,128 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerTaggedObjectParser + : Asn1TaggedObjectParser + { + private int _baseTag; + private int _tagNumber; + private Stream _contentStream; + + private bool _indefiniteLength; + + internal BerTaggedObjectParser( + int baseTag, + int tagNumber, + Stream contentStream) + { + if (!contentStream.CanRead) + throw new ArgumentException("Expected stream to be readable", "contentStream"); + + _baseTag = baseTag; + _tagNumber = tagNumber; + _contentStream = contentStream; + _indefiniteLength = contentStream is IndefiniteLengthInputStream; + } + + public bool IsConstructed + { + get { return (_baseTag & Asn1Tags.Constructed) != 0; } + } + + public int TagNo + { + get { return _tagNumber; } + } + + public IAsn1Convertible GetObjectParser( + int tag, + bool isExplicit) + { + if (isExplicit) + { + return new Asn1StreamParser(_contentStream).ReadObject(); + } + + switch (tag) + { + case Asn1Tags.Set: + if (_indefiniteLength) + { + return new BerSetParser(new Asn1StreamParser(_contentStream)); + } + else + { + return new DerSetParser(new Asn1StreamParser(_contentStream)); + } + case Asn1Tags.Sequence: + if (_indefiniteLength) + { + return new BerSequenceParser(new Asn1StreamParser(_contentStream)); + } + else + { + return new DerSequenceParser(new Asn1StreamParser(_contentStream)); + } + case Asn1Tags.OctetString: + // TODO Is the handling of definite length constructed encodings correct? + if (_indefiniteLength || IsConstructed) + { + return new BerOctetStringParser(new Asn1StreamParser(_contentStream)); + } + else + { + return new DerOctetStringParser((DefiniteLengthInputStream)_contentStream); + } + } + + throw Platform.CreateNotImplementedException("implicit tagging"); + } + + private Asn1EncodableVector rLoadVector(Stream inStream) + { + try + { + return new Asn1StreamParser(inStream).ReadVector(); + } + catch (IOException e) + { + throw new InvalidOperationException(e.Message, e); + } + } + + public Asn1Object ToAsn1Object() + { + if (_indefiniteLength) + { + Asn1EncodableVector v = rLoadVector(_contentStream); + + return v.Count == 1 + ? new BerTaggedObject(true, _tagNumber, v[0]) + : new BerTaggedObject(false, _tagNumber, BerSequence.FromVector(v)); + } + + if (IsConstructed) + { + Asn1EncodableVector v = rLoadVector(_contentStream); + + return v.Count == 1 + ? new DerTaggedObject(true, _tagNumber, v[0]) + : new DerTaggedObject(false, _tagNumber, DerSequence.FromVector(v)); + } + + try + { + DefiniteLengthInputStream defIn = (DefiniteLengthInputStream) _contentStream; + return new DerTaggedObject(false, _tagNumber, new DerOctetString(defIn.ToArray())); + } + catch (IOException e) + { + throw new InvalidOperationException(e.Message, e); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BerNull.cs b/iTechSharp/srcbc/asn1/BerNull.cs new file mode 100644 index 0000000..0751bba --- /dev/null +++ b/iTechSharp/srcbc/asn1/BerNull.cs @@ -0,0 +1,35 @@ +using System; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * A BER Null object. + */ + public class BerNull + : DerNull + { + public static new readonly BerNull Instance = new BerNull(0); + + [Obsolete("Use static Instance object")] + public BerNull() + { + } + + private BerNull(int dummy) : base(dummy) + { + } + + internal override void Encode( + DerOutputStream derOut) + { + if (derOut is Asn1OutputStream || derOut is BerOutputStream) + { + derOut.WriteByte(Asn1Tags.Null); + } + else + { + base.Encode(derOut); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BerOctetString.cs b/iTechSharp/srcbc/asn1/BerOctetString.cs new file mode 100644 index 0000000..ce92e1a --- /dev/null +++ b/iTechSharp/srcbc/asn1/BerOctetString.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class BerOctetString + : DerOctetString, IEnumerable + { + private const int MaxLength = 1000; + + /** + * convert a vector of octet strings into a single byte string + */ + private static byte[] ToBytes( + IEnumerable octs) + { + MemoryStream bOut = new MemoryStream(); + foreach (DerOctetString o in octs) + { + byte[] octets = o.GetOctets(); + bOut.Write(octets, 0, octets.Length); + } + return bOut.ToArray(); + } + + private readonly IEnumerable octs; + + /// The octets making up the octet string. + public BerOctetString( + byte[] str) + : base(str) + { + } + + public BerOctetString( + IEnumerable octets) + : base(ToBytes(octets)) + { + this.octs = octets; + } + + public BerOctetString( + Asn1Object obj) + : base(obj) + { + } + + public BerOctetString( + Asn1Encodable obj) + : base(obj.ToAsn1Object()) + { + } + + public override byte[] GetOctets() + { + return str; + } + + /** + * return the DER octets that make up this string. + */ + public IEnumerator GetEnumerator() + { + if (octs == null) + { + return GenerateOcts().GetEnumerator(); + } + + return octs.GetEnumerator(); + } + + [Obsolete("Use GetEnumerator() instead")] + public IEnumerator GetObjects() + { + return GetEnumerator(); + } + + private ArrayList GenerateOcts() + { + int start = 0; + int end = 0; + ArrayList vec = new ArrayList(); + + while ((end + 1) < str.Length) + { + if (str[end] == 0 && str[end + 1] == 0) + { + byte[] nStr = new byte[end - start + 1]; + + Array.Copy(str, start, nStr, 0, nStr.Length); + + vec.Add(new DerOctetString(nStr)); + start = end + 1; + } + end++; + } + + byte[] nStr2 = new byte[str.Length - start]; + + Array.Copy(str, start, nStr2, 0, nStr2.Length); + + vec.Add(new DerOctetString(nStr2)); + + return vec; + } + + internal override void Encode( + DerOutputStream derOut) + { + if (derOut is Asn1OutputStream || derOut is BerOutputStream) + { + derOut.WriteByte(Asn1Tags.Constructed | Asn1Tags.OctetString); + + derOut.WriteByte(0x80); + + // + // write out the octet array + // + if (octs != null) + { + foreach (DerOctetString oct in octs) + { + derOut.WriteObject(oct); + } + } + else + { + for (int i = 0; i < str.Length; i += MaxLength) + { + int end = System.Math.Min(str.Length, i + MaxLength); + + byte[] nStr = new byte[end - i]; + + Array.Copy(str, i, nStr, 0, nStr.Length); + + derOut.WriteObject(new DerOctetString(nStr)); + } + } + + derOut.WriteByte(0x00); + derOut.WriteByte(0x00); + } + else + { + base.Encode(derOut); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BerOutputStream.cs b/iTechSharp/srcbc/asn1/BerOutputStream.cs new file mode 100644 index 0000000..b3ece10 --- /dev/null +++ b/iTechSharp/srcbc/asn1/BerOutputStream.cs @@ -0,0 +1,36 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + // TODO Make Obsolete in favour of Asn1OutputStream? + public class BerOutputStream + : DerOutputStream + { + public BerOutputStream(Stream os) : base(os) + { + } + + [Obsolete("Use version taking an Asn1Encodable arg instead")] + public override void WriteObject( + object obj) + { + if (obj == null) + { + WriteNull(); + } + else if (obj is Asn1Object) + { + ((Asn1Object)obj).Encode(this); + } + else if (obj is Asn1Encodable) + { + ((Asn1Encodable)obj).ToAsn1Object().Encode(this); + } + else + { + throw new IOException("object not BerEncodable"); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BerSequence.cs b/iTechSharp/srcbc/asn1/BerSequence.cs new file mode 100644 index 0000000..70b43fc --- /dev/null +++ b/iTechSharp/srcbc/asn1/BerSequence.cs @@ -0,0 +1,69 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class BerSequence + : DerSequence + { + public static new readonly BerSequence Empty = new BerSequence(); + + public static new BerSequence FromVector( + Asn1EncodableVector v) + { + return v.Count < 1 ? Empty : new BerSequence(v); + } + + /** + * create an empty sequence + */ + public BerSequence() + { + } + + /** + * create a sequence containing one object + */ + public BerSequence( + Asn1Encodable obj) + : base(obj) + { + } + + public BerSequence( + params Asn1Encodable[] v) + : base(v) + { + } + + /** + * create a sequence containing a vector of objects. + */ + public BerSequence( + Asn1EncodableVector v) + : base(v) + { + } + + /* + */ + internal override void Encode( + DerOutputStream derOut) + { + if (derOut is Asn1OutputStream || derOut is BerOutputStream) + { + derOut.WriteByte(Asn1Tags.Sequence | Asn1Tags.Constructed); + derOut.WriteByte(0x80); + + foreach (Asn1Encodable o in this) + { + derOut.WriteObject(o); + } + + derOut.WriteByte(0x00); + derOut.WriteByte(0x00); + } + else + { + base.Encode(derOut); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BerSet.cs b/iTechSharp/srcbc/asn1/BerSet.cs new file mode 100644 index 0000000..a181e17 --- /dev/null +++ b/iTechSharp/srcbc/asn1/BerSet.cs @@ -0,0 +1,70 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class BerSet + : DerSet + { + public static new readonly BerSet Empty = new BerSet(); + + public static new BerSet FromVector( + Asn1EncodableVector v) + { + return v.Count < 1 ? Empty : new BerSet(v); + } + + internal static new BerSet FromVector( + Asn1EncodableVector v, + bool needsSorting) + { + return v.Count < 1 ? Empty : new BerSet(v, needsSorting); + } + + /** + * create an empty sequence + */ + public BerSet() + { + } + + /** + * create a set containing one object + */ + public BerSet(Asn1Encodable obj) : base(obj) + { + } + + /** + * create a set containing a vector of objects. + */ + public BerSet(Asn1EncodableVector v) : base(v, false) + { + } + + internal BerSet(Asn1EncodableVector v, bool needsSorting) : base(v, needsSorting) + { + } + + /* + */ + internal override void Encode( + DerOutputStream derOut) + { + if (derOut is Asn1OutputStream || derOut is BerOutputStream) + { + derOut.WriteByte(Asn1Tags.Set | Asn1Tags.Constructed); + derOut.WriteByte(0x80); + + foreach (Asn1Encodable o in this) + { + derOut.WriteObject(o); + } + + derOut.WriteByte(0x00); + derOut.WriteByte(0x00); + } + else + { + base.Encode(derOut); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/BerTaggedObject.cs b/iTechSharp/srcbc/asn1/BerTaggedObject.cs new file mode 100644 index 0000000..228b136 --- /dev/null +++ b/iTechSharp/srcbc/asn1/BerTaggedObject.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * BER TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ + public class BerTaggedObject + : DerTaggedObject + { + /** + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public BerTaggedObject( + int tagNo, + Asn1Encodable obj) + : base(tagNo, obj) + { + } + + /** + * @param explicitly true if an explicitly tagged object. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public BerTaggedObject( + bool explicitly, + int tagNo, + Asn1Encodable obj) + : base(explicitly, tagNo, obj) + { + } + + /** + * create an implicitly tagged object that contains a zero + * length sequence. + */ + public BerTaggedObject( + int tagNo) + : base(false, tagNo, BerSequence.Empty) + { + } + + internal override void Encode( + DerOutputStream derOut) + { + if (derOut is Asn1OutputStream || derOut is BerOutputStream) + { + derOut.WriteTag((byte)(Asn1Tags.Constructed | Asn1Tags.Tagged), tagNo); + derOut.WriteByte(0x80); + + if (!IsEmpty()) + { + if (!explicitly) + { + IEnumerable eObj; + if (obj is Asn1OctetString) + { + if (obj is BerOctetString) + { + eObj = (BerOctetString) obj; + } + else + { + Asn1OctetString octs = (Asn1OctetString)obj; + eObj = new BerOctetString(octs.GetOctets()); + } + } + else if (obj is Asn1Sequence) + { + eObj = (Asn1Sequence) obj; + } + else if (obj is Asn1Set) + { + eObj = (Asn1Set) obj; + } + else + { + throw Platform.CreateNotImplementedException(obj.GetType().Name); + } + + foreach (Asn1Encodable o in eObj) + { + derOut.WriteObject(o); + } + } + else + { + derOut.WriteObject(obj); + } + } + + derOut.WriteByte(0x00); + derOut.WriteByte(0x00); + } + else + { + base.Encode(derOut); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/ConstructedOctetStream.cs b/iTechSharp/srcbc/asn1/ConstructedOctetStream.cs new file mode 100644 index 0000000..1773b22 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ConstructedOctetStream.cs @@ -0,0 +1,102 @@ +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + internal class ConstructedOctetStream + : BaseInputStream + { + private readonly Asn1StreamParser _parser; + + private bool _first = true; + private Stream _currentStream; + + internal ConstructedOctetStream( + Asn1StreamParser parser) + { + _parser = parser; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (_currentStream == null) + { + if (!_first) + return 0; + + Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject(); + + if (s == null) + return 0; + + _first = false; + _currentStream = s.GetOctetStream(); + } + + int totalRead = 0; + + for (;;) + { + int numRead = _currentStream.Read(buffer, offset + totalRead, count - totalRead); + + if (numRead > 0) + { + totalRead += numRead; + + if (totalRead == count) + return totalRead; + } + else + { + Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject(); + + if (aos == null) + { + _currentStream = null; + return totalRead; + } + + _currentStream = aos.GetOctetStream(); + } + } + } + + public override int ReadByte() + { + if (_currentStream == null) + { + if (!_first) + return 0; + + Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject(); + + if (s == null) + return 0; + + _first = false; + _currentStream = s.GetOctetStream(); + } + + for (;;) + { + int b = _currentStream.ReadByte(); + + if (b >= 0) + { + return b; + } + + Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject(); + + if (aos == null) + { + _currentStream = null; + return -1; + } + + _currentStream = aos.GetOctetStream(); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/DERGenerator.cs b/iTechSharp/srcbc/asn1/DERGenerator.cs new file mode 100644 index 0000000..3efa5d1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DERGenerator.cs @@ -0,0 +1,107 @@ +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public abstract class DerGenerator + : Asn1Generator + { + private bool _tagged = false; + private bool _isExplicit; + private int _tagNo; + + protected DerGenerator( + Stream outStream) + : base(outStream) + { + } + + protected DerGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream) + { + _tagged = true; + _isExplicit = isExplicit; + _tagNo = tagNo; + } + + private static void WriteLength( + Stream outStr, + int length) + { + if (length > 127) + { + int size = 1; + int val = length; + + while ((val >>= 8) != 0) + { + size++; + } + + outStr.WriteByte((byte)(size | 0x80)); + + for (int i = (size - 1) * 8; i >= 0; i -= 8) + { + outStr.WriteByte((byte)(length >> i)); + } + } + else + { + outStr.WriteByte((byte)length); + } + } + + internal static void WriteDerEncoded( + Stream outStream, + int tag, + byte[] bytes) + { + outStream.WriteByte((byte) tag); + WriteLength(outStream, bytes.Length); + outStream.Write(bytes, 0, bytes.Length); + } + + internal void WriteDerEncoded( + int tag, + byte[] bytes) + { + if (_tagged) + { + int tagNum = _tagNo | Asn1Tags.Tagged; + + if (_isExplicit) + { + int newTag = _tagNo | Asn1Tags.Constructed | Asn1Tags.Tagged; + MemoryStream bOut = new MemoryStream(); + WriteDerEncoded(bOut, tag, bytes); + WriteDerEncoded(Out, newTag, bOut.ToArray()); + } + else + { + if ((tag & Asn1Tags.Constructed) != 0) + { + tagNum |= Asn1Tags.Constructed; + } + + WriteDerEncoded(Out, tagNum, bytes); + } + } + else + { + WriteDerEncoded(Out, tag, bytes); + } + } + + internal static void WriteDerEncoded( + Stream outStr, + int tag, + Stream inStr) + { + WriteDerEncoded(outStr, tag, Streams.ReadAll(inStr)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DEROctetStringParser.cs b/iTechSharp/srcbc/asn1/DEROctetStringParser.cs new file mode 100644 index 0000000..b0d3ad8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DEROctetStringParser.cs @@ -0,0 +1,36 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerOctetStringParser + : Asn1OctetStringParser + { + private readonly DefiniteLengthInputStream stream; + + internal DerOctetStringParser( + DefiniteLengthInputStream stream) + { + this.stream = stream; + } + + public Stream GetOctetStream() + { + return stream; + } + + public Asn1Object ToAsn1Object() + { + try + { + return new DerOctetString(stream.ToArray()); + } + catch (IOException e) + { + throw new InvalidOperationException("IOException converting stream to byte array: " + e.Message, e); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/DERSequenceGenerator.cs b/iTechSharp/srcbc/asn1/DERSequenceGenerator.cs new file mode 100644 index 0000000..4c2bfd0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DERSequenceGenerator.cs @@ -0,0 +1,40 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerSequenceGenerator + : DerGenerator + { + private readonly MemoryStream _bOut = new MemoryStream(); + + public DerSequenceGenerator( + Stream outStream) + : base(outStream) + { + } + + public DerSequenceGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream, tagNo, isExplicit) + { + } + + public override void AddObject( + Asn1Encodable obj) + { + new DerOutputStream(_bOut).WriteObject(obj); + } + + public override Stream GetRawOutputStream() + { + return _bOut; + } + + public override void Close() + { + WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Sequence, _bOut.ToArray()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DERSequenceParser.cs b/iTechSharp/srcbc/asn1/DERSequenceParser.cs new file mode 100644 index 0000000..69c2b9b --- /dev/null +++ b/iTechSharp/srcbc/asn1/DERSequenceParser.cs @@ -0,0 +1,24 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class DerSequenceParser + : Asn1SequenceParser + { + private readonly Asn1StreamParser _parser; + + internal DerSequenceParser( + Asn1StreamParser parser) + { + this._parser = parser; + } + + public IAsn1Convertible ReadObject() + { + return _parser.ReadObject(); + } + + public Asn1Object ToAsn1Object() + { + return new DerSequence(_parser.ReadVector()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DERSetGenerator.cs b/iTechSharp/srcbc/asn1/DERSetGenerator.cs new file mode 100644 index 0000000..455ca88 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DERSetGenerator.cs @@ -0,0 +1,40 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerSetGenerator + : DerGenerator + { + private readonly MemoryStream _bOut = new MemoryStream(); + + public DerSetGenerator( + Stream outStream) + : base(outStream) + { + } + + public DerSetGenerator( + Stream outStream, + int tagNo, + bool isExplicit) + : base(outStream, tagNo, isExplicit) + { + } + + public override void AddObject( + Asn1Encodable obj) + { + new DerOutputStream(_bOut).WriteObject(obj); + } + + public override Stream GetRawOutputStream() + { + return _bOut; + } + + public override void Close() + { + WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Set, _bOut.ToArray()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DERSetParser.cs b/iTechSharp/srcbc/asn1/DERSetParser.cs new file mode 100644 index 0000000..d67f135 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DERSetParser.cs @@ -0,0 +1,24 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class DerSetParser + : Asn1SetParser + { + private readonly Asn1StreamParser _parser; + + internal DerSetParser( + Asn1StreamParser parser) + { + this._parser = parser; + } + + public IAsn1Convertible ReadObject() + { + return _parser.ReadObject(); + } + + public Asn1Object ToAsn1Object() + { + return new DerSet(_parser.ReadVector(), false); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DefiniteLengthInputStream.cs b/iTechSharp/srcbc/asn1/DefiniteLengthInputStream.cs new file mode 100644 index 0000000..ee222f2 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DefiniteLengthInputStream.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + class DefiniteLengthInputStream + : LimitedInputStream + { + private static readonly byte[] EmptyBytes = new byte[0]; + + private int _length; + + internal DefiniteLengthInputStream( + Stream inStream, + int length) + : base(inStream) + { + if (length < 0) + throw new ArgumentException("negative lengths not allowed", "length"); + + this._length = length; + } + + public override int ReadByte() + { + if (_length > 0) + { + int b = _in.ReadByte(); + + if (b < 0) + throw new EndOfStreamException(); + + --_length; + return b; + } + + SetParentEofDetect(true); + + return -1; + } + + public override int Read( + byte[] buf, + int off, + int len) + { + if (_length > 0) + { + int toRead = System.Math.Min(len, _length); + int numRead = _in.Read(buf, off, toRead); + + if (numRead < 1) + throw new EndOfStreamException(); + + _length -= numRead; + return numRead; + } + + SetParentEofDetect(true); + + return 0; + } + + internal byte[] ToArray() + { + byte[] bytes; + if (_length > 0) + { + bytes = new byte[_length]; + if (Streams.ReadFully(_in, bytes) < _length) + throw new EndOfStreamException(); + _length = 0; + } + else + { + bytes = EmptyBytes; + } + + SetParentEofDetect(true); + + return bytes; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerApplicationSpecific.cs b/iTechSharp/srcbc/asn1/DerApplicationSpecific.cs new file mode 100644 index 0000000..21d3488 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerApplicationSpecific.cs @@ -0,0 +1,150 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Base class for an application specific object + */ + public class DerApplicationSpecific + : Asn1Object + { + private readonly bool isConstructed; + private readonly int tag; + private readonly byte[] octets; + + internal DerApplicationSpecific( + bool isConstructed, + int tag, + byte[] octets) + { + this.isConstructed = isConstructed; + this.tag = tag; + this.octets = octets; + } + + public DerApplicationSpecific( + int tag, + byte[] octets) + : this(false, tag, octets) + { + } + + public DerApplicationSpecific( + int tag, + Asn1Encodable obj) + : this(true, tag, obj) + { + } + + public DerApplicationSpecific( + bool isExplicit, + int tag, + Asn1Encodable obj) + { + if (tag >= 0x1f) + throw new IOException("unsupported tag number"); + + byte[] data = obj.GetDerEncoded(); + + this.isConstructed = isExplicit; + this.tag = tag; + + if (isExplicit) + { + this.octets = data; + } + else + { + int lenBytes = GetLengthOfLength(data); + byte[] tmp = new byte[data.Length - lenBytes]; + Array.Copy(data, lenBytes, tmp, 0, tmp.Length); + this.octets = tmp; + } + } + + private int GetLengthOfLength( + byte[] data) + { + int count = 2; // TODO: assumes only a 1 byte tag number + + while((data[count - 1] & 0x80) != 0) + { + count++; + } + + return count; + } + + public bool IsConstructed() + { + return isConstructed; + } + + public byte[] GetContents() + { + return octets; + } + + public int ApplicationTag + { + get { return tag; } + } + + public Asn1Object GetObject() + { + return FromByteArray(GetContents()); + } + + /** + * Return the enclosed object assuming implicit tagging. + * + * @param derTagNo the type tag that should be applied to the object's contents. + * @return the resulting object + * @throws IOException if reconstruction fails. + */ + public Asn1Object GetObject( + int derTagNo) + { + if (tag >= 0x1f) + throw new IOException("unsupported tag number"); + + byte[] tmp = this.GetEncoded(); + tmp[0] = (byte) derTagNo; + + return FromByteArray(tmp);; + } + + internal override void Encode( + DerOutputStream derOut) + { + int classBits = Asn1Tags.Application; + if (isConstructed) + { + classBits |= Asn1Tags.Constructed; + } + + derOut.WriteEncoded(classBits, tag, octets); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerApplicationSpecific other = asn1Object as DerApplicationSpecific; + + if (other == null) + return false; + + return this.isConstructed == other.isConstructed + && this.tag == other.tag + && Arrays.AreEqual(this.octets, other.octets); + } + + protected override int Asn1GetHashCode() + { + return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(octets); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerBMPString.cs b/iTechSharp/srcbc/asn1/DerBMPString.cs new file mode 100644 index 0000000..c018aa1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerBMPString.cs @@ -0,0 +1,118 @@ +using System; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der BMPString object. + */ + public class DerBmpString + : DerStringBase + { + private readonly string str; + + /** + * return a BMP string from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static DerBmpString GetInstance( + object obj) + { + if (obj == null || obj is DerBmpString) + { + return (DerBmpString)obj; + } + + if (obj is Asn1OctetString) + { + return new DerBmpString(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return a BMP string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerBmpString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - byte encoded string. + */ + public DerBmpString( + byte[] str) + { + if (str == null) + throw new ArgumentNullException("str"); + + char[] cs = new char[str.Length / 2]; + + for (int i = 0; i != cs.Length; i++) + { + cs[i] = (char)((str[2 * i] << 8) | (str[2 * i + 1] & 0xff)); + } + + this.str = new string(cs); + } + + /** + * basic constructor + */ + public DerBmpString( + string str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerBmpString other = asn1Object as DerBmpString; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + + internal override void Encode( + DerOutputStream derOut) + { + char[] c = str.ToCharArray(); + byte[] b = new byte[c.Length * 2]; + + for (int i = 0; i != c.Length; i++) + { + b[2 * i] = (byte)(c[i] >> 8); + b[2 * i + 1] = (byte)c[i]; + } + + derOut.WriteEncoded(Asn1Tags.BmpString, b); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerBitString.cs b/iTechSharp/srcbc/asn1/DerBitString.cs new file mode 100644 index 0000000..9a3398a --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerBitString.cs @@ -0,0 +1,245 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerBitString + : DerStringBase + { + private static readonly char[] table + = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + private readonly byte[] data; + private readonly int padBits; + + /** + * return the correct number of pad bits for a bit string defined in + * a 32 bit constant + */ + static internal int GetPadBits( + int bitString) + { + int val = 0; + for (int i = 3; i >= 0; i--) + { + // + // this may look a little odd, but if it isn't done like this pre jdk1.2 + // JVM's break! + // + if (i != 0) + { + if ((bitString >> (i * 8)) != 0) + { + val = (bitString >> (i * 8)) & 0xFF; + break; + } + } + else + { + if (bitString != 0) + { + val = bitString & 0xFF; + break; + } + } + } + + if (val == 0) + { + return 7; + } + + int bits = 1; + + while (((val <<= 1) & 0xFF) != 0) + { + bits++; + } + + return 8 - bits; + } + + /** + * return the correct number of bytes for a bit string defined in + * a 32 bit constant + */ + static internal byte[] GetBytes( + int bitString) + { + int bytes = 4; + for (int i = 3; i >= 1; i--) + { + if ((bitString & (0xFF << (i * 8))) != 0) + { + break; + } + bytes--; + } + + byte[] result = new byte[bytes]; + for (int i = 0; i < bytes; i++) + { + result[i] = (byte) ((bitString >> (i * 8)) & 0xFF); + } + + return result; + } + + /** + * return a Bit string from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerBitString GetInstance( + object obj) + { + if (obj == null || obj is DerBitString) + { + return (DerBitString) obj; + } + + if (obj is Asn1OctetString) + { + byte[] bytes = ((Asn1OctetString) obj).GetOctets(); + int padBits = bytes[0]; + byte[] data = new byte[bytes.Length - 1]; + + Array.Copy(bytes, 1, data, 0, bytes.Length - 1); + + return new DerBitString(data, padBits); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject) obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return a Bit string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerBitString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + internal DerBitString( + byte data, + int padBits) + { + this.data = new byte[]{ data }; + this.padBits = padBits; + } + + /** + * @param data the octets making up the bit string. + * @param padBits the number of extra bits at the end of the string. + */ + public DerBitString( + byte[] data, + int padBits) + { + // TODO Deep copy? + this.data = data; + this.padBits = padBits; + } + + public DerBitString( + byte[] data) + { + // TODO Deep copy? + this.data = data; + } + + public DerBitString( + Asn1Encodable obj) + { + this.data = obj.GetDerEncoded(); +// this.padBits = 0; + } + + public byte[] GetBytes() + { + return data; + } + + public int PadBits + { + get { return padBits; } + } + + /** + * @return the value of the bit string as an int (truncating if necessary) + */ + public int IntValue + { + get + { + int value = 0; + + for (int i = 0; i != data.Length && i != 4; i++) + { + value |= (data[i] & 0xff) << (8 * i); + } + + return value; + } + } + + internal override void Encode( + DerOutputStream derOut) + { + byte[] bytes = new byte[GetBytes().Length + 1]; + + bytes[0] = (byte) PadBits; + Array.Copy(GetBytes(), 0, bytes, 1, bytes.Length - 1); + + derOut.WriteEncoded(Asn1Tags.BitString, bytes); + } + + protected override int Asn1GetHashCode() + { + return padBits.GetHashCode() ^ Arrays.GetHashCode(data); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerBitString other = asn1Object as DerBitString; + + if (other == null) + return false; + + return this.padBits == other.padBits + && Arrays.AreEqual(this.data, other.data); + } + + public override string GetString() + { + StringBuilder buffer = new StringBuilder("#"); + + byte[] str = GetDerEncoded(); + + for (int i = 0; i != str.Length; i++) + { + uint ubyte = str[i]; + buffer.Append(table[(ubyte >> 4) & 0xf]); + buffer.Append(table[str[i] & 0xf]); + } + + return buffer.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerBoolean.cs b/iTechSharp/srcbc/asn1/DerBoolean.cs new file mode 100644 index 0000000..b714cfa --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerBoolean.cs @@ -0,0 +1,110 @@ +using System; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerBoolean + : Asn1Object + { + private readonly byte value; + + public static readonly DerBoolean False = new DerBoolean(false); + public static readonly DerBoolean True = new DerBoolean(true); + + /** + * return a bool from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerBoolean GetInstance( + object obj) + { + if (obj == null || obj is DerBoolean) + { + return (DerBoolean) obj; + } + + if (obj is Asn1OctetString) + { + return new DerBoolean(((Asn1OctetString) obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject) obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return a DerBoolean from the passed in bool. + */ + public static DerBoolean GetInstance( + bool value) + { + return value ? True : False; + } + + /** + * return a Boolean from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerBoolean GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public DerBoolean( + byte[] value) + { + // TODO Are there any constraints on the possible byte values? + this.value = value[0]; + } + + private DerBoolean( + bool value) + { + this.value = value ? (byte)0xff : (byte)0; + } + + public bool IsTrue + { + get { return value != 0; } + } + + internal override void Encode( + DerOutputStream derOut) + { + // TODO Should we make sure the byte value is one of '0' or '0xff' here? + derOut.WriteEncoded(Asn1Tags.Boolean, new byte[]{ value }); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerBoolean other = asn1Object as DerBoolean; + + if (other == null) + return false; + + return IsTrue == other.IsTrue; + } + + protected override int Asn1GetHashCode() + { + return IsTrue.GetHashCode(); + } + + public override string ToString() + { + return IsTrue ? "TRUE" : "FALSE"; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerEnumerated.cs b/iTechSharp/srcbc/asn1/DerEnumerated.cs new file mode 100644 index 0000000..d31c586 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerEnumerated.cs @@ -0,0 +1,103 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerEnumerated + : Asn1Object + { + private readonly byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerEnumerated GetInstance( + object obj) + { + if (obj == null || obj is DerEnumerated) + { + return (DerEnumerated)obj; + } + + if (obj is Asn1OctetString) + { + return new DerEnumerated(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an Enumerated from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerEnumerated GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public DerEnumerated( + int value) + { + bytes = BigInteger.ValueOf(value).ToByteArray(); + } + + public DerEnumerated( + BigInteger value) + { + bytes = value.ToByteArray(); + } + + public DerEnumerated( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger Value + { + get + { + return new BigInteger(bytes); + } + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.Enumerated, bytes); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerEnumerated other = asn1Object as DerEnumerated; + + if (other == null) + return false; + + return Arrays.AreEqual(this.bytes, other.bytes); + } + + protected override int Asn1GetHashCode() + { + return Arrays.GetHashCode(bytes); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerGeneralString.cs b/iTechSharp/srcbc/asn1/DerGeneralString.cs new file mode 100644 index 0000000..1146074 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerGeneralString.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerGeneralString + : DerStringBase + { + private readonly string str; + + public static DerGeneralString GetInstance( + object obj) + { + if (obj == null || obj is DerGeneralString) + { + return (DerGeneralString) obj; + } + if (obj is Asn1OctetString) + { + return new DerGeneralString(((Asn1OctetString) obj).GetOctets()); + } + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject) obj).GetObject()); + } + throw new ArgumentException("illegal object in GetInstance: " + + obj.GetType().Name); + } + + public static DerGeneralString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public DerGeneralString( + byte[] str) + : this(Encoding.ASCII.GetString(str, 0, str.Length)) + { + } + + public DerGeneralString( + string str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + public byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(str); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.GeneralString, GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerGeneralString other = asn1Object as DerGeneralString; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerGeneralizedTime.cs b/iTechSharp/srcbc/asn1/DerGeneralizedTime.cs new file mode 100644 index 0000000..f1fee1c --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerGeneralizedTime.cs @@ -0,0 +1,289 @@ +using System; +using System.Globalization; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Generalized time object. + */ + public class DerGeneralizedTime + : Asn1Object + { + private readonly string time; + + /** + * return a generalized time from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerGeneralizedTime GetInstance( + object obj) + { + if (obj == null || obj is DerGeneralizedTime) + { + return (DerGeneralizedTime)obj; + } + + if (obj is Asn1OctetString) + { + return new DerGeneralizedTime(((Asn1OctetString)obj).GetOctets()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj"); + } + + /** + * return a Generalized Time object from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerGeneralizedTime GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z + * for local time, or Z+-HHMM on the end, for difference between local + * time and UTC time. The fractional second amount f must consist of at + * least one number with trailing zeroes removed. + * + * @param time the time string. + * @exception ArgumentException if string is an illegal format. + */ + public DerGeneralizedTime( + string time) + { + this.time = time; + + try + { + ToDateTime(); + } + catch (FormatException e) + { + throw new ArgumentException("invalid date string: " + e.Message); + } + } + + /** + * base constructor from a local time object + */ + public DerGeneralizedTime( + DateTime time) + { + this.time = time.ToString(@"yyyyMMddHHmmss\Z"); + } + + internal DerGeneralizedTime( + byte[] bytes) + { + // + // explicitly convert to characters + // + this.time = Encoding.ASCII.GetString(bytes, 0, bytes.Length); + } + + /** + * Return the time. + * @return The time string as it appeared in the encoded object. + */ + public string TimeString + { + get { return time; } + } + + /** + * return the time - always in the form of + * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm). + *

      + * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *

      +         *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
      +         * 
      + * To read in the time and Get a date which is compatible with our local + * time zone.

      + */ + public string GetTime() + { + // + // standardise the format. + // + if (time[time.Length - 1] == 'Z') + { + return time.Substring(0, time.Length - 1) + "GMT+00:00"; + } + else + { + int signPos = time.Length - 5; + char sign = time[signPos]; + if (sign == '-' || sign == '+') + { + return time.Substring(0, signPos) + + "GMT" + + time.Substring(signPos, 3) + + ":" + + time.Substring(signPos + 3); + } + else + { + signPos = time.Length - 3; + sign = time[signPos]; + if (sign == '-' || sign == '+') + { + return time.Substring(0, signPos) + + "GMT" + + time.Substring(signPos) + + ":00"; + } + } + } + + return time + CalculateGmtOffset(); + } + + private string CalculateGmtOffset() + { + char sign = '+'; + + // Note: GetUtcOffset incorporates Daylight Savings offset + int minutes = TimeZone.CurrentTimeZone.GetUtcOffset(ToDateTime()).Minutes; + if (minutes < 0) + { + sign = '-'; + minutes = -minutes; + } + int hours = minutes / 60; + minutes %= 60; + + return "GMT" + sign + Convert(hours) + ":" + Convert(minutes); + } + + private static string Convert( + int time) + { + if (time < 10) + { + return "0" + time; + } + + return time.ToString(); + } + + public DateTime ToDateTime() + { + string formatStr; + string d = time; + bool makeUniversal = false; + + if (d.EndsWith("Z")) + { + if (HasFractionalSeconds) + { + int fCount = d.Length - d.IndexOf('.') - 2; + formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z"; + } + else + { + formatStr = @"yyyyMMddHHmmss\Z"; + } + } + else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0) + { + d = GetTime(); + makeUniversal = true; + + if (HasFractionalSeconds) + { + int fCount = d.IndexOf("GMT") - 1 - d.IndexOf('.'); + formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz"; + } + else + { + formatStr = @"yyyyMMddHHmmss'GMT'zzz"; + } + } + else + { + if (HasFractionalSeconds) + { + int fCount = d.Length - 1 - d.IndexOf('.'); + formatStr = @"yyyyMMddHHmmss." + FString(fCount); + } + else + { + formatStr = @"yyyyMMddHHmmss"; + } + + // TODO? +// dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID())); + } + + return ParseDateString(d, formatStr, makeUniversal); + } + + private string FString( + int count) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < count; ++i) + { + sb.Append('f'); + } + return sb.ToString(); + } + + private DateTime ParseDateString( + string dateStr, + string formatStr, + bool makeUniversal) + { + DateTime dt = DateTime.ParseExact( + dateStr, + formatStr, + DateTimeFormatInfo.InvariantInfo); + + return makeUniversal ? dt.ToUniversalTime() : dt; + } + + private bool HasFractionalSeconds + { + get { return time.IndexOf('.') == 14; } + } + + private byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(time); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.GeneralizedTime, GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerGeneralizedTime other = asn1Object as DerGeneralizedTime; + + if (other == null) + return false; + + return this.time.Equals(other.time); + } + + protected override int Asn1GetHashCode() + { + return time.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerIA5String.cs b/iTechSharp/srcbc/asn1/DerIA5String.cs new file mode 100644 index 0000000..88f3bec --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerIA5String.cs @@ -0,0 +1,146 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der IA5String object - this is an ascii string. + */ + public class DerIA5String + : DerStringBase + { + private readonly string str; + + /** + * return a IA5 string from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerIA5String GetInstance( + object obj) + { + if (obj == null || obj is DerIA5String) + { + return (DerIA5String)obj; + } + + if (obj is Asn1OctetString) + { + return new DerIA5String(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an IA5 string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerIA5String GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - with bytes. + */ + public DerIA5String( + byte[] str) + : this(Encoding.ASCII.GetString(str, 0, str.Length), false) + { + } + + /** + * basic constructor - without validation. + */ + public DerIA5String( + string str) + : this(str, false) + { + } + + /** + * Constructor with optional validation. + * + * @param string the base string to wrap. + * @param validate whether or not to check the string. + * @throws ArgumentException if validate is true and the string + * contains characters that should not be in an IA5String. + */ + public DerIA5String( + string str, + bool validate) + { + if (str == null) + throw new ArgumentNullException("str"); + if (validate && !IsIA5String(str)) + throw new ArgumentException("string contains illegal characters", "str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + public byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(str); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.IA5String, GetOctets()); + } + + protected override int Asn1GetHashCode() + { + return this.str.GetHashCode(); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerIA5String other = asn1Object as DerIA5String; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + + /** + * return true if the passed in String can be represented without + * loss as an IA5String, false otherwise. + * + * @return true if in printable set, false otherwise. + */ + public static bool IsIA5String( + string str) + { + foreach (char ch in str) + { + if (ch > 0x007f) + { + return false; + } + } + + return true; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerInteger.cs b/iTechSharp/srcbc/asn1/DerInteger.cs new file mode 100644 index 0000000..03fd04d --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerInteger.cs @@ -0,0 +1,128 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerInteger + : Asn1Object + { + private readonly byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerInteger GetInstance( + object obj) + { + if (obj == null) + { + return null; + } + + DerInteger i = obj as DerInteger; + if (i != null) + { + return i; + } + + Asn1OctetString octs = obj as Asn1OctetString; + if (octs != null) + { + return new DerInteger(octs.GetOctets()); + } + + Asn1TaggedObject tagged = obj as Asn1TaggedObject; + if (tagged != null) + { + return GetInstance(tagged.GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an Integer from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerInteger GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + if (obj == null) + throw new ArgumentNullException("obj"); + + return GetInstance(obj.GetObject()); + } + + public DerInteger( + int value) + { + bytes = BigInteger.ValueOf(value).ToByteArray(); + } + + public DerInteger( + BigInteger value) + { + if (value == null) + throw new ArgumentNullException("value"); + + bytes = value.ToByteArray(); + } + + public DerInteger( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger Value + { + get { return new BigInteger(bytes); } + } + + /** + * in some cases positive values Get crammed into a space, + * that's not quite big enough... + */ + public BigInteger PositiveValue + { + get { return new BigInteger(1, bytes); } + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.Integer, bytes); + } + + protected override int Asn1GetHashCode() + { + return Arrays.GetHashCode(bytes); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerInteger other = asn1Object as DerInteger; + + if (other == null) + return false; + + return Arrays.AreEqual(this.bytes, other.bytes); + } + + public override string ToString() + { + return Value.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerNull.cs b/iTechSharp/srcbc/asn1/DerNull.cs new file mode 100644 index 0000000..a802f64 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerNull.cs @@ -0,0 +1,41 @@ +using System; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * A Null object. + */ + public class DerNull + : Asn1Null + { + public static readonly DerNull Instance = new DerNull(0); + + byte[] zeroBytes = new byte[0]; + + [Obsolete("Use static Instance object")] + public DerNull() + { + } + + protected internal DerNull(int dummy) + { + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.Null, zeroBytes); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + return asn1Object is DerNull; + } + + protected override int Asn1GetHashCode() + { + return -1; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerNumericString.cs b/iTechSharp/srcbc/asn1/DerNumericString.cs new file mode 100644 index 0000000..bff9ba7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerNumericString.cs @@ -0,0 +1,139 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. + */ + public class DerNumericString + : DerStringBase + { + private readonly string str; + + /** + * return a Numeric string from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerNumericString GetInstance( + object obj) + { + if (obj == null || obj is DerNumericString) + { + return (DerNumericString)obj; + } + + if (obj is Asn1OctetString) + { + return new DerNumericString(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an Numeric string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerNumericString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - with bytes. + */ + public DerNumericString( + byte[] str) + : this(Encoding.ASCII.GetString(str, 0, str.Length), false) + { + } + + /** + * basic constructor - without validation.. + */ + public DerNumericString( + string str) + : this(str, false) + { + } + + /** + * Constructor with optional validation. + * + * @param string the base string to wrap. + * @param validate whether or not to check the string. + * @throws ArgumentException if validate is true and the string + * contains characters that should not be in a NumericString. + */ + public DerNumericString( + string str, + bool validate) + { + if (str == null) + throw new ArgumentNullException("str"); + if (validate && !IsNumericString(str)) + throw new ArgumentException("string contains illegal characters", "str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + public byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(str); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.NumericString, GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerNumericString other = asn1Object as DerNumericString; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + + /** + * Return true if the string can be represented as a NumericString ('0'..'9', ' ') + * + * @param str string to validate. + * @return true if numeric, fale otherwise. + */ + public static bool IsNumericString( + string str) + { + foreach (char ch in str) + { + if (ch > 0x007f || (ch != ' ' && !char.IsDigit(ch))) + return false; + } + + return true; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerObjectIdentifier.cs b/iTechSharp/srcbc/asn1/DerObjectIdentifier.cs new file mode 100644 index 0000000..a6b0981 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerObjectIdentifier.cs @@ -0,0 +1,260 @@ +using System; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerObjectIdentifier + : Asn1Object + { + private static readonly Regex OidRegex = new Regex(@"\A[0-2](\.[0-9]+)+\z"); + + private readonly string identifier; + + /** + * return an Oid from the passed in object + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerObjectIdentifier GetInstance( + object obj) + { + if (obj == null || obj is DerObjectIdentifier) + { + return (DerObjectIdentifier) obj; + } + + if (obj is Asn1OctetString) + { + return new DerObjectIdentifier(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj"); + } + + /** + * return an object Identifier from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerObjectIdentifier GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public DerObjectIdentifier( + string identifier) + { + if (identifier == null) + throw new ArgumentNullException("identifier"); + if (!OidRegex.IsMatch(identifier)) + throw new FormatException("string " + identifier + " not an OID"); + + this.identifier = identifier; + } + + // TODO Change to ID? + public string Id + { + get { return identifier; } + } + + internal DerObjectIdentifier( + byte[] bytes) + : this(MakeOidStringFromBytes(bytes)) + { + } + + private void WriteField( + Stream outputStream, + long fieldValue) + { + if (fieldValue >= (1L << 7)) + { + if (fieldValue >= (1L << 14)) + { + if (fieldValue >= (1L << 21)) + { + if (fieldValue >= (1L << 28)) + { + if (fieldValue >= (1L << 35)) + { + if (fieldValue >= (1L << 42)) + { + if (fieldValue >= (1L << 49)) + { + if (fieldValue >= (1L << 56)) + { + outputStream.WriteByte((byte)((fieldValue >> 56) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 49) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 42) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 35) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 28) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 21) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 14) | 0x80)); + } + outputStream.WriteByte((byte)((fieldValue >> 7) | 0x80)); + } + outputStream.WriteByte((byte)(fieldValue & 0x7f)); + } + + private void WriteField( + Stream outputStream, + BigInteger fieldValue) + { + int byteCount = (fieldValue.BitLength + 6) / 7; + if (byteCount == 0) + { + outputStream.WriteByte(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount-1; i >= 0; i--) + { + tmp[i] = (byte) ((tmpValue.IntValue & 0x7f) | 0x80); + tmpValue = tmpValue.ShiftRight(7); + } + tmp[byteCount-1] &= 0x7f; + outputStream.Write(tmp, 0, tmp.Length); + } + } + + internal override void Encode( + DerOutputStream derOut) + { + OidTokenizer tok = new OidTokenizer(identifier); + MemoryStream bOut = new MemoryStream(); + DerOutputStream dOut = new DerOutputStream(bOut); + + string token = tok.NextToken(); + int first = int.Parse(token); + + token = tok.NextToken(); + int second = int.Parse(token); + + WriteField(bOut, first * 40 + second); + + while (tok.HasMoreTokens) + { + token = tok.NextToken(); + if (token.Length < 18) + { + WriteField(bOut, Int64.Parse(token)); + } + else + { + WriteField(bOut, new BigInteger(token)); + } + } + + dOut.Close(); + + derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, bOut.ToArray()); + } + + protected override int Asn1GetHashCode() + { + return identifier.GetHashCode(); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerObjectIdentifier other = asn1Object as DerObjectIdentifier; + + if (other == null) + return false; + + return this.identifier.Equals(other.identifier); + } + + public override string ToString() + { + return identifier; + } + + private static string MakeOidStringFromBytes( + byte[] bytes) + { + StringBuilder objId = new StringBuilder(); + long value = 0; + BigInteger bigValue = null; + bool first = true; + + for (int i = 0; i != bytes.Length; i++) + { + int b = bytes[i]; + + if (value < 0x80000000000000L) + { + value = value * 128 + (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + switch ((int)value / 40) + { + case 0: + objId.Append('0'); + break; + case 1: + objId.Append('1'); + value -= 40; + break; + default: + objId.Append('2'); + value -= 80; + break; + } + first = false; + } + + objId.Append('.'); + objId.Append(value); + value = 0; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.ValueOf(value); + } + bigValue = bigValue.ShiftLeft(7); + bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f)); + if ((b & 0x80) == 0) + { + objId.Append('.'); + objId.Append(bigValue); + bigValue = null; + value = 0; + } + } + } + + return objId.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerOctetString.cs b/iTechSharp/srcbc/asn1/DerOctetString.cs new file mode 100644 index 0000000..c046c94 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerOctetString.cs @@ -0,0 +1,34 @@ +namespace Org.BouncyCastle.Asn1 +{ + public class DerOctetString + : Asn1OctetString + { + /// The octets making up the octet string. + public DerOctetString( + byte[] str) + : base(str) + { + } + + public DerOctetString( + Asn1Encodable obj) + : base(obj) + { + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.OctetString, str); + } + + internal static void Encode( + DerOutputStream derOut, + byte[] bytes, + int offset, + int length) + { + derOut.WriteEncoded(Asn1Tags.OctetString, bytes, offset, length); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerOutputStream.cs b/iTechSharp/srcbc/asn1/DerOutputStream.cs new file mode 100644 index 0000000..da4bd06 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerOutputStream.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerOutputStream + : FilterStream + { + public DerOutputStream(Stream os) + : base(os) + { + } + + private void WriteLength( + int length) + { + if (length > 127) + { + int size = 1; + uint val = (uint) length; + + while ((val >>= 8) != 0) + { + size++; + } + + WriteByte((byte)(size | 0x80)); + + for (int i = (size - 1) * 8; i >= 0; i -= 8) + { + WriteByte((byte)(length >> i)); + } + } + else + { + WriteByte((byte)length); + } + } + + internal void WriteEncoded( + int tag, + byte[] bytes) + { + WriteByte((byte) tag); + WriteLength(bytes.Length); + Write(bytes, 0, bytes.Length); + } + + internal void WriteEncoded( + int tag, + byte[] bytes, + int offset, + int length) + { + WriteByte((byte) tag); + WriteLength(length); + Write(bytes, offset, length); + } + + internal void WriteTag( + int flags, + int tagNo) + { + if (tagNo < 31) + { + WriteByte((byte)(flags | tagNo)); + } + else + { + WriteByte((byte)(flags | 0x1f)); + if (tagNo < 128) + { + WriteByte((byte)tagNo); + } + else + { + byte[] stack = new byte[5]; + int pos = stack.Length; + + stack[--pos] = (byte)(tagNo & 0x7F); + + do + { + tagNo >>= 7; + stack[--pos] = (byte)(tagNo & 0x7F | 0x80); + } + while (tagNo > 127); + + Write(stack, pos, stack.Length - pos); + } + } + } + + internal void WriteEncoded( + int flags, + int tagNo, + byte[] bytes) + { + WriteTag(flags, tagNo); + WriteLength(bytes.Length); + Write(bytes, 0, bytes.Length); + } + + protected void WriteNull() + { + WriteByte(Asn1Tags.Null); + WriteByte(0x00); + } + + [Obsolete("Use version taking an Asn1Encodable arg instead")] + public virtual void WriteObject( + object obj) + { + if (obj == null) + { + WriteNull(); + } + else if (obj is Asn1Object) + { + ((Asn1Object)obj).Encode(this); + } + else if (obj is Asn1Encodable) + { + ((Asn1Encodable)obj).ToAsn1Object().Encode(this); + } + else + { + throw new IOException("object not Asn1Object"); + } + } + + public virtual void WriteObject( + Asn1Encodable obj) + { + if (obj == null) + { + WriteNull(); + } + else + { + obj.ToAsn1Object().Encode(this); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerPrintableString.cs b/iTechSharp/srcbc/asn1/DerPrintableString.cs new file mode 100644 index 0000000..b91b918 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerPrintableString.cs @@ -0,0 +1,164 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der PrintableString object. + */ + public class DerPrintableString + : DerStringBase + { + private readonly string str; + + /** + * return a printable string from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerPrintableString GetInstance( + object obj) + { + if (obj == null || obj is DerPrintableString) + { + return (DerPrintableString)obj; + } + + if (obj is Asn1OctetString) + { + return new DerPrintableString(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return a Printable string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerPrintableString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - byte encoded string. + */ + public DerPrintableString( + byte[] str) + : this(Encoding.ASCII.GetString(str, 0, str.Length), false) + { + } + + /** + * basic constructor - this does not validate the string + */ + public DerPrintableString( + string str) + : this(str, false) + { + } + + /** + * Constructor with optional validation. + * + * @param string the base string to wrap. + * @param validate whether or not to check the string. + * @throws ArgumentException if validate is true and the string + * contains characters that should not be in a PrintableString. + */ + public DerPrintableString( + string str, + bool validate) + { + if (str == null) + throw new ArgumentNullException("str"); + if (validate && !IsPrintableString(str)) + throw new ArgumentException("string contains illegal characters", "str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + public byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(str); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.PrintableString, GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerPrintableString other = asn1Object as DerPrintableString; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + + /** + * return true if the passed in String can be represented without + * loss as a PrintableString, false otherwise. + * + * @return true if in printable set, false otherwise. + */ + public static bool IsPrintableString( + string str) + { + foreach (char ch in str) + { + if (ch > 0x007f) + return false; + + if (char.IsLetterOrDigit(ch)) + continue; + +// if (char.IsPunctuation(ch)) +// continue; + + switch (ch) + { + case ' ': + case '\'': + case '(': + case ')': + case '+': + case '-': + case '.': + case ':': + case '=': + case '?': + case '/': + case ',': + continue; + } + + return false; + } + + return true; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerSequence.cs b/iTechSharp/srcbc/asn1/DerSequence.cs new file mode 100644 index 0000000..b50a779 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerSequence.cs @@ -0,0 +1,85 @@ +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class DerSequence + : Asn1Sequence + { + public static readonly DerSequence Empty = new DerSequence(); + + public static DerSequence FromVector( + Asn1EncodableVector v) + { + return v.Count < 1 ? Empty : new DerSequence(v); + } + + /** + * create an empty sequence + */ + public DerSequence() + : base(0) + { + } + + /** + * create a sequence containing one object + */ + public DerSequence( + Asn1Encodable obj) + : base(1) + { + AddObject(obj); + } + + public DerSequence( + params Asn1Encodable[] v) + : base(v.Length) + { + foreach (Asn1Encodable ae in v) + { + AddObject(ae); + } + } + + /** + * create a sequence containing a vector of objects. + */ + public DerSequence( + Asn1EncodableVector v) + : base(v.Count) + { + foreach (Asn1Encodable ae in v) + { + AddObject(ae); + } + } + + /* + * A note on the implementation: + *

      + * As Der requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputing Sequence, + * we also have to specify Constructed, and the objects length. + */ + internal override void Encode( + DerOutputStream derOut) + { + // TODO Intermediate buffer could be avoided if we could calculate expected length + MemoryStream bOut = new MemoryStream(); + DerOutputStream dOut = new DerOutputStream(bOut); + + foreach (Asn1Encodable obj in this) + { + dOut.WriteObject(obj); + } + + dOut.Close(); + + byte[] bytes = bOut.ToArray(); + + derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, bytes); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerSet.cs b/iTechSharp/srcbc/asn1/DerSet.cs new file mode 100644 index 0000000..c66dde8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerSet.cs @@ -0,0 +1,108 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * A Der encoded set object + */ + public class DerSet + : Asn1Set + { + public static readonly DerSet Empty = new DerSet(); + + public static DerSet FromVector( + Asn1EncodableVector v) + { + return v.Count < 1 ? Empty : new DerSet(v); + } + + internal static DerSet FromVector( + Asn1EncodableVector v, + bool needsSorting) + { + return v.Count < 1 ? Empty : new DerSet(v, needsSorting); + } + + /** + * create an empty set + */ + public DerSet() + : base(0) + { + } + + /** + * @param obj - a single object that makes up the set. + */ + public DerSet( + Asn1Encodable obj) + : base(1) + { + AddObject(obj); + } + + public DerSet( + params Asn1Encodable[] v) + : base(v.Length) + { + foreach (Asn1Encodable o in v) + { + AddObject(o); + } + + Sort(); + } + + /** + * @param v - a vector of objects making up the set. + */ + public DerSet( + Asn1EncodableVector v) + : this(v, true) + { + } + + internal DerSet( + Asn1EncodableVector v, + bool needsSorting) + : base(v.Count) + { + foreach (Asn1Encodable o in v) + { + AddObject(o); + } + + if (needsSorting) + { + Sort(); + } + } + + /* + * A note on the implementation: + *

      + * As Der requires the constructed, definite-length model to + * be used for structured types, this varies slightly from the + * ASN.1 descriptions given. Rather than just outputing Set, + * we also have to specify Constructed, and the objects length. + */ + internal override void Encode( + DerOutputStream derOut) + { + // TODO Intermediate buffer could be avoided if we could calculate expected length + MemoryStream bOut = new MemoryStream(); + DerOutputStream dOut = new DerOutputStream(bOut); + + foreach (Asn1Encodable obj in this) + { + dOut.WriteObject(obj); + } + + dOut.Close(); + + byte[] bytes = bOut.ToArray(); + + derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, bytes); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerStringBase.cs b/iTechSharp/srcbc/asn1/DerStringBase.cs new file mode 100644 index 0000000..2a5fb04 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerStringBase.cs @@ -0,0 +1,22 @@ +namespace Org.BouncyCastle.Asn1 +{ + public abstract class DerStringBase + : Asn1Object, IAsn1String + { + protected DerStringBase() + { + } + + public abstract string GetString(); + + public override string ToString() + { + return GetString(); + } + + protected override int Asn1GetHashCode() + { + return GetString().GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerT61String.cs b/iTechSharp/srcbc/asn1/DerT61String.cs new file mode 100644 index 0000000..3d20518 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerT61String.cs @@ -0,0 +1,105 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der T61String (also the teletex string) - 8-bit characters + */ + public class DerT61String + : DerStringBase + { + private readonly string str; + + /** + * return a T61 string from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerT61String GetInstance( + object obj) + { + if (obj == null || obj is DerT61String) + { + return (DerT61String)obj; + } + + if (obj is Asn1OctetString) + { + return new DerT61String(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an T61 string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerT61String GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - with bytes. + */ + public DerT61String( + byte[] str) + : this(Strings.FromByteArray(str)) + { + } + + /** + * basic constructor - with string. + */ + public DerT61String( + string str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.T61String, GetOctets()); + } + + public byte[] GetOctets() + { + return Strings.ToByteArray(str); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerT61String other = asn1Object as DerT61String; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerTaggedObject.cs b/iTechSharp/srcbc/asn1/DerTaggedObject.cs new file mode 100644 index 0000000..717d724 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerTaggedObject.cs @@ -0,0 +1,72 @@ +namespace Org.BouncyCastle.Asn1 +{ + /** + * DER TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ + public class DerTaggedObject + : Asn1TaggedObject + { + /** + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public DerTaggedObject( + int tagNo, + Asn1Encodable obj) + : base(tagNo, obj) + { + } + + /** + * @param explicitly true if an explicitly tagged object. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public DerTaggedObject( + bool explicitly, + int tagNo, + Asn1Encodable obj) + : base(explicitly, tagNo, obj) + { + } + + /** + * create an implicitly tagged object that contains a zero + * length sequence. + */ + public DerTaggedObject( + int tagNo) + : base(false, tagNo, DerSequence.Empty) + { + } + + internal override void Encode( + DerOutputStream derOut) + { + if (!IsEmpty()) + { + byte[] bytes = obj.GetDerEncoded(); + + if (explicitly) + { + derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, bytes); + } + else + { + // + // need to mark constructed types... (preserve Constructed tag) + // + int flags = (bytes[0] & Asn1Tags.Constructed) | Asn1Tags.Tagged; + derOut.WriteTag(flags, tagNo); + derOut.Write(bytes, 1, bytes.Length - 1); + } + } + else + { + derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, new byte[0]); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerUTCTime.cs b/iTechSharp/srcbc/asn1/DerUTCTime.cs new file mode 100644 index 0000000..4141856 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerUTCTime.cs @@ -0,0 +1,259 @@ +using System; +using System.Globalization; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * UTC time object. + */ + public class DerUtcTime + : Asn1Object + { + private readonly string time; + + /** + * return an UTC Time from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerUtcTime GetInstance( + object obj) + { + if (obj == null || obj is DerUtcTime) + { + return (DerUtcTime)obj; + } + + if (obj is Asn1OctetString) + { + return new DerUtcTime(((Asn1OctetString)obj).GetOctets()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an UTC Time from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerUtcTime GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were + * never encoded. When you're creating one of these objects from scratch, that's + * what you want to use, otherwise we'll try to deal with whatever Gets read from + * the input stream... (this is why the input format is different from the GetTime() + * method output). + *

      + * @param time the time string.

      + */ + public DerUtcTime( + string time) + { + if (time == null) + throw new ArgumentNullException("time"); + + this.time = time; + + try + { + ToDateTime(); + } + catch (FormatException e) + { + throw new ArgumentException("invalid date string: " + e.Message); + } + } + + /** + * base constructor from a DateTime object + */ + public DerUtcTime( + DateTime time) + { + this.time = time.ToString("yyMMddHHmmss") + "Z"; + } + + internal DerUtcTime( + byte[] bytes) + { + // + // explicitly convert to characters + // + this.time = Encoding.ASCII.GetString(bytes, 0, bytes.Length); + } + +// public DateTime ToDateTime() +// { +// string tm = this.AdjustedTimeString; +// +// return new DateTime( +// Int16.Parse(tm.Substring(0, 4)), +// Int16.Parse(tm.Substring(4, 2)), +// Int16.Parse(tm.Substring(6, 2)), +// Int16.Parse(tm.Substring(8, 2)), +// Int16.Parse(tm.Substring(10, 2)), +// Int16.Parse(tm.Substring(12, 2))); +// } + + /** + * return the time as a date based on whatever a 2 digit year will return. For + * standardised processing use ToAdjustedDateTime(). + * + * @return the resulting date + * @exception ParseException if the date string cannot be parsed. + */ + public DateTime ToDateTime() + { + return ParseDateString(TimeString, @"yyMMddHHmmss'GMT'zzz"); + } + + /** + * return the time as an adjusted date + * in the range of 1950 - 2049. + * + * @return a date in the range of 1950 to 2049. + * @exception ParseException if the date string cannot be parsed. + */ + public DateTime ToAdjustedDateTime() + { + return ParseDateString(AdjustedTimeString, @"yyyyMMddHHmmss'GMT'zzz"); + } + + private DateTime ParseDateString( + string dateStr, + string formatStr) + { + DateTime dt = DateTime.ParseExact( + dateStr, + formatStr, + DateTimeFormatInfo.InvariantInfo); + + return dt.ToUniversalTime(); + } + + /** + * return the time - always in the form of + * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). + *

      + * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *

      +         *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
      +         * 
      + * To read in the time and Get a date which is compatible with our local + * time zone.

      + *

      + * Note: In some cases, due to the local date processing, this + * may lead to unexpected results. If you want to stick the normal + * convention of 1950 to 2049 use the GetAdjustedTime() method.

      + */ + public string TimeString + { + get + { + // + // standardise the format. + // + if (time.IndexOf('-') < 0 && time.IndexOf('+') < 0) + { + if (time.Length == 11) + { + return time.Substring(0, 10) + "00GMT+00:00"; + } + else + { + return time.Substring(0, 12) + "GMT+00:00"; + } + } + else + { + int index = time.IndexOf('-'); + if (index < 0) + { + index = time.IndexOf('+'); + } + string d = time; + + if (index == time.Length - 3) + { + d += "00"; + } + + if (index == 10) + { + return d.Substring(0, 10) + "00GMT" + d.Substring(10, 3) + ":" + d.Substring(13, 2); + } + else + { + return d.Substring(0, 12) + "GMT" + d.Substring(12, 3) + ":" + d.Substring(15, 2); + } + } + } + } + + [Obsolete("Use 'AdjustedTimeString' property instead")] + public string AdjustedTime + { + get { return AdjustedTimeString; } + } + + /// + /// Return a time string as an adjusted date with a 4 digit year. + /// This goes in the range of 1950 - 2049. + /// + public string AdjustedTimeString + { + get + { + string d = TimeString; + string c = d[0] < '5' ? "20" : "19"; + + return c + d; + } + } + + private byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(time); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.UtcTime, GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerUtcTime other = asn1Object as DerUtcTime; + + if (other == null) + return false; + + return this.time.Equals(other.time); + } + + protected override int Asn1GetHashCode() + { + return time.GetHashCode(); + } + + public override string ToString() + { + return time; + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerUTF8String.cs b/iTechSharp/srcbc/asn1/DerUTF8String.cs new file mode 100644 index 0000000..9a85d4d --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerUTF8String.cs @@ -0,0 +1,99 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der UTF8String object. + */ + public class DerUtf8String + : DerStringBase + { + private readonly string str; + + /** + * return an UTF8 string from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerUtf8String GetInstance( + object obj) + { + if (obj == null || obj is DerUtf8String) + { + return (DerUtf8String)obj; + } + + if (obj is Asn1OctetString) + { + return new DerUtf8String(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return an UTF8 string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerUtf8String GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - byte encoded string. + */ + internal DerUtf8String( + byte[] str) + : this(Encoding.UTF8.GetString(str, 0, str.Length)) + { + } + + /** + * basic constructor + */ + public DerUtf8String( + string str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerUtf8String other = asn1Object as DerUtf8String; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.Utf8String, Encoding.UTF8.GetBytes(str)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerUniversalString.cs b/iTechSharp/srcbc/asn1/DerUniversalString.cs new file mode 100644 index 0000000..4dee536 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerUniversalString.cs @@ -0,0 +1,105 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der UniversalString object. + */ + public class DerUniversalString + : DerStringBase + { + private static readonly char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + private readonly byte[] str; + + /** + * return a Universal string from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerUniversalString GetInstance( + object obj) + { + if (obj == null || obj is DerUniversalString) + { + return (DerUniversalString)obj; + } + + if (obj is Asn1OctetString) + { + return new DerUniversalString(((Asn1OctetString)obj).GetOctets()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return a Universal string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerUniversalString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - byte encoded string. + */ + public DerUniversalString( + byte[] str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + public override string GetString() + { + StringBuilder buffer = new StringBuilder("#"); + byte[] enc = GetDerEncoded(); + + for (int i = 0; i != enc.Length; i++) + { + uint ubyte = enc[i]; + buffer.Append(table[(ubyte >> 4) & 0xf]); + buffer.Append(table[enc[i] & 0xf]); + } + + return buffer.ToString(); + } + + public byte[] GetOctets() + { + return (byte[]) str.Clone(); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.UniversalString, this.str); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerUniversalString other = asn1Object as DerUniversalString; + + if (other == null) + return false; + +// return this.GetString().Equals(other.GetString()); + return Arrays.AreEqual(this.str, other.str); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerUnknownTag.cs b/iTechSharp/srcbc/asn1/DerUnknownTag.cs new file mode 100644 index 0000000..4566524 --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerUnknownTag.cs @@ -0,0 +1,64 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * We insert one of these when we find a tag we don't recognise. + */ + public class DerUnknownTag + : Asn1Object + { + private readonly int tag; + private readonly byte[] data; + + /** + * @param tag the tag value. + * @param data the contents octets. + */ + public DerUnknownTag( + int tag, + byte[] data) + { + if (data == null) + throw new ArgumentNullException("data"); + + this.tag = tag; + this.data = data; + } + + public int Tag + { + get { return tag; } + } + + public byte[] GetData() + { + return data; + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(tag, data); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerUnknownTag other = asn1Object as DerUnknownTag; + + if (other == null) + return false; + + return this.tag == other.tag + && Arrays.AreEqual(this.data, other.data); + } + + protected override int Asn1GetHashCode() + { + return tag.GetHashCode() ^ Arrays.GetHashCode(data); + } + } +} diff --git a/iTechSharp/srcbc/asn1/DerVisibleString.cs b/iTechSharp/srcbc/asn1/DerVisibleString.cs new file mode 100644 index 0000000..b0a25cf --- /dev/null +++ b/iTechSharp/srcbc/asn1/DerVisibleString.cs @@ -0,0 +1,109 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Der VisibleString object. + */ + public class DerVisibleString + : DerStringBase + { + private readonly string str; + + /** + * return a Visible string from the passed in object. + * + * @exception ArgumentException if the object cannot be converted. + */ + public static DerVisibleString GetInstance( + object obj) + { + if (obj == null || obj is DerVisibleString) + { + return (DerVisibleString)obj; + } + + if (obj is Asn1OctetString) + { + return new DerVisibleString(((Asn1OctetString)obj).GetOctets()); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject)obj).GetObject()); + } + + throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name); + } + + /** + * return a Visible string from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the tagged object cannot + * be converted. + */ + public static DerVisibleString GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + /** + * basic constructor - byte encoded string. + */ + public DerVisibleString( + byte[] str) + : this(Encoding.ASCII.GetString(str, 0, str.Length)) + { + } + + /** + * basic constructor + */ + public DerVisibleString( + string str) + { + if (str == null) + throw new ArgumentNullException("str"); + + this.str = str; + } + + public override string GetString() + { + return str; + } + + public byte[] GetOctets() + { + return Encoding.ASCII.GetBytes(str); + } + + internal override void Encode( + DerOutputStream derOut) + { + derOut.WriteEncoded(Asn1Tags.VisibleString, GetOctets()); + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + DerVisibleString other = asn1Object as DerVisibleString; + + if (other == null) + return false; + + return this.str.Equals(other.str); + } + + protected override int Asn1GetHashCode() + { + return this.str.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/IAsn1Convertible.cs b/iTechSharp/srcbc/asn1/IAsn1Convertible.cs new file mode 100644 index 0000000..d3f83af --- /dev/null +++ b/iTechSharp/srcbc/asn1/IAsn1Convertible.cs @@ -0,0 +1,7 @@ +namespace Org.BouncyCastle.Asn1 +{ + public interface IAsn1Convertible + { + Asn1Object ToAsn1Object(); + } +} diff --git a/iTechSharp/srcbc/asn1/IAsn1String.cs b/iTechSharp/srcbc/asn1/IAsn1String.cs new file mode 100644 index 0000000..cbc2635 --- /dev/null +++ b/iTechSharp/srcbc/asn1/IAsn1String.cs @@ -0,0 +1,10 @@ +namespace Org.BouncyCastle.Asn1 +{ + /** + * basic interface for Der string objects. + */ + public interface IAsn1String + { + string GetString(); + } +} diff --git a/iTechSharp/srcbc/asn1/IndefiniteLengthInputStream.cs b/iTechSharp/srcbc/asn1/IndefiniteLengthInputStream.cs new file mode 100644 index 0000000..ab361e0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/IndefiniteLengthInputStream.cs @@ -0,0 +1,95 @@ +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + class IndefiniteLengthInputStream + : LimitedInputStream + { + private int _b1; + private int _b2; + private bool _eofReached = false; + private bool _eofOn00 = true; + + internal IndefiniteLengthInputStream( + Stream inStream) + : base(inStream) + { + _b1 = inStream.ReadByte(); + _b2 = inStream.ReadByte(); + _eofReached = (_b2 < 0); + } + + internal void SetEofOn00( + bool eofOn00) + { + _eofOn00 = eofOn00; + } + + internal bool CheckForEof() + { + if (_eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) + { + _eofReached = true; + SetParentEofDetect(true); + } + + return _eofReached; + } + + public override int Read( + byte[] buffer, + int offset, + int count) + { + // Only use this optimisation if we aren't checking for 00 + if (_eofOn00 || count < 3) + return base.Read(buffer, offset, count); + + if (_eofReached) + return 0; + + int numRead = _in.Read(buffer, offset + 2, count - 2); + + if (numRead <= 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + buffer[offset] = (byte)_b1; + buffer[offset + 1] = (byte)_b2; + + _b1 = _in.ReadByte(); + _b2 = _in.ReadByte(); + + if (_b2 < 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + return numRead + 2; + } + + public override int ReadByte() + { + if (CheckForEof()) + return -1; + + int b = _in.ReadByte(); + + if (b < 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + int v = _b1; + + _b1 = _b2; + _b2 = b; + + return v; + } + } +} diff --git a/iTechSharp/srcbc/asn1/LazyASN1InputStream.cs b/iTechSharp/srcbc/asn1/LazyASN1InputStream.cs new file mode 100644 index 0000000..4cf2305 --- /dev/null +++ b/iTechSharp/srcbc/asn1/LazyASN1InputStream.cs @@ -0,0 +1,33 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + public class LazyAsn1InputStream + : Asn1InputStream + { + public LazyAsn1InputStream( + byte[] input) + : base(input) + { + } + + public LazyAsn1InputStream( + Stream inputStream) + : base(inputStream) + { + } + + internal override DerSequence CreateDerSequence( + DefiniteLengthInputStream dIn) + { + return new LazyDerSequence(dIn.ToArray()); + } + + internal override DerSet CreateDerSet( + DefiniteLengthInputStream dIn) + { + return new LazyDerSet(dIn.ToArray()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/LazyDERSequence.cs b/iTechSharp/srcbc/asn1/LazyDERSequence.cs new file mode 100644 index 0000000..e20f76b --- /dev/null +++ b/iTechSharp/srcbc/asn1/LazyDERSequence.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; +using System.Diagnostics; + +namespace Org.BouncyCastle.Asn1 +{ + internal class LazyDerSequence + : DerSequence + { + private byte[] encoded; + private bool parsed = false; + + internal LazyDerSequence( + byte[] encoded) + { + this.encoded = encoded; + } + + private void Parse() + { + Debug.Assert(parsed == false); + + Asn1InputStream e = new LazyAsn1InputStream(encoded); + + Asn1Object o; + while ((o = e.ReadObject()) != null) + { + AddObject(o); + } + + encoded = null; + parsed = true; + } + + public override Asn1Encodable this[int index] + { + get + { + if (!parsed) + { + Parse(); + } + + return base[index]; + } + } + + public override IEnumerator GetEnumerator() + { + if (!parsed) + { + Parse(); + } + + return base.GetEnumerator(); + } + + public override int Count + { + get + { + if (!parsed) + { + Parse(); + } + + return base.Count; + } + } + + internal override void Encode( + DerOutputStream derOut) + { + if (parsed) + { + base.Encode(derOut); + } + else + { + derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, encoded); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/LazyDERSet.cs b/iTechSharp/srcbc/asn1/LazyDERSet.cs new file mode 100644 index 0000000..31bf441 --- /dev/null +++ b/iTechSharp/srcbc/asn1/LazyDERSet.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; +using System.Diagnostics; + +namespace Org.BouncyCastle.Asn1 +{ + internal class LazyDerSet + : DerSet + { + private byte[] encoded; + private bool parsed = false; + + internal LazyDerSet( + byte[] encoded) + { + this.encoded = encoded; + } + + private void Parse() + { + Debug.Assert(parsed == false); + + Asn1InputStream e = new LazyAsn1InputStream(encoded); + + Asn1Object o; + while ((o = e.ReadObject()) != null) + { + AddObject(o); + } + + encoded = null; + parsed = true; + } + + public override Asn1Encodable this[int index] + { + get + { + if (!parsed) + { + Parse(); + } + + return base[index]; + } + } + + public override IEnumerator GetEnumerator() + { + if (!parsed) + { + Parse(); + } + + return base.GetEnumerator(); + } + + public override int Count + { + get + { + if (!parsed) + { + Parse(); + } + + return base.Count; + } + } + + internal override void Encode( + DerOutputStream derOut) + { + if (parsed) + { + base.Encode(derOut); + } + else + { + derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, encoded); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/LimitedInputStream.cs b/iTechSharp/srcbc/asn1/LimitedInputStream.cs new file mode 100644 index 0000000..0cb0a31 --- /dev/null +++ b/iTechSharp/srcbc/asn1/LimitedInputStream.cs @@ -0,0 +1,26 @@ +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + internal abstract class LimitedInputStream + : BaseInputStream + { + protected readonly Stream _in; + + internal LimitedInputStream( + Stream inStream) + { + this._in = inStream; + } + + protected virtual void SetParentEofDetect(bool on) + { + if (_in is IndefiniteLengthInputStream) + { + ((IndefiniteLengthInputStream)_in).SetEofOn00(on); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/OidTokenizer.cs b/iTechSharp/srcbc/asn1/OidTokenizer.cs new file mode 100644 index 0000000..6e76e8c --- /dev/null +++ b/iTechSharp/srcbc/asn1/OidTokenizer.cs @@ -0,0 +1,45 @@ +namespace Org.BouncyCastle.Asn1 +{ + /** + * class for breaking up an Oid into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + */ + public class OidTokenizer + { + private string oid; + private int index; + + public OidTokenizer( + string oid) + { + this.oid = oid; + } + + public bool HasMoreTokens + { + get { return index != -1; } + } + + public string NextToken() + { + if (index == -1) + { + return null; + } + + int end = oid.IndexOf('.', index); + if (end == -1) + { + string lastToken = oid.Substring(index); + index = -1; + return lastToken; + } + + string nextToken = oid.Substring(index, end - index); + index = end + 1; + return nextToken; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cmp/PKIFailureInfo.cs b/iTechSharp/srcbc/asn1/cmp/PKIFailureInfo.cs new file mode 100644 index 0000000..1df0e06 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cmp/PKIFailureInfo.cs @@ -0,0 +1,73 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + /** + *
      +	 * PKIFailureInfo ::= BIT STRING {
      +	 * badAlg               (0),
      +	 *   -- unrecognized or unsupported Algorithm Identifier
      +	 * badMessageCheck      (1), -- integrity check failed (e.g., signature did not verify)
      +	 * badRequest           (2),
      +	 *   -- transaction not permitted or supported
      +	 * badTime              (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
      +	 * badCertId            (4), -- no certificate could be found matching the provided criteria
      +	 * badDataFormat        (5),
      +	 *   -- the data submitted has the wrong format
      +	 * wrongAuthority       (6), -- the authority indicated in the request is different from the one creating the response token
      +	 * incorrectData        (7), -- the requester's data is incorrect (for notary services)
      +	 * missingTimeStamp     (8), -- when the timestamp is missing but should be there (by policy)
      +	 * badPOP               (9)  -- the proof-of-possession failed
      +	 * timeNotAvailable    (14),
      +	 *   -- the TSA's time source is not available
      +	 * unacceptedPolicy    (15),
      +	 *   -- the requested TSA policy is not supported by the TSA
      +	 * unacceptedExtension (16),
      +	 *   -- the requested extension is not supported by the TSA
      +	 *  addInfoNotAvailable (17)
      +	 *    -- the additional information requested could not be understood
      +	 *    -- or is not available
      +	 *  systemFailure       (25)
      +	 *    -- the request cannot be handled due to system failure
      +	 * 
      + */ + public class PkiFailureInfo + : DerBitString + { + public const int BadAlg = (1 << 7); // unrecognized or unsupported Algorithm Identifier + public const int BadMessageCheck = (1 << 6); // integrity check failed (e.g., signature did not verify) + public const int BadRequest = (1 << 5); + public const int BadTime = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy + public const int BadCertId = (1 << 3); // no certificate could be found matching the provided criteria + public const int BadDataFormat = (1 << 2); + public const int WrongAuthority = (1 << 1); // the authority indicated in the request is different from the one creating the response token + public const int IncorrectData = 1; // the requester's data is incorrect (for notary services) + public const int MissingTimeStamp = (1 << 15); // when the timestamp is missing but should be there (by policy) + public const int BadPop = (1 << 14); // the proof-of-possession failed + public const int TimeNotAvailable = (1 << 9); // the TSA's time source is not available + public const int UnacceptedPolicy = (1 << 8); // the requested TSA policy is not supported by the TSA + public const int UnacceptedExtension = (1 << 23); //the requested extension is not supported by the TSA + public const int AddInfoNotAvailable = (1 << 22); //the additional information requested could not be understood or is not available + public const int SystemFailure = (1 << 30); //the request cannot be handled due to system failure + + /** + * Basic constructor. + */ + public PkiFailureInfo( + int info) + : base(GetBytes(info), GetPadBits(info)) + { + } + + public PkiFailureInfo( + DerBitString info) + : base(info.GetBytes(), info.PadBits) + { + } + + public override string ToString() + { + return "PkiFailureInfo: 0x" + this.IntValue.ToString("X"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cmp/PKIFreeText.cs b/iTechSharp/srcbc/asn1/cmp/PKIFreeText.cs new file mode 100644 index 0000000..571c8d9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cmp/PKIFreeText.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class PkiFreeText + : Asn1Encodable + { + internal Asn1Sequence strings; + + public static PkiFreeText GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + public static PkiFreeText GetInstance( + object obj) + { + if (obj is PkiFreeText) + { + return (PkiFreeText)obj; + } + else if (obj is Asn1Sequence) + { + return new PkiFreeText((Asn1Sequence)obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public PkiFreeText( + Asn1Sequence seq) + { + foreach (object o in seq) + { + if (!(o is DerUtf8String)) + { + throw new ArgumentException("attempt to insert non UTF8 STRING into PkiFreeText"); + } + } + + this.strings = seq; + } + + public PkiFreeText( + DerUtf8String p) + { + strings = new DerSequence(p); + } + + /** + * Return the number of string elements present. + * + * @return number of elements present. + */ + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return strings.Count; } + } + + public int Count + { + get { return strings.Count; } + } + + /** + * Return the UTF8STRING at index. + * + * @param index index of the string of interest + * @return the string at index. + */ + public DerUtf8String this[int index] + { + get { return (DerUtf8String) strings[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public DerUtf8String GetStringAt( + int index) + { + return this[index]; + } + + /** + *
      +		 * PkiFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + return strings; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cmp/PKIStatus.cs b/iTechSharp/srcbc/asn1/cmp/PKIStatus.cs new file mode 100644 index 0000000..c56380f --- /dev/null +++ b/iTechSharp/srcbc/asn1/cmp/PKIStatus.cs @@ -0,0 +1,14 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public enum PkiStatus + { + Granted = 0, + GrantedWithMods = 1, + Rejection = 2, + Waiting = 3, + RevocationWarning = 4, + RevocationNotification = 5, + } +} diff --git a/iTechSharp/srcbc/asn1/cmp/PKIStatusInfo.cs b/iTechSharp/srcbc/asn1/cmp/PKIStatusInfo.cs new file mode 100644 index 0000000..2463e00 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cmp/PKIStatusInfo.cs @@ -0,0 +1,165 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class PkiStatusInfo + : Asn1Encodable + { + DerInteger status; + PkiFreeText statusString; + DerBitString failInfo; + + public static PkiStatusInfo GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + public static PkiStatusInfo GetInstance( + object obj) + { + if (obj is PkiStatusInfo) + { + return (PkiStatusInfo)obj; + } + else if (obj is Asn1Sequence) + { + return new PkiStatusInfo((Asn1Sequence)obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public PkiStatusInfo( + Asn1Sequence seq) + { + this.status = DerInteger.GetInstance(seq[0]); + + this.statusString = null; + this.failInfo = null; + + if (seq.Count > 2) + { + this.statusString = PkiFreeText.GetInstance(seq[1]); + this.failInfo = DerBitString.GetInstance(seq[2]); + } + else if (seq.Count > 1) + { + object obj = seq[1]; + if (obj is DerBitString) + { + this.failInfo = DerBitString.GetInstance(obj); + } + else + { + this.statusString = PkiFreeText.GetInstance(obj); + } + } + } + + /** + * @param status + */ + public PkiStatusInfo(int status) + { + this.status = new DerInteger(status); + } + + /** + * @param status + * @param statusString + */ + public PkiStatusInfo( + int status, + PkiFreeText statusString) + { + this.status = new DerInteger(status); + this.statusString = statusString; + } + + public PkiStatusInfo( + int status, + PkiFreeText statusString, + PkiFailureInfo failInfo) + { + this.status = new DerInteger(status); + this.statusString = statusString; + this.failInfo = failInfo; + } + + public BigInteger Status + { + get + { + return status.Value; + } + } + + public PkiFreeText StatusString + { + get + { + return statusString; + } + } + + public DerBitString FailInfo + { + get + { + return failInfo; + } + } + + /** + *
      +		 * PkiStatusInfo ::= SEQUENCE {
      +		 *     status        PKIStatus,                (INTEGER)
      +		 *     statusString  PkiFreeText     OPTIONAL,
      +		 *     failInfo      PkiFailureInfo  OPTIONAL  (BIT STRING)
      +		 * }
      +		 *
      +		 * PKIStatus:
      +		 *   granted                (0), -- you got exactly what you asked for
      +		 *   grantedWithMods        (1), -- you got something like what you asked for
      +		 *   rejection              (2), -- you don't get it, more information elsewhere in the message
      +		 *   waiting                (3), -- the request body part has not yet been processed, expect to hear more later
      +		 *   revocationWarning      (4), -- this message contains a warning that a revocation is imminent
      +		 *   revocationNotification (5), -- notification that a revocation has occurred
      +		 *   keyUpdateWarning       (6)  -- update already done for the oldCertId specified in CertReqMsg
      +		 *
      +		 * PkiFailureInfo:
      +		 *   badAlg           (0), -- unrecognized or unsupported Algorithm Identifier
      +		 *   badMessageCheck  (1), -- integrity check failed (e.g., signature did not verify)
      +		 *   badRequest       (2), -- transaction not permitted or supported
      +		 *   badTime          (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
      +		 *   badCertId        (4), -- no certificate could be found matching the provided criteria
      +		 *   badDataFormat    (5), -- the data submitted has the wrong format
      +		 *   wrongAuthority   (6), -- the authority indicated in the request is different from the one creating the response token
      +		 *   incorrectData    (7), -- the requester's data is incorrect (for notary services)
      +		 *   missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy)
      +		 *   badPOP           (9)  -- the proof-of-possession failed
      +		 *
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(status); + + if (statusString != null) + { + v.Add(statusString); + } + + if (failInfo!= null) + { + v.Add(failInfo); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/Attribute.cs b/iTechSharp/srcbc/asn1/cms/Attribute.cs new file mode 100644 index 0000000..bfdd1d4 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/Attribute.cs @@ -0,0 +1,68 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class Attribute + : Asn1Encodable + { + private DerObjectIdentifier attrType; + private Asn1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static Attribute GetInstance( + object obj) + { + if (obj == null || obj is Attribute) + { + return (Attribute) obj; + } + + if (obj is Asn1Sequence) + { + return new Attribute((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public Attribute( + Asn1Sequence seq) + { + attrType = (DerObjectIdentifier)seq[0]; + attrValues = (Asn1Set)seq[1]; + } + + public Attribute( + DerObjectIdentifier attrType, + Asn1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public DerObjectIdentifier AttrType { get { return attrType; } } + + public Asn1Set AttrValues { get { return attrValues; } } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +        * Attribute ::= SEQUENCE {
      +        *     attrType OBJECT IDENTIFIER,
      +        *     attrValues SET OF AttributeValue
      +        * }
      +        * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(attrType, attrValues); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/AttributeTable.cs b/iTechSharp/srcbc/asn1/cms/AttributeTable.cs new file mode 100644 index 0000000..614372f --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/AttributeTable.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class AttributeTable + { + private readonly Hashtable attributes; + + public AttributeTable( + Hashtable attrs) + { + this.attributes = new Hashtable(attrs); + } + + public AttributeTable( + Asn1EncodableVector v) + { + this.attributes = new Hashtable(v.Count); + + foreach (Asn1Encodable o in v) + { + Attribute a = Attribute.GetInstance(o); + + AddAttribute(a); + } + } + + public AttributeTable( + Asn1Set s) + { + this.attributes = new Hashtable(s.Count); + + for (int i = 0; i != s.Count; i++) + { + Attribute a = Attribute.GetInstance(s[i]); + + AddAttribute(a); + } + } + + private void AddAttribute( + Attribute a) + { + DerObjectIdentifier oid = a.AttrType; + object obj = attributes[oid]; + + if (obj == null) + { + attributes[oid] = a; + } + else + { + ArrayList v; + + if (obj is Attribute) + { + v = new ArrayList(); + + v.Add(obj); + v.Add(a); + } + else + { + v = (ArrayList) obj; + + v.Add(a); + } + + attributes[oid] = v; + } + } + + /// Return the first attribute matching the given OBJECT IDENTIFIER + public Attribute this[DerObjectIdentifier oid] + { + get + { + object obj = attributes[oid]; + + if (obj is ArrayList) + { + return (Attribute)((ArrayList)obj)[0]; + } + + return (Attribute) obj; + } + } + + [Obsolete("Use 'object[oid]' syntax instead")] + public Attribute Get( + DerObjectIdentifier oid) + { + return this[oid]; + } + + /** + * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be + * empty if there are no attributes of the required type present. + * + * @param oid type of attribute required. + * @return a vector of all the attributes found of type oid. + */ + public Asn1EncodableVector GetAll( + DerObjectIdentifier oid) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + object obj = attributes[oid]; + + if (obj is ArrayList) + { + foreach (Attribute a in (ArrayList)obj) + { + v.Add(a); + } + } + else if (obj != null) + { + v.Add((Attribute) obj); + } + + return v; + } + + public Hashtable ToHashtable() + { + return new Hashtable(attributes); + } + + public Asn1EncodableVector ToAsn1EncodableVector() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + foreach (object obj in attributes.Values) + { + if (obj is ArrayList) + { + foreach (object el in (ArrayList)obj) + { + v.Add(Attribute.GetInstance(el)); + } + } + else + { + v.Add(Attribute.GetInstance(obj)); + } + } + + return v; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/CMSAttributes.cs b/iTechSharp/srcbc/asn1/cms/CMSAttributes.cs new file mode 100644 index 0000000..e0218e7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/CMSAttributes.cs @@ -0,0 +1,13 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public abstract class CmsAttributes + { + public static readonly DerObjectIdentifier ContentType = PkcsObjectIdentifiers.Pkcs9AtContentType; + public static readonly DerObjectIdentifier MessageDigest = PkcsObjectIdentifiers.Pkcs9AtMessageDigest; + public static readonly DerObjectIdentifier SigningTime = PkcsObjectIdentifiers.Pkcs9AtSigningTime; + public static readonly DerObjectIdentifier CounterSignature = PkcsObjectIdentifiers.Pkcs9AtCounterSignature; + } +} diff --git a/iTechSharp/srcbc/asn1/cms/CMSObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/cms/CMSObjectIdentifiers.cs new file mode 100644 index 0000000..8797ecd --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/CMSObjectIdentifiers.cs @@ -0,0 +1,15 @@ +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public abstract class CmsObjectIdentifiers + { + public static readonly DerObjectIdentifier Data = PkcsObjectIdentifiers.Data; + public static readonly DerObjectIdentifier SignedData = PkcsObjectIdentifiers.SignedData; + public static readonly DerObjectIdentifier EnvelopedData = PkcsObjectIdentifiers.EnvelopedData; + public static readonly DerObjectIdentifier SignedAndEnvelopedData = PkcsObjectIdentifiers.SignedAndEnvelopedData; + public static readonly DerObjectIdentifier DigestedData = PkcsObjectIdentifiers.DigestedData; + public static readonly DerObjectIdentifier EncryptedData = PkcsObjectIdentifiers.EncryptedData; + public static readonly DerObjectIdentifier CompressedData = PkcsObjectIdentifiers.IdCTCompressedData; + } +} diff --git a/iTechSharp/srcbc/asn1/cms/CompressedData.cs b/iTechSharp/srcbc/asn1/cms/CompressedData.cs new file mode 100644 index 0000000..5a24c2f --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/CompressedData.cs @@ -0,0 +1,100 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + * RFC 3274 - CMS Compressed Data. + *
      +     * CompressedData ::= Sequence {
      +     *  version CMSVersion,
      +     *  compressionAlgorithm CompressionAlgorithmIdentifier,
      +     *  encapContentInfo EncapsulatedContentInfo
      +     * }
      +     * 
      + */ + public class CompressedData + : Asn1Encodable + { + private DerInteger version; + private AlgorithmIdentifier compressionAlgorithm; + private ContentInfo encapContentInfo; + + public CompressedData( + AlgorithmIdentifier compressionAlgorithm, + ContentInfo encapContentInfo) + { + this.version = new DerInteger(0); + this.compressionAlgorithm = compressionAlgorithm; + this.encapContentInfo = encapContentInfo; + } + + public CompressedData( + Asn1Sequence seq) + { + this.version = (DerInteger) seq[0]; + this.compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]); + this.encapContentInfo = ContentInfo.GetInstance(seq[2]); + } + + /** + * return a CompressedData object from a tagged object. + * + * @param ato the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static CompressedData GetInstance( + Asn1TaggedObject ato, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(ato, explicitly)); + } + + /** + * return a CompressedData object from the given object. + * + * @param _obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static CompressedData GetInstance( + object obj) + { + if (obj == null || obj is CompressedData) + { + return (CompressedData)obj; + } + + if (obj is Asn1Sequence) + { + return new CompressedData((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid CompressedData: " + obj.GetType().Name); + } + + public DerInteger Version + { + get { return version; } + } + + public AlgorithmIdentifier CompressionAlgorithmIdentifier + { + get { return compressionAlgorithm; } + } + + public ContentInfo EncapContentInfo + { + get { return encapContentInfo; } + } + + public override Asn1Object ToAsn1Object() + { + return new BerSequence(version, compressionAlgorithm, encapContentInfo); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/CompressedDataParser.cs b/iTechSharp/srcbc/asn1/cms/CompressedDataParser.cs new file mode 100644 index 0000000..7c53453 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/CompressedDataParser.cs @@ -0,0 +1,47 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + * RFC 3274 - CMS Compressed Data. + *
      +	* CompressedData ::= SEQUENCE {
      +	*  version CMSVersion,
      +	*  compressionAlgorithm CompressionAlgorithmIdentifier,
      +	*  encapContentInfo EncapsulatedContentInfo
      +	* }
      +	* 
      + */ + public class CompressedDataParser + { + private DerInteger _version; + private AlgorithmIdentifier _compressionAlgorithm; + private ContentInfoParser _encapContentInfo; + + public CompressedDataParser( + Asn1SequenceParser seq) + { + this._version = (DerInteger)seq.ReadObject(); + this._compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object()); + this._encapContentInfo = new ContentInfoParser((Asn1SequenceParser)seq.ReadObject()); + } + + public DerInteger Version + { + get { return _version; } + } + + public AlgorithmIdentifier CompressionAlgorithmIdentifier + { + get { return _compressionAlgorithm; } + } + + public ContentInfoParser GetEncapContentInfo() + { + return _encapContentInfo; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/ContentInfo.cs b/iTechSharp/srcbc/asn1/cms/ContentInfo.cs new file mode 100644 index 0000000..4521c2f --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/ContentInfo.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class ContentInfo + : Asn1Encodable + { + private readonly DerObjectIdentifier contentType; + private readonly Asn1Encodable content; + + public static ContentInfo GetInstance( + object obj) + { + if (obj == null || obj is ContentInfo) + { + return (ContentInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new ContentInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name); + } + + private ContentInfo( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + contentType = (DerObjectIdentifier) seq[0]; + + if (seq.Count > 1) + { + Asn1TaggedObject optOcts = (Asn1TaggedObject) seq[1]; + if (optOcts.TagNo != 0) + throw new ArgumentException("Tag number for 'content' must be 0"); + + content = optOcts.GetObject(); + } + } + + public ContentInfo( + DerObjectIdentifier contentType, + Asn1Encodable content) + { + this.contentType = contentType; + this.content = content; + } + + public DerObjectIdentifier ContentType + { + get { return contentType; } + } + + public Asn1Encodable Content + { + get { return content; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +		 * ContentInfo ::= Sequence {
      +		 *          contentType ContentType,
      +		 *          content
      +		 *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(contentType); + + if (content != null) + { + v.Add(new BerTaggedObject(0, content)); + } + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/ContentInfoParser.cs b/iTechSharp/srcbc/asn1/cms/ContentInfoParser.cs new file mode 100644 index 0000000..541cc0f --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/ContentInfoParser.cs @@ -0,0 +1,40 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +	* ContentInfo ::= SEQUENCE {
      +	*          contentType ContentType,
      +	*          content
      +	*          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
      +	* 
      + */ + public class ContentInfoParser + { + private DerObjectIdentifier contentType; + private Asn1TaggedObjectParser content; + + public ContentInfoParser( + Asn1SequenceParser seq) + { + contentType = (DerObjectIdentifier)seq.ReadObject(); + content = (Asn1TaggedObjectParser)seq.ReadObject(); + } + + public DerObjectIdentifier ContentType + { + get { return contentType; } + } + + public IAsn1Convertible GetContent( + int tag) + { + if (content == null) + return null; + + return content.GetObjectParser(tag, true); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/EncryptedContentInfo.cs b/iTechSharp/srcbc/asn1/cms/EncryptedContentInfo.cs new file mode 100644 index 0000000..f76f51c --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/EncryptedContentInfo.cs @@ -0,0 +1,98 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class EncryptedContentInfo + : Asn1Encodable + { + private DerObjectIdentifier contentType; + private AlgorithmIdentifier contentEncryptionAlgorithm; + private Asn1OctetString encryptedContent; + + public EncryptedContentInfo( + DerObjectIdentifier contentType, + AlgorithmIdentifier contentEncryptionAlgorithm, + Asn1OctetString encryptedContent) + { + this.contentType = contentType; + this.contentEncryptionAlgorithm = contentEncryptionAlgorithm; + this.encryptedContent = encryptedContent; + } + + public EncryptedContentInfo( + Asn1Sequence seq) + { + contentType = (DerObjectIdentifier) seq[0]; + contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]); + + if (seq.Count > 2) + { + encryptedContent = Asn1OctetString.GetInstance( + (Asn1TaggedObject) seq[2], false); + } + } + + /** + * return an EncryptedContentInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static EncryptedContentInfo GetInstance( + object obj) + { + if (obj == null || obj is EncryptedContentInfo) + { + return (EncryptedContentInfo)obj; + } + + if (obj is Asn1Sequence) + { + return new EncryptedContentInfo((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid EncryptedContentInfo: " + obj.GetType().Name); + } + + public DerObjectIdentifier ContentType + { + get { return contentType; } + } + + public AlgorithmIdentifier ContentEncryptionAlgorithm + { + get { return contentEncryptionAlgorithm; } + } + + public Asn1OctetString EncryptedContent + { + get { return encryptedContent; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * EncryptedContentInfo ::= Sequence {
      +         *     contentType ContentType,
      +         *     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
      +         *     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + contentType, contentEncryptionAlgorithm); + + if (encryptedContent != null) + { + v.Add(new BerTaggedObject(false, 0, encryptedContent)); + } + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/EncryptedContentInfoParser.cs b/iTechSharp/srcbc/asn1/cms/EncryptedContentInfoParser.cs new file mode 100644 index 0000000..af748b1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/EncryptedContentInfoParser.cs @@ -0,0 +1,46 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + *
      +	* EncryptedContentInfo ::= SEQUENCE {
      +	*     contentType ContentType,
      +	*     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
      +	*     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
      +	* }
      +	* 
      + */ + public class EncryptedContentInfoParser + { + private DerObjectIdentifier _contentType; + private AlgorithmIdentifier _contentEncryptionAlgorithm; + private Asn1TaggedObjectParser _encryptedContent; + + public EncryptedContentInfoParser( + Asn1SequenceParser seq) + { + _contentType = (DerObjectIdentifier)seq.ReadObject(); + _contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object()); + _encryptedContent = (Asn1TaggedObjectParser)seq.ReadObject(); + } + + public DerObjectIdentifier ContentType + { + get { return _contentType; } + } + + public AlgorithmIdentifier ContentEncryptionAlgorithm + { + get { return _contentEncryptionAlgorithm; } + } + + public IAsn1Convertible GetEncryptedContent( + int tag) + { + return _encryptedContent.GetObjectParser(tag, false); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/EncryptedData.cs b/iTechSharp/srcbc/asn1/cms/EncryptedData.cs new file mode 100644 index 0000000..5b83782 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/EncryptedData.cs @@ -0,0 +1,95 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class EncryptedData + : Asn1Encodable + { + private readonly DerInteger version; + private readonly EncryptedContentInfo encryptedContentInfo; + private readonly Asn1Set unprotectedAttrs; + + public static EncryptedData GetInstance( + object obj) + { + if (obj is EncryptedData) + return (EncryptedData) obj; + + if (obj is Asn1Sequence) + return new EncryptedData((Asn1Sequence) obj); + + throw new ArgumentException("Invalid EncryptedData: " + obj.GetType().Name); + } + + public EncryptedData( + EncryptedContentInfo encInfo) + : this(encInfo, null) + { + } + + public EncryptedData( + EncryptedContentInfo encInfo, + Asn1Set unprotectedAttrs) + { + if (encInfo == null) + throw new ArgumentNullException("encInfo"); + + this.version = new DerInteger((unprotectedAttrs == null) ? 0 : 2); + this.encryptedContentInfo = encInfo; + this.unprotectedAttrs = unprotectedAttrs; + } + + private EncryptedData( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 2 || seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.version = DerInteger.GetInstance(seq[0]); + this.encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[1]); + + if (seq.Count > 2) + { + this.unprotectedAttrs = Asn1Set.GetInstance(seq[2]); + } + } + + public virtual DerInteger Version + { + get { return version; } + } + + public virtual EncryptedContentInfo EncryptedContentInfo + { + get { return encryptedContentInfo; } + } + + public virtual Asn1Set UnprotectedAttrs + { + get { return unprotectedAttrs; } + } + + /** + *
      +		*       EncryptedData ::= SEQUENCE {
      +		*                     version CMSVersion,
      +		*                     encryptedContentInfo EncryptedContentInfo,
      +		*                     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
      +		* 
      + * @return a basic ASN.1 object representation. + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(version, encryptedContentInfo); + + if (unprotectedAttrs != null) + { + v.Add(new BerTaggedObject(false, 1, unprotectedAttrs)); + } + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/EnvelopedData.cs b/iTechSharp/srcbc/asn1/cms/EnvelopedData.cs new file mode 100644 index 0000000..0e18bd8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/EnvelopedData.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class EnvelopedData + : Asn1Encodable + { + private DerInteger version; + private OriginatorInfo originatorInfo; + private Asn1Set recipientInfos; + private EncryptedContentInfo encryptedContentInfo; + private Asn1Set unprotectedAttrs; + + public EnvelopedData( + OriginatorInfo originatorInfo, + Asn1Set recipientInfos, + EncryptedContentInfo encryptedContentInfo, + Asn1Set unprotectedAttrs) + { + if (originatorInfo != null || unprotectedAttrs != null) + { + version = new DerInteger(2); + } + else + { + version = new DerInteger(0); + + foreach (object o in recipientInfos) + { + RecipientInfo ri = RecipientInfo.GetInstance(o); + + if (!ri.Version.Equals(version)) + { + version = new DerInteger(2); + break; + } + } + } + + this.originatorInfo = originatorInfo; + this.recipientInfos = recipientInfos; + this.encryptedContentInfo = encryptedContentInfo; + this.unprotectedAttrs = unprotectedAttrs; + } + + public EnvelopedData( + Asn1Sequence seq) + { + int index = 0; + + version = (DerInteger) seq[index++]; + + object tmp = seq[index++]; + + if (tmp is Asn1TaggedObject) + { + originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject) tmp, false); + tmp = seq[index++]; + } + + recipientInfos = Asn1Set.GetInstance(tmp); + encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[index++]); + + if (seq.Count > index) + { + unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject) seq[index], false); + } + } + + /** + * return an EnvelopedData object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static EnvelopedData GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return an EnvelopedData object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static EnvelopedData GetInstance( + object obj) + { + if (obj == null || obj is EnvelopedData) + { + return (EnvelopedData)obj; + } + + if (obj is Asn1Sequence) + { + return new EnvelopedData((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid EnvelopedData: " + obj.GetType().Name); + } + + public DerInteger Version { get { return version; } } + + public OriginatorInfo OriginatorInfo { get { return originatorInfo; } } + + public Asn1Set RecipientInfos { get { return recipientInfos; } } + + public EncryptedContentInfo EncryptedContentInfo { get { return encryptedContentInfo; } } + + public Asn1Set UnprotectedAttrs { get { return unprotectedAttrs; } } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * EnvelopedData ::= Sequence {
      +         *     version CMSVersion,
      +         *     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
      +         *     recipientInfos RecipientInfos,
      +         *     encryptedContentInfo EncryptedContentInfo,
      +         *     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(version); + + if (originatorInfo != null) + { + v.Add(new DerTaggedObject(false, 0, originatorInfo)); + } + + v.Add(recipientInfos, encryptedContentInfo); + + if (unprotectedAttrs != null) + { + v.Add(new DerTaggedObject(false, 1, unprotectedAttrs)); + } + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/EnvelopedDataParser.cs b/iTechSharp/srcbc/asn1/cms/EnvelopedDataParser.cs new file mode 100644 index 0000000..877696e --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/EnvelopedDataParser.cs @@ -0,0 +1,106 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + *
      +	* EnvelopedData ::= SEQUENCE {
      +	*     version CMSVersion,
      +	*     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
      +	*     recipientInfos RecipientInfos,
      +	*     encryptedContentInfo EncryptedContentInfo,
      +	*     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
      +	* }
      +	* 
      + */ + public class EnvelopedDataParser + { + private Asn1SequenceParser _seq; + private DerInteger _version; + private IAsn1Convertible _nextObject; + private bool _originatorInfoCalled; + + public EnvelopedDataParser( + Asn1SequenceParser seq) + { + this._seq = seq; + this._version = (DerInteger)seq.ReadObject(); + } + + public DerInteger Version + { + get { return _version; } + } + + public OriginatorInfo GetOriginatorInfo() + { + _originatorInfoCalled = true; + + if (_nextObject == null) + { + _nextObject = _seq.ReadObject(); + } + + if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0) + { + Asn1SequenceParser originatorInfo = (Asn1SequenceParser) + ((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Sequence, false); + _nextObject = null; + return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object()); + } + + return null; + } + + public Asn1SetParser GetRecipientInfos() + { + if (!_originatorInfoCalled) + { + GetOriginatorInfo(); + } + + if (_nextObject == null) + { + _nextObject = _seq.ReadObject(); + } + + Asn1SetParser recipientInfos = (Asn1SetParser)_nextObject; + _nextObject = null; + return recipientInfos; + } + + public EncryptedContentInfoParser GetEncryptedContentInfo() + { + if (_nextObject == null) + { + _nextObject = _seq.ReadObject(); + } + + if (_nextObject != null) + { + Asn1SequenceParser o = (Asn1SequenceParser) _nextObject; + _nextObject = null; + return new EncryptedContentInfoParser(o); + } + + return null; + } + + public Asn1SetParser GetUnprotectedAttrs() + { + if (_nextObject == null) + { + _nextObject = _seq.ReadObject(); + } + + if (_nextObject != null) + { + IAsn1Convertible o = _nextObject; + _nextObject = null; + return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false); + } + + return null; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/IssuerAndSerialNumber.cs b/iTechSharp/srcbc/asn1/cms/IssuerAndSerialNumber.cs new file mode 100644 index 0000000..5f8e8c2 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/IssuerAndSerialNumber.cs @@ -0,0 +1,70 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class IssuerAndSerialNumber + : Asn1Encodable + { + X509Name name; + DerInteger serialNumber; + + public static IssuerAndSerialNumber GetInstance( + object obj) + { + if (obj is IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)obj; + } + + if (obj is Asn1Sequence) + { + return new IssuerAndSerialNumber((Asn1Sequence)obj); + } + + throw new ArgumentException( + "Illegal object in IssuerAndSerialNumber: " + obj.GetType().Name); + } + + public IssuerAndSerialNumber( + Asn1Sequence seq) + { + this.name = X509Name.GetInstance(seq[0]); + this.serialNumber = (DerInteger) seq[1]; + } + + public IssuerAndSerialNumber( + X509Name name, + BigInteger serialNumber) + { + this.name = name; + this.serialNumber = new DerInteger(serialNumber); + } + + public IssuerAndSerialNumber( + X509Name name, + DerInteger serialNumber) + { + this.name = name; + this.serialNumber = serialNumber; + } + + public X509Name Name + { + get { return name; } + } + + public DerInteger SerialNumber + { + get { return serialNumber; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(name, serialNumber); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/KEKIdentifier.cs b/iTechSharp/srcbc/asn1/cms/KEKIdentifier.cs new file mode 100644 index 0000000..b438ea9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/KEKIdentifier.cs @@ -0,0 +1,133 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class KekIdentifier + : Asn1Encodable + { + private Asn1OctetString keyIdentifier; + private DerGeneralizedTime date; + private OtherKeyAttribute other; + + public KekIdentifier( + byte[] keyIdentifier, + DerGeneralizedTime date, + OtherKeyAttribute other) + { + this.keyIdentifier = new DerOctetString(keyIdentifier); + this.date = date; + this.other = other; + } + + public KekIdentifier( + Asn1Sequence seq) + { + keyIdentifier = (Asn1OctetString) seq[0]; + + switch (seq.Count) + { + case 1: + break; + case 2: + if (seq[1] is DerGeneralizedTime) + { + date = (DerGeneralizedTime) seq[1]; + } + else + { + other = OtherKeyAttribute.GetInstance(seq[2]); + } + break; + case 3: + date = (DerGeneralizedTime) seq[1]; + other = OtherKeyAttribute.GetInstance(seq[2]); + break; + default: + throw new ArgumentException("Invalid KekIdentifier"); + } + } + + /** + * return a KekIdentifier object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KekIdentifier GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return a KekIdentifier object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static KekIdentifier GetInstance( + object obj) + { + if (obj == null || obj is KekIdentifier) + { + return (KekIdentifier)obj; + } + + if (obj is Asn1Sequence) + { + return new KekIdentifier((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid KekIdentifier: " + obj.GetType().Name); + } + + public Asn1OctetString KeyIdentifier + { + get { return keyIdentifier; } + } + + public DerGeneralizedTime Date + { + get { return date; } + } + + public OtherKeyAttribute Other + { + get { return other; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * KekIdentifier ::= Sequence {
      +         *     keyIdentifier OCTET STRING,
      +         *     date GeneralizedTime OPTIONAL,
      +         *     other OtherKeyAttribute OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(keyIdentifier); + + if (date != null) + { + v.Add(date); + } + + if (other != null) + { + v.Add(other); + } + + return new DerSequence(v); + } + } +} + diff --git a/iTechSharp/srcbc/asn1/cms/KEKRecipientInfo.cs b/iTechSharp/srcbc/asn1/cms/KEKRecipientInfo.cs new file mode 100644 index 0000000..88b8b07 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/KEKRecipientInfo.cs @@ -0,0 +1,110 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class KekRecipientInfo + : Asn1Encodable + { + private DerInteger version; + private KekIdentifier kekID; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private Asn1OctetString encryptedKey; + + public KekRecipientInfo( + KekIdentifier kekID, + AlgorithmIdentifier keyEncryptionAlgorithm, + Asn1OctetString encryptedKey) + { + this.version = new DerInteger(4); + this.kekID = kekID; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public KekRecipientInfo( + Asn1Sequence seq) + { + version = (DerInteger) seq[0]; + kekID = KekIdentifier.GetInstance(seq[1]); + keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]); + encryptedKey = (Asn1OctetString) seq[3]; + } + + /** + * return a KekRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KekRecipientInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return a KekRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static KekRecipientInfo GetInstance( + object obj) + { + if (obj == null || obj is KekRecipientInfo) + { + return (KekRecipientInfo)obj; + } + + if(obj is Asn1Sequence) + { + return new KekRecipientInfo((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid KekRecipientInfo: " + obj.GetType().Name); + } + + public DerInteger Version + { + get { return version; } + } + + public KekIdentifier KekID + { + get { return kekID; } + } + + public AlgorithmIdentifier KeyEncryptionAlgorithm + { + get { return keyEncryptionAlgorithm; } + } + + public Asn1OctetString EncryptedKey + { + get { return encryptedKey; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * KekRecipientInfo ::= Sequence {
      +         *     version CMSVersion,  -- always set to 4
      +         *     kekID KekIdentifier,
      +         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
      +         *     encryptedKey EncryptedKey
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(version, kekID, keyEncryptionAlgorithm, encryptedKey); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientIdentifier.cs b/iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientIdentifier.cs new file mode 100644 index 0000000..1f8b8db --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientIdentifier.cs @@ -0,0 +1,90 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class KeyAgreeRecipientIdentifier + : Asn1Encodable + { + /** + * return an KeyAgreeRecipientIdentifier object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param isExplicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KeyAgreeRecipientIdentifier GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + /** + * return an KeyAgreeRecipientIdentifier object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static KeyAgreeRecipientIdentifier GetInstance( + object obj) + { + if (obj == null || obj is KeyAgreeRecipientIdentifier) + { + return (KeyAgreeRecipientIdentifier)obj; + } + + if (obj is Asn1Sequence) + { + return new KeyAgreeRecipientIdentifier((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid KeyAgreeRecipientIdentifier: " + obj.GetType().FullName, "obj"); + } + + private readonly IssuerAndSerialNumber issuerSerial; + private const RecipientKeyIdentifier rKeyID = null; + + public KeyAgreeRecipientIdentifier( + IssuerAndSerialNumber issuerSerial) + { + this.issuerSerial = issuerSerial; + } + + private KeyAgreeRecipientIdentifier( + Asn1Sequence seq) + { + this.issuerSerial = IssuerAndSerialNumber.GetInstance(seq); + } + + public IssuerAndSerialNumber IssuerAndSerialNumber + { + get { return issuerSerial; } + } + + public RecipientKeyIdentifier RKeyID + { + get { return rKeyID; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +		 * KeyAgreeRecipientIdentifier ::= CHOICE {
      +		 *     issuerAndSerialNumber IssuerAndSerialNumber,
      +		 *     rKeyId [0] IMPLICIT RecipientKeyIdentifier
      +		 * }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + if (issuerSerial != null) + { + return issuerSerial.ToAsn1Object(); + } + + return new DerTaggedObject(false, 0, rKeyID); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientInfo.cs b/iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientInfo.cs new file mode 100644 index 0000000..a0191ac --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientInfo.cs @@ -0,0 +1,143 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class KeyAgreeRecipientInfo + : Asn1Encodable + { + private DerInteger version; + private OriginatorIdentifierOrKey originator; + private Asn1OctetString ukm; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private Asn1Sequence recipientEncryptedKeys; + + public KeyAgreeRecipientInfo( + OriginatorIdentifierOrKey originator, + Asn1OctetString ukm, + AlgorithmIdentifier keyEncryptionAlgorithm, + Asn1Sequence recipientEncryptedKeys) + { + this.version = new DerInteger(3); + this.originator = originator; + this.ukm = ukm; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.recipientEncryptedKeys = recipientEncryptedKeys; + } + + public KeyAgreeRecipientInfo( + Asn1Sequence seq) + { + int index = 0; + + version = (DerInteger) seq[index++]; + originator = OriginatorIdentifierOrKey.GetInstance( + (Asn1TaggedObject) seq[index++], true); + + if (seq[index] is Asn1TaggedObject) + { + ukm = Asn1OctetString.GetInstance( + (Asn1TaggedObject) seq[index++], true); + } + + keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance( + seq[index++]); + + recipientEncryptedKeys = (Asn1Sequence) seq[index++]; + } + + /** + * return a KeyAgreeRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KeyAgreeRecipientInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return a KeyAgreeRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static KeyAgreeRecipientInfo GetInstance( + object obj) + { + if (obj == null || obj is KeyAgreeRecipientInfo) + { + return (KeyAgreeRecipientInfo)obj; + } + + if (obj is Asn1Sequence) + { + return new KeyAgreeRecipientInfo((Asn1Sequence)obj); + } + + throw new ArgumentException( + "Illegal object in KeyAgreeRecipientInfo: " + obj.GetType().Name); + + } + + public DerInteger Version + { + get { return version; } + } + + public OriginatorIdentifierOrKey Originator + { + get { return originator; } + } + + public Asn1OctetString UserKeyingMaterial + { + get { return ukm; } + } + + public AlgorithmIdentifier KeyEncryptionAlgorithm + { + get { return keyEncryptionAlgorithm; } + } + + public Asn1Sequence RecipientEncryptedKeys + { + get { return recipientEncryptedKeys; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * KeyAgreeRecipientInfo ::= Sequence {
      +         *     version CMSVersion,  -- always set to 3
      +         *     originator [0] EXPLICIT OriginatorIdentifierOrKey,
      +         *     ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
      +         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
      +         *     recipientEncryptedKeys RecipientEncryptedKeys
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, new DerTaggedObject(true, 0, originator)); + + if (ukm != null) + { + v.Add(new DerTaggedObject(true, 1, ukm)); + } + + v.Add(keyEncryptionAlgorithm, recipientEncryptedKeys); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/KeyTransRecipientInfo.cs b/iTechSharp/srcbc/asn1/cms/KeyTransRecipientInfo.cs new file mode 100644 index 0000000..01611e0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/KeyTransRecipientInfo.cs @@ -0,0 +1,103 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class KeyTransRecipientInfo + : Asn1Encodable + { + private DerInteger version; + private RecipientIdentifier rid; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private Asn1OctetString encryptedKey; + + public KeyTransRecipientInfo( + RecipientIdentifier rid, + AlgorithmIdentifier keyEncryptionAlgorithm, + Asn1OctetString encryptedKey) + { + if (rid.ToAsn1Object() is Asn1TaggedObject) + { + this.version = new DerInteger(2); + } + else + { + this.version = new DerInteger(0); + } + + this.rid = rid; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public KeyTransRecipientInfo( + Asn1Sequence seq) + { + this.version = (DerInteger) seq[0]; + this.rid = RecipientIdentifier.GetInstance(seq[1]); + this.keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]); + this.encryptedKey = (Asn1OctetString) seq[3]; + } + + /** + * return a KeyTransRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static KeyTransRecipientInfo GetInstance( + object obj) + { + if (obj == null || obj is KeyTransRecipientInfo) + { + return (KeyTransRecipientInfo) obj; + } + + if(obj is Asn1Sequence) + { + return new KeyTransRecipientInfo((Asn1Sequence) obj); + } + + throw new ArgumentException( + "Illegal object in KeyTransRecipientInfo: " + obj.GetType().Name); + } + + public DerInteger Version + { + get { return version; } + } + + public RecipientIdentifier RecipientIdentifier + { + get { return rid; } + } + + public AlgorithmIdentifier KeyEncryptionAlgorithm + { + get { return keyEncryptionAlgorithm; } + } + + public Asn1OctetString EncryptedKey + { + get { return encryptedKey; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * KeyTransRecipientInfo ::= Sequence {
      +         *     version CMSVersion,  -- always set to 0 or 2
      +         *     rid RecipientIdentifier,
      +         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
      +         *     encryptedKey EncryptedKey
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(version, rid, keyEncryptionAlgorithm, encryptedKey); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/OriginatorIdentifierOrKey.cs b/iTechSharp/srcbc/asn1/cms/OriginatorIdentifierOrKey.cs new file mode 100644 index 0000000..6eeb1a3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/OriginatorIdentifierOrKey.cs @@ -0,0 +1,115 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class OriginatorIdentifierOrKey + : Asn1Encodable + { + private Asn1Encodable id; + + public OriginatorIdentifierOrKey( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public OriginatorIdentifierOrKey( + Asn1OctetString id) + { + this.id = new DerTaggedObject(false, 0, id); + } + + public OriginatorIdentifierOrKey( + OriginatorPublicKey id) + { + this.id = new DerTaggedObject(false, 1, id); + } + + public OriginatorIdentifierOrKey( + Asn1Object id) + { + this.id = id; + } + + /** + * return an OriginatorIdentifierOrKey object from a tagged object. + * + * @param o the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorIdentifierOrKey GetInstance( + Asn1TaggedObject o, + bool explicitly) + { + if (!explicitly) + { + throw new ArgumentException( + "Can't implicitly tag OriginatorIdentifierOrKey"); + } + + return GetInstance(o.GetObject()); + } + + /** + * return an OriginatorIdentifierOrKey object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static OriginatorIdentifierOrKey GetInstance( + object o) + { + if (o == null || o is OriginatorIdentifierOrKey) + { + return (OriginatorIdentifierOrKey)o; + } + + if (o is Asn1Object) + { + return new OriginatorIdentifierOrKey((Asn1Object)o); + } + + throw new ArgumentException("Invalid OriginatorIdentifierOrKey: " + o.GetType().Name); + } + + public Asn1Encodable ID + { + get { return id; } + } + + public OriginatorPublicKey OriginatorKey + { + get + { + if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 1) + { + return OriginatorPublicKey.GetInstance((Asn1TaggedObject)id, false); + } + + return null; + } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OriginatorIdentifierOrKey ::= CHOICE {
      +         *     issuerAndSerialNumber IssuerAndSerialNumber,
      +         *     subjectKeyIdentifier [0] SubjectKeyIdentifier,
      +         *     originatorKey [1] OriginatorPublicKey
      +         * }
      +         *
      +         * SubjectKeyIdentifier ::= OCTET STRING
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return id.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/OriginatorInfo.cs b/iTechSharp/srcbc/asn1/cms/OriginatorInfo.cs new file mode 100644 index 0000000..829b85c --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/OriginatorInfo.cs @@ -0,0 +1,125 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class OriginatorInfo + : Asn1Encodable + { + private Asn1Set certs; + private Asn1Set crls; + + public OriginatorInfo( + Asn1Set certs, + Asn1Set crls) + { + this.certs = certs; + this.crls = crls; + } + + public OriginatorInfo( + Asn1Sequence seq) + { + switch (seq.Count) + { + case 0: // empty + break; + case 1: + Asn1TaggedObject o = (Asn1TaggedObject) seq[0]; + switch (o.TagNo) + { + case 0 : + certs = Asn1Set.GetInstance(o, false); + break; + case 1 : + crls = Asn1Set.GetInstance(o, false); + break; + default: + throw new ArgumentException("Bad tag in OriginatorInfo: " + o.TagNo); + } + break; + case 2: + certs = Asn1Set.GetInstance((Asn1TaggedObject) seq[0], false); + crls = Asn1Set.GetInstance((Asn1TaggedObject) seq[1], false); + break; + default: + throw new ArgumentException("OriginatorInfo too big"); + } + } + + /** + * return an OriginatorInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return an OriginatorInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static OriginatorInfo GetInstance( + object obj) + { + if (obj == null || obj is OriginatorInfo) + { + return (OriginatorInfo)obj; + } + + if (obj is Asn1Sequence) + { + return new OriginatorInfo((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid OriginatorInfo: " + obj.GetType().Name); + } + + public Asn1Set Certificates + { + get { return certs; } + } + + public Asn1Set Crls + { + get { return crls; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OriginatorInfo ::= Sequence {
      +         *     certs [0] IMPLICIT CertificateSet OPTIONAL,
      +         *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (certs != null) + { + v.Add(new DerTaggedObject(false, 0, certs)); + } + + if (crls != null) + { + v.Add(new DerTaggedObject(false, 1, crls)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/OriginatorPublicKey.cs b/iTechSharp/srcbc/asn1/cms/OriginatorPublicKey.cs new file mode 100644 index 0000000..4e6be3b --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/OriginatorPublicKey.cs @@ -0,0 +1,91 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class OriginatorPublicKey + : Asn1Encodable + { + private AlgorithmIdentifier algorithm; + private DerBitString publicKey; + + public OriginatorPublicKey( + AlgorithmIdentifier algorithm, + byte[] publicKey) + { + this.algorithm = algorithm; + this.publicKey = new DerBitString(publicKey); + } + + public OriginatorPublicKey( + Asn1Sequence seq) + { + algorithm = AlgorithmIdentifier.GetInstance(seq[0]); + publicKey = (DerBitString) seq[1]; + } + + /** + * return an OriginatorPublicKey object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorPublicKey GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return an OriginatorPublicKey object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static OriginatorPublicKey GetInstance( + object obj) + { + if (obj == null || obj is OriginatorPublicKey) + { + return (OriginatorPublicKey)obj; + } + + if (obj is Asn1Sequence) + { + return new OriginatorPublicKey((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid OriginatorPublicKey: " + obj.GetType().Name); + } + + public AlgorithmIdentifier Algorithm + { + get { return algorithm; } + } + + public DerBitString PublicKey + { + get { return publicKey; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OriginatorPublicKey ::= Sequence {
      +         *     algorithm AlgorithmIdentifier,
      +         *     publicKey BIT STRING
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(algorithm, publicKey); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/OtherKeyAttribute.cs b/iTechSharp/srcbc/asn1/cms/OtherKeyAttribute.cs new file mode 100644 index 0000000..4366cf8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/OtherKeyAttribute.cs @@ -0,0 +1,74 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class OtherKeyAttribute + : Asn1Encodable + { + private DerObjectIdentifier keyAttrId; + private Asn1Encodable keyAttr; + + /** + * return an OtherKeyAttribute object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static OtherKeyAttribute GetInstance( + object obj) + { + if (obj == null || obj is OtherKeyAttribute) + { + return (OtherKeyAttribute) obj; + } + + if (obj is Asn1Sequence) + { + return new OtherKeyAttribute((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public OtherKeyAttribute( + Asn1Sequence seq) + { + keyAttrId = (DerObjectIdentifier) seq[0]; + keyAttr = seq[1]; + } + + public OtherKeyAttribute( + DerObjectIdentifier keyAttrId, + Asn1Encodable keyAttr) + { + this.keyAttrId = keyAttrId; + this.keyAttr = keyAttr; + } + + public DerObjectIdentifier KeyAttrId + { + get { return keyAttrId; } + } + + public Asn1Encodable KeyAttr + { + get { return keyAttr; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OtherKeyAttribute ::= Sequence {
      +         *     keyAttrId OBJECT IDENTIFIER,
      +         *     keyAttr ANY DEFINED BY keyAttrId OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(keyAttrId, keyAttr); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/OtherRecipientInfo.cs b/iTechSharp/srcbc/asn1/cms/OtherRecipientInfo.cs new file mode 100644 index 0000000..153d2ac --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/OtherRecipientInfo.cs @@ -0,0 +1,89 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class OtherRecipientInfo + : Asn1Encodable + { + private DerObjectIdentifier oriType; + private Asn1Encodable oriValue; + + public OtherRecipientInfo( + DerObjectIdentifier oriType, + Asn1Encodable oriValue) + { + this.oriType = oriType; + this.oriValue = oriValue; + } + + public OtherRecipientInfo( + Asn1Sequence seq) + { + oriType = DerObjectIdentifier.GetInstance(seq[0]); + oriValue = seq[1]; + } + + /** + * return a OtherRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OtherRecipientInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return a OtherRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static OtherRecipientInfo GetInstance( + object obj) + { + if (obj == null || obj is OtherRecipientInfo) + { + return (OtherRecipientInfo)obj; + } + + if (obj is Asn1Sequence) + { + return new OtherRecipientInfo((Asn1Sequence)obj); + } + + throw new ArgumentException("Invalid OtherRecipientInfo: " + obj.GetType().Name); + } + + public DerObjectIdentifier OriType + { + get { return oriType; } + } + + public Asn1Encodable OriValue + { + get { return oriValue; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OtherRecipientInfo ::= Sequence {
      +         *    oriType OBJECT IDENTIFIER,
      +         *    oriValue ANY DEFINED BY oriType }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(oriType, oriValue); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/PasswordRecipientInfo.cs b/iTechSharp/srcbc/asn1/cms/PasswordRecipientInfo.cs new file mode 100644 index 0000000..55e3a04 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/PasswordRecipientInfo.cs @@ -0,0 +1,137 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class PasswordRecipientInfo + : Asn1Encodable + { + private readonly DerInteger version; + private readonly AlgorithmIdentifier keyDerivationAlgorithm; + private readonly AlgorithmIdentifier keyEncryptionAlgorithm; + private readonly Asn1OctetString encryptedKey; + + public PasswordRecipientInfo( + AlgorithmIdentifier keyEncryptionAlgorithm, + Asn1OctetString encryptedKey) + { + this.version = new DerInteger(0); + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public PasswordRecipientInfo( + AlgorithmIdentifier keyDerivationAlgorithm, + AlgorithmIdentifier keyEncryptionAlgorithm, + Asn1OctetString encryptedKey) + { + this.version = new DerInteger(0); + this.keyDerivationAlgorithm = keyDerivationAlgorithm; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public PasswordRecipientInfo( + Asn1Sequence seq) + { + version = (DerInteger) seq[0]; + + if (seq[1] is Asn1TaggedObject) + { + keyDerivationAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject) seq[1], false); + keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]); + encryptedKey = (Asn1OctetString) seq[3]; + } + else + { + keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]); + encryptedKey = (Asn1OctetString) seq[2]; + } + } + + /** + * return a PasswordRecipientInfo object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param explicitly true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static PasswordRecipientInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /** + * return a PasswordRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static PasswordRecipientInfo GetInstance( + object obj) + { + if (obj == null || obj is PasswordRecipientInfo) + { + return (PasswordRecipientInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new PasswordRecipientInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid PasswordRecipientInfo: " + obj.GetType().Name); + } + + public DerInteger Version + { + get { return version; } + } + + public AlgorithmIdentifier KeyDerivationAlgorithm + { + get { return keyDerivationAlgorithm; } + } + + public AlgorithmIdentifier KeyEncryptionAlgorithm + { + get { return keyEncryptionAlgorithm; } + } + + public Asn1OctetString EncryptedKey + { + get { return encryptedKey; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * PasswordRecipientInfo ::= Sequence {
      +         *   version CMSVersion,   -- Always set to 0
      +         *   keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
      +         *                             OPTIONAL,
      +         *  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
      +         *  encryptedKey EncryptedKey }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(version); + + if (keyDerivationAlgorithm != null) + { + v.Add(new DerTaggedObject(false, 0, keyDerivationAlgorithm)); + } + + v.Add(keyEncryptionAlgorithm, encryptedKey); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/RecipientEncryptedKey.cs b/iTechSharp/srcbc/asn1/cms/RecipientEncryptedKey.cs new file mode 100644 index 0000000..5ba25a7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/RecipientEncryptedKey.cs @@ -0,0 +1,88 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class RecipientEncryptedKey + : Asn1Encodable + { + private readonly KeyAgreeRecipientIdentifier identifier; + private readonly Asn1OctetString encryptedKey; + + private RecipientEncryptedKey( + Asn1Sequence seq) + { + identifier = KeyAgreeRecipientIdentifier.GetInstance(seq[0]); + encryptedKey = (Asn1OctetString) seq[1]; + } + + /** + * return an RecipientEncryptedKey object from a tagged object. + * + * @param obj the tagged object holding the object we want. + * @param isExplicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static RecipientEncryptedKey GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + /** + * return a RecipientEncryptedKey object from the given object. + * + * @param obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static RecipientEncryptedKey GetInstance( + object obj) + { + if (obj == null || obj is RecipientEncryptedKey) + { + return (RecipientEncryptedKey) obj; + } + + if (obj is Asn1Sequence) + { + return new RecipientEncryptedKey((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid RecipientEncryptedKey: " + obj.GetType().FullName, "obj"); + } + + public RecipientEncryptedKey( + KeyAgreeRecipientIdentifier id, + Asn1OctetString encryptedKey) + { + this.identifier = id; + this.encryptedKey = encryptedKey; + } + + public KeyAgreeRecipientIdentifier Identifier + { + get { return identifier; } + } + + public Asn1OctetString EncryptedKey + { + get { return encryptedKey; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +		 * RecipientEncryptedKey ::= SEQUENCE {
      +		 *     rid KeyAgreeRecipientIdentifier,
      +		 *     encryptedKey EncryptedKey
      +		 * }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(identifier, encryptedKey); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/RecipientIdentifier.cs b/iTechSharp/srcbc/asn1/cms/RecipientIdentifier.cs new file mode 100644 index 0000000..e8f2724 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/RecipientIdentifier.cs @@ -0,0 +1,94 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class RecipientIdentifier + : Asn1Encodable + { + private Asn1Encodable id; + + public RecipientIdentifier( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public RecipientIdentifier( + Asn1OctetString id) + { + this.id = new DerTaggedObject(false, 0, id); + } + + public RecipientIdentifier( + Asn1Object id) + { + this.id = id; + } + + /** + * return a RecipientIdentifier object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static RecipientIdentifier GetInstance( + object o) + { + if (o == null || o is RecipientIdentifier) + { + return (RecipientIdentifier)o; + } + + if (o is IssuerAndSerialNumber) + { + return new RecipientIdentifier((IssuerAndSerialNumber) o); + } + + if (o is Asn1OctetString) + { + return new RecipientIdentifier((Asn1OctetString) o); + } + + if (o is Asn1Object) + { + return new RecipientIdentifier((Asn1Object) o); + } + + throw new ArgumentException( + "Illegal object in RecipientIdentifier: " + o.GetType().Name); + } + + public bool IsTagged { get { return (id is Asn1TaggedObject); } } + + public Asn1Encodable ID + { + get + { + if (id is Asn1TaggedObject) + { + return Asn1OctetString.GetInstance((Asn1TaggedObject) id, false); + } + + return IssuerAndSerialNumber.GetInstance(id); + } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * RecipientIdentifier ::= CHOICE {
      +         *     issuerAndSerialNumber IssuerAndSerialNumber,
      +         *     subjectKeyIdentifier [0] SubjectKeyIdentifier
      +         * }
      +         *
      +         * SubjectKeyIdentifier ::= OCTET STRING
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return id.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/RecipientInfo.cs b/iTechSharp/srcbc/asn1/cms/RecipientInfo.cs new file mode 100644 index 0000000..a9b171f --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/RecipientInfo.cs @@ -0,0 +1,151 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class RecipientInfo + : Asn1Encodable + { + internal Asn1Encodable info; + + public RecipientInfo( + KeyTransRecipientInfo info) + { + this.info = info; + } + + public RecipientInfo( + KeyAgreeRecipientInfo info) + { + this.info = new DerTaggedObject(false, 1, info); + } + + public RecipientInfo( + KekRecipientInfo info) + { + this.info = new DerTaggedObject(false, 2, info); + } + + public RecipientInfo( + PasswordRecipientInfo info) + { + this.info = new DerTaggedObject(false, 3, info); + } + + public RecipientInfo( + OtherRecipientInfo info) + { + this.info = new DerTaggedObject(false, 4, info); + } + + public RecipientInfo( + Asn1Object info) + { + this.info = info; + } + + public static RecipientInfo GetInstance( + object o) + { + if (o == null || o is RecipientInfo) + { + return (RecipientInfo) o; + } + + if (o is Asn1Sequence) + { + return new RecipientInfo((Asn1Sequence) o); + } + + if (o is Asn1TaggedObject) + { + return new RecipientInfo((Asn1TaggedObject) o); + } + + throw new ArgumentException("unknown object in factory: " + o.GetType().Name); + } + + public DerInteger Version + { + get + { + if (info is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject) info; + + switch (o.TagNo) + { + case 1: + return KeyAgreeRecipientInfo.GetInstance(o, false).Version; + case 2: + return GetKekInfo(o).Version; + case 3: + return PasswordRecipientInfo.GetInstance(o, false).Version; + case 4: + return new DerInteger(0); // no syntax version for OtherRecipientInfo + default: + throw new InvalidOperationException("unknown tag"); + } + } + + return KeyTransRecipientInfo.GetInstance(info).Version; + } + } + + public bool IsTagged + { + get { return info is Asn1TaggedObject; } + } + + public Asn1Encodable Info + { + get + { + if (info is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject) info; + + switch (o.TagNo) + { + case 1: + return KeyAgreeRecipientInfo.GetInstance(o, false); + case 2: + return GetKekInfo(o); + case 3: + return PasswordRecipientInfo.GetInstance(o, false); + case 4: + return OtherRecipientInfo.GetInstance(o, false); + default: + throw new InvalidOperationException("unknown tag"); + } + } + + return KeyTransRecipientInfo.GetInstance(info); + } + } + + private KekRecipientInfo GetKekInfo( + Asn1TaggedObject o) + { + // For compatibility with erroneous version, we don't always pass 'false' here + return KekRecipientInfo.GetInstance(o, o.IsExplicit()); + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * RecipientInfo ::= CHOICE {
      +         *     ktri KeyTransRecipientInfo,
      +         *     kari [1] KeyAgreeRecipientInfo,
      +         *     kekri [2] KekRecipientInfo,
      +         *     pwri [3] PasswordRecipientInfo,
      +         *     ori [4] OtherRecipientInfo }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return info.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/RecipientKeyIdentifier.cs b/iTechSharp/srcbc/asn1/cms/RecipientKeyIdentifier.cs new file mode 100644 index 0000000..05ce8bf --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/RecipientKeyIdentifier.cs @@ -0,0 +1,135 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class RecipientKeyIdentifier + : Asn1Encodable + { + private Asn1OctetString subjectKeyIdentifier; + private DerGeneralizedTime date; + private OtherKeyAttribute other; + + public RecipientKeyIdentifier( + Asn1OctetString subjectKeyIdentifier, + DerGeneralizedTime date, + OtherKeyAttribute other) + { + this.subjectKeyIdentifier = subjectKeyIdentifier; + this.date = date; + this.other = other; + } + + public RecipientKeyIdentifier( + Asn1Sequence seq) + { + subjectKeyIdentifier = Asn1OctetString.GetInstance( + seq[0]); + + switch(seq.Count) + { + case 1: + break; + case 2: + if (seq[1] is DerGeneralizedTime) + { + date = (DerGeneralizedTime) seq[1]; + } + else + { + other = OtherKeyAttribute.GetInstance(seq[2]); + } + break; + case 3: + date = (DerGeneralizedTime) seq[1]; + other = OtherKeyAttribute.GetInstance(seq[2]); + break; + default: + throw new ArgumentException("Invalid KekIdentifier"); + } + } + + /** + * return a RecipientKeyIdentifier object from a tagged object. + * + * @param _ato the tagged object holding the object we want. + * @param _explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception ArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static RecipientKeyIdentifier GetInstance( + Asn1TaggedObject ato, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(ato, explicitly)); + } + + /** + * return a RecipientKeyIdentifier object from the given object. + * + * @param _obj the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static RecipientKeyIdentifier GetInstance( + object obj) + { + if (obj == null || obj is RecipientKeyIdentifier) + { + return (RecipientKeyIdentifier) obj; + } + + if (obj is Asn1Sequence) + { + return new RecipientKeyIdentifier((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid RecipientKeyIdentifier: " + obj.GetType().Name); + } + + public Asn1OctetString SubjectKeyIdentifier + { + get { return subjectKeyIdentifier; } + } + + public DerGeneralizedTime Date + { + get { return date; } + } + + public OtherKeyAttribute OtherKeyAttribute + { + get { return other; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * RecipientKeyIdentifier ::= Sequence {
      +         *     subjectKeyIdentifier SubjectKeyIdentifier,
      +         *     date GeneralizedTime OPTIONAL,
      +         *     other OtherKeyAttribute OPTIONAL
      +         * }
      +         *
      +         * SubjectKeyIdentifier ::= OCTET STRING
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(subjectKeyIdentifier); + + if (date != null) + { + v.Add(date); + } + + if (other != null) + { + v.Add(other); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/SignedData.cs b/iTechSharp/srcbc/asn1/cms/SignedData.cs new file mode 100644 index 0000000..e2d5bd3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/SignedData.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + * a signed data object. + */ + public class SignedData + : Asn1Encodable + { + private readonly DerInteger version; + private readonly Asn1Set digestAlgorithms; + private readonly ContentInfo contentInfo; + private readonly Asn1Set certificates; + private readonly Asn1Set crls; + private readonly Asn1Set signerInfos; + private readonly bool certsBer; + private readonly bool crlsBer; + + public static SignedData GetInstance( + object obj) + { + if (obj is SignedData) + { + return (SignedData) obj; + } + + if (obj is Asn1Sequence) + { + return new SignedData((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public SignedData( + Asn1Set digestAlgorithms, + ContentInfo contentInfo, + Asn1Set certificates, + Asn1Set crls, + Asn1Set signerInfos) + { + this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos); + this.digestAlgorithms = digestAlgorithms; + this.contentInfo = contentInfo; + this.certificates = certificates; + this.crls = crls; + this.signerInfos = signerInfos; + this.crlsBer = crls is BerSet; + this.certsBer = certificates is BerSet; + } + + // RFC3852, section 5.1: + // IF ((certificates is present) AND + // (any certificates with a type of other are present)) OR + // ((crls is present) AND + // (any crls with a type of other are present)) + // THEN version MUST be 5 + // ELSE + // IF (certificates is present) AND + // (any version 2 attribute certificates are present) + // THEN version MUST be 4 + // ELSE + // IF ((certificates is present) AND + // (any version 1 attribute certificates are present)) OR + // (any SignerInfo structures are version 3) OR + // (encapContentInfo eContentType is other than id-data) + // THEN version MUST be 3 + // ELSE version MUST be 1 + // + private DerInteger CalculateVersion( + DerObjectIdentifier contentOid, + Asn1Set certs, + Asn1Set crls, + Asn1Set signerInfs) + { + bool otherCert = false; + bool otherCrl = false; + bool attrCertV1Found = false; + bool attrCertV2Found = false; + + if (certs != null) + { + foreach (object obj in certs) + { + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tagged = (Asn1TaggedObject)obj; + + if (tagged.TagNo == 1) + { + attrCertV1Found = true; + } + else if (tagged.TagNo == 2) + { + attrCertV2Found = true; + } + else if (tagged.TagNo == 3) + { + otherCert = true; + break; + } + } + } + } + + if (otherCert) + { + return new DerInteger(5); + } + + if (crls != null) + { + foreach (object obj in crls) + { + if (obj is Asn1TaggedObject) + { + otherCrl = true; + break; + } + } + } + + if (otherCrl) + { + return new DerInteger(5); + } + + if (attrCertV2Found) + { + return new DerInteger(4); + } + + if (attrCertV1Found) + { + return new DerInteger(3); + } + + if (contentOid.Equals(CmsObjectIdentifiers.Data) + && !CheckForVersion3(signerInfs)) + { + return new DerInteger(1); + } + + return new DerInteger(3); + } + + private bool CheckForVersion3( + Asn1Set signerInfs) + { + foreach (object obj in signerInfs) + { + SignerInfo s = SignerInfo.GetInstance(obj); + + if (s.Version.Value.IntValue == 3) + { + return true; + } + } + + return false; + } + + private SignedData( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + version = (DerInteger)e.Current; + + e.MoveNext(); + digestAlgorithms = ((Asn1Set)e.Current); + + e.MoveNext(); + contentInfo = ContentInfo.GetInstance(e.Current); + + while (e.MoveNext()) + { + Asn1Object o = (Asn1Object)e.Current; + + // + // an interesting feature of SignedData is that there appear + // to be varying implementations... + // for the moment we ignore anything which doesn't fit. + // + if (o is Asn1TaggedObject) + { + Asn1TaggedObject tagged = (Asn1TaggedObject)o; + + switch (tagged.TagNo) + { + case 0: + certsBer = tagged is BerTaggedObject; + certificates = Asn1Set.GetInstance(tagged, false); + break; + case 1: + crlsBer = tagged is BerTaggedObject; + crls = Asn1Set.GetInstance(tagged, false); + break; + default: + throw new ArgumentException("unknown tag value " + tagged.TagNo); + } + } + else + { + signerInfos = (Asn1Set) o; + } + } + } + + public DerInteger Version + { + get { return version; } + } + + public Asn1Set DigestAlgorithms + { + get { return digestAlgorithms; } + } + + public ContentInfo EncapContentInfo + { + get { return contentInfo; } + } + + public Asn1Set Certificates + { + get { return certificates; } + } + + public Asn1Set CRLs + { + get { return crls; } + } + + public Asn1Set SignerInfos + { + get { return signerInfos; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * SignedData ::= Sequence {
      +         *     version CMSVersion,
      +         *     digestAlgorithms DigestAlgorithmIdentifiers,
      +         *     encapContentInfo EncapsulatedContentInfo,
      +         *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
      +         *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
      +         *     signerInfos SignerInfos
      +         *   }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, digestAlgorithms, contentInfo); + + if (certificates != null) + { + if (certsBer) + { + v.Add(new BerTaggedObject(false, 0, certificates)); + } + else + { + v.Add(new DerTaggedObject(false, 0, certificates)); + } + } + + if (crls != null) + { + if (crlsBer) + { + v.Add(new BerTaggedObject(false, 1, crls)); + } + else + { + v.Add(new DerTaggedObject(false, 1, crls)); + } + } + + v.Add(signerInfos); + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/SignedDataParser.cs b/iTechSharp/srcbc/asn1/cms/SignedDataParser.cs new file mode 100644 index 0000000..3413092 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/SignedDataParser.cs @@ -0,0 +1,112 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1.Cms +{ + /** + *
      +	* SignedData ::= SEQUENCE {
      +	*     version CMSVersion,
      +	*     digestAlgorithms DigestAlgorithmIdentifiers,
      +	*     encapContentInfo EncapsulatedContentInfo,
      +	*     certificates [0] IMPLICIT CertificateSet OPTIONAL,
      +	*     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
      +	*     signerInfos SignerInfos
      +	*   }
      +	* 
      + */ + public class SignedDataParser + { + private Asn1SequenceParser _seq; + private DerInteger _version; + private object _nextObject; + private bool _certsCalled; + private bool _crlsCalled; + + public static SignedDataParser GetInstance( + object o) + { + if (o is Asn1Sequence) + return new SignedDataParser(((Asn1Sequence)o).Parser); + + if (o is Asn1SequenceParser) + return new SignedDataParser((Asn1SequenceParser)o); + + throw new IOException("unknown object encountered: " + o.GetType().Name); + } + + public SignedDataParser( + Asn1SequenceParser seq) + { + this._seq = seq; + this._version = (DerInteger)seq.ReadObject(); + } + + public DerInteger Version + { + get { return _version; } + } + + public Asn1SetParser GetDigestAlgorithms() + { + return (Asn1SetParser)_seq.ReadObject(); + } + + public ContentInfoParser GetEncapContentInfo() + { + return new ContentInfoParser((Asn1SequenceParser)_seq.ReadObject()); + } + + public Asn1SetParser GetCertificates() + { + _certsCalled = true; + _nextObject = _seq.ReadObject(); + + if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0) + { + Asn1SetParser certs = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false); + _nextObject = null; + + return certs; + } + + return null; + } + + public Asn1SetParser GetCrls() + { + if (!_certsCalled) + throw new IOException("GetCerts() has not been called."); + + _crlsCalled = true; + + if (_nextObject == null) + { + _nextObject = _seq.ReadObject(); + } + + if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 1) + { + Asn1SetParser crls = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false); + _nextObject = null; + + return crls; + } + + return null; + } + + public Asn1SetParser GetSignerInfos() + { + if (!_certsCalled || !_crlsCalled) + throw new IOException("GetCerts() and/or GetCrls() has not been called."); + + if (_nextObject == null) + { + _nextObject = _seq.ReadObject(); + } + + return (Asn1SetParser)_nextObject; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/SignerIdentifier.cs b/iTechSharp/srcbc/asn1/cms/SignerIdentifier.cs new file mode 100644 index 0000000..07c24c0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/SignerIdentifier.cs @@ -0,0 +1,94 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class SignerIdentifier + : Asn1Encodable + { + private Asn1Encodable id; + + public SignerIdentifier( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public SignerIdentifier( + Asn1OctetString id) + { + this.id = new DerTaggedObject(false, 0, id); + } + + public SignerIdentifier( + Asn1Object id) + { + this.id = id; + } + + /** + * return a SignerIdentifier object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static SignerIdentifier GetInstance( + object o) + { + if (o == null || o is SignerIdentifier) + { + return (SignerIdentifier) o; + } + + if (o is IssuerAndSerialNumber) + { + return new SignerIdentifier((IssuerAndSerialNumber) o); + } + + if (o is Asn1OctetString) + { + return new SignerIdentifier((Asn1OctetString) o); + } + + if (o is Asn1Object) + { + return new SignerIdentifier((Asn1Object) o); + } + + throw new ArgumentException( + "Illegal object in SignerIdentifier: " + o.GetType().Name); + } + + public bool IsTagged { get { return (id is Asn1TaggedObject); } } + + public Asn1Encodable ID + { + get + { + if (id is Asn1TaggedObject) + { + return Asn1OctetString.GetInstance((Asn1TaggedObject)id, false); + } + + return id; + } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * SignerIdentifier ::= CHOICE {
      +         *     issuerAndSerialNumber IssuerAndSerialNumber,
      +         *     subjectKeyIdentifier [0] SubjectKeyIdentifier
      +         * }
      +         *
      +         * SubjectKeyIdentifier ::= OCTET STRING
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return id.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/SignerInfo.cs b/iTechSharp/srcbc/asn1/cms/SignerInfo.cs new file mode 100644 index 0000000..d478507 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/SignerInfo.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class SignerInfo + : Asn1Encodable + { + private DerInteger version; + private SignerIdentifier sid; + private AlgorithmIdentifier digAlgorithm; + private Asn1Set authenticatedAttributes; + private AlgorithmIdentifier digEncryptionAlgorithm; + private Asn1OctetString encryptedDigest; + private Asn1Set unauthenticatedAttributes; + + public static SignerInfo GetInstance( + object obj) + { + if (obj == null || obj is SignerInfo) + { + return (SignerInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new SignerInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public SignerInfo( + SignerIdentifier sid, + AlgorithmIdentifier digAlgorithm, + Asn1Set authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + Asn1OctetString encryptedDigest, + Asn1Set unauthenticatedAttributes) + { + if (sid.IsTagged) + { + this.version = new DerInteger(3); + } + else + { + this.version = new DerInteger(1); + } + + this.sid = sid; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = authenticatedAttributes; + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public SignerInfo( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + version = (DerInteger) e.Current; + + e.MoveNext(); + sid = SignerIdentifier.GetInstance(e.Current); + + e.MoveNext(); + digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current); + + e.MoveNext(); + object obj = e.Current; + + if (obj is Asn1TaggedObject) + { + authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false); + + e.MoveNext(); + digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current); + } + else + { + authenticatedAttributes = null; + digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj); + } + + e.MoveNext(); + encryptedDigest = DerOctetString.GetInstance(e.Current); + + if (e.MoveNext()) + { + unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false); + } + else + { + unauthenticatedAttributes = null; + } + } + + public DerInteger Version { get { return version; } } + + public SignerIdentifier SignerID { get { return sid; } } + + public Asn1Set AuthenticatedAttributes { get { return authenticatedAttributes; } } + + public AlgorithmIdentifier DigestAlgorithm { get { return digAlgorithm; } } + + public Asn1OctetString EncryptedDigest { get { return encryptedDigest; } } + + public AlgorithmIdentifier DigestEncryptionAlgorithm { get { return digEncryptionAlgorithm; } } + + public Asn1Set UnauthenticatedAttributes { get { return unauthenticatedAttributes; } } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  SignerInfo ::= Sequence {
      +         *      version Version,
      +         *      SignerIdentifier sid,
      +         *      digestAlgorithm DigestAlgorithmIdentifier,
      +         *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
      +         *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
      +         *      encryptedDigest EncryptedDigest,
      +         *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
      +         *  }
      +         *
      +         *  EncryptedDigest ::= OCTET STRING
      +         *
      +         *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
      +         *
      +         *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, sid, digAlgorithm); + + if (authenticatedAttributes != null) + { + v.Add(new DerTaggedObject(false, 0, authenticatedAttributes)); + } + + v.Add(digEncryptionAlgorithm, encryptedDigest); + + if (unauthenticatedAttributes != null) + { + v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cms/Time.cs b/iTechSharp/srcbc/asn1/cms/Time.cs new file mode 100644 index 0000000..3fad3b9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cms/Time.cs @@ -0,0 +1,124 @@ +using System; +using System.Globalization; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Cms +{ + public class Time + : Asn1Encodable + { + private readonly Asn1Object time; + + public static Time GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public Time( + Asn1Object time) + { + if (!(time is DerUtcTime) + && !(time is DerGeneralizedTime)) + { + throw new ArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + DateTime date) + { + string d = date.ToString("yyyyMMddHHmmss") + "Z"; + + int year = int.Parse(d.Substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DerGeneralizedTime(d); + } + else + { + time = new DerUtcTime(d.Substring(2)); + } + } + + public static Time GetInstance( + object obj) + { + if (obj is Time) + { + return (Time)obj; + } + + if (obj is DerUtcTime) + { + return new Time((DerUtcTime)obj); + } + + if (obj is DerGeneralizedTime) + { + return new Time((DerGeneralizedTime)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public string TimeString + { + get + { + if (time is DerUtcTime) + { + return ((DerUtcTime)time).AdjustedTimeString; + } + else + { + return ((DerGeneralizedTime)time).GetTime(); + } + } + } + + public DateTime Date + { + get + { + try + { + if (time is DerUtcTime) + { + return ((DerUtcTime)time).ToAdjustedDateTime(); + } + + return ((DerGeneralizedTime)time).ToDateTime(); + } + catch (FormatException e) + { + // this should never happen + throw new InvalidOperationException("invalid date string: " + e.Message); + } + } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Time ::= CHOICE {
      +         *             utcTime        UTCTime,
      +         *             generalTime    GeneralizedTime }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return time; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/CryptoProObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/cryptopro/CryptoProObjectIdentifiers.cs new file mode 100644 index 0000000..6e0e023 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/CryptoProObjectIdentifiers.cs @@ -0,0 +1,48 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + public abstract class CryptoProObjectIdentifiers + { + // GOST Algorithms OBJECT IDENTIFIERS : + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)} + public const string GostID = "1.2.643.2.2"; + + public static readonly DerObjectIdentifier GostR3411 = new DerObjectIdentifier(GostID + ".9"); + + public static readonly DerObjectIdentifier GostR28147Cbc = new DerObjectIdentifier(GostID + ".21"); + + public static readonly DerObjectIdentifier GostR3410x94 = new DerObjectIdentifier(GostID + ".20"); + public static readonly DerObjectIdentifier GostR3410x2001 = new DerObjectIdentifier(GostID + ".19"); + public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x94 = new DerObjectIdentifier(GostID + ".4"); + public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x2001 = new DerObjectIdentifier(GostID + ".3"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) } + public static readonly DerObjectIdentifier GostR3411x94CryptoProParamSet = new DerObjectIdentifier(GostID + ".30.1"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) } + public static readonly DerObjectIdentifier GostR3410x94CryptoProA = new DerObjectIdentifier(GostID + ".32.2"); + public static readonly DerObjectIdentifier GostR3410x94CryptoProB = new DerObjectIdentifier(GostID + ".32.3"); + public static readonly DerObjectIdentifier GostR3410x94CryptoProC = new DerObjectIdentifier(GostID + ".32.4"); + public static readonly DerObjectIdentifier GostR3410x94CryptoProD = new DerObjectIdentifier(GostID + ".32.5"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) } + public static readonly DerObjectIdentifier GostR3410x94CryptoProXchA = new DerObjectIdentifier(GostID + ".33.1"); + public static readonly DerObjectIdentifier GostR3410x94CryptoProXchB = new DerObjectIdentifier(GostID + ".33.2"); + public static readonly DerObjectIdentifier GostR3410x94CryptoProXchC = new DerObjectIdentifier(GostID + ".33.3"); + + //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) } + public static readonly DerObjectIdentifier GostR3410x2001CryptoProA = new DerObjectIdentifier(GostID + ".35.1"); + public static readonly DerObjectIdentifier GostR3410x2001CryptoProB = new DerObjectIdentifier(GostID + ".35.2"); + public static readonly DerObjectIdentifier GostR3410x2001CryptoProC = new DerObjectIdentifier(GostID + ".35.3"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) } + public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchA = new DerObjectIdentifier(GostID + ".36.0"); + public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchB = new DerObjectIdentifier(GostID + ".36.1"); + + public static readonly DerObjectIdentifier GostElSgDH3410Default = new DerObjectIdentifier(GostID + ".36.0"); + public static readonly DerObjectIdentifier GostElSgDH3410x1 = new DerObjectIdentifier(GostID + ".36.1"); + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/ECGOST3410NamedCurves.cs b/iTechSharp/srcbc/asn1/cryptopro/ECGOST3410NamedCurves.cs new file mode 100644 index 0000000..76b95bf --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/ECGOST3410NamedCurves.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + /** + * table of the available named parameters for GOST 3410-2001. + */ + public sealed class ECGost3410NamedCurves + { + private ECGost3410NamedCurves() + { + } + + internal static readonly Hashtable objIds = new Hashtable(); + internal static readonly Hashtable parameters = new Hashtable(); + internal static readonly Hashtable names = new Hashtable(); + + static ECGost3410NamedCurves() + { + BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); + BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + FpCurve curve = new FpCurve( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a + new BigInteger("166")); // b + + ECDomainParameters ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + BigInteger.One, // x + new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y + false), + mod_q); + + parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams; + + mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); + mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + curve = new FpCurve( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), + new BigInteger("166")); + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + BigInteger.One, // x + new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y + false), + mod_q); + + parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams; + + mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p + mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q + + curve = new FpCurve( + mod_p, // p + new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a + new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595")); // b + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + BigInteger.One, // x + new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124"), // y + false), + mod_q); // q + + parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams; + + mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); + mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); + + curve = new FpCurve( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), + new BigInteger("32858")); + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + BigInteger.Zero, // x + new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y + false), + mod_q); + + parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams; + + mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p + mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q + curve = new FpCurve( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a + new BigInteger("32858")); // b + + ecParams = new ECDomainParameters( + curve, + curve.CreatePoint( + BigInteger.Zero, // x + new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y + false), + mod_q); // q + + parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams; + + objIds["GostR3410-2001-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProA; + objIds["GostR3410-2001-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProB; + objIds["GostR3410-2001-CryptoPro-C"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProC; + objIds["GostR3410-2001-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA; + objIds["GostR3410-2001-CryptoPro-XchB"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB; + + names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = "GostR3410-2001-CryptoPro-A"; + names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = "GostR3410-2001-CryptoPro-B"; + names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = "GostR3410-2001-CryptoPro-C"; + names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = "GostR3410-2001-CryptoPro-XchA"; + names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = "GostR3410-2001-CryptoPro-XchB"; + } + + /** + * return the ECDomainParameters object for the given OID, null if it + * isn't present. + * + * @param oid an object identifier representing a named parameters, if present. + */ + public static ECDomainParameters GetByOid( + DerObjectIdentifier oid) + { + return (ECDomainParameters) parameters[oid]; + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + + public static ECDomainParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name]; + + if (oid != null) + { + return (ECDomainParameters) parameters[oid]; + } + + return null; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string) names[oid]; + } + + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier) objIds[name]; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/ECGOST3410ParamSetParameters.cs b/iTechSharp/srcbc/asn1/cryptopro/ECGOST3410ParamSetParameters.cs new file mode 100644 index 0000000..6f4435d --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/ECGOST3410ParamSetParameters.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + public class ECGost3410ParamSetParameters + : Asn1Encodable + { + internal readonly DerInteger p, q, a, b, x, y; + + public static ECGost3410ParamSetParameters GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static ECGost3410ParamSetParameters GetInstance( + object obj) + { + if (obj == null || obj is ECGost3410ParamSetParameters) + { + return (ECGost3410ParamSetParameters) obj; + } + + if (obj is Asn1Sequence) + { + return new ECGost3410ParamSetParameters((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name); + } + + public ECGost3410ParamSetParameters( + BigInteger a, + BigInteger b, + BigInteger p, + BigInteger q, + int x, + BigInteger y) + { + this.a = new DerInteger(a); + this.b = new DerInteger(b); + this.p = new DerInteger(p); + this.q = new DerInteger(q); + this.x = new DerInteger(x); + this.y = new DerInteger(y); + } + + public ECGost3410ParamSetParameters( + Asn1Sequence seq) + { + if (seq.Count != 6) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.a = DerInteger.GetInstance(seq[0]); + this.b = DerInteger.GetInstance(seq[1]); + this.p = DerInteger.GetInstance(seq[2]); + this.q = DerInteger.GetInstance(seq[3]); + this.x = DerInteger.GetInstance(seq[4]); + this.y = DerInteger.GetInstance(seq[5]); + } + + public BigInteger P + { + get { return p.PositiveValue; } + } + + public BigInteger Q + { + get { return q.PositiveValue; } + } + + public BigInteger A + { + get { return a.PositiveValue; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(a, b, p, q, x, y); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/GOST28147Parameters.cs b/iTechSharp/srcbc/asn1/cryptopro/GOST28147Parameters.cs new file mode 100644 index 0000000..eb7e0e3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/GOST28147Parameters.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + public class Gost28147Parameters + : Asn1Encodable + { + private readonly Asn1OctetString iv; + private readonly DerObjectIdentifier paramSet; + + public static Gost28147Parameters GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static Gost28147Parameters GetInstance( + object obj) + { + if (obj == null || obj is Gost28147Parameters) + { + return (Gost28147Parameters) obj; + } + + if (obj is Asn1Sequence) + { + return new Gost28147Parameters((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name); + } + + private Gost28147Parameters( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.iv = Asn1OctetString.GetInstance(seq[0]); + this.paramSet = DerObjectIdentifier.GetInstance(seq[1]); + } + + /** + *
      +         * Gost28147-89-Parameters ::=
      +         *               SEQUENCE {
      +         *                       iv                   Gost28147-89-IV,
      +         *                       encryptionParamSet   OBJECT IDENTIFIER
      +         *                }
      +         *
      +         *   Gost28147-89-IV ::= OCTET STRING (SIZE (8))
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(iv, paramSet); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/GOST3410NamedParameters.cs b/iTechSharp/srcbc/asn1/cryptopro/GOST3410NamedParameters.cs new file mode 100644 index 0000000..19ade03 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/GOST3410NamedParameters.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + /** + * table of the available named parameters for GOST 3410-94. + */ + public sealed class Gost3410NamedParameters + { + private Gost3410NamedParameters() + { + } + + private static readonly Hashtable objIds = new Hashtable(); + private static readonly Hashtable parameters = new Hashtable(); + + private static readonly Gost3410ParamSetParameters cryptoProA = new Gost3410ParamSetParameters( + 1024, + new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"), + new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"), + new BigInteger("100997906755055304772081815535925224869841082572053457874823515875577147990529272777244152852699298796483356699682842027972896052747173175480590485607134746852141928680912561502802222185647539190902656116367847270145019066794290930185446216399730872221732889830323194097355403213400972588322876850946740663962") + // validationAlgorithm { + // algorithm + // id-GostR3410-94-bBis, + // parameters + // GostR3410-94-ValidationBisParameters: { + // x0 1376285941, + // c 3996757427 + // } + // } + + ); + + private static readonly Gost3410ParamSetParameters cryptoProB = new Gost3410ParamSetParameters( + 1024, + new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"), + new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"), + new BigInteger("42941826148615804143873447737955502392672345968607143066798112994089471231420027060385216699563848719957657284814898909770759462613437669456364882730370838934791080835932647976778601915343474400961034231316672578686920482194932878633360203384797092684342247621055760235016132614780652761028509445403338652341") + // validationAlgorithm { + // algorithm + // id-GostR3410-94-bBis, + // parameters + // GostR3410-94-ValidationBisParameters: { + // x0 1536654555, + // c 1855361757, + // d 14408629386140014567655 + //4902939282056547857802241461782996702017713059974755104394739915140 + //6115284791024439062735788342744854120601660303926203867703556828005 + //8957203818114895398976594425537561271800850306 + // } + // } + //} + ); + + private static readonly Gost3410ParamSetParameters cryptoProXchA = new Gost3410ParamSetParameters( + 1024, + new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"), + new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"), + new BigInteger("133531813272720673433859519948319001217942375967847486899482359599369642528734712461590403327731821410328012529253871914788598993103310567744136196364803064721377826656898686468463277710150809401182608770201615324990468332931294920912776241137878030224355746606283971659376426832674269780880061631528163475887") + ); + + static Gost3410NamedParameters() + { + parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProA] = cryptoProA; + parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProB] = cryptoProB; + //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProC] = cryptoProC; + //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProD] = cryptoProD; + parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA] = cryptoProXchA; + //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchB] = cryptoProXchA; + //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchC] = cryptoProXchA; + + objIds["GostR3410-94-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProA; + objIds["GostR3410-94-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProB; + objIds["GostR3410-94-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA; + } + + /** + * return the GOST3410ParamSetParameters object for the given OID, null if it + * isn't present. + * + * @param oid an object identifier representing a named parameters, if present. + */ + public static Gost3410ParamSetParameters GetByOid( + DerObjectIdentifier oid) + { + return (Gost3410ParamSetParameters) parameters[oid]; + } + + /** + * returns an enumeration containing the name strings for parameters + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + + public static Gost3410ParamSetParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name]; + + if (oid != null) + { + return (Gost3410ParamSetParameters) parameters[oid]; + } + + return null; + } + + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier) objIds[name]; + } + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/GOST3410ParamSetParameters.cs b/iTechSharp/srcbc/asn1/cryptopro/GOST3410ParamSetParameters.cs new file mode 100644 index 0000000..f133cdf --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/GOST3410ParamSetParameters.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + public class Gost3410ParamSetParameters + : Asn1Encodable + { + private readonly int keySize; + private readonly DerInteger p, q, a; + + public static Gost3410ParamSetParameters GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static Gost3410ParamSetParameters GetInstance( + object obj) + { + if (obj == null || obj is Gost3410ParamSetParameters) + { + return (Gost3410ParamSetParameters) obj; + } + + if (obj is Asn1Sequence) + { + return new Gost3410ParamSetParameters((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name); + } + + public Gost3410ParamSetParameters( + int keySize, + BigInteger p, + BigInteger q, + BigInteger a) + { + this.keySize = keySize; + this.p = new DerInteger(p); + this.q = new DerInteger(q); + this.a = new DerInteger(a); + } + + private Gost3410ParamSetParameters( + Asn1Sequence seq) + { + if (seq.Count != 4) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.keySize = DerInteger.GetInstance(seq[0]).Value.IntValue; + this.p = DerInteger.GetInstance(seq[1]); + this.q = DerInteger.GetInstance(seq[2]); + this.a = DerInteger.GetInstance(seq[3]); + } + + public int KeySize + { + get { return keySize; } + } + + public BigInteger P + { + get { return p.PositiveValue; } + } + + public BigInteger Q + { + get { return q.PositiveValue; } + } + + public BigInteger A + { + get { return a.PositiveValue; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(new DerInteger(keySize), p, q, a); + } + } +} diff --git a/iTechSharp/srcbc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs b/iTechSharp/srcbc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs new file mode 100644 index 0000000..8bc1460 --- /dev/null +++ b/iTechSharp/srcbc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs @@ -0,0 +1,99 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.CryptoPro +{ + public class Gost3410PublicKeyAlgParameters + : Asn1Encodable + { + private DerObjectIdentifier publicKeyParamSet; + private DerObjectIdentifier digestParamSet; + private DerObjectIdentifier encryptionParamSet; + + public static Gost3410PublicKeyAlgParameters GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static Gost3410PublicKeyAlgParameters GetInstance( + object obj) + { + if (obj == null || obj is Gost3410PublicKeyAlgParameters) + { + return (Gost3410PublicKeyAlgParameters) obj; + } + + if (obj is Asn1Sequence) + { + return new Gost3410PublicKeyAlgParameters((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name); + } + + public Gost3410PublicKeyAlgParameters( + DerObjectIdentifier publicKeyParamSet, + DerObjectIdentifier digestParamSet) + : this (publicKeyParamSet, digestParamSet, null) + { + } + + public Gost3410PublicKeyAlgParameters( + DerObjectIdentifier publicKeyParamSet, + DerObjectIdentifier digestParamSet, + DerObjectIdentifier encryptionParamSet) + { + if (publicKeyParamSet == null) + throw new ArgumentNullException("publicKeyParamSet"); + if (digestParamSet == null) + throw new ArgumentNullException("digestParamSet"); + + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = encryptionParamSet; + } + + public Gost3410PublicKeyAlgParameters( + Asn1Sequence seq) + { + this.publicKeyParamSet = (DerObjectIdentifier) seq[0]; + this.digestParamSet = (DerObjectIdentifier) seq[1]; + + if (seq.Count > 2) + { + this.encryptionParamSet = (DerObjectIdentifier) seq[2]; + } + } + + public DerObjectIdentifier PublicKeyParamSet + { + get { return publicKeyParamSet; } + } + + public DerObjectIdentifier DigestParamSet + { + get { return digestParamSet; } + } + + public DerObjectIdentifier EncryptionParamSet + { + get { return encryptionParamSet; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + publicKeyParamSet, digestParamSet); + + if (encryptionParamSet != null) + { + v.Add(encryptionParamSet); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CertificateValues.cs b/iTechSharp/srcbc/asn1/esf/CertificateValues.cs new file mode 100644 index 0000000..e0fb39b --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CertificateValues.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.3.1 Certificate Values Attribute Definition + /// + /// CertificateValues ::= SEQUENCE OF Certificate + /// + /// + public class CertificateValues + : Asn1Encodable + { + private readonly Asn1Sequence certificates; + + public static CertificateValues GetInstance( + object obj) + { + if (obj == null || obj is CertificateValues) + return (CertificateValues) obj; + + if (obj is Asn1Sequence) + return new CertificateValues((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CertificateValues' factory: " + + obj.GetType().Name, + "obj"); + } + + private CertificateValues( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + + foreach (Asn1Encodable ae in seq) + { + X509CertificateStructure.GetInstance(ae.ToAsn1Object()); + } + + this.certificates = seq; + } + + public CertificateValues( + params X509CertificateStructure[] certificates) + { + if (certificates == null) + throw new ArgumentNullException("certificates"); + + this.certificates = new DerSequence(certificates); + } + + public CertificateValues( + IEnumerable certificates) + { + if (certificates == null) + throw new ArgumentNullException("certificates"); + if (!CollectionUtilities.CheckElementsAreOfType(certificates, typeof(X509CertificateStructure))) + throw new ArgumentException("Must contain only 'X509CertificateStructure' objects", "certificates"); + + this.certificates = new DerSequence( + Asn1EncodableVector.FromEnumerable(certificates)); + } + + public X509CertificateStructure[] GetCertificates() + { + X509CertificateStructure[] result = new X509CertificateStructure[certificates.Count]; + for (int i = 0; i < certificates.Count; ++i) + { + result[i] = X509CertificateStructure.GetInstance(certificates[i]); + } + return result; + } + + public override Asn1Object ToAsn1Object() + { + return certificates; + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CommitmentTypeIdentifier.cs b/iTechSharp/srcbc/asn1/esf/CommitmentTypeIdentifier.cs new file mode 100644 index 0000000..65cd45b --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CommitmentTypeIdentifier.cs @@ -0,0 +1,17 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.Esf +{ + public abstract class CommitmentTypeIdentifier + { + public static readonly DerObjectIdentifier ProofOfOrigin = PkcsObjectIdentifiers.IdCtiEtsProofOfOrigin; + public static readonly DerObjectIdentifier ProofOfReceipt = PkcsObjectIdentifiers.IdCtiEtsProofOfReceipt; + public static readonly DerObjectIdentifier ProofOfDelivery = PkcsObjectIdentifiers.IdCtiEtsProofOfDelivery; + public static readonly DerObjectIdentifier ProofOfSender = PkcsObjectIdentifiers.IdCtiEtsProofOfSender; + public static readonly DerObjectIdentifier ProofOfApproval = PkcsObjectIdentifiers.IdCtiEtsProofOfApproval; + public static readonly DerObjectIdentifier ProofOfCreation = PkcsObjectIdentifiers.IdCtiEtsProofOfCreation; + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CommitmentTypeIndication.cs b/iTechSharp/srcbc/asn1/esf/CommitmentTypeIndication.cs new file mode 100644 index 0000000..8342cbf --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CommitmentTypeIndication.cs @@ -0,0 +1,95 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Esf +{ + public class CommitmentTypeIndication + : Asn1Encodable + { + private readonly DerObjectIdentifier commitmentTypeId; + private readonly Asn1Sequence commitmentTypeQualifier; + + public static CommitmentTypeIndication GetInstance( + object obj) + { + if (obj == null || obj is CommitmentTypeIndication) + return (CommitmentTypeIndication) obj; + + if (obj is Asn1Sequence) + return new CommitmentTypeIndication((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CommitmentTypeIndication' factory: " + + obj.GetType().Name, + "obj"); + } + + public CommitmentTypeIndication( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.commitmentTypeId = (DerObjectIdentifier) seq[0].ToAsn1Object(); + + if (seq.Count > 1) + { + this.commitmentTypeQualifier = (Asn1Sequence) seq[1].ToAsn1Object(); + } + } + + public CommitmentTypeIndication( + DerObjectIdentifier commitmentTypeId) + : this(commitmentTypeId, null) + { + } + + public CommitmentTypeIndication( + DerObjectIdentifier commitmentTypeId, + Asn1Sequence commitmentTypeQualifier) + { + if (commitmentTypeId == null) + throw new ArgumentNullException("commitmentTypeId"); + + this.commitmentTypeId = commitmentTypeId; + + if (commitmentTypeQualifier != null) + { + this.commitmentTypeQualifier = commitmentTypeQualifier; + } + } + + public DerObjectIdentifier CommitmentTypeID + { + get { return commitmentTypeId; } + } + + public Asn1Sequence CommitmentTypeQualifier + { + get { return commitmentTypeQualifier; } + } + + /** + *
      +        * CommitmentTypeIndication ::= SEQUENCE {
      +        *      commitmentTypeId   CommitmentTypeIdentifier,
      +        *      commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
      +        *              CommitmentTypeQualifier OPTIONAL }
      +        * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(commitmentTypeId); + + if (commitmentTypeQualifier != null) + { + v.Add(commitmentTypeQualifier); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CommitmentTypeQualifier.cs b/iTechSharp/srcbc/asn1/esf/CommitmentTypeQualifier.cs new file mode 100644 index 0000000..09ff707 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CommitmentTypeQualifier.cs @@ -0,0 +1,119 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /** + * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126). + * + *
      +    *   CommitmentTypeQualifier ::= SEQUENCE {
      +    *       commitmentTypeIdentifier  CommitmentTypeIdentifier,
      +    *       qualifier          ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
      +    * 
      + */ + public class CommitmentTypeQualifier + : Asn1Encodable + { + private readonly DerObjectIdentifier commitmentTypeIdentifier; + private readonly Asn1Object qualifier; + + /** + * Creates a new CommitmentTypeQualifier instance. + * + * @param commitmentTypeIdentifier a CommitmentTypeIdentifier value + */ + public CommitmentTypeQualifier( + DerObjectIdentifier commitmentTypeIdentifier) + : this(commitmentTypeIdentifier, null) + { + } + + /** + * Creates a new CommitmentTypeQualifier instance. + * + * @param commitmentTypeIdentifier a CommitmentTypeIdentifier value + * @param qualifier the qualifier, defined by the above field. + */ + public CommitmentTypeQualifier( + DerObjectIdentifier commitmentTypeIdentifier, + Asn1Encodable qualifier) + { + if (commitmentTypeIdentifier == null) + throw new ArgumentNullException("commitmentTypeIdentifier"); + + this.commitmentTypeIdentifier = commitmentTypeIdentifier; + + if (qualifier != null) + { + this.qualifier = qualifier.ToAsn1Object(); + } + } + + /** + * Creates a new CommitmentTypeQualifier instance. + * + * @param as CommitmentTypeQualifier structure + * encoded as an Asn1Sequence. + */ + public CommitmentTypeQualifier( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + commitmentTypeIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object(); + + if (seq.Count > 1) + { + qualifier = seq[1].ToAsn1Object(); + } + } + + public static CommitmentTypeQualifier GetInstance( + object obj) + { + if (obj == null || obj is CommitmentTypeQualifier) + return (CommitmentTypeQualifier) obj; + + if (obj is Asn1Sequence) + return new CommitmentTypeQualifier((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CommitmentTypeQualifier' factory: " + + obj.GetType().Name, + "obj"); + } + + public DerObjectIdentifier CommitmentTypeIdentifier + { + get { return commitmentTypeIdentifier; } + } + + public Asn1Object Qualifier + { + get { return qualifier; } + } + + /** + * Returns a DER-encodable representation of this instance. + * + * @return a Asn1Object value + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + commitmentTypeIdentifier); + + if (qualifier != null) + { + v.Add(qualifier); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CompleteCertificateRefs.cs b/iTechSharp/srcbc/asn1/esf/CompleteCertificateRefs.cs new file mode 100644 index 0000000..7f1c835 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CompleteCertificateRefs.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.1 Complete Certificate Refs Attribute Definition + /// + /// CompleteCertificateRefs ::= SEQUENCE OF OtherCertID + /// + /// + public class CompleteCertificateRefs + : Asn1Encodable + { + private readonly Asn1Sequence otherCertIDs; + + public static CompleteCertificateRefs GetInstance( + object obj) + { + if (obj == null || obj is CompleteCertificateRefs) + return (CompleteCertificateRefs) obj; + + if (obj is Asn1Sequence) + return new CompleteCertificateRefs((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CompleteCertificateRefs' factory: " + + obj.GetType().Name, + "obj"); + } + + private CompleteCertificateRefs( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + + foreach (Asn1Encodable ae in seq) + { + OtherCertID.GetInstance(ae.ToAsn1Object()); + } + + this.otherCertIDs = seq; + } + + public CompleteCertificateRefs( + params OtherCertID[] otherCertIDs) + { + if (otherCertIDs == null) + throw new ArgumentNullException("otherCertIDs"); + + this.otherCertIDs = new DerSequence(otherCertIDs); + } + + public CompleteCertificateRefs( + IEnumerable otherCertIDs) + { + if (otherCertIDs == null) + throw new ArgumentNullException("otherCertIDs"); + if (!CollectionUtilities.CheckElementsAreOfType(otherCertIDs, typeof(OtherCertID))) + throw new ArgumentException("Must contain only 'OtherCertID' objects", "otherCertIDs"); + + this.otherCertIDs = new DerSequence( + Asn1EncodableVector.FromEnumerable(otherCertIDs)); + } + + public OtherCertID[] GetOtherCertIDs() + { + OtherCertID[] result = new OtherCertID[otherCertIDs.Count]; + for (int i = 0; i < otherCertIDs.Count; ++i) + { + result[i] = OtherCertID.GetInstance(otherCertIDs[i].ToAsn1Object()); + } + return result; + } + + public override Asn1Object ToAsn1Object() + { + return otherCertIDs; + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CompleteRevocationRefs.cs b/iTechSharp/srcbc/asn1/esf/CompleteRevocationRefs.cs new file mode 100644 index 0000000..4e1fb40 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CompleteRevocationRefs.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef + /// + /// + public class CompleteRevocationRefs + : Asn1Encodable + { + private readonly Asn1Sequence crlOcspRefs; + + public static CompleteRevocationRefs GetInstance( + object obj) + { + if (obj == null || obj is CompleteRevocationRefs) + return (CompleteRevocationRefs) obj; + + if (obj is Asn1Sequence) + return new CompleteRevocationRefs((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CompleteRevocationRefs' factory: " + + obj.GetType().Name, + "obj"); + } + + private CompleteRevocationRefs( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + + foreach (Asn1Encodable ae in seq) + { + CrlOcspRef.GetInstance(ae.ToAsn1Object()); + } + + this.crlOcspRefs = seq; + } + + public CompleteRevocationRefs( + params CrlOcspRef[] crlOcspRefs) + { + if (crlOcspRefs == null) + throw new ArgumentNullException("crlOcspRefs"); + + this.crlOcspRefs = new DerSequence(crlOcspRefs); + } + + public CompleteRevocationRefs( + IEnumerable crlOcspRefs) + { + if (crlOcspRefs == null) + throw new ArgumentNullException("crlOcspRefs"); + if (!CollectionUtilities.CheckElementsAreOfType(crlOcspRefs, typeof(CrlOcspRef))) + throw new ArgumentException("Must contain only 'CrlOcspRef' objects", "crlOcspRefs"); + + this.crlOcspRefs = new DerSequence( + Asn1EncodableVector.FromEnumerable(crlOcspRefs)); + } + + public CrlOcspRef[] GetCrlOcspRefs() + { + CrlOcspRef[] result = new CrlOcspRef[crlOcspRefs.Count]; + for (int i = 0; i < crlOcspRefs.Count; ++i) + { + result[i] = CrlOcspRef.GetInstance(crlOcspRefs[i].ToAsn1Object()); + } + return result; + } + + public override Asn1Object ToAsn1Object() + { + return crlOcspRefs; + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CrlIdentifier.cs b/iTechSharp/srcbc/asn1/esf/CrlIdentifier.cs new file mode 100644 index 0000000..dfff7d8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CrlIdentifier.cs @@ -0,0 +1,110 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// CrlIdentifier ::= SEQUENCE + /// { + /// crlissuer Name, + /// crlIssuedTime UTCTime, + /// crlNumber INTEGER OPTIONAL + /// } + /// + /// + public class CrlIdentifier + : Asn1Encodable + { + private readonly X509Name crlIssuer; + private readonly DerUtcTime crlIssuedTime; + private readonly DerInteger crlNumber; + + public static CrlIdentifier GetInstance( + object obj) + { + if (obj == null || obj is CrlIdentifier) + return (CrlIdentifier) obj; + + if (obj is Asn1Sequence) + return new CrlIdentifier((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CrlIdentifier' factory: " + + obj.GetType().Name, + "obj"); + } + + private CrlIdentifier( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 2 || seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.crlIssuer = X509Name.GetInstance(seq[0]); + this.crlIssuedTime = DerUtcTime.GetInstance(seq[1]); + + if (seq.Count > 2) + { + this.crlNumber = DerInteger.GetInstance(seq[2]); + } + } + + public CrlIdentifier( + X509Name crlIssuer, + DateTime crlIssuedTime) + : this(crlIssuer, crlIssuedTime, null) + { + } + + public CrlIdentifier( + X509Name crlIssuer, + DateTime crlIssuedTime, + BigInteger crlNumber) + { + if (crlIssuer == null) + throw new ArgumentNullException("crlIssuer"); + + this.crlIssuer = crlIssuer; + this.crlIssuedTime = new DerUtcTime(crlIssuedTime); + + if (crlNumber != null) + { + this.crlNumber = new DerInteger(crlNumber); + } + } + + public X509Name CrlIssuer + { + get { return crlIssuer; } + } + + public DateTime CrlIssuedTime + { + get { return crlIssuedTime.ToAdjustedDateTime(); } + } + + public BigInteger CrlNumber + { + get { return crlNumber == null ? null : crlNumber.Value; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + crlIssuer.ToAsn1Object(), crlIssuedTime); + + if (crlNumber != null) + { + v.Add(crlNumber); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CrlListID.cs b/iTechSharp/srcbc/asn1/esf/CrlListID.cs new file mode 100644 index 0000000..2aae9b9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CrlListID.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// CRLListID ::= SEQUENCE + /// { + /// crls SEQUENCE OF CrlValidatedID + /// } + /// + /// + public class CrlListID + : Asn1Encodable + { + private readonly Asn1Sequence crls; + + public static CrlListID GetInstance( + object obj) + { + if (obj == null || obj is CrlListID) + return (CrlListID) obj; + + if (obj is Asn1Sequence) + return new CrlListID((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CrlListID' factory: " + + obj.GetType().Name, + "obj"); + } + + private CrlListID( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 1) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.crls = (Asn1Sequence) seq[0].ToAsn1Object(); + + foreach (Asn1Encodable ae in this.crls) + { + CrlValidatedID.GetInstance(ae.ToAsn1Object()); + } + } + + public CrlListID( + params CrlValidatedID[] crls) + { + if (crls == null) + throw new ArgumentNullException("crls"); + + this.crls = new DerSequence(crls); + } + + public CrlListID( + IEnumerable crls) + { + if (crls == null) + throw new ArgumentNullException("crls"); + if (!CollectionUtilities.CheckElementsAreOfType(crls, typeof(CrlValidatedID))) + throw new ArgumentException("Must contain only 'CrlValidatedID' objects", "crls"); + + this.crls = new DerSequence( + Asn1EncodableVector.FromEnumerable(crls)); + } + + public CrlValidatedID[] GetCrls() + { + CrlValidatedID[] result = new CrlValidatedID[crls.Count]; + for (int i = 0; i < crls.Count; ++i) + { + result[i] = CrlValidatedID.GetInstance(crls[i].ToAsn1Object()); + } + return result; + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(crls); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CrlOcspRef.cs b/iTechSharp/srcbc/asn1/esf/CrlOcspRef.cs new file mode 100644 index 0000000..c8e10d5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CrlOcspRef.cs @@ -0,0 +1,111 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// CrlOcspRef ::= SEQUENCE { + /// crlids [0] CRLListID OPTIONAL, + /// ocspids [1] OcspListID OPTIONAL, + /// otherRev [2] OtherRevRefs OPTIONAL + /// } + /// + /// + public class CrlOcspRef + : Asn1Encodable + { + private readonly CrlListID crlids; + private readonly OcspListID ocspids; + private readonly OtherRevRefs otherRev; + + public static CrlOcspRef GetInstance( + object obj) + { + if (obj == null || obj is CrlOcspRef) + return (CrlOcspRef) obj; + + if (obj is Asn1Sequence) + return new CrlOcspRef((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CrlOcspRef' factory: " + + obj.GetType().Name, + "obj"); + } + + private CrlOcspRef( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + + foreach (Asn1TaggedObject taggedObj in seq) + { + Asn1Object asn1Obj = taggedObj.GetObject(); + + switch (taggedObj.TagNo) + { + case 0: + this.crlids = CrlListID.GetInstance(asn1Obj); + break; + case 1: + this.ocspids = OcspListID.GetInstance(asn1Obj); + break; + case 2: + this.otherRev = OtherRevRefs.GetInstance(asn1Obj); + break; + default: + throw new ArgumentException("Illegal tag in CrlOcspRef", "seq"); + } + } + } + + public CrlOcspRef( + CrlListID crlids, + OcspListID ocspids, + OtherRevRefs otherRev) + { + this.crlids = crlids; + this.ocspids = ocspids; + this.otherRev = otherRev; + } + + public CrlListID CrlIDs + { + get { return crlids; } + } + + public OcspListID OcspIDs + { + get { return ocspids; } + } + + public OtherRevRefs OtherRev + { + get { return otherRev; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (crlids != null) + { + v.Add(new DerTaggedObject(true, 0, crlids.ToAsn1Object())); + } + + if (ocspids != null) + { + v.Add(new DerTaggedObject(true, 1, ocspids.ToAsn1Object())); + } + + if (otherRev != null) + { + v.Add(new DerTaggedObject(true, 2, otherRev.ToAsn1Object())); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/CrlValidatedID.cs b/iTechSharp/srcbc/asn1/esf/CrlValidatedID.cs new file mode 100644 index 0000000..165f547 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/CrlValidatedID.cs @@ -0,0 +1,89 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// CrlValidatedID ::= SEQUENCE { + /// crlHash OtherHash, + /// crlIdentifier CrlIdentifier OPTIONAL} + /// + /// + public class CrlValidatedID + : Asn1Encodable + { + private readonly OtherHash crlHash; + private readonly CrlIdentifier crlIdentifier; + + public static CrlValidatedID GetInstance( + object obj) + { + if (obj == null || obj is CrlValidatedID) + return (CrlValidatedID) obj; + + if (obj is Asn1Sequence) + return new CrlValidatedID((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'CrlValidatedID' factory: " + + obj.GetType().Name, + "obj"); + } + + private CrlValidatedID( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.crlHash = OtherHash.GetInstance(seq[0].ToAsn1Object()); + + if (seq.Count > 1) + { + this.crlIdentifier = CrlIdentifier.GetInstance(seq[1].ToAsn1Object()); + } + } + + public CrlValidatedID( + OtherHash crlHash) + : this(crlHash, null) + { + } + + public CrlValidatedID( + OtherHash crlHash, + CrlIdentifier crlIdentifier) + { + if (crlHash == null) + throw new ArgumentNullException("crlHash"); + + this.crlHash = crlHash; + this.crlIdentifier = crlIdentifier; + } + + public OtherHash CrlHash + { + get { return crlHash; } + } + + public CrlIdentifier CrlIdentifier + { + get { return crlIdentifier; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(crlHash.ToAsn1Object()); + + if (crlIdentifier != null) + { + v.Add(crlIdentifier.ToAsn1Object()); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/ESFAttributes.cs b/iTechSharp/srcbc/asn1/esf/ESFAttributes.cs new file mode 100644 index 0000000..31b8b43 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/ESFAttributes.cs @@ -0,0 +1,24 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.Esf +{ + public abstract class EsfAttributes + { + public static readonly DerObjectIdentifier SigPolicyId = PkcsObjectIdentifiers.IdAAEtsSigPolicyID; + public static readonly DerObjectIdentifier CommitmentType = PkcsObjectIdentifiers.IdAAEtsCommitmentType; + public static readonly DerObjectIdentifier SignerLocation = PkcsObjectIdentifiers.IdAAEtsSignerLocation; + public static readonly DerObjectIdentifier SignerAttr = PkcsObjectIdentifiers.IdAAEtsSignerAttr; + public static readonly DerObjectIdentifier OtherSigCert = PkcsObjectIdentifiers.IdAAEtsOtherSigCert; + public static readonly DerObjectIdentifier ContentTimestamp = PkcsObjectIdentifiers.IdAAEtsContentTimestamp; + public static readonly DerObjectIdentifier CertificateRefs = PkcsObjectIdentifiers.IdAAEtsCertificateRefs; + public static readonly DerObjectIdentifier RevocationRefs = PkcsObjectIdentifiers.IdAAEtsRevocationRefs; + public static readonly DerObjectIdentifier CertValues = PkcsObjectIdentifiers.IdAAEtsCertValues; + public static readonly DerObjectIdentifier RevocationValues = PkcsObjectIdentifiers.IdAAEtsRevocationValues; + public static readonly DerObjectIdentifier EscTimeStamp = PkcsObjectIdentifiers.IdAAEtsEscTimeStamp; + public static readonly DerObjectIdentifier CertCrlTimestamp = PkcsObjectIdentifiers.IdAAEtsCertCrlTimestamp; + public static readonly DerObjectIdentifier ArchiveTimestamp = PkcsObjectIdentifiers.IdAAEtsArchiveTimestamp; + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OcspIdentifier.cs b/iTechSharp/srcbc/asn1/esf/OcspIdentifier.cs new file mode 100644 index 0000000..949b682 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OcspIdentifier.cs @@ -0,0 +1,77 @@ +using System; + +using Org.BouncyCastle.Asn1.Ocsp; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// OcspIdentifier ::= SEQUENCE { + /// ocspResponderID ResponderID, + /// -- As in OCSP response data + /// producedAt GeneralizedTime + /// -- As in OCSP response data + /// } + /// + /// + public class OcspIdentifier + : Asn1Encodable + { + private readonly ResponderID ocspResponderID; + private readonly DerGeneralizedTime producedAt; + + public static OcspIdentifier GetInstance( + object obj) + { + if (obj == null || obj is OcspIdentifier) + return (OcspIdentifier) obj; + + if (obj is Asn1Sequence) + return new OcspIdentifier((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OcspIdentifier' factory: " + + obj.GetType().Name, + "obj"); + } + + private OcspIdentifier( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.ocspResponderID = ResponderID.GetInstance(seq[0].ToAsn1Object()); + this.producedAt = (DerGeneralizedTime) seq[1].ToAsn1Object(); + } + + public OcspIdentifier( + ResponderID ocspResponderID, + DateTime producedAt) + { + if (ocspResponderID == null) + throw new ArgumentNullException(); + + this.ocspResponderID = ocspResponderID; + this.producedAt = new DerGeneralizedTime(producedAt); + } + + public ResponderID OcspResponderID + { + get { return ocspResponderID; } + } + + public DateTime ProducedAt + { + get { return producedAt.ToDateTime(); } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(ocspResponderID, producedAt); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OcspListID.cs b/iTechSharp/srcbc/asn1/esf/OcspListID.cs new file mode 100644 index 0000000..1f3f3a3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OcspListID.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// OcspListID ::= SEQUENCE { + /// ocspResponses SEQUENCE OF OcspResponsesID + /// } + /// + /// + public class OcspListID + : Asn1Encodable + { + private readonly Asn1Sequence ocspResponses; + + public static OcspListID GetInstance( + object obj) + { + if (obj == null || obj is OcspListID) + return (OcspListID) obj; + + if (obj is Asn1Sequence) + return new OcspListID((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OcspListID' factory: " + + obj.GetType().Name, + "obj"); + } + + private OcspListID( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 1) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.ocspResponses = (Asn1Sequence) seq[0].ToAsn1Object(); + + foreach (Asn1Encodable ae in this.ocspResponses) + { + OcspResponsesID.GetInstance(ae.ToAsn1Object()); + } + } + + public OcspListID( + params OcspResponsesID[] ocspResponses) + { + if (ocspResponses == null) + throw new ArgumentNullException("ocspResponses"); + + this.ocspResponses = new DerSequence(ocspResponses); + } + + public OcspListID( + IEnumerable ocspResponses) + { + if (ocspResponses == null) + throw new ArgumentNullException("ocspResponses"); + if (!CollectionUtilities.CheckElementsAreOfType(ocspResponses, typeof(OcspResponsesID))) + throw new ArgumentException("Must contain only 'OcspResponsesID' objects", "ocspResponses"); + + this.ocspResponses = new DerSequence( + Asn1EncodableVector.FromEnumerable(ocspResponses)); + } + + public OcspResponsesID[] GetOcspResponses() + { + OcspResponsesID[] result = new OcspResponsesID[ocspResponses.Count]; + for (int i = 0; i < ocspResponses.Count; ++i) + { + result[i] = OcspResponsesID.GetInstance(ocspResponses[i].ToAsn1Object()); + } + return result; + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(ocspResponses); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OcspResponsesID.cs b/iTechSharp/srcbc/asn1/esf/OcspResponsesID.cs new file mode 100644 index 0000000..e09508a --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OcspResponsesID.cs @@ -0,0 +1,92 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// OcspResponsesID ::= SEQUENCE { + /// ocspIdentifier OcspIdentifier, + /// ocspRepHash OtherHash OPTIONAL + /// } + /// + /// + public class OcspResponsesID + : Asn1Encodable + { + private readonly OcspIdentifier ocspIdentifier; + private readonly OtherHash ocspRepHash; + + public static OcspResponsesID GetInstance( + object obj) + { + if (obj == null || obj is OcspResponsesID) + return (OcspResponsesID) obj; + + if (obj is Asn1Sequence) + return new OcspResponsesID((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OcspResponsesID' factory: " + + obj.GetType().Name, + "obj"); + } + + private OcspResponsesID( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.ocspIdentifier = OcspIdentifier.GetInstance(seq[0].ToAsn1Object()); + + if (seq.Count > 1) + { + this.ocspRepHash = OtherHash.GetInstance(seq[1].ToAsn1Object()); + } + } + + public OcspResponsesID( + OcspIdentifier ocspIdentifier) + : this(ocspIdentifier, null) + { + } + + public OcspResponsesID( + OcspIdentifier ocspIdentifier, + OtherHash ocspRepHash) + { + if (ocspIdentifier == null) + throw new ArgumentNullException("ocspIdentifier"); + + this.ocspIdentifier = ocspIdentifier; + this.ocspRepHash = ocspRepHash; + } + + public OcspIdentifier OcspIdentifier + { + get { return ocspIdentifier; } + } + + public OtherHash OcspRepHash + { + get { return ocspRepHash; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + ocspIdentifier.ToAsn1Object()); + + if (ocspRepHash != null) + { + v.Add(ocspRepHash.ToAsn1Object()); + } + + return new DerSequence(v); + } + + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OtherCertID.cs b/iTechSharp/srcbc/asn1/esf/OtherCertID.cs new file mode 100644 index 0000000..6d12555 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OtherCertID.cs @@ -0,0 +1,93 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// OtherCertID ::= SEQUENCE { + /// otherCertHash OtherHash, + /// issuerSerial IssuerSerial OPTIONAL + /// } + /// + /// + public class OtherCertID + : Asn1Encodable + { + private readonly OtherHash otherCertHash; + private readonly IssuerSerial issuerSerial; + + public static OtherCertID GetInstance( + object obj) + { + if (obj == null || obj is OtherCertID) + return (OtherCertID) obj; + + if (obj is Asn1Sequence) + return new OtherCertID((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OtherCertID' factory: " + + obj.GetType().Name, + "obj"); + } + + private OtherCertID( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.otherCertHash = OtherHash.GetInstance(seq[0].ToAsn1Object()); + + if (seq.Count > 1) + { + this.issuerSerial = IssuerSerial.GetInstance(seq[1].ToAsn1Object()); + } + } + + public OtherCertID( + OtherHash otherCertHash) + : this(otherCertHash, null) + { + } + + public OtherCertID( + OtherHash otherCertHash, + IssuerSerial issuerSerial) + { + if (otherCertHash == null) + throw new ArgumentNullException("otherCertHash"); + + this.otherCertHash = otherCertHash; + this.issuerSerial = issuerSerial; + } + + public OtherHash OtherCertHash + { + get { return otherCertHash; } + } + + public IssuerSerial IssuerSerial + { + get { return issuerSerial; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + otherCertHash.ToAsn1Object()); + + if (issuerSerial != null) + { + v.Add(issuerSerial.ToAsn1Object()); + } + + return new DerSequence(v); + } + + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OtherHash.cs b/iTechSharp/srcbc/asn1/esf/OtherHash.cs new file mode 100644 index 0000000..15b285e --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OtherHash.cs @@ -0,0 +1,89 @@ +using System; + +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// OtherHash ::= CHOICE { + /// sha1Hash OtherHashValue, -- This contains a SHA-1 hash + /// otherHash OtherHashAlgAndValue + /// } + /// + /// OtherHashValue ::= OCTET STRING + /// + /// + public class OtherHash + : Asn1Encodable + //, Asn1Choice + { + private readonly Asn1OctetString sha1Hash; + private readonly OtherHashAlgAndValue otherHash; + + public static OtherHash GetInstance( + object obj) + { + if (obj == null || obj is OtherHash) + return (OtherHash) obj; + + if (obj is Asn1OctetString) + return new OtherHash((Asn1OctetString) obj); + + return new OtherHash( + OtherHashAlgAndValue.GetInstance(obj)); + } + + public OtherHash( + byte[] sha1Hash) + { + if (sha1Hash == null) + throw new ArgumentNullException("sha1Hash"); + + this.sha1Hash = new DerOctetString(sha1Hash); + } + + public OtherHash( + Asn1OctetString sha1Hash) + { + if (sha1Hash == null) + throw new ArgumentNullException("sha1Hash"); + + this.sha1Hash = sha1Hash; + } + + public OtherHash( + OtherHashAlgAndValue otherHash) + { + if (otherHash == null) + throw new ArgumentNullException("otherHash"); + + this.otherHash = otherHash; + } + + public AlgorithmIdentifier HashAlgorithm + { + get + { + return otherHash == null + ? new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1) + : otherHash.HashAlgorithm; + } + } + + public byte[] GetHashValue() + { + return otherHash == null + ? sha1Hash.GetOctets() + : otherHash.GetHashValue(); + } + + public override Asn1Object ToAsn1Object() + { + return otherHash == null + ? sha1Hash + : otherHash.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OtherHashAlgAndValue.cs b/iTechSharp/srcbc/asn1/esf/OtherHashAlgAndValue.cs new file mode 100644 index 0000000..b6bd4f4 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OtherHashAlgAndValue.cs @@ -0,0 +1,94 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// Summary description for OtherHashAlgAndValue. + /// + /// + /// + /// OtherHashAlgAndValue ::= SEQUENCE { + /// hashAlgorithm AlgorithmIdentifier, + /// hashValue OtherHashValue + /// } + /// + /// OtherHashValue ::= OCTET STRING + /// + /// + public class OtherHashAlgAndValue + : Asn1Encodable + { + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly Asn1OctetString hashValue; + + public static OtherHashAlgAndValue GetInstance( + object obj) + { + if (obj == null || obj is OtherHashAlgAndValue) + return (OtherHashAlgAndValue) obj; + + if (obj is Asn1Sequence) + return new OtherHashAlgAndValue((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OtherHashAlgAndValue' factory: " + + obj.GetType().Name, + "obj"); + } + + private OtherHashAlgAndValue( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0].ToAsn1Object()); + this.hashValue = (Asn1OctetString) seq[1].ToAsn1Object(); + } + + public OtherHashAlgAndValue( + AlgorithmIdentifier hashAlgorithm, + byte[] hashValue) + { + if (hashAlgorithm == null) + throw new ArgumentNullException("hashAlgorithm"); + if (hashValue == null) + throw new ArgumentNullException("hashValue"); + + this.hashAlgorithm = hashAlgorithm; + this.hashValue = new DerOctetString(hashValue); + } + + public OtherHashAlgAndValue( + AlgorithmIdentifier hashAlgorithm, + Asn1OctetString hashValue) + { + if (hashAlgorithm == null) + throw new ArgumentNullException("hashAlgorithm"); + if (hashValue == null) + throw new ArgumentNullException("hashValue"); + + this.hashAlgorithm = hashAlgorithm; + this.hashValue = hashValue; + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public byte[] GetHashValue() + { + return hashValue.GetOctets(); + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(hashAlgorithm, hashValue); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OtherRevRefs.cs b/iTechSharp/srcbc/asn1/esf/OtherRevRefs.cs new file mode 100644 index 0000000..56713e3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OtherRevRefs.cs @@ -0,0 +1,78 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition + /// + /// OtherRevRefs ::= SEQUENCE + /// { + /// otherRevRefType OtherRevRefType, + /// otherRevRefs ANY DEFINED BY otherRevRefType + /// } + /// + /// OtherRevRefType ::= OBJECT IDENTIFIER + /// + /// + public class OtherRevRefs + : Asn1Encodable + { + private readonly DerObjectIdentifier otherRevRefType; + private readonly Asn1Object otherRevRefs; + + public static OtherRevRefs GetInstance( + object obj) + { + if (obj == null || obj is OtherRevRefs) + return (OtherRevRefs) obj; + + if (obj is Asn1Sequence) + return new OtherRevRefs((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OtherRevRefs' factory: " + + obj.GetType().Name, + "obj"); + } + + private OtherRevRefs( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.otherRevRefType = (DerObjectIdentifier) seq[0].ToAsn1Object(); + this.otherRevRefs = seq[1].ToAsn1Object(); + } + + public OtherRevRefs( + DerObjectIdentifier otherRevRefType, + Asn1Encodable otherRevRefs) + { + if (otherRevRefType == null) + throw new ArgumentNullException("otherRevRefType"); + if (otherRevRefs == null) + throw new ArgumentNullException("otherRevRefs"); + + this.otherRevRefType = otherRevRefType; + this.otherRevRefs = otherRevRefs.ToAsn1Object(); + } + + public DerObjectIdentifier OtherRevRefType + { + get { return otherRevRefType; } + } + + public Asn1Object OtherRevRefsObject + { + get { return otherRevRefs; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(otherRevRefType, otherRevRefs); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OtherRevVals.cs b/iTechSharp/srcbc/asn1/esf/OtherRevVals.cs new file mode 100644 index 0000000..b88a1a7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OtherRevVals.cs @@ -0,0 +1,78 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.3.2 Revocation Values Attribute Definition + /// + /// OtherRevVals ::= SEQUENCE + /// { + /// otherRevValType OtherRevValType, + /// otherRevVals ANY DEFINED BY otherRevValType + /// } + /// + /// OtherRevValType ::= OBJECT IDENTIFIER + /// + /// + public class OtherRevVals + : Asn1Encodable + { + private readonly DerObjectIdentifier otherRevValType; + private readonly Asn1Object otherRevVals; + + public static OtherRevVals GetInstance( + object obj) + { + if (obj == null || obj is OtherRevVals) + return (OtherRevVals) obj; + + if (obj is Asn1Sequence) + return new OtherRevVals((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OtherRevVals' factory: " + + obj.GetType().Name, + "obj"); + } + + private OtherRevVals( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.otherRevValType = (DerObjectIdentifier) seq[0].ToAsn1Object(); + this.otherRevVals = seq[1].ToAsn1Object(); + } + + public OtherRevVals( + DerObjectIdentifier otherRevValType, + Asn1Encodable otherRevVals) + { + if (otherRevValType == null) + throw new ArgumentNullException("otherRevValType"); + if (otherRevVals == null) + throw new ArgumentNullException("otherRevVals"); + + this.otherRevValType = otherRevValType; + this.otherRevVals = otherRevVals.ToAsn1Object(); + } + + public DerObjectIdentifier OtherRevValType + { + get { return otherRevValType; } + } + + public Asn1Object OtherRevValsObject + { + get { return otherRevVals; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(otherRevValType, otherRevVals); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/OtherSigningCertificate.cs b/iTechSharp/srcbc/asn1/esf/OtherSigningCertificate.cs new file mode 100644 index 0000000..90e385a --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/OtherSigningCertificate.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// OtherSigningCertificate ::= SEQUENCE { + /// certs SEQUENCE OF OtherCertID, + /// policies SEQUENCE OF PolicyInformation OPTIONAL + /// } + /// + /// + public class OtherSigningCertificate + : Asn1Encodable + { + private readonly Asn1Sequence certs; + private readonly Asn1Sequence policies; + + public static OtherSigningCertificate GetInstance( + object obj) + { + if (obj == null || obj is OtherSigningCertificate) + return (OtherSigningCertificate) obj; + + if (obj is Asn1Sequence) + return new OtherSigningCertificate((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'OtherSigningCertificate' factory: " + + obj.GetType().Name, + "obj"); + } + + private OtherSigningCertificate( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object()); + + if (seq.Count > 1) + { + this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object()); + } + } + + public OtherSigningCertificate( + params OtherCertID[] certs) + : this(certs, null) + { + } + + public OtherSigningCertificate( + OtherCertID[] certs, + params PolicyInformation[] policies) + { + if (certs == null) + throw new ArgumentNullException("certs"); + + this.certs = new DerSequence(certs); + + if (policies != null) + { + this.policies = new DerSequence(policies); + } + } + + public OtherSigningCertificate( + IEnumerable certs) + : this(certs, null) + { + } + + public OtherSigningCertificate( + IEnumerable certs, + IEnumerable policies) + { + if (certs == null) + throw new ArgumentNullException("certs"); + if (!CollectionUtilities.CheckElementsAreOfType(certs, typeof(OtherCertID))) + throw new ArgumentException("Must contain only 'OtherCertID' objects", "certs"); + + this.certs = new DerSequence( + Asn1EncodableVector.FromEnumerable(certs)); + + if (policies != null) + { + if (!CollectionUtilities.CheckElementsAreOfType(policies, typeof(PolicyInformation))) + throw new ArgumentException("Must contain only 'PolicyInformation' objects", "policies"); + + this.policies = new DerSequence( + Asn1EncodableVector.FromEnumerable(policies)); + } + } + + public OtherCertID[] GetCerts() + { + OtherCertID[] cs = new OtherCertID[certs.Count]; + for (int i = 0; i < certs.Count; ++i) + { + cs[i] = OtherCertID.GetInstance(certs[i].ToAsn1Object()); + } + return cs; + } + + public PolicyInformation[] GetPolicies() + { + if (policies == null) + return null; + + PolicyInformation[] ps = new PolicyInformation[policies.Count]; + for (int i = 0; i < policies.Count; ++i) + { + ps[i] = PolicyInformation.GetInstance(policies[i].ToAsn1Object()); + } + return ps; + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(certs); + + if (policies != null) + { + v.Add(policies); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/RevocationValues.cs b/iTechSharp/srcbc/asn1/esf/RevocationValues.cs new file mode 100644 index 0000000..35800f3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/RevocationValues.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// RFC 3126: 4.3.2 Revocation Values Attribute Definition + /// + /// RevocationValues ::= SEQUENCE { + /// crlVals [0] SEQUENCE OF CertificateList OPTIONAL, + /// ocspVals [1] SEQUENCE OF BasicOCSPResponse OPTIONAL, + /// otherRevVals [2] OtherRevVals + /// } + /// + /// + public class RevocationValues + : Asn1Encodable + { + private readonly Asn1Sequence crlVals; + private readonly Asn1Sequence ocspVals; + private readonly OtherRevVals otherRevVals; + + public static RevocationValues GetInstance( + object obj) + { + if (obj == null || obj is RevocationValues) + return (RevocationValues) obj; + + if (obj is Asn1Sequence) + return new RevocationValues((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'RevocationValues' factory: " + + obj.GetType().Name, + "obj"); + } + + private RevocationValues( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 1 || seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + bool otherRevValsFound = false; + + foreach (Asn1TaggedObject taggedObj in seq) + { + Asn1Object asn1Obj = taggedObj.GetObject(); + switch (taggedObj.TagNo) + { + case 0: + Asn1Sequence crlValsSeq = (Asn1Sequence) asn1Obj; + foreach (Asn1Encodable ae in crlValsSeq) + { + CertificateList.GetInstance(ae.ToAsn1Object()); + } + this.crlVals = crlValsSeq; + break; + case 1: + Asn1Sequence ocspValsSeq = (Asn1Sequence) asn1Obj; + foreach (Asn1Encodable ae in ocspValsSeq) + { + BasicOcspResponse.GetInstance(ae.ToAsn1Object()); + } + this.ocspVals = ocspValsSeq; + break; + case 2: + this.otherRevVals = OtherRevVals.GetInstance(asn1Obj); + otherRevValsFound = true; + break; + default: + throw new ArgumentException("Illegal tag in RevocationValues", "seq"); + } + } + + if (!otherRevValsFound) + throw new ArgumentException("No otherRevVals found", "seq"); + } + + public RevocationValues( + CertificateList[] crlVals, + BasicOcspResponse[] ocspVals, + OtherRevVals otherRevVals) + { + if (otherRevVals == null) + throw new ArgumentNullException("otherRevVals"); + + if (crlVals != null) + { + this.crlVals = new DerSequence(crlVals); + } + + if (ocspVals != null) + { + this.ocspVals = new DerSequence(ocspVals); + } + + this.otherRevVals = otherRevVals; + } + + public RevocationValues( + IEnumerable crlVals, + IEnumerable ocspVals, + OtherRevVals otherRevVals) + { + if (otherRevVals == null) + throw new ArgumentNullException("otherRevVals"); + + if (crlVals != null) + { + if (!CollectionUtilities.CheckElementsAreOfType(crlVals, typeof(CertificateList))) + throw new ArgumentException("Must contain only 'CertificateList' objects", "crlVals"); + + this.crlVals = new DerSequence( + Asn1EncodableVector.FromEnumerable(crlVals)); + } + + if (ocspVals != null) + { + if (!CollectionUtilities.CheckElementsAreOfType(ocspVals, typeof(BasicOcspResponse))) + throw new ArgumentException("Must contain only 'BasicOcspResponse' objects", "ocspVals"); + + this.ocspVals = new DerSequence( + Asn1EncodableVector.FromEnumerable(ocspVals)); + } + + this.otherRevVals = otherRevVals; + } + + public CertificateList[] GetCrlVals() + { + CertificateList[] result = new CertificateList[crlVals.Count]; + for (int i = 0; i < crlVals.Count; ++i) + { + result[i] = CertificateList.GetInstance(crlVals[i].ToAsn1Object()); + } + return result; + } + + public BasicOcspResponse[] GetOcspVals() + { + BasicOcspResponse[] result = new BasicOcspResponse[ocspVals.Count]; + for (int i = 0; i < ocspVals.Count; ++i) + { + result[i] = BasicOcspResponse.GetInstance(ocspVals[i].ToAsn1Object()); + } + return result; + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (crlVals != null) + { + v.Add(new DerTaggedObject(true, 0, crlVals)); + } + + if (ocspVals != null) + { + v.Add(new DerTaggedObject(true, 1, ocspVals)); + } + + v.Add(new DerTaggedObject(true, 2, otherRevVals.ToAsn1Object())); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/SigPolicyQualifierInfo.cs b/iTechSharp/srcbc/asn1/esf/SigPolicyQualifierInfo.cs new file mode 100644 index 0000000..2d36bc7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/SigPolicyQualifierInfo.cs @@ -0,0 +1,71 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// SigPolicyQualifierInfo ::= SEQUENCE { + /// sigPolicyQualifierId SigPolicyQualifierId, + /// sigQualifier ANY DEFINED BY sigPolicyQualifierId + /// } + /// + /// SigPolicyQualifierId ::= OBJECT IDENTIFIER + /// + /// + public class SigPolicyQualifierInfo + : Asn1Encodable + { + private readonly DerObjectIdentifier sigPolicyQualifierId; + private readonly Asn1Object sigQualifier; + + public static SigPolicyQualifierInfo GetInstance( + object obj) + { + if (obj == null || obj is SigPolicyQualifierInfo) + return (SigPolicyQualifierInfo) obj; + + if (obj is Asn1Sequence) + return new SigPolicyQualifierInfo((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'SigPolicyQualifierInfo' factory: " + + obj.GetType().Name, + "obj"); + } + + private SigPolicyQualifierInfo( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.sigPolicyQualifierId = (DerObjectIdentifier) seq[0].ToAsn1Object(); + this.sigQualifier = seq[1].ToAsn1Object(); + } + + public SigPolicyQualifierInfo( + DerObjectIdentifier sigPolicyQualifierId, + Asn1Encodable sigQualifier) + { + this.sigPolicyQualifierId = sigPolicyQualifierId; + this.sigQualifier = sigQualifier.ToAsn1Object(); + } + + public DerObjectIdentifier SigPolicyQualifierId + { + get { return sigPolicyQualifierId; } + } + + public Asn1Object SigQualifier + { + get { return sigQualifier; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(sigPolicyQualifierId, sigQualifier); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/SignaturePolicyId.cs b/iTechSharp/srcbc/asn1/esf/SignaturePolicyId.cs new file mode 100644 index 0000000..545be2c --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/SignaturePolicyId.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// SignaturePolicyId ::= SEQUENCE { + /// sigPolicyIdentifier SigPolicyId, + /// sigPolicyHash SigPolicyHash, + /// sigPolicyQualifiers SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL + /// } + /// + /// SigPolicyId ::= OBJECT IDENTIFIER + /// + /// SigPolicyHash ::= OtherHashAlgAndValue + /// + /// + public class SignaturePolicyId + : Asn1Encodable + { + private readonly DerObjectIdentifier sigPolicyIdentifier; + private readonly OtherHashAlgAndValue sigPolicyHash; + private readonly Asn1Sequence sigPolicyQualifiers; + + public static SignaturePolicyId GetInstance( + object obj) + { + if (obj == null || obj is SignaturePolicyId) + return (SignaturePolicyId) obj; + + if (obj is Asn1Sequence) + return new SignaturePolicyId((Asn1Sequence) obj); + + throw new ArgumentException( + "Unknown object in 'SignaturePolicyId' factory: " + + obj.GetType().Name, + "obj"); + } + + private SignaturePolicyId( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + if (seq.Count < 2 || seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.sigPolicyIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object(); + this.sigPolicyHash = OtherHashAlgAndValue.GetInstance(seq[1].ToAsn1Object()); + + if (seq.Count > 2) + { + this.sigPolicyQualifiers = (Asn1Sequence) seq[2].ToAsn1Object(); + } + } + + public SignaturePolicyId( + DerObjectIdentifier sigPolicyIdentifier, + OtherHashAlgAndValue sigPolicyHash) + : this(sigPolicyIdentifier, sigPolicyHash, null) + { + } + + public SignaturePolicyId( + DerObjectIdentifier sigPolicyIdentifier, + OtherHashAlgAndValue sigPolicyHash, + params SigPolicyQualifierInfo[] sigPolicyQualifiers) + { + if (sigPolicyIdentifier == null) + throw new ArgumentNullException("sigPolicyIdentifier"); + if (sigPolicyHash == null) + throw new ArgumentNullException("sigPolicyHash"); + + this.sigPolicyIdentifier = sigPolicyIdentifier; + this.sigPolicyHash = sigPolicyHash; + + if (sigPolicyQualifiers != null) + { + this.sigPolicyQualifiers = new DerSequence(sigPolicyQualifiers); + } + } + + public SignaturePolicyId( + DerObjectIdentifier sigPolicyIdentifier, + OtherHashAlgAndValue sigPolicyHash, + IEnumerable sigPolicyQualifiers) + { + if (sigPolicyIdentifier == null) + throw new ArgumentNullException("sigPolicyIdentifier"); + if (sigPolicyHash == null) + throw new ArgumentNullException("sigPolicyHash"); + + this.sigPolicyIdentifier = sigPolicyIdentifier; + this.sigPolicyHash = sigPolicyHash; + + if (sigPolicyQualifiers != null) + { + if (!CollectionUtilities.CheckElementsAreOfType(sigPolicyQualifiers, typeof(SigPolicyQualifierInfo))) + throw new ArgumentException("Must contain only 'SigPolicyQualifierInfo' objects", "sigPolicyQualifiers"); + + this.sigPolicyQualifiers = new DerSequence( + Asn1EncodableVector.FromEnumerable(sigPolicyQualifiers)); + } + } + + public DerObjectIdentifier SigPolicyIdentifier + { + get { return sigPolicyIdentifier; } + } + + public OtherHashAlgAndValue SigPolicyHash + { + get { return sigPolicyHash; } + } + + public SigPolicyQualifierInfo[] GetSigPolicyQualifiers() + { + if (sigPolicyQualifiers == null) + return null; + + SigPolicyQualifierInfo[] infos = new SigPolicyQualifierInfo[sigPolicyQualifiers.Count]; + for (int i = 0; i < sigPolicyQualifiers.Count; ++i) + { + infos[i] = SigPolicyQualifierInfo.GetInstance(sigPolicyQualifiers[i]); + } + return infos; + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + sigPolicyIdentifier, sigPolicyHash.ToAsn1Object()); + + if (sigPolicyQualifiers != null) + { + v.Add(sigPolicyQualifiers.ToAsn1Object()); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/SignaturePolicyIdentifier.cs b/iTechSharp/srcbc/asn1/esf/SignaturePolicyIdentifier.cs new file mode 100644 index 0000000..6eb89c7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/SignaturePolicyIdentifier.cs @@ -0,0 +1,65 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// SignaturePolicyIdentifier ::= CHOICE { + /// SignaturePolicyId SignaturePolicyId, + /// SignaturePolicyImplied SignaturePolicyImplied + /// } + /// + /// SignaturePolicyImplied ::= NULL + /// + /// + public class SignaturePolicyIdentifier + : Asn1Encodable + //, Asn1Choice + { + private readonly SignaturePolicyId sigPolicy; + + public static SignaturePolicyIdentifier GetInstance( + object obj) + { + if (obj == null || obj is SignaturePolicyIdentifier) + return (SignaturePolicyIdentifier) obj; + + if (obj is SignaturePolicyId) + return new SignaturePolicyIdentifier((SignaturePolicyId) obj); + + if (obj is Asn1Null) + return new SignaturePolicyIdentifier(); + + throw new ArgumentException( + "Unknown object in 'SignaturePolicyIdentifier' factory: " + + obj.GetType().Name, + "obj"); + } + + public SignaturePolicyIdentifier() + { + this.sigPolicy = null; + } + + public SignaturePolicyIdentifier( + SignaturePolicyId signaturePolicyId) + { + if (signaturePolicyId == null) + throw new ArgumentNullException("signaturePolicyId"); + + this.sigPolicy = signaturePolicyId; + } + + public SignaturePolicyId SignaturePolicyId + { + get { return sigPolicy; } + } + + public override Asn1Object ToAsn1Object() + { + return sigPolicy == null + ? DerNull.Instance + : sigPolicy.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/esf/SignerLocation.cs b/iTechSharp/srcbc/asn1/esf/SignerLocation.cs new file mode 100644 index 0000000..d2cef51 --- /dev/null +++ b/iTechSharp/srcbc/asn1/esf/SignerLocation.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /** + * Signer-Location attribute (RFC3126). + * + *
      +	*   SignerLocation ::= SEQUENCE {
      +	*       countryName        [0] DirectoryString OPTIONAL,
      +	*       localityName       [1] DirectoryString OPTIONAL,
      +	*       postalAddress      [2] PostalAddress OPTIONAL }
      +	*
      +	*   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
      +	* 
      + */ + public class SignerLocation + : Asn1Encodable + { + // TODO Should these be using DirectoryString? + private DerUtf8String countryName; + private DerUtf8String localityName; + private Asn1Sequence postalAddress; + + public SignerLocation( + Asn1Sequence seq) + { + foreach (Asn1TaggedObject obj in seq) + { + switch (obj.TagNo) + { + case 0: + this.countryName = DerUtf8String.GetInstance(obj, true); + break; + case 1: + this.localityName = DerUtf8String.GetInstance(obj, true); + break; + case 2: + bool isExplicit = obj.IsExplicit(); // handle erroneous implicitly tagged sequences + this.postalAddress = Asn1Sequence.GetInstance(obj, isExplicit); + if (postalAddress != null && postalAddress.Count > 6) + throw new ArgumentException("postal address must contain less than 6 strings"); + break; + default: + throw new ArgumentException("illegal tag"); + } + } + } + + public SignerLocation( + DerUtf8String countryName, + DerUtf8String localityName, + Asn1Sequence postalAddress) + { + if (postalAddress != null && postalAddress.Count > 6) + { + throw new ArgumentException("postal address must contain less than 6 strings"); + } + + if (countryName != null) + { + this.countryName = DerUtf8String.GetInstance(countryName.ToAsn1Object()); + } + + if (localityName != null) + { + this.localityName = DerUtf8String.GetInstance(localityName.ToAsn1Object()); + } + + if (postalAddress != null) + { + this.postalAddress = (Asn1Sequence) postalAddress.ToAsn1Object(); + } + } + + public static SignerLocation GetInstance( + object obj) + { + if (obj == null || obj is SignerLocation) + { + return (SignerLocation) obj; + } + + return new SignerLocation(Asn1Sequence.GetInstance(obj)); + } + + public DerUtf8String CountryName + { + get { return countryName; } + } + + public DerUtf8String LocalityName + { + get { return localityName; } + } + + public Asn1Sequence PostalAddress + { + get { return postalAddress; } + } + + /** + *
      +		*   SignerLocation ::= SEQUENCE {
      +		*       countryName        [0] DirectoryString OPTIONAL,
      +		*       localityName       [1] DirectoryString OPTIONAL,
      +		*       postalAddress      [2] PostalAddress OPTIONAL }
      +		*
      +		*   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
      +		*
      +		*   DirectoryString ::= CHOICE {
      +		*         teletexString           TeletexString (SIZE (1..MAX)),
      +		*         printableString         PrintableString (SIZE (1..MAX)),
      +		*         universalString         UniversalString (SIZE (1..MAX)),
      +		*         utf8String              UTF8String (SIZE (1.. MAX)),
      +		*         bmpString               BMPString (SIZE (1..MAX)) }
      +		* 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (countryName != null) + { + v.Add(new DerTaggedObject(true, 0, countryName)); + } + + if (localityName != null) + { + v.Add(new DerTaggedObject(true, 1, localityName)); + } + + if (postalAddress != null) + { + v.Add(new DerTaggedObject(true, 2, postalAddress)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/ContentHints.cs b/iTechSharp/srcbc/asn1/ess/ContentHints.cs new file mode 100644 index 0000000..a430fea --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/ContentHints.cs @@ -0,0 +1,92 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class ContentHints + : Asn1Encodable + { + private readonly DerUtf8String contentDescription; + private readonly DerObjectIdentifier contentType; + + public static ContentHints GetInstance( + object o) + { + if (o == null || o is ContentHints) + { + return (ContentHints)o; + } + + if (o is Asn1Sequence) + { + return new ContentHints((Asn1Sequence)o); + } + + throw new ArgumentException("unknown object in 'ContentHints' factory : " + + o.GetType().Name + "."); + } + + /** + * constructor + */ + private ContentHints( + Asn1Sequence seq) + { + IAsn1Convertible field = seq[0]; + if (field.ToAsn1Object() is DerUtf8String) + { + contentDescription = DerUtf8String.GetInstance(field); + contentType = DerObjectIdentifier.GetInstance(seq[1]); + } + else + { + contentType = DerObjectIdentifier.GetInstance(seq[0]); + } + } + + public ContentHints( + DerObjectIdentifier contentType) + { + this.contentType = contentType; + this.contentDescription = null; + } + + public ContentHints( + DerObjectIdentifier contentType, + DerUtf8String contentDescription) + { + this.contentType = contentType; + this.contentDescription = contentDescription; + } + + public DerObjectIdentifier ContentType + { + get { return contentType; } + } + + public DerUtf8String ContentDescription + { + get { return contentDescription; } + } + + /** + *
      +		 * ContentHints ::= SEQUENCE {
      +		 *   contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
      +		 *   contentType ContentType }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (contentDescription != null) + { + v.Add(contentDescription); + } + + v.Add(contentType); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/ContentIdentifier.cs b/iTechSharp/srcbc/asn1/ess/ContentIdentifier.cs new file mode 100644 index 0000000..8058dcc --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/ContentIdentifier.cs @@ -0,0 +1,65 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class ContentIdentifier + : Asn1Encodable + { + private Asn1OctetString value; + + public static ContentIdentifier GetInstance( + object o) + { + if (o == null || o is ContentIdentifier) + { + return (ContentIdentifier) o; + } + + if (o is Asn1OctetString) + { + return new ContentIdentifier((Asn1OctetString) o); + } + + throw new ArgumentException( + "unknown object in 'ContentIdentifier' factory : " + + o.GetType().Name + "."); + } + + /** + * Create from OCTET STRING whose octets represent the identifier. + */ + public ContentIdentifier( + Asn1OctetString value) + { + this.value = value; + } + + /** + * Create from byte array representing the identifier. + */ + public ContentIdentifier( + byte[] value) + : this(new DerOctetString(value)) + { + } + + public Asn1OctetString Value + { + get { return value; } + } + + /** + * The definition of ContentIdentifier is + *
      +		 * ContentIdentifier ::=  OCTET STRING
      +		 * 
      + * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 7 } + */ + public override Asn1Object ToAsn1Object() + { + return value; + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/ESSCertID.cs b/iTechSharp/srcbc/asn1/ess/ESSCertID.cs new file mode 100644 index 0000000..4d449a7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/ESSCertID.cs @@ -0,0 +1,93 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class EssCertID + : Asn1Encodable + { + private Asn1OctetString certHash; + private IssuerSerial issuerSerial; + + public static EssCertID GetInstance( + object o) + { + if (o == null || o is EssCertID) + { + return (EssCertID) o; + } + + if (o is Asn1Sequence) + { + return new EssCertID((Asn1Sequence) o); + } + + throw new ArgumentException( + "unknown object in 'EssCertID' factory : " + + o.GetType().Name + "."); + } + + /** + * constructor + */ + public EssCertID( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + this.certHash = Asn1OctetString.GetInstance(seq[0]); + + if (seq.Count > 1) + { + issuerSerial = IssuerSerial.GetInstance(seq[1]); + } + } + + public EssCertID( + byte[] hash) + { + certHash = new DerOctetString(hash); + } + + public EssCertID( + byte[] hash, + IssuerSerial issuerSerial) + { + this.certHash = new DerOctetString(hash); + this.issuerSerial = issuerSerial; + } + + public byte[] GetCertHash() + { + return certHash.GetOctets(); + } + + public IssuerSerial IssuerSerial + { + get { return issuerSerial; } + } + + /** + *
      +		 * EssCertID ::= SEQUENCE {
      +		 *     certHash Hash,
      +		 *     issuerSerial IssuerSerial OPTIONAL }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(certHash); + + if (issuerSerial != null) + { + v.Add(issuerSerial); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/ESSCertIDv2.cs b/iTechSharp/srcbc/asn1/ess/ESSCertIDv2.cs new file mode 100644 index 0000000..ca22456 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/ESSCertIDv2.cs @@ -0,0 +1,138 @@ +using System; + +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class EssCertIDv2 + : Asn1Encodable + { + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly byte[] certHash; + private readonly IssuerSerial issuerSerial; + + private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier( + NistObjectIdentifiers.IdSha256, DerNull.Instance); + + public static EssCertIDv2 GetInstance( + object o) + { + if (o == null || o is EssCertIDv2) + return (EssCertIDv2) o; + + if (o is Asn1Sequence) + return new EssCertIDv2((Asn1Sequence) o); + + throw new ArgumentException( + "unknown object in 'EssCertIDv2' factory : " + + o.GetType().Name + "."); + } + + private EssCertIDv2( + Asn1Sequence seq) + { + if (seq.Count != 2 && seq.Count != 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + int count = 0; + + if (seq[0] is Asn1OctetString) + { + // Default value + this.hashAlgorithm = DefaultAlgID; + } + else + { + this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object()); + } + + this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets(); + + if (seq.Count > count) + { + this.issuerSerial = IssuerSerial.GetInstance( + Asn1Sequence.GetInstance(seq[count].ToAsn1Object())); + } + } + + public EssCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash) + : this(algId, certHash, null) + { + } + + public EssCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash, + IssuerSerial issuerSerial) + { + if (algId == null) + { + // Default value + this.hashAlgorithm = DefaultAlgID; + } + else + { + this.hashAlgorithm = algId; + } + + this.certHash = certHash; + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return this.hashAlgorithm; } + } + + public byte[] GetCertHash() + { + return Arrays.Clone(certHash); + } + + public IssuerSerial IssuerSerial + { + get { return issuerSerial; } + } + + /** + *
      +		 * EssCertIDv2 ::=  SEQUENCE {
      +		 *     hashAlgorithm     AlgorithmIdentifier
      +		 *              DEFAULT {algorithm id-sha256 parameters NULL},
      +		 *     certHash          Hash,
      +		 *     issuerSerial      IssuerSerial OPTIONAL
      +		 * }
      +		 *
      +		 * Hash ::= OCTET STRING
      +		 *
      +		 * IssuerSerial ::= SEQUENCE {
      +		 *     issuer         GeneralNames,
      +		 *     serialNumber   CertificateSerialNumber
      +		 * }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (!hashAlgorithm.Equals(DefaultAlgID)) + { + v.Add(hashAlgorithm); + } + + v.Add(new DerOctetString(certHash).ToAsn1Object()); + + if (issuerSerial != null) + { + v.Add(issuerSerial); + } + + return new DerSequence(v); + } + + } +} diff --git a/iTechSharp/srcbc/asn1/ess/OtherCertID.cs b/iTechSharp/srcbc/asn1/ess/OtherCertID.cs new file mode 100644 index 0000000..972ef8c --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/OtherCertID.cs @@ -0,0 +1,132 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ess +{ + [Obsolete("Use version in Asn1.Esf instead")] + public class OtherCertID + : Asn1Encodable + { + private Asn1Encodable otherCertHash; + private IssuerSerial issuerSerial; + + public static OtherCertID GetInstance( + object o) + { + if (o == null || o is OtherCertID) + { + return (OtherCertID) o; + } + + if (o is Asn1Sequence) + { + return new OtherCertID((Asn1Sequence) o); + } + + throw new ArgumentException( + "unknown object in 'OtherCertID' factory : " + + o.GetType().Name + "."); + } + + /** + * constructor + */ + public OtherCertID( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + if (seq[0].ToAsn1Object() is Asn1OctetString) + { + otherCertHash = Asn1OctetString.GetInstance(seq[0]); + } + else + { + otherCertHash = DigestInfo.GetInstance(seq[0]); + } + + if (seq.Count > 1) + { + issuerSerial = IssuerSerial.GetInstance(Asn1Sequence.GetInstance(seq[1])); + } + } + + public OtherCertID( + AlgorithmIdentifier algId, + byte[] digest) + { + this.otherCertHash = new DigestInfo(algId, digest); + } + + public OtherCertID( + AlgorithmIdentifier algId, + byte[] digest, + IssuerSerial issuerSerial) + { + this.otherCertHash = new DigestInfo(algId, digest); + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier AlgorithmHash + { + get + { + if (otherCertHash.ToAsn1Object() is Asn1OctetString) + { + // SHA-1 + return new AlgorithmIdentifier("1.3.14.3.2.26"); + } + + return DigestInfo.GetInstance(otherCertHash).AlgorithmID; + } + } + + public byte[] GetCertHash() + { + if (otherCertHash.ToAsn1Object() is Asn1OctetString) + { + // SHA-1 + return ((Asn1OctetString) otherCertHash.ToAsn1Object()).GetOctets(); + } + + return DigestInfo.GetInstance(otherCertHash).GetDigest(); + } + + public IssuerSerial IssuerSerial + { + get { return issuerSerial; } + } + + /** + *
      +		 * OtherCertID ::= SEQUENCE {
      +		 *     otherCertHash    OtherHash,
      +		 *     issuerSerial     IssuerSerial OPTIONAL }
      +		 *
      +		 * OtherHash ::= CHOICE {
      +		 *     sha1Hash     OCTET STRING,
      +		 *     otherHash    OtherHashAlgAndValue }
      +		 *
      +		 * OtherHashAlgAndValue ::= SEQUENCE {
      +		 *     hashAlgorithm    AlgorithmIdentifier,
      +		 *     hashValue        OCTET STRING }
      +		 *
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(otherCertHash); + + if (issuerSerial != null) + { + v.Add(issuerSerial); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/OtherSigningCertificate.cs b/iTechSharp/srcbc/asn1/ess/OtherSigningCertificate.cs new file mode 100644 index 0000000..c165fec --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/OtherSigningCertificate.cs @@ -0,0 +1,109 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ess +{ + [Obsolete("Use version in Asn1.Esf instead")] + public class OtherSigningCertificate + : Asn1Encodable + { + private Asn1Sequence certs, policies; + + public static OtherSigningCertificate GetInstance( + object o) + { + if (o == null || o is OtherSigningCertificate) + { + return (OtherSigningCertificate) o; + } + + if (o is Asn1Sequence) + { + return new OtherSigningCertificate((Asn1Sequence) o); + } + + throw new ArgumentException( + "unknown object in 'OtherSigningCertificate' factory : " + + o.GetType().Name + "."); + } + + /** + * constructors + */ + public OtherSigningCertificate( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + this.certs = Asn1Sequence.GetInstance(seq[0]); + + if (seq.Count > 1) + { + this.policies = Asn1Sequence.GetInstance(seq[1]); + } + } + + public OtherSigningCertificate( + OtherCertID otherCertID) + { + certs = new DerSequence(otherCertID); + } + + public OtherCertID[] GetCerts() + { + OtherCertID[] cs = new OtherCertID[certs.Count]; + + for (int i = 0; i != certs.Count; ++i) + { + cs[i] = OtherCertID.GetInstance(certs[i]); + } + + return cs; + } + + public PolicyInformation[] GetPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] ps = new PolicyInformation[policies.Count]; + + for (int i = 0; i != policies.Count; i++) + { + ps[i] = PolicyInformation.GetInstance(policies[i]); + } + + return ps; + } + + /** + * The definition of OtherSigningCertificate is + *
      +		 * OtherSigningCertificate ::=  SEQUENCE {
      +		 *      certs        SEQUENCE OF OtherCertID,
      +		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
      +		 * }
      +		 * 
      + * id-aa-ets-otherSigCert OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 19 } + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(certs); + + if (policies != null) + { + v.Add(policies); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/SigningCertificate.cs b/iTechSharp/srcbc/asn1/ess/SigningCertificate.cs new file mode 100644 index 0000000..366749b --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/SigningCertificate.cs @@ -0,0 +1,108 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class SigningCertificate + : Asn1Encodable + { + private Asn1Sequence certs, policies; + + public static SigningCertificate GetInstance( + object o) + { + if (o == null || o is SigningCertificate) + { + return (SigningCertificate) o; + } + + if (o is Asn1Sequence) + { + return new SigningCertificate((Asn1Sequence) o); + } + + throw new ArgumentException( + "unknown object in 'SigningCertificate' factory : " + + o.GetType().Name + "."); + } + + /** + * constructors + */ + public SigningCertificate( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + this.certs = Asn1Sequence.GetInstance(seq[0]); + + if (seq.Count > 1) + { + this.policies = Asn1Sequence.GetInstance(seq[1]); + } + } + + public SigningCertificate( + EssCertID essCertID) + { + certs = new DerSequence(essCertID); + } + + public EssCertID[] GetCerts() + { + EssCertID[] cs = new EssCertID[certs.Count]; + + for (int i = 0; i != certs.Count; i++) + { + cs[i] = EssCertID.GetInstance(certs[i]); + } + + return cs; + } + + public PolicyInformation[] GetPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] ps = new PolicyInformation[policies.Count]; + + for (int i = 0; i != policies.Count; i++) + { + ps[i] = PolicyInformation.GetInstance(policies[i]); + } + + return ps; + } + + /** + * The definition of SigningCertificate is + *
      +		 * SigningCertificate ::=  SEQUENCE {
      +		 *      certs        SEQUENCE OF EssCertID,
      +		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
      +		 * }
      +		 * 
      + * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 12 } + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(certs); + + if (policies != null) + { + v.Add(policies); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ess/SigningCertificateV2.cs b/iTechSharp/srcbc/asn1/ess/SigningCertificateV2.cs new file mode 100644 index 0000000..a2aff48 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ess/SigningCertificateV2.cs @@ -0,0 +1,106 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class SigningCertificateV2 + : Asn1Encodable + { + private readonly Asn1Sequence certs; + private readonly Asn1Sequence policies; + + public static SigningCertificateV2 GetInstance( + object o) + { + if (o == null || o is SigningCertificateV2) + return (SigningCertificateV2) o; + + if (o is Asn1Sequence) + return new SigningCertificateV2((Asn1Sequence) o); + + throw new ArgumentException( + "unknown object in 'SigningCertificateV2' factory : " + + o.GetType().Name + "."); + } + + private SigningCertificateV2( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object()); + + if (seq.Count > 1) + { + this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object()); + } + } + + public SigningCertificateV2( + EssCertIDv2[] certs) + { + this.certs = new DerSequence(certs); + } + + public SigningCertificateV2( + EssCertIDv2[] certs, + PolicyInformation[] policies) + { + this.certs = new DerSequence(certs); + + if (policies != null) + { + this.policies = new DerSequence(policies); + } + } + + public EssCertIDv2[] GetCerts() + { + EssCertIDv2[] certIds = new EssCertIDv2[certs.Count]; + for (int i = 0; i != certs.Count; i++) + { + certIds[i] = EssCertIDv2.GetInstance(certs[i]); + } + return certIds; + } + + public PolicyInformation[] GetPolicies() + { + if (policies == null) + return null; + + PolicyInformation[] policyInformations = new PolicyInformation[policies.Count]; + for (int i = 0; i != policies.Count; i++) + { + policyInformations[i] = PolicyInformation.GetInstance(policies[i]); + } + return policyInformations; + } + + /** + * The definition of SigningCertificateV2 is + *
      +		 * SigningCertificateV2 ::=  SEQUENCE {
      +		 *      certs        SEQUENCE OF EssCertIDv2,
      +		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
      +		 * }
      +		 * 
      + * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 47 } + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(certs); + + if (policies != null) + { + v.Add(policies); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/gnu/GNUObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/gnu/GNUObjectIdentifiers.cs new file mode 100644 index 0000000..9311a3a --- /dev/null +++ b/iTechSharp/srcbc/asn1/gnu/GNUObjectIdentifiers.cs @@ -0,0 +1,31 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Gnu +{ + public abstract class GnuObjectIdentifiers + { + public static readonly DerObjectIdentifier Gnu = new DerObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius + public static readonly DerObjectIdentifier GnuPG = new DerObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten) + public static readonly DerObjectIdentifier Notation = new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation + public static readonly DerObjectIdentifier PkaAddress = new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress + public static readonly DerObjectIdentifier GnuRadar = new DerObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar + public static readonly DerObjectIdentifier DigestAlgorithm = new DerObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm + public static readonly DerObjectIdentifier Tiger192 = new DerObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192 + public static readonly DerObjectIdentifier EncryptionAlgorithm = new DerObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm + public static readonly DerObjectIdentifier Serpent = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent + public static readonly DerObjectIdentifier Serpent128Ecb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB + public static readonly DerObjectIdentifier Serpent128Cbc = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC + public static readonly DerObjectIdentifier Serpent128Ofb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB + public static readonly DerObjectIdentifier Serpent128Cfb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB + public static readonly DerObjectIdentifier Serpent192Ecb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB + public static readonly DerObjectIdentifier Serpent192Cbc = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC + public static readonly DerObjectIdentifier Serpent192Ofb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB + public static readonly DerObjectIdentifier Serpent192Cfb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB + public static readonly DerObjectIdentifier Serpent256Ecb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB + public static readonly DerObjectIdentifier Serpent256Cbc = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC + public static readonly DerObjectIdentifier Serpent256Ofb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB + public static readonly DerObjectIdentifier Serpent256Cfb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB + public static readonly DerObjectIdentifier Crc = new DerObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms + public static readonly DerObjectIdentifier Crc32 = new DerObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32 + } +} diff --git a/iTechSharp/srcbc/asn1/iana/IANAObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/iana/IANAObjectIdentifiers.cs new file mode 100644 index 0000000..63343f5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/iana/IANAObjectIdentifiers.cs @@ -0,0 +1,18 @@ +namespace Org.BouncyCastle.Asn1.Iana +{ + public abstract class IanaObjectIdentifiers + { + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)} + // + + public static readonly DerObjectIdentifier IsakmpOakley = new DerObjectIdentifier("1.3.6.1.5.5.8.1"); + + public static readonly DerObjectIdentifier HmacMD5 = new DerObjectIdentifier(IsakmpOakley + ".1"); + public static readonly DerObjectIdentifier HmacSha1 = new DerObjectIdentifier(IsakmpOakley + ".2"); + + public static readonly DerObjectIdentifier HmacTiger = new DerObjectIdentifier(IsakmpOakley + ".3"); + + public static readonly DerObjectIdentifier HmacRipeMD160 = new DerObjectIdentifier(IsakmpOakley + ".4"); + } +} diff --git a/iTechSharp/srcbc/asn1/icao/DataGroupHash.cs b/iTechSharp/srcbc/asn1/icao/DataGroupHash.cs new file mode 100644 index 0000000..91e46ca --- /dev/null +++ b/iTechSharp/srcbc/asn1/icao/DataGroupHash.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Icao +{ + /** + * The DataGroupHash object. + *
      +    * DataGroupHash  ::=  SEQUENCE {
      +    *      dataGroupNumber         DataGroupNumber,
      +    *      dataGroupHashValue     OCTET STRING }
      +    *
      +    * DataGroupNumber ::= INTEGER {
      +    *         dataGroup1    (1),
      +    *         dataGroup1    (2),
      +    *         dataGroup1    (3),
      +    *         dataGroup1    (4),
      +    *         dataGroup1    (5),
      +    *         dataGroup1    (6),
      +    *         dataGroup1    (7),
      +    *         dataGroup1    (8),
      +    *         dataGroup1    (9),
      +    *         dataGroup1    (10),
      +    *         dataGroup1    (11),
      +    *         dataGroup1    (12),
      +    *         dataGroup1    (13),
      +    *         dataGroup1    (14),
      +    *         dataGroup1    (15),
      +    *         dataGroup1    (16) }
      +    *
      +    * 
      + */ + public class DataGroupHash + : Asn1Encodable + { + private readonly DerInteger dataGroupNumber; + private readonly Asn1OctetString dataGroupHashValue; + + public static DataGroupHash GetInstance( + object obj) + { + if (obj == null || obj is DataGroupHash) + { + return (DataGroupHash) obj; + } + + if (obj is Asn1Sequence) + { + return new DataGroupHash(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName); + } + + private DataGroupHash( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.dataGroupNumber = DerInteger.GetInstance(seq[0]); + this.dataGroupHashValue = Asn1OctetString.GetInstance(seq[1]); + } + + public DataGroupHash( + int dataGroupNumber, + Asn1OctetString dataGroupHashValue) + { + this.dataGroupNumber = new DerInteger(dataGroupNumber); + this.dataGroupHashValue = dataGroupHashValue; + } + + public int DataGroupNumber + { + get { return dataGroupNumber.Value.IntValue; } + } + + public Asn1OctetString DataGroupHashValue + { + get { return dataGroupHashValue; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(dataGroupNumber, dataGroupHashValue); + } + } +} diff --git a/iTechSharp/srcbc/asn1/icao/ICAOObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/icao/ICAOObjectIdentifiers.cs new file mode 100644 index 0000000..0ed9f2b --- /dev/null +++ b/iTechSharp/srcbc/asn1/icao/ICAOObjectIdentifiers.cs @@ -0,0 +1,16 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Icao +{ + public abstract class IcaoObjectIdentifiers + { + // + // base id + // + public const string IdIcao = "1.3.27"; + + public static readonly DerObjectIdentifier IdIcaoMrtd = new DerObjectIdentifier(IdIcao + ".1"); + public static readonly DerObjectIdentifier IdIcaoMrtdSecurity = new DerObjectIdentifier(IdIcaoMrtd + ".1"); + public static readonly DerObjectIdentifier IdIcaoLdsSecurityObject = new DerObjectIdentifier(IdIcaoMrtdSecurity + ".1"); + } +} diff --git a/iTechSharp/srcbc/asn1/icao/LDSSecurityObject.cs b/iTechSharp/srcbc/asn1/icao/LDSSecurityObject.cs new file mode 100644 index 0000000..0973c34 --- /dev/null +++ b/iTechSharp/srcbc/asn1/icao/LDSSecurityObject.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Icao +{ + /** + * The LDSSecurityObject object. + *
      +    * LDSSecurityObject ::= SEQUENCE {
      +    *   version                LDSSecurityObjectVersion,
      +    *   hashAlgorithm          DigestAlgorithmIdentifier,
      +    *   dataGroupHashValues    SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup}
      +    *
      +    * DigestAlgorithmIdentifier ::= AlgorithmIdentifier,
      +    *
      +    * LDSSecurityObjectVersion :: INTEGER {V0(0)}
      +    * 
      + */ + + public class LdsSecurityObject + : Asn1Encodable + { + public const int UBDataGroups = 16; + + internal DerInteger version = new DerInteger(0); + internal AlgorithmIdentifier digestAlgorithmIdentifier; + internal DataGroupHash[] datagroupHash; + + public static LdsSecurityObject GetInstance( + object obj) + { + if (obj == null || obj is LdsSecurityObject) + { + return (LdsSecurityObject) obj; + } + + if (obj is Asn1Sequence) + { + return new LdsSecurityObject(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName); + } + + public LdsSecurityObject( + Asn1Sequence seq) + { + if (seq == null || seq.Count == 0) + { + throw new ArgumentException("null or empty sequence passed."); + } + + IEnumerator e = seq.GetEnumerator(); + + // version + e.MoveNext(); + version = DerInteger.GetInstance(e.Current); + // digestAlgorithmIdentifier + e.MoveNext(); + digestAlgorithmIdentifier = AlgorithmIdentifier.GetInstance(e.Current); + + e.MoveNext(); + Asn1Sequence datagroupHashSeq = Asn1Sequence.GetInstance(e.Current); + + CheckDatagroupHashSeqSize(datagroupHashSeq.Count); + + datagroupHash = new DataGroupHash[datagroupHashSeq.Count]; + for (int i= 0; i< datagroupHashSeq.Count; i++) + { + datagroupHash[i] = DataGroupHash.GetInstance(datagroupHashSeq[i]); + } + } + + public LdsSecurityObject( + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash) + { + this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; + this.datagroupHash = datagroupHash; + + CheckDatagroupHashSeqSize(datagroupHash.Length); + } + + private void CheckDatagroupHashSeqSize(int size) + { + if (size < 2 || size > UBDataGroups) + { + throw new ArgumentException("wrong size in DataGroupHashValues : not in (2.."+ UBDataGroups +")"); + } + } + + public AlgorithmIdentifier DigestAlgorithmIdentifier + { + get { return digestAlgorithmIdentifier; } + } + + public DataGroupHash[] GetDatagroupHash() + { + return datagroupHash; + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence( + version, + digestAlgorithmIdentifier, + new DerSequence(datagroupHash)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/ISISMTTObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/isismtt/ISISMTTObjectIdentifiers.cs new file mode 100644 index 0000000..af60b03 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/ISISMTTObjectIdentifiers.cs @@ -0,0 +1,177 @@ +namespace Org.BouncyCastle.Asn1.IsisMtt +{ + public abstract class IsisMttObjectIdentifiers + { + public static readonly DerObjectIdentifier IdIsisMtt = new DerObjectIdentifier("1.3.36.8"); + + public static readonly DerObjectIdentifier IdIsisMttCP = new DerObjectIdentifier(IdIsisMtt + ".1"); + + /** + * The id-isismtt-cp-accredited OID indicates that the certificate is a + * qualified certificate according to Directive 1999/93/EC of the European + * Parliament and of the Council of 13 December 1999 on a Community + * Framework for Electronic Signatures, which additionally conforms the + * special requirements of the SigG and has been issued by an accredited CA. + */ + public static readonly DerObjectIdentifier IdIsisMttCPAccredited = new DerObjectIdentifier(IdIsisMttCP + ".1"); + + public static readonly DerObjectIdentifier IdIsisMttAT = new DerObjectIdentifier(IdIsisMtt + ".3"); + + /** + * Certificate extensionDate of certificate generation + * + *
      +		 *		DateOfCertGenSyntax ::= GeneralizedTime
      +		 * 
      + */ + public static readonly DerObjectIdentifier IdIsisMttATDateOfCertGen = new DerObjectIdentifier(IdIsisMttAT + ".1"); + + /** + * Attribute to indicate that the certificate holder may sign in the name of + * a third person. May also be used as extension in a certificate. + */ + public static readonly DerObjectIdentifier IdIsisMttATProcuration = new DerObjectIdentifier(IdIsisMttAT + ".2"); + + /** + * Attribute to indicate admissions to certain professions. May be used as + * attribute in attribute certificate or as extension in a certificate + */ + public static readonly DerObjectIdentifier IdIsisMttATAdmission = new DerObjectIdentifier(IdIsisMttAT + ".3"); + + /** + * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST + * be used in new certificates in place of the extension/attribute + * MonetaryLimit since January 1, 2004. For the sake of backward + * compatibility with certificates already in use, SigG conforming + * components MUST support MonetaryLimit (as well as QcEuLimitValue). + */ + public static readonly DerObjectIdentifier IdIsisMttATMonetaryLimit = new DerObjectIdentifier(IdIsisMttAT + ".4"); + + /** + * A declaration of majority. May be used as attribute in attribute + * certificate or as extension in a certificate + */ + public static readonly DerObjectIdentifier IdIsisMttATDeclarationOfMajority = new DerObjectIdentifier(IdIsisMttAT + ".5"); + + /** + * + * Serial number of the smart card containing the corresponding private key + * + *
      +		 *		ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
      +		 * 
      + */ + public static readonly DerObjectIdentifier IdIsisMttATIccsn = new DerObjectIdentifier(IdIsisMttAT + ".6"); + + /** + * + * Reference for a file of a smartcard that stores the public key of this + * certificate and that is used as �security anchor�. + * + *
      +		 *		PKReferenceSyntax ::= OCTET STRING (SIZE(20))
      +		 * 
      + */ + public static readonly DerObjectIdentifier IdIsisMttATPKReference = new DerObjectIdentifier(IdIsisMttAT + ".7"); + + /** + * Some other restriction regarding the usage of this certificate. May be + * used as attribute in attribute certificate or as extension in a + * certificate. + * + *
      +		 *		RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
      +		 * 
      + * + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction + */ + public static readonly DerObjectIdentifier IdIsisMttATRestriction = new DerObjectIdentifier(IdIsisMttAT + ".8"); + + /** + * + * (Single)Request extension: Clients may include this extension in a + * (single) Request to request the responder to send the certificate in the + * response message along with the status information. Besides the LDAP + * service, this extension provides another mechanism for the distribution + * of certificates, which MAY optionally be provided by certificate + * repositories. + * + *
      +		 *		RetrieveIfAllowed ::= BOOLEAN
      +		 * 
      + */ + public static readonly DerObjectIdentifier IdIsisMttATRetrieveIfAllowed = new DerObjectIdentifier(IdIsisMttAT + ".9"); + + /** + * SingleOCSPResponse extension: The certificate requested by the client by + * inserting the RetrieveIfAllowed extension in the request, will be + * returned in this extension. + * + * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate + */ + public static readonly DerObjectIdentifier IdIsisMttATRequestedCertificate = new DerObjectIdentifier(IdIsisMttAT + ".10"); + + /** + * Base ObjectIdentifier for naming authorities + */ + public static readonly DerObjectIdentifier IdIsisMttATNamingAuthorities = new DerObjectIdentifier(IdIsisMttAT + ".11"); + + /** + * SingleOCSPResponse extension: Date, when certificate has been published + * in the directory and status information has become available. Currently, + * accrediting authorities enforce that SigG-conforming OCSP servers include + * this extension in the responses. + * + *
      +		 *		CertInDirSince ::= GeneralizedTime
      +		 * 
      + */ + public static readonly DerObjectIdentifier IdIsisMttATCertInDirSince = new DerObjectIdentifier(IdIsisMttAT + ".12"); + + /** + * Hash of a certificate in OCSP. + * + * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash + */ + public static readonly DerObjectIdentifier IdIsisMttATCertHash = new DerObjectIdentifier(IdIsisMttAT + ".13"); + + /** + *
      +		 *		NameAtBirth ::= DirectoryString(SIZE(1..64)
      +		 * 
      + * + * Used in + * {@link Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes SubjectDirectoryAttributes} + */ + public static readonly DerObjectIdentifier IdIsisMttATNameAtBirth = new DerObjectIdentifier(IdIsisMttAT + ".14"); + + /** + * Some other information of non-restrictive nature regarding the usage of + * this certificate. May be used as attribute in atribute certificate or as + * extension in a certificate. + * + *
      +		 *               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
      +		 * 
      + * + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax + */ + public static readonly DerObjectIdentifier IdIsisMttATAdditionalInformation = new DerObjectIdentifier(IdIsisMttAT + ".15"); + + /** + * Indicates that an attribute certificate exists, which limits the + * usability of this public key certificate. Whenever verifying a signature + * with the help of this certificate, the content of the corresponding + * attribute certificate should be concerned. This extension MUST be + * included in a PKC, if a corresponding attribute certificate (having the + * PKC as base certificate) contains some attribute that restricts the + * usability of the PKC too. Attribute certificates with restricting content + * MUST always be included in the signed document. + * + *
      +		 *		LiabilityLimitationFlagSyntax ::= BOOLEAN
      +		 * 
      + */ + public static readonly DerObjectIdentifier IdIsisMttATLiabilityLimitationFlag = new DerObjectIdentifier("0.2.262.1.10.12.0"); + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/ocsp/CertHash.cs b/iTechSharp/srcbc/asn1/isismtt/ocsp/CertHash.cs new file mode 100644 index 0000000..da5b530 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/ocsp/CertHash.cs @@ -0,0 +1,121 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp +{ + /** + * ISIS-MTT PROFILE: The responder may include this extension in a response to + * send the hash of the requested certificate to the responder. This hash is + * cryptographically bound to the certificate and serves as evidence that the + * certificate is known to the responder (i.e. it has been issued and is present + * in the directory). Hence, this extension is a means to provide a positive + * statement of availability as described in T8.[8]. As explained in T13.[1], + * clients may rely on this information to be able to validate signatures after + * the expiry of the corresponding certificate. Hence, clients MUST support this + * extension. If a positive statement of availability is to be delivered, this + * extension syntax and OID MUST be used. + *

      + *

      + *

      +	*     CertHash ::= SEQUENCE {
      +	*       hashAlgorithm AlgorithmIdentifier,
      +	*       certificateHash OCTET STRING
      +	*     }
      +	* 
      + */ + public class CertHash + : Asn1Encodable + { + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly byte[] certificateHash; + + public static CertHash GetInstance( + object obj) + { + if (obj == null || obj is CertHash) + { + return (CertHash) obj; + } + + if (obj is Asn1Sequence) + { + return new CertHash((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + *

      + * The sequence is of type CertHash: + *

      + *

      +		*     CertHash ::= SEQUENCE {
      +		*       hashAlgorithm AlgorithmIdentifier,
      +		*       certificateHash OCTET STRING
      +		*     }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private CertHash( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]); + this.certificateHash = DerOctetString.GetInstance(seq[1]).GetOctets(); + } + + /** + * Constructor from a given details. + * + * @param hashAlgorithm The hash algorithm identifier. + * @param certificateHash The hash of the whole DER encoding of the certificate. + */ + public CertHash( + AlgorithmIdentifier hashAlgorithm, + byte[] certificateHash) + { + if (hashAlgorithm == null) + throw new ArgumentNullException("hashAlgorithm"); + if (certificateHash == null) + throw new ArgumentNullException("certificateHash"); + + this.hashAlgorithm = hashAlgorithm; + this.certificateHash = (byte[]) certificateHash.Clone(); + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public byte[] CertificateHash + { + get { return (byte[]) certificateHash.Clone(); } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*     CertHash ::= SEQUENCE {
      +		*       hashAlgorithm AlgorithmIdentifier,
      +		*       certificateHash OCTET STRING
      +		*     }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(hashAlgorithm, new DerOctetString(certificateHash)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs b/iTechSharp/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs new file mode 100644 index 0000000..62657fe --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs @@ -0,0 +1,187 @@ +using System; +using System.IO; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp +{ + /** + * ISIS-MTT-Optional: The certificate requested by the client by inserting the + * RetrieveIfAllowed extension in the request, will be returned in this + * extension. + *

      + * ISIS-MTT-SigG: The signature act allows publishing certificates only then, + * when the certificate owner gives his isExplicit permission. Accordingly, there + * may be �nondownloadable� certificates, about which the responder must provide + * status information, but MUST NOT include them in the response. Clients may + * get therefore the following three kind of answers on a single request + * including the RetrieveIfAllowed extension: + *

        + *
      • a) the responder supports the extension and is allowed to publish the + * certificate: RequestedCertificate returned including the requested + * certificate
      • + *
      • b) the responder supports the extension but is NOT allowed to publish + * the certificate: RequestedCertificate returned including an empty OCTET + * STRING
      • + *
      • c) the responder does not support the extension: RequestedCertificate is + * not included in the response
      • + *
      + * Clients requesting RetrieveIfAllowed MUST be able to handle these cases. If + * any of the OCTET STRING options is used, it MUST contain the DER encoding of + * the requested certificate. + *

      + *

      +	*            RequestedCertificate ::= CHOICE {
      +	*              Certificate Certificate,
      +	*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
      +	*              attributeCertificate [1] EXPLICIT OCTET STRING
      +	*            }
      +	* 
      + */ + public class RequestedCertificate + : Asn1Encodable + //, ASN1Choice + { + public enum Choice + { + Certificate = -1, + PublicKeyCertificate = 0, + AttributeCertificate = 1 + } + + private readonly X509CertificateStructure cert; + private readonly byte[] publicKeyCert; + private readonly byte[] attributeCert; + + public static RequestedCertificate GetInstance( + object obj) + { + if (obj == null || obj is RequestedCertificate) + { + return (RequestedCertificate) obj; + } + + if (obj is Asn1Sequence) + { + return new RequestedCertificate(X509CertificateStructure.GetInstance(obj)); + } + + if (obj is Asn1TaggedObject) + { + return new RequestedCertificate((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static RequestedCertificate GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + if (!isExplicit) + throw new ArgumentException("choice item must be explicitly tagged"); + + return GetInstance(obj.GetObject()); + } + + private RequestedCertificate( + Asn1TaggedObject tagged) + { + switch ((Choice) tagged.TagNo) + { + case Choice.AttributeCertificate: + this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets(); + break; + case Choice.PublicKeyCertificate: + this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets(); + break; + default: + throw new ArgumentException("unknown tag number: " + tagged.TagNo); + } + } + + /** + * Constructor from a given details. + *

      + * Only one parameter can be given. All other must be null. + * + * @param certificate Given as Certificate + */ + public RequestedCertificate( + X509CertificateStructure certificate) + { + this.cert = certificate; + } + + public RequestedCertificate( + Choice type, + byte[] certificateOctets) + : this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets))) + { + } + + public Choice Type + { + get + { + if (cert != null) + return Choice.Certificate; + + if (publicKeyCert != null) + return Choice.PublicKeyCertificate; + + return Choice.AttributeCertificate; + } + } + + public byte[] GetCertificateBytes() + { + if (cert != null) + { + try + { + return cert.GetEncoded(); + } + catch (IOException e) + { + throw new InvalidOperationException("can't decode certificate: " + e); + } + } + + if (publicKeyCert != null) + return publicKeyCert; + + return attributeCert; + } + + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*            RequestedCertificate ::= CHOICE {
      +		*              Certificate Certificate,
      +		*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
      +		*              attributeCertificate [1] EXPLICIT OCTET STRING
      +		*            }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + if (publicKeyCert != null) + { + return new DerTaggedObject(0, new DerOctetString(publicKeyCert)); + } + + if (attributeCert != null) + { + return new DerTaggedObject(1, new DerOctetString(attributeCert)); + } + + return cert.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/AdditionalInformationSyntax.cs b/iTechSharp/srcbc/asn1/isismtt/x509/AdditionalInformationSyntax.cs new file mode 100644 index 0000000..11af9b9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/AdditionalInformationSyntax.cs @@ -0,0 +1,74 @@ +using System; + +using Org.BouncyCastle.Asn1.X500; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * Some other information of non-restrictive nature regarding the usage of this + * certificate. + * + *
      +	*    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
      +	* 
      + */ + public class AdditionalInformationSyntax + : Asn1Encodable + { + private readonly DirectoryString information; + + public static AdditionalInformationSyntax GetInstance( + object obj) + { + if (obj == null || obj is AdditionalInformationSyntax) + { + return (AdditionalInformationSyntax) obj; + } + + if (obj is IAsn1String) + { + return new AdditionalInformationSyntax(DirectoryString.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AdditionalInformationSyntax( + DirectoryString information) + { + this.information = information; + } + + /** + * Constructor from a given details. + * + * @param information The describtion of the information. + */ + public AdditionalInformationSyntax( + string information) + { + this.information = new DirectoryString(information); + } + + public virtual DirectoryString Information + { + get { return information; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*   AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return information.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/AdmissionSyntax.cs b/iTechSharp/srcbc/asn1/isismtt/x509/AdmissionSyntax.cs new file mode 100644 index 0000000..6c4a628 Binary files /dev/null and b/iTechSharp/srcbc/asn1/isismtt/x509/AdmissionSyntax.cs differ diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/Admissions.cs b/iTechSharp/srcbc/asn1/isismtt/x509/Admissions.cs new file mode 100644 index 0000000..40290c6 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/Admissions.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * An Admissions structure. + *

      + *

      +	*            Admissions ::= SEQUENCE
      +	*            {
      +	*              admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
      +	*              namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
      +	*              professionInfos SEQUENCE OF ProfessionInfo
      +	*            }
      +	* 

      + *

      + * + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority + */ + public class Admissions + : Asn1Encodable + { + private readonly GeneralName admissionAuthority; + private readonly NamingAuthority namingAuthority; + private readonly Asn1Sequence professionInfos; + + public static Admissions GetInstance( + object obj) + { + if (obj == null || obj is Admissions) + { + return (Admissions) obj; + } + + if (obj is Asn1Sequence) + { + return new Admissions((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + *

      + * The sequence is of type ProcurationSyntax: + *

      + *

      +		*            Admissions ::= SEQUENCE
      +		*            {
      +		*              admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
      +		*              namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
      +		*              professionInfos SEQUENCE OF ProfessionInfo
      +		*            }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private Admissions( + Asn1Sequence seq) + { + if (seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + Asn1Encodable o = (Asn1Encodable) e.Current; + if (o is Asn1TaggedObject) + { + switch (((Asn1TaggedObject)o).TagNo) + { + case 0: + admissionAuthority = GeneralName.GetInstance((Asn1TaggedObject)o, true); + break; + case 1: + namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true); + break; + default: + throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo); + } + e.MoveNext(); + o = (Asn1Encodable) e.Current; + } + if (o is Asn1TaggedObject) + { + switch (((Asn1TaggedObject)o).TagNo) + { + case 1: + namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true); + break; + default: + throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo); + } + e.MoveNext(); + o = (Asn1Encodable) e.Current; + } + professionInfos = Asn1Sequence.GetInstance(o); + if (e.MoveNext()) + { + throw new ArgumentException("Bad object encountered: " + e.Current.GetType().Name); + } + } + + /** + * Constructor from a given details. + *

      + * Parameter professionInfos is mandatory. + * + * @param admissionAuthority The admission authority. + * @param namingAuthority The naming authority. + * @param professionInfos The profession infos. + */ + public Admissions( + GeneralName admissionAuthority, + NamingAuthority namingAuthority, + ProfessionInfo[] professionInfos) + { + this.admissionAuthority = admissionAuthority; + this.namingAuthority = namingAuthority; + this.professionInfos = new DerSequence(professionInfos); + } + + public virtual GeneralName AdmissionAuthority + { + get { return admissionAuthority; } + } + + public virtual NamingAuthority NamingAuthority + { + get { return namingAuthority; } + } + + public ProfessionInfo[] GetProfessionInfos() + { + ProfessionInfo[] infos = new ProfessionInfo[professionInfos.Count]; + int count = 0; + foreach (Asn1Encodable ae in professionInfos) + { + infos[count++] = ProfessionInfo.GetInstance(ae); + } + return infos; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*       Admissions ::= SEQUENCE
      +		*       {
      +		*         admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
      +		*         namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
      +		*         professionInfos SEQUENCE OF ProfessionInfo
      +		*       }
      +		* 

      + *

      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + + if (admissionAuthority != null) + { + vec.Add(new DerTaggedObject(true, 0, admissionAuthority)); + } + + if (namingAuthority != null) + { + vec.Add(new DerTaggedObject(true, 1, namingAuthority)); + } + + vec.Add(professionInfos); + + return new DerSequence(vec); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs b/iTechSharp/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs new file mode 100644 index 0000000..581b4b3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs @@ -0,0 +1,171 @@ +using System; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * A declaration of majority. + *

      + *

      +	*           DeclarationOfMajoritySyntax ::= CHOICE
      +	*           {
      +	*             notYoungerThan [0] IMPLICIT INTEGER,
      +	*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
      +	*             {
      +	*               fullAge BOOLEAN DEFAULT TRUE,
      +	*               country PrintableString (SIZE(2))
      +	*             }
      +	*             dateOfBirth [2] IMPLICIT GeneralizedTime
      +	*           }
      +	* 
      + *

      + * fullAgeAtCountry indicates the majority of the owner with respect to the laws + * of a specific country. + */ + public class DeclarationOfMajority + : Asn1Encodable + //, ASN1Choice + { + public enum Choice + { + NotYoungerThan = 0, + FullAgeAtCountry = 1, + DateOfBirth = 2 + }; + + private readonly Asn1TaggedObject declaration; + + public DeclarationOfMajority( + int notYoungerThan) + { + declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan)); + } + + public DeclarationOfMajority( + bool fullAge, + string country) + { + if (country.Length > 2) + throw new ArgumentException("country can only be 2 characters"); + + DerPrintableString countryString = new DerPrintableString(country, true); + + DerSequence seq; + if (fullAge) + { + seq = new DerSequence(countryString); + } + else + { + seq = new DerSequence(DerBoolean.False, countryString); + } + + this.declaration = new DerTaggedObject(false, 1, seq); + } + + public DeclarationOfMajority( + DerGeneralizedTime dateOfBirth) + { + this.declaration = new DerTaggedObject(false, 2, dateOfBirth); + } + + public static DeclarationOfMajority GetInstance( + object obj) + { + if (obj == null || obj is DeclarationOfMajority) + { + return (DeclarationOfMajority) obj; + } + + if (obj is Asn1TaggedObject) + { + return new DeclarationOfMajority((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private DeclarationOfMajority( + Asn1TaggedObject o) + { + if (o.TagNo > 2) + throw new ArgumentException("Bad tag number: " + o.TagNo); + + this.declaration = o; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*           DeclarationOfMajoritySyntax ::= CHOICE
      +		*           {
      +		*             notYoungerThan [0] IMPLICIT INTEGER,
      +		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
      +		*             {
      +		*               fullAge BOOLEAN DEFAULT TRUE,
      +		*               country PrintableString (SIZE(2))
      +		*             }
      +		*             dateOfBirth [2] IMPLICIT GeneralizedTime
      +		*           }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return declaration; + } + + public Choice Type + { + get { return (Choice) declaration.TagNo; } + } + + /** + * @return notYoungerThan if that's what we are, -1 otherwise + */ + public virtual int NotYoungerThan + { + get + { + switch ((Choice) declaration.TagNo) + { + case Choice.NotYoungerThan: + return DerInteger.GetInstance(declaration, false).Value.IntValue; + default: + return -1; + } + } + } + + public virtual Asn1Sequence FullAgeAtCountry + { + get + { + switch ((Choice) declaration.TagNo) + { + case Choice.FullAgeAtCountry: + return Asn1Sequence.GetInstance(declaration, false); + default: + return null; + } + } + } + + public virtual DerGeneralizedTime DateOfBirth + { + get + { + switch ((Choice) declaration.TagNo) + { + case Choice.DateOfBirth: + return DerGeneralizedTime.GetInstance(declaration, false); + default: + return null; + } + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/MonetaryLimit.cs b/iTechSharp/srcbc/asn1/isismtt/x509/MonetaryLimit.cs new file mode 100644 index 0000000..f70ae34 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/MonetaryLimit.cs @@ -0,0 +1,122 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST be + * used in new certificates in place of the extension/attribute MonetaryLimit + * since January 1, 2004. For the sake of backward compatibility with + * certificates already in use, components SHOULD support MonetaryLimit (as well + * as QcEuLimitValue). + *

      + * Indicates a monetary limit within which the certificate holder is authorized + * to act. (This value DOES NOT express a limit on the liability of the + * certification authority). + *

      + *

      +	*    MonetaryLimitSyntax ::= SEQUENCE
      +	*    {
      +	*      currency PrintableString (SIZE(3)),
      +	*      amount INTEGER,
      +	*      exponent INTEGER
      +	*    }
      +	* 
      + *

      + * currency must be the ISO code. + *

      + * value = amount�10*exponent + */ + public class MonetaryLimit + : Asn1Encodable + { + private readonly DerPrintableString currency; + private readonly DerInteger amount; + private readonly DerInteger exponent; + + public static MonetaryLimit GetInstance( + object obj) + { + if (obj == null || obj is MonetaryLimit) + { + return (MonetaryLimit) obj; + } + + if (obj is Asn1Sequence) + { + return new MonetaryLimit(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private MonetaryLimit( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + currency = DerPrintableString.GetInstance(seq[0]); + amount = DerInteger.GetInstance(seq[1]); + exponent = DerInteger.GetInstance(seq[2]); + } + + /** + * Constructor from a given details. + *

      + *

      + * value = amount�10^exponent + * + * @param currency The currency. Must be the ISO code. + * @param amount The amount + * @param exponent The exponent + */ + public MonetaryLimit( + string currency, + int amount, + int exponent) + { + this.currency = new DerPrintableString(currency, true); + this.amount = new DerInteger(amount); + this.exponent = new DerInteger(exponent); + } + + public virtual string Currency + { + get { return currency.GetString(); } + } + + public virtual BigInteger Amount + { + get { return amount.Value; } + } + + public virtual BigInteger Exponent + { + get { return exponent.Value; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*    MonetaryLimitSyntax ::= SEQUENCE
      +		*    {
      +		*      currency PrintableString (SIZE(3)),
      +		*      amount INTEGER,
      +		*      exponent INTEGER
      +		*    }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(currency, amount, exponent); + } + + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/NamingAuthority.cs b/iTechSharp/srcbc/asn1/isismtt/x509/NamingAuthority.cs new file mode 100644 index 0000000..4262fd0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/NamingAuthority.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X500; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * Names of authorities which are responsible for the administration of title + * registers. + * + *
      +	*             NamingAuthority ::= SEQUENCE 
      +	*             {
      +	*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
      +	*               namingAuthorityUrl IA5String OPTIONAL,
      +	*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
      +	*             }
      +	* 
      + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax + * + */ + public class NamingAuthority + : Asn1Encodable + { + /** + * Profession OIDs should always be defined under the OID branch of the + * responsible naming authority. At the time of this writing, the work group + * �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the + * first naming authority under the OID id-isismtt-at-namingAuthorities. + */ + public static readonly DerObjectIdentifier IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + = new DerObjectIdentifier(IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities + ".1"); + + private readonly DerObjectIdentifier namingAuthorityID; + private readonly string namingAuthorityUrl; + private readonly DirectoryString namingAuthorityText; + + public static NamingAuthority GetInstance( + object obj) + { + if (obj == null || obj is NamingAuthority) + { + return (NamingAuthority) obj; + } + + if (obj is Asn1Sequence) + { + return new NamingAuthority((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static NamingAuthority GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + /** + * Constructor from Asn1Sequence. + *

      + *

      + *

      +		*             NamingAuthority ::= SEQUENCE
      +		*             {
      +		*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
      +		*               namingAuthorityUrl IA5String OPTIONAL,
      +		*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
      +		*             }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private NamingAuthority( + Asn1Sequence seq) + { + if (seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + IEnumerator e = seq.GetEnumerator(); + + if (e.MoveNext()) + { + Asn1Encodable o = (Asn1Encodable) e.Current; + if (o is DerObjectIdentifier) + { + namingAuthorityID = (DerObjectIdentifier) o; + } + else if (o is DerIA5String) + { + namingAuthorityUrl = DerIA5String.GetInstance(o).GetString(); + } + else if (o is IAsn1String) + { + namingAuthorityText = DirectoryString.GetInstance(o); + } + else + { + throw new ArgumentException("Bad object encountered: " + o.GetType().Name); + } + } + + if (e.MoveNext()) + { + Asn1Encodable o = (Asn1Encodable) e.Current; + if (o is DerIA5String) + { + namingAuthorityUrl = DerIA5String.GetInstance(o).GetString(); + } + else if (o is IAsn1String) + { + namingAuthorityText = DirectoryString.GetInstance(o); + } + else + { + throw new ArgumentException("Bad object encountered: " + o.GetType().Name); + } + } + + if (e.MoveNext()) + { + Asn1Encodable o = (Asn1Encodable) e.Current; + if (o is IAsn1String) + { + namingAuthorityText = DirectoryString.GetInstance(o); + } + else + { + throw new ArgumentException("Bad object encountered: " + o.GetType().Name); + } + } + } + + /** + * @return Returns the namingAuthorityID. + */ + public virtual DerObjectIdentifier NamingAuthorityID + { + get { return namingAuthorityID; } + } + + /** + * @return Returns the namingAuthorityText. + */ + public virtual DirectoryString NamingAuthorityText + { + get { return namingAuthorityText; } + } + + /** + * @return Returns the namingAuthorityUrl. + */ + public virtual string NamingAuthorityUrl + { + get { return namingAuthorityUrl; } + } + + /** + * Constructor from given details. + *

      + * All parameters can be combined. + * + * @param namingAuthorityID ObjectIdentifier for naming authority. + * @param namingAuthorityUrl URL for naming authority. + * @param namingAuthorityText Textual representation of naming authority. + */ + public NamingAuthority( + DerObjectIdentifier namingAuthorityID, + string namingAuthorityUrl, + DirectoryString namingAuthorityText) + { + this.namingAuthorityID = namingAuthorityID; + this.namingAuthorityUrl = namingAuthorityUrl; + this.namingAuthorityText = namingAuthorityText; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*             NamingAuthority ::= SEQUENCE
      +		*             {
      +		*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
      +		*               namingAuthorityUrl IA5String OPTIONAL,
      +		*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
      +		*             }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + if (namingAuthorityID != null) + { + vec.Add(namingAuthorityID); + } + if (namingAuthorityUrl != null) + { + vec.Add(new DerIA5String(namingAuthorityUrl, true)); + } + if (namingAuthorityText != null) + { + vec.Add(namingAuthorityText); + } + return new DerSequence(vec); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/ProcurationSyntax.cs b/iTechSharp/srcbc/asn1/isismtt/x509/ProcurationSyntax.cs new file mode 100644 index 0000000..a25df22 --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/ProcurationSyntax.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X500; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * Attribute to indicate that the certificate holder may sign in the name of a + * third person. + *

      + * ISIS-MTT PROFILE: The corresponding ProcurationSyntax contains either the + * name of the person who is represented (subcomponent thirdPerson) or a + * reference to his/her base certificate (in the component signingFor, + * subcomponent certRef), furthermore the optional components country and + * typeSubstitution to indicate the country whose laws apply, and respectively + * the type of procuration (e.g. manager, procuration, custody). + *

      + *

      + * ISIS-MTT PROFILE: The GeneralName MUST be of type directoryName and MAY only + * contain: - RFC3039 attributes, except pseudonym (countryName, commonName, + * surname, givenName, serialNumber, organizationName, organizationalUnitName, + * stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName + * attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship, + * countryOfResidence and NameAtBirth). + *

      + *
      +	*               ProcurationSyntax ::= SEQUENCE {
      +	*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
      +	*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
      +	*                 signingFor [3] EXPLICIT SigningFor 
      +	*               }
      +	*               
      +	*               SigningFor ::= CHOICE 
      +	*               { 
      +	*                 thirdPerson GeneralName,
      +	*                 certRef IssuerSerial 
      +	*               }
      +	* 
      + * + */ + public class ProcurationSyntax + : Asn1Encodable + { + private readonly string country; + private readonly DirectoryString typeOfSubstitution; + private readonly GeneralName thirdPerson; + private readonly IssuerSerial certRef; + + public static ProcurationSyntax GetInstance( + object obj) + { + if (obj == null || obj is ProcurationSyntax) + { + return (ProcurationSyntax) obj; + } + + if (obj is Asn1Sequence) + { + return new ProcurationSyntax((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + *

      + * The sequence is of type ProcurationSyntax: + *

      + *

      +		*               ProcurationSyntax ::= SEQUENCE {
      +		*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
      +		*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
      +		*                 signingFor [3] EXPLICIT SigningFor
      +		*               }
      +		* 

      + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + *

      + * + * @param seq The ASN.1 sequence. + */ + private ProcurationSyntax( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + IEnumerator e = seq.GetEnumerator(); + + while (e.MoveNext()) + { + Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current); + switch (o.TagNo) + { + case 1: + country = DerPrintableString.GetInstance(o, true).GetString(); + break; + case 2: + typeOfSubstitution = DirectoryString.GetInstance(o, true); + break; + case 3: + Asn1Object signingFor = o.GetObject(); + if (signingFor is Asn1TaggedObject) + { + thirdPerson = GeneralName.GetInstance(signingFor); + } + else + { + certRef = IssuerSerial.GetInstance(signingFor); + } + break; + default: + throw new ArgumentException("Bad tag number: " + o.TagNo); + } + } + } + + /** + * Constructor from a given details. + *

      + *

      + * Either generalName or certRef MUST be + * null. + * + * @param country The country code whose laws apply. + * @param typeOfSubstitution The type of procuration. + * @param certRef Reference to certificate of the person who is represented. + */ + public ProcurationSyntax( + string country, + DirectoryString typeOfSubstitution, + IssuerSerial certRef) + { + this.country = country; + this.typeOfSubstitution = typeOfSubstitution; + this.thirdPerson = null; + this.certRef = certRef; + } + + /** + * Constructor from a given details. + *

      + *

      + * Either generalName or certRef MUST be + * null. + * + * @param country The country code whose laws apply. + * @param typeOfSubstitution The type of procuration. + * @param thirdPerson The GeneralName of the person who is represented. + */ + public ProcurationSyntax( + string country, + DirectoryString typeOfSubstitution, + GeneralName thirdPerson) + { + this.country = country; + this.typeOfSubstitution = typeOfSubstitution; + this.thirdPerson = thirdPerson; + this.certRef = null; + } + + public virtual string Country + { + get { return country; } + } + + public virtual DirectoryString TypeOfSubstitution + { + get { return typeOfSubstitution; } + } + + public virtual GeneralName ThirdPerson + { + get { return thirdPerson; } + } + + public virtual IssuerSerial CertRef + { + get { return certRef; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*               ProcurationSyntax ::= SEQUENCE {
      +		*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
      +		*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
      +		*                 signingFor [3] EXPLICIT SigningFor
      +		*               }
      +		* 

      + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + *

      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + if (country != null) + { + vec.Add(new DerTaggedObject(true, 1, new DerPrintableString(country, true))); + } + if (typeOfSubstitution != null) + { + vec.Add(new DerTaggedObject(true, 2, typeOfSubstitution)); + } + if (thirdPerson != null) + { + vec.Add(new DerTaggedObject(true, 3, thirdPerson)); + } + else + { + vec.Add(new DerTaggedObject(true, 3, certRef)); + } + + return new DerSequence(vec); + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/ProfessionInfo.cs b/iTechSharp/srcbc/asn1/isismtt/x509/ProfessionInfo.cs new file mode 100644 index 0000000..3bad2cb --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/ProfessionInfo.cs @@ -0,0 +1,386 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X500; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * Professions, specializations, disciplines, fields of activity, etc. + * + *
      +	*               ProfessionInfo ::= SEQUENCE 
      +	*               {
      +	*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
      +	*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
      +	*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
      +	*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
      +	*                 addProfessionInfo OCTET STRING OPTIONAL 
      +	*               }
      +	* 
      + * + * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax + */ + public class ProfessionInfo + : Asn1Encodable + { + /** + * Rechtsanw�ltin + */ + public static readonly DerObjectIdentifier Rechtsanwltin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".1"); + + /** + * Rechtsanwalt + */ + public static readonly DerObjectIdentifier Rechtsanwalt = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".2"); + + /** + * Rechtsbeistand + */ + public static readonly DerObjectIdentifier Rechtsbeistand = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".3"); + + /** + * Steuerberaterin + */ + public static readonly DerObjectIdentifier Steuerberaterin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".4"); + + /** + * Steuerberater + */ + public static readonly DerObjectIdentifier Steuerberater = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".5"); + + /** + * Steuerbevollm�chtigte + */ + public static readonly DerObjectIdentifier Steuerbevollmchtigte = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".6"); + + /** + * Steuerbevollm�chtigter + */ + public static readonly DerObjectIdentifier Steuerbevollmchtigter = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".7"); + + /** + * Notarin + */ + public static readonly DerObjectIdentifier Notarin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".8"); + + /** + * Notar + */ + public static readonly DerObjectIdentifier Notar = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".9"); + + /** + * Notarvertreterin + */ + public static readonly DerObjectIdentifier Notarvertreterin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".10"); + + /** + * Notarvertreter + */ + public static readonly DerObjectIdentifier Notarvertreter = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".11"); + + /** + * Notariatsverwalterin + */ + public static readonly DerObjectIdentifier Notariatsverwalterin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".12"); + + /** + * Notariatsverwalter + */ + public static readonly DerObjectIdentifier Notariatsverwalter = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".13"); + + /** + * Wirtschaftspr�ferin + */ + public static readonly DerObjectIdentifier Wirtschaftsprferin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".14"); + + /** + * Wirtschaftspr�fer + */ + public static readonly DerObjectIdentifier Wirtschaftsprfer = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".15"); + + /** + * Vereidigte Buchpr�ferin + */ + public static readonly DerObjectIdentifier VereidigteBuchprferin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".16"); + + /** + * Vereidigter Buchpr�fer + */ + public static readonly DerObjectIdentifier VereidigterBuchprfer = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".17"); + + /** + * Patentanw�ltin + */ + public static readonly DerObjectIdentifier Patentanwltin = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".18"); + + /** + * Patentanwalt + */ + public static readonly DerObjectIdentifier Patentanwalt = new DerObjectIdentifier( + NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".19"); + + private readonly NamingAuthority namingAuthority; + private readonly Asn1Sequence professionItems; + private readonly Asn1Sequence professionOids; + private readonly string registrationNumber; + private readonly Asn1OctetString addProfessionInfo; + + public static ProfessionInfo GetInstance( + object obj) + { + if (obj == null || obj is ProfessionInfo) + { + return (ProfessionInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new ProfessionInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + *

      + *

      + *

      +		*               ProfessionInfo ::= SEQUENCE
      +		*               {
      +		*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
      +		*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
      +		*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
      +		*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
      +		*                 addProfessionInfo OCTET STRING OPTIONAL
      +		*               }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private ProfessionInfo( + Asn1Sequence seq) + { + if (seq.Count > 5) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + Asn1Encodable o = (Asn1Encodable) e.Current; + + if (o is Asn1TaggedObject) + { + Asn1TaggedObject ato = (Asn1TaggedObject) o; + if (ato.TagNo != 0) + throw new ArgumentException("Bad tag number: " + ato.TagNo); + + namingAuthority = NamingAuthority.GetInstance(ato, true); + e.MoveNext(); + o = (Asn1Encodable) e.Current; + } + + professionItems = Asn1Sequence.GetInstance(o); + + if (e.MoveNext()) + { + o = (Asn1Encodable) e.Current; + if (o is Asn1Sequence) + { + professionOids = Asn1Sequence.GetInstance(o); + } + else if (o is DerPrintableString) + { + registrationNumber = DerPrintableString.GetInstance(o).GetString(); + } + else if (o is Asn1OctetString) + { + addProfessionInfo = Asn1OctetString.GetInstance(o); + } + else + { + throw new ArgumentException("Bad object encountered: " + o.GetType().Name); + } + } + + if (e.MoveNext()) + { + o = (Asn1Encodable) e.Current; + if (o is DerPrintableString) + { + registrationNumber = DerPrintableString.GetInstance(o).GetString(); + } + else if (o is DerOctetString) + { + addProfessionInfo = (DerOctetString) o; + } + else + { + throw new ArgumentException("Bad object encountered: " + o.GetType().Name); + } + } + + if (e.MoveNext()) + { + o = (Asn1Encodable) e.Current; + if (o is DerOctetString) + { + addProfessionInfo = (DerOctetString) o; + } + else + { + throw new ArgumentException("Bad object encountered: " + o.GetType().Name); + } + } + } + + /** + * Constructor from given details. + *

      + * professionItems is mandatory, all other parameters are + * optional. + * + * @param namingAuthority The naming authority. + * @param professionItems Directory strings of the profession. + * @param professionOids DERObjectIdentfier objects for the + * profession. + * @param registrationNumber Registration number. + * @param addProfessionInfo Additional infos in encoded form. + */ + public ProfessionInfo( + NamingAuthority namingAuthority, + DirectoryString[] professionItems, + DerObjectIdentifier[] professionOids, + string registrationNumber, + Asn1OctetString addProfessionInfo) + { + this.namingAuthority = namingAuthority; + this.professionItems = new DerSequence(professionItems); + if (professionOids != null) + { + this.professionOids = new DerSequence(professionOids); + } + this.registrationNumber = registrationNumber; + this.addProfessionInfo = addProfessionInfo; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*               ProfessionInfo ::= SEQUENCE
      +		*               {
      +		*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
      +		*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
      +		*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
      +		*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
      +		*                 addProfessionInfo OCTET STRING OPTIONAL
      +		*               }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + if (namingAuthority != null) + { + vec.Add(new DerTaggedObject(true, 0, namingAuthority)); + } + vec.Add(professionItems); + if (professionOids != null) + { + vec.Add(professionOids); + } + if (registrationNumber != null) + { + vec.Add(new DerPrintableString(registrationNumber, true)); + } + if (addProfessionInfo != null) + { + vec.Add(addProfessionInfo); + } + return new DerSequence(vec); + } + + /** + * @return Returns the addProfessionInfo. + */ + public virtual Asn1OctetString AddProfessionInfo + { + get { return addProfessionInfo; } + } + + /** + * @return Returns the namingAuthority. + */ + public virtual NamingAuthority NamingAuthority + { + get { return namingAuthority; } + } + + /** + * @return Returns the professionItems. + */ + public virtual DirectoryString[] GetProfessionItems() + { + DirectoryString[] result = new DirectoryString[professionItems.Count]; + + for (int i = 0; i < professionItems.Count; ++i) + { + result[i] = DirectoryString.GetInstance(professionItems[i]); + } + + return result; + } + + /** + * @return Returns the professionOids. + */ + public virtual DerObjectIdentifier[] GetProfessionOids() + { + if (professionOids == null) + { + return new DerObjectIdentifier[0]; + } + + DerObjectIdentifier[] result = new DerObjectIdentifier[professionOids.Count]; + + for (int i = 0; i < professionOids.Count; ++i) + { + result[i] = DerObjectIdentifier.GetInstance(professionOids[i]); + } + + return result; + } + + /** + * @return Returns the registrationNumber. + */ + public virtual string RegistrationNumber + { + get { return registrationNumber; } + } + } +} diff --git a/iTechSharp/srcbc/asn1/isismtt/x509/Restriction.cs b/iTechSharp/srcbc/asn1/isismtt/x509/Restriction.cs new file mode 100644 index 0000000..087c4cb --- /dev/null +++ b/iTechSharp/srcbc/asn1/isismtt/x509/Restriction.cs @@ -0,0 +1,85 @@ +using System; + +using Org.BouncyCastle.Asn1.X500; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * Some other restriction regarding the usage of this certificate. + *

      + *

      +	*  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
      +	* 
      + */ + public class Restriction + : Asn1Encodable + { + private readonly DirectoryString restriction; + + public static Restriction GetInstance( + object obj) + { + if (obj == null || obj is Restriction) + { + return (Restriction) obj; + } + + if (obj is IAsn1String) + { + return new Restriction(DirectoryString.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from DirectoryString. + *

      + * The DirectoryString is of type RestrictionSyntax: + *

      + *

      +		*      RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
      +		* 
      + * + * @param restriction A IAsn1String. + */ + private Restriction( + DirectoryString restriction) + { + this.restriction = restriction; + } + + /** + * Constructor from a given details. + * + * @param restriction The description of the restriction. + */ + public Restriction( + string restriction) + { + this.restriction = new DirectoryString(restriction); + } + + public virtual DirectoryString RestrictionString + { + get { return restriction; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*      RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
      +		* 

      + *

      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return restriction.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/kisa/KISAObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/kisa/KISAObjectIdentifiers.cs new file mode 100644 index 0000000..05351ec --- /dev/null +++ b/iTechSharp/srcbc/asn1/kisa/KISAObjectIdentifiers.cs @@ -0,0 +1,8 @@ +namespace Org.BouncyCastle.Asn1.Kisa +{ + public abstract class KisaObjectIdentifiers + { + public static readonly DerObjectIdentifier IdSeedCbc = new DerObjectIdentifier("1.2.410.200004.1.4"); + public static readonly DerObjectIdentifier IdNpkiAppCmsSeedWrap = new DerObjectIdentifier("1.2.410.200004.7.1.1.1"); + } +} diff --git a/iTechSharp/srcbc/asn1/microsoft/MicrosoftObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/microsoft/MicrosoftObjectIdentifiers.cs new file mode 100644 index 0000000..b8aba7e --- /dev/null +++ b/iTechSharp/srcbc/asn1/microsoft/MicrosoftObjectIdentifiers.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Microsoft +{ + public abstract class MicrosoftObjectIdentifiers + { + // + // Microsoft + // iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311) + // + public static readonly DerObjectIdentifier Microsoft = new DerObjectIdentifier("1.3.6.1.4.1.311"); + public static readonly DerObjectIdentifier MicrosoftCertTemplateV1 = new DerObjectIdentifier(Microsoft + ".20.2"); + public static readonly DerObjectIdentifier MicrosoftCAVersion = new DerObjectIdentifier(Microsoft + ".21.1"); + public static readonly DerObjectIdentifier MicrosoftPrevCACertHash = new DerObjectIdentifier(Microsoft + ".21.2"); + public static readonly DerObjectIdentifier MicrosoftCertTemplateV2 = new DerObjectIdentifier(Microsoft + ".21.7"); + public static readonly DerObjectIdentifier MicrosoftAppPolicies = new DerObjectIdentifier(Microsoft + ".21.10"); + } +} diff --git a/iTechSharp/srcbc/asn1/misc/CAST5CBCParameters.cs b/iTechSharp/srcbc/asn1/misc/CAST5CBCParameters.cs new file mode 100644 index 0000000..51fd660 --- /dev/null +++ b/iTechSharp/srcbc/asn1/misc/CAST5CBCParameters.cs @@ -0,0 +1,74 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.Misc +{ + public class Cast5CbcParameters + : Asn1Encodable + { + private readonly DerInteger keyLength; + private readonly Asn1OctetString iv; + + public static Cast5CbcParameters GetInstance( + object o) + { + if (o is Cast5CbcParameters) + { + return (Cast5CbcParameters) o; + } + + if (o is Asn1Sequence) + { + return new Cast5CbcParameters((Asn1Sequence) o); + } + + throw new ArgumentException("unknown object in Cast5CbcParameters factory"); + } + + public Cast5CbcParameters( + byte[] iv, + int keyLength) + { + this.iv = new DerOctetString(iv); + this.keyLength = new DerInteger(keyLength); + } + + private Cast5CbcParameters( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + iv = (Asn1OctetString) seq[0]; + keyLength = (DerInteger) seq[1]; + } + + public byte[] GetIV() + { + return Arrays.Clone(iv.GetOctets()); + } + + public int KeyLength + { + get { return keyLength.Value.IntValue; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * cast5CBCParameters ::= Sequence {
      +         *                           iv         OCTET STRING DEFAULT 0,
      +         *                                  -- Initialization vector
      +         *                           keyLength  Integer
      +         *                                  -- Key length, in bits
      +         *                      }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(iv, keyLength); + } + } +} diff --git a/iTechSharp/srcbc/asn1/misc/IDEACBCPar.cs b/iTechSharp/srcbc/asn1/misc/IDEACBCPar.cs new file mode 100644 index 0000000..72a60b9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/misc/IDEACBCPar.cs @@ -0,0 +1,68 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Misc +{ + public class IdeaCbcPar + : Asn1Encodable + { + internal Asn1OctetString iv; + + public static IdeaCbcPar GetInstance( + object o) + { + if (o is IdeaCbcPar) + { + return (IdeaCbcPar) o; + } + + if (o is Asn1Sequence) + { + return new IdeaCbcPar((Asn1Sequence) o); + } + + throw new ArgumentException("unknown object in IDEACBCPar factory"); + } + + public IdeaCbcPar( + byte[] iv) + { + this.iv = new DerOctetString(iv); + } + + private IdeaCbcPar( + Asn1Sequence seq) + { + if (seq.Count == 1) + { + iv = (Asn1OctetString) seq[0]; + } + } + + public byte[] GetIV() + { + return iv == null ? null : iv.GetOctets(); + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * IDEA-CBCPar ::= Sequence {
      +         *                      iv    OCTET STRING OPTIONAL -- exactly 8 octets
      +         *                  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (iv != null) + { + v.Add(iv); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/misc/MiscObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/misc/MiscObjectIdentifiers.cs new file mode 100644 index 0000000..01004d8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/misc/MiscObjectIdentifiers.cs @@ -0,0 +1,48 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Misc +{ + public abstract class MiscObjectIdentifiers + { + // + // Netscape + // iso/itu(2) joint-assign(16) us(840) uscompany(1) Netscape(113730) cert-extensions(1) } + // + public static readonly DerObjectIdentifier Netscape = new DerObjectIdentifier("2.16.840.1.113730.1"); + public static readonly DerObjectIdentifier NetscapeCertType = new DerObjectIdentifier(Netscape + ".1"); + public static readonly DerObjectIdentifier NetscapeBaseUrl = new DerObjectIdentifier(Netscape + ".2"); + public static readonly DerObjectIdentifier NetscapeRevocationUrl = new DerObjectIdentifier(Netscape + ".3"); + public static readonly DerObjectIdentifier NetscapeCARevocationUrl = new DerObjectIdentifier(Netscape + ".4"); + public static readonly DerObjectIdentifier NetscapeRenewalUrl = new DerObjectIdentifier(Netscape + ".7"); + public static readonly DerObjectIdentifier NetscapeCAPolicyUrl = new DerObjectIdentifier(Netscape + ".8"); + public static readonly DerObjectIdentifier NetscapeSslServerName = new DerObjectIdentifier(Netscape + ".12"); + public static readonly DerObjectIdentifier NetscapeCertComment = new DerObjectIdentifier(Netscape + ".13"); + // + // Verisign + // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) } + // + internal const string Verisign = "2.16.840.1.113733.1"; + + // + // CZAG - country, zip, age, and gender + // + public static readonly DerObjectIdentifier VerisignCzagExtension = new DerObjectIdentifier(Verisign + ".6.3"); + + // D&B D-U-N-S number + public static readonly DerObjectIdentifier VerisignDnbDunsNumber = new DerObjectIdentifier(Verisign + ".6.15"); + + // + // Novell + // iso/itu(2) country(16) us(840) organization(1) novell(113719) + // + public static readonly string Novell = "2.16.840.1.113719"; + public static readonly DerObjectIdentifier NovellSecurityAttribs = new DerObjectIdentifier(Novell + ".1.9.4.1"); + + // + // Entrust + // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7) + // + public static readonly string Entrust = "1.2.840.113533.7"; + public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0"); + } +} diff --git a/iTechSharp/srcbc/asn1/misc/NetscapeCertType.cs b/iTechSharp/srcbc/asn1/misc/NetscapeCertType.cs new file mode 100644 index 0000000..d5db652 --- /dev/null +++ b/iTechSharp/srcbc/asn1/misc/NetscapeCertType.cs @@ -0,0 +1,54 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Misc +{ + /** + * The NetscapeCertType object. + *
      +     *    NetscapeCertType ::= BIT STRING {
      +     *         SSLClient               (0),
      +     *         SSLServer               (1),
      +     *         S/MIME                  (2),
      +     *         Object Signing          (3),
      +     *         Reserved                (4),
      +     *         SSL CA                  (5),
      +     *         S/MIME CA               (6),
      +     *         Object Signing CA       (7) }
      +     * 
      + */ + public class NetscapeCertType + : DerBitString + { + public const int SslClient = (1 << 7); + public const int SslServer = (1 << 6); + public const int Smime = (1 << 5); + public const int ObjectSigning = (1 << 4); + public const int Reserved = (1 << 3); + public const int SslCA = (1 << 2); + public const int SmimeCA = (1 << 1); + public const int ObjectSigningCA = (1 << 0); + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA) + */ + public NetscapeCertType(int usage) + : base(GetBytes(usage), GetPadBits(usage)) + { + } + + public NetscapeCertType(DerBitString usage) + : base(usage.GetBytes(), usage.PadBits) + { + } + + public override string ToString() + { + byte[] data = GetBytes(); + return "NetscapeCertType: 0x" + (data[0] & 0xff).ToString("X"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/misc/NetscapeRevocationURL.cs b/iTechSharp/srcbc/asn1/misc/NetscapeRevocationURL.cs new file mode 100644 index 0000000..6cac031 --- /dev/null +++ b/iTechSharp/srcbc/asn1/misc/NetscapeRevocationURL.cs @@ -0,0 +1,18 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Misc +{ + public class NetscapeRevocationUrl + : DerIA5String + { + public NetscapeRevocationUrl(DerIA5String str) + : base(str.GetString()) + { + } + + public override string ToString() + { + return "NetscapeRevocationUrl: " + this.GetString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/misc/VerisignCzagExtension.cs b/iTechSharp/srcbc/asn1/misc/VerisignCzagExtension.cs new file mode 100644 index 0000000..1c3054b --- /dev/null +++ b/iTechSharp/srcbc/asn1/misc/VerisignCzagExtension.cs @@ -0,0 +1,18 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Misc +{ + public class VerisignCzagExtension + : DerIA5String + { + public VerisignCzagExtension(DerIA5String str) + : base(str.GetString()) + { + } + + public override string ToString() + { + return "VerisignCzagExtension: " + this.GetString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/mozilla/PublicKeyAndChallenge.cs b/iTechSharp/srcbc/asn1/mozilla/PublicKeyAndChallenge.cs new file mode 100644 index 0000000..1e08b80 --- /dev/null +++ b/iTechSharp/srcbc/asn1/mozilla/PublicKeyAndChallenge.cs @@ -0,0 +1,67 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Mozilla +{ + /** + * This is designed to parse + * the PublicKeyAndChallenge created by the KEYGEN tag included by + * Mozilla based browsers. + *
      +	 *  PublicKeyAndChallenge ::= SEQUENCE {
      +	 *    spki SubjectPublicKeyInfo,
      +	 *    challenge IA5STRING
      +	 *  }
      +	 *
      +	 *  
      + */ + public class PublicKeyAndChallenge + : Asn1Encodable + { + private Asn1Sequence pkacSeq; + private SubjectPublicKeyInfo spki; + private DerIA5String challenge; + + public static PublicKeyAndChallenge GetInstance( + object obj) + { + if (obj is PublicKeyAndChallenge) + { + return (PublicKeyAndChallenge) obj; + } + + if (obj is Asn1Sequence) + { + return new PublicKeyAndChallenge((Asn1Sequence) obj); + } + + throw new ArgumentException( + "unknown object in 'PublicKeyAndChallenge' factory : " + + obj.GetType().Name + "."); + } + + public PublicKeyAndChallenge( + Asn1Sequence seq) + { + pkacSeq = seq; + spki = SubjectPublicKeyInfo.GetInstance(seq[0]); + challenge = DerIA5String.GetInstance(seq[1]); + } + + public override Asn1Object ToAsn1Object() + { + return pkacSeq; + } + + public SubjectPublicKeyInfo SubjectPublicKeyInfo + { + get { return spki; } + } + + public DerIA5String Challenge + { + get { return challenge; } + } + } +} diff --git a/iTechSharp/srcbc/asn1/nist/NISTNamedCurves.cs b/iTechSharp/srcbc/asn1/nist/NISTNamedCurves.cs new file mode 100644 index 0000000..52cde89 --- /dev/null +++ b/iTechSharp/srcbc/asn1/nist/NISTNamedCurves.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.Nist +{ + /** + * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2 + */ + public sealed class NistNamedCurves + { + private NistNamedCurves() + { + } + + private static readonly Hashtable objIds = new Hashtable(); + private static readonly Hashtable names = new Hashtable(); + + private static void DefineCurve( + string name, + DerObjectIdentifier oid) + { + objIds.Add(name, oid); + names.Add(oid, name); + } + + static NistNamedCurves() + { + DefineCurve("B-571", SecObjectIdentifiers.SecT571r1); + DefineCurve("B-409", SecObjectIdentifiers.SecT409r1); + DefineCurve("B-283", SecObjectIdentifiers.SecT283r1); + DefineCurve("B-233", SecObjectIdentifiers.SecT233r1); + DefineCurve("B-163", SecObjectIdentifiers.SecT163r2); + DefineCurve("P-521", SecObjectIdentifiers.SecP521r1); + DefineCurve("P-256", SecObjectIdentifiers.SecP256r1); + DefineCurve("P-224", SecObjectIdentifiers.SecP224r1); + DefineCurve("P-384", SecObjectIdentifiers.SecP384r1); + } + + public static X9ECParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToUpper(CultureInfo.InvariantCulture)]; + + if (oid != null) + { + return GetByOid(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters GetByOid( + DerObjectIdentifier oid) + { + return SecNamedCurves.GetByOid(oid); + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier) objIds[name.ToUpper(CultureInfo.InvariantCulture)]; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string) names[oid]; + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + } +} diff --git a/iTechSharp/srcbc/asn1/nist/NISTObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/nist/NISTObjectIdentifiers.cs new file mode 100644 index 0000000..619b6fb --- /dev/null +++ b/iTechSharp/srcbc/asn1/nist/NISTObjectIdentifiers.cs @@ -0,0 +1,55 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Nist +{ + public sealed class NistObjectIdentifiers + { + private NistObjectIdentifiers() + { + } + + // + // NIST + // iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) + + // + // nistalgorithms(4) + // + public static readonly DerObjectIdentifier NistAlgorithm = new DerObjectIdentifier("2.16.840.1.101.3.4"); + + public static readonly DerObjectIdentifier IdSha256 = new DerObjectIdentifier(NistAlgorithm + ".2.1"); + public static readonly DerObjectIdentifier IdSha384 = new DerObjectIdentifier(NistAlgorithm + ".2.2"); + public static readonly DerObjectIdentifier IdSha512 = new DerObjectIdentifier(NistAlgorithm + ".2.3"); + public static readonly DerObjectIdentifier IdSha224 = new DerObjectIdentifier(NistAlgorithm + ".2.4"); + + public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1"); + + public static readonly DerObjectIdentifier IdAes128Ecb = new DerObjectIdentifier(Aes + ".1"); + public static readonly DerObjectIdentifier IdAes128Cbc = new DerObjectIdentifier(Aes + ".2"); + public static readonly DerObjectIdentifier IdAes128Ofb = new DerObjectIdentifier(Aes + ".3"); + public static readonly DerObjectIdentifier IdAes128Cfb = new DerObjectIdentifier(Aes + ".4"); + public static readonly DerObjectIdentifier IdAes128Wrap = new DerObjectIdentifier(Aes + ".5"); + + public static readonly DerObjectIdentifier IdAes192Ecb = new DerObjectIdentifier(Aes + ".21"); + public static readonly DerObjectIdentifier IdAes192Cbc = new DerObjectIdentifier(Aes + ".22"); + public static readonly DerObjectIdentifier IdAes192Ofb = new DerObjectIdentifier(Aes + ".23"); + public static readonly DerObjectIdentifier IdAes192Cfb = new DerObjectIdentifier(Aes + ".24"); + public static readonly DerObjectIdentifier IdAes192Wrap = new DerObjectIdentifier(Aes + ".25"); + + public static readonly DerObjectIdentifier IdAes256Ecb = new DerObjectIdentifier(Aes + ".41"); + public static readonly DerObjectIdentifier IdAes256Cbc = new DerObjectIdentifier(Aes + ".42"); + public static readonly DerObjectIdentifier IdAes256Ofb = new DerObjectIdentifier(Aes + ".43"); + public static readonly DerObjectIdentifier IdAes256Cfb = new DerObjectIdentifier(Aes + ".44"); + public static readonly DerObjectIdentifier IdAes256Wrap = new DerObjectIdentifier(Aes + ".45"); + + // + // signatures + // + public static readonly DerObjectIdentifier IdDsaWithSha2 = new DerObjectIdentifier(NistAlgorithm + ".3"); + + public static readonly DerObjectIdentifier DsaWithSha224 = new DerObjectIdentifier(IdDsaWithSha2 + ".1"); + public static readonly DerObjectIdentifier DsaWithSha256 = new DerObjectIdentifier(IdDsaWithSha2 + ".2"); + public static readonly DerObjectIdentifier DsaWithSha384 = new DerObjectIdentifier(IdDsaWithSha2 + ".3"); + public static readonly DerObjectIdentifier DsaWithSha512 = new DerObjectIdentifier(IdDsaWithSha2 + ".4"); + } +} diff --git a/iTechSharp/srcbc/asn1/ntt/NTTObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/ntt/NTTObjectIdentifiers.cs new file mode 100644 index 0000000..cd25956 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ntt/NTTObjectIdentifiers.cs @@ -0,0 +1,14 @@ +namespace Org.BouncyCastle.Asn1.Ntt +{ + /// From RFC 3657 + public abstract class NttObjectIdentifiers + { + public static readonly DerObjectIdentifier IdCamellia128Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.2"); + public static readonly DerObjectIdentifier IdCamellia192Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.3"); + public static readonly DerObjectIdentifier IdCamellia256Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.4"); + + public static readonly DerObjectIdentifier IdCamellia128Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.2"); + public static readonly DerObjectIdentifier IdCamellia192Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.3"); + public static readonly DerObjectIdentifier IdCamellia256Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.4"); + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/BasicOCSPResponse.cs b/iTechSharp/srcbc/asn1/ocsp/BasicOCSPResponse.cs new file mode 100644 index 0000000..dd666ad --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/BasicOCSPResponse.cs @@ -0,0 +1,131 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class BasicOcspResponse + : Asn1Encodable + { + private readonly ResponseData tbsResponseData; + private readonly AlgorithmIdentifier signatureAlgorithm; + private readonly DerBitString signature; + private readonly Asn1Sequence certs; + + public static BasicOcspResponse GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static BasicOcspResponse GetInstance( + object obj) + { + if (obj == null || obj is BasicOcspResponse) + { + return (BasicOcspResponse)obj; + } + + if (obj is Asn1Sequence) + { + return new BasicOcspResponse((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public BasicOcspResponse( + ResponseData tbsResponseData, + AlgorithmIdentifier signatureAlgorithm, + DerBitString signature, + Asn1Sequence certs) + { + this.tbsResponseData = tbsResponseData; + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private BasicOcspResponse( + Asn1Sequence seq) + { + this.tbsResponseData = ResponseData.GetInstance(seq[0]); + this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]); + this.signature = (DerBitString)seq[2]; + + if (seq.Count > 3) + { + this.certs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[3], true); + } + } + + [Obsolete("Use TbsResponseData property instead")] + public ResponseData GetTbsResponseData() + { + return tbsResponseData; + } + + public ResponseData TbsResponseData + { + get { return tbsResponseData; } + } + + [Obsolete("Use SignatureAlgorithm property instead")] + public AlgorithmIdentifier GetSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public AlgorithmIdentifier SignatureAlgorithm + { + get { return signatureAlgorithm; } + } + + [Obsolete("Use Signature property instead")] + public DerBitString GetSignature() + { + return signature; + } + + public DerBitString Signature + { + get { return signature; } + } + + [Obsolete("Use Certs property instead")] + public Asn1Sequence GetCerts() + { + return certs; + } + + public Asn1Sequence Certs + { + get { return certs; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * BasicOcspResponse       ::= Sequence {
      +         *      tbsResponseData      ResponseData,
      +         *      signatureAlgorithm   AlgorithmIdentifier,
      +         *      signature            BIT STRING,
      +         *      certs                [0] EXPLICIT Sequence OF Certificate OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + tbsResponseData, signatureAlgorithm, signature); + + if (certs != null) + { + v.Add(new DerTaggedObject(true, 0, certs)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/CertID.cs b/iTechSharp/srcbc/asn1/ocsp/CertID.cs new file mode 100644 index 0000000..4b25109 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/CertID.cs @@ -0,0 +1,98 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class CertID + : Asn1Encodable + { + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly Asn1OctetString issuerNameHash; + private readonly Asn1OctetString issuerKeyHash; + private readonly DerInteger serialNumber; + + public static CertID GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static CertID GetInstance( + object obj) + { + if (obj == null || obj is CertID) + { + return (CertID)obj; + } + + if (obj is Asn1Sequence) + { + return new CertID((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public CertID( + AlgorithmIdentifier hashAlgorithm, + Asn1OctetString issuerNameHash, + Asn1OctetString issuerKeyHash, + DerInteger serialNumber) + { + this.hashAlgorithm = hashAlgorithm; + this.issuerNameHash = issuerNameHash; + this.issuerKeyHash = issuerKeyHash; + this.serialNumber = serialNumber; + } + + private CertID( + Asn1Sequence seq) + { + if (seq.Count != 4) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]); + this.issuerNameHash = Asn1OctetString.GetInstance(seq[1]); + this.issuerKeyHash = Asn1OctetString.GetInstance(seq[2]); + this.serialNumber = DerInteger.GetInstance(seq[3]); + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public Asn1OctetString IssuerNameHash + { + get { return issuerNameHash; } + } + + public Asn1OctetString IssuerKeyHash + { + get { return issuerKeyHash; } + } + + public DerInteger SerialNumber + { + get { return serialNumber; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * CertID          ::=     Sequence {
      +         *     hashAlgorithm       AlgorithmIdentifier,
      +         *     issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
      +         *     issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
      +         *     serialNumber        CertificateSerialNumber }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(hashAlgorithm, issuerNameHash, issuerKeyHash, serialNumber); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/CertStatus.cs b/iTechSharp/srcbc/asn1/ocsp/CertStatus.cs new file mode 100644 index 0000000..d922572 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/CertStatus.cs @@ -0,0 +1,94 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class CertStatus + : Asn1Encodable + { + private readonly int tagNo; + private readonly Asn1Encodable value; + + /** + * create a CertStatus object with a tag of zero. + */ + public CertStatus() + { + tagNo = 0; + value = DerNull.Instance; + } + + public CertStatus( + RevokedInfo info) + { + tagNo = 1; + value = info; + } + + public CertStatus( + int tagNo, + Asn1Encodable value) + { + this.tagNo = tagNo; + this.value = value; + } + + public CertStatus( + Asn1TaggedObject choice) + { + this.tagNo = choice.TagNo; + + switch (choice.TagNo) + { + case 1: + value = RevokedInfo.GetInstance(choice, false); + break; + case 0: + case 2: + value = DerNull.Instance; + break; + } + } + + public static CertStatus GetInstance( + object obj) + { + if (obj == null || obj is CertStatus) + { + return (CertStatus)obj; + } + + if (obj is Asn1TaggedObject) + { + return new CertStatus((Asn1TaggedObject)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public int TagNo + { + get { return tagNo; } + } + + public Asn1Encodable Status + { + get { return value; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  CertStatus ::= CHOICE {
      +         *                  good        [0]     IMPLICIT Null,
      +         *                  revoked     [1]     IMPLICIT RevokedInfo,
      +         *                  unknown     [2]     IMPLICIT UnknownInfo }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerTaggedObject(false, tagNo, value); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/CrlID.cs b/iTechSharp/srcbc/asn1/ocsp/CrlID.cs new file mode 100644 index 0000000..cfb3d6f --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/CrlID.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class CrlID + : Asn1Encodable + { + private readonly DerIA5String crlUrl; + private readonly DerInteger crlNum; + private readonly DerGeneralizedTime crlTime; + + // TODO Add GetInstance method(s) and amke this private? + public CrlID( + Asn1Sequence seq) + { + foreach (Asn1TaggedObject o in seq) + { + switch (o.TagNo) + { + case 0: + crlUrl = DerIA5String.GetInstance(o, true); + break; + case 1: + crlNum = DerInteger.GetInstance(o, true); + break; + case 2: + crlTime = DerGeneralizedTime.GetInstance(o, true); + break; + default: + throw new ArgumentException("unknown tag number: " + o.TagNo); + } + } + } + + public DerIA5String CrlUrl + { + get { return crlUrl; } + } + + public DerInteger CrlNum + { + get { return crlNum; } + } + + public DerGeneralizedTime CrlTime + { + get { return crlTime; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * CrlID ::= Sequence {
      +         *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
      +         *     crlNum               [1]     EXPLICIT Integer OPTIONAL,
      +         *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (crlUrl != null) + { + v.Add(new DerTaggedObject(true, 0, crlUrl)); + } + + if (crlNum != null) + { + v.Add(new DerTaggedObject(true, 1, crlNum)); + } + + if (crlTime != null) + { + v.Add(new DerTaggedObject(true, 2, crlTime)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/OCSPObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/ocsp/OCSPObjectIdentifiers.cs new file mode 100644 index 0000000..a37c855 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/OCSPObjectIdentifiers.cs @@ -0,0 +1,23 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public abstract class OcspObjectIdentifiers + { + internal const string PkixOcspId = "1.3.6.1.5.5.7.48.1"; + + public static readonly DerObjectIdentifier PkixOcsp = new DerObjectIdentifier(PkixOcspId); + public static readonly DerObjectIdentifier PkixOcspBasic = new DerObjectIdentifier(PkixOcspId + ".1"); + + // + // extensions + // + public static readonly DerObjectIdentifier PkixOcspNonce = new DerObjectIdentifier(PkixOcsp + ".2"); + public static readonly DerObjectIdentifier PkixOcspCrl = new DerObjectIdentifier(PkixOcsp + ".3"); + + public static readonly DerObjectIdentifier PkixOcspResponse = new DerObjectIdentifier(PkixOcsp + ".4"); + public static readonly DerObjectIdentifier PkixOcspNocheck = new DerObjectIdentifier(PkixOcsp + ".5"); + public static readonly DerObjectIdentifier PkixOcspArchiveCutoff = new DerObjectIdentifier(PkixOcsp + ".6"); + public static readonly DerObjectIdentifier PkixOcspServiceLocator = new DerObjectIdentifier(PkixOcsp + ".7"); + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/OCSPRequest.cs b/iTechSharp/srcbc/asn1/ocsp/OCSPRequest.cs new file mode 100644 index 0000000..1e804d7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/OCSPRequest.cs @@ -0,0 +1,89 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class OcspRequest + : Asn1Encodable + { + private readonly TbsRequest tbsRequest; + private readonly Signature optionalSignature; + + public static OcspRequest GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static OcspRequest GetInstance( + object obj) + { + if (obj == null || obj is OcspRequest) + { + return (OcspRequest)obj; + } + + if (obj is Asn1Sequence) + { + return new OcspRequest((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public OcspRequest( + TbsRequest tbsRequest, + Signature optionalSignature) + { + if (tbsRequest == null) + throw new ArgumentNullException("tbsRequest"); + + this.tbsRequest = tbsRequest; + this.optionalSignature = optionalSignature; + } + + private OcspRequest( + Asn1Sequence seq) + { + tbsRequest = TbsRequest.GetInstance(seq[0]); + + if (seq.Count == 2) + { + optionalSignature = Signature.GetInstance( + (Asn1TaggedObject)seq[1], true); + } + } + + public TbsRequest TbsRequest + { + get { return tbsRequest; } + } + + public Signature OptionalSignature + { + get { return optionalSignature; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OcspRequest     ::=     Sequence {
      +         *     tbsRequest                  TBSRequest,
      +         *     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(tbsRequest); + + if (optionalSignature != null) + { + v.Add(new DerTaggedObject(true, 0, optionalSignature)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/OCSPResponse.cs b/iTechSharp/srcbc/asn1/ocsp/OCSPResponse.cs new file mode 100644 index 0000000..e9aad81 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/OCSPResponse.cs @@ -0,0 +1,90 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class OcspResponse + : Asn1Encodable + { + private readonly OcspResponseStatus responseStatus; + private readonly ResponseBytes responseBytes; + + public static OcspResponse GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static OcspResponse GetInstance( + object obj) + { + if (obj == null || obj is OcspResponse) + { + return (OcspResponse)obj; + } + + if (obj is Asn1Sequence) + { + return new OcspResponse((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public OcspResponse( + OcspResponseStatus responseStatus, + ResponseBytes responseBytes) + { + if (responseStatus == null) + throw new ArgumentNullException("responseStatus"); + + this.responseStatus = responseStatus; + this.responseBytes = responseBytes; + } + + private OcspResponse( + Asn1Sequence seq) + { + responseStatus = new OcspResponseStatus( + DerEnumerated.GetInstance(seq[0])); + + if (seq.Count == 2) + { + responseBytes = ResponseBytes.GetInstance( + (Asn1TaggedObject)seq[1], true); + } + } + + public OcspResponseStatus ResponseStatus + { + get { return responseStatus; } + } + + public ResponseBytes ResponseBytes + { + get { return responseBytes; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * OcspResponse ::= Sequence {
      +         *     responseStatus         OcspResponseStatus,
      +         *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(responseStatus); + + if (responseBytes != null) + { + v.Add(new DerTaggedObject(true, 0, responseBytes)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/OCSPResponseStatus.cs b/iTechSharp/srcbc/asn1/ocsp/OCSPResponseStatus.cs new file mode 100644 index 0000000..653317e --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/OCSPResponseStatus.cs @@ -0,0 +1,41 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class OcspResponseStatus + : DerEnumerated + { + public const int Successful = 0; + public const int MalformedRequest = 1; + public const int InternalError = 2; + public const int TryLater = 3; + public const int SignatureRequired = 5; + public const int Unauthorized = 6; + + /** + * The OcspResponseStatus enumeration. + *
      +         * OcspResponseStatus ::= Enumerated {
      +         *     successful            (0),  --Response has valid confirmations
      +         *     malformedRequest      (1),  --Illegal confirmation request
      +         *     internalError         (2),  --Internal error in issuer
      +         *     tryLater              (3),  --Try again later
      +         *                                 --(4) is not used
      +         *     sigRequired           (5),  --Must sign the request
      +         *     unauthorized          (6)   --Request unauthorized
      +         * }
      +         * 
      + */ + public OcspResponseStatus(int value) + : base(value) + { + } + + public OcspResponseStatus(DerEnumerated value) + : base(value.Value.IntValue) + { + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/Request.cs b/iTechSharp/srcbc/asn1/ocsp/Request.cs new file mode 100644 index 0000000..116c15e --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/Request.cs @@ -0,0 +1,90 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class Request + : Asn1Encodable + { + private readonly CertID reqCert; + private readonly X509Extensions singleRequestExtensions; + + public static Request GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static Request GetInstance( + object obj) + { + if (obj == null || obj is Request) + { + return (Request)obj; + } + + if (obj is Asn1Sequence) + { + return new Request((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public Request( + CertID reqCert, + X509Extensions singleRequestExtensions) + { + if (reqCert == null) + throw new ArgumentNullException("reqCert"); + + this.reqCert = reqCert; + this.singleRequestExtensions = singleRequestExtensions; + } + + private Request( + Asn1Sequence seq) + { + reqCert = CertID.GetInstance(seq[0]); + + if (seq.Count == 2) + { + singleRequestExtensions = X509Extensions.GetInstance( + (Asn1TaggedObject)seq[1], true); + } + } + + public CertID ReqCert + { + get { return reqCert; } + } + + public X509Extensions SingleRequestExtensions + { + get { return singleRequestExtensions; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Request         ::=     Sequence {
      +         *     reqCert                     CertID,
      +         *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(reqCert); + + if (singleRequestExtensions != null) + { + v.Add(new DerTaggedObject(true, 0, singleRequestExtensions)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/ResponderID.cs b/iTechSharp/srcbc/asn1/ocsp/ResponderID.cs new file mode 100644 index 0000000..1ee0058 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/ResponderID.cs @@ -0,0 +1,77 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class ResponderID + : Asn1Encodable + { + private readonly Asn1Encodable id; + + public static ResponderID GetInstance( + object obj) + { + if (obj == null || obj is ResponderID) + { + return (ResponderID)obj; + } + + if (obj is DerOctetString) + { + return new ResponderID((DerOctetString)obj); + } + + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject)obj; + + if (o.TagNo == 1) + { + return new ResponderID(X509Name.GetInstance(o, true)); + } + + return new ResponderID(Asn1OctetString.GetInstance(o, true)); + } + + return new ResponderID(X509Name.GetInstance(obj)); + } + + public ResponderID( + Asn1OctetString id) + { + if (id == null) + throw new ArgumentNullException("id"); + + this.id = id; + } + + public ResponderID( + X509Name id) + { + if (id == null) + throw new ArgumentNullException("id"); + + this.id = id; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * ResponderID ::= CHOICE {
      +         *      byName          [1] Name,
      +         *      byKey           [2] KeyHash }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + if (id is Asn1OctetString) + { + return new DerTaggedObject(true, 2, id); + } + + return new DerTaggedObject(true, 1, id); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/ResponseBytes.cs b/iTechSharp/srcbc/asn1/ocsp/ResponseBytes.cs new file mode 100644 index 0000000..2ce59fa --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/ResponseBytes.cs @@ -0,0 +1,82 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class ResponseBytes + : Asn1Encodable + { + private readonly DerObjectIdentifier responseType; + private readonly Asn1OctetString response; + + public static ResponseBytes GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static ResponseBytes GetInstance( + object obj) + { + if (obj == null || obj is ResponseBytes) + { + return (ResponseBytes)obj; + } + + if (obj is Asn1Sequence) + { + return new ResponseBytes((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public ResponseBytes( + DerObjectIdentifier responseType, + Asn1OctetString response) + { + if (responseType == null) + throw new ArgumentNullException("responseType"); + if (response == null) + throw new ArgumentNullException("response"); + + this.responseType = responseType; + this.response = response; + } + + private ResponseBytes( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.responseType = DerObjectIdentifier.GetInstance(seq[0]); + this.response = Asn1OctetString.GetInstance(seq[1]); + } + + public DerObjectIdentifier ResponseType + { + get { return responseType; } + } + + public Asn1OctetString Response + { + get { return response; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * ResponseBytes ::=       Sequence {
      +         *     responseType   OBJECT IDENTIFIER,
      +         *     response       OCTET STRING }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(responseType, response); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/ResponseData.cs b/iTechSharp/srcbc/asn1/ocsp/ResponseData.cs new file mode 100644 index 0000000..173829d --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/ResponseData.cs @@ -0,0 +1,158 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class ResponseData + : Asn1Encodable + { + private static readonly DerInteger V1 = new DerInteger(0); + + private readonly bool versionPresent; + private readonly DerInteger version; + private readonly ResponderID responderID; + private readonly DerGeneralizedTime producedAt; + private readonly Asn1Sequence responses; + private readonly X509Extensions responseExtensions; + + public static ResponseData GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static ResponseData GetInstance( + object obj) + { + if (obj == null || obj is ResponseData) + { + return (ResponseData)obj; + } + + if (obj is Asn1Sequence) + { + return new ResponseData((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public ResponseData( + DerInteger version, + ResponderID responderID, + DerGeneralizedTime producedAt, + Asn1Sequence responses, + X509Extensions responseExtensions) + { + this.version = version; + this.responderID = responderID; + this.producedAt = producedAt; + this.responses = responses; + this.responseExtensions = responseExtensions; + } + + public ResponseData( + ResponderID responderID, + DerGeneralizedTime producedAt, + Asn1Sequence responses, + X509Extensions responseExtensions) + : this(V1, responderID, producedAt, responses, responseExtensions) + { + } + + private ResponseData( + Asn1Sequence seq) + { + int index = 0; + + Asn1Encodable enc = seq[0]; + if (enc is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject)enc; + + if (o.TagNo == 0) + { + this.versionPresent = true; + this.version = DerInteger.GetInstance(o, true); + index++; + } + else + { + this.version = V1; + } + } + else + { + this.version = V1; + } + + this.responderID = ResponderID.GetInstance(seq[index++]); + this.producedAt = (DerGeneralizedTime)seq[index++]; + this.responses = (Asn1Sequence)seq[index++]; + + if (seq.Count > index) + { + this.responseExtensions = X509Extensions.GetInstance( + (Asn1TaggedObject)seq[index], true); + } + } + + public DerInteger Version + { + get { return version; } + } + + public ResponderID ResponderID + { + get { return responderID; } + } + + public DerGeneralizedTime ProducedAt + { + get { return producedAt; } + } + + public Asn1Sequence Responses + { + get { return responses; } + } + + public X509Extensions ResponseExtensions + { + get { return responseExtensions; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * ResponseData ::= Sequence {
      +         *     version              [0] EXPLICIT Version DEFAULT v1,
      +         *     responderID              ResponderID,
      +         *     producedAt               GeneralizedTime,
      +         *     responses                Sequence OF SingleResponse,
      +         *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (versionPresent || !version.Equals(V1)) + { + v.Add(new DerTaggedObject(true, 0, version)); + } + + v.Add(responderID, producedAt, responses); + + if (responseExtensions != null) + { + v.Add(new DerTaggedObject(true, 1, responseExtensions)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/RevokedInfo.cs b/iTechSharp/srcbc/asn1/ocsp/RevokedInfo.cs new file mode 100644 index 0000000..7d9d590 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/RevokedInfo.cs @@ -0,0 +1,96 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class RevokedInfo + : Asn1Encodable + { + private readonly DerGeneralizedTime revocationTime; + private readonly CrlReason revocationReason; + + public static RevokedInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static RevokedInfo GetInstance( + object obj) + { + if (obj == null || obj is RevokedInfo) + { + return (RevokedInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new RevokedInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public RevokedInfo( + DerGeneralizedTime revocationTime) + : this(revocationTime, null) + { + } + + public RevokedInfo( + DerGeneralizedTime revocationTime, + CrlReason revocationReason) + { + if (revocationTime == null) + throw new ArgumentNullException("revocationTime"); + + this.revocationTime = revocationTime; + this.revocationReason = revocationReason; + } + + private RevokedInfo( + Asn1Sequence seq) + { + this.revocationTime = (DerGeneralizedTime) seq[0]; + + if (seq.Count > 1) + { + this.revocationReason = new CrlReason( + DerEnumerated.GetInstance((Asn1TaggedObject) seq[1], true)); + } + } + + public DerGeneralizedTime RevocationTime + { + get { return revocationTime; } + } + + public CrlReason RevocationReason + { + get { return revocationReason; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * RevokedInfo ::= Sequence {
      +         *      revocationTime              GeneralizedTime,
      +         *      revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(revocationTime); + + if (revocationReason != null) + { + v.Add(new DerTaggedObject(true, 0, revocationReason)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/ServiceLocator.cs b/iTechSharp/srcbc/asn1/ocsp/ServiceLocator.cs new file mode 100644 index 0000000..56bc49d --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/ServiceLocator.cs @@ -0,0 +1,95 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class ServiceLocator + : Asn1Encodable + { + private readonly X509Name issuer; + private readonly Asn1Object locator; + + public static ServiceLocator GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static ServiceLocator GetInstance( + object obj) + { + if (obj == null || obj is ServiceLocator) + { + return (ServiceLocator) obj; + } + + if (obj is Asn1Sequence) + { + return new ServiceLocator((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public ServiceLocator( + X509Name issuer) + : this(issuer, null) + { + } + + public ServiceLocator( + X509Name issuer, + Asn1Object locator) + { + if (issuer == null) + throw new ArgumentNullException("issuer"); + + this.issuer = issuer; + this.locator = locator; + } + + private ServiceLocator( + Asn1Sequence seq) + { + this.issuer = X509Name.GetInstance(seq[0]); + + if (seq.Count > 1) + { + this.locator = seq[1].ToAsn1Object(); + } + } + + public X509Name Issuer + { + get { return issuer; } + } + + public Asn1Object Locator + { + get { return locator; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * ServiceLocator ::= Sequence {
      +         *     issuer    Name,
      +         *     locator   AuthorityInfoAccessSyntax OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(issuer); + + if (locator != null) + { + v.Add(locator); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/Signature.cs b/iTechSharp/srcbc/asn1/ocsp/Signature.cs new file mode 100644 index 0000000..a07e7a7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/Signature.cs @@ -0,0 +1,110 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class Signature + : Asn1Encodable + { + internal AlgorithmIdentifier signatureAlgorithm; + internal DerBitString signatureValue; + internal Asn1Sequence certs; + + public static Signature GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static Signature GetInstance( + object obj) + { + if (obj == null || obj is Signature) + { + return (Signature)obj; + } + + if (obj is Asn1Sequence) + { + return new Signature((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DerBitString signatureValue) + : this(signatureAlgorithm, signatureValue, null) + { + } + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DerBitString signatureValue, + Asn1Sequence certs) + { + if (signatureAlgorithm == null) + throw new ArgumentException("signatureAlgorithm"); + if (signatureValue == null) + throw new ArgumentException("signatureValue"); + + this.signatureAlgorithm = signatureAlgorithm; + this.signatureValue = signatureValue; + this.certs = certs; + } + + private Signature( + Asn1Sequence seq) + { + signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]); + signatureValue = (DerBitString)seq[1]; + + if (seq.Count == 3) + { + certs = Asn1Sequence.GetInstance( + (Asn1TaggedObject)seq[2], true); + } + } + + public AlgorithmIdentifier SignatureAlgorithm + { + get { return signatureAlgorithm; } + } + + public DerBitString SignatureValue + { + get { return signatureValue; } + } + + public Asn1Sequence Certs + { + get { return certs; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Signature       ::=     Sequence {
      +         *     signatureAlgorithm      AlgorithmIdentifier,
      +         *     signature               BIT STRING,
      +         *     certs               [0] EXPLICIT Sequence OF Certificate OPTIONAL}
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + signatureAlgorithm, signatureValue); + + if (certs != null) + { + v.Add(new DerTaggedObject(true, 0, certs)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/SingleResponse.cs b/iTechSharp/srcbc/asn1/ocsp/SingleResponse.cs new file mode 100644 index 0000000..93d4c21 --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/SingleResponse.cs @@ -0,0 +1,137 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +using System; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class SingleResponse + : Asn1Encodable + { + private readonly CertID certID; + private readonly CertStatus certStatus; + private readonly DerGeneralizedTime thisUpdate; + private readonly DerGeneralizedTime nextUpdate; + private readonly X509Extensions singleExtensions; + + public SingleResponse( + CertID certID, + CertStatus certStatus, + DerGeneralizedTime thisUpdate, + DerGeneralizedTime nextUpdate, + X509Extensions singleExtensions) + { + this.certID = certID; + this.certStatus = certStatus; + this.thisUpdate = thisUpdate; + this.nextUpdate = nextUpdate; + this.singleExtensions = singleExtensions; + } + + public SingleResponse( + Asn1Sequence seq) + { + this.certID = CertID.GetInstance(seq[0]); + this.certStatus = CertStatus.GetInstance(seq[1]); + this.thisUpdate = (DerGeneralizedTime)seq[2]; + + if (seq.Count > 4) + { + this.nextUpdate = DerGeneralizedTime.GetInstance( + (Asn1TaggedObject) seq[3], true); + this.singleExtensions = X509Extensions.GetInstance( + (Asn1TaggedObject) seq[4], true); + } + else if (seq.Count > 3) + { + Asn1TaggedObject o = (Asn1TaggedObject) seq[3]; + + if (o.TagNo == 0) + { + this.nextUpdate = DerGeneralizedTime.GetInstance(o, true); + } + else + { + this.singleExtensions = X509Extensions.GetInstance(o, true); + } + } + } + + public static SingleResponse GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static SingleResponse GetInstance( + object obj) + { + if (obj == null || obj is SingleResponse) + { + return (SingleResponse)obj; + } + + if (obj is Asn1Sequence) + { + return new SingleResponse((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public CertID CertId + { + get { return certID; } + } + + public CertStatus CertStatus + { + get { return certStatus; } + } + + public DerGeneralizedTime ThisUpdate + { + get { return thisUpdate; } + } + + public DerGeneralizedTime NextUpdate + { + get { return nextUpdate; } + } + + public X509Extensions SingleExtensions + { + get { return singleExtensions; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  SingleResponse ::= Sequence {
      +         *          certID                       CertID,
      +         *          certStatus                   CertStatus,
      +         *          thisUpdate                   GeneralizedTime,
      +         *          nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
      +         *          singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + certID, certStatus, thisUpdate); + + if (nextUpdate != null) + { + v.Add(new DerTaggedObject(true, 0, nextUpdate)); + } + + if (singleExtensions != null) + { + v.Add(new DerTaggedObject(true, 1, singleExtensions)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/ocsp/TBSRequest.cs b/iTechSharp/srcbc/asn1/ocsp/TBSRequest.cs new file mode 100644 index 0000000..d9780eb --- /dev/null +++ b/iTechSharp/srcbc/asn1/ocsp/TBSRequest.cs @@ -0,0 +1,147 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +using System; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class TbsRequest + : Asn1Encodable + { + private static readonly DerInteger V1 = new DerInteger(0); + + private readonly DerInteger version; + private readonly GeneralName requestorName; + private readonly Asn1Sequence requestList; + private readonly X509Extensions requestExtensions; + + public static TbsRequest GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static TbsRequest GetInstance( + object obj) + { + if (obj == null || obj is TbsRequest) + { + return (TbsRequest)obj; + } + + if (obj is Asn1Sequence) + { + return new TbsRequest((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public TbsRequest( + GeneralName requestorName, + Asn1Sequence requestList, + X509Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = requestExtensions; + } + + private TbsRequest( + Asn1Sequence seq) + { + int index = 0; + + Asn1Encodable enc = seq[0]; + if (enc is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject) enc; + + if (o.TagNo == 0) + { + version = DerInteger.GetInstance(o, true); + index++; + } + else + { + version = V1; + } + } + else + { + version = V1; + } + + if (seq[index] is Asn1TaggedObject) + { + requestorName = GeneralName.GetInstance((Asn1TaggedObject) seq[index++], true); + } + + requestList = (Asn1Sequence) seq[index++]; + + if (seq.Count == (index + 1)) + { + requestExtensions = X509Extensions.GetInstance((Asn1TaggedObject) seq[index], true); + } + } + + public DerInteger Version + { + get { return version; } + } + + public GeneralName RequestorName + { + get { return requestorName; } + } + + public Asn1Sequence RequestList + { + get { return requestList; } + } + + public X509Extensions RequestExtensions + { + get { return requestExtensions; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * TBSRequest      ::=     Sequence {
      +         *     version             [0]     EXPLICIT Version DEFAULT v1,
      +         *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
      +         *     requestList                 Sequence OF Request,
      +         *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + // + // if default don't include. + // + if (!version.Equals(V1)) + { + v.Add(new DerTaggedObject(true, 0, version)); + } + + if (requestorName != null) + { + v.Add(new DerTaggedObject(true, 1, requestorName)); + } + + v.Add(requestList); + + if (requestExtensions != null) + { + v.Add(new DerTaggedObject(true, 2, requestExtensions)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/oiw/ElGamalParameter.cs b/iTechSharp/srcbc/asn1/oiw/ElGamalParameter.cs new file mode 100644 index 0000000..3e020f0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/oiw/ElGamalParameter.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Oiw +{ + public class ElGamalParameter + : Asn1Encodable + { + internal DerInteger p, g; + + public ElGamalParameter( + BigInteger p, + BigInteger g) + { + this.p = new DerInteger(p); + this.g = new DerInteger(g); + } + + public ElGamalParameter( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + p = DerInteger.GetInstance(seq[0]); + g = DerInteger.GetInstance(seq[1]); + } + + public BigInteger P + { + get { return p.PositiveValue; } + } + + public BigInteger G + { + get { return g.PositiveValue; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(p, g); + } + } +} diff --git a/iTechSharp/srcbc/asn1/oiw/OIWObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/oiw/OIWObjectIdentifiers.cs new file mode 100644 index 0000000..3d8d4cf --- /dev/null +++ b/iTechSharp/srcbc/asn1/oiw/OIWObjectIdentifiers.cs @@ -0,0 +1,24 @@ +namespace Org.BouncyCastle.Asn1.Oiw +{ + public abstract class OiwObjectIdentifiers + { + public static readonly DerObjectIdentifier MD4WithRsa = new DerObjectIdentifier("1.3.14.3.2.2"); + public static readonly DerObjectIdentifier MD5WithRsa = new DerObjectIdentifier("1.3.14.3.2.3"); + public static readonly DerObjectIdentifier MD4WithRsaEncryption = new DerObjectIdentifier("1.3.14.3.2.4"); + + public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7"); + + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26"); + + public static readonly DerObjectIdentifier DsaWithSha1 = new DerObjectIdentifier("1.3.14.3.2.27"); + + public static readonly DerObjectIdentifier Sha1WithRsa = new DerObjectIdentifier("1.3.14.3.2.29"); + + // ElGamal Algorithm OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } + // + public static readonly DerObjectIdentifier ElGamalAlgorithm = new DerObjectIdentifier("1.3.14.7.2.1.1"); + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/Attribute.cs b/iTechSharp/srcbc/asn1/pkcs/Attribute.cs new file mode 100644 index 0000000..ceec115 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/Attribute.cs @@ -0,0 +1,79 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class AttributePkcs + : Asn1Encodable + { + private readonly DerObjectIdentifier attrType; + private readonly Asn1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static AttributePkcs GetInstance( + object obj) + { + AttributePkcs attr = obj as AttributePkcs; + if (obj == null || attr != null) + { + return attr; + } + + Asn1Sequence seq = obj as Asn1Sequence; + if (seq != null) + { + return new AttributePkcs(seq); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + private AttributePkcs( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + attrType = DerObjectIdentifier.GetInstance(seq[0]); + attrValues = Asn1Set.GetInstance(seq[1]); + } + + public AttributePkcs( + DerObjectIdentifier attrType, + Asn1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public DerObjectIdentifier AttrType + { + get { return attrType; } + } + + public Asn1Set AttrValues + { + get { return attrValues; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Attr ::= Sequence {
      +         *     attrType OBJECT IDENTIFIER,
      +         *     attrValues Set OF AttributeValue
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(attrType, attrValues); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/AuthenticatedSafe.cs b/iTechSharp/srcbc/asn1/pkcs/AuthenticatedSafe.cs new file mode 100644 index 0000000..f3dabb8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/AuthenticatedSafe.cs @@ -0,0 +1,37 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class AuthenticatedSafe + : Asn1Encodable + { + private readonly ContentInfo[] info; + + public AuthenticatedSafe( + Asn1Sequence seq) + { + info = new ContentInfo[seq.Count]; + + for (int i = 0; i != info.Length; i++) + { + info[i] = ContentInfo.GetInstance(seq[i]); + } + } + + public AuthenticatedSafe( + ContentInfo[] info) + { + this.info = (ContentInfo[]) info.Clone(); + } + + public ContentInfo[] GetContentInfo() + { + return (ContentInfo[]) info.Clone(); + } + + public override Asn1Object ToAsn1Object() + { + return new BerSequence(info); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/CertBag.cs b/iTechSharp/srcbc/asn1/pkcs/CertBag.cs new file mode 100644 index 0000000..41afa1b --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/CertBag.cs @@ -0,0 +1,46 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class CertBag + : Asn1Encodable + { + private readonly Asn1Sequence seq; + private readonly DerObjectIdentifier certID; + private readonly Asn1Object certValue; + + public CertBag( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.seq = seq; + this.certID = DerObjectIdentifier.GetInstance(seq[0]); + this.certValue = DerTaggedObject.GetInstance(seq[1]).GetObject(); + } + + public CertBag( + DerObjectIdentifier certID, + Asn1Object certValue) + { + this.certID = certID; + this.certValue = certValue; + } + + public DerObjectIdentifier CertID + { + get { return certID; } + } + + public Asn1Object CertValue + { + get { return certValue; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(certID, new DerTaggedObject(0, certValue)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/CertificationRequest.cs b/iTechSharp/srcbc/asn1/pkcs/CertificationRequest.cs new file mode 100644 index 0000000..bb0e0cc --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/CertificationRequest.cs @@ -0,0 +1,81 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + /** + * Pkcs10 Certfication request object. + *
      +     * CertificationRequest ::= Sequence {
      +     *   certificationRequestInfo  CertificationRequestInfo,
      +     *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
      +     *   signature                 BIT STRING
      +     * }
      +     * 
      + */ + public class CertificationRequest + : Asn1Encodable + { + protected CertificationRequestInfo reqInfo; + protected AlgorithmIdentifier sigAlgId; + protected DerBitString sigBits; + + public static CertificationRequest GetInstance( + object obj) + { + if (obj is CertificationRequest) + return (CertificationRequest) obj; + + if (obj is Asn1Sequence) + return new CertificationRequest((Asn1Sequence) obj); + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + protected CertificationRequest() + { + } + + public CertificationRequest( + CertificationRequestInfo requestInfo, + AlgorithmIdentifier algorithm, + DerBitString signature) + { + this.reqInfo = requestInfo; + this.sigAlgId = algorithm; + this.sigBits = signature; + } + + public CertificationRequest( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + reqInfo = CertificationRequestInfo.GetInstance(seq[0]); + sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]); + sigBits = DerBitString.GetInstance(seq[2]); + } + + public CertificationRequestInfo GetCertificationRequestInfo() + { + return reqInfo; + } + + public AlgorithmIdentifier SignatureAlgorithm + { + get { return sigAlgId; } + } + + public DerBitString Signature + { + get { return sigBits; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(reqInfo, sigAlgId, sigBits); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/CertificationRequestInfo.cs b/iTechSharp/srcbc/asn1/pkcs/CertificationRequestInfo.cs new file mode 100644 index 0000000..690d068 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/CertificationRequestInfo.cs @@ -0,0 +1,123 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + /** + * Pkcs10 CertificationRequestInfo object. + *
      +     *  CertificationRequestInfo ::= Sequence {
      +     *   version             Integer { v1(0) } (v1,...),
      +     *   subject             Name,
      +     *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
      +     *   attributes          [0] Attributes{{ CRIAttributes }}
      +     *  }
      +     *
      +     *  Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
      +     *
      +     *  Attr { ATTRIBUTE:IOSet } ::= Sequence {
      +     *    type    ATTRIBUTE.&id({IOSet}),
      +     *    values  Set SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
      +     *  }
      +     * 
      + */ + public class CertificationRequestInfo + : Asn1Encodable + { + internal DerInteger version = new DerInteger(0); + internal X509Name subject; + internal SubjectPublicKeyInfo subjectPKInfo; + internal Asn1Set attributes; + + public static CertificationRequestInfo GetInstance( + object obj) + { + if (obj is CertificationRequestInfo) + { + return (CertificationRequestInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new CertificationRequestInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public CertificationRequestInfo( + X509Name subject, + SubjectPublicKeyInfo pkInfo, + Asn1Set attributes) + { + this.subject = subject; + this.subjectPKInfo = pkInfo; + this.attributes = attributes; + + if (subject == null || version == null || subjectPKInfo == null) + { + throw new ArgumentException( + "Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + private CertificationRequestInfo( + Asn1Sequence seq) + { + version = (DerInteger) seq[0]; + + subject = X509Name.GetInstance(seq[1]); + subjectPKInfo = SubjectPublicKeyInfo.GetInstance(seq[2]); + + // + // some CertificationRequestInfo objects seem to treat this field + // as optional. + // + if (seq.Count > 3) + { + DerTaggedObject tagobj = (DerTaggedObject) seq[3]; + attributes = Asn1Set.GetInstance(tagobj, false); + } + + if (subject == null || version == null || subjectPKInfo == null) + { + throw new ArgumentException( + "Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + public DerInteger Version + { + get { return version; } + } + + public X509Name Subject + { + get { return subject; } + } + + public SubjectPublicKeyInfo SubjectPublicKeyInfo + { + get { return subjectPKInfo; } + } + + public Asn1Set Attributes + { + get { return attributes; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, subject, subjectPKInfo); + + if (attributes != null) + { + v.Add(new DerTaggedObject(false, 0, attributes)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/ContentInfo.cs b/iTechSharp/srcbc/asn1/pkcs/ContentInfo.cs new file mode 100644 index 0000000..78213c1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/ContentInfo.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class ContentInfo + : Asn1Encodable + { + private readonly DerObjectIdentifier contentType; + private readonly Asn1Encodable content; + + public static ContentInfo GetInstance( + object obj) + { + if (obj is ContentInfo) + { + return (ContentInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new ContentInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + private ContentInfo( + Asn1Sequence seq) + { + contentType = (DerObjectIdentifier) seq[0]; + + if (seq.Count > 1) + { + content = ((Asn1TaggedObject) seq[1]).GetObject(); + } + } + + public ContentInfo( + DerObjectIdentifier contentType, + Asn1Encodable content) + { + this.contentType = contentType; + this.content = content; + } + + public DerObjectIdentifier ContentType + { + get { return contentType; } + } + + public Asn1Encodable Content + { + get { return content; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * ContentInfo ::= Sequence {
      +         *          contentType ContentType,
      +         *          content
      +         *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(contentType); + + if (content != null) + { + v.Add(new BerTaggedObject(0, content)); + } + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/DHParameter.cs b/iTechSharp/srcbc/asn1/pkcs/DHParameter.cs new file mode 100644 index 0000000..25a091a --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/DHParameter.cs @@ -0,0 +1,72 @@ +using Org.BouncyCastle.Asn1; +using System; +using System.Collections; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class DHParameter + : Asn1Encodable + { + internal DerInteger p, g, l; + + public DHParameter( + BigInteger p, + BigInteger g, + int l) + { + this.p = new DerInteger(p); + this.g = new DerInteger(g); + + if (l != 0) + { + this.l = new DerInteger(l); + } + } + + public DHParameter( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + p = (DerInteger)e.Current; + + e.MoveNext(); + g = (DerInteger)e.Current; + + if (e.MoveNext()) + { + l = (DerInteger) e.Current; + } + } + + public BigInteger P + { + get { return p.PositiveValue; } + } + + public BigInteger G + { + get { return g.PositiveValue; } + } + + public BigInteger L + { + get { return l == null ? null : l.PositiveValue; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(p, g); + + if (this.l != null) + { + v.Add(l); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/EncryptedData.cs b/iTechSharp/srcbc/asn1/pkcs/EncryptedData.cs new file mode 100644 index 0000000..2af7f33 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/EncryptedData.cs @@ -0,0 +1,104 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + /** + * The EncryptedData object. + *
      +     *      EncryptedData ::= Sequence {
      +     *           version Version,
      +     *           encryptedContentInfo EncryptedContentInfo
      +     *      }
      +     *
      +     *
      +     *      EncryptedContentInfo ::= Sequence {
      +     *          contentType ContentType,
      +     *          contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
      +     *          encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
      +     *    }
      +     *
      +     *    EncryptedContent ::= OCTET STRING
      +     * 
      + */ + public class EncryptedData + : Asn1Encodable + { + private readonly Asn1Sequence data; +// private readonly DerObjectIdentifier bagId; +// private readonly Asn1Object bagValue; + + public static EncryptedData GetInstance( + object obj) + { + if (obj is EncryptedData) + { + return (EncryptedData) obj; + } + + if (obj is Asn1Sequence) + { + return new EncryptedData((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + private EncryptedData( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + int version = ((DerInteger) seq[0]).Value.IntValue; + if (version != 0) + { + throw new ArgumentException("sequence not version 0"); + } + + this.data = (Asn1Sequence) seq[1]; + } + + public EncryptedData( + DerObjectIdentifier contentType, + AlgorithmIdentifier encryptionAlgorithm, + Asn1Encodable content) + { + data = new BerSequence( + contentType, + encryptionAlgorithm.ToAsn1Object(), + new BerTaggedObject(false, 0, content)); + } + + public DerObjectIdentifier ContentType + { + get { return (DerObjectIdentifier) data[0]; } + } + + public AlgorithmIdentifier EncryptionAlgorithm + { + get { return AlgorithmIdentifier.GetInstance(data[1]); } + } + + public Asn1OctetString Content + { + get + { + if (data.Count == 3) + { + DerTaggedObject o = (DerTaggedObject) data[2]; + + return Asn1OctetString.GetInstance(o.GetObject()); + } + + return null; + } + } + + public override Asn1Object ToAsn1Object() + { + return new BerSequence(new DerInteger(0), data); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/EncryptedPrivateKeyInfo.cs b/iTechSharp/srcbc/asn1/pkcs/EncryptedPrivateKeyInfo.cs new file mode 100644 index 0000000..b97b8f5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/EncryptedPrivateKeyInfo.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class EncryptedPrivateKeyInfo + : Asn1Encodable + { + private readonly AlgorithmIdentifier algId; + private readonly Asn1OctetString data; + + private EncryptedPrivateKeyInfo( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + algId = AlgorithmIdentifier.GetInstance(seq[0]); + data = Asn1OctetString.GetInstance(seq[1]); + } + + public EncryptedPrivateKeyInfo( + AlgorithmIdentifier algId, + byte[] encoding) + { + this.algId = algId; + this.data = new DerOctetString(encoding); + } + + public static EncryptedPrivateKeyInfo GetInstance( + object obj) + { + if (obj is EncryptedPrivateKeyInfo) + { + return (EncryptedPrivateKeyInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new EncryptedPrivateKeyInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public AlgorithmIdentifier EncryptionAlgorithm + { + get { return algId; } + } + + public byte[] GetEncryptedData() + { + return data.GetOctets(); + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * EncryptedPrivateKeyInfo ::= Sequence {
      +         *      encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
      +         *      encryptedData EncryptedData
      +         * }
      +         *
      +         * EncryptedData ::= OCTET STRING
      +         *
      +         * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
      +         *          ... -- For local profiles
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(algId, data); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/EncryptionScheme.cs b/iTechSharp/srcbc/asn1/pkcs/EncryptionScheme.cs new file mode 100644 index 0000000..5337dc7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/EncryptionScheme.cs @@ -0,0 +1,31 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class EncryptionScheme + : AlgorithmIdentifier + { + private readonly Asn1Object objectID, obj; + + internal EncryptionScheme( + Asn1Sequence seq) + : base(seq) + { + objectID = (Asn1Object) seq[0]; + obj = (Asn1Object) seq[1]; + } + + public Asn1Object Asn1Object + { + get { return obj; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(objectID, obj); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/IssuerAndSerialNumber.cs b/iTechSharp/srcbc/asn1/pkcs/IssuerAndSerialNumber.cs new file mode 100644 index 0000000..ff608f1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/IssuerAndSerialNumber.cs @@ -0,0 +1,71 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class IssuerAndSerialNumber + : Asn1Encodable + { + private readonly X509Name name; + private readonly DerInteger certSerialNumber; + + public static IssuerAndSerialNumber GetInstance( + object obj) + { + if (obj is IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber) obj; + } + + if (obj is Asn1Sequence) + { + return new IssuerAndSerialNumber((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + private IssuerAndSerialNumber( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.name = X509Name.GetInstance(seq[0]); + this.certSerialNumber = DerInteger.GetInstance(seq[1]); + } + + public IssuerAndSerialNumber( + X509Name name, + BigInteger certSerialNumber) + { + this.name = name; + this.certSerialNumber = new DerInteger(certSerialNumber); + } + + public IssuerAndSerialNumber( + X509Name name, + DerInteger certSerialNumber) + { + this.name = name; + this.certSerialNumber = certSerialNumber; + } + + public X509Name Name + { + get { return name; } + } + + public DerInteger CertificateSerialNumber + { + get { return certSerialNumber; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(name, certSerialNumber); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/KeyDerivationFunc.cs b/iTechSharp/srcbc/asn1/pkcs/KeyDerivationFunc.cs new file mode 100644 index 0000000..1bc0a61 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/KeyDerivationFunc.cs @@ -0,0 +1,21 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class KeyDerivationFunc + : AlgorithmIdentifier + { + internal KeyDerivationFunc(Asn1Sequence seq) + : base(seq) + { + } + + internal KeyDerivationFunc( + DerObjectIdentifier id, + Asn1Encodable parameters) + : base(id, parameters) + { + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/MacData.cs b/iTechSharp/srcbc/asn1/pkcs/MacData.cs new file mode 100644 index 0000000..c318eaf --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/MacData.cs @@ -0,0 +1,81 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class MacData + : Asn1Encodable + { + internal DigestInfo digInfo; + internal byte[] salt; + internal BigInteger iterationCount; + + public static MacData GetInstance( + object obj) + { + if (obj is MacData) + { + return (MacData) obj; + } + + if (obj is Asn1Sequence) + { + return new MacData((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + private MacData( + Asn1Sequence seq) + { + this.digInfo = DigestInfo.GetInstance(seq[0]); + this.salt = ((Asn1OctetString) seq[1]).GetOctets(); + + if (seq.Count == 3) + { + this.iterationCount = ((DerInteger) seq[2]).Value; + } + else + { + this.iterationCount = BigInteger.One; + } + } + + public MacData( + DigestInfo digInfo, + byte[] salt, + int iterationCount) + { + this.digInfo = digInfo; + this.salt = (byte[]) salt.Clone(); + this.iterationCount = BigInteger.ValueOf(iterationCount); + } + + public DigestInfo Mac + { + get { return digInfo; } + } + + public byte[] GetSalt() + { + return (byte[]) salt.Clone(); + } + + public BigInteger IterationCount + { + get { return iterationCount; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence( + digInfo, + new DerOctetString(salt), + new DerInteger(iterationCount)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/PBEParameter.cs b/iTechSharp/srcbc/asn1/pkcs/PBEParameter.cs new file mode 100644 index 0000000..48659ad --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/PBEParameter.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class PbeParameter + : Asn1Encodable + { + private readonly Asn1OctetString octStr; + private readonly DerInteger iterationCount; + + public static PbeParameter GetInstance( + object obj) + { + if (obj is PbeParameter || obj == null) + { + return (PbeParameter) obj; + } + + if (obj is Asn1Sequence) + { + return new PbeParameter((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + private PbeParameter( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + octStr = Asn1OctetString.GetInstance(seq[0]); + iterationCount = DerInteger.GetInstance(seq[1]); + } + + public PbeParameter( + byte[] salt, + int iterationCount) + { + this.octStr = new DerOctetString(salt); + this.iterationCount = new DerInteger(iterationCount); + } + + public byte[] GetSalt() + { + return octStr.GetOctets(); + } + + public BigInteger IterationCount + { + get { return iterationCount.Value; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(octStr, iterationCount); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/PBES2Parameters.cs b/iTechSharp/srcbc/asn1/pkcs/PBES2Parameters.cs new file mode 100644 index 0000000..86f1ec3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/PBES2Parameters.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class PbeS2Parameters + : Asn1Encodable + { + private readonly KeyDerivationFunc func; + private readonly EncryptionScheme scheme; + + public PbeS2Parameters( + Asn1Sequence obj) + { + IEnumerator e = obj.GetEnumerator(); + + e.MoveNext(); + Asn1Sequence funcSeq = (Asn1Sequence) e.Current; + + if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2)) + { + func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2, funcSeq[1]); + } + else + { + func = new KeyDerivationFunc(funcSeq); + } + + e.MoveNext(); + scheme = new EncryptionScheme((Asn1Sequence) e.Current); + } + + public KeyDerivationFunc KeyDerivationFunc + { + get { return func; } + } + + public EncryptionScheme EncryptionScheme + { + get { return scheme; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(func, scheme); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/PBKDF2Params.cs b/iTechSharp/srcbc/asn1/pkcs/PBKDF2Params.cs new file mode 100644 index 0000000..b98e6f4 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/PBKDF2Params.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class Pbkdf2Params + : Asn1Encodable + { + internal Asn1OctetString octStr; + internal DerInteger iterationCount; + internal DerInteger keyLength; + + public static Pbkdf2Params GetInstance( + object obj) + { + if (obj is Pbkdf2Params || obj == null) + { + return (Pbkdf2Params) obj; + } + + if (obj is Asn1Sequence) + { + return new Pbkdf2Params((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public Pbkdf2Params( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + octStr = (Asn1OctetString) e.Current; + + e.MoveNext(); + iterationCount = (DerInteger) e.Current; + + if (e.MoveNext()) + { + keyLength = (DerInteger) e.Current; + } + } + + public Pbkdf2Params( + byte[] salt, + int iterationCount) + { + this.octStr = new DerOctetString(salt); + this.iterationCount = new DerInteger(iterationCount); + } + + public byte[] GetSalt() + { + return octStr.GetOctets(); + } + + public BigInteger IterationCount + { + get { return iterationCount.Value; } + } + + public BigInteger KeyLength + { + get { return keyLength == null ? null : keyLength.Value; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + octStr, iterationCount); + + if (keyLength != null) + { + v.Add(keyLength); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/PKCS12PBEParams.cs b/iTechSharp/srcbc/asn1/pkcs/PKCS12PBEParams.cs new file mode 100644 index 0000000..7521f93 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/PKCS12PBEParams.cs @@ -0,0 +1,63 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class Pkcs12PbeParams + : Asn1Encodable + { + private readonly DerInteger iterations; + private readonly Asn1OctetString iv; + + public Pkcs12PbeParams( + byte[] salt, + int iterations) + { + this.iv = new DerOctetString(salt); + this.iterations = new DerInteger(iterations); + } + + private Pkcs12PbeParams( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + iv = Asn1OctetString.GetInstance(seq[0]); + iterations = DerInteger.GetInstance(seq[1]); + } + + public static Pkcs12PbeParams GetInstance( + object obj) + { + if (obj is Pkcs12PbeParams) + { + return (Pkcs12PbeParams) obj; + } + + if (obj is Asn1Sequence) + { + return new Pkcs12PbeParams((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public BigInteger Iterations + { + get { return iterations.Value; } + } + + public byte[] GetIV() + { + return iv.GetOctets(); + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(iv, iterations); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/PKCSObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/pkcs/PKCSObjectIdentifiers.cs new file mode 100644 index 0000000..7141d1d --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/PKCSObjectIdentifiers.cs @@ -0,0 +1,251 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public abstract class PkcsObjectIdentifiers + { + // + // pkcs-1 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } + // + public const string Pkcs1 = "1.2.840.113549.1.1"; + + public static readonly DerObjectIdentifier RsaEncryption = new DerObjectIdentifier(Pkcs1 + ".1"); + public static readonly DerObjectIdentifier MD2WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".2"); + public static readonly DerObjectIdentifier MD4WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".3"); + public static readonly DerObjectIdentifier MD5WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".4"); + public static readonly DerObjectIdentifier Sha1WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".5"); + public static readonly DerObjectIdentifier SrsaOaepEncryptionSet = new DerObjectIdentifier(Pkcs1 + ".6"); + public static readonly DerObjectIdentifier IdRsaesOaep = new DerObjectIdentifier(Pkcs1 + ".7"); + public static readonly DerObjectIdentifier IdMgf1 = new DerObjectIdentifier(Pkcs1 + ".8"); + public static readonly DerObjectIdentifier IdPSpecified = new DerObjectIdentifier(Pkcs1 + ".9"); + public static readonly DerObjectIdentifier IdRsassaPss = new DerObjectIdentifier(Pkcs1 + ".10"); + public static readonly DerObjectIdentifier Sha256WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".11"); + public static readonly DerObjectIdentifier Sha384WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".12"); + public static readonly DerObjectIdentifier Sha512WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".13"); + public static readonly DerObjectIdentifier Sha224WithRsaEncryption = new DerObjectIdentifier(Pkcs1 + ".14"); + + // + // pkcs-3 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 } + // + public const string Pkcs3 = "1.2.840.113549.1.3"; + + public static readonly DerObjectIdentifier DhKeyAgreement = new DerObjectIdentifier(Pkcs3 + ".1"); + + // + // pkcs-5 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } + // + public const string Pkcs5 = "1.2.840.113549.1.5"; + + public static readonly DerObjectIdentifier PbeWithMD2AndDesCbc = new DerObjectIdentifier(Pkcs5 + ".1"); + public static readonly DerObjectIdentifier PbeWithMD2AndRC2Cbc = new DerObjectIdentifier(Pkcs5 + ".4"); + public static readonly DerObjectIdentifier PbeWithMD5AndDesCbc = new DerObjectIdentifier(Pkcs5 + ".3"); + public static readonly DerObjectIdentifier PbeWithMD5AndRC2Cbc = new DerObjectIdentifier(Pkcs5 + ".6"); + public static readonly DerObjectIdentifier PbeWithSha1AndDesCbc = new DerObjectIdentifier(Pkcs5 + ".10"); + public static readonly DerObjectIdentifier PbeWithSha1AndRC2Cbc = new DerObjectIdentifier(Pkcs5 + ".11"); + + public static readonly DerObjectIdentifier IdPbeS2 = new DerObjectIdentifier(Pkcs5 + ".13"); + public static readonly DerObjectIdentifier IdPbkdf2 = new DerObjectIdentifier(Pkcs5 + ".12"); + + // + // encryptionAlgorithm OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) 3 } + // + public const string EncryptionAlgorithm = "1.2.840.113549.3"; + + public static readonly DerObjectIdentifier DesEde3Cbc = new DerObjectIdentifier(EncryptionAlgorithm + ".7"); + public static readonly DerObjectIdentifier RC2Cbc = new DerObjectIdentifier(EncryptionAlgorithm + ".2"); + + // + // object identifiers for digests + // + public const string DigestAlgorithm = "1.2.840.113549.2"; + + // + // md2 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 2} + // + public static readonly DerObjectIdentifier MD2 = new DerObjectIdentifier(DigestAlgorithm + ".2"); + + // + // md4 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 4} + // + public static readonly DerObjectIdentifier MD4 = new DerObjectIdentifier(DigestAlgorithm + ".4"); + + // + // md5 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 5} + // + public static readonly DerObjectIdentifier MD5 = new DerObjectIdentifier(DigestAlgorithm + ".5"); + + public static readonly DerObjectIdentifier IdHmacWithSha1 = new DerObjectIdentifier(DigestAlgorithm + ".7"); + public static readonly DerObjectIdentifier IdHmacWithSha224 = new DerObjectIdentifier(DigestAlgorithm + ".8"); + public static readonly DerObjectIdentifier IdHmacWithSha256 = new DerObjectIdentifier(DigestAlgorithm + ".9"); + public static readonly DerObjectIdentifier IdHmacWithSha384 = new DerObjectIdentifier(DigestAlgorithm + ".10"); + public static readonly DerObjectIdentifier IdHmacWithSha512 = new DerObjectIdentifier(DigestAlgorithm + ".11"); + + // + // pkcs-7 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } + // + public const string Pkcs7 = "1.2.840.113549.1.7"; + + public static readonly DerObjectIdentifier Data = new DerObjectIdentifier(Pkcs7 + ".1"); + public static readonly DerObjectIdentifier SignedData = new DerObjectIdentifier(Pkcs7 + ".2"); + public static readonly DerObjectIdentifier EnvelopedData = new DerObjectIdentifier(Pkcs7 + ".3"); + public static readonly DerObjectIdentifier SignedAndEnvelopedData = new DerObjectIdentifier(Pkcs7 + ".4"); + public static readonly DerObjectIdentifier DigestedData = new DerObjectIdentifier(Pkcs7 + ".5"); + public static readonly DerObjectIdentifier EncryptedData = new DerObjectIdentifier(Pkcs7 + ".6"); + + // + // pkcs-9 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } + // + public const string Pkcs9 = "1.2.840.113549.1.9"; + + public static readonly DerObjectIdentifier Pkcs9AtEmailAddress = new DerObjectIdentifier(Pkcs9 + ".1"); + public static readonly DerObjectIdentifier Pkcs9AtUnstructuredName = new DerObjectIdentifier(Pkcs9 + ".2"); + public static readonly DerObjectIdentifier Pkcs9AtContentType = new DerObjectIdentifier(Pkcs9 + ".3"); + public static readonly DerObjectIdentifier Pkcs9AtMessageDigest = new DerObjectIdentifier(Pkcs9 + ".4"); + public static readonly DerObjectIdentifier Pkcs9AtSigningTime = new DerObjectIdentifier(Pkcs9 + ".5"); + public static readonly DerObjectIdentifier Pkcs9AtCounterSignature = new DerObjectIdentifier(Pkcs9 + ".6"); + public static readonly DerObjectIdentifier Pkcs9AtChallengePassword = new DerObjectIdentifier(Pkcs9 + ".7"); + public static readonly DerObjectIdentifier Pkcs9AtUnstructuredAddress = new DerObjectIdentifier(Pkcs9 + ".8"); + public static readonly DerObjectIdentifier Pkcs9AtExtendedCertificateAttributes = new DerObjectIdentifier(Pkcs9 + ".9"); + public static readonly DerObjectIdentifier Pkcs9AtSigningDescription = new DerObjectIdentifier(Pkcs9 + ".13"); + public static readonly DerObjectIdentifier Pkcs9AtExtensionRequest = new DerObjectIdentifier(Pkcs9 + ".14"); + public static readonly DerObjectIdentifier Pkcs9AtSmimeCapabilities = new DerObjectIdentifier(Pkcs9 + ".15"); + public static readonly DerObjectIdentifier Pkcs9AtFriendlyName = new DerObjectIdentifier(Pkcs9 + ".20"); + public static readonly DerObjectIdentifier Pkcs9AtLocalKeyID = new DerObjectIdentifier(Pkcs9 + ".21"); + + [Obsolete("Use X509Certificate instead")] + public static readonly DerObjectIdentifier X509CertType = new DerObjectIdentifier(Pkcs9 + ".22.1"); + + public const string CertTypes = Pkcs9 + ".22"; + public static readonly DerObjectIdentifier X509Certificate = new DerObjectIdentifier(CertTypes + ".1"); + public static readonly DerObjectIdentifier SdsiCertificate = new DerObjectIdentifier(CertTypes + ".2"); + + public const string CrlTypes = Pkcs9 + ".23"; + public static readonly DerObjectIdentifier X509Crl = new DerObjectIdentifier(CrlTypes + ".1"); + + public static readonly DerObjectIdentifier IdAlgPwriKek = new DerObjectIdentifier(Pkcs9 + ".16.3.9"); + + // + // SMIME capability sub oids. + // + public static readonly DerObjectIdentifier PreferSignedData = new DerObjectIdentifier(Pkcs9 + ".15.1"); + public static readonly DerObjectIdentifier CannotDecryptAny = new DerObjectIdentifier(Pkcs9 + ".15.2"); + public static readonly DerObjectIdentifier SmimeCapabilitiesVersions = new DerObjectIdentifier(Pkcs9 + ".15.3"); + + // + // other SMIME attributes + // + public static readonly DerObjectIdentifier IdAAReceiptRequest = new DerObjectIdentifier(Pkcs9 + ".16.2.1"); + + // + // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)} + // + public const string IdCT = "1.2.840.113549.1.9.16.1"; + + public static readonly DerObjectIdentifier IdCTTstInfo = new DerObjectIdentifier(IdCT + ".4"); + public static readonly DerObjectIdentifier IdCTCompressedData = new DerObjectIdentifier(IdCT + ".9"); + + // + // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)} + // + public const string IdCti = "1.2.840.113549.1.9.16.6"; + + public static readonly DerObjectIdentifier IdCtiEtsProofOfOrigin = new DerObjectIdentifier(IdCti + ".1"); + public static readonly DerObjectIdentifier IdCtiEtsProofOfReceipt = new DerObjectIdentifier(IdCti + ".2"); + public static readonly DerObjectIdentifier IdCtiEtsProofOfDelivery = new DerObjectIdentifier(IdCti + ".3"); + public static readonly DerObjectIdentifier IdCtiEtsProofOfSender = new DerObjectIdentifier(IdCti + ".4"); + public static readonly DerObjectIdentifier IdCtiEtsProofOfApproval = new DerObjectIdentifier(IdCti + ".5"); + public static readonly DerObjectIdentifier IdCtiEtsProofOfCreation = new DerObjectIdentifier(IdCti + ".6"); + + // + // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} + // + public const string IdAA = "1.2.840.113549.1.9.16.2"; + + public static readonly DerObjectIdentifier IdAAContentHint = new DerObjectIdentifier(IdAA + ".4"); // See RFC 2634 + + /* + * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} + * + */ + public static readonly DerObjectIdentifier IdAAEncrypKeyPref = new DerObjectIdentifier(IdAA + ".11"); + public static readonly DerObjectIdentifier IdAASigningCertificate = new DerObjectIdentifier(IdAA + ".12"); + public static readonly DerObjectIdentifier IdAASigningCertificateV2 = new DerObjectIdentifier(IdAA + ".47"); + + public static readonly DerObjectIdentifier IdAAContentIdentifier = new DerObjectIdentifier(IdAA + ".7"); // See RFC 2634 + + /* + * RFC 3126 + */ + public static readonly DerObjectIdentifier IdAASignatureTimeStampToken = new DerObjectIdentifier(IdAA + ".14"); + + public static readonly DerObjectIdentifier IdAAEtsSigPolicyID = new DerObjectIdentifier(IdAA + ".15"); + public static readonly DerObjectIdentifier IdAAEtsCommitmentType = new DerObjectIdentifier(IdAA + ".16"); + public static readonly DerObjectIdentifier IdAAEtsSignerLocation = new DerObjectIdentifier(IdAA + ".17"); + public static readonly DerObjectIdentifier IdAAEtsSignerAttr = new DerObjectIdentifier(IdAA + ".18"); + public static readonly DerObjectIdentifier IdAAEtsOtherSigCert = new DerObjectIdentifier(IdAA + ".19"); + public static readonly DerObjectIdentifier IdAAEtsContentTimestamp = new DerObjectIdentifier(IdAA + ".20"); + public static readonly DerObjectIdentifier IdAAEtsCertificateRefs = new DerObjectIdentifier(IdAA + ".21"); + public static readonly DerObjectIdentifier IdAAEtsRevocationRefs = new DerObjectIdentifier(IdAA + ".22"); + public static readonly DerObjectIdentifier IdAAEtsCertValues = new DerObjectIdentifier(IdAA + ".23"); + public static readonly DerObjectIdentifier IdAAEtsRevocationValues = new DerObjectIdentifier(IdAA + ".24"); + public static readonly DerObjectIdentifier IdAAEtsEscTimeStamp = new DerObjectIdentifier(IdAA + ".25"); + public static readonly DerObjectIdentifier IdAAEtsCertCrlTimestamp = new DerObjectIdentifier(IdAA + ".26"); + public static readonly DerObjectIdentifier IdAAEtsArchiveTimestamp = new DerObjectIdentifier(IdAA + ".27"); + + [Obsolete("Use 'IdAAEtsSigPolicyID' instead")] + public static readonly DerObjectIdentifier IdAASigPolicyID = IdAAEtsSigPolicyID; + [Obsolete("Use 'IdAAEtsCommitmentType' instead")] + public static readonly DerObjectIdentifier IdAACommitmentType = IdAAEtsCommitmentType; + [Obsolete("Use 'IdAAEtsSignerLocation' instead")] + public static readonly DerObjectIdentifier IdAASignerLocation = IdAAEtsSignerLocation; + [Obsolete("Use 'IdAAEtsOtherSigCert' instead")] + public static readonly DerObjectIdentifier IdAAOtherSigCert = IdAAEtsOtherSigCert; + + // + // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)} + // + public const string IdSpq = "1.2.840.113549.1.9.16.5"; + + public static readonly DerObjectIdentifier IdSpqEtsUri = new DerObjectIdentifier(IdSpq + ".1"); + public static readonly DerObjectIdentifier IdSpqEtsUNotice = new DerObjectIdentifier(IdSpq + ".2"); + + // + // pkcs-12 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } + // + public const string Pkcs12 = "1.2.840.113549.1.12"; + public const string BagTypes = Pkcs12 + ".10.1"; + + public static readonly DerObjectIdentifier KeyBag = new DerObjectIdentifier(BagTypes + ".1"); + public static readonly DerObjectIdentifier Pkcs8ShroudedKeyBag = new DerObjectIdentifier(BagTypes + ".2"); + public static readonly DerObjectIdentifier CertBag = new DerObjectIdentifier(BagTypes + ".3"); + public static readonly DerObjectIdentifier CrlBag = new DerObjectIdentifier(BagTypes + ".4"); + public static readonly DerObjectIdentifier SecretBag = new DerObjectIdentifier(BagTypes + ".5"); + public static readonly DerObjectIdentifier SafeContentsBag = new DerObjectIdentifier(BagTypes + ".6"); + + public const string Pkcs12PbeIds = Pkcs12 + ".1"; + + public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC4 = new DerObjectIdentifier(Pkcs12PbeIds + ".1"); + public static readonly DerObjectIdentifier PbeWithShaAnd40BitRC4 = new DerObjectIdentifier(Pkcs12PbeIds + ".2"); + public static readonly DerObjectIdentifier PbeWithShaAnd3KeyTripleDesCbc = new DerObjectIdentifier(Pkcs12PbeIds + ".3"); + public static readonly DerObjectIdentifier PbeWithShaAnd2KeyTripleDesCbc = new DerObjectIdentifier(Pkcs12PbeIds + ".4"); + public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC2Cbc = new DerObjectIdentifier(Pkcs12PbeIds + ".5"); + public static readonly DerObjectIdentifier PbewithShaAnd40BitRC2Cbc = new DerObjectIdentifier(Pkcs12PbeIds + ".6"); + + public static readonly DerObjectIdentifier IdAlgCms3DesWrap = new DerObjectIdentifier("1.2.840.113549.1.9.16.3.6"); + public static readonly DerObjectIdentifier IdAlgCmsRC2Wrap = new DerObjectIdentifier("1.2.840.113549.1.9.16.3.7"); + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/Pfx.cs b/iTechSharp/srcbc/asn1/pkcs/Pfx.cs new file mode 100644 index 0000000..9676f64 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/Pfx.cs @@ -0,0 +1,65 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + /** + * the infamous Pfx from Pkcs12 + */ + public class Pfx + : Asn1Encodable + { + private ContentInfo contentInfo; + private MacData macData; + + public Pfx( + Asn1Sequence seq) + { + BigInteger version = ((DerInteger) seq[0]).Value; + if (version.IntValue != 3) + { + throw new ArgumentException("wrong version for PFX PDU"); + } + + contentInfo = ContentInfo.GetInstance(seq[1]); + + if (seq.Count == 3) + { + macData = MacData.GetInstance(seq[2]); + } + } + + public Pfx( + ContentInfo contentInfo, + MacData macData) + { + this.contentInfo = contentInfo; + this.macData = macData; + } + + public ContentInfo AuthSafe + { + get { return contentInfo; } + } + + public MacData MacData + { + get { return macData; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + new DerInteger(3), contentInfo); + + if (macData != null) + { + v.Add(macData); + } + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/PrivateKeyInfo.cs b/iTechSharp/srcbc/asn1/pkcs/PrivateKeyInfo.cs new file mode 100644 index 0000000..d5ab73f --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/PrivateKeyInfo.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class PrivateKeyInfo + : Asn1Encodable + { + private readonly Asn1Object privKey; + private readonly AlgorithmIdentifier algID; + private readonly Asn1Set attributes; + + public static PrivateKeyInfo GetInstance( + object obj) + { + if (obj is PrivateKeyInfo || obj == null) + { + return (PrivateKeyInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new PrivateKeyInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public PrivateKeyInfo( + AlgorithmIdentifier algID, + Asn1Object privateKey) + : this(algID, privateKey, null) + { + } + + public PrivateKeyInfo( + AlgorithmIdentifier algID, + Asn1Object privateKey, + Asn1Set attributes) + { + this.privKey = privateKey; + this.algID = algID; + this.attributes = attributes; + } + + private PrivateKeyInfo( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + BigInteger version = ((DerInteger) e.Current).Value; + if (version.IntValue != 0) + { + throw new ArgumentException("wrong version for private key info"); + } + + e.MoveNext(); + algID = AlgorithmIdentifier.GetInstance(e.Current); + + try + { + e.MoveNext(); + Asn1OctetString data = (Asn1OctetString) e.Current; + + privKey = Asn1Object.FromByteArray(data.GetOctets()); + } + catch (IOException) + { + throw new ArgumentException("Error recoverying private key from sequence"); + } + + if (e.MoveNext()) + { + attributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false); + } + } + + public AlgorithmIdentifier AlgorithmID + { + get { return algID; } + } + + public Asn1Object PrivateKey + { + get { return privKey; } + } + + public Asn1Set Attributes + { + get { return attributes; } + } + + /** + * write out an RSA private key with it's asscociated information + * as described in Pkcs8. + *
      +         *      PrivateKeyInfo ::= Sequence {
      +         *                              version Version,
      +         *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
      +         *                              privateKey PrivateKey,
      +         *                              attributes [0] IMPLICIT Attributes OPTIONAL
      +         *                          }
      +         *      Version ::= Integer {v1(0)} (v1,...)
      +         *
      +         *      PrivateKey ::= OCTET STRING
      +         *
      +         *      Attributes ::= Set OF Attr
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + new DerInteger(0), + algID, + new DerOctetString(privKey)); + + if (attributes != null) + { + v.Add(new DerTaggedObject(false, 0, attributes)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/RC2CBCParameter.cs b/iTechSharp/srcbc/asn1/pkcs/RC2CBCParameter.cs new file mode 100644 index 0000000..f5355d0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/RC2CBCParameter.cs @@ -0,0 +1,81 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class RC2CbcParameter + : Asn1Encodable + { + internal DerInteger version; + internal Asn1OctetString iv; + + public static RC2CbcParameter GetInstance( + object obj) + { + if (obj is Asn1Sequence) + { + return new RC2CbcParameter((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public RC2CbcParameter( + byte[] iv) + { + this.iv = new DerOctetString(iv); + } + + public RC2CbcParameter( + int parameterVersion, + byte[] iv) + { + this.version = new DerInteger(parameterVersion); + this.iv = new DerOctetString(iv); + } + + private RC2CbcParameter( + Asn1Sequence seq) + { + if (seq.Count == 1) + { + iv = (Asn1OctetString)seq[0]; + } + else + { + version = (DerInteger)seq[0]; + iv = (Asn1OctetString)seq[1]; + } + } + + public BigInteger RC2ParameterVersion + { + get + { + return version == null ? null : version.Value; + } + } + + public byte[] GetIV() + { + return Arrays.Clone(iv.GetOctets()); + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (version != null) + { + v.Add(version); + } + + v.Add(iv); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/RSAESOAEPparams.cs b/iTechSharp/srcbc/asn1/pkcs/RSAESOAEPparams.cs new file mode 100644 index 0000000..5ecb394 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/RSAESOAEPparams.cs @@ -0,0 +1,145 @@ +using System; + +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class RsaesOaepParameters + : Asn1Encodable + { + private AlgorithmIdentifier hashAlgorithm; + private AlgorithmIdentifier maskGenAlgorithm; + private AlgorithmIdentifier pSourceAlgorithm; + + public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance); + public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm); + public readonly static AlgorithmIdentifier DefaultPSourceAlgorithm = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0])); + + public static RsaesOaepParameters GetInstance( + object obj) + { + if (obj is RsaesOaepParameters) + { + return (RsaesOaepParameters)obj; + } + else if (obj is Asn1Sequence) + { + return new RsaesOaepParameters((Asn1Sequence)obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + /** + * The default version + */ + public RsaesOaepParameters() + { + hashAlgorithm = DefaultHashAlgorithm; + maskGenAlgorithm = DefaultMaskGenFunction; + pSourceAlgorithm = DefaultPSourceAlgorithm; + } + + public RsaesOaepParameters( + AlgorithmIdentifier hashAlgorithm, + AlgorithmIdentifier maskGenAlgorithm, + AlgorithmIdentifier pSourceAlgorithm) + { + this.hashAlgorithm = hashAlgorithm; + this.maskGenAlgorithm = maskGenAlgorithm; + this.pSourceAlgorithm = pSourceAlgorithm; + } + + public RsaesOaepParameters( + Asn1Sequence seq) + { + hashAlgorithm = DefaultHashAlgorithm; + maskGenAlgorithm = DefaultMaskGenFunction; + pSourceAlgorithm = DefaultPSourceAlgorithm; + + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject o = (Asn1TaggedObject)seq[i]; + + switch (o.TagNo) + { + case 0: + hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true); + break; + case 1: + maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true); + break; + case 2: + pSourceAlgorithm = AlgorithmIdentifier.GetInstance(o, true); + break; + default: + throw new ArgumentException("unknown tag"); + } + } + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public AlgorithmIdentifier MaskGenAlgorithm + { + get { return maskGenAlgorithm; } + } + + public AlgorithmIdentifier PSourceAlgorithm + { + get { return pSourceAlgorithm; } + } + + /** + *
      +		 *  RSAES-OAEP-params ::= SEQUENCE {
      +		 *     hashAlgorithm      [0] OAEP-PSSDigestAlgorithms     DEFAULT sha1,
      +		 *     maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
      +		 *     pSourceAlgorithm   [2] PKCS1PSourceAlgorithms  DEFAULT pSpecifiedEmpty
      +		 *   }
      +		 *
      +		 *   OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
      +		 *     { OID id-sha1 PARAMETERS NULL   }|
      +		 *     { OID id-sha256 PARAMETERS NULL }|
      +		 *     { OID id-sha384 PARAMETERS NULL }|
      +		 *     { OID id-sha512 PARAMETERS NULL },
      +		 *     ...  -- Allows for future expansion --
      +		 *   }
      +		 *   PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
      +		 *     { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
      +		 *    ...  -- Allows for future expansion --
      +		 *   }
      +		 *   PKCS1PSourceAlgorithms    ALGORITHM-IDENTIFIER ::= {
      +		 *     { OID id-pSpecified PARAMETERS OCTET STRING },
      +		 *     ...  -- Allows for future expansion --
      +		 *  }
      +		 * 
      + * @return the asn1 primitive representing the parameters. + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (!hashAlgorithm.Equals(DefaultHashAlgorithm)) + { + v.Add(new DerTaggedObject(true, 0, hashAlgorithm)); + } + + if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction)) + { + v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm)); + } + + if (!pSourceAlgorithm.Equals(DefaultPSourceAlgorithm)) + { + v.Add(new DerTaggedObject(true, 2, pSourceAlgorithm)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/RSAPrivateKeyStructure.cs b/iTechSharp/srcbc/asn1/pkcs/RSAPrivateKeyStructure.cs new file mode 100644 index 0000000..dbb07c7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/RSAPrivateKeyStructure.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class RsaPrivateKeyStructure + : Asn1Encodable + { + private readonly BigInteger modulus; + private readonly BigInteger publicExponent; + private readonly BigInteger privateExponent; + private readonly BigInteger prime1; + private readonly BigInteger prime2; + private readonly BigInteger exponent1; + private readonly BigInteger exponent2; + private readonly BigInteger coefficient; + + public RsaPrivateKeyStructure( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger prime1, + BigInteger prime2, + BigInteger exponent1, + BigInteger exponent2, + BigInteger coefficient) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + this.privateExponent = privateExponent; + this.prime1 = prime1; + this.prime2 = prime2; + this.exponent1 = exponent1; + this.exponent2 = exponent2; + this.coefficient = coefficient; + } + + public RsaPrivateKeyStructure( + Asn1Sequence seq) + { + BigInteger version = ((DerInteger) seq[0]).Value; + if (version.IntValue != 0) + throw new ArgumentException("wrong version for RSA private key"); + + modulus = ((DerInteger) seq[1]).Value; + publicExponent = ((DerInteger) seq[2]).Value; + privateExponent = ((DerInteger) seq[3]).Value; + prime1 = ((DerInteger) seq[4]).Value; + prime2 = ((DerInteger) seq[5]).Value; + exponent1 = ((DerInteger) seq[6]).Value; + exponent2 = ((DerInteger) seq[7]).Value; + coefficient = ((DerInteger) seq[8]).Value; + } + + public BigInteger Modulus + { + get { return modulus; } + } + + public BigInteger PublicExponent + { + get { return publicExponent; } + } + + public BigInteger PrivateExponent + { + get { return privateExponent; } + } + + public BigInteger Prime1 + { + get { return prime1; } + } + + public BigInteger Prime2 + { + get { return prime2; } + } + + public BigInteger Exponent1 + { + get { return exponent1; } + } + + public BigInteger Exponent2 + { + get { return exponent2; } + } + + public BigInteger Coefficient + { + get { return coefficient; } + } + + /** + * This outputs the key in Pkcs1v2 format. + *
      +         *      RsaPrivateKey ::= Sequence {
      +         *                          version Version,
      +         *                          modulus Integer, -- n
      +         *                          publicExponent Integer, -- e
      +         *                          privateExponent Integer, -- d
      +         *                          prime1 Integer, -- p
      +         *                          prime2 Integer, -- q
      +         *                          exponent1 Integer, -- d mod (p-1)
      +         *                          exponent2 Integer, -- d mod (q-1)
      +         *                          coefficient Integer -- (inverse of q) mod p
      +         *                      }
      +         *
      +         *      Version ::= Integer
      +         * 
      + *

      This routine is written to output Pkcs1 version 0, private keys.

      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence( + new DerInteger(0), // version + new DerInteger(Modulus), + new DerInteger(PublicExponent), + new DerInteger(PrivateExponent), + new DerInteger(Prime1), + new DerInteger(Prime2), + new DerInteger(Exponent1), + new DerInteger(Exponent2), + new DerInteger(Coefficient)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/RSASSAPSSparams.cs b/iTechSharp/srcbc/asn1/pkcs/RSASSAPSSparams.cs new file mode 100644 index 0000000..9416207 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/RSASSAPSSparams.cs @@ -0,0 +1,165 @@ +using System; + +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class RsassaPssParameters + : Asn1Encodable + { + private AlgorithmIdentifier hashAlgorithm; + private AlgorithmIdentifier maskGenAlgorithm; + private DerInteger saltLength; + private DerInteger trailerField; + + public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance); + public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm); + public readonly static DerInteger DefaultSaltLength = new DerInteger(20); + public readonly static DerInteger DefaultTrailerField = new DerInteger(1); + + public static RsassaPssParameters GetInstance( + object obj) + { + if (obj == null || obj is RsassaPssParameters) + { + return (RsassaPssParameters)obj; + } + + if (obj is Asn1Sequence) + { + return new RsassaPssParameters((Asn1Sequence)obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + /** + * The default version + */ + public RsassaPssParameters() + { + hashAlgorithm = DefaultHashAlgorithm; + maskGenAlgorithm = DefaultMaskGenFunction; + saltLength = DefaultSaltLength; + trailerField = DefaultTrailerField; + } + + public RsassaPssParameters( + AlgorithmIdentifier hashAlgorithm, + AlgorithmIdentifier maskGenAlgorithm, + DerInteger saltLength, + DerInteger trailerField) + { + this.hashAlgorithm = hashAlgorithm; + this.maskGenAlgorithm = maskGenAlgorithm; + this.saltLength = saltLength; + this.trailerField = trailerField; + } + + public RsassaPssParameters( + Asn1Sequence seq) + { + hashAlgorithm = DefaultHashAlgorithm; + maskGenAlgorithm = DefaultMaskGenFunction; + saltLength = DefaultSaltLength; + trailerField = DefaultTrailerField; + + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject o = (Asn1TaggedObject)seq[i]; + + switch (o.TagNo) + { + case 0: + hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true); + break; + case 1: + maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true); + break; + case 2: + saltLength = DerInteger.GetInstance(o, true); + break; + case 3: + trailerField = DerInteger.GetInstance(o, true); + break; + default: + throw new ArgumentException("unknown tag"); + } + } + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public AlgorithmIdentifier MaskGenAlgorithm + { + get { return maskGenAlgorithm; } + } + + public DerInteger SaltLength + { + get { return saltLength; } + } + + public DerInteger TrailerField + { + get { return trailerField; } + } + + /** + *
      +		 * RSASSA-PSS-params ::= SEQUENCE {
      +		 *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms  DEFAULT sha1,
      +		 *    maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
      +		 *    saltLength         [2] INTEGER  DEFAULT 20,
      +		 *    trailerField       [3] TrailerField  DEFAULT trailerFieldBC
      +		 *  }
      +		 *
      +		 * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
      +		 *    { OID id-sha1 PARAMETERS NULL   }|
      +		 *    { OID id-sha256 PARAMETERS NULL }|
      +		 *    { OID id-sha384 PARAMETERS NULL }|
      +		 *    { OID id-sha512 PARAMETERS NULL },
      +		 *    ...  -- Allows for future expansion --
      +		 * }
      +		 *
      +		 * PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
      +		 *   { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
      +		 *    ...  -- Allows for future expansion --
      +		 * }
      +		 *
      +		 * TrailerField ::= INTEGER { trailerFieldBC(1) }
      +		 * 
      + * @return the asn1 primitive representing the parameters. + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (!hashAlgorithm.Equals(DefaultHashAlgorithm)) + { + v.Add(new DerTaggedObject(true, 0, hashAlgorithm)); + } + + if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction)) + { + v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm)); + } + + if (!saltLength.Equals(DefaultSaltLength)) + { + v.Add(new DerTaggedObject(true, 2, saltLength)); + } + + if (!trailerField.Equals(DefaultTrailerField)) + { + v.Add(new DerTaggedObject(true, 3, trailerField)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/SafeBag.cs b/iTechSharp/srcbc/asn1/pkcs/SafeBag.cs new file mode 100644 index 0000000..4b9350b --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/SafeBag.cs @@ -0,0 +1,70 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class SafeBag + : Asn1Encodable + { + private readonly DerObjectIdentifier bagID; + private readonly Asn1Object bagValue; + private readonly Asn1Set bagAttributes; + + public SafeBag( + DerObjectIdentifier oid, + Asn1Object obj) + { + this.bagID = oid; + this.bagValue = obj; + this.bagAttributes = null; + } + + public SafeBag( + DerObjectIdentifier oid, + Asn1Object obj, + Asn1Set bagAttributes) + { + this.bagID = oid; + this.bagValue = obj; + this.bagAttributes = bagAttributes; + } + + public SafeBag( + Asn1Sequence seq) + { + this.bagID = (DerObjectIdentifier) seq[0]; + this.bagValue = ((DerTaggedObject) seq[1]).GetObject(); + if (seq.Count == 3) + { + this.bagAttributes = (Asn1Set) seq[2]; + } + } + + public DerObjectIdentifier BagID + { + get { return bagID; } + } + + public Asn1Object BagValue + { + get { return bagValue; } + } + + public Asn1Set BagAttributes + { + get { return bagAttributes; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + bagID, new DerTaggedObject(0, bagValue)); + + if (bagAttributes != null) + { + v.Add(bagAttributes); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/SignedData.cs b/iTechSharp/srcbc/asn1/pkcs/SignedData.cs new file mode 100644 index 0000000..10951d3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/SignedData.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + /** + * a Pkcs#7 signed data object. + */ + public class SignedData + : Asn1Encodable + { + private readonly DerInteger version; + private readonly Asn1Set digestAlgorithms; + private readonly ContentInfo contentInfo; + private readonly Asn1Set certificates; + private readonly Asn1Set crls; + private readonly Asn1Set signerInfos; + + public static SignedData GetInstance( + object obj) + { + if (obj is SignedData) + { + return (SignedData) obj; + } + + if (obj is Asn1Sequence) + { + return new SignedData((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public SignedData( + DerInteger _version, + Asn1Set _digestAlgorithms, + ContentInfo _contentInfo, + Asn1Set _certificates, + Asn1Set _crls, + Asn1Set _signerInfos) + { + version = _version; + digestAlgorithms = _digestAlgorithms; + contentInfo = _contentInfo; + certificates = _certificates; + crls = _crls; + signerInfos = _signerInfos; + } + + private SignedData( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + version = (DerInteger) e.Current; + + e.MoveNext(); + digestAlgorithms = (Asn1Set) e.Current; + + e.MoveNext(); + contentInfo = ContentInfo.GetInstance(e.Current); + + while (e.MoveNext()) + { + Asn1Object o = (Asn1Object) e.Current; + + // + // an interesting feature of SignedData is that there appear to be varying implementations... + // for the moment we ignore anything which doesn't fit. + // + if (o is DerTaggedObject) + { + DerTaggedObject tagged = (DerTaggedObject) o; + + switch (tagged.TagNo) + { + case 0: + certificates = Asn1Set.GetInstance(tagged, false); + break; + case 1: + crls = Asn1Set.GetInstance(tagged, false); + break; + default: + throw new ArgumentException("unknown tag value " + tagged.TagNo); + } + } + else + { + signerInfos = (Asn1Set) o; + } + } + } + + public DerInteger Version + { + get { return version; } + } + + public Asn1Set DigestAlgorithms + { + get { return digestAlgorithms; } + } + + public ContentInfo ContentInfo + { + get { return contentInfo; } + } + + public Asn1Set Certificates + { + get { return certificates; } + } + + public Asn1Set Crls + { + get { return crls; } + } + + public Asn1Set SignerInfos + { + get { return signerInfos; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  SignedData ::= Sequence {
      +         *      version Version,
      +         *      digestAlgorithms DigestAlgorithmIdentifiers,
      +         *      contentInfo ContentInfo,
      +         *      certificates
      +         *          [0] IMPLICIT ExtendedCertificatesAndCertificates
      +         *                   OPTIONAL,
      +         *      crls
      +         *          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
      +         *      signerInfos SignerInfos }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, digestAlgorithms, contentInfo); + + if (certificates != null) + { + v.Add(new DerTaggedObject(false, 0, certificates)); + } + + if (crls != null) + { + v.Add(new DerTaggedObject(false, 1, crls)); + } + + v.Add(signerInfos); + + return new BerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/pkcs/SignerInfo.cs b/iTechSharp/srcbc/asn1/pkcs/SignerInfo.cs new file mode 100644 index 0000000..1e46945 --- /dev/null +++ b/iTechSharp/srcbc/asn1/pkcs/SignerInfo.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + /** + * a Pkcs#7 signer info object. + */ + public class SignerInfo + : Asn1Encodable + { + private DerInteger version; + private IssuerAndSerialNumber issuerAndSerialNumber; + private AlgorithmIdentifier digAlgorithm; + private Asn1Set authenticatedAttributes; + private AlgorithmIdentifier digEncryptionAlgorithm; + private Asn1OctetString encryptedDigest; + private Asn1Set unauthenticatedAttributes; + + public static SignerInfo GetInstance( + object obj) + { + if (obj is SignerInfo) + { + return (SignerInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new SignerInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public SignerInfo( + DerInteger version, + IssuerAndSerialNumber issuerAndSerialNumber, + AlgorithmIdentifier digAlgorithm, + Asn1Set authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + Asn1OctetString encryptedDigest, + Asn1Set unauthenticatedAttributes) + { + this.version = version; + this.issuerAndSerialNumber = issuerAndSerialNumber; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = authenticatedAttributes; + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public SignerInfo( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + version = (DerInteger) e.Current; + + e.MoveNext(); + issuerAndSerialNumber = IssuerAndSerialNumber.GetInstance(e.Current); + + e.MoveNext(); + digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current); + + e.MoveNext(); + object obj = e.Current; + + if (obj is Asn1TaggedObject) + { + authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false); + + e.MoveNext(); + digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current); + } + else + { + authenticatedAttributes = null; + digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj); + } + + e.MoveNext(); + encryptedDigest = DerOctetString.GetInstance(e.Current); + + if (e.MoveNext()) + { + unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false); + } + else + { + unauthenticatedAttributes = null; + } + } + + public DerInteger Version { get { return version; } } + + public IssuerAndSerialNumber IssuerAndSerialNumber { get { return issuerAndSerialNumber; } } + + public Asn1Set AuthenticatedAttributes { get { return authenticatedAttributes; } } + + public AlgorithmIdentifier DigestAlgorithm { get { return digAlgorithm; } } + + public Asn1OctetString EncryptedDigest { get { return encryptedDigest; } } + + public AlgorithmIdentifier DigestEncryptionAlgorithm { get { return digEncryptionAlgorithm; } } + + public Asn1Set UnauthenticatedAttributes { get { return unauthenticatedAttributes; } } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  SignerInfo ::= Sequence {
      +         *      version Version,
      +         *      issuerAndSerialNumber IssuerAndSerialNumber,
      +         *      digestAlgorithm DigestAlgorithmIdentifier,
      +         *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
      +         *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
      +         *      encryptedDigest EncryptedDigest,
      +         *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
      +         *  }
      +         *
      +         *  EncryptedDigest ::= OCTET STRING
      +         *
      +         *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
      +         *
      +         *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, issuerAndSerialNumber, digAlgorithm); + + if (authenticatedAttributes != null) + { + v.Add(new DerTaggedObject(false, 0, authenticatedAttributes)); + } + + v.Add(digEncryptionAlgorithm, encryptedDigest); + + if (unauthenticatedAttributes != null) + { + v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/sec/ECPrivateKeyStructure.cs b/iTechSharp/srcbc/asn1/sec/ECPrivateKeyStructure.cs new file mode 100644 index 0000000..b4592cd --- /dev/null +++ b/iTechSharp/srcbc/asn1/sec/ECPrivateKeyStructure.cs @@ -0,0 +1,82 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +using System; + +namespace Org.BouncyCastle.Asn1.Sec +{ + /** + * the elliptic curve private key object from SEC 1 + */ + public class ECPrivateKeyStructure + : Asn1Encodable + { + private readonly Asn1Sequence seq; + + public ECPrivateKeyStructure( + Asn1Sequence seq) + { + if (seq == null) + throw new ArgumentNullException("seq"); + + this.seq = seq; + } + + public ECPrivateKeyStructure( + BigInteger key) + { + this.seq = new DerSequence( + new DerInteger(1), + new DerOctetString(key.ToByteArrayUnsigned())); + } + + public BigInteger GetKey() + { + Asn1OctetString octs = (Asn1OctetString) seq[1]; + + return new BigInteger(1, octs.GetOctets()); + } + + public DerBitString GetPublicKey() + { + return (DerBitString) GetObjectInTag(1); + } + + public Asn1Object GetParameters() + { + return GetObjectInTag(0); + } + + private Asn1Object GetObjectInTag( + int tagNo) + { + foreach (Asn1Encodable ae in seq) + { + Asn1Object obj = ae.ToAsn1Object(); + + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tag = (Asn1TaggedObject) obj; + if (tag.TagNo == tagNo) + { + return tag.GetObject(); + } + } + } + + return null; + } + + /** + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] Parameters OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL } + */ + public override Asn1Object ToAsn1Object() + { + return seq; + } + } +} diff --git a/iTechSharp/srcbc/asn1/sec/SECNamedCurves.cs b/iTechSharp/srcbc/asn1/sec/SECNamedCurves.cs new file mode 100644 index 0000000..3eb5e35 --- /dev/null +++ b/iTechSharp/srcbc/asn1/sec/SECNamedCurves.cs @@ -0,0 +1,1191 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.Sec +{ + public sealed class SecNamedCurves + { + private SecNamedCurves() + { + } + + private static BigInteger FromHex( + string hex) + { + return new BigInteger(1, Hex.Decode(hex)); + } + + /* + * secp112r1 + */ + internal class Secp112r1Holder + : X9ECParametersHolder + { + private Secp112r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp112r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = (2^128 - 3) / 76439 + BigInteger p = FromHex("DB7C2ABF62E35E668076BEAD208B"); + BigInteger a = FromHex("DB7C2ABF62E35E668076BEAD2088"); + BigInteger b = FromHex("659EF8BA043916EEDE8911702B22"); + byte[] S = Hex.Decode("00F50B028E4D696E676875615175290472783FB1"); + BigInteger n = FromHex("DB7C2ABF62E35E7628DFAC6561C5"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "09487239995A5EE76B55F9C2F098")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "09487239995A5EE76B55F9C2F098" + + "A89CE5AF8724C0A23E0E0FF77500")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp112r2 + */ + internal class Secp112r2Holder + : X9ECParametersHolder + { + private Secp112r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp112r2Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = (2^128 - 3) / 76439 + BigInteger p = FromHex("DB7C2ABF62E35E668076BEAD208B"); + BigInteger a = FromHex("6127C24C05F38A0AAAF65C0EF02C"); + BigInteger b = FromHex("51DEF1815DB5ED74FCC34C85D709"); + byte[] S = Hex.Decode("002757A1114D696E6768756151755316C05E0BD4"); + BigInteger n = FromHex("36DF0AAFD8B8D7597CA10520D04B"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "4BA30AB5E892B4E1649DD0928643")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "4BA30AB5E892B4E1649DD0928643" + + "ADCD46F5882E3747DEF36E956E97")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp128r1 + */ + internal class Secp128r1Holder + : X9ECParametersHolder + { + private Secp128r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp128r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^128 - 2^97 - 1 + BigInteger p = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("E87579C11079F43DD824993C2CEE5ED3"); + byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679"); + BigInteger n = FromHex("FFFFFFFE0000000075A30D1B9038A115"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "161FF7528B899B2D0C28607CA52C5B86")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "161FF7528B899B2D0C28607CA52C5B86" + + "CF5AC8395BAFEB13C02DA292DDED7A83")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp128r2 + */ + internal class Secp128r2Holder + : X9ECParametersHolder + { + private Secp128r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp128r2Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^128 - 2^97 - 1 + BigInteger p = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1"); + BigInteger b = FromHex("5EEEFCA380D02919DC2C6558BB6D8A5D"); + byte[] S = Hex.Decode("004D696E67687561517512D8F03431FCE63B88F4"); + BigInteger n = FromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "7B6AA5D85E572983E6FB32A7CDEBC140" + + "27B6916A894D3AEE7106FE805FC34B44")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp160k1 + */ + internal class Secp160k1Holder + : X9ECParametersHolder + { + private Secp160k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp160k1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(7); + byte[] S = null; + BigInteger n = FromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + + "938CF935318FDCED6BC28286531733C3F03C4FEE")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp160r1 + */ + internal class Secp160r1Holder + : X9ECParametersHolder + { + private Secp160r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp160r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^160 - 2^31 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"); + BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"); + BigInteger b = FromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"); + byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345"); + BigInteger n = FromHex("0100000000000000000001F4C8F927AED3CA752257"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "4A96B5688EF573284664698968C38BB913CBFC82")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "4A96B5688EF573284664698968C38BB913CBFC82" + + "23A628553168947D59DCC912042351377AC5FB32")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp160r2 + */ + internal class Secp160r2Holder + : X9ECParametersHolder + { + private Secp160r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp160r2Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); + BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70"); + BigInteger b = FromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA"); + byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751"); + BigInteger n = FromHex("0100000000000000000000351EE786A818F3A1A16B"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp192k1 + */ + internal class Secp192k1Holder + : X9ECParametersHolder + { + private Secp192k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"); + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(3); + byte[] S = null; + BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp192r1 + */ + internal class Secp192r1Holder + : X9ECParametersHolder + { + private Secp192r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^192 - 2^64 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"); + byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); + BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp224k1 + */ + internal class Secp224k1Holder + : X9ECParametersHolder + { + private Secp224k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"); + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(5); + byte[] S = null; + BigInteger n = FromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp224r1 + */ + internal class Secp224r1Holder + : X9ECParametersHolder + { + private Secp224r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^224 - 2^96 + 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); + BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"); + BigInteger b = FromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"); + byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp256k1 + */ + internal class Secp256k1Holder + : X9ECParametersHolder + { + private Secp256k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"); + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(7); + byte[] S = null; + BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp256r1 + */ + internal class Secp256r1Holder + : X9ECParametersHolder + { + private Secp256r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1 + BigInteger p = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); + byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90"); + BigInteger n = FromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp384r1 + */ + internal class Secp384r1Holder + : X9ECParametersHolder + { + private Secp384r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^384 - 2^128 - 2^96 + 2^32 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); + BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"); + BigInteger b = FromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"); + byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp521r1 + */ + internal class Secp521r1Holder + : X9ECParametersHolder + { + private Secp521r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^521 - 1 + BigInteger p = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); + byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); + BigInteger h = BigInteger.ValueOf(1); + + ECCurve curve = new FpCurve(p, a, b); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect113r1 + */ + internal class Sect113r1Holder + : X9ECParametersHolder + { + private Sect113r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect113r1Holder(); + + private const int m = 113; + private const int k = 9; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("003088250CA6E7C7FE649CE85820F7"); + BigInteger b = FromHex("00E8BEE4D3E2260744188BE0E9C723"); + byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); + BigInteger n = FromHex("0100000000000000D9CCEC8A39E56F"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "009D73616F35F4AB1407D73562C10F")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "009D73616F35F4AB1407D73562C10F" + + "00A52830277958EE84D1315ED31886")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect113r2 + */ + internal class Sect113r2Holder + : X9ECParametersHolder + { + private Sect113r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect113r2Holder(); + + private const int m = 113; + private const int k = 9; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("00689918DBEC7E5A0DD6DFC0AA55C7"); + BigInteger b = FromHex("0095E9A9EC9B297BD4BF36E059184F"); + byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D"); + BigInteger n = FromHex("010000000000000108789B2496AF93"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "01A57A6A7B26CA5EF52FCDB8164797")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "01A57A6A7B26CA5EF52FCDB8164797" + + "00B3ADC94ED1FE674C06E695BABA1D")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect131r1 + */ + internal class Sect131r1Holder + : X9ECParametersHolder + { + private Sect131r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect131r1Holder(); + + private const int m = 131; + private const int k1 = 2; + private const int k2 = 3; + private const int k3 = 8; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("07A11B09A76B562144418FF3FF8C2570B8"); + BigInteger b = FromHex("0217C05610884B63B9C6C7291678F9D341"); + byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2"); + BigInteger n = FromHex("0400000000000000023123953A9464B54D"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "0081BAF91FDF9833C40F9C181343638399")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "0081BAF91FDF9833C40F9C181343638399" + + "078C6E7EA38C001F73C8134B1B4EF9E150")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect131r2 + */ + internal class Sect131r2Holder + : X9ECParametersHolder + { + private Sect131r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect131r2Holder(); + + private const int m = 131; + private const int k1 = 2; + private const int k2 = 3; + private const int k3 = 8; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("03E5A88919D7CAFCBF415F07C2176573B2"); + BigInteger b = FromHex("04B8266A46C55657AC734CE38F018F2192"); + byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); + BigInteger n = FromHex("0400000000000000016954A233049BA98F"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "0356DCD8F2F95031AD652D23951BB366A8")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "0356DCD8F2F95031AD652D23951BB366A8" + + "0648F06D867940A5366D9E265DE9EB240F")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect163k1 + */ + internal class Sect163k1Holder + : X9ECParametersHolder + { + private Sect163k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect163k1Holder(); + + private const int m = 163; + private const int k1 = 3; + private const int k2 = 6; + private const int k3 = 7; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.ValueOf(1); + BigInteger b = BigInteger.ValueOf(1); + byte[] S = null; + BigInteger n = FromHex("04000000000000000000020108A2E0CC0D99F8A5EF"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect163r1 + */ + internal class Sect163r1Holder + : X9ECParametersHolder + { + private Sect163r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect163r1Holder(); + + private const int m = 163; + private const int k1 = 3; + private const int k2 = 6; + private const int k3 = 7; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2"); + BigInteger b = FromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9"); + byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); + BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "0369979697AB43897789566789567F787A7876A654")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "0369979697AB43897789566789567F787A7876A654" + + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect163r2 + */ + internal class Sect163r2Holder + : X9ECParametersHolder + { + private Sect163r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect163r2Holder(); + + private const int m = 163; + private const int k1 = 3; + private const int k2 = 6; + private const int k3 = 7; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.ValueOf(1); + BigInteger b = FromHex("020A601907B8C953CA1481EB10512F78744A3205FD"); + byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); + BigInteger n = FromHex("040000000000000000000292FE77E70C12A4234C33"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect193r1 + */ + internal class Sect193r1Holder + : X9ECParametersHolder + { + private Sect193r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect193r1Holder(); + + private const int m = 193; + private const int k = 15; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01"); + BigInteger b = FromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814"); + byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30"); + BigInteger n = FromHex("01000000000000000000000000C7F34A778F443ACC920EBA49"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect193r2 + */ + internal class Sect193r2Holder + : X9ECParametersHolder + { + private Sect193r2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect193r2Holder(); + + private const int m = 193; + private const int k = 15; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = FromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B"); + BigInteger b = FromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE"); + byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211"); + BigInteger n = FromHex("010000000000000000000000015AAB561B005413CCD4EE99D5"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect233k1 + */ + internal class Sect233k1Holder + : X9ECParametersHolder + { + private Sect233k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect233k1Holder(); + + private const int m = 233; + private const int k = 74; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(1); + byte[] S = null; + BigInteger n = FromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect233r1 + */ + internal class Sect233r1Holder + : X9ECParametersHolder + { + private Sect233r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect233r1Holder(); + + private const int m = 233; + private const int k = 74; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.ValueOf(1); + BigInteger b = FromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"); + byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); + BigInteger n = FromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect239k1 + */ + internal class Sect239k1Holder + : X9ECParametersHolder + { + private Sect239k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect239k1Holder(); + + private const int m = 239; + private const int k = 158; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(1); + byte[] S = null; + BigInteger n = FromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect283k1 + */ + internal class Sect283k1Holder + : X9ECParametersHolder + { + private Sect283k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect283k1Holder(); + + private const int m = 283; + private const int k1 = 5; + private const int k2 = 7; + private const int k3 = 12; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(1); + byte[] S = null; + BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect283r1 + */ + internal class Sect283r1Holder + : X9ECParametersHolder + { + private Sect283r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect283r1Holder(); + + private const int m = 283; + private const int k1 = 5; + private const int k2 = 7; + private const int k3 = 12; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.ValueOf(1); + BigInteger b = FromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"); + byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); + BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect409k1 + */ + internal class Sect409k1Holder + : X9ECParametersHolder + { + private Sect409k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect409k1Holder(); + + private const int m = 409; + private const int k = 87; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(1); + byte[] S = null; + BigInteger n = FromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect409r1 + */ + internal class Sect409r1Holder + : X9ECParametersHolder + { + private Sect409r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect409r1Holder(); + + private const int m = 409; + private const int k = 87; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.ValueOf(1); + BigInteger b = FromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F"); + byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); + BigInteger n = FromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect571k1 + */ + internal class Sect571k1Holder + : X9ECParametersHolder + { + private Sect571k1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect571k1Holder(); + + private const int m = 571; + private const int k1 = 2; + private const int k2 = 5; + private const int k3 = 10; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.Zero; + BigInteger b = BigInteger.ValueOf(1); + byte[] S = null; + BigInteger n = FromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("02" + //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * sect571r1 + */ + internal class Sect571r1Holder + : X9ECParametersHolder + { + private Sect571r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Sect571r1Holder(); + + private const int m = 571; + private const int k1 = 2; + private const int k2 = 5; + private const int k3 = 10; + + protected override X9ECParameters CreateParameters() + { + BigInteger a = BigInteger.ValueOf(1); + BigInteger b = FromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"); + byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); + BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.DecodePoint(Hex.Decode("03" + //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); + ECPoint G = curve.DecodePoint(Hex.Decode("04" + + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + + private static readonly Hashtable objIds = new Hashtable(); + private static readonly Hashtable curves = new Hashtable(); + private static readonly Hashtable names = new Hashtable(); + + private static void DefineCurve( + string name, + DerObjectIdentifier oid, + X9ECParametersHolder holder) + { + objIds.Add(name, oid); + names.Add(oid, name); + curves.Add(oid, holder); + } + + static SecNamedCurves() + { + DefineCurve("secp112r1", SecObjectIdentifiers.SecP112r1, Secp112r1Holder.Instance); + DefineCurve("secp112r2", SecObjectIdentifiers.SecP112r2, Secp112r2Holder.Instance); + DefineCurve("secp128r1", SecObjectIdentifiers.SecP128r1, Secp128r1Holder.Instance); + DefineCurve("secp128r2", SecObjectIdentifiers.SecP128r2, Secp128r2Holder.Instance); + DefineCurve("secp160k1", SecObjectIdentifiers.SecP160k1, Secp160k1Holder.Instance); + DefineCurve("secp160r1", SecObjectIdentifiers.SecP160r1, Secp160r1Holder.Instance); + DefineCurve("secp160r2", SecObjectIdentifiers.SecP160r2, Secp160r2Holder.Instance); + DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance); + DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance); + DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance); + DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance); + DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance); + DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance); + DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance); + DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance); + + DefineCurve("sect113r1", SecObjectIdentifiers.SecT113r1, Sect113r1Holder.Instance); + DefineCurve("sect113r2", SecObjectIdentifiers.SecT113r2, Sect113r2Holder.Instance); + DefineCurve("sect131r1", SecObjectIdentifiers.SecT131r1, Sect131r1Holder.Instance); + DefineCurve("sect131r2", SecObjectIdentifiers.SecT131r2, Sect131r2Holder.Instance); + DefineCurve("sect163k1", SecObjectIdentifiers.SecT163k1, Sect163k1Holder.Instance); + DefineCurve("sect163r1", SecObjectIdentifiers.SecT163r1, Sect163r1Holder.Instance); + DefineCurve("sect163r2", SecObjectIdentifiers.SecT163r2, Sect163r2Holder.Instance); + DefineCurve("sect193r1", SecObjectIdentifiers.SecT193r1, Sect193r1Holder.Instance); + DefineCurve("sect193r2", SecObjectIdentifiers.SecT193r2, Sect193r2Holder.Instance); + DefineCurve("sect233k1", SecObjectIdentifiers.SecT233k1, Sect233k1Holder.Instance); + DefineCurve("sect233r1", SecObjectIdentifiers.SecT233r1, Sect233r1Holder.Instance); + DefineCurve("sect239k1", SecObjectIdentifiers.SecT239k1, Sect239k1Holder.Instance); + DefineCurve("sect283k1", SecObjectIdentifiers.SecT283k1, Sect283k1Holder.Instance); + DefineCurve("sect283r1", SecObjectIdentifiers.SecT283r1, Sect283r1Holder.Instance); + DefineCurve("sect409k1", SecObjectIdentifiers.SecT409k1, Sect409k1Holder.Instance); + DefineCurve("sect409r1", SecObjectIdentifiers.SecT409r1, Sect409r1Holder.Instance); + DefineCurve("sect571k1", SecObjectIdentifiers.SecT571k1, Sect571k1Holder.Instance); + DefineCurve("sect571r1", SecObjectIdentifiers.SecT571r1, Sect571r1Holder.Instance); + } + + public static X9ECParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) + objIds[name.ToLower(CultureInfo.InvariantCulture)]; + + return oid == null ? null : GetByOid(oid); + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters GetByOid( + DerObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid]; + + return holder == null ? null : holder.Parameters; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier) objIds[name.ToLower(CultureInfo.InvariantCulture)]; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string) names[oid]; + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + } +} diff --git a/iTechSharp/srcbc/asn1/sec/SECObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/sec/SECObjectIdentifiers.cs new file mode 100644 index 0000000..afc10e1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/sec/SECObjectIdentifiers.cs @@ -0,0 +1,52 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; + +namespace Org.BouncyCastle.Asn1.Sec +{ + public abstract class SecObjectIdentifiers + { + /** + * EllipticCurve OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) + * } + */ + public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.132.0"); + + public static readonly DerObjectIdentifier SecT163k1 = new DerObjectIdentifier(EllipticCurve + ".1"); + public static readonly DerObjectIdentifier SecT163r1 = new DerObjectIdentifier(EllipticCurve + ".2"); + public static readonly DerObjectIdentifier SecT239k1 = new DerObjectIdentifier(EllipticCurve + ".3"); + public static readonly DerObjectIdentifier SecT113r1 = new DerObjectIdentifier(EllipticCurve + ".4"); + public static readonly DerObjectIdentifier SecT113r2 = new DerObjectIdentifier(EllipticCurve + ".5"); + public static readonly DerObjectIdentifier SecP112r1 = new DerObjectIdentifier(EllipticCurve + ".6"); + public static readonly DerObjectIdentifier SecP112r2 = new DerObjectIdentifier(EllipticCurve + ".7"); + public static readonly DerObjectIdentifier SecP160r1 = new DerObjectIdentifier(EllipticCurve + ".8"); + public static readonly DerObjectIdentifier SecP160k1 = new DerObjectIdentifier(EllipticCurve + ".9"); + public static readonly DerObjectIdentifier SecP256k1 = new DerObjectIdentifier(EllipticCurve + ".10"); + public static readonly DerObjectIdentifier SecT163r2 = new DerObjectIdentifier(EllipticCurve + ".15"); + public static readonly DerObjectIdentifier SecT283k1 = new DerObjectIdentifier(EllipticCurve + ".16"); + public static readonly DerObjectIdentifier SecT283r1 = new DerObjectIdentifier(EllipticCurve + ".17"); + public static readonly DerObjectIdentifier SecT131r1 = new DerObjectIdentifier(EllipticCurve + ".22"); + public static readonly DerObjectIdentifier SecT131r2 = new DerObjectIdentifier(EllipticCurve + ".23"); + public static readonly DerObjectIdentifier SecT193r1 = new DerObjectIdentifier(EllipticCurve + ".24"); + public static readonly DerObjectIdentifier SecT193r2 = new DerObjectIdentifier(EllipticCurve + ".25"); + public static readonly DerObjectIdentifier SecT233k1 = new DerObjectIdentifier(EllipticCurve + ".26"); + public static readonly DerObjectIdentifier SecT233r1 = new DerObjectIdentifier(EllipticCurve + ".27"); + public static readonly DerObjectIdentifier SecP128r1 = new DerObjectIdentifier(EllipticCurve + ".28"); + public static readonly DerObjectIdentifier SecP128r2 = new DerObjectIdentifier(EllipticCurve + ".29"); + public static readonly DerObjectIdentifier SecP160r2 = new DerObjectIdentifier(EllipticCurve + ".30"); + public static readonly DerObjectIdentifier SecP192k1 = new DerObjectIdentifier(EllipticCurve + ".31"); + public static readonly DerObjectIdentifier SecP224k1 = new DerObjectIdentifier(EllipticCurve + ".32"); + public static readonly DerObjectIdentifier SecP224r1 = new DerObjectIdentifier(EllipticCurve + ".33"); + public static readonly DerObjectIdentifier SecP384r1 = new DerObjectIdentifier(EllipticCurve + ".34"); + public static readonly DerObjectIdentifier SecP521r1 = new DerObjectIdentifier(EllipticCurve + ".35"); + public static readonly DerObjectIdentifier SecT409k1 = new DerObjectIdentifier(EllipticCurve + ".36"); + public static readonly DerObjectIdentifier SecT409r1 = new DerObjectIdentifier(EllipticCurve + ".37"); + public static readonly DerObjectIdentifier SecT571k1 = new DerObjectIdentifier(EllipticCurve + ".38"); + public static readonly DerObjectIdentifier SecT571r1 = new DerObjectIdentifier(EllipticCurve + ".39"); + + public static readonly DerObjectIdentifier SecP192r1 = X9ObjectIdentifiers.Prime192v1; + public static readonly DerObjectIdentifier SecP256r1 = X9ObjectIdentifiers.Prime256v1; + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/asn1/smime/SMIMEAttributes.cs b/iTechSharp/srcbc/asn1/smime/SMIMEAttributes.cs new file mode 100644 index 0000000..e154e5e --- /dev/null +++ b/iTechSharp/srcbc/asn1/smime/SMIMEAttributes.cs @@ -0,0 +1,11 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.Smime +{ + public abstract class SmimeAttributes + { + public static readonly DerObjectIdentifier SmimeCapabilities = PkcsObjectIdentifiers.Pkcs9AtSmimeCapabilities; + public static readonly DerObjectIdentifier EncrypKeyPref = PkcsObjectIdentifiers.IdAAEncrypKeyPref; + } +} diff --git a/iTechSharp/srcbc/asn1/smime/SMIMECapabilities.cs b/iTechSharp/srcbc/asn1/smime/SMIMECapabilities.cs new file mode 100644 index 0000000..62a3774 --- /dev/null +++ b/iTechSharp/srcbc/asn1/smime/SMIMECapabilities.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Smime +{ + /** + * Handler class for dealing with S/MIME Capabilities + */ + public class SmimeCapabilities + : Asn1Encodable + { + /** + * general preferences + */ + public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData; + public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny; + public static readonly DerObjectIdentifier SmimeCapabilitesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions; + + /** + * encryption algorithms preferences + */ + public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7"); + public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc; + public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc; + + private Asn1Sequence capabilities; + + /** + * return an Attr object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static SmimeCapabilities GetInstance( + object obj) + { + if (obj == null || obj is SmimeCapabilities) + { + return (SmimeCapabilities) obj; + } + + if (obj is Asn1Sequence) + { + return new SmimeCapabilities((Asn1Sequence) obj); + } + + if (obj is AttributeX509) + { + return new SmimeCapabilities( + (Asn1Sequence)(((AttributeX509) obj).AttrValues[0])); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public SmimeCapabilities( + Asn1Sequence seq) + { + capabilities = seq; + } + + /** + * returns an ArrayList with 0 or more objects of all the capabilities + * matching the passed in capability Oid. If the Oid passed is null the + * entire set is returned. + */ + public ArrayList GetCapabilities( + DerObjectIdentifier capability) + { + ArrayList list = new ArrayList(); + + if (capability == null) + { + foreach (object o in capabilities) + { + SmimeCapability cap = SmimeCapability.GetInstance(o); + + list.Add(cap); + } + } + else + { + foreach (object o in capabilities) + { + SmimeCapability cap = SmimeCapability.GetInstance(o); + + if (capability.Equals(cap.CapabilityID)) + { + list.Add(cap); + } + } + } + + return list; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * SMIMECapabilities ::= Sequence OF SMIMECapability
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return capabilities; + } + } +} diff --git a/iTechSharp/srcbc/asn1/smime/SMIMECapabilitiesAttribute.cs b/iTechSharp/srcbc/asn1/smime/SMIMECapabilitiesAttribute.cs new file mode 100644 index 0000000..310c478 --- /dev/null +++ b/iTechSharp/srcbc/asn1/smime/SMIMECapabilitiesAttribute.cs @@ -0,0 +1,16 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Smime +{ + public class SmimeCapabilitiesAttribute + : AttributeX509 + { + public SmimeCapabilitiesAttribute( + SmimeCapabilityVector capabilities) + : base(SmimeAttributes.SmimeCapabilities, + new DerSet(new DerSequence(capabilities.ToAsn1EncodableVector()))) + { + } + } +} diff --git a/iTechSharp/srcbc/asn1/smime/SMIMECapability.cs b/iTechSharp/srcbc/asn1/smime/SMIMECapability.cs new file mode 100644 index 0000000..5709cb8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/smime/SMIMECapability.cs @@ -0,0 +1,101 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.Smime +{ + public class SmimeCapability + : Asn1Encodable + { + /** + * general preferences + */ + public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData; + public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny; + public static readonly DerObjectIdentifier SmimeCapabilitiesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions; + + /** + * encryption algorithms preferences + */ + public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7"); + public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc; + public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc; + + private DerObjectIdentifier capabilityID; + private Asn1Object parameters; + + public SmimeCapability( + Asn1Sequence seq) + { + capabilityID = (DerObjectIdentifier) seq[0].ToAsn1Object(); + + if (seq.Count > 1) + { + parameters = seq[1].ToAsn1Object(); + } + } + + public SmimeCapability( + DerObjectIdentifier capabilityID, + Asn1Encodable parameters) + { + if (capabilityID == null) + throw new ArgumentNullException("capabilityID"); + + this.capabilityID = capabilityID; + + if (parameters != null) + { + this.parameters = parameters.ToAsn1Object(); + } + } + + public static SmimeCapability GetInstance( + object obj) + { + if (obj == null || obj is SmimeCapability) + { + return (SmimeCapability) obj; + } + + if (obj is Asn1Sequence) + { + return new SmimeCapability((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid SmimeCapability"); + } + + public DerObjectIdentifier CapabilityID + { + get { return capabilityID; } + } + + public Asn1Object Parameters + { + get { return parameters; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * SMIMECapability ::= Sequence {
      +         *     capabilityID OBJECT IDENTIFIER,
      +         *     parameters ANY DEFINED BY capabilityID OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(capabilityID); + + if (parameters != null) + { + v.Add(parameters); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/smime/SMIMECapabilityVector.cs b/iTechSharp/srcbc/asn1/smime/SMIMECapabilityVector.cs new file mode 100644 index 0000000..842825b --- /dev/null +++ b/iTechSharp/srcbc/asn1/smime/SMIMECapabilityVector.cs @@ -0,0 +1,37 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Smime +{ + /** + * Handler for creating a vector S/MIME Capabilities + */ + public class SmimeCapabilityVector + { + private readonly Asn1EncodableVector capabilities = new Asn1EncodableVector(); + + public void AddCapability( + DerObjectIdentifier capability) + { + capabilities.Add(new DerSequence(capability)); + } + + public void AddCapability( + DerObjectIdentifier capability, + int value) + { + capabilities.Add(new DerSequence(capability, new DerInteger(value))); + } + + public void AddCapability( + DerObjectIdentifier capability, + Asn1Encodable parameters) + { + capabilities.Add(new DerSequence(capability, parameters)); + } + + public Asn1EncodableVector ToAsn1EncodableVector() + { + return capabilities; + } + } +} diff --git a/iTechSharp/srcbc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs b/iTechSharp/srcbc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs new file mode 100644 index 0000000..19c5fd7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs @@ -0,0 +1,44 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Smime +{ + /** + * The SmimeEncryptionKeyPreference object. + *
      +     * SmimeEncryptionKeyPreference ::= CHOICE {
      +     *     issuerAndSerialNumber   [0] IssuerAndSerialNumber,
      +     *     receipentKeyId          [1] RecipientKeyIdentifier,
      +     *     subjectAltKeyIdentifier [2] SubjectKeyIdentifier
      +     * }
      +     * 
      + */ + public class SmimeEncryptionKeyPreferenceAttribute + : AttributeX509 + { + public SmimeEncryptionKeyPreferenceAttribute( + IssuerAndSerialNumber issAndSer) + : base(SmimeAttributes.EncrypKeyPref, + new DerSet(new DerTaggedObject(false, 0, issAndSer))) + { + } + + public SmimeEncryptionKeyPreferenceAttribute( + RecipientKeyIdentifier rKeyID) + : base(SmimeAttributes.EncrypKeyPref, + new DerSet(new DerTaggedObject(false, 1, rKeyID))) + { + } + + /** + * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one) + */ + public SmimeEncryptionKeyPreferenceAttribute( + Asn1OctetString sKeyID) + : base(SmimeAttributes.EncrypKeyPref, + new DerSet(new DerTaggedObject(false, 2, sKeyID))) + { + } + } +} diff --git a/iTechSharp/srcbc/asn1/teletrust/TeleTrusTNamedCurves.cs b/iTechSharp/srcbc/asn1/teletrust/TeleTrusTNamedCurves.cs new file mode 100644 index 0000000..25032dd --- /dev/null +++ b/iTechSharp/srcbc/asn1/teletrust/TeleTrusTNamedCurves.cs @@ -0,0 +1,427 @@ +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.TeleTrust +{ + /** + * elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation" + * http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt + */ + public class TeleTrusTNamedCurves + { + internal class BrainpoolP160r1Holder + : X9ECParametersHolder + { + private BrainpoolP160r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP160r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q + new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a + new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G + new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP160t1Holder + : X9ECParametersHolder + { + private BrainpoolP160t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP160t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + // new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a' + new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G + new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP192r1Holder + : X9ECParametersHolder + { + private BrainpoolP192r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP192r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q + new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a + new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G + new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP192t1Holder + : X9ECParametersHolder + { + private BrainpoolP192t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP192t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + //new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a' + new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G' + new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP224r1Holder + : X9ECParametersHolder + { + private BrainpoolP224r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP224r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q + new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a + new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G + new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n + new BigInteger("01", 16)); // n + } + } + + internal class BrainpoolP224t1Holder + : X9ECParametersHolder + { + private BrainpoolP224t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP224t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + //new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a' + new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G' + new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP256r1Holder + : X9ECParametersHolder + { + private BrainpoolP256r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP256r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q + new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a + new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP256t1Holder + : X9ECParametersHolder + { + private BrainpoolP256t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP256t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + //new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a' + new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G' + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP320r1Holder + : X9ECParametersHolder + { + private BrainpoolP320r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP320r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q + new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a + new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP320t1Holder + : X9ECParametersHolder + { + private BrainpoolP320t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP320t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + //new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a' + new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G' + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP384r1Holder + : X9ECParametersHolder + { + private BrainpoolP384r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP384r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q + new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a + new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP384t1Holder + : X9ECParametersHolder + { + private BrainpoolP384t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP384t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + //new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a' + new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G' + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP512r1Holder + : X9ECParametersHolder + { + private BrainpoolP512r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP512r1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q + new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a + new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16)); // b + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n + new BigInteger("01", 16)); // h + } + } + + internal class BrainpoolP512t1Holder + : X9ECParametersHolder + { + private BrainpoolP512t1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new BrainpoolP512t1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve curve = new FpCurve( + //new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a' + new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)); // b' + + return new X9ECParameters( + curve, + curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G' + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n + new BigInteger("01", 16)); // h + } + } + + + private static readonly Hashtable objIds = new Hashtable(); + private static readonly Hashtable curves = new Hashtable(); + private static readonly Hashtable names = new Hashtable(); + + private static void DefineCurve( + string name, + DerObjectIdentifier oid, + X9ECParametersHolder holder) + { + objIds.Add(name, oid); + names.Add(oid, name); + curves.Add(oid, holder); + } + + static TeleTrusTNamedCurves() + { + DefineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance); + DefineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance); + DefineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance); + DefineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance); + DefineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance); + DefineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance); + DefineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance); + DefineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance); + DefineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance); + DefineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance); + DefineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance); + DefineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance); + DefineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance); + DefineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance); + } + + public static X9ECParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) + objIds[name.ToLower(CultureInfo.InvariantCulture)]; + + return oid == null ? null : GetByOid(oid); + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters GetByOid( + DerObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid]; + + return holder == null ? null : holder.Parameters; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier) objIds[name.ToLower(CultureInfo.InvariantCulture)]; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string) names[oid]; + } + + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + + public static DerObjectIdentifier GetOid( + short curvesize, + bool twisted) + { + return GetOid("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/teletrust/TeleTrusTObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/teletrust/TeleTrusTObjectIdentifiers.cs new file mode 100644 index 0000000..56e7084 --- /dev/null +++ b/iTechSharp/srcbc/asn1/teletrust/TeleTrusTObjectIdentifiers.cs @@ -0,0 +1,45 @@ +namespace Org.BouncyCastle.Asn1.TeleTrust +{ + public sealed class TeleTrusTObjectIdentifiers + { + private TeleTrusTObjectIdentifiers() + { + } + + public static readonly DerObjectIdentifier TeleTrusTAlgorithm = new DerObjectIdentifier("1.3.36.3"); + + public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.1"); + public static readonly DerObjectIdentifier RipeMD128 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.2"); + public static readonly DerObjectIdentifier RipeMD256 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.3"); + + public static readonly DerObjectIdentifier TeleTrusTRsaSignatureAlgorithm = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.1"); + + public static readonly DerObjectIdentifier RsaSignatureWithRipeMD160 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".2"); + public static readonly DerObjectIdentifier RsaSignatureWithRipeMD128 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".3"); + public static readonly DerObjectIdentifier RsaSignatureWithRipeMD256 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".4"); + + public static readonly DerObjectIdentifier ECSign = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2"); + + public static readonly DerObjectIdentifier ECSignWithSha1 = new DerObjectIdentifier(ECSign + ".1"); + public static readonly DerObjectIdentifier ECSignWithRipeMD160 = new DerObjectIdentifier(ECSign + ".2"); + + public static readonly DerObjectIdentifier EccBrainpool = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2.8"); + public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(EccBrainpool + ".1"); + public static readonly DerObjectIdentifier VersionOne = new DerObjectIdentifier(EllipticCurve + ".1"); + + public static readonly DerObjectIdentifier BrainpoolP160R1 = new DerObjectIdentifier(VersionOne + ".1"); + public static readonly DerObjectIdentifier BrainpoolP160T1 = new DerObjectIdentifier(VersionOne + ".2"); + public static readonly DerObjectIdentifier BrainpoolP192R1 = new DerObjectIdentifier(VersionOne + ".3"); + public static readonly DerObjectIdentifier BrainpoolP192T1 = new DerObjectIdentifier(VersionOne + ".4"); + public static readonly DerObjectIdentifier BrainpoolP224R1 = new DerObjectIdentifier(VersionOne + ".5"); + public static readonly DerObjectIdentifier BrainpoolP224T1 = new DerObjectIdentifier(VersionOne + ".6"); + public static readonly DerObjectIdentifier BrainpoolP256R1 = new DerObjectIdentifier(VersionOne + ".7"); + public static readonly DerObjectIdentifier BrainpoolP256T1 = new DerObjectIdentifier(VersionOne + ".8"); + public static readonly DerObjectIdentifier BrainpoolP320R1 = new DerObjectIdentifier(VersionOne + ".9"); + public static readonly DerObjectIdentifier BrainpoolP320T1 = new DerObjectIdentifier(VersionOne + ".10"); + public static readonly DerObjectIdentifier BrainpoolP384R1 = new DerObjectIdentifier(VersionOne + ".11"); + public static readonly DerObjectIdentifier BrainpoolP384T1 = new DerObjectIdentifier(VersionOne + ".12"); + public static readonly DerObjectIdentifier BrainpoolP512R1 = new DerObjectIdentifier(VersionOne + ".13"); + public static readonly DerObjectIdentifier BrainpoolP512T1 = new DerObjectIdentifier(VersionOne + ".14"); + } +} diff --git a/iTechSharp/srcbc/asn1/tsp/Accuracy.cs b/iTechSharp/srcbc/asn1/tsp/Accuracy.cs new file mode 100644 index 0000000..a193f52 --- /dev/null +++ b/iTechSharp/srcbc/asn1/tsp/Accuracy.cs @@ -0,0 +1,149 @@ +using System; + +namespace Org.BouncyCastle.Asn1.Tsp +{ + public class Accuracy + : Asn1Encodable + { + private readonly DerInteger seconds; + private readonly DerInteger millis; + private readonly DerInteger micros; + + // constants + protected const int MinMillis = 1; + protected const int MaxMillis = 999; + protected const int MinMicros = 1; + protected const int MaxMicros = 999; + + public Accuracy( + DerInteger seconds, + DerInteger millis, + DerInteger micros) + { + //Verifications + if (millis != null + && (millis.Value.IntValue < MinMillis + || millis.Value.IntValue > MaxMillis)) + { + throw new ArgumentException( + "Invalid millis field : not in (1..999)"); + } + + if (micros != null + && (micros.Value.IntValue < MinMicros + || micros.Value.IntValue > MaxMicros)) + { + throw new ArgumentException( + "Invalid micros field : not in (1..999)"); + } + + this.seconds = seconds; + this.millis = millis; + this.micros = micros; + } + + private Accuracy( + Asn1Sequence seq) + { + for (int i = 0; i < seq.Count; ++i) + { + // seconds + if (seq[i] is DerInteger) + { + seconds = (DerInteger) seq[i]; + } + else if (seq[i] is DerTaggedObject) + { + DerTaggedObject extra = (DerTaggedObject) seq[i]; + + switch (extra.TagNo) + { + case 0: + millis = DerInteger.GetInstance(extra, false); + if (millis.Value.IntValue < MinMillis + || millis.Value.IntValue > MaxMillis) + { + throw new ArgumentException( + "Invalid millis field : not in (1..999)."); + } + break; + case 1: + micros = DerInteger.GetInstance(extra, false); + if (micros.Value.IntValue < MinMicros + || micros.Value.IntValue > MaxMicros) + { + throw new ArgumentException( + "Invalid micros field : not in (1..999)."); + } + break; + default: + throw new ArgumentException("Invalig tag number"); + } + } + } + } + + public static Accuracy GetInstance( + object o) + { + if (o == null || o is Accuracy) + { + return (Accuracy) o; + } + + if (o is Asn1Sequence) + { + return new Accuracy((Asn1Sequence) o); + } + + throw new ArgumentException( + "Unknown object in 'Accuracy' factory: " + o.GetType().FullName); + } + + public DerInteger Seconds + { + get { return seconds; } + } + + public DerInteger Millis + { + get { return millis; } + } + + public DerInteger Micros + { + get { return micros; } + } + + /** + *
      +		 * Accuracy ::= SEQUENCE {
      +		 *             seconds        INTEGER              OPTIONAL,
      +		 *             millis     [0] INTEGER  (1..999)    OPTIONAL,
      +		 *             micros     [1] INTEGER  (1..999)    OPTIONAL
      +		 *             }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (seconds != null) + { + v.Add(seconds); + } + + if (millis != null) + { + v.Add(new DerTaggedObject(false, 0, millis)); + } + + if (micros != null) + { + v.Add(new DerTaggedObject(false, 1, micros)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/tsp/MessageImprint.cs b/iTechSharp/srcbc/asn1/tsp/MessageImprint.cs new file mode 100644 index 0000000..0933bae --- /dev/null +++ b/iTechSharp/srcbc/asn1/tsp/MessageImprint.cs @@ -0,0 +1,74 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Tsp +{ + public class MessageImprint + : Asn1Encodable + { + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly byte[] hashedMessage; + + /** + * @param o + * @return a MessageImprint object. + */ + public static MessageImprint GetInstance( + object o) + { + if (o == null || o is MessageImprint) + { + return (MessageImprint) o; + } + + if (o is Asn1Sequence) + { + return new MessageImprint((Asn1Sequence) o); + } + + throw new ArgumentException( + "Unknown object in 'MessageImprint' factory: " + o.GetType().FullName); + } + + private MessageImprint( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]); + this.hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets(); + } + + public MessageImprint( + AlgorithmIdentifier hashAlgorithm, + byte[] hashedMessage) + { + this.hashAlgorithm = hashAlgorithm; + this.hashedMessage = hashedMessage; + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public byte[] GetHashedMessage() + { + return hashedMessage; + } + + /** + *
      +		 *    MessageImprint ::= SEQUENCE  {
      +		 *       hashAlgorithm                AlgorithmIdentifier,
      +		 *       hashedMessage                OCTET STRING  }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(hashAlgorithm, new DerOctetString(hashedMessage)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/tsp/TSTInfo.cs b/iTechSharp/srcbc/asn1/tsp/TSTInfo.cs new file mode 100644 index 0000000..c05c670 --- /dev/null +++ b/iTechSharp/srcbc/asn1/tsp/TSTInfo.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Tsp +{ + public class TstInfo + : Asn1Encodable + { + private readonly DerInteger version; + private readonly DerObjectIdentifier tsaPolicyId; + private readonly MessageImprint messageImprint; + private readonly DerInteger serialNumber; + private readonly DerGeneralizedTime genTime; + private readonly Accuracy accuracy; + private readonly DerBoolean ordering; + private readonly DerInteger nonce; + private readonly GeneralName tsa; + private readonly X509Extensions extensions; + + public static TstInfo GetInstance( + object o) + { + if (o == null || o is TstInfo) + { + return (TstInfo) o; + } + + if (o is Asn1Sequence) + { + return new TstInfo((Asn1Sequence) o); + } + + if (o is Asn1OctetString) + { + try + { + byte[] octets = ((Asn1OctetString)o).GetOctets(); + return GetInstance(Asn1Object.FromByteArray(octets)); + } + catch (IOException) + { + throw new ArgumentException( + "Bad object format in 'TstInfo' factory."); + } + } + + throw new ArgumentException( + "Unknown object in 'TstInfo' factory: " + o.GetType().FullName); + } + + private TstInfo( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + // version + e.MoveNext(); + version = DerInteger.GetInstance(e.Current); + + // tsaPolicy + e.MoveNext(); + tsaPolicyId = DerObjectIdentifier.GetInstance(e.Current); + + // messageImprint + e.MoveNext(); + messageImprint = MessageImprint.GetInstance(e.Current); + + // serialNumber + e.MoveNext(); + serialNumber = DerInteger.GetInstance(e.Current); + + // genTime + e.MoveNext(); + genTime = DerGeneralizedTime.GetInstance(e.Current); + + // default for ordering + ordering = DerBoolean.False; + + while (e.MoveNext()) + { + Asn1Object o = (Asn1Object) e.Current; + + if (o is Asn1TaggedObject) + { + DerTaggedObject tagged = (DerTaggedObject) o; + + switch (tagged.TagNo) + { + case 0: + tsa = GeneralName.GetInstance(tagged, true); + break; + case 1: + extensions = X509Extensions.GetInstance(tagged, false); + break; + default: + throw new ArgumentException("Unknown tag value " + tagged.TagNo); + } + } + + if (o is DerSequence) + { + accuracy = Accuracy.GetInstance(o); + } + + if (o is DerBoolean) + { + ordering = DerBoolean.GetInstance(o); + } + + if (o is DerInteger) + { + nonce = DerInteger.GetInstance(o); + } + } + } + + public TstInfo( + DerObjectIdentifier tsaPolicyId, + MessageImprint messageImprint, + DerInteger serialNumber, + DerGeneralizedTime genTime, + Accuracy accuracy, + DerBoolean ordering, + DerInteger nonce, + GeneralName tsa, + X509Extensions extensions) + { + this.version = new DerInteger(1); + this.tsaPolicyId = tsaPolicyId; + this.messageImprint = messageImprint; + this.serialNumber = serialNumber; + this.genTime = genTime; + this.accuracy = accuracy; + this.ordering = ordering; + this.nonce = nonce; + this.tsa = tsa; + this.extensions = extensions; + } + + public MessageImprint MessageImprint + { + get { return messageImprint; } + } + + public DerObjectIdentifier Policy + { + get { return tsaPolicyId; } + } + + public DerInteger SerialNumber + { + get { return serialNumber; } + } + + public Accuracy Accuracy + { + get { return accuracy; } + } + + public DerGeneralizedTime GenTime + { + get { return genTime; } + } + + public DerBoolean Ordering + { + get { return ordering; } + } + + public DerInteger Nonce + { + get { return nonce; } + } + + public GeneralName Tsa + { + get { return tsa; } + } + + public X509Extensions Extensions + { + get { return extensions; } + } + + /** + *
      +		 *
      +		 *     TstInfo ::= SEQUENCE  {
      +		 *        version                      INTEGER  { v1(1) },
      +		 *        policy                       TSAPolicyId,
      +		 *        messageImprint               MessageImprint,
      +		 *          -- MUST have the same value as the similar field in
      +		 *          -- TimeStampReq
      +		 *        serialNumber                 INTEGER,
      +		 *         -- Time-Stamping users MUST be ready to accommodate integers
      +		 *         -- up to 160 bits.
      +		 *        genTime                      GeneralizedTime,
      +		 *        accuracy                     Accuracy                 OPTIONAL,
      +		 *        ordering                     BOOLEAN             DEFAULT FALSE,
      +		 *        nonce                        INTEGER                  OPTIONAL,
      +		 *          -- MUST be present if the similar field was present
      +		 *          -- in TimeStampReq.  In that case it MUST have the same value.
      +		 *        tsa                          [0] GeneralName          OPTIONAL,
      +		 *        extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
      +		 *
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, tsaPolicyId, messageImprint, serialNumber, genTime); + + if (accuracy != null) + { + v.Add(accuracy); + } + + if (ordering != null && ordering.IsTrue) + { + v.Add(ordering); + } + + if (nonce != null) + { + v.Add(nonce); + } + + if (tsa != null) + { + v.Add(new DerTaggedObject(true, 0, tsa)); + } + + if (extensions != null) + { + v.Add(new DerTaggedObject(false, 1, extensions)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/tsp/TimeStampReq.cs b/iTechSharp/srcbc/asn1/tsp/TimeStampReq.cs new file mode 100644 index 0000000..55e973e --- /dev/null +++ b/iTechSharp/srcbc/asn1/tsp/TimeStampReq.cs @@ -0,0 +1,164 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Tsp +{ + public class TimeStampReq + : Asn1Encodable + { + private readonly DerInteger version; + private readonly MessageImprint messageImprint; + private readonly DerObjectIdentifier tsaPolicy; + private readonly DerInteger nonce; + private readonly DerBoolean certReq; + private readonly X509Extensions extensions; + + public static TimeStampReq GetInstance( + object o) + { + if (o == null || o is TimeStampReq) + { + return (TimeStampReq) o; + } + + if (o is Asn1Sequence) + { + return new TimeStampReq((Asn1Sequence) o); + } + + throw new ArgumentException( + "Unknown object in 'TimeStampReq' factory: " + o.GetType().FullName); + } + + private TimeStampReq( + Asn1Sequence seq) + { + int nbObjects = seq.Count; + int seqStart = 0; + + // version + version = DerInteger.GetInstance(seq[seqStart++]); + + // messageImprint + messageImprint = MessageImprint.GetInstance(seq[seqStart++]); + + for (int opt = seqStart; opt < nbObjects; opt++) + { + // tsaPolicy + if (seq[opt] is DerObjectIdentifier) + { + tsaPolicy = DerObjectIdentifier.GetInstance(seq[opt]); + } + // nonce + else if (seq[opt] is DerInteger) + { + nonce = DerInteger.GetInstance(seq[opt]); + } + // certReq + else if (seq[opt] is DerBoolean) + { + certReq = DerBoolean.GetInstance(seq[opt]); + } + // extensions + else if (seq[opt] is Asn1TaggedObject) + { + Asn1TaggedObject tagged = (Asn1TaggedObject) seq[opt]; + if (tagged.TagNo == 0) + { + extensions = X509Extensions.GetInstance(tagged, false); + } + } + } + } + + public TimeStampReq( + MessageImprint messageImprint, + DerObjectIdentifier tsaPolicy, + DerInteger nonce, + DerBoolean certReq, + X509Extensions extensions) + { + // default + this.version = new DerInteger(1); + + this.messageImprint = messageImprint; + this.tsaPolicy = tsaPolicy; + this.nonce = nonce; + this.certReq = certReq; + this.extensions = extensions; + } + + public DerInteger Version + { + get { return version; } + } + + public MessageImprint MessageImprint + { + get { return messageImprint; } + } + + public DerObjectIdentifier ReqPolicy + { + get { return tsaPolicy; } + } + + public DerInteger Nonce + { + get { return nonce; } + } + + public DerBoolean CertReq + { + get { return certReq; } + } + + public X509Extensions Extensions + { + get { return extensions; } + } + + /** + *
      +		 * TimeStampReq ::= SEQUENCE  {
      +		 *  version                      INTEGER  { v1(1) },
      +		 *  messageImprint               MessageImprint,
      +		 *    --a hash algorithm OID and the hash value of the data to be
      +		 *    --time-stamped
      +		 *  reqPolicy             TSAPolicyId              OPTIONAL,
      +		 *  nonce                 INTEGER                  OPTIONAL,
      +		 *  certReq               BOOLEAN                  DEFAULT FALSE,
      +		 *  extensions            [0] IMPLICIT Extensions  OPTIONAL
      +		 * }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, messageImprint); + + if (tsaPolicy != null) + { + v.Add(tsaPolicy); + } + + if (nonce != null) + { + v.Add(nonce); + } + + if (certReq != null && certReq.IsTrue) + { + v.Add(certReq); + } + + if (extensions != null) + { + v.Add(new DerTaggedObject(false, 0, extensions)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/tsp/TimeStampResp.cs b/iTechSharp/srcbc/asn1/tsp/TimeStampResp.cs new file mode 100644 index 0000000..f26fb30 --- /dev/null +++ b/iTechSharp/srcbc/asn1/tsp/TimeStampResp.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.Cms; + +namespace Org.BouncyCastle.Asn1.Tsp +{ + public class TimeStampResp + : Asn1Encodable + { + private readonly PkiStatusInfo pkiStatusInfo; + private readonly ContentInfo timeStampToken; + + public static TimeStampResp GetInstance( + object o) + { + if (o == null || o is TimeStampResp) + { + return (TimeStampResp) o; + } + + if (o is Asn1Sequence) + { + return new TimeStampResp((Asn1Sequence) o); + } + + throw new ArgumentException( + "Unknown object in 'TimeStampResp' factory: " + o.GetType().FullName); + } + + private TimeStampResp( + Asn1Sequence seq) + { + this.pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]); + + if (seq.Count > 1) + { + this.timeStampToken = ContentInfo.GetInstance(seq[1]); + } + } + + public TimeStampResp( + PkiStatusInfo pkiStatusInfo, + ContentInfo timeStampToken) + { + this.pkiStatusInfo = pkiStatusInfo; + this.timeStampToken = timeStampToken; + } + + public PkiStatusInfo Status + { + get { return pkiStatusInfo; } + } + + public ContentInfo TimeStampToken + { + get { return timeStampToken; } + } + + /** + *
      +		 * TimeStampResp ::= SEQUENCE  {
      +		 *   status                  PkiStatusInfo,
      +		 *   timeStampToken          TimeStampToken     OPTIONAL  }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo); + + if (timeStampToken != null) + { + v.Add(timeStampToken); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/util/Asn1Dump.cs b/iTechSharp/srcbc/asn1/util/Asn1Dump.cs new file mode 100644 index 0000000..3f4b995 --- /dev/null +++ b/iTechSharp/srcbc/asn1/util/Asn1Dump.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections; +using System.Text; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.Utilities +{ + public sealed class Asn1Dump + { + private static readonly string NewLine = Platform.NewLine; + + private Asn1Dump() + { + } + + private const string Tab = " "; + + /** + * dump a Der object as a formatted string with indentation + * + * @param obj the Asn1Object to be dumped out. + */ + private static string AsString( + string indent, + Asn1Object obj) + { + if (obj is Asn1Sequence) + { + StringBuilder buf = new StringBuilder(indent); + + string tab = indent + Tab; + + if (obj is BerSequence) + { + buf.Append("BER Sequence"); + } + else if (obj is DerSequence) + { + buf.Append("DER Sequence"); + } + else + { + buf.Append("Sequence"); + } + + buf.Append(NewLine); + + foreach (Asn1Encodable o in ((Asn1Sequence)obj)) + { + if (o == null || o is Asn1Null) + { + buf.Append(tab); + buf.Append("NULL"); + buf.Append(NewLine); + } + else + { + buf.Append(AsString(tab, o.ToAsn1Object())); + } + } + return buf.ToString(); + } + else if (obj is DerTaggedObject) + { + StringBuilder buf = new StringBuilder(); + string tab = indent + Tab; + + buf.Append(indent); + if (obj is BerTaggedObject) + { + buf.Append("BER Tagged ["); + } + else + { + buf.Append("Tagged ["); + } + + DerTaggedObject o = (DerTaggedObject)obj; + + buf.Append(((int)o.TagNo).ToString()); + buf.Append(']'); + + if (!o.IsExplicit()) + { + buf.Append(" IMPLICIT "); + } + + buf.Append(NewLine); + + if (o.IsEmpty()) + { + buf.Append(tab); + buf.Append("EMPTY"); + buf.Append(NewLine); + } + else + { + buf.Append(AsString(tab, o.GetObject())); + } + + return buf.ToString(); + } + else if (obj is BerSet) + { + StringBuilder buf = new StringBuilder(); + string tab = indent + Tab; + + buf.Append(indent); + buf.Append("BER Set"); + buf.Append(NewLine); + + foreach (Asn1Encodable o in ((Asn1Set)obj)) + { + if (o == null) + { + buf.Append(tab); + buf.Append("NULL"); + buf.Append(NewLine); + } + else + { + buf.Append(AsString(tab, o.ToAsn1Object())); + } + } + + return buf.ToString(); + } + else if (obj is DerSet) + { + StringBuilder buf = new StringBuilder(); + string tab = indent + Tab; + + buf.Append(indent); + buf.Append("DER Set"); + buf.Append(NewLine); + + foreach (Asn1Encodable o in ((Asn1Set)obj)) + { + if (o == null) + { + buf.Append(tab); + buf.Append("NULL"); + buf.Append(NewLine); + } + else + { + buf.Append(AsString(tab, o.ToAsn1Object())); + } + } + + return buf.ToString(); + } + else if (obj is DerObjectIdentifier) + { + return indent + "ObjectIdentifier(" + ((DerObjectIdentifier)obj).Id + ")" + NewLine; + } + else if (obj is DerBoolean) + { + return indent + "Boolean(" + ((DerBoolean)obj).IsTrue + ")" + NewLine; + } + else if (obj is DerInteger) + { + return indent + "Integer(" + ((DerInteger)obj).Value + ")" + NewLine; + } + else if (obj is BerOctetString) + { + return indent + "BER Octet String" + "[" + ((Asn1OctetString)obj).GetOctets().Length + "] " + NewLine; + } + else if (obj is DerOctetString) + { + return indent + "DER Octet String" + "[" + ((Asn1OctetString)obj).GetOctets().Length + "] " + NewLine; + } + else if (obj is DerBitString) + { + return indent + "DER Bit String" + "[" + ((DerBitString)obj).GetBytes().Length + ", " + ((DerBitString)obj).PadBits + "] " + NewLine; + } + else if (obj is DerIA5String) + { + return indent + "IA5String(" + ((DerIA5String)obj).GetString() + ") " + NewLine; + } + else if (obj is DerUtf8String) + { + return indent + "UTF8String(" + ((DerUtf8String)obj).GetString() + ") " + NewLine; + } + else if (obj is DerPrintableString) + { + return indent + "PrintableString(" + ((DerPrintableString)obj).GetString() + ") " + NewLine; + } + else if (obj is DerVisibleString) + { + return indent + "VisibleString(" + ((DerVisibleString)obj).GetString() + ") " + NewLine; + } + else if (obj is DerBmpString) + { + return indent + "BMPString(" + ((DerBmpString)obj).GetString() + ") " + NewLine; + } + else if (obj is DerT61String) + { + return indent + "T61String(" + ((DerT61String)obj).GetString() + ") " + NewLine; + } + else if (obj is DerUtcTime) + { + return indent + "UTCTime(" + ((DerUtcTime)obj).TimeString + ") " + NewLine; + } + else if (obj is DerGeneralizedTime) + { + return indent + "GeneralizedTime(" + ((DerGeneralizedTime)obj).GetTime() + ") " + NewLine; + } + else if (obj is DerUnknownTag) + { + byte[] hex = Hex.Encode(((DerUnknownTag)obj).GetData()); + return indent + "Unknown " + ((int)((DerUnknownTag)obj).Tag).ToString("X") + " " + + Encoding.ASCII.GetString(hex, 0, hex.Length) + NewLine; + } + else + { + return indent + obj.ToString() + NewLine; + } + } + + [Obsolete("Use version accepting Asn1Encodable")] + public static string DumpAsString( + object obj) + { + if (obj is Asn1Object) + { + return AsString("", (Asn1Object)obj); + } + else if (obj is Asn1Encodable) + { + return AsString("", ((Asn1Encodable)obj).ToAsn1Object()); + } + + return "unknown object type " + obj.ToString(); + } + + /** + * dump out a DER object as a formatted string + * + * @param obj the Asn1Encodable to be dumped out. + */ + public static string DumpAsString( + Asn1Encodable obj) + { + return AsString("", obj.ToAsn1Object()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/util/Dump.cs b/iTechSharp/srcbc/asn1/util/Dump.cs new file mode 100644 index 0000000..27c87f1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/util/Dump.cs @@ -0,0 +1,28 @@ +using Org.BouncyCastle.Asn1; + +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1.Utilities +{ + public sealed class Dump + { + private Dump() + { + } + + public static void Main(string[] args) + { + FileStream fIn = File.OpenRead(args[0]); + Asn1InputStream bIn = new Asn1InputStream(fIn); + + Asn1Object obj; + while ((obj = bIn.ReadObject()) != null) + { + Console.WriteLine(Asn1Dump.DumpAsString(obj)); + } + + bIn.Close(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/util/FilterStream.cs b/iTechSharp/srcbc/asn1/util/FilterStream.cs new file mode 100644 index 0000000..27dc0af --- /dev/null +++ b/iTechSharp/srcbc/asn1/util/FilterStream.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1.Utilities +{ + public class FilterStream : Stream + { + public FilterStream(Stream s) + { + this.s = s; + } + public override bool CanRead + { + get { return s.CanRead; } + } + public override bool CanSeek + { + get { return s.CanSeek; } + } + public override bool CanWrite + { + get { return s.CanWrite; } + } + public override long Length + { + get { return s.Length; } + } + public override long Position + { + get { return s.Position; } + set { s.Position = value; } + } + public override void Close() + { + s.Close(); + } + public override void Flush() + { + s.Flush(); + } + public override long Seek(long offset, SeekOrigin origin) + { + return s.Seek(offset, origin); + } + public override void SetLength(long value) + { + s.SetLength(value); + } + public override int Read(byte[] buffer, int offset, int count) + { + return s.Read(buffer, offset, count); + } + public override int ReadByte() + { + return s.ReadByte(); + } + public override void Write(byte[] buffer, int offset, int count) + { + s.Write(buffer, offset, count); + } + public override void WriteByte(byte value) + { + s.WriteByte(value); + } + private readonly Stream s; + } +} diff --git a/iTechSharp/srcbc/asn1/x500/DirectoryString.cs b/iTechSharp/srcbc/asn1/x500/DirectoryString.cs new file mode 100644 index 0000000..8fb97db --- /dev/null +++ b/iTechSharp/srcbc/asn1/x500/DirectoryString.cs @@ -0,0 +1,76 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X500 +{ + public class DirectoryString + : Asn1Encodable, IAsn1String + //, Asn1Choice + { + private readonly DerStringBase str; + + public static DirectoryString GetInstance( + object obj) + { + if (obj is DirectoryString) + { + return (DirectoryString) obj; + } + + if (obj is DerStringBase) + { + if (obj is DerT61String + || obj is DerPrintableString + || obj is DerUniversalString + || obj is DerUtf8String + || obj is DerBmpString) + { + return new DirectoryString((DerStringBase) obj); + } + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static DirectoryString GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + if (!isExplicit) + throw new ArgumentException("choice item must be explicitly tagged"); + + return GetInstance(obj.GetObject()); + } + + private DirectoryString( + DerStringBase str) + { + this.str = str; + } + + public DirectoryString( + string str) + { + this.str = new DerUtf8String(str); + } + + public string GetString() + { + return str.GetString(); + } + + /** + *
      +		 *  DirectoryString ::= CHOICE {
      +		 *    teletexString               TeletexString (SIZE (1..MAX)),
      +		 *    printableString             PrintableString (SIZE (1..MAX)),
      +		 *    universalString             UniversalString (SIZE (1..MAX)),
      +		 *    utf8String                  UTF8String (SIZE (1..MAX)),
      +		 *    bmpString                   BMPString (SIZE (1..MAX))  }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + return str.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AccessDescription.cs b/iTechSharp/srcbc/asn1/x509/AccessDescription.cs new file mode 100644 index 0000000..a45f43b --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AccessDescription.cs @@ -0,0 +1,88 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The AccessDescription object. + *
      +	 * AccessDescription  ::=  SEQUENCE {
      +	 *       accessMethod          OBJECT IDENTIFIER,
      +	 *       accessLocation        GeneralName  }
      +	 * 
      + */ + public class AccessDescription + : Asn1Encodable + { + public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2"); + + public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1"); + + internal DerObjectIdentifier accessMethod; + internal GeneralName accessLocation; + + public static AccessDescription GetInstance( + object obj) + { + if (obj is AccessDescription) + { + return (AccessDescription) obj; + } + + if (obj is Asn1Sequence) + { + return new AccessDescription((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AccessDescription( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("wrong number of elements in inner sequence"); + + accessMethod = DerObjectIdentifier.GetInstance(seq[0]); + accessLocation = GeneralName.GetInstance(seq[1]); + } + + /** + * create an AccessDescription with the oid and location provided. + */ + public AccessDescription( + DerObjectIdentifier oid, + GeneralName location) + { + accessMethod = oid; + accessLocation = location; + } + + /** + * + * @return the access method. + */ + public DerObjectIdentifier AccessMethod + { + get { return accessMethod; } + } + + /** + * + * @return the access location + */ + public GeneralName AccessLocation + { + get { return accessLocation; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(accessMethod, accessLocation); + } + + public override string ToString() + { + return ("AccessDescription: Oid(" + this.accessMethod.Id + ")"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AlgorithmIdentifier.cs b/iTechSharp/srcbc/asn1/x509/AlgorithmIdentifier.cs new file mode 100644 index 0000000..6f24a73 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AlgorithmIdentifier.cs @@ -0,0 +1,110 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AlgorithmIdentifier + : Asn1Encodable + { + private readonly DerObjectIdentifier objectID; + private readonly Asn1Encodable parameters; + + public static AlgorithmIdentifier GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static AlgorithmIdentifier GetInstance( + object obj) + { + if (obj == null || obj is AlgorithmIdentifier) + { + return (AlgorithmIdentifier) obj; + } + + if (obj is DerObjectIdentifier) + { + return new AlgorithmIdentifier((DerObjectIdentifier) obj); + } + + if (obj is string) + { + return new AlgorithmIdentifier((string) obj); + } + + if (obj is Asn1Sequence) + { + return new AlgorithmIdentifier((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public AlgorithmIdentifier( + DerObjectIdentifier objectID) + { + this.objectID = objectID; + } + + public AlgorithmIdentifier( + string objectID) + { + this.objectID = new DerObjectIdentifier(objectID); + } + + public AlgorithmIdentifier( + DerObjectIdentifier objectID, + Asn1Encodable parameters) + { + this.objectID = objectID; + this.parameters = parameters; + } + + internal AlgorithmIdentifier( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + objectID = DerObjectIdentifier.GetInstance(seq[0]); + + if (seq.Count == 2) + { + parameters = seq[1]; + } + } + + public virtual DerObjectIdentifier ObjectID + { + get { return objectID; } + } + + public Asn1Encodable Parameters + { + get { return parameters; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *      AlgorithmIdentifier ::= Sequence {
      +         *                            algorithm OBJECT IDENTIFIER,
      +         *                            parameters ANY DEFINED BY algorithm OPTIONAL }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(objectID); + + if (parameters != null) + { + v.Add(parameters); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AttCertIssuer.cs b/iTechSharp/srcbc/asn1/x509/AttCertIssuer.cs new file mode 100644 index 0000000..b5d4f47 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AttCertIssuer.cs @@ -0,0 +1,86 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttCertIssuer + : Asn1Encodable + { + internal readonly Asn1Encodable obj; + internal readonly Asn1Object choiceObj; + + public static AttCertIssuer GetInstance( + object obj) + { + if (obj is AttCertIssuer) + { + return (AttCertIssuer)obj; + } + else if (obj is V2Form) + { + return new AttCertIssuer(V2Form.GetInstance(obj)); + } + else if (obj is GeneralNames) + { + return new AttCertIssuer((GeneralNames)obj); + } + else if (obj is Asn1TaggedObject) + { + return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false)); + } + else if (obj is Asn1Sequence) + { + return new AttCertIssuer(GeneralNames.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static AttCertIssuer GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(obj.GetObject()); // must be explictly tagged + } + + /// + /// Don't use this one if you are trying to be RFC 3281 compliant. + /// Use it for v1 attribute certificates only. + /// + /// Our GeneralNames structure + public AttCertIssuer( + GeneralNames names) + { + obj = names; + choiceObj = obj.ToAsn1Object(); + } + + public AttCertIssuer( + V2Form v2Form) + { + obj = v2Form; + choiceObj = new DerTaggedObject(false, 0, obj); + } + + public Asn1Encodable Issuer + { + get { return obj; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  AttCertIssuer ::= CHOICE {
      +         *       v1Form   GeneralNames,  -- MUST NOT be used in this
      +         *                               -- profile
      +         *       v2Form   [0] V2Form     -- v2 only
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return choiceObj; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AttCertValidityPeriod.cs b/iTechSharp/srcbc/asn1/x509/AttCertValidityPeriod.cs new file mode 100644 index 0000000..7f86cd0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AttCertValidityPeriod.cs @@ -0,0 +1,78 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttCertValidityPeriod + : Asn1Encodable + { + private readonly DerGeneralizedTime notBeforeTime; + private readonly DerGeneralizedTime notAfterTime; + + public static AttCertValidityPeriod GetInstance( + object obj) + { + if (obj is AttCertValidityPeriod || obj == null) + { + return (AttCertValidityPeriod) obj; + } + + if (obj is Asn1Sequence) + { + return new AttCertValidityPeriod((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static AttCertValidityPeriod GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + private AttCertValidityPeriod( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + notBeforeTime = DerGeneralizedTime.GetInstance(seq[0]); + notAfterTime = DerGeneralizedTime.GetInstance(seq[1]); + } + + public AttCertValidityPeriod( + DerGeneralizedTime notBeforeTime, + DerGeneralizedTime notAfterTime) + { + this.notBeforeTime = notBeforeTime; + this.notAfterTime = notAfterTime; + } + + public DerGeneralizedTime NotBeforeTime + { + get { return notBeforeTime; } + } + + public DerGeneralizedTime NotAfterTime + { + get { return notAfterTime; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  AttCertValidityPeriod  ::= Sequence {
      +         *       notBeforeTime  GeneralizedTime,
      +         *       notAfterTime   GeneralizedTime
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(notBeforeTime, notAfterTime); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/Attribute.cs b/iTechSharp/srcbc/asn1/x509/Attribute.cs new file mode 100644 index 0000000..7279134 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/Attribute.cs @@ -0,0 +1,77 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttributeX509 + : Asn1Encodable + { + private readonly DerObjectIdentifier attrType; + private readonly Asn1Set attrValues; + + /** + * return an Attr object from the given object. + * + * @param o the object we want converted. + * @exception ArgumentException if the object cannot be converted. + */ + public static AttributeX509 GetInstance( + object obj) + { + if (obj == null || obj is AttributeX509) + { + return (AttributeX509) obj; + } + + if (obj is Asn1Sequence) + { + return new AttributeX509((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AttributeX509( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + attrType = DerObjectIdentifier.GetInstance(seq[0]); + attrValues = Asn1Set.GetInstance(seq[1]); + } + + public AttributeX509( + DerObjectIdentifier attrType, + Asn1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public DerObjectIdentifier AttrType + { + get { return attrType; } + } + + public Asn1Set AttrValues + { + get { return attrValues; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Attr ::= Sequence {
      +         *     attrType OBJECT IDENTIFIER,
      +         *     attrValues Set OF AttributeValue
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(attrType, attrValues); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AttributeCertificate.cs b/iTechSharp/srcbc/asn1/x509/AttributeCertificate.cs new file mode 100644 index 0000000..4ad3246 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AttributeCertificate.cs @@ -0,0 +1,85 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttributeCertificate + : Asn1Encodable + { + private readonly AttributeCertificateInfo acinfo; + private readonly AlgorithmIdentifier signatureAlgorithm; + private readonly DerBitString signatureValue; + + /** + * @param obj + * @return + */ + public static AttributeCertificate GetInstance( + object obj) + { + if (obj is AttributeCertificate) + { + return (AttributeCertificate) obj; + } + + if (obj is Asn1Sequence) + { + return new AttributeCertificate((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public AttributeCertificate( + AttributeCertificateInfo acinfo, + AlgorithmIdentifier signatureAlgorithm, + DerBitString signatureValue) + { + this.acinfo = acinfo; + this.signatureAlgorithm = signatureAlgorithm; + this.signatureValue = signatureValue; + } + + private AttributeCertificate( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + this.acinfo = AttributeCertificateInfo.GetInstance(seq[0]); + this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]); + this.signatureValue = DerBitString.GetInstance(seq[2]); + } + + public AttributeCertificateInfo ACInfo + { + get { return acinfo; } + } + + public AlgorithmIdentifier SignatureAlgorithm + { + get { return signatureAlgorithm; } + } + + public DerBitString SignatureValue + { + get { return signatureValue; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  AttributeCertificate ::= Sequence {
      +         *       acinfo               AttributeCertificateInfo,
      +         *       signatureAlgorithm   AlgorithmIdentifier,
      +         *       signatureValue       BIT STRING
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(acinfo, signatureAlgorithm, signatureValue); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AttributeCertificateInfo.cs b/iTechSharp/srcbc/asn1/x509/AttributeCertificateInfo.cs new file mode 100644 index 0000000..dcef3d4 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AttributeCertificateInfo.cs @@ -0,0 +1,156 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttributeCertificateInfo + : Asn1Encodable + { + internal readonly DerInteger version; + internal readonly Holder holder; + internal readonly AttCertIssuer issuer; + internal readonly AlgorithmIdentifier signature; + internal readonly DerInteger serialNumber; + internal readonly AttCertValidityPeriod attrCertValidityPeriod; + internal readonly Asn1Sequence attributes; + internal readonly DerBitString issuerUniqueID; + internal readonly X509Extensions extensions; + + public static AttributeCertificateInfo GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + public static AttributeCertificateInfo GetInstance( + object obj) + { + if (obj is AttributeCertificateInfo) + { + return (AttributeCertificateInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new AttributeCertificateInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AttributeCertificateInfo( + Asn1Sequence seq) + { + if (seq.Count < 7 || seq.Count > 9) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + this.version = DerInteger.GetInstance(seq[0]); + this.holder = Holder.GetInstance(seq[1]); + this.issuer = AttCertIssuer.GetInstance(seq[2]); + this.signature = AlgorithmIdentifier.GetInstance(seq[3]); + this.serialNumber = DerInteger.GetInstance(seq[4]); + this.attrCertValidityPeriod = AttCertValidityPeriod.GetInstance(seq[5]); + this.attributes = Asn1Sequence.GetInstance(seq[6]); + + for (int i = 7; i < seq.Count; i++) + { + Asn1Encodable obj = (Asn1Encodable) seq[i]; + + if (obj is DerBitString) + { + this.issuerUniqueID = DerBitString.GetInstance(seq[i]); + } + else if (obj is Asn1Sequence || obj is X509Extensions) + { + this.extensions = X509Extensions.GetInstance(seq[i]); + } + } + } + + public DerInteger Version + { + get { return version; } + } + + public Holder Holder + { + get { return holder; } + } + + public AttCertIssuer Issuer + { + get { return issuer; } + } + + public AlgorithmIdentifier Signature + { + get { return signature; } + } + + public DerInteger SerialNumber + { + get { return serialNumber; } + } + + public AttCertValidityPeriod AttrCertValidityPeriod + { + get { return attrCertValidityPeriod; } + } + + public Asn1Sequence Attributes + { + get { return attributes; } + } + + public DerBitString IssuerUniqueID + { + get { return issuerUniqueID; } + } + + public X509Extensions Extensions + { + get { return extensions; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  AttributeCertificateInfo ::= Sequence {
      +         *       version              AttCertVersion -- version is v2,
      +         *       holder               Holder,
      +         *       issuer               AttCertIssuer,
      +         *       signature            AlgorithmIdentifier,
      +         *       serialNumber         CertificateSerialNumber,
      +         *       attrCertValidityPeriod   AttCertValidityPeriod,
      +         *       attributes           Sequence OF Attr,
      +         *       issuerUniqueID       UniqueIdentifier OPTIONAL,
      +         *       extensions           Extensions OPTIONAL
      +         *  }
      +         *
      +         *  AttCertVersion ::= Integer { v2(1) }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + version, holder, issuer, signature, serialNumber, + attrCertValidityPeriod, attributes); + + if (issuerUniqueID != null) + { + v.Add(issuerUniqueID); + } + + if (extensions != null) + { + v.Add(extensions); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AttributeTable.cs b/iTechSharp/srcbc/asn1/x509/AttributeTable.cs new file mode 100644 index 0000000..1913ab5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AttributeTable.cs @@ -0,0 +1,54 @@ +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttributeTable + { + private readonly Hashtable attributes; + + public AttributeTable( + Hashtable attrs) + { + this.attributes = new Hashtable(attrs); + } + + public AttributeTable( + Asn1EncodableVector v) + { + this.attributes = new Hashtable(v.Count); + + for (int i = 0; i != v.Count; i++) + { + AttributeX509 a = AttributeX509.GetInstance(v[i]); + + attributes.Add(a.AttrType, a); + } + } + + public AttributeTable( + Asn1Set s) + { + this.attributes = new Hashtable(s.Count); + + for (int i = 0; i != s.Count; i++) + { + AttributeX509 a = AttributeX509.GetInstance(s[i]); + + attributes.Add(a.AttrType, a); + } + } + + public AttributeX509 Get( + DerObjectIdentifier oid) + { + return (AttributeX509) attributes[oid]; + } + + public Hashtable ToHashtable() + { + return new Hashtable(attributes); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AuthorityInformationAccess.cs b/iTechSharp/srcbc/asn1/x509/AuthorityInformationAccess.cs new file mode 100644 index 0000000..524ce67 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AuthorityInformationAccess.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The AuthorityInformationAccess object. + *
      +     * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
      +     *
      +     * AuthorityInfoAccessSyntax  ::=
      +     *      Sequence SIZE (1..MAX) OF AccessDescription
      +     * AccessDescription  ::=  Sequence {
      +     *       accessMethod          OBJECT IDENTIFIER,
      +     *       accessLocation        GeneralName  }
      +     *
      +     * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
      +     * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
      +     * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
      +     * 
      + */ + public class AuthorityInformationAccess + : Asn1Encodable + { + internal readonly DerObjectIdentifier accessMethod; + internal readonly GeneralName accessLocation; + + public static AuthorityInformationAccess GetInstance( + object obj) + { + if (obj is AuthorityInformationAccess) + { + return (AuthorityInformationAccess) obj; + } + + if (obj is Asn1Sequence) + { + return new AuthorityInformationAccess((Asn1Sequence) obj); + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AuthorityInformationAccess( + Asn1Sequence seq) + { + foreach (DerSequence vec in seq) + { + if (vec.Count != 2) + { + throw new ArgumentException("wrong number of elements in inner sequence"); + } + + accessMethod = (DerObjectIdentifier) vec[0]; + accessLocation = (GeneralName) vec[1]; + } + } + + /** + * create an AuthorityInformationAccess with the oid and location provided. + */ + public AuthorityInformationAccess( + DerObjectIdentifier oid, + GeneralName location) + { + accessMethod = oid; + accessLocation = location; + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(new DerSequence(accessMethod, accessLocation)); + } + + public override string ToString() + { + return ("AuthorityInformationAccess: Oid(" + this.accessMethod.Id + ")"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/AuthorityKeyIdentifier.cs b/iTechSharp/srcbc/asn1/x509/AuthorityKeyIdentifier.cs new file mode 100644 index 0000000..12ccacf --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/AuthorityKeyIdentifier.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The AuthorityKeyIdentifier object. + *
      +     * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
      +     *
      +     *   AuthorityKeyIdentifier ::= Sequence {
      +     *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,
      +     *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,
      +     *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }
      +     *
      +     *   KeyIdentifier ::= OCTET STRING
      +     * 
      + * + */ + public class AuthorityKeyIdentifier + : Asn1Encodable + { + internal readonly Asn1OctetString keyidentifier; + internal readonly GeneralNames certissuer; + internal readonly DerInteger certserno; + + public static AuthorityKeyIdentifier GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static AuthorityKeyIdentifier GetInstance( + object obj) + { + if (obj is AuthorityKeyIdentifier) + { + return (AuthorityKeyIdentifier) obj; + } + + if (obj is Asn1Sequence) + { + return new AuthorityKeyIdentifier((Asn1Sequence) obj); + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + protected internal AuthorityKeyIdentifier( + Asn1Sequence seq) + { + foreach (Asn1TaggedObject o in seq) + { + switch (o.TagNo) + { + case 0: + this.keyidentifier = Asn1OctetString.GetInstance(o, false); + break; + case 1: + this.certissuer = GeneralNames.GetInstance(o, false); + break; + case 2: + this.certserno = DerInteger.GetInstance(o, false); + break; + default: + throw new ArgumentException("illegal tag"); + } + } + } + + /** + * + * Calulates the keyidentifier using a SHA1 hash over the BIT STRING + * from SubjectPublicKeyInfo as defined in RFC2459. + * + * Example of making a AuthorityKeyIdentifier: + *
      +	     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
      +		 *       publicKey.getEncoded()).readObject());
      +         *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
      +         * 
      + * + **/ + public AuthorityKeyIdentifier( + SubjectPublicKeyInfo spki) + { + IDigest digest = new Sha1Digest(); + byte[] resBuf = new byte[digest.GetDigestSize()]; + + byte[] bytes = spki.PublicKeyData.GetBytes(); + digest.BlockUpdate(bytes, 0, bytes.Length); + digest.DoFinal(resBuf, 0); + this.keyidentifier = new DerOctetString(resBuf); + } + + /** + * create an AuthorityKeyIdentifier with the GeneralNames tag and + * the serial number provided as well. + */ + public AuthorityKeyIdentifier( + SubjectPublicKeyInfo spki, + GeneralNames name, + BigInteger serialNumber) + { + IDigest digest = new Sha1Digest(); + byte[] resBuf = new byte[digest.GetDigestSize()]; + + byte[] bytes = spki.PublicKeyData.GetBytes(); + digest.BlockUpdate(bytes, 0, bytes.Length); + digest.DoFinal(resBuf, 0); + + this.keyidentifier = new DerOctetString(resBuf); + this.certissuer = name; + this.certserno = new DerInteger(serialNumber); + } + + /** + * create an AuthorityKeyIdentifier with the GeneralNames tag and + * the serial number provided. + */ + public AuthorityKeyIdentifier( + GeneralNames name, + BigInteger serialNumber) + { + this.keyidentifier = null; + this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object()); + this.certserno = new DerInteger(serialNumber); + } + + /** + * create an AuthorityKeyIdentifier with a precomputed key identifier + */ + public AuthorityKeyIdentifier( + byte[] keyIdentifier) + { + this.keyidentifier = new DerOctetString(keyIdentifier); + this.certissuer = null; + this.certserno = null; + } + + /** + * create an AuthorityKeyIdentifier with a precomupted key identifier + * and the GeneralNames tag and the serial number provided as well. + */ + public AuthorityKeyIdentifier( + byte[] keyIdentifier, + GeneralNames name, + BigInteger serialNumber) + { + this.keyidentifier = new DerOctetString(keyIdentifier); + this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object()); + this.certserno = new DerInteger(serialNumber); + } + + public byte[] GetKeyIdentifier() + { + return keyidentifier == null ? null : keyidentifier.GetOctets(); + } + + public GeneralNames AuthorityCertIssuer + { + get { return certissuer; } + } + + public BigInteger AuthorityCertSerialNumber + { + get { return certserno == null ? null : certserno.Value; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (keyidentifier != null) + { + v.Add(new DerTaggedObject(false, 0, keyidentifier)); + } + + if (certissuer != null) + { + v.Add(new DerTaggedObject(false, 1, certissuer)); + } + + if (certserno != null) + { + v.Add(new DerTaggedObject(false, 2, certserno)); + } + + return new DerSequence(v); + } + + public override string ToString() + { + return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.GetOctets() + ")"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/BasicConstraints.cs b/iTechSharp/srcbc/asn1/x509/BasicConstraints.cs new file mode 100644 index 0000000..522cb61 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/BasicConstraints.cs @@ -0,0 +1,133 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class BasicConstraints + : Asn1Encodable + { + private readonly DerBoolean cA; + private readonly DerInteger pathLenConstraint; + + public static BasicConstraints GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static BasicConstraints GetInstance( + object obj) + { + if (obj == null || obj is BasicConstraints) + { + return (BasicConstraints) obj; + } + + if (obj is Asn1Sequence) + { + return new BasicConstraints((Asn1Sequence) obj); + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private BasicConstraints( + Asn1Sequence seq) + { + if (seq.Count > 0) + { + if (seq[0] is DerBoolean) + { + this.cA = DerBoolean.GetInstance(seq[0]); + } + else + { + this.pathLenConstraint = DerInteger.GetInstance(seq[0]); + } + + if (seq.Count > 1) + { + if (this.cA == null) + throw new ArgumentException("wrong sequence in constructor", "seq"); + + this.pathLenConstraint = DerInteger.GetInstance(seq[1]); + } + } + } + + public BasicConstraints( + bool cA) + { + if (cA) + { + this.cA = DerBoolean.True; + } + } + + /** + * create a cA=true object for the given path length constraint. + * + * @param pathLenConstraint + */ + public BasicConstraints( + int pathLenConstraint) + { + this.cA = DerBoolean.True; + this.pathLenConstraint = new DerInteger(pathLenConstraint); + } + + public bool IsCA() + { + return cA != null && cA.IsTrue; + } + + public BigInteger PathLenConstraint + { + get { return pathLenConstraint == null ? null : pathLenConstraint.Value; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * BasicConstraints := Sequence {
      +         *    cA                  Boolean DEFAULT FALSE,
      +         *    pathLenConstraint   Integer (0..MAX) OPTIONAL
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (cA != null) + { + v.Add(cA); + } + + if (pathLenConstraint != null) // yes some people actually do this when cA is false... + { + v.Add(pathLenConstraint); + } + + return new DerSequence(v); + } + + public override string ToString() + { + if (pathLenConstraint == null) + { + return "BasicConstraints: isCa(" + this.IsCA() + ")"; + } + + return "BasicConstraints: isCa(" + this.IsCA() + "), pathLenConstraint = " + pathLenConstraint.Value; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/CRLDistPoint.cs b/iTechSharp/srcbc/asn1/x509/CRLDistPoint.cs new file mode 100644 index 0000000..2b5c197 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/CRLDistPoint.cs @@ -0,0 +1,93 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class CrlDistPoint + : Asn1Encodable + { + internal readonly Asn1Sequence seq; + + public static CrlDistPoint GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static CrlDistPoint GetInstance( + object obj) + { + if (obj is CrlDistPoint || obj == null) + { + return (CrlDistPoint) obj; + } + + if (obj is Asn1Sequence) + { + return new CrlDistPoint((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private CrlDistPoint( + Asn1Sequence seq) + { + this.seq = seq; + } + + public CrlDistPoint( + DistributionPoint[] points) + { + seq = new DerSequence(points); + } + + /** + * Return the distribution points making up the sequence. + * + * @return DistributionPoint[] + */ + public DistributionPoint[] GetDistributionPoints() + { + DistributionPoint[] dp = new DistributionPoint[seq.Count]; + + for (int i = 0; i != seq.Count; ++i) + { + dp[i] = DistributionPoint.GetInstance(seq[i]); + } + + return dp; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return seq; + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string sep = Platform.NewLine; + + buf.Append("CRLDistPoint:"); + buf.Append(sep); + DistributionPoint[] dp = GetDistributionPoints(); + for (int i = 0; i != dp.Length; i++) + { + buf.Append(" "); + buf.Append(dp[i]); + buf.Append(sep); + } + return buf.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/CRLNumber.cs b/iTechSharp/srcbc/asn1/x509/CRLNumber.cs new file mode 100644 index 0000000..d744416 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/CRLNumber.cs @@ -0,0 +1,30 @@ +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The CRLNumber object. + *
      +     * CRLNumber::= Integer(0..MAX)
      +     * 
      + */ + public class CrlNumber + : DerInteger + { + public CrlNumber( + BigInteger number) + : base(number) + { + } + + public BigInteger Number + { + get { return PositiveValue; } + } + + public override string ToString() + { + return "CRLNumber: " + Number; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/CRLReason.cs b/iTechSharp/srcbc/asn1/x509/CRLReason.cs new file mode 100644 index 0000000..e8eb53a --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/CRLReason.cs @@ -0,0 +1,61 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The CRLReason enumeration. + *
      +     * CRLReason ::= Enumerated {
      +     *  unspecified             (0),
      +     *  keyCompromise           (1),
      +     *  cACompromise            (2),
      +     *  affiliationChanged      (3),
      +     *  superseded              (4),
      +     *  cessationOfOperation    (5),
      +     *  certificateHold         (6),
      +     *  removeFromCRL           (8),
      +     *  privilegeWithdrawn      (9),
      +     *  aACompromise           (10)
      +     * }
      +     * 
      + */ + public class CrlReason + : DerEnumerated + { + public const int Unspecified = 0; + public const int KeyCompromise = 1; + public const int CACompromise = 2; + public const int AffiliationChanged = 3; + public const int Superseded = 4; + public const int CessationOfOperation = 5; + public const int CertificateHold = 6; + // 7 -> Unknown + public const int RemoveFromCrl = 8; + public const int PrivilegeWithdrawn = 9; + public const int AACompromise = 10; + + private static readonly string[] ReasonString = new string[] + { + "Unspecified", "KeyCompromise", "CACompromise", "AffiliationChanged", + "Superseded", "CessationOfOperation", "CertificateHold", "Unknown", + "RemoveFromCrl", "PrivilegeWithdrawn", "AACompromise" + }; + + public CrlReason( + int reason) + : base(reason) + { + } + + public CrlReason( + DerEnumerated reason) + : base(reason.Value.IntValue) + { + } + + public override string ToString() + { + int reason = Value.IntValue; + string str = (reason < 0 || reason > 10) ? "Invalid" : ReasonString[reason]; + return "CrlReason: " + str; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/CertPolicyId.cs b/iTechSharp/srcbc/asn1/x509/CertPolicyId.cs new file mode 100644 index 0000000..11cebcd --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/CertPolicyId.cs @@ -0,0 +1,20 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * CertPolicyId, used in the CertificatePolicies and PolicyMappings + * X509V3 Extensions. + * + *
      +     *     CertPolicyId ::= OBJECT IDENTIFIER
      +     * 
      + */ + public class CertPolicyID + : DerObjectIdentifier + { + public CertPolicyID( + string id) + : base(id) + { + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/CertificateList.cs b/iTechSharp/srcbc/asn1/x509/CertificateList.cs new file mode 100644 index 0000000..85351a0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/CertificateList.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * PKIX RFC-2459 + * + * The X.509 v2 CRL syntax is as follows. For signature calculation, + * the data that is to be signed is ASN.1 Der encoded. + * + *
      +     * CertificateList  ::=  Sequence  {
      +     *      tbsCertList          TbsCertList,
      +     *      signatureAlgorithm   AlgorithmIdentifier,
      +     *      signatureValue       BIT STRING  }
      +     * 
      + */ + public class CertificateList + : Asn1Encodable + { + private readonly TbsCertificateList tbsCertList; + private readonly AlgorithmIdentifier sigAlgID; + private readonly DerBitString sig; + + public static CertificateList GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static CertificateList GetInstance( + object obj) + { + if (obj is CertificateList) + { + return (CertificateList) obj; + } + + if (obj is Asn1Sequence) + { + return new CertificateList((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private CertificateList( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("sequence wrong size for CertificateList", "seq"); + + tbsCertList = TbsCertificateList.GetInstance(seq[0]); + sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]); + sig = DerBitString.GetInstance(seq[2]); + } + + public TbsCertificateList TbsCertList + { + get { return tbsCertList; } + } + + public CrlEntry[] GetRevokedCertificates() + { + return tbsCertList.GetRevokedCertificates(); + } + + public IEnumerable GetRevokedCertificateEnumeration() + { + return tbsCertList.GetRevokedCertificateEnumeration(); + } + + public AlgorithmIdentifier SignatureAlgorithm + { + get { return sigAlgID; } + } + + public DerBitString Signature + { + get { return sig; } + } + + public int Version + { + get { return tbsCertList.Version; } + } + + public X509Name Issuer + { + get { return tbsCertList.Issuer; } + } + + public Time ThisUpdate + { + get { return tbsCertList.ThisUpdate; } + } + + public Time NextUpdate + { + get { return tbsCertList.NextUpdate; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(tbsCertList, sigAlgID, sig); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/CertificatePair.cs b/iTechSharp/srcbc/asn1/x509/CertificatePair.cs new file mode 100644 index 0000000..8baa647 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/CertificatePair.cs @@ -0,0 +1,160 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * This class helps to support crossCerfificatePairs in a LDAP directory + * according RFC 2587 + * + *
      +	*     crossCertificatePairATTRIBUTE::={
      +	*       WITH SYNTAX   CertificatePair
      +	*       EQUALITY MATCHING RULE certificatePairExactMatch
      +	*       ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
      +	* 
      + * + *
      The forward elements of the crossCertificatePair attribute of a + * CA's directory entry shall be used to store all, except self-issued + * certificates issued to this CA. Optionally, the reverse elements of the + * crossCertificatePair attribute, of a CA's directory entry may contain a + * subset of certificates issued by this CA to other CAs. When both the forward + * and the reverse elements are present in a single attribute value, issuer name + * in one certificate shall match the subject name in the other and vice versa, + * and the subject public key in one certificate shall be capable of verifying + * the digital signature on the other certificate and vice versa. + * + * When a reverse element is present, the forward element value and the reverse + * element value need not be stored in the same attribute value; in other words, + * they can be stored in either a single attribute value or two attribute + * values.
      + * + *
      +	*       CertificatePair ::= SEQUENCE {
      +	*         forward		[0]	Certificate OPTIONAL,
      +	*         reverse		[1]	Certificate OPTIONAL,
      +	*         -- at least one of the pair shall be present -- }
      +	* 
      + */ + public class CertificatePair + : Asn1Encodable + { + private X509CertificateStructure forward, reverse; + + public static CertificatePair GetInstance( + object obj) + { + if (obj == null || obj is CertificatePair) + { + return (CertificatePair) obj; + } + + if (obj is Asn1Sequence) + { + return new CertificatePair((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + *

      + * The sequence is of type CertificatePair: + *

      + *

      +		*       CertificatePair ::= SEQUENCE {
      +		*         forward		[0]	Certificate OPTIONAL,
      +		*         reverse		[1]	Certificate OPTIONAL,
      +		*         -- at least one of the pair shall be present -- }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private CertificatePair( + Asn1Sequence seq) + { + if (seq.Count != 1 && seq.Count != 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + } + + foreach (object obj in seq) + { + Asn1TaggedObject o = Asn1TaggedObject.GetInstance(obj); + if (o.TagNo == 0) + { + forward = X509CertificateStructure.GetInstance(o, true); + } + else if (o.TagNo == 1) + { + reverse = X509CertificateStructure.GetInstance(o, true); + } + else + { + throw new ArgumentException("Bad tag number: " + o.TagNo); + } + } + } + + /** + * Constructor from a given details. + * + * @param forward Certificates issued to this CA. + * @param reverse Certificates issued by this CA to other CAs. + */ + public CertificatePair( + X509CertificateStructure forward, + X509CertificateStructure reverse) + { + this.forward = forward; + this.reverse = reverse; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*       CertificatePair ::= SEQUENCE {
      +		*         forward		[0]	Certificate OPTIONAL,
      +		*         reverse		[1]	Certificate OPTIONAL,
      +		*         -- at least one of the pair shall be present -- }
      +		* 
      + * + * @return a DERObject + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + + if (forward != null) + { + vec.Add(new DerTaggedObject(0, forward)); + } + + if (reverse != null) + { + vec.Add(new DerTaggedObject(1, reverse)); + } + + return new DerSequence(vec); + } + + /** + * @return Returns the forward. + */ + public X509CertificateStructure Forward + { + get { return forward; } + } + + /** + * @return Returns the reverse. + */ + public X509CertificateStructure Reverse + { + get { return reverse; } + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/DSAParameter.cs b/iTechSharp/srcbc/asn1/x509/DSAParameter.cs new file mode 100644 index 0000000..b2b325f --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/DSAParameter.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class DsaParameter + : Asn1Encodable + { + internal readonly DerInteger p, q, g; + + public static DsaParameter GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static DsaParameter GetInstance( + object obj) + { + if(obj == null || obj is DsaParameter) + { + return (DsaParameter) obj; + } + + if(obj is Asn1Sequence) + { + return new DsaParameter((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid DsaParameter: " + obj.GetType().Name); + } + + public DsaParameter( + BigInteger p, + BigInteger q, + BigInteger g) + { + this.p = new DerInteger(p); + this.q = new DerInteger(q); + this.g = new DerInteger(g); + } + + private DsaParameter( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.p = DerInteger.GetInstance(seq[0]); + this.q = DerInteger.GetInstance(seq[1]); + this.g = DerInteger.GetInstance(seq[2]); + } + + public BigInteger P + { + get { return p.PositiveValue; } + } + + public BigInteger Q + { + get { return q.PositiveValue; } + } + + public BigInteger G + { + get { return g.PositiveValue; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(p, q, g); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/DigestInfo.cs b/iTechSharp/srcbc/asn1/x509/DigestInfo.cs new file mode 100644 index 0000000..1dec227 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/DigestInfo.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The DigestInfo object. + *
      +     * DigestInfo::=Sequence{
      +     *          digestAlgorithm  AlgorithmIdentifier,
      +     *          digest OCTET STRING }
      +     * 
      + */ + public class DigestInfo + : Asn1Encodable + { + private readonly byte[] digest; + private readonly AlgorithmIdentifier algID; + + public static DigestInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static DigestInfo GetInstance( + object obj) + { + if (obj is DigestInfo) + { + return (DigestInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new DigestInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public DigestInfo( + AlgorithmIdentifier algID, + byte[] digest) + { + this.digest = digest; + this.algID = algID; + } + + private DigestInfo( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + algID = AlgorithmIdentifier.GetInstance(seq[0]); + digest = Asn1OctetString.GetInstance(seq[1]).GetOctets(); + } + + public AlgorithmIdentifier AlgorithmID + { + get { return algID; } + } + + public byte[] GetDigest() + { + return digest; + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(algID, new DerOctetString(digest)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/DisplayText.cs b/iTechSharp/srcbc/asn1/x509/DisplayText.cs new file mode 100644 index 0000000..287e597 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/DisplayText.cs @@ -0,0 +1,172 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * DisplayText class, used in + * CertificatePolicies X509 V3 extensions (in policy qualifiers). + * + *

      It stores a string in a chosen encoding. + *

      +	 * DisplayText ::= CHOICE {
      +	 *      ia5String        IA5String      (SIZE (1..200)),
      +	 *      visibleString    VisibleString  (SIZE (1..200)),
      +	 *      bmpString        BMPString      (SIZE (1..200)),
      +	 *      utf8String       UTF8String     (SIZE (1..200)) }
      +	 * 

      + * @see PolicyQualifierInfo + * @see PolicyInformation + */ + public class DisplayText + : Asn1Encodable + { + /** + * Constant corresponding to ia5String encoding. + * + */ + public const int ContentTypeIA5String = 0; + /** + * Constant corresponding to bmpString encoding. + * + */ + public const int ContentTypeBmpString = 1; + /** + * Constant corresponding to utf8String encoding. + * + */ + public const int ContentTypeUtf8String = 2; + /** + * Constant corresponding to visibleString encoding. + * + */ + public const int ContentTypeVisibleString = 3; + /** + * Describe constant DisplayTextMaximumSize here. + * + */ + public const int DisplayTextMaximumSize = 200; + + internal readonly int contentType; + internal readonly IAsn1String contents; + + /** + * Creates a new DisplayText instance. + * + * @param type the desired encoding type for the text. + * @param text the text to store. Strings longer than 200 + * characters are truncated. + */ + public DisplayText( + int type, + string text) + { + if (text.Length > DisplayTextMaximumSize) + { + // RFC3280 limits these strings to 200 chars + // truncate the string + text = text.Substring(0, DisplayTextMaximumSize); + } + + contentType = type; + switch (type) + { + case ContentTypeIA5String: + contents = (IAsn1String)new DerIA5String (text); + break; + case ContentTypeUtf8String: + contents = (IAsn1String)new DerUtf8String(text); + break; + case ContentTypeVisibleString: + contents = (IAsn1String)new DerVisibleString(text); + break; + case ContentTypeBmpString: + contents = (IAsn1String)new DerBmpString(text); + break; + default: + contents = (IAsn1String)new DerUtf8String(text); + break; + } + } + +// /** +// * return true if the passed in string can be represented without +// * loss as a PrintableString, false otherwise. +// */ +// private bool CanBePrintable( +// string str) +// { +// for (int i = str.Length - 1; i >= 0; i--) +// { +// if (str[i] > 0x007f) +// { +// return false; +// } +// } +// +// return true; +// } + + /** + * Creates a new DisplayText instance. + * + * @param text the text to encapsulate. Strings longer than 200 + * characters are truncated. + */ + public DisplayText( + string text) + { + // by default use UTF8String + if (text.Length > DisplayTextMaximumSize) + { + text = text.Substring(0, DisplayTextMaximumSize); + } + + contentType = ContentTypeUtf8String; + contents = new DerUtf8String(text); + } + + /** + * Creates a new DisplayText instance. + *

      Useful when reading back a DisplayText class + * from it's Asn1Encodable form.

      + * + * @param contents an Asn1Encodable instance. + */ + public DisplayText( + IAsn1String contents) + { + this.contents = contents; + } + + public static DisplayText GetInstance( + object obj) + { + if (obj is IAsn1String) + { + return new DisplayText((IAsn1String) obj); + } + + if (obj is DisplayText) + { + return (DisplayText) obj; + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public override Asn1Object ToAsn1Object() + { + return (Asn1Object) contents; + } + + /** + * Returns the stored string object. + * + * @return the stored text as a string. + */ + public string GetString() + { + return contents.GetString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/DistributionPoint.cs b/iTechSharp/srcbc/asn1/x509/DistributionPoint.cs new file mode 100644 index 0000000..ad1d398 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/DistributionPoint.cs @@ -0,0 +1,161 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The DistributionPoint object. + *
      +     * DistributionPoint ::= Sequence {
      +     *      distributionPoint [0] DistributionPointName OPTIONAL,
      +     *      reasons           [1] ReasonFlags OPTIONAL,
      +     *      cRLIssuer         [2] GeneralNames OPTIONAL
      +     * }
      +     * 
      + */ + public class DistributionPoint + : Asn1Encodable + { + internal readonly DistributionPointName distributionPoint; + internal readonly ReasonFlags reasons; + internal readonly GeneralNames cRLIssuer; + + public static DistributionPoint GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static DistributionPoint GetInstance( + object obj) + { + if(obj == null || obj is DistributionPoint) + { + return (DistributionPoint) obj; + } + + if(obj is Asn1Sequence) + { + return new DistributionPoint((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid DistributionPoint: " + obj.GetType().Name); + } + + private DistributionPoint( + Asn1Sequence seq) + { + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject t = Asn1TaggedObject.GetInstance(seq[i]); + + switch (t.TagNo) + { + case 0: + distributionPoint = DistributionPointName.GetInstance(t, true); + break; + case 1: + reasons = new ReasonFlags(DerBitString.GetInstance(t, false)); + break; + case 2: + cRLIssuer = GeneralNames.GetInstance(t, false); + break; + } + } + } + + public DistributionPoint( + DistributionPointName distributionPointName, + ReasonFlags reasons, + GeneralNames crlIssuer) + { + this.distributionPoint = distributionPointName; + this.reasons = reasons; + this.cRLIssuer = crlIssuer; + } + + public DistributionPointName DistributionPointName + { + get { return distributionPoint; } + } + + public ReasonFlags Reasons + { + get { return reasons; } + } + + public GeneralNames CrlIssuer + { + get { return cRLIssuer; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (distributionPoint != null) + { + // + // as this is a CHOICE it must be explicitly tagged + // + v.Add(new DerTaggedObject(0, distributionPoint)); + } + + if (reasons != null) + { + v.Add(new DerTaggedObject(false, 1, reasons)); + } + + if (cRLIssuer != null) + { + v.Add(new DerTaggedObject(false, 2, cRLIssuer)); + } + + return new DerSequence(v); + } + + public override string ToString() + { + string sep = Platform.NewLine; + StringBuilder buf = new StringBuilder(); + buf.Append("DistributionPoint: ["); + buf.Append(sep); + if (distributionPoint != null) + { + appendObject(buf, sep, "distributionPoint", distributionPoint.ToString()); + } + if (reasons != null) + { + appendObject(buf, sep, "reasons", reasons.ToString()); + } + if (cRLIssuer != null) + { + appendObject(buf, sep, "cRLIssuer", cRLIssuer.ToString()); + } + buf.Append("]"); + buf.Append(sep); + return buf.ToString(); + } + + private void appendObject( + StringBuilder buf, + string sep, + string name, + string val) + { + string indent = " "; + + buf.Append(indent); + buf.Append(name); + buf.Append(":"); + buf.Append(sep); + buf.Append(indent); + buf.Append(indent); + buf.Append(val); + buf.Append(sep); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/DistributionPointName.cs b/iTechSharp/srcbc/asn1/x509/DistributionPointName.cs new file mode 100644 index 0000000..8439a5d --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/DistributionPointName.cs @@ -0,0 +1,130 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The DistributionPointName object. + *
      +     * DistributionPointName ::= CHOICE {
      +     *     fullName                 [0] GeneralNames,
      +     *     nameRelativeToCRLIssuer  [1] RelativeDistinguishedName
      +     * }
      +     * 
      + */ + public class DistributionPointName + : Asn1Encodable + { + internal readonly Asn1Encodable name; + internal readonly int type; + + public const int FullName = 0; + public const int NameRelativeToCrlIssuer = 1; + + public static DistributionPointName GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1TaggedObject.GetInstance(obj, explicitly)); + } + + public static DistributionPointName GetInstance( + object obj) + { + if (obj == null || obj is DistributionPointName) + { + return (DistributionPointName) obj; + } + + if (obj is Asn1TaggedObject) + { + return new DistributionPointName((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public DistributionPointName( + int type, + Asn1Encodable name) + { + this.type = type; + this.name = name; + } + + public DistributionPointName( + GeneralNames name) + : this(FullName, name) + { + } + + public int PointType + { + get { return type; } + } + + public Asn1Encodable Name + { + get { return name; } + } + + public DistributionPointName( + Asn1TaggedObject obj) + { + this.type = obj.TagNo; + + if (type == FullName) + { + this.name = GeneralNames.GetInstance(obj, false); + } + else + { + this.name = Asn1Set.GetInstance(obj, false); + } + } + + public override Asn1Object ToAsn1Object() + { + return new DerTaggedObject(false, type, name); + } + + public override string ToString() + { + string sep = Platform.NewLine; + StringBuilder buf = new StringBuilder(); + buf.Append("DistributionPointName: ["); + buf.Append(sep); + if (type == FullName) + { + appendObject(buf, sep, "fullName", name.ToString()); + } + else + { + appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString()); + } + buf.Append("]"); + buf.Append(sep); + return buf.ToString(); + } + + private void appendObject( + StringBuilder buf, + string sep, + string name, + string val) + { + string indent = " "; + + buf.Append(indent); + buf.Append(name); + buf.Append(":"); + buf.Append(sep); + buf.Append(indent); + buf.Append(indent); + buf.Append(val); + buf.Append(sep); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/ExtendedKeyUsage.cs b/iTechSharp/srcbc/asn1/x509/ExtendedKeyUsage.cs new file mode 100644 index 0000000..2aee599 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/ExtendedKeyUsage.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The extendedKeyUsage object. + *
      +     *      extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
      +     * 
      + */ + public class ExtendedKeyUsage + : Asn1Encodable + { + internal readonly Hashtable usageTable = new Hashtable(); + internal readonly Asn1Sequence seq; + + public static ExtendedKeyUsage GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static ExtendedKeyUsage GetInstance( + object obj) + { + if (obj is ExtendedKeyUsage) + { + return (ExtendedKeyUsage) obj; + } + + if (obj is Asn1Sequence) + { + return new ExtendedKeyUsage((Asn1Sequence) obj); + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name); + } + + private ExtendedKeyUsage( + Asn1Sequence seq) + { + this.seq = seq; + + foreach (object o in seq) + { + if (!(o is DerObjectIdentifier)) + throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage."); + + this.usageTable.Add(o, o); + } + } + + public ExtendedKeyUsage( + ArrayList usages) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + foreach (Asn1Object o in usages) + { + v.Add(o); + + this.usageTable.Add(o, o); + } + + this.seq = new DerSequence(v); + } + + public bool HasKeyPurposeId( + KeyPurposeID keyPurposeId) + { + return usageTable[keyPurposeId] != null; + } + + /** + * Returns all extended key usages. + * The returned ArrayList contains DerObjectIdentifier instances. + * @return An ArrayList with all key purposes. + */ + public ArrayList GetUsages() + { + return new ArrayList(usageTable.Values); + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return usageTable.Count; } + } + + public int Count + { + get { return usageTable.Count; } + } + + public override Asn1Object ToAsn1Object() + { + return seq; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/GeneralName.cs b/iTechSharp/srcbc/asn1/x509/GeneralName.cs new file mode 100644 index 0000000..2a19237 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/GeneralName.cs @@ -0,0 +1,240 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities.Net; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The GeneralName object. + *
      +     * GeneralName ::= CHOICE {
      +     *      otherName                       [0]     OtherName,
      +     *      rfc822Name                      [1]     IA5String,
      +     *      dNSName                         [2]     IA5String,
      +     *      x400Address                     [3]     ORAddress,
      +     *      directoryName                   [4]     Name,
      +     *      ediPartyName                    [5]     EDIPartyName,
      +     *      uniformResourceIdentifier       [6]     IA5String,
      +     *      iPAddress                       [7]     OCTET STRING,
      +     *      registeredID                    [8]     OBJECT IDENTIFIER}
      +     *
      +     * OtherName ::= Sequence {
      +     *      type-id    OBJECT IDENTIFIER,
      +     *      value      [0] EXPLICIT ANY DEFINED BY type-id }
      +     *
      +     * EDIPartyName ::= Sequence {
      +     *      nameAssigner            [0]     DirectoryString OPTIONAL,
      +     *      partyName               [1]     DirectoryString }
      +     * 
      + */ + public class GeneralName + : Asn1Encodable + { + public const int OtherName = 0; + public const int Rfc822Name = 1; + public const int DnsName = 2; + public const int X400Address = 3; + public const int DirectoryName = 4; + public const int EdiPartyName = 5; + public const int UniformResourceIdentifier = 6; + public const int IPAddress = 7; + public const int RegisteredID = 8; + + internal readonly Asn1Encodable obj; + internal readonly int tag; + + public GeneralName( + X509Name directoryName) + { + this.obj = directoryName; + this.tag = 4; + } + + /** + * When the subjectAltName extension contains an Internet mail address, + * the address MUST be included as an rfc822Name. The format of an + * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822]. + * + * When the subjectAltName extension contains a domain name service + * label, the domain name MUST be stored in the dNSName (an IA5String). + * The name MUST be in the "preferred name syntax," as specified by RFC + * 1034 [RFC 1034]. + * + * When the subjectAltName extension contains a URI, the name MUST be + * stored in the uniformResourceIdentifier (an IA5String). The name MUST + * be a non-relative URL, and MUST follow the URL syntax and encoding + * rules specified in [RFC 1738]. The name must include both a scheme + * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme- + * specific-part must include a fully qualified domain name or IP + * address as the host. + * + * When the subjectAltName extension contains a iPAddress, the address + * MUST be stored in the octet string in "network byte order," as + * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of + * each octet is the LSB of the corresponding byte in the network + * address. For IP Version 4, as specified in RFC 791, the octet string + * MUST contain exactly four octets. For IP Version 6, as specified in + * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC + * 1883]. + */ + public GeneralName( + Asn1Object name, + int tag) + { + this.obj = name; + this.tag = tag; + } + + public GeneralName( + int tag, + Asn1Encodable name) + { + this.obj = name; + this.tag = tag; + } + + /** + * Create a GeneralName for the given tag from the passed in String. + *

      + * This constructor can handle: + *

        + *
      • rfc822Name
      • + *
      • iPAddress
      • + *
      • directoryName
      • + *
      • dNSName
      • + *
      • uniformResourceIdentifier
      • + *
      • registeredID
      • + *
      + * For x400Address, otherName and ediPartyName there is no common string + * format defined. + *

      + * Note: A directory name can be encoded in different ways into a byte + * representation. Be aware of this if the byte representation is used for + * comparing results. + *

      + * + * @param tag tag number + * @param name string representation of name + * @throws ArgumentException if the string encoding is not correct or + * not supported. + */ + public GeneralName( + int tag, + string name) + { + this.tag = tag; + + if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier) + { + this.obj = new DerIA5String(name); + } + else if (tag == RegisteredID) + { + this.obj = new DerObjectIdentifier(name); + } + else if (tag == DirectoryName) + { + this.obj = new X509Name(name); + } + else if (tag == IPAddress) + { + if (!Org.BouncyCastle.Utilities.Net.IPAddress.IsValid(name)) + throw new ArgumentException("IP Address is invalid", "name"); + + this.obj = new DerOctetString(Encoding.UTF8.GetBytes(name)); + } + else + { + throw new ArgumentException("can't process string for tag: " + tag, "tag"); + } + } + + public static GeneralName GetInstance( + object obj) + { + if (obj == null || obj is GeneralName) + { + return (GeneralName) obj; + } + + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tagObj = (Asn1TaggedObject) obj; + int tag = tagObj.TagNo; + + switch (tag) + { + case OtherName: + return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false)); + case Rfc822Name: + return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false)); + case DnsName: + return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false)); + case X400Address: + throw new ArgumentException("unknown tag: " + tag); + case DirectoryName: + return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, true)); + case EdiPartyName: + return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false)); + case UniformResourceIdentifier: + return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false)); + case IPAddress: + return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false)); + case RegisteredID: + return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false)); + } + + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public static GeneralName GetInstance( + Asn1TaggedObject tagObj, + bool explicitly) + { + return GetInstance(Asn1TaggedObject.GetInstance(tagObj, explicitly)); + } + + public int TagNo + { + get { return tag; } + } + + public Asn1Encodable Name + { + get { return obj; } + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + buf.Append(tag); + buf.Append(": "); + + switch (tag) + { + case Rfc822Name: + case DnsName: + case UniformResourceIdentifier: + buf.Append(DerIA5String.GetInstance(obj).GetString()); + break; + case DirectoryName: + buf.Append(X509Name.GetInstance(obj).ToString()); + break; + default: + buf.Append(obj.ToString()); + break; + } + + return buf.ToString(); + } + + public override Asn1Object ToAsn1Object() + { + // Explicitly tagged if DirectoryName + return new DerTaggedObject(tag == 4, tag, obj); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/GeneralNames.cs b/iTechSharp/srcbc/asn1/x509/GeneralNames.cs new file mode 100644 index 0000000..e0136c9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/GeneralNames.cs @@ -0,0 +1,91 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class GeneralNames + : Asn1Encodable + { + private readonly Asn1Sequence seq; + + public static GeneralNames GetInstance( + object obj) + { + if (obj == null || obj is GeneralNames) + { + return (GeneralNames) obj; + } + + if (obj is Asn1Sequence) + { + return new GeneralNames((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static GeneralNames GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /// Construct a GeneralNames object containing one GeneralName. + /// The name to be contained. + public GeneralNames( + GeneralName name) + { + this.seq = new DerSequence(name); + } + + private GeneralNames( + Asn1Sequence seq) + { + this.seq = seq; + } + + public GeneralName[] GetNames() + { + GeneralName[] names = new GeneralName[seq.Count]; + + for (int i = 0; i != seq.Count; i++) + { + names[i] = GeneralName.GetInstance(seq[i]); + } + + return names; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return seq; + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string sep = Platform.NewLine; + GeneralName[] names = GetNames(); + + buf.Append("GeneralNames:"); + buf.Append(sep); + + for (int i = 0; i != names.Length; i++) + { + buf.Append(" "); + buf.Append(names[i]); + buf.Append(sep); + } + return buf.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/GeneralSubtree.cs b/iTechSharp/srcbc/asn1/x509/GeneralSubtree.cs new file mode 100644 index 0000000..febf5e5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/GeneralSubtree.cs @@ -0,0 +1,177 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Class for containing a restriction object subtrees in NameConstraints. See + * RFC 3280. + * + *
      +	 *
      +	 *       GeneralSubtree ::= SEQUENCE
      +	 *       {
      +	 *         baseName                    GeneralName,
      +	 *         minimum         [0]     BaseDistance DEFAULT 0,
      +	 *         maximum         [1]     BaseDistance OPTIONAL
      +	 *       }
      +	 * 
      + * + * @see org.bouncycastle.asn1.x509.NameConstraints + * + */ + public class GeneralSubtree + : Asn1Encodable + { + private readonly GeneralName baseName; + private readonly DerInteger minimum; + private readonly DerInteger maximum; + + private GeneralSubtree( + Asn1Sequence seq) + { + baseName = GeneralName.GetInstance(seq[0]); + + switch (seq.Count) + { + case 1: + break; + case 2: + { + Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[1]); + switch (o.TagNo) + { + case 0: + minimum = DerInteger.GetInstance(o, false); + break; + case 1: + maximum = DerInteger.GetInstance(o, false); + break; + default: + throw new ArgumentException("Bad tag number: " + o.TagNo); + } + break; + } + case 3: + { + minimum = DerInteger.GetInstance(Asn1TaggedObject.GetInstance(seq[1])); + maximum = DerInteger.GetInstance(Asn1TaggedObject.GetInstance(seq[2])); + break; + } + default: + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + } + + /** + * Constructor from a given details. + * + * According RFC 3280, the minimum and maximum fields are not used with any + * name forms, thus minimum MUST be zero, and maximum MUST be absent. + *

      + * If minimum is null, zero is assumed, if + * maximum is null, maximum is absent.

      + * + * @param baseName + * A restriction. + * @param minimum + * Minimum + * + * @param maximum + * Maximum + */ + public GeneralSubtree( + GeneralName baseName, + BigInteger minimum, + BigInteger maximum) + { + this.baseName = baseName; + if (minimum != null) + { + this.minimum = new DerInteger(minimum); + } + if (maximum != null) + { + this.maximum = new DerInteger(maximum); + } + } + + public GeneralSubtree( + GeneralName baseName) + : this(baseName, null, null) + { + } + + public static GeneralSubtree GetInstance( + Asn1TaggedObject o, + bool isExplicit) + { + return new GeneralSubtree(Asn1Sequence.GetInstance(o, isExplicit)); + } + + public static GeneralSubtree GetInstance( + object obj) + { + if (obj == null) + { + return null; + } + + if (obj is GeneralSubtree) + { + return (GeneralSubtree) obj; + } + + return new GeneralSubtree(Asn1Sequence.GetInstance(obj)); + } + + public GeneralName Base + { + get { return baseName; } + } + + public BigInteger Minimum + { + get { return minimum == null ? BigInteger.Zero : minimum.Value; } + } + + public BigInteger Maximum + { + get { return maximum == null ? null : maximum.Value; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + * Returns: + * + *
      +		 *       GeneralSubtree ::= SEQUENCE
      +		 *       {
      +		 *         baseName                    GeneralName,
      +		 *         minimum         [0]     BaseDistance DEFAULT 0,
      +		 *         maximum         [1]     BaseDistance OPTIONAL
      +		 *       }
      +		 * 
      + * + * @return a DERObject + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(baseName); + + if (minimum != null && minimum.Value.SignValue != 0) + { + v.Add(new DerTaggedObject(false, 0, minimum)); + } + + if (maximum != null) + { + v.Add(new DerTaggedObject(false, 1, maximum)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/Holder.cs b/iTechSharp/srcbc/asn1/x509/Holder.cs new file mode 100644 index 0000000..d04f1cb --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/Holder.cs @@ -0,0 +1,257 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The Holder object. + *

      + * For an v2 attribute certificate this is: + * + *

      +	 *            Holder ::= SEQUENCE {
      +	 *                  baseCertificateID   [0] IssuerSerial OPTIONAL,
      +	 *                           -- the issuer and serial number of
      +	 *                           -- the holder's Public Key Certificate
      +	 *                  entityName          [1] GeneralNames OPTIONAL,
      +	 *                           -- the name of the claimant or role
      +	 *                  objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
      +	 *                           -- used to directly authenticate the holder,
      +	 *                           -- for example, an executable
      +	 *            }
      +	 * 
      + *

      + *

      + * For an v1 attribute certificate this is: + * + *

      +	 *         subject CHOICE {
      +	 *          baseCertificateID [0] IssuerSerial,
      +	 *          -- associated with a Public Key Certificate
      +	 *          subjectName [1] GeneralNames },
      +	 *          -- associated with a name
      +	 * 
      + *

      + */ + public class Holder + : Asn1Encodable + { + internal readonly IssuerSerial baseCertificateID; + internal readonly GeneralNames entityName; + internal readonly ObjectDigestInfo objectDigestInfo; + private readonly int version; + + public static Holder GetInstance( + object obj) + { + if (obj is Holder) + { + return (Holder) obj; + } + + if (obj is Asn1Sequence) + { + return new Holder((Asn1Sequence) obj); + } + + if (obj is Asn1TaggedObject) + { + return new Holder((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor for a holder for an v1 attribute certificate. + * + * @param tagObj The ASN.1 tagged holder object. + */ + public Holder( + Asn1TaggedObject tagObj) + { + switch (tagObj.TagNo) + { + case 0: + baseCertificateID = IssuerSerial.GetInstance(tagObj, false); + break; + case 1: + entityName = GeneralNames.GetInstance(tagObj, false); + break; + default: + throw new ArgumentException("unknown tag in Holder"); + } + + this.version = 0; + } + + /** + * Constructor for a holder for an v2 attribute certificate. * + * + * @param seq The ASN.1 sequence. + */ + private Holder( + Asn1Sequence seq) + { + if (seq.Count > 3) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[i]); + + switch (tObj.TagNo) + { + case 0: + baseCertificateID = IssuerSerial.GetInstance(tObj, false); + break; + case 1: + entityName = GeneralNames.GetInstance(tObj, false); + break; + case 2: + objectDigestInfo = ObjectDigestInfo.GetInstance(tObj, false); + break; + default: + throw new ArgumentException("unknown tag in Holder"); + } + } + + this.version = 1; + } + + public Holder( + IssuerSerial baseCertificateID) + : this(baseCertificateID, 1) + { + } + + /** + * Constructs a holder from a IssuerSerial. + * @param baseCertificateID The IssuerSerial. + * @param version The version of the attribute certificate. + */ + public Holder( + IssuerSerial baseCertificateID, + int version) + { + this.baseCertificateID = baseCertificateID; + this.version = version; + } + + /** + * Returns 1 for v2 attribute certificates or 0 for v1 attribute + * certificates. + * @return The version of the attribute certificate. + */ + public int Version + { + get { return version; } + } + + /** + * Constructs a holder with an entityName for v2 attribute certificates or + * with a subjectName for v1 attribute certificates. + * + * @param entityName The entity or subject name. + */ + public Holder( + GeneralNames entityName) + : this(entityName, 1) + { + } + + /** + * Constructs a holder with an entityName for v2 attribute certificates or + * with a subjectName for v1 attribute certificates. + * + * @param entityName The entity or subject name. + * @param version The version of the attribute certificate. + */ + public Holder( + GeneralNames entityName, + int version) + { + this.entityName = entityName; + this.version = version; + } + + /** + * Constructs a holder from an object digest info. + * + * @param objectDigestInfo The object digest info object. + */ + public Holder( + ObjectDigestInfo objectDigestInfo) + { + this.objectDigestInfo = objectDigestInfo; + this.version = 1; + } + + public IssuerSerial BaseCertificateID + { + get { return baseCertificateID; } + } + + /** + * Returns the entityName for an v2 attribute certificate or the subjectName + * for an v1 attribute certificate. + * + * @return The entityname or subjectname. + */ + public GeneralNames EntityName + { + get { return entityName; } + } + + public ObjectDigestInfo ObjectDigestInfo + { + get { return objectDigestInfo; } + } + + /** + * The Holder object. + *
      +         *  Holder ::= Sequence {
      +         *        baseCertificateID   [0] IssuerSerial OPTIONAL,
      +         *                 -- the issuer and serial number of
      +         *                 -- the holder's Public Key Certificate
      +         *        entityName          [1] GeneralNames OPTIONAL,
      +         *                 -- the name of the claimant or role
      +         *        objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
      +         *                 -- used to directly authenticate the holder,
      +         *                 -- for example, an executable
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + if (version == 1) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (baseCertificateID != null) + { + v.Add(new DerTaggedObject(false, 0, baseCertificateID)); + } + + if (entityName != null) + { + v.Add(new DerTaggedObject(false, 1, entityName)); + } + + if (objectDigestInfo != null) + { + v.Add(new DerTaggedObject(false, 2, objectDigestInfo)); + } + + return new DerSequence(v); + } + + if (entityName != null) + { + return new DerTaggedObject(false, 1, entityName); + } + + return new DerTaggedObject(false, 0, baseCertificateID); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/IetfAttrSyntax.cs b/iTechSharp/srcbc/asn1/x509/IetfAttrSyntax.cs new file mode 100644 index 0000000..e719865 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/IetfAttrSyntax.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Implementation of IetfAttrSyntax as specified by RFC3281. + */ + public class IetfAttrSyntax + : Asn1Encodable + { + public const int ValueOctets = 1; + public const int ValueOid = 2; + public const int ValueUtf8 = 3; + + internal readonly GeneralNames policyAuthority; + internal readonly Asn1EncodableVector values = new Asn1EncodableVector(); + + internal int valueChoice = -1; + + /** + * + */ + public IetfAttrSyntax( + Asn1Sequence seq) + { + int i = 0; + + if (seq[0] is Asn1TaggedObject) + { + policyAuthority = GeneralNames.GetInstance(((Asn1TaggedObject)seq[0]), false); + i++; + } + else if (seq.Count == 2) + { // VOMS fix + policyAuthority = GeneralNames.GetInstance(seq[0]); + i++; + } + + if (!(seq[i] is Asn1Sequence)) + { + throw new ArgumentException("Non-IetfAttrSyntax encoding"); + } + + seq = (Asn1Sequence) seq[i]; + + foreach (Asn1Object obj in seq) + { + int type; + + if (obj is DerObjectIdentifier) + { + type = ValueOid; + } + else if (obj is DerUtf8String) + { + type = ValueUtf8; + } + else if (obj is DerOctetString) + { + type = ValueOctets; + } + else + { + throw new ArgumentException("Bad value type encoding IetfAttrSyntax"); + } + + if (valueChoice < 0) + { + valueChoice = type; + } + + if (type != valueChoice) + { + throw new ArgumentException("Mix of value types in IetfAttrSyntax"); + } + + values.Add(obj); + } + } + + public GeneralNames PolicyAuthority + { + get { return policyAuthority; } + } + + public int ValueType + { + get { return valueChoice; } + } + + public object[] GetValues() + { + if (this.ValueType == ValueOctets) + { + Asn1OctetString[] tmp = new Asn1OctetString[values.Count]; + + for (int i = 0; i != tmp.Length; i++) + { + tmp[i] = (Asn1OctetString) values[i]; + } + + return tmp; + } + + if (this.ValueType == ValueOid) + { + DerObjectIdentifier[] tmp = new DerObjectIdentifier[values.Count]; + + for (int i = 0; i != tmp.Length; i++) + { + tmp[i] = (DerObjectIdentifier) values[i]; + } + + return tmp; + } + + { + DerUtf8String[] tmp = new DerUtf8String[values.Count]; + + for (int i = 0; i != tmp.Length; i++) + { + tmp[i] = (DerUtf8String) values[i]; + } + + return tmp; + } + } + + /** + * + *
      +         *
      +         *  IetfAttrSyntax ::= Sequence {
      +         *    policyAuthority [0] GeneralNames OPTIONAL,
      +         *    values Sequence OF CHOICE {
      +         *      octets OCTET STRING,
      +         *      oid OBJECT IDENTIFIER,
      +         *      string UTF8String
      +         *    }
      +         *  }
      +         *
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (policyAuthority != null) + { + v.Add(new DerTaggedObject(0, policyAuthority)); + } + + v.Add(new DerSequence(values)); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/IssuerSerial.cs b/iTechSharp/srcbc/asn1/x509/IssuerSerial.cs new file mode 100644 index 0000000..6a24e73 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/IssuerSerial.cs @@ -0,0 +1,98 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class IssuerSerial + : Asn1Encodable + { + internal readonly GeneralNames issuer; + internal readonly DerInteger serial; + internal readonly DerBitString issuerUid; + + public static IssuerSerial GetInstance( + object obj) + { + if (obj == null || obj is IssuerSerial) + { + return (IssuerSerial) obj; + } + + if (obj is Asn1Sequence) + { + return new IssuerSerial((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static IssuerSerial GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + private IssuerSerial( + Asn1Sequence seq) + { + if (seq.Count != 2 && seq.Count != 3) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + issuer = GeneralNames.GetInstance(seq[0]); + serial = DerInteger.GetInstance(seq[1]); + + if (seq.Count == 3) + { + issuerUid = DerBitString.GetInstance(seq[2]); + } + } + + public IssuerSerial( + GeneralNames issuer, + DerInteger serial) + { + this.issuer = issuer; + this.serial = serial; + } + + public GeneralNames Issuer + { + get { return issuer; } + } + + public DerInteger Serial + { + get { return serial; } + } + + public DerBitString IssuerUid + { + get { return issuerUid; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  IssuerSerial  ::=  Sequence {
      +         *       issuer         GeneralNames,
      +         *       serial         CertificateSerialNumber,
      +         *       issuerUid      UniqueIdentifier OPTIONAL
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + issuer, serial); + + if (issuerUid != null) + { + v.Add(issuerUid); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/IssuingDistributionPoint.cs b/iTechSharp/srcbc/asn1/x509/IssuingDistributionPoint.cs new file mode 100644 index 0000000..3af0d56 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/IssuingDistributionPoint.cs @@ -0,0 +1,247 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + *
      +	 * IssuingDistributionPoint ::= SEQUENCE { 
      +	 *   distributionPoint          [0] DistributionPointName OPTIONAL, 
      +	 *   onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE, 
      +	 *   onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE, 
      +	 *   onlySomeReasons            [3] ReasonFlags OPTIONAL, 
      +	 *   indirectCRL                [4] BOOLEAN DEFAULT FALSE,
      +	 *   onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
      +	 * 
      + */ + public class IssuingDistributionPoint + : Asn1Encodable + { + private readonly DistributionPointName _distributionPoint; + private readonly bool _onlyContainsUserCerts; + private readonly bool _onlyContainsCACerts; + private readonly ReasonFlags _onlySomeReasons; + private readonly bool _indirectCRL; + private readonly bool _onlyContainsAttributeCerts; + + private readonly Asn1Sequence seq; + + public static IssuingDistributionPoint GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static IssuingDistributionPoint GetInstance( + object obj) + { + if (obj == null || obj is IssuingDistributionPoint) + { + return (IssuingDistributionPoint) obj; + } + + if (obj is Asn1Sequence) + { + return new IssuingDistributionPoint((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from given details. + * + * @param distributionPoint + * May contain an URI as pointer to most current CRL. + * @param onlyContainsUserCerts Covers revocation information for end certificates. + * @param onlyContainsCACerts Covers revocation information for CA certificates. + * + * @param onlySomeReasons + * Which revocation reasons does this point cover. + * @param indirectCRL + * If true then the CRL contains revocation + * information about certificates ssued by other CAs. + * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates. + */ + public IssuingDistributionPoint( + DistributionPointName distributionPoint, + bool onlyContainsUserCerts, + bool onlyContainsCACerts, + ReasonFlags onlySomeReasons, + bool indirectCRL, + bool onlyContainsAttributeCerts) + { + this._distributionPoint = distributionPoint; + this._indirectCRL = indirectCRL; + this._onlyContainsAttributeCerts = onlyContainsAttributeCerts; + this._onlyContainsCACerts = onlyContainsCACerts; + this._onlyContainsUserCerts = onlyContainsUserCerts; + this._onlySomeReasons = onlySomeReasons; + + Asn1EncodableVector vec = new Asn1EncodableVector(); + if (distributionPoint != null) + { // CHOICE item so explicitly tagged + vec.Add(new DerTaggedObject(true, 0, distributionPoint)); + } + if (onlyContainsUserCerts) + { + vec.Add(new DerTaggedObject(false, 1, DerBoolean.True)); + } + if (onlyContainsCACerts) + { + vec.Add(new DerTaggedObject(false, 2, DerBoolean.True)); + } + if (onlySomeReasons != null) + { + vec.Add(new DerTaggedObject(false, 3, onlySomeReasons)); + } + if (indirectCRL) + { + vec.Add(new DerTaggedObject(false, 4, DerBoolean.True)); + } + if (onlyContainsAttributeCerts) + { + vec.Add(new DerTaggedObject(false, 5, DerBoolean.True)); + } + + seq = new DerSequence(vec); + } + + /** + * Constructor from Asn1Sequence + */ + private IssuingDistributionPoint( + Asn1Sequence seq) + { + this.seq = seq; + + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]); + + switch (o.TagNo) + { + case 0: + // CHOICE so explicit + _distributionPoint = DistributionPointName.GetInstance(o, true); + break; + case 1: + _onlyContainsUserCerts = DerBoolean.GetInstance(o, false).IsTrue; + break; + case 2: + _onlyContainsCACerts = DerBoolean.GetInstance(o, false).IsTrue; + break; + case 3: + _onlySomeReasons = new ReasonFlags(ReasonFlags.GetInstance(o, false)); + break; + case 4: + _indirectCRL = DerBoolean.GetInstance(o, false).IsTrue; + break; + case 5: + _onlyContainsAttributeCerts = DerBoolean.GetInstance(o, false).IsTrue; + break; + default: + throw new ArgumentException("unknown tag in IssuingDistributionPoint"); + } + } + } + + public bool OnlyContainsUserCerts + { + get { return _onlyContainsUserCerts; } + } + + public bool OnlyContainsCACerts + { + get { return _onlyContainsCACerts; } + } + + public bool IsIndirectCrl + { + get { return _indirectCRL; } + } + + public bool OnlyContainsAttributeCerts + { + get { return _onlyContainsAttributeCerts; } + } + + /** + * @return Returns the distributionPoint. + */ + public DistributionPointName DistributionPoint + { + get { return _distributionPoint; } + } + + /** + * @return Returns the onlySomeReasons. + */ + public ReasonFlags OnlySomeReasons + { + get { return _onlySomeReasons; } + } + + public override Asn1Object ToAsn1Object() + { + return seq; + } + + public override string ToString() + { + string sep = Platform.NewLine; + StringBuilder buf = new StringBuilder(); + + buf.Append("IssuingDistributionPoint: ["); + buf.Append(sep); + if (_distributionPoint != null) + { + appendObject(buf, sep, "distributionPoint", _distributionPoint.ToString()); + } + if (_onlyContainsUserCerts) + { + appendObject(buf, sep, "onlyContainsUserCerts", _onlyContainsUserCerts.ToString()); + } + if (_onlyContainsCACerts) + { + appendObject(buf, sep, "onlyContainsCACerts", _onlyContainsCACerts.ToString()); + } + if (_onlySomeReasons != null) + { + appendObject(buf, sep, "onlySomeReasons", _onlySomeReasons.ToString()); + } + if (_onlyContainsAttributeCerts) + { + appendObject(buf, sep, "onlyContainsAttributeCerts", _onlyContainsAttributeCerts.ToString()); + } + if (_indirectCRL) + { + appendObject(buf, sep, "indirectCRL", _indirectCRL.ToString()); + } + buf.Append("]"); + buf.Append(sep); + return buf.ToString(); + } + + private void appendObject( + StringBuilder buf, + string sep, + string name, + string val) + { + string indent = " "; + + buf.Append(indent); + buf.Append(name); + buf.Append(":"); + buf.Append(sep); + buf.Append(indent); + buf.Append(indent); + buf.Append(val); + buf.Append(sep); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/KeyPurposeId.cs b/iTechSharp/srcbc/asn1/x509/KeyPurposeId.cs new file mode 100644 index 0000000..4b48a9b --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/KeyPurposeId.cs @@ -0,0 +1,36 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The KeyPurposeID object. + *
      +     *     KeyPurposeID ::= OBJECT IDENTIFIER
      +     * 
      + */ + public sealed class KeyPurposeID + : DerObjectIdentifier + { + private const string IdKP = "1.3.6.1.5.5.7.3"; + + private KeyPurposeID( + string id) + : base(id) + { + } + + public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0"); + public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1"); + public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2"); + public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3"); + public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4"); + public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5"); + public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6"); + public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7"); + public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8"); + public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9"); + + // + // microsoft key purpose ids + // + public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2"); + } +} diff --git a/iTechSharp/srcbc/asn1/x509/KeyUsage.cs b/iTechSharp/srcbc/asn1/x509/KeyUsage.cs new file mode 100644 index 0000000..fef04e8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/KeyUsage.cs @@ -0,0 +1,79 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The KeyUsage object. + *
      +     *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
      +     *
      +     *    KeyUsage ::= BIT STRING {
      +     *         digitalSignature        (0),
      +     *         nonRepudiation          (1),
      +     *         keyEncipherment         (2),
      +     *         dataEncipherment        (3),
      +     *         keyAgreement            (4),
      +     *         keyCertSign             (5),
      +     *         cRLSign                 (6),
      +     *         encipherOnly            (7),
      +     *         decipherOnly            (8) }
      +     * 
      + */ + public class KeyUsage + : DerBitString + { + public const int DigitalSignature = (1 << 7); + public const int NonRepudiation = (1 << 6); + public const int KeyEncipherment = (1 << 5); + public const int DataEncipherment = (1 << 4); + public const int KeyAgreement = (1 << 3); + public const int KeyCertSign = (1 << 2); + public const int CrlSign = (1 << 1); + public const int EncipherOnly = (1 << 0); + public const int DecipherOnly = (1 << 15); + + public static new KeyUsage GetInstance( + object obj) + { + if (obj is KeyUsage) + { + return (KeyUsage)obj; + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + return new KeyUsage(DerBitString.GetInstance(obj)); + } + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment) + */ + public KeyUsage( + int usage) + : base(GetBytes(usage), GetPadBits(usage)) + { + } + + private KeyUsage( + DerBitString usage) + : base(usage.GetBytes(), usage.PadBits) + { + } + + public override string ToString() + { + byte[] data = GetBytes(); + if (data.Length == 1) + { + return "KeyUsage: 0x" + (data[0] & 0xff).ToString("X"); + } + + return "KeyUsage: 0x" + ((data[1] & 0xff) << 8 | (data[0] & 0xff)).ToString("X"); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/NameConstraints.cs b/iTechSharp/srcbc/asn1/x509/NameConstraints.cs new file mode 100644 index 0000000..d6e9c10 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/NameConstraints.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class NameConstraints + : Asn1Encodable + { + private Asn1Sequence permitted, excluded; + + public NameConstraints( + Asn1Sequence seq) + { + foreach (Asn1TaggedObject o in seq) + { + switch (o.TagNo) + { + case 0: + permitted = Asn1Sequence.GetInstance(o, false); + break; + case 1: + excluded = Asn1Sequence.GetInstance(o, false); + break; + } + } + } + + /** + * Constructor from a given details. + * + *

      permitted and excluded are Vectors of GeneralSubtree objects.

      + * + * @param permitted Permitted subtrees + * @param excluded Excluded subtrees + */ + public NameConstraints( + ArrayList permitted, + ArrayList excluded) + { + if (permitted != null) + { + this.permitted = createSequence(permitted); + } + + if (excluded != null) + { + this.excluded = createSequence(excluded); + } + } + + private DerSequence createSequence( + ArrayList subtree) + { + GeneralSubtree[] gsts = (GeneralSubtree[]) subtree.ToArray(typeof(GeneralSubtree)); + + return new DerSequence(gsts); + } + + public Asn1Sequence PermittedSubtrees + { + get { return permitted; } + } + + public Asn1Sequence ExcludedSubtrees + { + get { return excluded; } + } + + /* + * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees + * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL } + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (permitted != null) + { + v.Add(new DerTaggedObject(false, 0, permitted)); + } + + if (excluded != null) + { + v.Add(new DerTaggedObject(false, 1, excluded)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/NoticeReference.cs b/iTechSharp/srcbc/asn1/x509/NoticeReference.cs new file mode 100644 index 0000000..fd329dd --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/NoticeReference.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * NoticeReference class, used in + * CertificatePolicies X509 V3 extensions + * (in policy qualifiers). + * + *
      +	 *  NoticeReference ::= Sequence {
      +	 *      organization     DisplayText,
      +	 *      noticeNumbers    Sequence OF Integer }
      +	 *
      +	 * 
      + * + * @see PolicyQualifierInfo + * @see PolicyInformation + */ + public class NoticeReference + : Asn1Encodable + { + internal readonly DisplayText organization; + internal readonly Asn1Sequence noticeNumbers; + + /** + * Creates a new NoticeReference instance. + * + * @param orgName a string value + * @param numbers a ArrayList value + */ + public NoticeReference( + string orgName, + ArrayList numbers) + { + organization = new DisplayText(orgName); + + object o = numbers[0]; + + Asn1EncodableVector av = new Asn1EncodableVector(); + if (o is int) + { + foreach (int nm in numbers) + { + av.Add(new DerInteger(nm)); + } + } + + noticeNumbers = new DerSequence(av); + } + + /** + * Creates a new NoticeReference instance. + * + * @param orgName a string value + * @param numbers an Asn1Sequence value + */ + public NoticeReference( + string orgName, + Asn1Sequence numbers) + { + organization = new DisplayText(orgName); + noticeNumbers = numbers; + } + + /** + * Creates a new NoticeReference instance. + * + * @param displayTextType an int value + * @param orgName a string value + * @param numbers an Asn1Sequence value + */ + public NoticeReference( + int displayTextType, + string orgName, + Asn1Sequence numbers) + { + organization = new DisplayText(displayTextType, orgName); + noticeNumbers = numbers; + } + + /** + * Creates a new NoticeReference instance. + *

      Useful for reconstructing a NoticeReference + * instance from its encodable/encoded form.

      + * + * @param as an Asn1Sequence value obtained from either + * calling @{link ToAsn1Object()} for a NoticeReference + * instance or from parsing it from a Der-encoded stream. + */ + private NoticeReference( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + organization = DisplayText.GetInstance(seq[0]); + noticeNumbers = Asn1Sequence.GetInstance(seq[1]); + } + + public static NoticeReference GetInstance( + object obj) + { + if (obj is NoticeReference) + { + return (NoticeReference) obj; + } + + if (obj is Asn1Sequence) + { + return new NoticeReference((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + /** + * Describe ToAsn1Object method here. + * + * @return a Asn1Object value + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(organization, noticeNumbers); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/ObjectDigestInfo.cs b/iTechSharp/srcbc/asn1/x509/ObjectDigestInfo.cs new file mode 100644 index 0000000..6d5b9c6 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/ObjectDigestInfo.cs @@ -0,0 +1,177 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates. + * + *
      +	 *  
      +	 *    ObjectDigestInfo ::= SEQUENCE {
      +	 *         digestedObjectType  ENUMERATED {
      +	 *                 publicKey            (0),
      +	 *                 publicKeyCert        (1),
      +	 *                 otherObjectTypes     (2) },
      +	 *                         -- otherObjectTypes MUST NOT
      +	 *                         -- be used in this profile
      +	 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
      +	 *         digestAlgorithm     AlgorithmIdentifier,
      +	 *         objectDigest        BIT STRING
      +	 *    }
      +	 *   
      +	 * 
      + * + */ + public class ObjectDigestInfo + : Asn1Encodable + { + /** + * The public key is hashed. + */ + public const int PublicKey = 0; + + /** + * The public key certificate is hashed. + */ + public const int PublicKeyCert = 1; + + /** + * An other object is hashed. + */ + public const int OtherObjectDigest = 2; + + internal readonly DerEnumerated digestedObjectType; + internal readonly DerObjectIdentifier otherObjectTypeID; + internal readonly AlgorithmIdentifier digestAlgorithm; + internal readonly DerBitString objectDigest; + + public static ObjectDigestInfo GetInstance( + object obj) + { + if (obj == null || obj is ObjectDigestInfo) + { + return (ObjectDigestInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new ObjectDigestInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static ObjectDigestInfo GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit)); + } + + /** + * Constructor from given details. + *

      + * If digestedObjectType is not {@link #publicKeyCert} or + * {@link #publicKey} otherObjectTypeID must be given, + * otherwise it is ignored.

      + * + * @param digestedObjectType The digest object type. + * @param otherObjectTypeID The object type ID for + * otherObjectDigest. + * @param digestAlgorithm The algorithm identifier for the hash. + * @param objectDigest The hash value. + */ + public ObjectDigestInfo( + int digestedObjectType, + string otherObjectTypeID, + AlgorithmIdentifier digestAlgorithm, + byte[] objectDigest) + { + this.digestedObjectType = new DerEnumerated(digestedObjectType); + + if (digestedObjectType == OtherObjectDigest) + { + this.otherObjectTypeID = new DerObjectIdentifier(otherObjectTypeID); + } + + this.digestAlgorithm = digestAlgorithm; + + this.objectDigest = new DerBitString(objectDigest); + } + + private ObjectDigestInfo( + Asn1Sequence seq) + { + if (seq.Count > 4 || seq.Count < 3) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + digestedObjectType = DerEnumerated.GetInstance(seq[0]); + + int offset = 0; + + if (seq.Count == 4) + { + otherObjectTypeID = DerObjectIdentifier.GetInstance(seq[1]); + offset++; + } + + digestAlgorithm = AlgorithmIdentifier.GetInstance(seq[1 + offset]); + objectDigest = DerBitString.GetInstance(seq[2 + offset]); + } + + public DerEnumerated DigestedObjectType + { + get { return digestedObjectType; } + } + + public DerObjectIdentifier OtherObjectTypeID + { + get { return otherObjectTypeID; } + } + + public AlgorithmIdentifier DigestAlgorithm + { + get { return digestAlgorithm; } + } + + public DerBitString ObjectDigest + { + get { return objectDigest; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + *
      +		 *  
      +		 *    ObjectDigestInfo ::= SEQUENCE {
      +		 *         digestedObjectType  ENUMERATED {
      +		 *                 publicKey            (0),
      +		 *                 publicKeyCert        (1),
      +		 *                 otherObjectTypes     (2) },
      +		 *                         -- otherObjectTypes MUST NOT
      +		 *                         -- be used in this profile
      +		 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
      +		 *         digestAlgorithm     AlgorithmIdentifier,
      +		 *         objectDigest        BIT STRING
      +		 *    }
      +		 *   
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(digestedObjectType); + + if (otherObjectTypeID != null) + { + v.Add(otherObjectTypeID); + } + + v.Add(digestAlgorithm, objectDigest); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/PolicyInformation.cs b/iTechSharp/srcbc/asn1/x509/PolicyInformation.cs new file mode 100644 index 0000000..29d2450 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/PolicyInformation.cs @@ -0,0 +1,80 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class PolicyInformation + : Asn1Encodable + { + private readonly DerObjectIdentifier policyIdentifier; + private readonly Asn1Sequence policyQualifiers; + + private PolicyInformation( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + policyIdentifier = DerObjectIdentifier.GetInstance(seq[0]); + + if (seq.Count > 1) + { + policyQualifiers = Asn1Sequence.GetInstance(seq[1]); + } + } + + public PolicyInformation( + DerObjectIdentifier policyIdentifier) + { + this.policyIdentifier = policyIdentifier; + } + + public PolicyInformation( + DerObjectIdentifier policyIdentifier, + Asn1Sequence policyQualifiers) + { + this.policyIdentifier = policyIdentifier; + this.policyQualifiers = policyQualifiers; + } + + public static PolicyInformation GetInstance( + object obj) + { + if (obj == null || obj is PolicyInformation) + { + return (PolicyInformation) obj; + } + + return new PolicyInformation(Asn1Sequence.GetInstance(obj)); + } + + public DerObjectIdentifier PolicyIdentifier + { + get { return policyIdentifier; } + } + + public Asn1Sequence PolicyQualifiers + { + get { return policyQualifiers; } + } + + /* + * PolicyInformation ::= Sequence { + * policyIdentifier CertPolicyId, + * policyQualifiers Sequence SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(policyIdentifier); + + if (policyQualifiers != null) + { + v.Add(policyQualifiers); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/PolicyMappings.cs b/iTechSharp/srcbc/asn1/x509/PolicyMappings.cs new file mode 100644 index 0000000..9e1a31a --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/PolicyMappings.cs @@ -0,0 +1,62 @@ +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * PolicyMappings V3 extension, described in RFC3280. + *
      +	 *    PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
      +	 *      issuerDomainPolicy      CertPolicyId,
      +	 *      subjectDomainPolicy     CertPolicyId }
      +	 * 
      + * + * @see RFC 3280, section 4.2.1.6 + */ + public class PolicyMappings + : Asn1Encodable + { + private readonly Asn1Sequence seq; + + /** + * Creates a new PolicyMappings instance. + * + * @param seq an Asn1Sequence constructed as specified + * in RFC 3280 + */ + public PolicyMappings( + Asn1Sequence seq) + { + this.seq = seq; + } + + /** + * Creates a new PolicyMappings instance. + * + * @param mappings a HashMap value that maps + * string oids + * to other string oids. + */ + public PolicyMappings( + Hashtable mappings) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + foreach (string idp in mappings.Keys) + { + string sdp = (string) mappings[idp]; + + v.Add( + new DerSequence( + new DerObjectIdentifier(idp), + new DerObjectIdentifier(sdp))); + } + + seq = new DerSequence(v); + } + + public override Asn1Object ToAsn1Object() + { + return seq; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/PolicyQualifierId.cs b/iTechSharp/srcbc/asn1/x509/PolicyQualifierId.cs new file mode 100644 index 0000000..c858f08 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/PolicyQualifierId.cs @@ -0,0 +1,28 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * PolicyQualifierId, used in the CertificatePolicies + * X509V3 extension. + * + *
      +	 *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
      +	 *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
      +	 *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
      +	 *  PolicyQualifierId ::=
      +	 *       OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
      +	 * 
      + */ + public sealed class PolicyQualifierID : DerObjectIdentifier + { + private const string IdQt = "1.3.6.1.5.5.7.2"; + + private PolicyQualifierID( + string id) + : base(id) + { + } + + public static readonly PolicyQualifierID IdQtCps = new PolicyQualifierID(IdQt + ".1"); + public static readonly PolicyQualifierID IdQtUnotice = new PolicyQualifierID(IdQt + ".2"); + } +} diff --git a/iTechSharp/srcbc/asn1/x509/PolicyQualifierInfo.cs b/iTechSharp/srcbc/asn1/x509/PolicyQualifierInfo.cs new file mode 100644 index 0000000..187f8d3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/PolicyQualifierInfo.cs @@ -0,0 +1,91 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Policy qualifiers, used in the X509V3 CertificatePolicies + * extension. + * + *
      +	 *   PolicyQualifierInfo ::= Sequence {
      +	 *       policyQualifierId  PolicyQualifierId,
      +	 *       qualifier          ANY DEFINED BY policyQualifierId }
      +	 * 
      + */ + public class PolicyQualifierInfo + : Asn1Encodable + { + internal readonly DerObjectIdentifier policyQualifierId; + internal readonly Asn1Encodable qualifier; + + /** + * Creates a new PolicyQualifierInfo instance. + * + * @param policyQualifierId a PolicyQualifierId value + * @param qualifier the qualifier, defined by the above field. + */ + public PolicyQualifierInfo( + DerObjectIdentifier policyQualifierId, + Asn1Encodable qualifier) + { + this.policyQualifierId = policyQualifierId; + this.qualifier = qualifier; + } + + /** + * Creates a new PolicyQualifierInfo containing a + * cPSuri qualifier. + * + * @param cps the CPS (certification practice statement) uri as a + * string. + */ + public PolicyQualifierInfo( + string cps) + { + policyQualifierId = PolicyQualifierID.IdQtCps; + qualifier = new DerIA5String(cps); + } + + /** + * Creates a new PolicyQualifierInfo instance. + * + * @param as PolicyQualifierInfo X509 structure + * encoded as an Asn1Sequence. + */ + private PolicyQualifierInfo( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + policyQualifierId = DerObjectIdentifier.GetInstance(seq[0]); + qualifier = seq[1]; + } + + public static PolicyQualifierInfo GetInstance( + object obj) + { + if (obj is PolicyQualifierInfo) + { + return (PolicyQualifierInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new PolicyQualifierInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + /** + * Returns a Der-encodable representation of this instance. + * + * @return a Asn1Object value + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(policyQualifierId, qualifier); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/PrivateKeyUsagePeriod.cs b/iTechSharp/srcbc/asn1/x509/PrivateKeyUsagePeriod.cs new file mode 100644 index 0000000..ad2961e --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/PrivateKeyUsagePeriod.cs @@ -0,0 +1,82 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /// + ///
      +	/// PrivateKeyUsagePeriod ::= SEQUENCE
      +	/// {
      +	/// notBefore       [0]     GeneralizedTime OPTIONAL,
      +	/// notAfter        [1]     GeneralizedTime OPTIONAL }
      +	/// 
      + ///
      + public class PrivateKeyUsagePeriod + : Asn1Encodable + { + public static PrivateKeyUsagePeriod GetInstance( + object obj) + { + if (obj is PrivateKeyUsagePeriod) + { + return (PrivateKeyUsagePeriod) obj; + } + + if (obj is Asn1Sequence) + { + return new PrivateKeyUsagePeriod((Asn1Sequence) obj); + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + private DerGeneralizedTime _notBefore, _notAfter; + + private PrivateKeyUsagePeriod( + Asn1Sequence seq) + { + foreach (Asn1TaggedObject tObj in seq) + { + if (tObj.TagNo == 0) + { + _notBefore = DerGeneralizedTime.GetInstance(tObj, false); + } + else if (tObj.TagNo == 1) + { + _notAfter = DerGeneralizedTime.GetInstance(tObj, false); + } + } + } + + public DerGeneralizedTime NotBefore + { + get { return _notBefore; } + } + + public DerGeneralizedTime NotAfter + { + get { return _notAfter; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (_notBefore != null) + { + v.Add(new DerTaggedObject(false, 0, _notBefore)); + } + + if (_notAfter != null) + { + v.Add(new DerTaggedObject(false, 1, _notAfter)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/RSAPublicKeyStructure.cs b/iTechSharp/srcbc/asn1/x509/RSAPublicKeyStructure.cs new file mode 100644 index 0000000..d5e75f1 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/RSAPublicKeyStructure.cs @@ -0,0 +1,82 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class RsaPublicKeyStructure + : Asn1Encodable + { + private BigInteger modulus; + private BigInteger publicExponent; + + public static RsaPublicKeyStructure GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static RsaPublicKeyStructure GetInstance( + object obj) + { + if (obj == null || obj is RsaPublicKeyStructure) + { + return (RsaPublicKeyStructure) obj; + } + + if (obj is Asn1Sequence) + { + return new RsaPublicKeyStructure((Asn1Sequence) obj); + } + + throw new ArgumentException("Invalid RsaPublicKeyStructure: " + obj.GetType().Name); + } + + public RsaPublicKeyStructure( + BigInteger modulus, + BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + private RsaPublicKeyStructure( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + modulus = DerInteger.GetInstance(seq[0]).PositiveValue; + publicExponent = DerInteger.GetInstance(seq[1]).PositiveValue; + } + + public BigInteger Modulus + { + get { return modulus; } + } + + public BigInteger PublicExponent + { + get { return publicExponent; } + } + + /** + * This outputs the key in Pkcs1v2 format. + *
      +         *      RSAPublicKey ::= Sequence {
      +         *                          modulus Integer, -- n
      +         *                          publicExponent Integer, -- e
      +         *                      }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence( + new DerInteger(Modulus), + new DerInteger(PublicExponent)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/ReasonFlags.cs b/iTechSharp/srcbc/asn1/x509/ReasonFlags.cs new file mode 100644 index 0000000..f204c36 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/ReasonFlags.cs @@ -0,0 +1,46 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The ReasonFlags object. + *
      +     * ReasonFlags ::= BIT STRING {
      +     *    unused(0),
      +     *    keyCompromise(1),
      +     *    cACompromise(2),
      +     *    affiliationChanged(3),
      +     *    superseded(4),
      +     *    cessationOfOperation(5),
      +     *    certficateHold(6)
      +     * }
      +     * 
      + */ + public class ReasonFlags + : DerBitString + { + public const int Unused = (1 << 7); + public const int KeyCompromise = (1 << 6); + public const int CACompromise = (1 << 5); + public const int AffiliationChanged = (1 << 4); + public const int Superseded = (1 << 3); + public const int CessationOfOperation = (1 << 2); + public const int CertificateHold = (1 << 1); + public const int PrivilegeWithdrawn = (1 << 0); + public const int AACompromise = (1 << 15); + + /** + * @param reasons - the bitwise OR of the Key Reason flags giving the + * allowed uses for the key. + */ + public ReasonFlags( + int reasons) + : base(GetBytes(reasons), GetPadBits(reasons)) + { + } + + public ReasonFlags( + DerBitString reasons) + : base(reasons.GetBytes(), reasons.PadBits) + { + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/RoleSyntax.cs b/iTechSharp/srcbc/asn1/x509/RoleSyntax.cs new file mode 100644 index 0000000..7058363 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/RoleSyntax.cs @@ -0,0 +1,234 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Implementation of the RoleSyntax object as specified by the RFC3281. + * + *
      +	* RoleSyntax ::= SEQUENCE {
      +	*                 roleAuthority  [0] GeneralNames OPTIONAL,
      +	*                 roleName       [1] GeneralName
      +	*           }
      +	* 
      + */ + public class RoleSyntax + : Asn1Encodable + { + private readonly GeneralNames roleAuthority; + private readonly GeneralName roleName; + + /** + * RoleSyntax factory method. + * @param obj the object used to construct an instance of + * RoleSyntax. It must be an instance of RoleSyntax + * or Asn1Sequence. + * @return the instance of RoleSyntax built from the + * supplied object. + * @throws java.lang.ArgumentException if the object passed + * to the factory is not an instance of RoleSyntax or + * Asn1Sequence. + */ + public static RoleSyntax GetInstance( + object obj) + { + if (obj == null || obj is RoleSyntax) + { + return (RoleSyntax) obj; + } + + if (obj is Asn1Sequence) + { + return new RoleSyntax((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in 'RoleSyntax' factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor. + * @param roleAuthority the role authority of this RoleSyntax. + * @param roleName the role name of this RoleSyntax. + */ + public RoleSyntax( + GeneralNames roleAuthority, + GeneralName roleName) + { + if (roleName == null + || roleName.TagNo != GeneralName.UniformResourceIdentifier + || ((IAsn1String) roleName.Name).GetString().Equals("")) + { + throw new ArgumentException("the role name MUST be non empty and MUST " + + "use the URI option of GeneralName"); + } + + this.roleAuthority = roleAuthority; + this.roleName = roleName; + } + + /** + * Constructor. Invoking this constructor is the same as invoking + * new RoleSyntax(null, roleName). + * @param roleName the role name of this RoleSyntax. + */ + public RoleSyntax( + GeneralName roleName) + : this(null, roleName) + { + } + + /** + * Utility constructor. Takes a string argument representing + * the role name, builds a GeneralName to hold the role name + * and calls the constructor that takes a GeneralName. + * @param roleName + */ + public RoleSyntax( + string roleName) + : this(new GeneralName(GeneralName.UniformResourceIdentifier, + (roleName == null)? "": roleName)) + { + } + + /** + * Constructor that builds an instance of RoleSyntax by + * extracting the encoded elements from the Asn1Sequence + * object supplied. + * @param seq an instance of Asn1Sequence that holds + * the encoded elements used to build this RoleSyntax. + */ + private RoleSyntax( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]); + switch (taggedObject.TagNo) + { + case 0: + roleAuthority = GeneralNames.GetInstance(taggedObject, false); + break; + case 1: + roleName = GeneralName.GetInstance(taggedObject, false); + break; + default: + throw new ArgumentException("Unknown tag in RoleSyntax"); + } + } + } + + /** + * Gets the role authority of this RoleSyntax. + * @return an instance of GeneralNames holding the + * role authority of this RoleSyntax. + */ + public GeneralNames RoleAuthority + { + get { return this.roleAuthority; } + } + + /** + * Gets the role name of this RoleSyntax. + * @return an instance of GeneralName holding the + * role name of this RoleSyntax. + */ + public GeneralName RoleName + { + get { return this.roleName; } + } + + /** + * Gets the role name as a java.lang.string object. + * @return the role name of this RoleSyntax represented as a + * string object. + */ + public string GetRoleNameAsString() + { + return ((IAsn1String) this.roleName.Name).GetString(); + } + + /** + * Gets the role authority as a string[] object. + * @return the role authority of this RoleSyntax represented as a + * string[] array. + */ + public string[] GetRoleAuthorityAsString() + { + if (roleAuthority == null) + { + return new string[0]; + } + + GeneralName[] names = roleAuthority.GetNames(); + string[] namesString = new string[names.Length]; + for(int i = 0; i < names.Length; i++) + { + Asn1Encodable asn1Value = names[i].Name; + if (asn1Value is IAsn1String) + { + namesString[i] = ((IAsn1String) asn1Value).GetString(); + } + else + { + namesString[i] = asn1Value.ToString(); + } + } + + return namesString; + } + + /** + * Implementation of the method ToAsn1Object as + * required by the superclass ASN1Encodable. + * + *
      +		* RoleSyntax ::= SEQUENCE {
      +		*                 roleAuthority  [0] GeneralNames OPTIONAL,
      +		*                 roleName       [1] GeneralName
      +		*           }
      +		* 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (this.roleAuthority != null) + { + v.Add(new DerTaggedObject(false, 0, roleAuthority)); + } + + v.Add(new DerTaggedObject(false, 1, roleName)); + + return new DerSequence(v); + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder("Name: " + this.GetRoleNameAsString() + + " - Auth: "); + + if (this.roleAuthority == null || roleAuthority.GetNames().Length == 0) + { + buff.Append("N/A"); + } + else + { + string[] names = this.GetRoleAuthorityAsString(); + buff.Append('[').Append(names[0]); + for(int i = 1; i < names.Length; i++) + { + buff.Append(", ").Append(names[i]); + } + buff.Append(']'); + } + + return buff.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/SubjectDirectoryAttributes.cs b/iTechSharp/srcbc/asn1/x509/SubjectDirectoryAttributes.cs new file mode 100644 index 0000000..93beaec --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/SubjectDirectoryAttributes.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * This extension may contain further X.500 attributes of the subject. See also + * RFC 3039. + * + *
      +	 *     SubjectDirectoryAttributes ::= Attributes
      +	 *     Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
      +	 *     Attribute ::= SEQUENCE
      +	 *     {
      +	 *       type AttributeType
      +	 *       values SET OF AttributeValue
      +	 *     }
      +	 *
      +	 *     AttributeType ::= OBJECT IDENTIFIER
      +	 *     AttributeValue ::= ANY DEFINED BY AttributeType
      +	 * 
      + * + * @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers. + */ + public class SubjectDirectoryAttributes + : Asn1Encodable + { + private readonly ArrayList attributes = new ArrayList(); + + public static SubjectDirectoryAttributes GetInstance( + object obj) + { + if (obj == null || obj is SubjectDirectoryAttributes) + { + return (SubjectDirectoryAttributes) obj; + } + + if (obj is Asn1Sequence) + { + return new SubjectDirectoryAttributes((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + * + * The sequence is of type SubjectDirectoryAttributes: + * + *
      +		 *      SubjectDirectoryAttributes ::= Attributes
      +		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
      +		 *      Attribute ::= SEQUENCE
      +		 *      {
      +		 *        type AttributeType
      +		 *        values SET OF AttributeValue
      +		 *      }
      +		 *
      +		 *      AttributeType ::= OBJECT IDENTIFIER
      +		 *      AttributeValue ::= ANY DEFINED BY AttributeType
      +		 * 
      + * + * @param seq + * The ASN.1 sequence. + */ + private SubjectDirectoryAttributes( + Asn1Sequence seq) + { + foreach (object o in seq) + { + Asn1Sequence s = Asn1Sequence.GetInstance(o); + attributes.Add(AttributeX509.GetInstance(s)); + } + } + + /** + * Constructor from an ArrayList of attributes. + * + * The ArrayList consists of attributes of type {@link Attribute Attribute} + * + * @param attributes The attributes. + * + */ + public SubjectDirectoryAttributes( + ArrayList attributes) + { + this.attributes.AddRange(attributes); + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + * Returns: + * + *
      +		 *      SubjectDirectoryAttributes ::= Attributes
      +		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
      +		 *      Attribute ::= SEQUENCE
      +		 *      {
      +		 *        type AttributeType
      +		 *        values SET OF AttributeValue
      +		 *      }
      +		 *
      +		 *      AttributeType ::= OBJECT IDENTIFIER
      +		 *      AttributeValue ::= ANY DEFINED BY AttributeType
      +		 * 
      + * + * @return a DERObject + */ + public override Asn1Object ToAsn1Object() + { + AttributeX509[] v = (AttributeX509[]) attributes.ToArray(typeof(AttributeX509)); + + return new DerSequence(v); + } + + /** + * @return Returns the attributes. + */ + public IEnumerable Attributes + { + get { return new EnumerableProxy(attributes); } + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/SubjectKeyIdentifier.cs b/iTechSharp/srcbc/asn1/x509/SubjectKeyIdentifier.cs new file mode 100644 index 0000000..02e7de4 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/SubjectKeyIdentifier.cs @@ -0,0 +1,95 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The SubjectKeyIdentifier object. + *
      +     * SubjectKeyIdentifier::= OCTET STRING
      +     * 
      + */ + public class SubjectKeyIdentifier + : Asn1Encodable + { + private readonly byte[] keyIdentifier; + + public static SubjectKeyIdentifier GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1OctetString.GetInstance(obj, explicitly)); + } + + public static SubjectKeyIdentifier GetInstance( + object obj) + { + if (obj is SubjectKeyIdentifier) + { + return (SubjectKeyIdentifier) obj; + } + + if (obj is SubjectPublicKeyInfo) + { + return new SubjectKeyIdentifier((SubjectPublicKeyInfo) obj); + } + + if (obj is Asn1OctetString) + { + return new SubjectKeyIdentifier((Asn1OctetString) obj); + } + + if (obj is X509Extension) + { + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + } + + throw new ArgumentException("Invalid SubjectKeyIdentifier: " + obj.GetType().Name); + } + + public SubjectKeyIdentifier( + byte[] keyID) + { + if (keyID == null) + throw new ArgumentNullException("keyID"); + + this.keyIdentifier = keyID; + } + + public SubjectKeyIdentifier( + Asn1OctetString keyID) + { + this.keyIdentifier = keyID.GetOctets(); + } + + /** + * + * Calulates the keyIdentifier using a SHA1 hash over the BIT STRING + * from SubjectPublicKeyInfo as defined in RFC2459. + * + **/ + public SubjectKeyIdentifier( + SubjectPublicKeyInfo spki) + { + IDigest digest = new Sha1Digest(); + byte[] resBuf = new byte[digest.GetDigestSize()]; + + byte[] bytes = spki.PublicKeyData.GetBytes(); + digest.BlockUpdate(bytes, 0, bytes.Length); + digest.DoFinal(resBuf, 0); + this.keyIdentifier = resBuf; + } + + public byte[] GetKeyIdentifier() + { + return keyIdentifier; + } + + public override Asn1Object ToAsn1Object() + { + return new DerOctetString(keyIdentifier); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/SubjectPublicKeyInfo.cs b/iTechSharp/srcbc/asn1/x509/SubjectPublicKeyInfo.cs new file mode 100644 index 0000000..07e6868 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/SubjectPublicKeyInfo.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The object that contains the public key stored in a certficate. + *

      + * The GetEncoded() method in the public keys in the JCE produces a DER + * encoded one of these.

      + */ + public class SubjectPublicKeyInfo + : Asn1Encodable + { + private readonly AlgorithmIdentifier algID; + private readonly DerBitString keyData; + + public static SubjectPublicKeyInfo GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static SubjectPublicKeyInfo GetInstance( + object obj) + { + if (obj is SubjectPublicKeyInfo) + { + return (SubjectPublicKeyInfo) obj; + } + + if (obj is Asn1Sequence) + { + return new SubjectPublicKeyInfo((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public SubjectPublicKeyInfo( + AlgorithmIdentifier algID, + Asn1Encodable publicKey) + { + this.keyData = new DerBitString(publicKey); + this.algID = algID; + } + + public SubjectPublicKeyInfo( + AlgorithmIdentifier algID, + byte[] publicKey) + { + this.keyData = new DerBitString(publicKey); + this.algID = algID; + } + + private SubjectPublicKeyInfo( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + this.algID = AlgorithmIdentifier.GetInstance(seq[0]); + this.keyData = DerBitString.GetInstance(seq[1]); + } + + public AlgorithmIdentifier AlgorithmID + { + get { return algID; } + } + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine raises an IOException. + * + * @exception IOException - if the bit string doesn't represent a Der + * encoded object. + */ + public Asn1Object GetPublicKey() + { + return Asn1Object.FromByteArray(keyData.GetBytes()); + } + + /** + * for when the public key is raw bits... + */ + public DerBitString PublicKeyData + { + get { return keyData; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * SubjectPublicKeyInfo ::= Sequence {
      +         *                          algorithm AlgorithmIdentifier,
      +         *                          publicKey BIT STRING }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(algID, keyData); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/TBSCertList.cs b/iTechSharp/srcbc/asn1/x509/TBSCertList.cs new file mode 100644 index 0000000..b5934a2 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/TBSCertList.cs @@ -0,0 +1,274 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class CrlEntry + : Asn1Encodable + { + internal Asn1Sequence seq; + internal DerInteger userCertificate; + internal Time revocationDate; + internal X509Extensions crlEntryExtensions; + + public CrlEntry( + Asn1Sequence seq) + { + if (seq.Count < 2 || seq.Count > 3) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + this.seq = seq; + + userCertificate = DerInteger.GetInstance(seq[0]); + revocationDate = Time.GetInstance(seq[1]); + } + + public DerInteger UserCertificate + { + get { return userCertificate; } + } + + public Time RevocationDate + { + get { return revocationDate; } + } + + public X509Extensions Extensions + { + get + { + if (crlEntryExtensions == null && seq.Count == 3) + { + crlEntryExtensions = X509Extensions.GetInstance(seq[2]); + } + + return crlEntryExtensions; + } + } + + public override Asn1Object ToAsn1Object() + { + return seq; + } + } + + /** + * PKIX RFC-2459 - TbsCertList object. + *
      +     * TbsCertList  ::=  Sequence  {
      +     *      version                 Version OPTIONAL,
      +     *                                   -- if present, shall be v2
      +     *      signature               AlgorithmIdentifier,
      +     *      issuer                  Name,
      +     *      thisUpdate              Time,
      +     *      nextUpdate              Time OPTIONAL,
      +     *      revokedCertificates     Sequence OF Sequence  {
      +     *           userCertificate         CertificateSerialNumber,
      +     *           revocationDate          Time,
      +     *           crlEntryExtensions      Extensions OPTIONAL
      +     *                                         -- if present, shall be v2
      +     *                                }  OPTIONAL,
      +     *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
      +     *                                         -- if present, shall be v2
      +     *                                }
      +     * 
      + */ + public class TbsCertificateList + : Asn1Encodable + { + private class RevokedCertificatesEnumeration + : IEnumerable + { + private readonly IEnumerable en; + + internal RevokedCertificatesEnumeration( + IEnumerable en) + { + this.en = en; + } + + public IEnumerator GetEnumerator() + { + return new RevokedCertificatesEnumerator(en.GetEnumerator()); + } + + private class RevokedCertificatesEnumerator + : IEnumerator + { + private readonly IEnumerator e; + + internal RevokedCertificatesEnumerator( + IEnumerator e) + { + this.e = e; + } + + public bool MoveNext() + { + return e.MoveNext(); + } + + public void Reset() + { + e.Reset(); + } + + public object Current + { + get { return new CrlEntry(Asn1Sequence.GetInstance(e.Current)); } + } + } + } + + internal Asn1Sequence seq; + internal DerInteger version; + internal AlgorithmIdentifier signature; + internal X509Name issuer; + internal Time thisUpdate; + internal Time nextUpdate; + internal Asn1Sequence revokedCertificates; + internal X509Extensions crlExtensions; + + public static TbsCertificateList GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static TbsCertificateList GetInstance( + object obj) + { + TbsCertificateList list = obj as TbsCertificateList; + + if (obj == null || list != null) + { + return list; + } + + if (obj is Asn1Sequence) + { + return new TbsCertificateList((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + internal TbsCertificateList( + Asn1Sequence seq) + { + if (seq.Count < 3 || seq.Count > 7) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + int seqPos = 0; + + this.seq = seq; + + if (seq[seqPos] is DerInteger) + { + version = DerInteger.GetInstance(seq[seqPos++]); + } + else + { + version = new DerInteger(0); + } + + signature = AlgorithmIdentifier.GetInstance(seq[seqPos++]); + issuer = X509Name.GetInstance(seq[seqPos++]); + thisUpdate = Time.GetInstance(seq[seqPos++]); + + if (seqPos < seq.Count + && (seq[seqPos] is DerUtcTime + || seq[seqPos] is DerGeneralizedTime + || seq[seqPos] is Time)) + { + nextUpdate = Time.GetInstance(seq[seqPos++]); + } + + if (seqPos < seq.Count + && !(seq[seqPos] is DerTaggedObject)) + { + revokedCertificates = Asn1Sequence.GetInstance(seq[seqPos++]); + } + + if (seqPos < seq.Count + && seq[seqPos] is DerTaggedObject) + { + crlExtensions = X509Extensions.GetInstance(seq[seqPos]); + } + } + + public int Version + { + get { return version.Value.IntValue + 1; } + } + + public DerInteger VersionNumber + { + get { return version; } + } + + public AlgorithmIdentifier Signature + { + get { return signature; } + } + + public X509Name Issuer + { + get { return issuer; } + } + + public Time ThisUpdate + { + get { return thisUpdate; } + } + + public Time NextUpdate + { + get { return nextUpdate; } + } + + public CrlEntry[] GetRevokedCertificates() + { + if (revokedCertificates == null) + { + return new CrlEntry[0]; + } + + CrlEntry[] entries = new CrlEntry[revokedCertificates.Count]; + + for (int i = 0; i < entries.Length; i++) + { + entries[i] = new CrlEntry(Asn1Sequence.GetInstance(revokedCertificates[i])); + } + + return entries; + } + + public IEnumerable GetRevokedCertificateEnumeration() + { + if (revokedCertificates == null) + { + return EmptyEnumerable.Instance; + } + + return new RevokedCertificatesEnumeration(revokedCertificates); + } + + public X509Extensions Extensions + { + get { return crlExtensions; } + } + + public override Asn1Object ToAsn1Object() + { + return seq; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/TBSCertificateStructure.cs b/iTechSharp/srcbc/asn1/x509/TBSCertificateStructure.cs new file mode 100644 index 0000000..03bc6be --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/TBSCertificateStructure.cs @@ -0,0 +1,189 @@ +using System; + +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The TbsCertificate object. + *
      +     * TbsCertificate ::= Sequence {
      +     *      version          [ 0 ]  Version DEFAULT v1(0),
      +     *      serialNumber            CertificateSerialNumber,
      +     *      signature               AlgorithmIdentifier,
      +     *      issuer                  Name,
      +     *      validity                Validity,
      +     *      subject                 Name,
      +     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
      +     *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
      +     *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
      +     *      extensions        [ 3 ] Extensions OPTIONAL
      +     *      }
      +     * 
      + *

      + * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class + * will parse them, but you really shouldn't be creating new ones.

      + */ + public class TbsCertificateStructure + : Asn1Encodable + { + internal Asn1Sequence seq; + internal DerInteger version; + internal DerInteger serialNumber; + internal AlgorithmIdentifier signature; + internal X509Name issuer; + internal Time startDate, endDate; + internal X509Name subject; + internal SubjectPublicKeyInfo subjectPublicKeyInfo; + internal DerBitString issuerUniqueID; + internal DerBitString subjectUniqueID; + internal X509Extensions extensions; + + public static TbsCertificateStructure GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static TbsCertificateStructure GetInstance( + object obj) + { + if (obj is TbsCertificateStructure) + { + return (TbsCertificateStructure) obj; + } + + if (obj is Asn1Sequence) + { + return new TbsCertificateStructure((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + internal TbsCertificateStructure( + Asn1Sequence seq) + { + int seqStart = 0; + + this.seq = seq; + + // + // some certficates don't include a version number - we assume v1 + // + if (seq[0] is DerTaggedObject) + { + version = DerInteger.GetInstance(seq[0]); + } + else + { + seqStart = -1; // field 0 is missing! + version = new DerInteger(0); + } + + serialNumber = DerInteger.GetInstance(seq[seqStart + 1]); + + signature = AlgorithmIdentifier.GetInstance(seq[seqStart + 2]); + issuer = X509Name.GetInstance(seq[seqStart + 3]); + + // + // before and after dates + // + Asn1Sequence dates = (Asn1Sequence)seq[seqStart + 4]; + + startDate = Time.GetInstance(dates[0]); + endDate = Time.GetInstance(dates[1]); + + subject = X509Name.GetInstance(seq[seqStart + 5]); + + // + // public key info. + // + subjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(seq[seqStart + 6]); + + for (int extras = seq.Count - (seqStart + 6) - 1; extras > 0; extras--) + { + DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras]; + + switch (extra.TagNo) + { + case 1: + issuerUniqueID = DerBitString.GetInstance(extra, false); + break; + case 2: + subjectUniqueID = DerBitString.GetInstance(extra, false); + break; + case 3: + extensions = X509Extensions.GetInstance(extra); + break; + } + } + } + + public int Version + { + get { return version.Value.IntValue + 1; } + } + + public DerInteger VersionNumber + { + get { return version; } + } + + public DerInteger SerialNumber + { + get { return serialNumber; } + } + + public AlgorithmIdentifier Signature + { + get { return signature; } + } + + public X509Name Issuer + { + get { return issuer; } + } + + public Time StartDate + { + get { return startDate; } + } + + public Time EndDate + { + get { return endDate; } + } + + public X509Name Subject + { + get { return subject; } + } + + public SubjectPublicKeyInfo SubjectPublicKeyInfo + { + get { return subjectPublicKeyInfo; } + } + + public DerBitString IssuerUniqueID + { + get { return issuerUniqueID; } + } + + public DerBitString SubjectUniqueID + { + get { return subjectUniqueID; } + } + + public X509Extensions Extensions + { + get { return extensions; } + } + + public override Asn1Object ToAsn1Object() + { + return seq; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/Target.cs b/iTechSharp/srcbc/asn1/x509/Target.cs new file mode 100644 index 0000000..2b1d6f5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/Target.cs @@ -0,0 +1,140 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Target structure used in target information extension for attribute + * certificates from RFC 3281. + * + *
      +	 *     Target  ::= CHOICE {
      +	 *       targetName          [0] GeneralName,
      +	 *       targetGroup         [1] GeneralName,
      +	 *       targetCert          [2] TargetCert
      +	 *     }
      +	 * 
      + * + *

      + * The targetCert field is currently not supported and must not be used + * according to RFC 3281.

      + */ + public class Target + : Asn1Encodable + //, ASN1Choice + { + public enum Choice + { + Name = 0, + Group = 1 + }; + + private readonly GeneralName targetName; + private readonly GeneralName targetGroup; + + /** + * Creates an instance of a Target from the given object. + *

      + * obj can be a Target or a {@link Asn1TaggedObject}

      + * + * @param obj The object. + * @return A Target instance. + * @throws ArgumentException if the given object cannot be + * interpreted as Target. + */ + public static Target GetInstance( + object obj) + { + if (obj is Target) + { + return (Target) obj; + } + + if (obj is Asn1TaggedObject) + { + return new Target((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1TaggedObject. + * + * @param tagObj The tagged object. + * @throws ArgumentException if the encoding is wrong. + */ + private Target( + Asn1TaggedObject tagObj) + { + switch ((Choice) tagObj.TagNo) + { + case Choice.Name: // GeneralName is already a choice so explicit + targetName = GeneralName.GetInstance(tagObj, true); + break; + case Choice.Group: + targetGroup = GeneralName.GetInstance(tagObj, true); + break; + default: + throw new ArgumentException("unknown tag: " + tagObj.TagNo); + } + } + + /** + * Constructor from given details. + *

      + * Exactly one of the parameters must be not null.

      + * + * @param type the choice type to apply to the name. + * @param name the general name. + * @throws ArgumentException if type is invalid. + */ + public Target( + Choice type, + GeneralName name) + : this(new DerTaggedObject((int) type, name)) + { + } + + /** + * @return Returns the targetGroup. + */ + public virtual GeneralName TargetGroup + { + get { return targetGroup; } + } + + /** + * @return Returns the targetName. + */ + public virtual GeneralName TargetName + { + get { return targetName; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + * Returns: + * + *
      +		 *     Target  ::= CHOICE {
      +		 *       targetName          [0] GeneralName,
      +		 *       targetGroup         [1] GeneralName,
      +		 *       targetCert          [2] TargetCert
      +		 *     }
      +		 * 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + // GeneralName is a choice already so most be explicitly tagged + if (targetName != null) + { + return new DerTaggedObject(true, 0, targetName); + } + + return new DerTaggedObject(true, 1, targetGroup); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/TargetInformation.cs b/iTechSharp/srcbc/asn1/x509/TargetInformation.cs new file mode 100644 index 0000000..75b18c0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/TargetInformation.cs @@ -0,0 +1,123 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Target information extension for attributes certificates according to RFC + * 3281. + * + *
      +	 *           SEQUENCE OF Targets
      +	 * 
      + * + */ + public class TargetInformation + : Asn1Encodable + { + private readonly Asn1Sequence targets; + + /** + * Creates an instance of a TargetInformation from the given object. + *

      + * obj can be a TargetInformation or a {@link Asn1Sequence}

      + * + * @param obj The object. + * @return A TargetInformation instance. + * @throws ArgumentException if the given object cannot be interpreted as TargetInformation. + */ + public static TargetInformation GetInstance( + object obj) + { + if (obj is TargetInformation) + { + return (TargetInformation) obj; + } + + if (obj is Asn1Sequence) + { + return new TargetInformation((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from a Asn1Sequence. + * + * @param seq The Asn1Sequence. + * @throws ArgumentException if the sequence does not contain + * correctly encoded Targets elements. + */ + private TargetInformation( + Asn1Sequence targets) + { + this.targets = targets; + } + + /** + * Returns the targets in this target information extension. + *

      + * The ArrayList is cloned before it is returned.

      + * + * @return Returns the targets. + */ + public virtual Targets[] GetTargetsObjects() + { + Targets[] result = new Targets[targets.Count]; + + for (int i = 0; i < targets.Count; ++i) + { + result[i] = Targets.GetInstance(targets[i]); + } + + return result; + } + + /** + * Constructs a target information from a single targets element. + * According to RFC 3281 only one targets element must be produced. + * + * @param targets A Targets instance. + */ + public TargetInformation( + Targets targets) + { + this.targets = new DerSequence(targets); + } + + /** + * According to RFC 3281 only one targets element must be produced. If + * multiple targets are given they must be merged in + * into one targets element. + * + * @param targets An array with {@link Targets}. + */ + public TargetInformation( + Target[] targets) + : this(new Targets(targets)) + { + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + * Returns: + * + *
      +		 *          SEQUENCE OF Targets
      +		 * 
      + * + *

      + * According to RFC 3281 only one targets element must be produced. If + * multiple targets are given in the constructor they are merged into one + * targets element. If this was produced from a + * {@link Org.BouncyCastle.Asn1.Asn1Sequence} the encoding is kept.

      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return targets; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/Targets.cs b/iTechSharp/srcbc/asn1/x509/Targets.cs new file mode 100644 index 0000000..3e436d8 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/Targets.cs @@ -0,0 +1,121 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Targets structure used in target information extension for attribute + * certificates from RFC 3281. + * + *
      +	 *            Targets ::= SEQUENCE OF Target
      +	 *           
      +	 *            Target  ::= CHOICE {
      +	 *              targetName          [0] GeneralName,
      +	 *              targetGroup         [1] GeneralName,
      +	 *              targetCert          [2] TargetCert
      +	 *            }
      +	 *           
      +	 *            TargetCert  ::= SEQUENCE {
      +	 *              targetCertificate    IssuerSerial,
      +	 *              targetName           GeneralName OPTIONAL,
      +	 *              certDigestInfo       ObjectDigestInfo OPTIONAL
      +	 *            }
      +	 * 
      + * + * @see org.bouncycastle.asn1.x509.Target + * @see org.bouncycastle.asn1.x509.TargetInformation + */ + public class Targets + : Asn1Encodable + { + private readonly Asn1Sequence targets; + + /** + * Creates an instance of a Targets from the given object. + *

      + * obj can be a Targets or a {@link Asn1Sequence}

      + * + * @param obj The object. + * @return A Targets instance. + * @throws ArgumentException if the given object cannot be interpreted as Target. + */ + public static Targets GetInstance( + object obj) + { + if (obj is Targets) + { + return (Targets) obj; + } + + if (obj is Asn1Sequence) + { + return new Targets((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + * + * @param targets The ASN.1 SEQUENCE. + * @throws ArgumentException if the contents of the sequence are + * invalid. + */ + private Targets( + Asn1Sequence targets) + { + this.targets = targets; + } + + /** + * Constructor from given targets. + *

      + * The ArrayList is copied.

      + * + * @param targets An ArrayList of {@link Target}s. + * @see Target + * @throws ArgumentException if the ArrayList contains not only Targets. + */ + public Targets( + Target[] targets) + { + this.targets = new DerSequence(targets); + } + + /** + * Returns the targets in an ArrayList. + *

      + * The ArrayList is cloned before it is returned.

      + * + * @return Returns the targets. + */ + public virtual Target[] GetTargets() + { + Target[] result = new Target[targets.Count]; + + for (int i = 0; i < targets.Count; ++i) + { + result[i] = Target.GetInstance(targets[i]); + } + + return result; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + * Returns: + * + *
      +		 *            Targets ::= SEQUENCE OF Target
      +		 * 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return targets; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/Time.cs b/iTechSharp/srcbc/asn1/x509/Time.cs new file mode 100644 index 0000000..b03cca7 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/Time.cs @@ -0,0 +1,126 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class Time + : Asn1Encodable + { + internal Asn1Object time; + + public static Time GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public Time( + Asn1Object time) + { + if (time == null) + throw new ArgumentNullException("time"); + + if (!(time is DerUtcTime) && !(time is DerGeneralizedTime)) + { + throw new ArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + DateTime date) + { + string d = date.ToString("yyyyMMddHHmmss") + "Z"; + + int year = Int32.Parse(d.Substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DerGeneralizedTime(d); + } + else + { + time = new DerUtcTime(d.Substring(2)); + } + } + + public static Time GetInstance( + object obj) + { + if (obj is Time) + { + return (Time) obj; + } + + if (obj is DerUtcTime) + { + return new Time((DerUtcTime) obj); + } + + if (obj is DerGeneralizedTime) + { + return new Time((DerGeneralizedTime) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public string GetTime() + { + if (time is DerUtcTime) + { + return ((DerUtcTime) time).AdjustedTimeString; + } + + return ((DerGeneralizedTime) time).GetTime(); + } + + /// + /// Return our time as DateTime. + /// + /// A date time. + public DateTime ToDateTime() + { + try + { + if (time is DerUtcTime) + { + return ((DerUtcTime)time).ToAdjustedDateTime(); + } + else + { + return ((DerGeneralizedTime)time).ToDateTime(); + } + } + catch (FormatException e) + { + // this should never happen + throw new InvalidOperationException("invalid date string: " + e.Message); + } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Time ::= CHOICE {
      +         *             utcTime        UTCTime,
      +         *             generalTime    GeneralizedTime }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return time; + } + + public override string ToString() + { + return GetTime(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/UserNotice.cs b/iTechSharp/srcbc/asn1/x509/UserNotice.cs new file mode 100644 index 0000000..2878a18 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/UserNotice.cs @@ -0,0 +1,104 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * UserNotice class, used in + * CertificatePolicies X509 extensions (in policy + * qualifiers). + *
      +     * UserNotice ::= Sequence {
      +     *      noticeRef        NoticeReference OPTIONAL,
      +     *      explicitText     DisplayText OPTIONAL}
      +     *
      +     * 
      + * + * @see PolicyQualifierId + * @see PolicyInformation + */ + public class UserNotice + : Asn1Encodable + { + internal NoticeReference noticeRef; + internal DisplayText explicitText; + + /** + * Creates a new UserNotice instance. + * + * @param noticeRef a NoticeReference value + * @param explicitText a DisplayText value + */ + public UserNotice( + NoticeReference noticeRef, + DisplayText explicitText) + { + this.noticeRef = noticeRef; + this.explicitText = explicitText; + } + + /** + * Creates a new UserNotice instance. + * + * @param noticeRef a NoticeReference value + * @param str the explicitText field as a string. + */ + public UserNotice( + NoticeReference noticeRef, + string str) + { + this.noticeRef = noticeRef; + this.explicitText = new DisplayText(str); + } + + /** + * Creates a new UserNotice instance. + *

      Useful from reconstructing a UserNotice instance + * from its encodable/encoded form. + * + * @param as an ASN1Sequence value obtained from either + * calling @{link toASN1Object()} for a UserNotice + * instance or from parsing it from a DER-encoded stream.

      + */ + public UserNotice( + Asn1Sequence seq) + { + if (seq.Count == 2) + { + noticeRef = NoticeReference.GetInstance(seq[0]); + explicitText = DisplayText.GetInstance(seq[1]); + } + else if (seq.Count == 1) + { + if (seq[0].ToAsn1Object() is Asn1Sequence) + { + noticeRef = NoticeReference.GetInstance(seq[0]); + } + else + { + explicitText = DisplayText.GetInstance(seq[0]); + } + } + else + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector av = new Asn1EncodableVector(); + + if (noticeRef != null) + { + av.Add(noticeRef); + } + + if (explicitText != null) + { + av.Add(explicitText); + } + + return new DerSequence(av); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/V1TBSCertificateGenerator.cs b/iTechSharp/srcbc/asn1/x509/V1TBSCertificateGenerator.cs new file mode 100644 index 0000000..20b525a --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/V1TBSCertificateGenerator.cs @@ -0,0 +1,108 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Generator for Version 1 TbsCertificateStructures. + *
      +     * TbsCertificate ::= Sequence {
      +     *      version          [ 0 ]  Version DEFAULT v1(0),
      +     *      serialNumber            CertificateSerialNumber,
      +     *      signature               AlgorithmIdentifier,
      +     *      issuer                  Name,
      +     *      validity                Validity,
      +     *      subject                 Name,
      +     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
      +     *      }
      +     * 
      + * + */ + public class V1TbsCertificateGenerator + { + internal DerTaggedObject version = new DerTaggedObject(0, new DerInteger(0)); + internal DerInteger serialNumber; + internal AlgorithmIdentifier signature; + internal X509Name issuer; + internal Time startDate, endDate; + internal X509Name subject; + internal SubjectPublicKeyInfo subjectPublicKeyInfo; + + public V1TbsCertificateGenerator() + { + } + + public void SetSerialNumber( + DerInteger serialNumber) + { + this.serialNumber = serialNumber; + } + + public void SetSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + public void SetIssuer( + X509Name issuer) + { + this.issuer = issuer; + } + + public void SetStartDate( + Time startDate) + { + this.startDate = startDate; + } + + public void SetStartDate( + DerUtcTime startDate) + { + this.startDate = new Time(startDate); + } + + public void SetEndDate( + Time endDate) + { + this.endDate = endDate; + } + + public void SetEndDate( + DerUtcTime endDate) + { + this.endDate = new Time(endDate); + } + + public void SetSubject( + X509Name subject) + { + this.subject = subject; + } + + public void SetSubjectPublicKeyInfo( + SubjectPublicKeyInfo pubKeyInfo) + { + this.subjectPublicKeyInfo = pubKeyInfo; + } + + public TbsCertificateStructure GenerateTbsCertificate() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (subject == null) || (subjectPublicKeyInfo == null)) + { + throw new InvalidOperationException("not all mandatory fields set in V1 TBScertificate generator"); + } + + return new TbsCertificateStructure( + new DerSequence( + //version, - not required as default value + serialNumber, + signature, + issuer, + new DerSequence(startDate, endDate), // before and after dates + subject, + subjectPublicKeyInfo)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/V2AttributeCertificateInfoGenerator.cs b/iTechSharp/srcbc/asn1/x509/V2AttributeCertificateInfoGenerator.cs new file mode 100644 index 0000000..02580b5 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/V2AttributeCertificateInfoGenerator.cs @@ -0,0 +1,137 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Generator for Version 2 AttributeCertificateInfo + *
      +     * AttributeCertificateInfo ::= Sequence {
      +     *       version              AttCertVersion -- version is v2,
      +     *       holder               Holder,
      +     *       issuer               AttCertIssuer,
      +     *       signature            AlgorithmIdentifier,
      +     *       serialNumber         CertificateSerialNumber,
      +     *       attrCertValidityPeriod   AttCertValidityPeriod,
      +     *       attributes           Sequence OF Attr,
      +     *       issuerUniqueID       UniqueIdentifier OPTIONAL,
      +     *       extensions           Extensions OPTIONAL
      +     * }
      +     * 
      + * + */ + public class V2AttributeCertificateInfoGenerator + { + internal DerInteger version; + internal Holder holder; + internal AttCertIssuer issuer; + internal AlgorithmIdentifier signature; + internal DerInteger serialNumber; +// internal AttCertValidityPeriod attrCertValidityPeriod; + internal Asn1EncodableVector attributes; + internal DerBitString issuerUniqueID; + internal X509Extensions extensions; + internal DerGeneralizedTime startDate, endDate; + + public V2AttributeCertificateInfoGenerator() + { + this.version = new DerInteger(1); + attributes = new Asn1EncodableVector(); + } + + public void SetHolder( + Holder holder) + { + this.holder = holder; + } + + public void AddAttribute( + string oid, + Asn1Encodable value) + { + attributes.Add(new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value))); + } + + /** + * @param attribute + */ + public void AddAttribute(AttributeX509 attribute) + { + attributes.Add(attribute); + } + + public void SetSerialNumber( + DerInteger serialNumber) + { + this.serialNumber = serialNumber; + } + + public void SetSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + public void SetIssuer( + AttCertIssuer issuer) + { + this.issuer = issuer; + } + + public void SetStartDate( + DerGeneralizedTime startDate) + { + this.startDate = startDate; + } + + public void SetEndDate( + DerGeneralizedTime endDate) + { + this.endDate = endDate; + } + + public void SetIssuerUniqueID( + DerBitString issuerUniqueID) + { + this.issuerUniqueID = issuerUniqueID; + } + + public void SetExtensions( + X509Extensions extensions) + { + this.extensions = extensions; + } + + public AttributeCertificateInfo GenerateAttributeCertificateInfo() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (holder == null) || (attributes == null)) + { + throw new InvalidOperationException("not all mandatory fields set in V2 AttributeCertificateInfo generator"); + } + + Asn1EncodableVector v = new Asn1EncodableVector( + version, holder, issuer, signature, serialNumber); + + // + // before and after dates => AttCertValidityPeriod + // + v.Add(new AttCertValidityPeriod(startDate, endDate)); + + // Attributes + v.Add(new DerSequence(attributes)); + + if (issuerUniqueID != null) + { + v.Add(issuerUniqueID); + } + + if (extensions != null) + { + v.Add(extensions); + } + + return AttributeCertificateInfo.GetInstance(new DerSequence(v)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/V2Form.cs b/iTechSharp/srcbc/asn1/x509/V2Form.cs new file mode 100644 index 0000000..a9c4335 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/V2Form.cs @@ -0,0 +1,125 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class V2Form + : Asn1Encodable + { + internal GeneralNames issuerName; + internal IssuerSerial baseCertificateID; + internal ObjectDigestInfo objectDigestInfo; + + public static V2Form GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static V2Form GetInstance( + object obj) + { + if (obj is V2Form) + { + return (V2Form) obj; + } + + if (obj is Asn1Sequence) + { + return new V2Form((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public V2Form( + GeneralNames issuerName) + { + this.issuerName = issuerName; + } + + private V2Form( + Asn1Sequence seq) + { + if (seq.Count > 3) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + int index = 0; + + if (!(seq[0] is Asn1TaggedObject)) + { + index++; + this.issuerName = GeneralNames.GetInstance(seq[0]); + } + + for (int i = index; i != seq.Count; i++) + { + Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]); + if (o.TagNo == 0) + { + baseCertificateID = IssuerSerial.GetInstance(o, false); + } + else if (o.TagNo == 1) + { + objectDigestInfo = ObjectDigestInfo.GetInstance(o, false); + } + else + { + throw new ArgumentException("Bad tag number: " + o.TagNo); + } + } + } + + public GeneralNames IssuerName + { + get { return issuerName; } + } + + public IssuerSerial BaseCertificateID + { + get { return baseCertificateID; } + } + + public ObjectDigestInfo ObjectDigestInfo + { + get { return objectDigestInfo; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  V2Form ::= Sequence {
      +         *       issuerName            GeneralNames  OPTIONAL,
      +         *       baseCertificateID     [0] IssuerSerial  OPTIONAL,
      +         *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
      +         *         -- issuerName MUST be present in this profile
      +         *         -- baseCertificateID and objectDigestInfo MUST NOT
      +         *         -- be present in this profile
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (issuerName != null) + { + v.Add(issuerName); + } + + if (baseCertificateID != null) + { + v.Add(new DerTaggedObject(false, 0, baseCertificateID)); + } + + if (objectDigestInfo != null) + { + v.Add(new DerTaggedObject(false, 1, objectDigestInfo)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/V2TBSCertListGenerator.cs b/iTechSharp/srcbc/asn1/x509/V2TBSCertListGenerator.cs new file mode 100644 index 0000000..2624b30 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/V2TBSCertListGenerator.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Generator for Version 2 TbsCertList structures. + *
      +     *  TbsCertList  ::=  Sequence  {
      +     *       version                 Version OPTIONAL,
      +     *                                    -- if present, shall be v2
      +     *       signature               AlgorithmIdentifier,
      +     *       issuer                  Name,
      +     *       thisUpdate              Time,
      +     *       nextUpdate              Time OPTIONAL,
      +     *       revokedCertificates     Sequence OF Sequence  {
      +     *            userCertificate         CertificateSerialNumber,
      +     *            revocationDate          Time,
      +     *            crlEntryExtensions      Extensions OPTIONAL
      +     *                                          -- if present, shall be v2
      +     *                                 }  OPTIONAL,
      +     *       crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
      +     *                                          -- if present, shall be v2
      +     *                                 }
      +     * 
      + * + * Note: This class may be subject to change + */ + public class V2TbsCertListGenerator + { + private DerInteger version = new DerInteger(1); + private AlgorithmIdentifier signature; + private X509Name issuer; + private Time thisUpdate, nextUpdate; + private X509Extensions extensions; + private ArrayList crlEntries; + + public V2TbsCertListGenerator() + { + } + + public void SetSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + public void SetIssuer( + X509Name issuer) + { + this.issuer = issuer; + } + + public void SetThisUpdate( + DerUtcTime thisUpdate) + { + this.thisUpdate = new Time(thisUpdate); + } + + public void SetNextUpdate( + DerUtcTime nextUpdate) + { + this.nextUpdate = (nextUpdate != null) + ? new Time(nextUpdate) + : null; + } + + public void SetThisUpdate( + Time thisUpdate) + { + this.thisUpdate = thisUpdate; + } + + public void SetNextUpdate( + Time nextUpdate) + { + this.nextUpdate = nextUpdate; + } + + public void AddCrlEntry( + Asn1Sequence crlEntry) + { + if (crlEntries == null) + { + crlEntries = new ArrayList(); + } + + crlEntries.Add(crlEntry); + } + + public void AddCrlEntry(DerInteger userCertificate, DerUtcTime revocationDate, int reason) + { + AddCrlEntry(userCertificate, new Time(revocationDate), reason); + } + + public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason) + { + AddCrlEntry(userCertificate, revocationDate, reason, null); + } + + public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason, + DerGeneralizedTime invalidityDate) + { + ArrayList extOids = new ArrayList(); + ArrayList extValues = new ArrayList(); + + if (reason != 0) + { + CrlReason crlReason = new CrlReason(reason); + + try + { + extOids.Add(X509Extensions.ReasonCode); + extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded()))); + } + catch (IOException e) + { + throw new ArgumentException("error encoding reason: " + e); + } + } + + if (invalidityDate != null) + { + try + { + extOids.Add(X509Extensions.InvalidityDate); + extValues.Add(new X509Extension(false, new DerOctetString(invalidityDate.GetEncoded()))); + } + catch (IOException e) + { + throw new ArgumentException("error encoding invalidityDate: " + e); + } + } + + if (extOids.Count != 0) + { + AddCrlEntry(userCertificate, revocationDate, new X509Extensions(extOids, extValues)); + } + else + { + AddCrlEntry(userCertificate, revocationDate, null); + } + } + + public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, X509Extensions extensions) + { + Asn1EncodableVector v = new Asn1EncodableVector( + userCertificate, revocationDate); + + if (extensions != null) + { + v.Add(extensions); + } + + AddCrlEntry(new DerSequence(v)); + } + + public void SetExtensions( + X509Extensions extensions) + { + this.extensions = extensions; + } + + public TbsCertificateList GenerateTbsCertList() + { + if ((signature == null) || (issuer == null) || (thisUpdate == null)) + { + throw new InvalidOperationException("Not all mandatory fields set in V2 TbsCertList generator."); + } + + Asn1EncodableVector v = new Asn1EncodableVector( + version, signature, issuer, thisUpdate); + + if (nextUpdate != null) + { + v.Add(nextUpdate); + } + + // Add CRLEntries if they exist + if (crlEntries != null) + { + Asn1Sequence[] certs = (Asn1Sequence[]) crlEntries.ToArray(typeof(Asn1Sequence)); + + v.Add(new DerSequence(certs)); + } + + if (extensions != null) + { + v.Add(new DerTaggedObject(0, extensions)); + } + + return new TbsCertificateList(new DerSequence(v)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/V3TBSCertificateGenerator.cs b/iTechSharp/srcbc/asn1/x509/V3TBSCertificateGenerator.cs new file mode 100644 index 0000000..5df7755 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/V3TBSCertificateGenerator.cs @@ -0,0 +1,144 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Generator for Version 3 TbsCertificateStructures. + *
      +     * TbsCertificate ::= Sequence {
      +     *      version          [ 0 ]  Version DEFAULT v1(0),
      +     *      serialNumber            CertificateSerialNumber,
      +     *      signature               AlgorithmIdentifier,
      +     *      issuer                  Name,
      +     *      validity                Validity,
      +     *      subject                 Name,
      +     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
      +     *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
      +     *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
      +     *      extensions        [ 3 ] Extensions OPTIONAL
      +     *      }
      +     * 
      + * + */ + public class V3TbsCertificateGenerator + { + internal DerTaggedObject version = new DerTaggedObject(0, new DerInteger(2)); + internal DerInteger serialNumber; + internal AlgorithmIdentifier signature; + internal X509Name issuer; + internal Time startDate, endDate; + internal X509Name subject; + internal SubjectPublicKeyInfo subjectPublicKeyInfo; + internal X509Extensions extensions; + + private bool altNamePresentAndCritical; + + public V3TbsCertificateGenerator() + { + } + + public void SetSerialNumber( + DerInteger serialNumber) + { + this.serialNumber = serialNumber; + } + + public void SetSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + public void SetIssuer( + X509Name issuer) + { + this.issuer = issuer; + } + + public void SetStartDate( + DerUtcTime startDate) + { + this.startDate = new Time(startDate); + } + + public void SetStartDate( + Time startDate) + { + this.startDate = startDate; + } + + public void SetEndDate( + DerUtcTime endDate) + { + this.endDate = new Time(endDate); + } + + public void SetEndDate( + Time endDate) + { + this.endDate = endDate; + } + + public void SetSubject( + X509Name subject) + { + this.subject = subject; + } + + public void SetSubjectPublicKeyInfo( + SubjectPublicKeyInfo pubKeyInfo) + { + this.subjectPublicKeyInfo = pubKeyInfo; + } + + public void SetExtensions( + X509Extensions extensions) + { + this.extensions = extensions; + + if (extensions != null) + { + X509Extension altName = extensions.GetExtension(X509Extensions.SubjectAlternativeName); + + if (altName != null && altName.IsCritical) + { + altNamePresentAndCritical = true; + } + } + } + + public TbsCertificateStructure GenerateTbsCertificate() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (subject == null && !altNamePresentAndCritical) + || (subjectPublicKeyInfo == null)) + { + throw new InvalidOperationException("not all mandatory fields set in V3 TBScertificate generator"); + } + + DerSequence validity = new DerSequence(startDate, endDate); // before and after dates + + Asn1EncodableVector v = new Asn1EncodableVector( + version, serialNumber, signature, issuer, validity); + + if (subject != null) + { + v.Add(subject); + } + else + { + v.Add(DerSequence.Empty); + } + + v.Add(subjectPublicKeyInfo); + + if (extensions != null) + { + v.Add(new DerTaggedObject(3, extensions)); + } + + return new TbsCertificateStructure(new DerSequence(v)); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509Attributes.cs b/iTechSharp/srcbc/asn1/x509/X509Attributes.cs new file mode 100644 index 0000000..291329a --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509Attributes.cs @@ -0,0 +1,9 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class X509Attributes + { + public static readonly DerObjectIdentifier RoleSyntax = new DerObjectIdentifier("2.5.4.72"); + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509CertificateStructure.cs b/iTechSharp/srcbc/asn1/x509/X509CertificateStructure.cs new file mode 100644 index 0000000..6773e4e --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509CertificateStructure.cs @@ -0,0 +1,133 @@ +using System; + +using Org.BouncyCastle.Asn1.Pkcs; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * an X509Certificate structure. + *
      +     *  Certificate ::= Sequence {
      +     *      tbsCertificate          TbsCertificate,
      +     *      signatureAlgorithm      AlgorithmIdentifier,
      +     *      signature               BIT STRING
      +     *  }
      +     * 
      + */ + public class X509CertificateStructure + : Asn1Encodable + { + private readonly TbsCertificateStructure tbsCert; + private readonly AlgorithmIdentifier sigAlgID; + private readonly DerBitString sig; + + public static X509CertificateStructure GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static X509CertificateStructure GetInstance( + object obj) + { + if (obj is X509CertificateStructure) + { + return (X509CertificateStructure) obj; + } + + if (obj is Asn1Sequence) + { + return new X509CertificateStructure((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public X509CertificateStructure( + TbsCertificateStructure tbsCert, + AlgorithmIdentifier sigAlgID, + DerBitString sig) + { + if (tbsCert == null) + throw new ArgumentNullException("tbsCert"); + if (sigAlgID == null) + throw new ArgumentNullException("sigAlgID"); + if (sig == null) + throw new ArgumentNullException("sig"); + + this.tbsCert = tbsCert; + this.sigAlgID = sigAlgID; + this.sig = sig; + } + + private X509CertificateStructure( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("sequence wrong size for a certificate", "seq"); + + // + // correct x509 certficate + // + tbsCert = TbsCertificateStructure.GetInstance(seq[0]); + sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]); + sig = DerBitString.GetInstance(seq[2]); + } + + public TbsCertificateStructure TbsCertificate + { + get { return tbsCert; } + } + + public int Version + { + get { return tbsCert.Version; } + } + + public DerInteger SerialNumber + { + get { return tbsCert.SerialNumber; } + } + + public X509Name Issuer + { + get { return tbsCert.Issuer; } + } + + public Time StartDate + { + get { return tbsCert.StartDate; } + } + + public Time EndDate + { + get { return tbsCert.EndDate; } + } + + public X509Name Subject + { + get { return tbsCert.Subject; } + } + + public SubjectPublicKeyInfo SubjectPublicKeyInfo + { + get { return tbsCert.SubjectPublicKeyInfo; } + } + + public AlgorithmIdentifier SignatureAlgorithm + { + get { return sigAlgID; } + } + + public DerBitString Signature + { + get { return sig; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(tbsCert, sigAlgID, sig); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509DefaultEntryConverter.cs b/iTechSharp/srcbc/asn1/x509/X509DefaultEntryConverter.cs new file mode 100644 index 0000000..0d68a3d --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509DefaultEntryConverter.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The default converter for X509 DN entries when going from their + * string value to ASN.1 strings. + */ + public class X509DefaultEntryConverter + : X509NameEntryConverter + { + /** + * Apply default conversion for the given value depending on the oid + * and the character range of the value. + * + * @param oid the object identifier for the DN entry + * @param value the value associated with it + * @return the ASN.1 equivalent for the string value. + */ + public override Asn1Object GetConvertedValue( + DerObjectIdentifier oid, + string value) + { + if (value.Length != 0 && value[0] == '#') + { + try + { + return ConvertHexEncoded(value, 1); + } + catch (IOException) + { + throw new Exception("can't recode value for oid " + oid.Id); + } + } + + if (value.Length != 0 && value[0] == '\\') + { + value = value.Substring(1); + } + + if (oid.Equals(X509Name.EmailAddress) || oid.Equals(X509Name.DC)) + { + return new DerIA5String(value); + } + + if (oid.Equals(X509Name.DateOfBirth)) // accept time string as well as # (for compatibility) + { + return new DerGeneralizedTime(value); + } + + if (oid.Equals(X509Name.C) + || oid.Equals(X509Name.SerialNumber) + || oid.Equals(X509Name.DnQualifier)) + { + return new DerPrintableString(value); + } + + return new DerUtf8String(value); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509Extension.cs b/iTechSharp/srcbc/asn1/x509/X509Extension.cs new file mode 100644 index 0000000..e3298cf --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509Extension.cs @@ -0,0 +1,74 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * an object for the elements in the X.509 V3 extension block. + */ + public class X509Extension + { + internal bool critical; + internal Asn1OctetString value; + + public X509Extension( + DerBoolean critical, + Asn1OctetString value) + { + if (critical == null) + { + throw new ArgumentNullException("critical"); + } + + this.critical = critical.IsTrue; + this.value = value; + } + + public X509Extension( + bool critical, + Asn1OctetString value) + { + this.critical = critical; + this.value = value; + } + + public bool IsCritical { get { return critical; } } + + public Asn1OctetString Value { get { return value; } } + + public override int GetHashCode() + { + int vh = this.Value.GetHashCode(); + + return IsCritical ? vh : ~vh; + } + + public override bool Equals( + object obj) + { + X509Extension other = obj as X509Extension; + if (other == null) + { + return false; + } + + return Value.Equals(other.Value) && IsCritical == other.IsCritical; + } + + /// Convert the value of the passed in extension to an object. + /// The extension to parse. + /// The object the value string contains. + /// If conversion is not possible. + public static Asn1Object ConvertValueToObject( + X509Extension ext) + { + try + { + return Asn1Object.FromByteArray(ext.Value.GetOctets()); + } + catch (Exception e) + { + throw new ArgumentException("can't convert extension", e); + } + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509Extensions.cs b/iTechSharp/srcbc/asn1/x509/X509Extensions.cs new file mode 100644 index 0000000..1f31534 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509Extensions.cs @@ -0,0 +1,348 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class X509Extensions + : Asn1Encodable + { + /** + * Subject Directory Attributes + */ + public static readonly DerObjectIdentifier SubjectDirectoryAttributes = new DerObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + */ + public static readonly DerObjectIdentifier SubjectKeyIdentifier = new DerObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + */ + public static readonly DerObjectIdentifier KeyUsage = new DerObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + */ + public static readonly DerObjectIdentifier PrivateKeyUsagePeriod = new DerObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + */ + public static readonly DerObjectIdentifier SubjectAlternativeName = new DerObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + */ + public static readonly DerObjectIdentifier IssuerAlternativeName = new DerObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + */ + public static readonly DerObjectIdentifier BasicConstraints = new DerObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + */ + public static readonly DerObjectIdentifier CrlNumber = new DerObjectIdentifier("2.5.29.20"); + + /** + * Reason code + */ + public static readonly DerObjectIdentifier ReasonCode = new DerObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + */ + public static readonly DerObjectIdentifier InstructionCode = new DerObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + */ + public static readonly DerObjectIdentifier InvalidityDate = new DerObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + */ + public static readonly DerObjectIdentifier DeltaCrlIndicator = new DerObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + */ + public static readonly DerObjectIdentifier IssuingDistributionPoint = new DerObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + */ + public static readonly DerObjectIdentifier CertificateIssuer = new DerObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + */ + public static readonly DerObjectIdentifier NameConstraints = new DerObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + */ + public static readonly DerObjectIdentifier CrlDistributionPoints = new DerObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + */ + public static readonly DerObjectIdentifier CertificatePolicies = new DerObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + */ + public static readonly DerObjectIdentifier PolicyMappings = new DerObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + */ + public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + */ + public static readonly DerObjectIdentifier PolicyConstraints = new DerObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + */ + public static readonly DerObjectIdentifier ExtendedKeyUsage = new DerObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + */ + public static readonly DerObjectIdentifier FreshestCrl = new DerObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + */ + public static readonly DerObjectIdentifier InhibitAnyPolicy = new DerObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + */ + public static readonly DerObjectIdentifier AuthorityInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + */ + public static readonly DerObjectIdentifier SubjectInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + */ + public static readonly DerObjectIdentifier LogoType = new DerObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + */ + public static readonly DerObjectIdentifier BiometricInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + */ + public static readonly DerObjectIdentifier QCStatements = new DerObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + */ + public static readonly DerObjectIdentifier AuditIdentity = new DerObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + */ + public static readonly DerObjectIdentifier NoRevAvail = new DerObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + */ + public static readonly DerObjectIdentifier TargetInformation = new DerObjectIdentifier("2.5.29.55"); + + private readonly Hashtable extensions = new Hashtable(); + private readonly ArrayList ordering = new ArrayList(); + + public static X509Extensions GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static X509Extensions GetInstance( + object obj) + { + if (obj == null || obj is X509Extensions) + { + return (X509Extensions) obj; + } + + if (obj is Asn1Sequence) + { + return new X509Extensions((Asn1Sequence) obj); + } + + if (obj is Asn1TaggedObject) + { + return GetInstance(((Asn1TaggedObject) obj).GetObject()); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + * + * the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString) + */ + private X509Extensions( + Asn1Sequence seq) + { + foreach (Asn1Encodable ae in seq) + { + Asn1Sequence s = Asn1Sequence.GetInstance(ae.ToAsn1Object()); + + if (s.Count < 2 || s.Count > 3) + throw new ArgumentException("Bad sequence size: " + s.Count); + + DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()); + + bool isCritical = s.Count == 3 + && DerBoolean.GetInstance(s[1].ToAsn1Object()).IsTrue; + + Asn1OctetString octets = Asn1OctetString.GetInstance(s[s.Count - 1].ToAsn1Object()); + + extensions.Add(oid, new X509Extension(isCritical, octets)); + ordering.Add(oid); + } + } + + /** + * constructor from a table of extensions. + *

      + * it's is assumed the table contains Oid/string pairs.

      + */ + public X509Extensions( + Hashtable extensions) + : this(null, extensions) + { + } + + /** + * Constructor from a table of extensions with ordering. + *

      + * It's is assumed the table contains Oid/string pairs.

      + */ + public X509Extensions( + ArrayList ordering, + Hashtable extensions) + { + ICollection c = ordering == null + ? extensions.Keys + : ordering; + + this.ordering.AddRange(c); + + foreach (DerObjectIdentifier oid in this.ordering) + { + this.extensions.Add(oid, (X509Extension) extensions[oid]); + } + } + + /** + * Constructor from two vectors + * + * @param objectIDs an ArrayList of the object identifiers. + * @param values an ArrayList of the extension values. + */ + public X509Extensions( + ArrayList oids, + ArrayList values) + { + this.ordering.AddRange(oids); + + int count = 0; + foreach (DerObjectIdentifier oid in this.ordering) + { + this.extensions.Add(oid, (X509Extension) values[count++]); + } + } + + [Obsolete("Use ExtensionOids IEnumerable property")] + public IEnumerator Oids() + { + return ExtensionOids.GetEnumerator(); + } + + /** + * return an Enumeration of the extension field's object ids. + */ + public IEnumerable ExtensionOids + { + get { return new EnumerableProxy(ordering); } + } + + /** + * return the extension represented by the object identifier + * passed in. + * + * @return the extension if it's present, null otherwise. + */ + public X509Extension GetExtension( + DerObjectIdentifier oid) + { + return (X509Extension) extensions[oid]; + } + + /** + *
      +		 *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
      +		 *
      +		 *     Extension         ::=   SEQUENCE {
      +		 *        extnId            EXTENSION.&id ({ExtensionSet}),
      +		 *        critical          BOOLEAN DEFAULT FALSE,
      +		 *        extnValue         OCTET STRING }
      +		 * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + + foreach (DerObjectIdentifier oid in ordering) + { + X509Extension ext = (X509Extension) extensions[oid]; + Asn1EncodableVector v = new Asn1EncodableVector(oid); + + if (ext.IsCritical) + { + v.Add(DerBoolean.True); + } + + v.Add(ext.Value); + + vec.Add(new DerSequence(v)); + } + + return new DerSequence(vec); + } + + public bool Equivalent( + X509Extensions other) + { + if (extensions.Count != other.extensions.Count) + return false; + + foreach (DerObjectIdentifier oid in extensions.Keys) + { + if (!extensions[oid].Equals(other.extensions[oid])) + return false; + } + + return true; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509ExtensionsGenerator.cs b/iTechSharp/srcbc/asn1/x509/X509ExtensionsGenerator.cs new file mode 100644 index 0000000..abe1cf9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509ExtensionsGenerator.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /// Generator for X.509 extensions + public class X509ExtensionsGenerator + { + private Hashtable extensions = new Hashtable(); + private ArrayList extOrdering = new ArrayList(); + + /// Reset the generator + public void Reset() + { + extensions = new Hashtable(); + extOrdering = new ArrayList(); + } + + /// + /// Add an extension with the given oid and the passed in value to be included + /// in the OCTET STRING associated with the extension. + /// + /// OID for the extension. + /// True if critical, false otherwise. + /// The ASN.1 object to be included in the extension. + public void AddExtension( + DerObjectIdentifier oid, + bool critical, + Asn1Encodable extValue) + { + byte[] encoded; + try + { + encoded = extValue.GetDerEncoded(); + } + catch (Exception e) + { + throw new ArgumentException("error encoding value: " + e); + } + + this.AddExtension(oid, critical, encoded); + } + + /// + /// Add an extension with the given oid and the passed in byte array to be wrapped + /// in the OCTET STRING associated with the extension. + /// + /// OID for the extension. + /// True if critical, false otherwise. + /// The byte array to be wrapped. + public void AddExtension( + DerObjectIdentifier oid, + bool critical, + byte[] extValue) + { + if (extensions.ContainsKey(oid)) + { + throw new ArgumentException("extension " + oid + " already added"); + } + + extOrdering.Add(oid); + extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue))); + } + + /// Return true if there are no extension present in this generator. + /// True if empty, false otherwise + public bool IsEmpty + { + get { return extOrdering.Count < 1; } + } + + /// Generate an X509Extensions object based on the current state of the generator. + /// An X509Extensions object + public X509Extensions Generate() + { + return new X509Extensions(extOrdering, extensions); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509Name.cs b/iTechSharp/srcbc/asn1/x509/X509Name.cs new file mode 100644 index 0000000..9fff63c --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509Name.cs @@ -0,0 +1,1057 @@ +using System; +using System.Collections; +using System.Globalization; +using System.Text; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + *
      +    *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
      +    *
      +    *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
      +    *
      +    *     AttributeTypeAndValue ::= SEQUENCE {
      +    *                                   type  OBJECT IDENTIFIER,
      +    *                                   value ANY }
      +    * 
      + */ + public class X509Name + : Asn1Encodable + { + /** + * country code - StringType(SIZE(2)) + */ + public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11"); + + /** + * Title + */ + public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3"); + + /** + * street - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5"); + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8"); + + /** + * Naming attributes of type X520name + */ + public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4"); + public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42"); + public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43"); + public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44"); + public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45"); + + /** + * businessCategory - DirectoryString(SIZE(1..128) + */ + public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier( + "2.5.4.15"); + + /** + * postalCode - DirectoryString(SIZE(1..40) + */ + public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier( + "2.5.4.17"); + + /** + * dnQualifier - DirectoryString(SIZE(1..64) + */ + public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier( + "2.5.4.46"); + + /** + * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) + */ + public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier( + "2.5.4.65"); + + /** + * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z + */ + public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.1"); + + /** + * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) + */ + public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.2"); + + /** + * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" + */ + public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.3"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.4"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.5"); + + /** + * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) + */ + public static readonly DerObjectIdentifier NameAtBirth = new DerObjectIdentifier("1.3.36.8.3.14"); + + /** + * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF + * DirectoryString(SIZE(1..30)) + */ + public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16"); + + /** + * id-at-telephoneNumber + */ + public static readonly DerObjectIdentifier TelephoneNumber = new DerObjectIdentifier("2.5.4.20"); + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + *

      Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.

      + */ + public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress; + + /** + * more from PKCS#9 + */ + public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName; + public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress; + + /** + * email address in Verisign certificates + */ + public static readonly DerObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** + * determines whether or not strings should be processed and printed + * from back to front. + */ +// public static bool DefaultReverse = false; + public static bool DefaultReverse + { + get { return defaultReverse[0]; } + set { defaultReverse[0] = value; } + } + + private static readonly bool[] defaultReverse = { false }; + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + public static readonly Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 2253 + */ + public static readonly Hashtable RFC2253Symbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 1779 + * + */ + public static readonly Hashtable RFC1779Symbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + public static readonly Hashtable DefaultLookup = new Hashtable(); + + /** + * look up table translating OID values into their common symbols. + */ + [Obsolete("Use 'DefaultSymbols' instead")] + public static readonly Hashtable OIDLookup = DefaultSymbols; + + /** + * look up table translating string values into their OIDS - + * this static is scheduled for deletion + */ + [Obsolete("Use 'DefaultLookup' instead")] + public static readonly Hashtable SymbolLookup = DefaultLookup; + + static X509Name() + { + DefaultSymbols.Add(C, "C"); + DefaultSymbols.Add(O, "O"); + DefaultSymbols.Add(T, "T"); + DefaultSymbols.Add(OU, "OU"); + DefaultSymbols.Add(CN, "CN"); + DefaultSymbols.Add(L, "L"); + DefaultSymbols.Add(ST, "ST"); + DefaultSymbols.Add(SerialNumber, "SERIALNUMBER"); + DefaultSymbols.Add(EmailAddress, "E"); + DefaultSymbols.Add(DC, "DC"); + DefaultSymbols.Add(UID, "UID"); + DefaultSymbols.Add(Street, "STREET"); + DefaultSymbols.Add(Surname, "SURNAME"); + DefaultSymbols.Add(GivenName, "GIVENNAME"); + DefaultSymbols.Add(Initials, "INITIALS"); + DefaultSymbols.Add(Generation, "GENERATION"); + DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress"); + DefaultSymbols.Add(UnstructuredName, "unstructuredName"); + DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier"); + DefaultSymbols.Add(DnQualifier, "DN"); + DefaultSymbols.Add(Pseudonym, "Pseudonym"); + DefaultSymbols.Add(PostalAddress, "PostalAddress"); + DefaultSymbols.Add(NameAtBirth, "NameAtBirth"); + DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship"); + DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence"); + DefaultSymbols.Add(Gender, "Gender"); + DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth"); + DefaultSymbols.Add(DateOfBirth, "DateOfBirth"); + DefaultSymbols.Add(PostalCode, "PostalCode"); + DefaultSymbols.Add(BusinessCategory, "BusinessCategory"); + DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber"); + + RFC2253Symbols.Add(C, "C"); + RFC2253Symbols.Add(O, "O"); + RFC2253Symbols.Add(OU, "OU"); + RFC2253Symbols.Add(CN, "CN"); + RFC2253Symbols.Add(L, "L"); + RFC2253Symbols.Add(ST, "ST"); + RFC2253Symbols.Add(Street, "STREET"); + RFC2253Symbols.Add(DC, "DC"); + RFC2253Symbols.Add(UID, "UID"); + + RFC1779Symbols.Add(C, "C"); + RFC1779Symbols.Add(O, "O"); + RFC1779Symbols.Add(OU, "OU"); + RFC1779Symbols.Add(CN, "CN"); + RFC1779Symbols.Add(L, "L"); + RFC1779Symbols.Add(ST, "ST"); + RFC1779Symbols.Add(Street, "STREET"); + + DefaultLookup.Add("c", C); + DefaultLookup.Add("o", O); + DefaultLookup.Add("t", T); + DefaultLookup.Add("ou", OU); + DefaultLookup.Add("cn", CN); + DefaultLookup.Add("l", L); + DefaultLookup.Add("st", ST); + DefaultLookup.Add("serialnumber", SerialNumber); + DefaultLookup.Add("street", Street); + DefaultLookup.Add("emailaddress", E); + DefaultLookup.Add("dc", DC); + DefaultLookup.Add("e", E); + DefaultLookup.Add("uid", UID); + DefaultLookup.Add("surname", Surname); + DefaultLookup.Add("givenname", GivenName); + DefaultLookup.Add("initials", Initials); + DefaultLookup.Add("generation", Generation); + DefaultLookup.Add("unstructuredaddress", UnstructuredAddress); + DefaultLookup.Add("unstructuredname", UnstructuredName); + DefaultLookup.Add("uniqueidentifier", UniqueIdentifier); + DefaultLookup.Add("dn", DnQualifier); + DefaultLookup.Add("pseudonym", Pseudonym); + DefaultLookup.Add("postaladdress", PostalAddress); + DefaultLookup.Add("nameofbirth", NameAtBirth); + DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship); + DefaultLookup.Add("countryofresidence", CountryOfResidence); + DefaultLookup.Add("gender", Gender); + DefaultLookup.Add("placeofbirth", PlaceOfBirth); + DefaultLookup.Add("dateofbirth", DateOfBirth); + DefaultLookup.Add("postalcode", PostalCode); + DefaultLookup.Add("businesscategory", BusinessCategory); + DefaultLookup.Add("telephonenumber", TelephoneNumber); + } + + private readonly ArrayList ordering = new ArrayList(); + private readonly X509NameEntryConverter converter; + + private ArrayList values = new ArrayList(); + private ArrayList added = new ArrayList(); + private Asn1Sequence seq; + + /** + * Return a X509Name based on the passed in tagged object. + * + * @param obj tag object holding name. + * @param explicitly true if explicitly tagged false otherwise. + * @return the X509Name + */ + public static X509Name GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static X509Name GetInstance( + object obj) + { + if (obj == null || obj is X509Name) + { + return (X509Name) obj; + } + + if (obj is Asn1Sequence) + { + return new X509Name((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name); + } + + /** + * Constructor from Asn1Sequence + * + * the principal will be a list of constructed sets, each containing an (OID, string) pair. + */ + protected X509Name( + Asn1Sequence seq) + { + this.seq = seq; + + foreach (Asn1Encodable asn1Obj in seq) + { + Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object()); + + for (int i = 0; i < asn1Set.Count; i++) + { + Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object()); + + if (s.Count != 2) + throw new ArgumentException("badly sized pair"); + + ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object())); + + Asn1Object derValue = s[1].ToAsn1Object(); + if (derValue is IAsn1String && !(derValue is DerUniversalString)) + { + string v = ((IAsn1String)derValue).GetString(); + if (v.StartsWith("#")) + { + v = "\\" + v; + } + + values.Add(v); + } + else + { + byte[] hex = Hex.Encode(derValue.GetEncoded()); + values.Add("#" + Encoding.ASCII.GetString(hex, 0, hex.Length)); + } + + added.Add(i != 0); + } + } + } + + /** + * Constructor from a table of attributes with ordering. + *

      + * it's is assumed the table contains OID/string pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. The ordering ArrayList should contain the OIDs + * in the order they are meant to be encoded or printed in ToString.

      + */ + public X509Name( + ArrayList ordering, + Hashtable attributes) + : this(ordering, attributes, new X509DefaultEntryConverter()) + { + } + + /** + * Constructor from a table of attributes with ordering. + *

      + * it's is assumed the table contains OID/string pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. The ordering ArrayList should contain the OIDs + * in the order they are meant to be encoded or printed in ToString.

      + *

      + * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts.

      + */ + public X509Name( + ArrayList ordering, + Hashtable attributes, + X509NameEntryConverter converter) + { + this.converter = converter; + + foreach (DerObjectIdentifier oid in ordering) + { + object attribute = attributes[oid]; + if (attribute == null) + { + throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name"); + } + + this.ordering.Add(oid); + this.added.Add(false); + this.values.Add(attribute); // copy the hash table + } + } + + /** + * Takes two vectors one of the oids and the other of the values. + */ + public X509Name( + ArrayList oids, + ArrayList values) + : this(oids, values, new X509DefaultEntryConverter()) + { + } + + /** + * Takes two vectors one of the oids and the other of the values. + *

      + * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts.

      + */ + public X509Name( + ArrayList oids, + ArrayList values, + X509NameEntryConverter converter) + { + this.converter = converter; + + if (oids.Count != values.Count) + { + throw new ArgumentException("'oids' must be same length as 'values'."); + } + + for (int i = 0; i < oids.Count; i++) + { + this.ordering.Add(oids[i]); + this.values.Add(values[i]); + this.added.Add(false); + } + } + +// private static bool IsEncoded( +// string s) +// { +// return s.StartsWith("#"); +// } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. + */ + public X509Name( + string dirName) + : this(DefaultReverse, DefaultLookup, dirName) + { + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes with each + * string value being converted to its associated ASN.1 type using the passed + * in converter. + */ + public X509Name( + string dirName, + X509NameEntryConverter converter) + : this(DefaultReverse, DefaultLookup, dirName, converter) + { + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. If reverse + * is true, create the encoded version of the sequence starting from the + * last element in the string. + */ + public X509Name( + bool reverse, + string dirName) + : this(reverse, DefaultLookup, dirName) + { + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes with each + * string value being converted to its associated ASN.1 type using the passed + * in converter. If reverse is true the ASN.1 sequence representing the DN will + * be built by starting at the end of the string, rather than the start. + */ + public X509Name( + bool reverse, + string dirName, + X509NameEntryConverter converter) + : this(reverse, DefaultLookup, dirName, converter) + { + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. lookUp + * should provide a table of lookups, indexed by lowercase only strings and + * yielding a DerObjectIdentifier, other than that OID. and numeric oids + * will be processed automatically. + *
      + * If reverse is true, create the encoded version of the sequence + * starting from the last element in the string. + * @param reverse true if we should start scanning from the end (RFC 2553). + * @param lookUp table of names and their oids. + * @param dirName the X.500 string to be parsed. + */ + public X509Name( + bool reverse, + Hashtable lookUp, + string dirName) + : this(reverse, lookUp, dirName, new X509DefaultEntryConverter()) + { + } + + private DerObjectIdentifier DecodeOid( + string name, + IDictionary lookUp) + { + if (name.ToUpper(CultureInfo.InvariantCulture).StartsWith("OID.")) + { + return new DerObjectIdentifier(name.Substring(4)); + } + else if (name[0] >= '0' && name[0] <= '9') + { + return new DerObjectIdentifier(name); + } + + DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[name.ToLower(CultureInfo.InvariantCulture)]; + if (oid == null) + { + throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } + + return oid; + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. lookUp + * should provide a table of lookups, indexed by lowercase only strings and + * yielding a DerObjectIdentifier, other than that OID. and numeric oids + * will be processed automatically. The passed in converter is used to convert the + * string values to the right of each equals sign to their ASN.1 counterparts. + *
      + * @param reverse true if we should start scanning from the end, false otherwise. + * @param lookUp table of names and oids. + * @param dirName the string dirName + * @param converter the converter to convert string values into their ASN.1 equivalents + */ + public X509Name( + bool reverse, + IDictionary lookUp, + string dirName, + X509NameEntryConverter converter) + { + this.converter = converter; + X509NameTokenizer nTok = new X509NameTokenizer(dirName); + + while (nTok.HasMoreTokens()) + { + string token = nTok.NextToken(); + int index = token.IndexOf('='); + + if (index == -1) + { + throw new ArgumentException("badly formated directory string"); + } + + string name = token.Substring(0, index); + string value = token.Substring(index + 1); + DerObjectIdentifier oid = DecodeOid(name, lookUp); + + if (value.IndexOf('+') > 0) + { + X509NameTokenizer vTok = new X509NameTokenizer(value, '+'); + string v = vTok.NextToken(); + + this.ordering.Add(oid); + this.values.Add(v); + this.added.Add(false); + + while (vTok.HasMoreTokens()) + { + string sv = vTok.NextToken(); + int ndx = sv.IndexOf('='); + + string nm = sv.Substring(0, ndx); + string vl = sv.Substring(ndx + 1); + this.ordering.Add(DecodeOid(nm, lookUp)); + this.values.Add(vl); + this.added.Add(true); + } + } + else + { + this.ordering.Add(oid); + this.values.Add(value); + this.added.Add(false); + } + } + + if (reverse) + { +// this.ordering.Reverse(); +// this.values.Reverse(); +// this.added.Reverse(); + ArrayList o = new ArrayList(); + ArrayList v = new ArrayList(); + ArrayList a = new ArrayList(); + int count = 1; + + for (int i = 0; i < this.ordering.Count; i++) + { + if (!((bool) this.added[i])) + { + count = 0; + } + + int index = count++; + + o.Insert(index, this.ordering[i]); + v.Insert(index, this.values[i]); + a.Insert(index, this.added[i]); + } + + this.ordering = o; + this.values = v; + this.added = a; + } + } + + /** + * return an ArrayList of the oids in the name, in the order they were found. + */ + public ArrayList GetOids() + { + return (ArrayList) ordering.Clone(); + } + + /** + * return an ArrayList of the values found in the name, in the order they + * were found. + */ + public ArrayList GetValues() + { + return (ArrayList) values.Clone(); + } + + /** + * return an ArrayList of the values found in the name, in the order they + * were found, with the DN label corresponding to passed in oid. + */ + public ArrayList GetValues( + DerObjectIdentifier oid) + { + ArrayList v = new ArrayList(); + + for (int i = 0; i != values.Count; i++) + { + if (ordering[i].Equals(oid)) + { + string val = (string)values[i]; + + if (val.StartsWith("\\#")) + { + val = val.Substring(1); + } + + v.Add(val); + } + } + + return v; + } + + public override Asn1Object ToAsn1Object() + { + if (seq == null) + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + Asn1EncodableVector sVec = new Asn1EncodableVector(); + DerObjectIdentifier lstOid = null; + + for (int i = 0; i != ordering.Count; i++) + { + DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i]; + string str = (string)values[i]; + + if (lstOid == null + || ((bool)this.added[i])) + { + } + else + { + vec.Add(new DerSet(sVec)); + sVec = new Asn1EncodableVector(); + } + + sVec.Add( + new DerSequence( + oid, + converter.GetConvertedValue(oid, str))); + + lstOid = oid; + } + + vec.Add(new DerSet(sVec)); + + seq = new DerSequence(vec); + } + + return seq; + } + + [Obsolete("Use 'Equivalent(X509Name, int)' instead")] + public bool Equals( + X509Name other, + bool inOrder) + { + return Equivalent(other, inOrder); + } + + /// The X509Name object to test equivalency against. + /// If true, the order of elements must be the same, + /// as well as the values associated with each element. + public bool Equivalent( + X509Name other, + bool inOrder) + { + if (!inOrder) + return this.Equivalent(other); + + if (other == null) + return false; + + if (other == this) + return true; + + int orderingSize = ordering.Count; + + if (orderingSize != other.ordering.Count) + return false; + + for (int i = 0; i < orderingSize; i++) + { + DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i]; + DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i]; + + if (!oid.Equals(oOid)) + return false; + + string val = (string) values[i]; + string oVal = (string) other.values[i]; + + if (!equivalentStrings(val, oVal)) + return false; + } + + return true; + } + + [Obsolete("Use 'Equivalent(X509Name)' instead")] + public bool Equals( + X509Name other) + { + return Equivalent(other); + } + + /** + * test for equivalence - note: case is ignored. + */ + public bool Equivalent( + X509Name other) + { + if (other == null) + return false; + + if (other == this) + return true; + + int orderingSize = ordering.Count; + + if (orderingSize != other.ordering.Count) + { + return false; + } + + bool[] indexes = new bool[orderingSize]; + int start, end, delta; + + if (ordering[0].Equals(other.ordering[0])) // guess forward + { + start = 0; + end = orderingSize; + delta = 1; + } + else // guess reversed - most common problem + { + start = orderingSize - 1; + end = -1; + delta = -1; + } + + for (int i = start; i != end; i += delta) + { + bool found = false; + DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i]; + string value = (string)values[i]; + + for (int j = 0; j < orderingSize; j++) + { + if (indexes[j]) + { + continue; + } + + DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j]; + + if (oid.Equals(oOid)) + { + string oValue = (string)other.values[j]; + + if (equivalentStrings(value, oValue)) + { + indexes[j] = true; + found = true; + break; + } + } + } + + if (!found) + { + return false; + } + } + + return true; + } + + private bool equivalentStrings( + string s1, + string s2) + { + string value = s1.ToLower(CultureInfo.InvariantCulture).Trim(); + string oValue = s2.ToLower(CultureInfo.InvariantCulture).Trim(); + + if (!value.Equals(oValue)) + { + value = stripInternalSpaces(value); + oValue = stripInternalSpaces(oValue); + + if (!value.Equals(oValue)) + { + return false; + } + } + + return true; + } + + private string stripInternalSpaces( + string str) + { + StringBuilder res = new StringBuilder(); + + if (str.Length != 0) + { + char c1 = str[0]; + + res.Append(c1); + + for (int k = 1; k < str.Length; k++) + { + char c2 = str[k]; + if (!(c1 == ' ' && c2 == ' ')) + { + res.Append(c2); + } + c1 = c2; + } + } + + return res.ToString(); + } + + private void AppendValue( + StringBuilder buf, + Hashtable oidSymbols, + DerObjectIdentifier oid, + string val) + { + string sym = (string) oidSymbols[oid]; + + if (sym != null) + { + buf.Append(sym); + } + else + { + buf.Append(oid.Id); + } + + buf.Append('='); + + int index = buf.Length; + + buf.Append(val); + + int end = buf.Length; + + if (val.StartsWith("\\#")) + { + index += 2; + } + + while (index != end) + { + if ((buf[index] == ',') + || (buf[index] == '"') + || (buf[index] == '\\') + || (buf[index] == '+') + || (buf[index] == '<') + || (buf[index] == '>') + || (buf[index] == ';')) + { + buf.Insert(index++, "\\"); + end++; + } + + index++; + } + } + + /** + * convert the structure to a string - if reverse is true the + * oids and values are listed out starting with the last element + * in the sequence (ala RFC 2253), otherwise the string will begin + * with the first element of the structure. If no string definition + * for the oid is found in oidSymbols the string value of the oid is + * added. Two standard symbol tables are provided DefaultSymbols, and + * RFC2253Symbols as part of this class. + * + * @param reverse if true start at the end of the sequence and work back. + * @param oidSymbols look up table strings for oids. + */ + public string ToString( + bool reverse, + Hashtable oidSymbols) + { + StringBuilder buf = new StringBuilder(); + ArrayList components = new ArrayList(); + bool first = true; + + StringBuilder ava = null; + + for (int i = 0; i < ordering.Count; i++) + { + if ((bool) added[i]) + { + ava.Append('+'); + AppendValue(ava, oidSymbols, + (DerObjectIdentifier)ordering[i], + (string)values[i]); + } + else + { + ava = new StringBuilder(); + AppendValue(ava, oidSymbols, + (DerObjectIdentifier)ordering[i], + (string)values[i]); + components.Add(ava); + } + } + + if (reverse) + { + for (int i = components.Count - 1; i >= 0; i--) + { + if (first) + { + first = false; + } + else + { + buf.Append(','); + } + + buf.Append(components[i].ToString()); + } + } + else + { + for (int i = 0; i < components.Count; i++) + { + if (first) + { + first = false; + } + else + { + buf.Append(','); + } + + buf.Append(components[i].ToString()); + } + } + + return buf.ToString(); + } + + public override string ToString() + { + return ToString(DefaultReverse, DefaultSymbols); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509NameEntryConverter.cs b/iTechSharp/srcbc/asn1/x509/X509NameEntryConverter.cs new file mode 100644 index 0000000..5872656 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509NameEntryConverter.cs @@ -0,0 +1,89 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * It turns out that the number of standard ways the fields in a DN should be + * encoded into their ASN.1 counterparts is rapidly approaching the + * number of machines on the internet. By default the X509Name class + * will produce UTF8Strings in line with the current recommendations (RFC 3280). + *

      + * An example of an encoder look like below: + *

      +     * public class X509DirEntryConverter
      +     *     : X509NameEntryConverter
      +     * {
      +     *     public Asn1Object GetConvertedValue(
      +     *         DerObjectIdentifier  oid,
      +     *         string               value)
      +     *     {
      +     *         if (str.Length() != 0 && str.charAt(0) == '#')
      +     *         {
      +     *             return ConvertHexEncoded(str, 1);
      +     *         }
      +     *         if (oid.Equals(EmailAddress))
      +     *         {
      +     *             return new DerIA5String(str);
      +     *         }
      +     *         else if (CanBePrintable(str))
      +     *         {
      +     *             return new DerPrintableString(str);
      +     *         }
      +     *         else if (CanBeUTF8(str))
      +     *         {
      +     *             return new DerUtf8String(str);
      +     *         }
      +     *         else
      +     *         {
      +     *             return new DerBmpString(str);
      +     *         }
      +     *     }
      +     * }
      +	 * 
      + *

      + */ + public abstract class X509NameEntryConverter + { + /** + * Convert an inline encoded hex string rendition of an ASN.1 + * object back into its corresponding ASN.1 object. + * + * @param str the hex encoded object + * @param off the index at which the encoding starts + * @return the decoded object + */ + protected Asn1Object ConvertHexEncoded( + string hexString, + int offset) + { + string str = hexString.Substring(offset); + + return Asn1Object.FromByteArray(Hex.Decode(str)); + } + + /** + * return true if the passed in string can be represented without + * loss as a PrintableString, false otherwise. + */ + protected bool CanBePrintable( + string str) + { + return DerPrintableString.IsPrintableString(str); + } + + /** + * Convert the passed in string value into the appropriate ASN.1 + * encoded object. + * + * @param oid the oid associated with the value in the DN. + * @param value the value of the particular DN component. + * @return the ASN.1 equivalent for the value. + */ + public abstract Asn1Object GetConvertedValue(DerObjectIdentifier oid, string value); + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509NameTokenizer.cs b/iTechSharp/srcbc/asn1/x509/X509NameTokenizer.cs new file mode 100644 index 0000000..51ade3d --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509NameTokenizer.cs @@ -0,0 +1,101 @@ +using System.Text; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * class for breaking up an X500 Name into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + */ + public class X509NameTokenizer + { + private string value; + private int index; + private char separator; + private StringBuilder buffer = new StringBuilder(); + + public X509NameTokenizer( + string oid) + : this(oid, ',') + { + } + + public X509NameTokenizer( + string oid, + char separator) + { + this.value = oid; + this.index = -1; + this.separator = separator; + } + + public bool HasMoreTokens() + { + return index != value.Length; + } + + public string NextToken() + { + if (index == value.Length) + { + return null; + } + + int end = index + 1; + bool quoted = false; + bool escaped = false; + + buffer.Remove(0, buffer.Length); + + while (end != value.Length) + { + char c = value[end]; + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + buffer.Append(c); + } + + escaped = false; + } + else + { + if (escaped || quoted) + { + if (c == '#' && buffer[buffer.Length - 1] == '=') + { + buffer.Append('\\'); + } + buffer.Append(c); + escaped = false; + } + else if (c == '\\') + { + escaped = true; + } + else if (c == separator) + { + break; + } + else + { + buffer.Append(c); + } + } + + end++; + } + + index = end; + + return buffer.ToString().Trim(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/X509ObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/x509/X509ObjectIdentifiers.cs new file mode 100644 index 0000000..357c4b3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/X509ObjectIdentifiers.cs @@ -0,0 +1,56 @@ +namespace Org.BouncyCastle.Asn1.X509 +{ + public abstract class X509ObjectIdentifiers + { + // + // base id + // + internal const string ID = "2.5.4"; + + public static readonly DerObjectIdentifier CommonName = new DerObjectIdentifier(ID + ".3"); + public static readonly DerObjectIdentifier CountryName = new DerObjectIdentifier(ID + ".6"); + public static readonly DerObjectIdentifier LocalityName = new DerObjectIdentifier(ID + ".7"); + public static readonly DerObjectIdentifier StateOrProvinceName = new DerObjectIdentifier(ID + ".8"); + public static readonly DerObjectIdentifier Organization = new DerObjectIdentifier(ID + ".10"); + public static readonly DerObjectIdentifier OrganizationalUnitName = new DerObjectIdentifier(ID + ".11"); + + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26"); + + // + // ripemd160 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RipeMD-160(1)} + // + public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier("1.3.36.3.2.1"); + + // + // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) } + // + public static readonly DerObjectIdentifier RipeMD160WithRsaEncryption = new DerObjectIdentifier("1.3.36.3.3.1.2"); + + public static readonly DerObjectIdentifier IdEARsa = new DerObjectIdentifier("2.5.8.1.1"); + + // id-pkix + public static readonly DerObjectIdentifier IdPkix = new DerObjectIdentifier("1.3.6.1.5.5.7"); + + // + // private internet extensions + // + public static readonly DerObjectIdentifier IdPE = new DerObjectIdentifier(IdPkix + ".1"); + + // + // authority information access + // + public static readonly DerObjectIdentifier IdAD = new DerObjectIdentifier(IdPkix + ".48"); + public static readonly DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier(IdAD + ".2"); + public static readonly DerObjectIdentifier IdADOcsp = new DerObjectIdentifier(IdAD + ".1"); + + // + // OID for ocsp and crl uri in AuthorityInformationAccess extension + // + public static readonly DerObjectIdentifier OcspAccessMethod = IdADOcsp; + public static readonly DerObjectIdentifier CrlAccessMethod = IdADCAIssuers; + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/BiometricData.cs b/iTechSharp/srcbc/asn1/x509/qualified/BiometricData.cs new file mode 100644 index 0000000..61d7c99 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/BiometricData.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The BiometricData object. + *
      +    * BiometricData  ::=  SEQUENCE {
      +    *       typeOfBiometricData  TypeOfBiometricData,
      +    *       hashAlgorithm        AlgorithmIdentifier,
      +    *       biometricDataHash    OCTET STRING,
      +    *       sourceDataUri        IA5String OPTIONAL  }
      +    * 
      + */ + public class BiometricData + : Asn1Encodable + { + private readonly TypeOfBiometricData typeOfBiometricData; + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly Asn1OctetString biometricDataHash; + private readonly DerIA5String sourceDataUri; + + public static BiometricData GetInstance( + object obj) + { + if (obj == null || obj is BiometricData) + { + return (BiometricData)obj; + } + + if (obj is Asn1Sequence) + { + return new BiometricData(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + private BiometricData( + Asn1Sequence seq) + { + typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[0]); + hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]); + biometricDataHash = Asn1OctetString.GetInstance(seq[2]); + + if (seq.Count > 3) + { + sourceDataUri = DerIA5String.GetInstance(seq[3]); + } + } + + public BiometricData( + TypeOfBiometricData typeOfBiometricData, + AlgorithmIdentifier hashAlgorithm, + Asn1OctetString biometricDataHash, + DerIA5String sourceDataUri) + { + this.typeOfBiometricData = typeOfBiometricData; + this.hashAlgorithm = hashAlgorithm; + this.biometricDataHash = biometricDataHash; + this.sourceDataUri = sourceDataUri; + } + + public BiometricData( + TypeOfBiometricData typeOfBiometricData, + AlgorithmIdentifier hashAlgorithm, + Asn1OctetString biometricDataHash) + { + this.typeOfBiometricData = typeOfBiometricData; + this.hashAlgorithm = hashAlgorithm; + this.biometricDataHash = biometricDataHash; + this.sourceDataUri = null; + } + + public TypeOfBiometricData TypeOfBiometricData + { + get { return typeOfBiometricData; } + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return hashAlgorithm; } + } + + public Asn1OctetString BiometricDataHash + { + get { return biometricDataHash; } + } + + public DerIA5String SourceDataUri + { + get { return sourceDataUri; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector seq = new Asn1EncodableVector( + typeOfBiometricData, hashAlgorithm, biometricDataHash); + + if (sourceDataUri != null) + { + seq.Add(sourceDataUri); + } + + return new DerSequence(seq); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs new file mode 100644 index 0000000..86a4eee --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs @@ -0,0 +1,19 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + public abstract class EtsiQCObjectIdentifiers + { + // + // base id + // + public static readonly DerObjectIdentifier IdEtsiQcs = new DerObjectIdentifier("0.4.0.1862.1"); + + public static readonly DerObjectIdentifier IdEtsiQcsQcCompliance = new DerObjectIdentifier(IdEtsiQcs+".1"); + public static readonly DerObjectIdentifier IdEtsiQcsLimitValue = new DerObjectIdentifier(IdEtsiQcs+".2"); + public static readonly DerObjectIdentifier IdEtsiQcsRetentionPeriod = new DerObjectIdentifier(IdEtsiQcs+".3"); + public static readonly DerObjectIdentifier IdEtsiQcsQcSscd = new DerObjectIdentifier(IdEtsiQcs+".4"); + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs b/iTechSharp/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs new file mode 100644 index 0000000..cfb6449 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs @@ -0,0 +1,84 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The Iso4217CurrencyCode object. + *
      +    * Iso4217CurrencyCode  ::=  CHOICE {
      +    *       alphabetic              PrintableString (SIZE 3), --Recommended
      +    *       numeric              INTEGER (1..999) }
      +    * -- Alphabetic or numeric currency code as defined in ISO 4217
      +    * -- It is recommended that the Alphabetic form is used
      +    * 
      + */ + public class Iso4217CurrencyCode + : Asn1Encodable + { + internal const int AlphabeticMaxSize = 3; + internal const int NumericMinSize = 1; + internal const int NumericMaxSize = 999; + + internal Asn1Encodable obj; +// internal int numeric; + + public static Iso4217CurrencyCode GetInstance( + object obj) + { + if (obj == null || obj is Iso4217CurrencyCode) + { + return (Iso4217CurrencyCode) obj; + } + + if (obj is DerInteger) + { + DerInteger numericobj = DerInteger.GetInstance(obj); + int numeric = numericobj.Value.IntValue; + return new Iso4217CurrencyCode(numeric); + } + + if (obj is DerPrintableString) + { + DerPrintableString alphabetic = DerPrintableString.GetInstance(obj); + return new Iso4217CurrencyCode(alphabetic.GetString()); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public Iso4217CurrencyCode( + int numeric) + { + if (numeric > NumericMaxSize || numeric < NumericMinSize) + { + throw new ArgumentException("wrong size in numeric code : not in (" +NumericMinSize +".."+ NumericMaxSize +")"); + } + + obj = new DerInteger(numeric); + } + + public Iso4217CurrencyCode( + string alphabetic) + { + if (alphabetic.Length > AlphabeticMaxSize) + { + throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize); + } + + obj = new DerPrintableString(alphabetic); + } + + public bool IsAlphabetic { get { return obj is DerPrintableString; } } + + public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } } + + public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } } + + public override Asn1Object ToAsn1Object() + { + return obj.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/MonetaryValue.cs b/iTechSharp/srcbc/asn1/x509/qualified/MonetaryValue.cs new file mode 100644 index 0000000..45e1136 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/MonetaryValue.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The MonetaryValue object. + *
      +    * MonetaryValue  ::=  SEQUENCE {
      +    *       currency              Iso4217CurrencyCode,
      +    *       amount               INTEGER,
      +    *       exponent             INTEGER }
      +    * -- value = amount * 10^exponent
      +    * 
      + */ + public class MonetaryValue + : Asn1Encodable + { + internal Iso4217CurrencyCode currency; + internal DerInteger amount; + internal DerInteger exponent; + + public static MonetaryValue GetInstance( + object obj) + { + if (obj == null || obj is MonetaryValue) + { + return (MonetaryValue) obj; + } + + if (obj is Asn1Sequence) + { + return new MonetaryValue(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + private MonetaryValue( + Asn1Sequence seq) + { + if (seq.Count != 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + currency = Iso4217CurrencyCode.GetInstance(seq[0]); + amount = DerInteger.GetInstance(seq[1]); + exponent = DerInteger.GetInstance(seq[2]); + } + + public MonetaryValue( + Iso4217CurrencyCode currency, + int amount, + int exponent) + { + this.currency = currency; + this.amount = new DerInteger(amount); + this.exponent = new DerInteger(exponent); + } + + public Iso4217CurrencyCode Currency + { + get { return currency; } + } + + public BigInteger Amount + { + get { return amount.Value; } + } + + public BigInteger Exponent + { + get { return exponent.Value; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(currency, amount, exponent); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/QCStatement.cs b/iTechSharp/srcbc/asn1/x509/qualified/QCStatement.cs new file mode 100644 index 0000000..317f034 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/QCStatement.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The QCStatement object. + *
      +    * QCStatement ::= SEQUENCE {
      +    *   statementId        OBJECT IDENTIFIER,
      +    *   statementInfo      ANY DEFINED BY statementId OPTIONAL}
      +    * 
      + */ + public class QCStatement + : Asn1Encodable + { + private readonly DerObjectIdentifier qcStatementId; + private readonly Asn1Encodable qcStatementInfo; + + public static QCStatement GetInstance( + object obj) + { + if (obj == null || obj is QCStatement) + { + return (QCStatement) obj; + } + + if (obj is Asn1Sequence) + { + return new QCStatement(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + private QCStatement( + Asn1Sequence seq) + { + qcStatementId = DerObjectIdentifier.GetInstance(seq[0]); + + if (seq.Count > 1) + { + qcStatementInfo = seq[1]; + } + } + + public QCStatement( + DerObjectIdentifier qcStatementId) + { + this.qcStatementId = qcStatementId; + } + + public QCStatement( + DerObjectIdentifier qcStatementId, + Asn1Encodable qcStatementInfo) + { + this.qcStatementId = qcStatementId; + this.qcStatementInfo = qcStatementInfo; + } + + public DerObjectIdentifier StatementId + { + get { return qcStatementId; } + } + + public Asn1Encodable StatementInfo + { + get { return qcStatementInfo; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector seq = new Asn1EncodableVector(qcStatementId); + + if (qcStatementInfo != null) + { + seq.Add(qcStatementInfo); + } + + return new DerSequence(seq); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs new file mode 100644 index 0000000..8ebd69e --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs @@ -0,0 +1,21 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + public sealed class Rfc3739QCObjectIdentifiers + { + private Rfc3739QCObjectIdentifiers() + { + } + + // + // base id + // + public static readonly DerObjectIdentifier IdQcs = new DerObjectIdentifier("1.3.6.1.5.5.7.11"); + + public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV1 = new DerObjectIdentifier(IdQcs+".1"); + public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV2 = new DerObjectIdentifier(IdQcs+".2"); + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/SemanticsInformation.cs b/iTechSharp/srcbc/asn1/x509/qualified/SemanticsInformation.cs new file mode 100644 index 0000000..72e7cd0 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/SemanticsInformation.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The SemanticsInformation object. + *
      +    *       SemanticsInformation ::= SEQUENCE {
      +    *         semanticsIdentifier        OBJECT IDENTIFIER   OPTIONAL,
      +    *         nameRegistrationAuthorities NameRegistrationAuthorities
      +    *                                                         OPTIONAL }
      +    *         (WITH COMPONENTS {..., semanticsIdentifier PRESENT}|
      +    *          WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT})
      +    *
      +    *     NameRegistrationAuthorities ::=  SEQUENCE SIZE (1..MAX) OF
      +    *         GeneralName
      +    * 
      + */ + public class SemanticsInformation + : Asn1Encodable + { + private readonly DerObjectIdentifier semanticsIdentifier; + private readonly GeneralName[] nameRegistrationAuthorities; + + public static SemanticsInformation GetInstance( + object obj) + { + if (obj == null || obj is SemanticsInformation) + { + return (SemanticsInformation) obj; + } + + if (obj is Asn1Sequence) + { + return new SemanticsInformation(Asn1Sequence.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public SemanticsInformation( + Asn1Sequence seq) + { + if (seq.Count < 1) + { + throw new ArgumentException("no objects in SemanticsInformation"); + } + + IEnumerator e = seq.GetEnumerator(); + e.MoveNext(); + object obj = e.Current; + if (obj is DerObjectIdentifier) + { + semanticsIdentifier = DerObjectIdentifier.GetInstance(obj); + if (e.MoveNext()) + { + obj = e.Current; + } + else + { + obj = null; + } + } + + if (obj != null) + { + Asn1Sequence generalNameSeq = Asn1Sequence.GetInstance(obj ); + nameRegistrationAuthorities = new GeneralName[generalNameSeq.Count]; + for (int i= 0; i < generalNameSeq.Count; i++) + { + nameRegistrationAuthorities[i] = GeneralName.GetInstance(generalNameSeq[i]); + } + } + } + + public SemanticsInformation( + DerObjectIdentifier semanticsIdentifier, + GeneralName[] generalNames) + { + this.semanticsIdentifier = semanticsIdentifier; + this.nameRegistrationAuthorities = generalNames; + } + + public SemanticsInformation( + DerObjectIdentifier semanticsIdentifier) + { + this.semanticsIdentifier = semanticsIdentifier; + } + + public SemanticsInformation( + GeneralName[] generalNames) + { + this.nameRegistrationAuthorities = generalNames; + } + + public DerObjectIdentifier SemanticsIdentifier { get { return semanticsIdentifier; } } + + public GeneralName[] GetNameRegistrationAuthorities() + { + return nameRegistrationAuthorities; + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector seq = new Asn1EncodableVector(); + + if (this.semanticsIdentifier != null) + { + seq.Add(semanticsIdentifier); + } + + if (this.nameRegistrationAuthorities != null) + { + seq.Add(new DerSequence(nameRegistrationAuthorities)); + } + + return new DerSequence(seq); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs b/iTechSharp/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs new file mode 100644 index 0000000..51b3118 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs @@ -0,0 +1,91 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The TypeOfBiometricData object. + *
      +    * TypeOfBiometricData ::= CHOICE {
      +    *   predefinedBiometricType   PredefinedBiometricType,
      +    *   biometricDataOid          OBJECT IDENTIFIER }
      +    *
      +    * PredefinedBiometricType ::= INTEGER {
      +    *   picture(0),handwritten-signature(1)}
      +    *   (picture|handwritten-signature)
      +    * 
      + */ + public class TypeOfBiometricData + : Asn1Encodable + { + public const int Picture = 0; + public const int HandwrittenSignature = 1; + + internal Asn1Encodable obj; + + public static TypeOfBiometricData GetInstance( + object obj) + { + if (obj == null || obj is TypeOfBiometricData) + { + return (TypeOfBiometricData) obj; + } + + if (obj is DerInteger) + { + DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj); + int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue; + + return new TypeOfBiometricData(predefinedBiometricType); + } + + if (obj is DerObjectIdentifier) + { + DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj); + return new TypeOfBiometricData(BiometricDataOid); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public TypeOfBiometricData( + int predefinedBiometricType) + { + if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature) + { + obj = new DerInteger(predefinedBiometricType); + } + else + { + throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType); + } + } + + public TypeOfBiometricData( + DerObjectIdentifier biometricDataOid) + { + obj = biometricDataOid; + } + + public bool IsPredefined + { + get { return obj is DerInteger; } + } + + public int PredefinedBiometricType + { + get { return ((DerInteger) obj).Value.IntValue; } + } + + public DerObjectIdentifier BiometricDataOid + { + get { return (DerObjectIdentifier) obj; } + } + + public override Asn1Object ToAsn1Object() + { + return obj.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/sigi/NameOrPseudonym.cs b/iTechSharp/srcbc/asn1/x509/sigi/NameOrPseudonym.cs new file mode 100644 index 0000000..8e86823 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/sigi/NameOrPseudonym.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X500; + +namespace Org.BouncyCastle.Asn1.X509.SigI +{ + /** + * Structure for a name or pseudonym. + * + *
      +	*       NameOrPseudonym ::= CHOICE {
      +	*     	   surAndGivenName SEQUENCE {
      +	*     	     surName DirectoryString,
      +	*     	     givenName SEQUENCE OF DirectoryString 
      +	*         },
      +	*     	   pseudonym DirectoryString 
      +	*       }
      +	* 
      + * + * @see org.bouncycastle.asn1.x509.sigi.PersonalData + * + */ + public class NameOrPseudonym + : Asn1Encodable + //, Asn1Choice + { + private readonly DirectoryString pseudonym; + private readonly DirectoryString surname; + private readonly Asn1Sequence givenName; + + public static NameOrPseudonym GetInstance( + object obj) + { + if (obj == null || obj is NameOrPseudonym) + { + return (NameOrPseudonym)obj; + } + + if (obj is IAsn1String) + { + return new NameOrPseudonym(DirectoryString.GetInstance(obj)); + } + + if (obj is Asn1Sequence) + { + return new NameOrPseudonym((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from DERString. + *

      + * The sequence is of type NameOrPseudonym: + *

      + *

      +		*       NameOrPseudonym ::= CHOICE {
      +		*     	   surAndGivenName SEQUENCE {
      +		*     	     surName DirectoryString,
      +		*     	     givenName SEQUENCE OF DirectoryString
      +		*         },
      +		*     	   pseudonym DirectoryString
      +		*       }
      +		* 
      + * @param pseudonym pseudonym value to use. + */ + public NameOrPseudonym( + DirectoryString pseudonym) + { + this.pseudonym = pseudonym; + } + + /** + * Constructor from Asn1Sequence. + *

      + * The sequence is of type NameOrPseudonym: + *

      + *

      +		*       NameOrPseudonym ::= CHOICE {
      +		*     	   surAndGivenName SEQUENCE {
      +		*     	     surName DirectoryString,
      +		*     	     givenName SEQUENCE OF DirectoryString
      +		*         },
      +		*     	   pseudonym DirectoryString
      +		*       }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private NameOrPseudonym( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + if (!(seq[0] is IAsn1String)) + throw new ArgumentException("Bad object encountered: " + seq[0].GetType().Name); + + surname = DirectoryString.GetInstance(seq[0]); + givenName = Asn1Sequence.GetInstance(seq[1]); + } + + /** + * Constructor from a given details. + * + * @param pseudonym The pseudonym. + */ + public NameOrPseudonym( + string pseudonym) + : this(new DirectoryString(pseudonym)) + { + } + + /** + * Constructor from a given details. + * + * @param surname The surname. + * @param givenName A sequence of directory strings making up the givenName + */ + public NameOrPseudonym( + DirectoryString surname, + Asn1Sequence givenName) + { + this.surname = surname; + this.givenName = givenName; + } + + public DirectoryString Pseudonym + { + get { return pseudonym; } + } + + public DirectoryString Surname + { + get { return surname; } + } + + public DirectoryString[] GetGivenName() + { + DirectoryString[] items = new DirectoryString[givenName.Count]; + int count = 0; + foreach (object o in givenName) + { + items[count++] = DirectoryString.GetInstance(o); + } + return items; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*       NameOrPseudonym ::= CHOICE {
      +		*     	   surAndGivenName SEQUENCE {
      +		*     	     surName DirectoryString,
      +		*     	     givenName SEQUENCE OF DirectoryString
      +		*         },
      +		*     	   pseudonym DirectoryString
      +		*       }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + if (pseudonym != null) + { + return pseudonym.ToAsn1Object(); + } + + return new DerSequence(surname, givenName); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/sigi/PersonalData.cs b/iTechSharp/srcbc/asn1/x509/sigi/PersonalData.cs new file mode 100644 index 0000000..6acdc73 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/sigi/PersonalData.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X500; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X509.SigI +{ + /** + * Contains personal data for the otherName field in the subjectAltNames + * extension. + *

      + *

      +	*     PersonalData ::= SEQUENCE {
      +	*       nameOrPseudonym NameOrPseudonym,
      +	*       nameDistinguisher [0] INTEGER OPTIONAL,
      +	*       dateOfBirth [1] GeneralizedTime OPTIONAL,
      +	*       placeOfBirth [2] DirectoryString OPTIONAL,
      +	*       gender [3] PrintableString OPTIONAL,
      +	*       postalAddress [4] DirectoryString OPTIONAL
      +	*       }
      +	* 
      + * + * @see org.bouncycastle.asn1.x509.sigi.NameOrPseudonym + * @see org.bouncycastle.asn1.x509.sigi.SigIObjectIdentifiers + */ + public class PersonalData + : Asn1Encodable + { + private readonly NameOrPseudonym nameOrPseudonym; + private readonly BigInteger nameDistinguisher; + private readonly DerGeneralizedTime dateOfBirth; + private readonly DirectoryString placeOfBirth; + private readonly string gender; + private readonly DirectoryString postalAddress; + + public static PersonalData GetInstance( + object obj) + { + if (obj == null || obj is PersonalData) + { + return (PersonalData) obj; + } + + if (obj is Asn1Sequence) + { + return new PersonalData((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1Sequence. + *

      + * The sequence is of type NameOrPseudonym: + *

      + *

      +		*     PersonalData ::= SEQUENCE {
      +		*       nameOrPseudonym NameOrPseudonym,
      +		*       nameDistinguisher [0] INTEGER OPTIONAL,
      +		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
      +		*       placeOfBirth [2] DirectoryString OPTIONAL,
      +		*       gender [3] PrintableString OPTIONAL,
      +		*       postalAddress [4] DirectoryString OPTIONAL
      +		*       }
      +		* 
      + * + * @param seq The ASN.1 sequence. + */ + private PersonalData( + Asn1Sequence seq) + { + if (seq.Count < 1) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + IEnumerator e = seq.GetEnumerator(); + e.MoveNext(); + + nameOrPseudonym = NameOrPseudonym.GetInstance(e.Current); + + while (e.MoveNext()) + { + Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current); + int tag = o.TagNo; + switch (tag) + { + case 0: + nameDistinguisher = DerInteger.GetInstance(o, false).Value; + break; + case 1: + dateOfBirth = DerGeneralizedTime.GetInstance(o, false); + break; + case 2: + placeOfBirth = DirectoryString.GetInstance(o, true); + break; + case 3: + gender = DerPrintableString.GetInstance(o, false).GetString(); + break; + case 4: + postalAddress = DirectoryString.GetInstance(o, true); + break; + default: + throw new ArgumentException("Bad tag number: " + o.TagNo); + } + } + } + + /** + * Constructor from a given details. + * + * @param nameOrPseudonym Name or pseudonym. + * @param nameDistinguisher Name distinguisher. + * @param dateOfBirth Date of birth. + * @param placeOfBirth Place of birth. + * @param gender Gender. + * @param postalAddress Postal Address. + */ + public PersonalData( + NameOrPseudonym nameOrPseudonym, + BigInteger nameDistinguisher, + DerGeneralizedTime dateOfBirth, + DirectoryString placeOfBirth, + string gender, + DirectoryString postalAddress) + { + this.nameOrPseudonym = nameOrPseudonym; + this.dateOfBirth = dateOfBirth; + this.gender = gender; + this.nameDistinguisher = nameDistinguisher; + this.postalAddress = postalAddress; + this.placeOfBirth = placeOfBirth; + } + + public NameOrPseudonym NameOrPseudonym + { + get { return nameOrPseudonym; } + } + + public BigInteger NameDistinguisher + { + get { return nameDistinguisher; } + } + + public DerGeneralizedTime DateOfBirth + { + get { return dateOfBirth; } + } + + public DirectoryString PlaceOfBirth + { + get { return placeOfBirth; } + } + + public string Gender + { + get { return gender; } + } + + public DirectoryString PostalAddress + { + get { return postalAddress; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

      + * Returns: + *

      + *

      +		*     PersonalData ::= SEQUENCE {
      +		*       nameOrPseudonym NameOrPseudonym,
      +		*       nameDistinguisher [0] INTEGER OPTIONAL,
      +		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
      +		*       placeOfBirth [2] DirectoryString OPTIONAL,
      +		*       gender [3] PrintableString OPTIONAL,
      +		*       postalAddress [4] DirectoryString OPTIONAL
      +		*       }
      +		* 
      + * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + vec.Add(nameOrPseudonym); + if (nameDistinguisher != null) + { + vec.Add(new DerTaggedObject(false, 0, new DerInteger(nameDistinguisher))); + } + if (dateOfBirth != null) + { + vec.Add(new DerTaggedObject(false, 1, dateOfBirth)); + } + if (placeOfBirth != null) + { + vec.Add(new DerTaggedObject(true, 2, placeOfBirth)); + } + if (gender != null) + { + vec.Add(new DerTaggedObject(false, 3, new DerPrintableString(gender, true))); + } + if (postalAddress != null) + { + vec.Add(new DerTaggedObject(true, 4, postalAddress)); + } + return new DerSequence(vec); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x509/sigi/SigIObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/x509/sigi/SigIObjectIdentifiers.cs new file mode 100644 index 0000000..682311a --- /dev/null +++ b/iTechSharp/srcbc/asn1/x509/sigi/SigIObjectIdentifiers.cs @@ -0,0 +1,49 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509.SigI +{ + /** + * Object Identifiers of SigI specifciation (German Signature Law + * Interoperability specification). + */ + public sealed class SigIObjectIdentifiers + { + private SigIObjectIdentifiers() + { + } + + public readonly static DerObjectIdentifier IdSigI = new DerObjectIdentifier("1.3.36.8"); + + /** + * Key purpose IDs for German SigI (Signature Interoperability + * Specification) + */ + public readonly static DerObjectIdentifier IdSigIKP = new DerObjectIdentifier(IdSigI + ".2"); + + /** + * Certificate policy IDs for German SigI (Signature Interoperability + * Specification) + */ + public readonly static DerObjectIdentifier IdSigICP = new DerObjectIdentifier(IdSigI + ".1"); + + /** + * Other Name IDs for German SigI (Signature Interoperability Specification) + */ + public readonly static DerObjectIdentifier IdSigION = new DerObjectIdentifier(IdSigI + ".4"); + + /** + * To be used for for the generation of directory service certificates. + */ + public static readonly DerObjectIdentifier IdSigIKPDirectoryService = new DerObjectIdentifier(IdSigIKP + ".1"); + + /** + * ID for PersonalData + */ + public static readonly DerObjectIdentifier IdSigIONPersonalData = new DerObjectIdentifier(IdSigION + ".1"); + + /** + * Certificate is conform to german signature law. + */ + public static readonly DerObjectIdentifier IdSigICPSigConform = new DerObjectIdentifier(IdSigICP + ".1"); + } +} diff --git a/iTechSharp/srcbc/asn1/x9/KeySpecificInfo.cs b/iTechSharp/srcbc/asn1/x9/KeySpecificInfo.cs new file mode 100644 index 0000000..4629864 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/KeySpecificInfo.cs @@ -0,0 +1,58 @@ +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See + * RFC 2631, or X9.42, for further details. + */ + public class KeySpecificInfo + : Asn1Encodable + { + private DerObjectIdentifier algorithm; + private Asn1OctetString counter; + + public KeySpecificInfo( + DerObjectIdentifier algorithm, + Asn1OctetString counter) + { + this.algorithm = algorithm; + this.counter = counter; + } + + public KeySpecificInfo( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + algorithm = (DerObjectIdentifier)e.Current; + e.MoveNext(); + counter = (Asn1OctetString)e.Current; + } + + public DerObjectIdentifier Algorithm + { + get { return algorithm; } + } + + public Asn1OctetString Counter + { + get { return counter; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  KeySpecificInfo ::= Sequence {
      +         *      algorithm OBJECT IDENTIFIER,
      +         *      counter OCTET STRING SIZE (4..4)
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(algorithm, counter); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/OtherInfo.cs b/iTechSharp/srcbc/asn1/x9/OtherInfo.cs new file mode 100644 index 0000000..21863bd --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/OtherInfo.cs @@ -0,0 +1,88 @@ +using System.Collections; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See + * RFC 2631, or X9.42, for further details. + */ + public class OtherInfo + : Asn1Encodable + { + private KeySpecificInfo keyInfo; + private Asn1OctetString partyAInfo; + private Asn1OctetString suppPubInfo; + + public OtherInfo( + KeySpecificInfo keyInfo, + Asn1OctetString partyAInfo, + Asn1OctetString suppPubInfo) + { + this.keyInfo = keyInfo; + this.partyAInfo = partyAInfo; + this.suppPubInfo = suppPubInfo; + } + + public OtherInfo( + Asn1Sequence seq) + { + IEnumerator e = seq.GetEnumerator(); + + e.MoveNext(); + keyInfo = new KeySpecificInfo((Asn1Sequence) e.Current); + + while (e.MoveNext()) + { + DerTaggedObject o = (DerTaggedObject) e.Current; + + if (o.TagNo == 0) + { + partyAInfo = (Asn1OctetString) o.GetObject(); + } + else if ((int) o.TagNo == 2) + { + suppPubInfo = (Asn1OctetString) o.GetObject(); + } + } + } + + public KeySpecificInfo KeyInfo + { + get { return keyInfo; } + } + + public Asn1OctetString PartyAInfo + { + get { return partyAInfo; } + } + + public Asn1OctetString SuppPubInfo + { + get { return suppPubInfo; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  OtherInfo ::= Sequence {
      +         *      keyInfo KeySpecificInfo,
      +         *      partyAInfo [0] OCTET STRING OPTIONAL,
      +         *      suppPubInfo [2] OCTET STRING
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(keyInfo); + + if (partyAInfo != null) + { + v.Add(new DerTaggedObject(0, partyAInfo)); + } + + v.Add(new DerTaggedObject(2, suppPubInfo)); + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X962NamedCurves.cs b/iTechSharp/srcbc/asn1/x9/X962NamedCurves.cs new file mode 100644 index 0000000..f12aafb --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X962NamedCurves.cs @@ -0,0 +1,732 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * table of the current named curves defined in X.962 EC-DSA. + */ + public sealed class X962NamedCurves + { + private X962NamedCurves() + { + } + + internal class Prime192v1Holder + : X9ECParametersHolder + { + private Prime192v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime192v1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp192v1 = new FpCurve( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); + + return new X9ECParameters( + cFp192v1, + cFp192v1.DecodePoint( + Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), + new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16), + BigInteger.One, + Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5")); + } + } + + internal class Prime192v2Holder + : X9ECParametersHolder + { + private Prime192v2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime192v2Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp192v2 = new FpCurve( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16)); + + return new X9ECParameters( + cFp192v2, + cFp192v2.DecodePoint( + Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")), + new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16), + BigInteger.One, + Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6")); + } + } + + internal class Prime192v3Holder + : X9ECParametersHolder + { + private Prime192v3Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime192v3Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp192v3 = new FpCurve( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16)); + + return new X9ECParameters( + cFp192v3, + cFp192v3.DecodePoint( + Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")), + new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16), + BigInteger.One, + Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e")); + } + } + + internal class Prime239v1Holder + : X9ECParametersHolder + { + private Prime239v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime239v1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp239v1 = new FpCurve( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); + + return new X9ECParameters( + cFp239v1, + cFp239v1.DecodePoint( + Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), + new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16), + BigInteger.One, + Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d")); + } + } + + internal class Prime239v2Holder + : X9ECParametersHolder + { + private Prime239v2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime239v2Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp239v2 = new FpCurve( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16)); + + return new X9ECParameters( + cFp239v2, + cFp239v2.DecodePoint( + Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")), + new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16), + BigInteger.One, + Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616")); + } + } + + internal class Prime239v3Holder + : X9ECParametersHolder + { + private Prime239v3Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime239v3Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp239v3 = new FpCurve( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16)); + + return new X9ECParameters( + cFp239v3, + cFp239v3.DecodePoint( + Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")), + new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16), + BigInteger.One, + Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff")); + } + } + + internal class Prime256v1Holder + : X9ECParametersHolder + { + private Prime256v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Prime256v1Holder(); + + protected override X9ECParameters CreateParameters() + { + ECCurve cFp256v1 = new FpCurve( + new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"), + new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16), + new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)); + + return new X9ECParameters( + cFp256v1, + cFp256v1.DecodePoint( + Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), + new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16), + BigInteger.One, + Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90")); + } + } + + /* + * F2m Curves + */ + internal class C2pnb163v1Holder + : X9ECParametersHolder + { + private C2pnb163v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb163v1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve c2m163v1 = new F2mCurve( + 163, + 1, 2, 8, + new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16), + new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16), + n, h); + + return new X9ECParameters( + c2m163v1, + c2m163v1.DecodePoint( + Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")), + n, h, + Hex.Decode("D2COFB15760860DEF1EEF4D696E6768756151754")); + } + } + + internal class C2pnb163v2Holder + : X9ECParametersHolder + { + private C2pnb163v2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb163v2Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve c2m163v2 = new F2mCurve( + 163, + 1, 2, 8, + new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16), + new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16), + n, h); + + return new X9ECParameters( + c2m163v2, + c2m163v2.DecodePoint( + Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")), + n, h, + null); + } + } + + internal class C2pnb163v3Holder + : X9ECParametersHolder + { + private C2pnb163v3Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb163v3Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve c2m163v3 = new F2mCurve( + 163, + 1, 2, 8, + new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16), + new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16), + n, h); + + return new X9ECParameters( + c2m163v3, + c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), + n, h, + null); + } + } + + internal class C2pnb176w1Holder + : X9ECParametersHolder + { + private C2pnb176w1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb176w1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16); + BigInteger h = BigInteger.ValueOf(0xFF6E); + + ECCurve c2m176w1 = new F2mCurve( + 176, + 1, 2, 43, + new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16), + new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16), + n, h); + + return new X9ECParameters( + c2m176w1, + c2m176w1.DecodePoint( + Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")), + n, h, + null); + } + } + + internal class C2tnb191v1Holder + : X9ECParametersHolder + { + private C2tnb191v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb191v1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16); + BigInteger h = BigInteger.ValueOf(2); + + ECCurve c2m191v1 = new F2mCurve( + 191, + 9, + new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), + new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16), + n, h); + + return new X9ECParameters( + c2m191v1, + c2m191v1.DecodePoint( + Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")), + n, h, + Hex.Decode("4E13CA542744D696E67687561517552F279A8C84")); + } + } + + internal class C2tnb191v2Holder + : X9ECParametersHolder + { + private C2tnb191v2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb191v2Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve c2m191v2 = new F2mCurve( + 191, + 9, + new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16), + new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16), + n, h); + + return new X9ECParameters( + c2m191v2, + c2m191v2.DecodePoint( + Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")), + n, h, + null); + } + } + + internal class C2tnb191v3Holder + : X9ECParametersHolder + { + private C2tnb191v3Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb191v3Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16); + BigInteger h = BigInteger.ValueOf(6); + + ECCurve c2m191v3 = new F2mCurve( + 191, + 9, + new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16), + new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16), + n, h); + + return new X9ECParameters( + c2m191v3, + c2m191v3.DecodePoint( + Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")), + n, h, + null); + } + } + + internal class C2pnb208w1Holder + : X9ECParametersHolder + { + private C2pnb208w1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb208w1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16); + BigInteger h = BigInteger.ValueOf(0xFE48); + + ECCurve c2m208w1 = new F2mCurve( + 208, + 1, 2, 83, + new BigInteger("0", 16), + new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16), + n, h); + + return new X9ECParameters( + c2m208w1, + c2m208w1.DecodePoint( + Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")), + n, h, + null); + } + } + + internal class C2tnb239v1Holder + : X9ECParametersHolder + { + private C2tnb239v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb239v1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16); + BigInteger h = BigInteger.ValueOf(4); + + ECCurve c2m239v1 = new F2mCurve( + 239, + 36, + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), + n, h); + + return new X9ECParameters( + c2m239v1, + c2m239v1.DecodePoint( + Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")), + n, h, + null); + } + } + + internal class C2tnb239v2Holder + : X9ECParametersHolder + { + private C2tnb239v2Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb239v2Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16); + BigInteger h = BigInteger.ValueOf(6); + + ECCurve c2m239v2 = new F2mCurve( + 239, + 36, + new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16), + new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16), + n, h); + + return new X9ECParameters( + c2m239v2, + c2m239v2.DecodePoint( + Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")), + n, h, + null); + } + } + + internal class C2tnb239v3Holder + : X9ECParametersHolder + { + private C2tnb239v3Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb239v3Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16); + BigInteger h = BigInteger.ValueOf(10); + + ECCurve c2m239v3 = new F2mCurve( + 239, + 36, + new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16), + new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16), + n, h); + + return new X9ECParameters( + c2m239v3, + c2m239v3.DecodePoint( + Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")), + n, h, + null); + } + } + + internal class C2pnb272w1Holder + : X9ECParametersHolder + { + private C2pnb272w1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb272w1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16); + BigInteger h = BigInteger.ValueOf(0xFF06); + + ECCurve c2m272w1 = new F2mCurve( + 272, + 1, 3, 56, + new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16), + new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16), + n, h); + + return new X9ECParameters( + c2m272w1, + c2m272w1.DecodePoint( + Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")), + n, h, + null); + } + } + + internal class C2pnb304w1Holder + : X9ECParametersHolder + { + private C2pnb304w1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb304w1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16); + BigInteger h = BigInteger.ValueOf(0xFE2E); + + ECCurve c2m304w1 = new F2mCurve( + 304, + 1, 2, 11, + new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16), + new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16), + n, h); + + return new X9ECParameters( + c2m304w1, + c2m304w1.DecodePoint( + Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")), + n, h, + null); + } + } + + internal class C2tnb359v1Holder + : X9ECParametersHolder + { + private C2tnb359v1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb359v1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16); + BigInteger h = BigInteger.ValueOf(0x4C); + + ECCurve c2m359v1 = new F2mCurve( + 359, + 68, + new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16), + new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16), + n, h); + + return new X9ECParameters( + c2m359v1, + c2m359v1.DecodePoint( + Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")), + n, h, + null); + } + } + + internal class C2pnb368w1Holder + : X9ECParametersHolder + { + private C2pnb368w1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2pnb368w1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16); + BigInteger h = BigInteger.ValueOf(0xFF70); + + ECCurve c2m368w1 = new F2mCurve( + 368, + 1, 2, 85, + new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16), + new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16), + n, h); + + return new X9ECParameters( + c2m368w1, + c2m368w1.DecodePoint( + Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")), + n, h, + null); + } + } + + internal class C2tnb431r1Holder + : X9ECParametersHolder + { + private C2tnb431r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new C2tnb431r1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16); + BigInteger h = BigInteger.ValueOf(0x2760); + + ECCurve c2m431r1 = new F2mCurve( + 431, + 120, + new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16), + new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16), + n, h); + + return new X9ECParameters( + c2m431r1, + c2m431r1.DecodePoint( + Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")), + n, h, + null); + } + } + + private static readonly Hashtable objIds = new Hashtable(); + private static readonly Hashtable curves = new Hashtable(); + private static readonly Hashtable names = new Hashtable(); + + private static void DefineCurve( + string name, + DerObjectIdentifier oid, + X9ECParametersHolder holder) + { + objIds.Add(name, oid); + names.Add(oid, name); + curves.Add(oid, holder); + } + + static X962NamedCurves() + { + DefineCurve("prime192v1", X9ObjectIdentifiers.Prime192v1, Prime192v1Holder.Instance); + DefineCurve("prime192v2", X9ObjectIdentifiers.Prime192v2, Prime192v2Holder.Instance); + DefineCurve("prime192v3", X9ObjectIdentifiers.Prime192v3, Prime192v3Holder.Instance); + DefineCurve("prime239v1", X9ObjectIdentifiers.Prime239v1, Prime239v1Holder.Instance); + DefineCurve("prime239v2", X9ObjectIdentifiers.Prime239v2, Prime239v2Holder.Instance); + DefineCurve("prime239v3", X9ObjectIdentifiers.Prime239v3, Prime239v3Holder.Instance); + DefineCurve("prime256v1", X9ObjectIdentifiers.Prime256v1, Prime256v1Holder.Instance); + DefineCurve("c2pnb163v1", X9ObjectIdentifiers.C2Pnb163v1, C2pnb163v1Holder.Instance); + DefineCurve("c2pnb163v2", X9ObjectIdentifiers.C2Pnb163v2, C2pnb163v2Holder.Instance); + DefineCurve("c2pnb163v3", X9ObjectIdentifiers.C2Pnb163v3, C2pnb163v3Holder.Instance); + DefineCurve("c2pnb176w1", X9ObjectIdentifiers.C2Pnb176w1, C2pnb176w1Holder.Instance); + DefineCurve("c2tnb191v1", X9ObjectIdentifiers.C2Tnb191v1, C2tnb191v1Holder.Instance); + DefineCurve("c2tnb191v2", X9ObjectIdentifiers.C2Tnb191v2, C2tnb191v2Holder.Instance); + DefineCurve("c2tnb191v3", X9ObjectIdentifiers.C2Tnb191v3, C2tnb191v3Holder.Instance); + DefineCurve("c2pnb208w1", X9ObjectIdentifiers.C2Pnb208w1, C2pnb208w1Holder.Instance); + DefineCurve("c2tnb239v1", X9ObjectIdentifiers.C2Tnb239v1, C2tnb239v1Holder.Instance); + DefineCurve("c2tnb239v2", X9ObjectIdentifiers.C2Tnb239v2, C2tnb239v2Holder.Instance); + DefineCurve("c2tnb239v3", X9ObjectIdentifiers.C2Tnb239v3, C2tnb239v3Holder.Instance); + DefineCurve("c2pnb272w1", X9ObjectIdentifiers.C2Pnb272w1, C2pnb272w1Holder.Instance); + DefineCurve("c2pnb304w1", X9ObjectIdentifiers.C2Pnb304w1, C2pnb304w1Holder.Instance); + DefineCurve("c2tnb359v1", X9ObjectIdentifiers.C2Tnb359v1, C2tnb359v1Holder.Instance); + DefineCurve("c2pnb368w1", X9ObjectIdentifiers.C2Pnb368w1, C2pnb368w1Holder.Instance); + DefineCurve("c2tnb431r1", X9ObjectIdentifiers.C2Tnb431r1, C2tnb431r1Holder.Instance); + } + + public static X9ECParameters GetByName( + string name) + { + DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToLower(CultureInfo.InvariantCulture)]; + + return oid == null ? null : GetByOid(oid); + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters GetByOid( + DerObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid]; + + return holder == null ? null : holder.Parameters; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier) objIds[name.ToLower(CultureInfo.InvariantCulture)]; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string) names[oid]; + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(objIds.Keys); } + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X962Parameters.cs b/iTechSharp/srcbc/asn1/x9/X962Parameters.cs new file mode 100644 index 0000000..0b0faee --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X962Parameters.cs @@ -0,0 +1,53 @@ +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X9 +{ + public class X962Parameters + : Asn1Encodable + { + private readonly Asn1Object _params; + + public X962Parameters( + X9ECParameters ecParameters) + { + this._params = ecParameters.ToAsn1Object(); + } + + public X962Parameters( + DerObjectIdentifier namedCurve) + { + this._params = namedCurve; + } + + public X962Parameters( + Asn1Object obj) + { + this._params = obj; + } + + public bool IsNamedCurve + { + get { return (_params is DerObjectIdentifier); } + } + + public Asn1Object Parameters + { + get { return _params; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         * Parameters ::= CHOICE {
      +         *    ecParameters ECParameters,
      +         *    namedCurve   CURVES.&id({CurveNames}),
      +         *    implicitlyCA Null
      +         * }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return _params; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9Curve.cs b/iTechSharp/srcbc/asn1/x9/X9Curve.cs new file mode 100644 index 0000000..b92e7b3 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9Curve.cs @@ -0,0 +1,147 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * ASN.1 def for Elliptic-Curve Curve structure. See + * X9.62, for further details. + */ + public class X9Curve + : Asn1Encodable + { + private readonly ECCurve curve; + private readonly byte[] seed; + private readonly DerObjectIdentifier fieldIdentifier; + + public X9Curve( + ECCurve curve) + : this(curve, null) + { + this.curve = curve; + } + + public X9Curve( + ECCurve curve, + byte[] seed) + { + if (curve == null) + throw new ArgumentNullException("curve"); + + this.curve = curve; + this.seed = Arrays.Clone(seed); + + if (curve is FpCurve) + { + this.fieldIdentifier = X9ObjectIdentifiers.PrimeField; + } + else if (curve is F2mCurve) + { + this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField; + } + else + { + throw new ArgumentException("This type of ECCurve is not implemented"); + } + } + + public X9Curve( + X9FieldID fieldID, + Asn1Sequence seq) + { + if (fieldID == null) + throw new ArgumentNullException("fieldID"); + if (seq == null) + throw new ArgumentNullException("seq"); + + this.fieldIdentifier = fieldID.Identifier; + + if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)) + { + BigInteger q = ((DerInteger) fieldID.Parameters).Value; + X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]); + X9FieldElement x9B = new X9FieldElement(q, (Asn1OctetString) seq[1]); + curve = new FpCurve(q, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger()); + } + else + { + if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) + { + // Characteristic two field + DerSequence parameters = (DerSequence)fieldID.Parameters; + int m = ((DerInteger)parameters[0]).Value.IntValue; + DerObjectIdentifier representation + = (DerObjectIdentifier)parameters[1]; + + int k1 = 0; + int k2 = 0; + int k3 = 0; + if (representation.Equals(X9ObjectIdentifiers.TPBasis)) + { + // Trinomial basis representation + k1 = ((DerInteger)parameters[2]).Value.IntValue; + } + else + { + // Pentanomial basis representation + DerSequence pentanomial = (DerSequence) parameters[2]; + k1 = ((DerInteger) pentanomial[0]).Value.IntValue; + k2 = ((DerInteger) pentanomial[1]).Value.IntValue; + k3 = ((DerInteger) pentanomial[2]).Value.IntValue; + } + X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]); + X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]); + // TODO Is it possible to get the order (n) and cofactor(h) too? + curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger()); + } + } + + if (seq.Count == 3) + { + seed = ((DerBitString) seq[2]).GetBytes(); + } + } + + public ECCurve Curve + { + get { return curve; } + } + + public byte[] GetSeed() + { + return Arrays.Clone(seed); + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  Curve ::= Sequence {
      +         *      a               FieldElement,
      +         *      b               FieldElement,
      +         *      seed            BIT STRING      OPTIONAL
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField) + || fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) + { + v.Add(new X9FieldElement(curve.A).ToAsn1Object()); + v.Add(new X9FieldElement(curve.B).ToAsn1Object()); + } + + if (seed != null) + { + v.Add(new DerBitString(seed)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9ECParameters.cs b/iTechSharp/srcbc/asn1/x9/X9ECParameters.cs new file mode 100644 index 0000000..b4b1afb --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9ECParameters.cs @@ -0,0 +1,165 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * ASN.1 def for Elliptic-Curve ECParameters structure. See + * X9.62, for further details. + */ + public class X9ECParameters + : Asn1Encodable + { + private X9FieldID fieldID; + private ECCurve curve; + private ECPoint g; + private BigInteger n; + private BigInteger h; + private byte[] seed; + + public X9ECParameters( + Asn1Sequence seq) + { + if (!(seq[0] is DerInteger) + || !((DerInteger) seq[0]).Value.Equals(BigInteger.One)) + { + throw new ArgumentException("bad version in X9ECParameters"); + } + + X9Curve x9c = null; + if (seq[2] is X9Curve) + { + x9c = (X9Curve) seq[2]; + } + else + { + x9c = new X9Curve( + new X9FieldID( + (Asn1Sequence) seq[1]), + (Asn1Sequence) seq[2]); + } + + this.curve = x9c.Curve; + + if (seq[3] is X9ECPoint) + { + this.g = ((X9ECPoint) seq[3]).Point; + } + else + { + this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point; + } + + this.n = ((DerInteger) seq[4]).Value; + this.seed = x9c.GetSeed(); + + if (seq.Count == 6) + { + this.h = ((DerInteger) seq[5]).Value; + } + else + { + this.h = BigInteger.One; + } + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n) + : this(curve, g, n, BigInteger.One, null) + { + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h) + : this(curve, g, n, h, null) + { + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + { + this.curve = curve; + this.g = g; + this.n = n; + this.h = h; + this.seed = seed; + + if (curve is FpCurve) + { + this.fieldID = new X9FieldID(((FpCurve) curve).Q); + } + else if (curve is F2mCurve) + { + F2mCurve curveF2m = (F2mCurve) curve; + this.fieldID = new X9FieldID(curveF2m.M, curveF2m.K1, + curveF2m.K2, curveF2m.K3); + } + } + + public ECCurve Curve + { + get { return curve; } + } + + public ECPoint G + { + get { return g; } + } + + public BigInteger N + { + get { return n; } + } + + public BigInteger H + { + get { return h; } + } + + public byte[] GetSeed() + { + return seed; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  ECParameters ::= Sequence {
      +         *      version         Integer { ecpVer1(1) } (ecpVer1),
      +         *      fieldID         FieldID {{FieldTypes}},
      +         *      curve           X9Curve,
      +         *      base            X9ECPoint,
      +         *      order           Integer,
      +         *      cofactor        Integer OPTIONAL
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + new DerInteger(1), + fieldID, + new X9Curve(curve, seed), + new X9ECPoint(g), + new DerInteger(n)); + + if (!h.Equals(BigInteger.One)) + { + v.Add(new DerInteger(h)); + } + + return new DerSequence(v); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9ECParametersHolder.cs b/iTechSharp/srcbc/asn1/x9/X9ECParametersHolder.cs new file mode 100644 index 0000000..b345570 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9ECParametersHolder.cs @@ -0,0 +1,22 @@ +namespace Org.BouncyCastle.Asn1.X9 +{ + public abstract class X9ECParametersHolder + { + private X9ECParameters parameters; + + public X9ECParameters Parameters + { + get + { + if (parameters == null) + { + parameters = CreateParameters(); + } + + return parameters; + } + } + + protected abstract X9ECParameters CreateParameters(); + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9ECPoint.cs b/iTechSharp/srcbc/asn1/x9/X9ECPoint.cs new file mode 100644 index 0000000..ba2b2bc --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9ECPoint.cs @@ -0,0 +1,44 @@ +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * class for describing an ECPoint as a Der object. + */ + public class X9ECPoint + : Asn1Encodable + { + private readonly ECPoint p; + + public X9ECPoint( + ECPoint p) + { + this.p = p; + } + + public X9ECPoint( + ECCurve c, + Asn1OctetString s) + { + this.p = c.DecodePoint(s.GetOctets()); + } + + public ECPoint Point + { + get { return p; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +         *  ECPoint ::= OCTET STRING
      +         * 
      + *

      + * Octet string produced using ECPoint.GetEncoded().

      + */ + public override Asn1Object ToAsn1Object() + { + return new DerOctetString(p.GetEncoded()); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9FieldElement.cs b/iTechSharp/srcbc/asn1/x9/X9FieldElement.cs new file mode 100644 index 0000000..12e263e --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9FieldElement.cs @@ -0,0 +1,69 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * class for processing an FieldElement as a Der object. + */ + public class X9FieldElement + : Asn1Encodable + { + private ECFieldElement f; + + public X9FieldElement( + ECFieldElement f) + { + this.f = f; + } + + public X9FieldElement( + BigInteger p, + Asn1OctetString s) + : this(new FpFieldElement(p, new BigInteger(1, s.GetOctets()))) + { + } + + public X9FieldElement( + int m, + int k1, + int k2, + int k3, + Asn1OctetString s) + : this(new F2mFieldElement(m, k1, k2, k3, new BigInteger(1, s.GetOctets()))) + { + } + + public ECFieldElement Value + { + get { return f; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
      +		 *  FieldElement ::= OCTET STRING
      +		 * 
      + *

      + *

        + *
      1. if q is an odd prime then the field element is + * processed as an Integer and converted to an octet string + * according to x 9.62 4.3.1.
      2. + *
      3. if q is 2m then the bit string + * contained in the field element is converted into an octet + * string with the same ordering padded at the front if necessary. + *
      4. + *
      + *

      + */ + public override Asn1Object ToAsn1Object() + { + int byteCount = X9IntegerConverter.GetByteLength(f); + byte[] paddedBigInteger = X9IntegerConverter.IntegerToBytes(f.ToBigInteger(), byteCount); + + return new DerOctetString(paddedBigInteger); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9FieldID.cs b/iTechSharp/srcbc/asn1/x9/X9FieldID.cs new file mode 100644 index 0000000..c51cc4d --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9FieldID.cs @@ -0,0 +1,102 @@ +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * ASN.1 def for Elliptic-Curve Field ID structure. See + * X9.62, for further details. + */ + public class X9FieldID + : Asn1Encodable + { + private readonly DerObjectIdentifier id; + private readonly Asn1Object parameters; + + /** + * Constructor for elliptic curves over prime fields + * F2. + * @param primeP The prime p defining the prime field. + */ + public X9FieldID( + BigInteger primeP) + { + this.id = X9ObjectIdentifiers.PrimeField; + this.parameters = new DerInteger(primeP); + } + + /** + * Constructor for elliptic curves over binary fields + * F2m. + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).. + */ + public X9FieldID( + int m, + int k1, + int k2, + int k3) + { + this.id = X9ObjectIdentifiers.CharacteristicTwoField; + + Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m)); + + if (k2 == 0) + { + fieldIdParams.Add( + X9ObjectIdentifiers.TPBasis, + new DerInteger(k1)); + } + else + { + fieldIdParams.Add( + X9ObjectIdentifiers.PPBasis, + new DerSequence( + new DerInteger(k1), + new DerInteger(k2), + new DerInteger(k3))); + } + + this.parameters = new DerSequence(fieldIdParams); + } + + internal X9FieldID( + Asn1Sequence seq) + { + this.id = (DerObjectIdentifier) seq[0]; + this.parameters = (Asn1Object) seq[1]; + } + + public DerObjectIdentifier Identifier + { + get { return id; } + } + + public Asn1Object Parameters + { + get { return parameters; } + } + + /** + * Produce a Der encoding of the following structure. + *
      +         *  FieldID ::= Sequence {
      +         *      fieldType       FIELD-ID.&id({IOSet}),
      +         *      parameters      FIELD-ID.&Type({IOSet}{@fieldType})
      +         *  }
      +         * 
      + */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(id, parameters); + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9IntegerConverter.cs b/iTechSharp/srcbc/asn1/x9/X9IntegerConverter.cs new file mode 100644 index 0000000..6a19ded --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9IntegerConverter.cs @@ -0,0 +1,46 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Asn1.X9 +{ + public sealed class X9IntegerConverter + { + private X9IntegerConverter() + { + } + + public static int GetByteLength( + ECFieldElement fe) + { + return (fe.FieldSize + 7) / 8; + } + + public static int GetByteLength( + ECCurve c) + { + return (c.FieldSize + 7) / 8; + } + + public static byte[] IntegerToBytes( + BigInteger s, + int qLength) + { + // TODO Add methods to allow writing BigInteger to existing byte array? + byte[] bytes = s.ToByteArrayUnsigned(); + + if (bytes.Length > qLength) + throw new ArgumentException("s does not fit in specified number of bytes", "s"); + + if (qLength > bytes.Length) + { + byte[] tmp = new byte[qLength]; + Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length); + return tmp; + } + + return bytes; + } + } +} diff --git a/iTechSharp/srcbc/asn1/x9/X9ObjectIdentifiers.cs b/iTechSharp/srcbc/asn1/x9/X9ObjectIdentifiers.cs new file mode 100644 index 0000000..26520c9 --- /dev/null +++ b/iTechSharp/srcbc/asn1/x9/X9ObjectIdentifiers.cs @@ -0,0 +1,132 @@ +namespace Org.BouncyCastle.Asn1.X9 +{ + public abstract class X9ObjectIdentifiers + { + // + // X9.62 + // + // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x962(10045) } + // + internal const string AnsiX962 = "1.2.840.10045"; + internal const string IdFieldType = AnsiX962 + ".1"; + + public static readonly DerObjectIdentifier PrimeField + = new DerObjectIdentifier(IdFieldType + ".1"); + + public static readonly DerObjectIdentifier CharacteristicTwoField + = new DerObjectIdentifier(IdFieldType + ".2"); + + public static readonly DerObjectIdentifier GNBasis + = new DerObjectIdentifier(IdFieldType + ".2.3.1"); + + public static readonly DerObjectIdentifier TPBasis + = new DerObjectIdentifier(IdFieldType + ".2.3.2"); + + public static readonly DerObjectIdentifier PPBasis + = new DerObjectIdentifier(IdFieldType + ".2.3.3"); + + public const string IdECSigType = AnsiX962 + ".4"; + + public static readonly DerObjectIdentifier ECDsaWithSha1 + = new DerObjectIdentifier(IdECSigType + ".1"); + + public const string IdPublicKeyType = AnsiX962 + ".2"; + + public static readonly DerObjectIdentifier IdECPublicKey + = new DerObjectIdentifier(IdPublicKeyType + ".1"); + + public static readonly DerObjectIdentifier ECDsaWithSha2 = new DerObjectIdentifier(IdECSigType + ".3"); + public static readonly DerObjectIdentifier ECDsaWithSha224 = new DerObjectIdentifier(ECDsaWithSha2 + ".1"); + public static readonly DerObjectIdentifier ECDsaWithSha256 = new DerObjectIdentifier(ECDsaWithSha2 + ".2"); + public static readonly DerObjectIdentifier ECDsaWithSha384 = new DerObjectIdentifier(ECDsaWithSha2 + ".3"); + public static readonly DerObjectIdentifier ECDsaWithSha512 = new DerObjectIdentifier(ECDsaWithSha2 + ".4"); + + + // + // named curves + // + public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(AnsiX962 + ".3"); + + // + // Two Curves + // + public static readonly DerObjectIdentifier CTwoCurve = new DerObjectIdentifier(EllipticCurve + ".0"); + + public static readonly DerObjectIdentifier C2Pnb163v1 = new DerObjectIdentifier(CTwoCurve + ".1"); + public static readonly DerObjectIdentifier C2Pnb163v2 = new DerObjectIdentifier(CTwoCurve + ".2"); + public static readonly DerObjectIdentifier C2Pnb163v3 = new DerObjectIdentifier(CTwoCurve + ".3"); + public static readonly DerObjectIdentifier C2Pnb176w1 = new DerObjectIdentifier(CTwoCurve + ".4"); + public static readonly DerObjectIdentifier C2Tnb191v1 = new DerObjectIdentifier(CTwoCurve + ".5"); + public static readonly DerObjectIdentifier C2Tnb191v2 = new DerObjectIdentifier(CTwoCurve + ".6"); + public static readonly DerObjectIdentifier C2Tnb191v3 = new DerObjectIdentifier(CTwoCurve + ".7"); + public static readonly DerObjectIdentifier C2Onb191v4 = new DerObjectIdentifier(CTwoCurve + ".8"); + public static readonly DerObjectIdentifier C2Onb191v5 = new DerObjectIdentifier(CTwoCurve + ".9"); + public static readonly DerObjectIdentifier C2Pnb208w1 = new DerObjectIdentifier(CTwoCurve + ".10"); + public static readonly DerObjectIdentifier C2Tnb239v1 = new DerObjectIdentifier(CTwoCurve + ".11"); + public static readonly DerObjectIdentifier C2Tnb239v2 = new DerObjectIdentifier(CTwoCurve + ".12"); + public static readonly DerObjectIdentifier C2Tnb239v3 = new DerObjectIdentifier(CTwoCurve + ".13"); + public static readonly DerObjectIdentifier C2Onb239v4 = new DerObjectIdentifier(CTwoCurve + ".14"); + public static readonly DerObjectIdentifier C2Onb239v5 = new DerObjectIdentifier(CTwoCurve + ".15"); + public static readonly DerObjectIdentifier C2Pnb272w1 = new DerObjectIdentifier(CTwoCurve + ".16"); + public static readonly DerObjectIdentifier C2Pnb304w1 = new DerObjectIdentifier(CTwoCurve + ".17"); + public static readonly DerObjectIdentifier C2Tnb359v1 = new DerObjectIdentifier(CTwoCurve + ".18"); + public static readonly DerObjectIdentifier C2Pnb368w1 = new DerObjectIdentifier(CTwoCurve + ".19"); + public static readonly DerObjectIdentifier C2Tnb431r1 = new DerObjectIdentifier(CTwoCurve + ".20"); + + // + // Prime + // + public static readonly DerObjectIdentifier PrimeCurve = new DerObjectIdentifier(EllipticCurve + ".1"); + + public static readonly DerObjectIdentifier Prime192v1 = new DerObjectIdentifier(PrimeCurve + ".1"); + public static readonly DerObjectIdentifier Prime192v2 = new DerObjectIdentifier(PrimeCurve + ".2"); + public static readonly DerObjectIdentifier Prime192v3 = new DerObjectIdentifier(PrimeCurve + ".3"); + public static readonly DerObjectIdentifier Prime239v1 = new DerObjectIdentifier(PrimeCurve + ".4"); + public static readonly DerObjectIdentifier Prime239v2 = new DerObjectIdentifier(PrimeCurve + ".5"); + public static readonly DerObjectIdentifier Prime239v3 = new DerObjectIdentifier(PrimeCurve + ".6"); + public static readonly DerObjectIdentifier Prime256v1 = new DerObjectIdentifier(PrimeCurve + ".7"); + + // + // Diffie-Hellman + // + // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x942(10046) number-type(2) 1 } + // + public static readonly DerObjectIdentifier DHPublicNumber = new DerObjectIdentifier("1.2.840.10046.2.1"); + + // + // DSA + // + // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x957(10040) number-type(4) 1 } + public static readonly DerObjectIdentifier IdDsa = new DerObjectIdentifier("1.2.840.10040.4.1"); + + /** + * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + * us(840) x9-57 (10040) x9cm(4) 3 } + */ + public static readonly DerObjectIdentifier IdDsaWithSha1 = new DerObjectIdentifier("1.2.840.10040.4.3"); + + /** + * X9.63 + */ + public static readonly DerObjectIdentifier X9x63Scheme = new DerObjectIdentifier("1.3.133.16.840.63.0"); + public static readonly DerObjectIdentifier DHSinglePassStdDHSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".2"); + public static readonly DerObjectIdentifier DHSinglePassCofactorDHSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".3"); + public static readonly DerObjectIdentifier MqvSinglePassSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".16"); + + /** + * X9.42 + */ + public static readonly DerObjectIdentifier X9x42Schemes = new DerObjectIdentifier("1.2.840.10046.3"); + public static readonly DerObjectIdentifier DHStatic = new DerObjectIdentifier(X9x42Schemes + ".1"); + public static readonly DerObjectIdentifier DHEphem = new DerObjectIdentifier(X9x42Schemes + ".2"); + public static readonly DerObjectIdentifier DHOneFlow = new DerObjectIdentifier(X9x42Schemes + ".3"); + public static readonly DerObjectIdentifier DHHybrid1 = new DerObjectIdentifier(X9x42Schemes + ".4"); + public static readonly DerObjectIdentifier DHHybrid2 = new DerObjectIdentifier(X9x42Schemes + ".5"); + public static readonly DerObjectIdentifier DHHybridOneFlow = new DerObjectIdentifier(X9x42Schemes + ".6"); + public static readonly DerObjectIdentifier Mqv2 = new DerObjectIdentifier(X9x42Schemes + ".7"); + public static readonly DerObjectIdentifier Mqv1 = new DerObjectIdentifier(X9x42Schemes + ".8"); + } +} diff --git a/iTechSharp/srcbc/bcpg/ArmoredInputStream.cs b/iTechSharp/srcbc/bcpg/ArmoredInputStream.cs new file mode 100644 index 0000000..fc89b9f --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ArmoredInputStream.cs @@ -0,0 +1,492 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * reader for Base64 armored objects - read the headers and then start returning + * bytes when the data is reached. An IOException is thrown if the CRC check + * fails. + */ + public class ArmoredInputStream + : BaseInputStream + { + /* + * set up the decoding table. + */ + private readonly static byte[] decodingTable; + static ArmoredInputStream() + { + decodingTable = new byte[128]; + for (int i = 'A'; i <= 'Z'; i++) + { + decodingTable[i] = (byte)(i - 'A'); + } + for (int i = 'a'; i <= 'z'; i++) + { + decodingTable[i] = (byte)(i - 'a' + 26); + } + for (int i = '0'; i <= '9'; i++) + { + decodingTable[i] = (byte)(i - '0' + 52); + } + decodingTable['+'] = 62; + decodingTable['/'] = 63; + } + + /** + * decode the base 64 encoded input data. + * + * @return the offset the data starts in out. + */ + private int Decode( + int in0, + int in1, + int in2, + int in3, + int[] result) + { + if (in3 < 0) + { + throw new EndOfStreamException("unexpected end of file in armored stream."); + } + + int b1, b2, b3, b4; + if (in2 == '=') + { + b1 = decodingTable[in0] &0xff; + b2 = decodingTable[in1] & 0xff; + result[2] = ((b1 << 2) | (b2 >> 4)) & 0xff; + return 2; + } + else if (in3 == '=') + { + b1 = decodingTable[in0]; + b2 = decodingTable[in1]; + b3 = decodingTable[in2]; + result[1] = ((b1 << 2) | (b2 >> 4)) & 0xff; + result[2] = ((b2 << 4) | (b3 >> 2)) & 0xff; + return 1; + } + else + { + b1 = decodingTable[in0]; + b2 = decodingTable[in1]; + b3 = decodingTable[in2]; + b4 = decodingTable[in3]; + result[0] = ((b1 << 2) | (b2 >> 4)) & 0xff; + result[1] = ((b2 << 4) | (b3 >> 2)) & 0xff; + result[2] = ((b3 << 6) | b4) & 0xff; + return 0; + } + } + + Stream input; + bool start = true; + int[] outBuf = new int[3]; + int bufPtr = 3; + Crc24 crc = new Crc24(); + bool crcFound = false; + bool hasHeaders = true; + string header = null; + bool newLineFound = false; + bool clearText = false; + bool restart = false; + ArrayList headerList= new ArrayList(); + int lastC = 0; + + /** + * Create a stream for reading a PGP armoured message, parsing up to a header + * and then reading the data that follows. + * + * @param input + */ + public ArmoredInputStream( + Stream input) + : this(input, true) + { + } + + /** + * Create an armoured input stream which will assume the data starts + * straight away, or parse for headers first depending on the value of + * hasHeaders. + * + * @param input + * @param hasHeaders true if headers are to be looked for, false otherwise. + */ + public ArmoredInputStream( + Stream input, + bool hasHeaders) + { + this.input = input; + this.hasHeaders = hasHeaders; + + if (hasHeaders) + { + ParseHeaders(); + } + + start = false; + } + + private bool ParseHeaders() + { + header = null; + + int c; + int last = 0; + bool headerFound = false; + + headerList = new ArrayList(); + + // + // if restart we already have a header + // + if (restart) + { + headerFound = true; + } + else + { + while ((c = input.ReadByte()) >= 0) + { + if (c == '-' && (last == 0 || last == '\n' || last == '\r')) + { + headerFound = true; + break; + } + + last = c; + } + } + + if (headerFound) + { + StringBuilder Buffer = new StringBuilder("-"); + bool eolReached = false; + bool crLf = false; + + if (restart) // we've had to look ahead two '-' + { + Buffer.Append('-'); + } + + while ((c = input.ReadByte()) >= 0) + { + if (last == '\r' && c == '\n') + { + crLf = true; + } + if (eolReached && (last != '\r' && c == '\n')) + { + break; + } + if (eolReached && c == '\r') + { + break; + } + if (c == '\r' || (last != '\r' && c == '\n')) + { + string line = Buffer.ToString(); + if (line.Trim().Length < 1) + break; + headerList.Add(line); + Buffer.Length = 0; + } + + if (c != '\n' && c != '\r') + { + Buffer.Append((char)c); + eolReached = false; + } + else + { + if (c == '\r' || (last != '\r' && c == '\n')) + { + eolReached = true; + } + } + + last = c; + } + + if (crLf) + { + input.ReadByte(); // skip last \n + } + } + + if (headerList.Count > 0) + { + header = (string) headerList[0]; + } + + clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header); + newLineFound = true; + + return headerFound; + } + + /** + * @return true if we are inside the clear text section of a PGP + * signed message. + */ + public bool IsClearText() + { + return clearText; + } + + /** + * Return the armor header line (if there is one) + * @return the armor header line, null if none present. + */ + public string GetArmorHeaderLine() + { + return header; + } + + /** + * Return the armor headers (the lines after the armor header line), + * @return an array of armor headers, null if there aren't any. + */ + public string[] GetArmorHeaders() + { + if (headerList.Count <= 1) + { + return null; + } + + string[] hdrs = new string[headerList.Count - 1]; + for (int i = 0; i != hdrs.Length; i++) + { + hdrs[i] = (string) headerList[i + 1]; + } + + return hdrs; + } + + private int ReadIgnoreSpace() + { + int c; + do + { + c = input.ReadByte(); + } + while (c == ' ' || c == '\t'); + + return c; + } + + private int ReadIgnoreWhitespace() + { + int c; + do + { + c = input.ReadByte(); + } + while (c == ' ' || c == '\t' || c == '\r' || c == '\n'); + + return c; + } + + private int ReadByteClearText() + { + int c = input.ReadByte(); + + if (c == '\r' || (c == '\n' && lastC != '\r')) + { + newLineFound = true; + } + else if (newLineFound && c == '-') + { + c = input.ReadByte(); + if (c == '-') // a header, not dash escaped + { + clearText = false; + start = true; + restart = true; + } + else // a space - must be a dash escape + { + c = input.ReadByte(); + } + newLineFound = false; + } + else + { + if (c != '\n' && lastC != '\r') + { + newLineFound = false; + } + } + + lastC = c; + + return c; + } + + private int ReadClearText(byte[] buffer, int offset, int count) + { + int pos = offset; + try + { + int end = offset + count; + while (pos < end) + { + int c = ReadByteClearText(); + if (c == -1) + { + break; + } + buffer[pos++] = (byte) c; + } + } + catch (IOException ioe) + { + if (pos == offset) throw ioe; + } + + return pos - offset; + } + + private int DoReadByte() + { + if (bufPtr > 2 || crcFound) + { + int c = ReadIgnoreSpace(); + if (c == '\n' || c == '\r') + { + c = ReadIgnoreWhitespace(); + if (c == '=') // crc reached + { + bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf); + + if (bufPtr != 0) + { + throw new IOException("no crc found in armored message."); + } + + crcFound = true; + + int i = ((outBuf[0] & 0xff) << 16) + | ((outBuf[1] & 0xff) << 8) + | (outBuf[2] & 0xff); + + if (i != crc.Value) + { + throw new IOException("crc check failed in armored message."); + } + + return ReadByte(); + } + + if (c == '-') // end of record reached + { + while ((c = input.ReadByte()) >= 0) + { + if (c == '\n' || c == '\r') + { + break; + } + } + + if (!crcFound) + { + throw new IOException("crc check not found."); + } + + crcFound = false; + start = true; + bufPtr = 3; + + return -1; + } + } + + if (c < 0) + { + return -1; + } + + bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf); + } + + return outBuf[bufPtr++]; + } + + public override int ReadByte() + { + if (start) + { + if (hasHeaders) + { + ParseHeaders(); + } + + crc.Reset(); + start = false; + } + + if (clearText) + { + return ReadByteClearText(); + } + + int c = DoReadByte(); + + crc.Update(c); + + return c; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (start && count > 0) + { + if (hasHeaders) + { + ParseHeaders(); + } + start = false; + } + + if (clearText) + { + return ReadClearText(buffer, offset, count); + } + + int pos = offset; + try + { + int end = offset + count; + while (pos < end) + { + int c = DoReadByte(); + crc.Update(c); + if (c == -1) + { + break; + } + buffer[pos++] = (byte) c; + } + } + catch (IOException ioe) + { + if (pos == offset) throw ioe; + } + + return pos - offset; + } + + public override void Close() + { + input.Close(); + base.Close(); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/ArmoredOutputStream.cs b/iTechSharp/srcbc/bcpg/ArmoredOutputStream.cs new file mode 100644 index 0000000..6d622ed --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ArmoredOutputStream.cs @@ -0,0 +1,328 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic output stream. + */ + public class ArmoredOutputStream + : BaseOutputStream + { + private static readonly byte[] encodingTable = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', + (byte)'7', (byte)'8', (byte)'9', + (byte)'+', (byte)'/' + }; + + /** + * encode the input data producing a base 64 encoded byte array. + */ + private static void Encode( + Stream outStream, + int[] data, + int len) + { + Debug.Assert(len > 0); + Debug.Assert(len < 4); + + byte[] bs = new byte[4]; + int d1 = data[0]; + bs[0] = encodingTable[(d1 >> 2) & 0x3f]; + + switch (len) + { + case 1: + { + bs[1] = encodingTable[(d1 << 4) & 0x3f]; + bs[2] = (byte)'='; + bs[3] = (byte)'='; + break; + } + case 2: + { + int d2 = data[1]; + bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; + bs[2] = encodingTable[(d2 << 2) & 0x3f]; + bs[3] = (byte)'='; + break; + } + case 3: + { + int d2 = data[1]; + int d3 = data[2]; + bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; + bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f]; + bs[3] = encodingTable[d3 & 0x3f]; + break; + } + } + + outStream.Write(bs, 0, bs.Length); + } + + private readonly Stream outStream; + private int[] buf = new int[3]; + private int bufPtr = 0; + private Crc24 crc = new Crc24(); + private int chunkCount = 0; + private int lastb; + + private bool start = true; + private bool clearText = false; + private bool newLine = false; + + private string nl = Platform.NewLine; + + private string type; + private string headerStart = "-----BEGIN PGP "; + private string headerTail = "-----"; + private string footerStart = "-----END PGP "; + private string footerTail = "-----"; + + private string version = "BCPG v1.32"; + + private readonly IDictionary headers; + + public ArmoredOutputStream(Stream outStream) + { + this.outStream = outStream; + this.headers = new Hashtable(); + this.headers["Version"] = version; + } + + public ArmoredOutputStream(Stream outStream, IDictionary headers) + { + this.outStream = outStream; + this.headers = new Hashtable(headers); + this.headers["Version"] = version; + } + + /** + * Set an additional header entry. + * + * @param name the name of the header entry. + * @param v the value of the header entry. + */ + public void SetHeader( + string name, + string v) + { + headers[name] = v; + } + + /** + * Reset the headers to only contain a Version string. + */ + public void ResetHeaders() + { + headers.Clear(); + headers["Version"] = version; + } + + /** + * Start a clear text signed message. + * @param hashAlgorithm + */ + public void BeginClearText( + HashAlgorithmTag hashAlgorithm) + { + string hash; + + switch (hashAlgorithm) + { + case HashAlgorithmTag.Sha1: + hash = "SHA1"; + break; + case HashAlgorithmTag.Sha256: + hash = "SHA256"; + break; + case HashAlgorithmTag.Sha384: + hash = "SHA384"; + break; + case HashAlgorithmTag.Sha512: + hash = "SHA512"; + break; + case HashAlgorithmTag.MD2: + hash = "MD2"; + break; + case HashAlgorithmTag.MD5: + hash = "MD5"; + break; + case HashAlgorithmTag.RipeMD160: + hash = "RIPEMD160"; + break; + default: + throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm); + } + + DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); + DoWrite("Hash: " + hash + nl + nl); + + clearText = true; + newLine = true; + lastb = 0; + } + + public void EndClearText() + { + clearText = false; + } + + public override void WriteByte( + byte b) + { + if (clearText) + { + outStream.WriteByte(b); + + if (newLine) + { + if (!(b == '\n' && lastb == '\r')) + { + newLine = false; + } + if (b == '-') + { + outStream.WriteByte((byte)' '); + outStream.WriteByte((byte)'-'); // dash escape + } + } + if (b == '\r' || (b == '\n' && lastb != '\r')) + { + newLine = true; + } + lastb = b; + return; + } + + if (start) + { + bool newPacket = (b & 0x40) != 0; + + int tag; + if (newPacket) + { + tag = b & 0x3f; + } + else + { + tag = (b & 0x3f) >> 2; + } + + switch ((PacketTag)tag) + { + case PacketTag.PublicKey: + type = "PUBLIC KEY BLOCK"; + break; + case PacketTag.SecretKey: + type = "PRIVATE KEY BLOCK"; + break; + case PacketTag.Signature: + type = "SIGNATURE"; + break; + default: + type = "MESSAGE"; + break; + } + + DoWrite(headerStart + type + headerTail + nl); + WriteHeaderEntry("Version", (string) headers["Version"]); + + foreach (DictionaryEntry de in headers) + { + string k = (string) de.Key; + if (k != "Version") + { + string v = (string) de.Value; + WriteHeaderEntry(k, v); + } + } + + DoWrite(nl); + + start = false; + } + + if (bufPtr == 3) + { + Encode(outStream, buf, bufPtr); + bufPtr = 0; + if ((++chunkCount & 0xf) == 0) + { + DoWrite(nl); + } + } + + crc.Update(b); + buf[bufPtr++] = b & 0xff; + } + + /** + * Note: close does nor close the underlying stream. So it is possible to write + * multiple objects using armoring to a single stream. + */ + public override void Close() + { + if (type != null) + { + if (bufPtr > 0) + { + Encode(outStream, buf, bufPtr); + } + + DoWrite(nl + '='); + + int crcV = crc.Value; + + buf[0] = ((crcV >> 16) & 0xff); + buf[1] = ((crcV >> 8) & 0xff); + buf[2] = (crcV & 0xff); + + Encode(outStream, buf, 3); + + DoWrite(nl); + DoWrite(footerStart); + DoWrite(type); + DoWrite(footerTail); + DoWrite(nl); + + outStream.Flush(); + + type = null; + start = true; + base.Close(); + } + } + + private void WriteHeaderEntry( + string name, + string v) + { + DoWrite(name + ": " + v + nl); + } + + private void DoWrite( + string s) + { + byte[] bs = Encoding.ASCII.GetBytes(s); + outStream.Write(bs, 0, bs.Length); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/BcpgInputStream.cs b/iTechSharp/srcbc/bcpg/BcpgInputStream.cs new file mode 100644 index 0000000..3c69fbd --- /dev/null +++ b/iTechSharp/srcbc/bcpg/BcpgInputStream.cs @@ -0,0 +1,355 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Reader for PGP objects. + public class BcpgInputStream + : BaseInputStream + { + private Stream m_in; + private bool next = false; + private int nextB; + + internal static BcpgInputStream Wrap( + Stream inStr) + { + if (inStr is BcpgInputStream) + { + return (BcpgInputStream) inStr; + } + + return new BcpgInputStream(inStr); + } + + private BcpgInputStream( + Stream inputStream) + { + this.m_in = inputStream; + } + + public override int ReadByte() + { + if (next) + { + next = false; + return nextB; + } + + return m_in.ReadByte(); + } + + public override int Read( + byte[] buffer, + int offset, + int count) + { + // Strangely, when count == 0, we should still attempt to read a byte +// if (count == 0) +// return 0; + + if (!next) + return m_in.Read(buffer, offset, count); + + // We have next byte waiting, so return it + + if (nextB < 0) + return 0; // EndOfStream + + if (buffer == null) + throw new ArgumentNullException("buffer"); + + buffer[offset] = (byte) nextB; + next = false; + + return 1; + } + + public byte[] ReadAll() + { + return Streams.ReadAll(this); + } + + public void ReadFully( + byte[] buffer, + int off, + int len) + { + if (Streams.ReadFully(this, buffer, off, len) < len) + throw new EndOfStreamException(); + } + + public void ReadFully( + byte[] buffer) + { + ReadFully(buffer, 0, buffer.Length); + } + + /// Returns the next packet tag in the stream. + public PacketTag NextPacketTag() + { + if (!next) + { + try + { + nextB = m_in.ReadByte(); + } + catch (EndOfStreamException) + { + nextB = -1; + } + + next = true; + } + + if (nextB >= 0) + { + if ((nextB & 0x40) != 0) // new + { + return (PacketTag)(nextB & 0x3f); + } + else // old + { + return (PacketTag)((nextB & 0x3f) >> 2); + } + } + + return (PacketTag) nextB; + } + + public Packet ReadPacket() + { + int hdr = this.ReadByte(); + + if (hdr < 0) + { + return null; + } + + if ((hdr & 0x80) == 0) + { + throw new IOException("invalid header encountered"); + } + + bool newPacket = (hdr & 0x40) != 0; + PacketTag tag = 0; + int bodyLen = 0; + bool partial = false; + + if (newPacket) + { + tag = (PacketTag)(hdr & 0x3f); + + int l = this.ReadByte(); + + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + int b = m_in.ReadByte(); + bodyLen = ((l - 192) << 8) + (b) + 192; + } + else if (l == 255) + { + bodyLen = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16) + | (m_in.ReadByte() << 8) | m_in.ReadByte(); + } + else + { + partial = true; + bodyLen = 1 << (l & 0x1f); + } + } + else + { + int lengthType = hdr & 0x3; + + tag = (PacketTag)((hdr & 0x3f) >> 2); + + switch (lengthType) + { + case 0: + bodyLen = this.ReadByte(); + break; + case 1: + bodyLen = (this.ReadByte() << 8) | this.ReadByte(); + break; + case 2: + bodyLen = (this.ReadByte() << 24) | (this.ReadByte() << 16) + | (this.ReadByte() << 8) | this.ReadByte(); + break; + case 3: + partial = true; + break; + default: + throw new IOException("unknown length type encountered"); + } + } + + BcpgInputStream objStream; + if (bodyLen == 0 && partial) + { + objStream = this; + } + else + { + PartialInputStream pis = new PartialInputStream(this, partial, bodyLen); + objStream = new BcpgInputStream(pis); + } + + switch (tag) + { + case PacketTag.Reserved: + return new InputStreamPacket(objStream); + case PacketTag.PublicKeyEncryptedSession: + return new PublicKeyEncSessionPacket(objStream); + case PacketTag.Signature: + return new SignaturePacket(objStream); + case PacketTag.SymmetricKeyEncryptedSessionKey: + return new SymmetricKeyEncSessionPacket(objStream); + case PacketTag.OnePassSignature: + return new OnePassSignaturePacket(objStream); + case PacketTag.SecretKey: + return new SecretKeyPacket(objStream); + case PacketTag.PublicKey: + return new PublicKeyPacket(objStream); + case PacketTag.SecretSubkey: + return new SecretSubkeyPacket(objStream); + case PacketTag.CompressedData: + return new CompressedDataPacket(objStream); + case PacketTag.SymmetricKeyEncrypted: + return new SymmetricEncDataPacket(objStream); + case PacketTag.Marker: + return new MarkerPacket(objStream); + case PacketTag.LiteralData: + return new LiteralDataPacket(objStream); + case PacketTag.Trust: + return new TrustPacket(objStream); + case PacketTag.UserId: + return new UserIdPacket(objStream); + case PacketTag.UserAttribute: + return new UserAttributePacket(objStream); + case PacketTag.PublicSubkey: + return new PublicSubkeyPacket(objStream); + case PacketTag.SymmetricEncryptedIntegrityProtected: + return new SymmetricEncIntegrityPacket(objStream); + case PacketTag.ModificationDetectionCode: + return new ModDetectionCodePacket(objStream); + case PacketTag.Experimental1: + case PacketTag.Experimental2: + case PacketTag.Experimental3: + case PacketTag.Experimental4: + return new ExperimentalPacket(tag, objStream); + default: + throw new IOException("unknown packet type encountered: " + tag); + } + } + + public override void Close() + { + m_in.Close(); + base.Close(); + } + + /// + /// A stream that overlays our input stream, allowing the user to only read a segment of it. + /// NB: dataLength will be negative if the segment length is in the upper range above 2**31. + /// + private class PartialInputStream + : BaseInputStream + { + private BcpgInputStream m_in; + private bool partial; + private int dataLength; + + internal PartialInputStream( + BcpgInputStream bcpgIn, + bool partial, + int dataLength) + { + this.m_in = bcpgIn; + this.partial = partial; + this.dataLength = dataLength; + } + + public override int ReadByte() + { + do + { + if (dataLength != 0) + { + int ch = m_in.ReadByte(); + if (ch < 0) + { + throw new EndOfStreamException("Premature end of stream in PartialInputStream"); + } + dataLength--; + return ch; + } + } + while (partial && ReadPartialDataLength() >= 0); + + return -1; + } + + public override int Read(byte[] buffer, int offset, int count) + { + do + { + if (dataLength != 0) + { + int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; + int len = m_in.Read(buffer, offset, readLen); + if (len < 1) + { + throw new EndOfStreamException("Premature end of stream in PartialInputStream"); + } + dataLength -= len; + return len; + } + } + while (partial && ReadPartialDataLength() >= 0); + + return 0; + } + + private int ReadPartialDataLength() + { + int l = m_in.ReadByte(); + + if (l < 0) + { + return -1; + } + + partial = false; + + if (l < 192) + { + dataLength = l; + } + else if (l <= 223) + { + dataLength = ((l - 192) << 8) + (m_in.ReadByte()) + 192; + } + else if (l == 255) + { + dataLength = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16) + | (m_in.ReadByte() << 8) | m_in.ReadByte(); + } + else + { + partial = true; + dataLength = 1 << (l & 0x1f); + } + + return 0; + } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/BcpgObject.cs b/iTechSharp/srcbc/bcpg/BcpgObject.cs new file mode 100644 index 0000000..92811c3 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/BcpgObject.cs @@ -0,0 +1,22 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for a PGP object. + public abstract class BcpgObject + { + public virtual byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WriteObject(this); + + return bOut.ToArray(); + } + + public abstract void Encode(BcpgOutputStream bcpgOut); + } +} + diff --git a/iTechSharp/srcbc/bcpg/BcpgOutputStream.cs b/iTechSharp/srcbc/bcpg/BcpgOutputStream.cs new file mode 100644 index 0000000..204f65b --- /dev/null +++ b/iTechSharp/srcbc/bcpg/BcpgOutputStream.cs @@ -0,0 +1,390 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic output stream. + public class BcpgOutputStream + : BaseOutputStream + { + internal static BcpgOutputStream Wrap( + Stream outStr) + { + if (outStr is BcpgOutputStream) + { + return (BcpgOutputStream) outStr; + } + + return new BcpgOutputStream(outStr); + } + + private Stream outStr; + private byte[] partialBuffer; + private int partialBufferLength; + private int partialPower; + private int partialOffset; + private const int BufferSizePower = 16; // 2^16 size buffer on long files + + /// Create a stream representing a general packet. + /// Output stream to write to. + public BcpgOutputStream( + Stream outStr) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + this.outStr = outStr; + } + + /// Create a stream representing an old style partial object. + /// Output stream to write to. + /// The packet tag for the object. + public BcpgOutputStream( + Stream outStr, + PacketTag tag) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + this.outStr = outStr; + this.WriteHeader(tag, true, true, 0); + } + + /// Create a stream representing a general packet. + /// Output stream to write to. + /// Packet tag. + /// Size of chunks making up the packet. + /// If true, the header is written out in old format. + public BcpgOutputStream( + Stream outStr, + PacketTag tag, + long length, + bool oldFormat) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + this.outStr = outStr; + + if (length > 0xFFFFFFFFL) + { + this.WriteHeader(tag, false, true, 0); + this.partialBufferLength = 1 << BufferSizePower; + this.partialBuffer = new byte[partialBufferLength]; + this.partialPower = BufferSizePower; + this.partialOffset = 0; + } + else + { + this.WriteHeader(tag, oldFormat, false, length); + } + } + + /// Create a new style partial input stream buffered into chunks. + /// Output stream to write to. + /// Packet tag. + /// Size of chunks making up the packet. + public BcpgOutputStream( + Stream outStr, + PacketTag tag, + long length) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + this.outStr = outStr; + this.WriteHeader(tag, false, false, length); + } + + /// Create a new style partial input stream buffered into chunks. + /// Output stream to write to. + /// Packet tag. + /// Buffer to use for collecting chunks. + public BcpgOutputStream( + Stream outStr, + PacketTag tag, + byte[] buffer) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + this.outStr = outStr; + this.WriteHeader(tag, false, true, 0); + + this.partialBuffer = buffer; + + uint length = (uint) partialBuffer.Length; + for (partialPower = 0; length != 1; partialPower++) + { + length >>= 1; + } + + if (partialPower > 30) + { + throw new IOException("Buffer cannot be greater than 2^30 in length."); + } + this.partialBufferLength = 1 << partialPower; + this.partialOffset = 0; + } + + private void WriteNewPacketLength( + long bodyLen) + { + if (bodyLen < 192) + { + outStr.WriteByte((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + outStr.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192)); + outStr.WriteByte((byte)bodyLen); + } + else + { + outStr.WriteByte(0xff); + outStr.WriteByte((byte)(bodyLen >> 24)); + outStr.WriteByte((byte)(bodyLen >> 16)); + outStr.WriteByte((byte)(bodyLen >> 8)); + outStr.WriteByte((byte)bodyLen); + } + } + + private void WriteHeader( + PacketTag tag, + bool oldPackets, + bool partial, + long bodyLen) + { + int hdr = 0x80; + + if (partialBuffer != null) + { + PartialFlush(true); + partialBuffer = null; + } + + if (oldPackets) + { + hdr |= ((int) tag) << 2; + + if (partial) + { + this.WriteByte((byte)(hdr | 0x03)); + } + else + { + if (bodyLen <= 0xff) + { + this.WriteByte((byte) hdr); + this.WriteByte((byte)bodyLen); + } + else if (bodyLen <= 0xffff) + { + this.WriteByte((byte)(hdr | 0x01)); + this.WriteByte((byte)(bodyLen >> 8)); + this.WriteByte((byte)(bodyLen)); + } + else + { + this.WriteByte((byte)(hdr | 0x02)); + this.WriteByte((byte)(bodyLen >> 24)); + this.WriteByte((byte)(bodyLen >> 16)); + this.WriteByte((byte)(bodyLen >> 8)); + this.WriteByte((byte)bodyLen); + } + } + } + else + { + hdr |= 0x40 | (int) tag; + this.WriteByte((byte) hdr); + + if (partial) + { + partialOffset = 0; + } + else + { + this.WriteNewPacketLength(bodyLen); + } + } + } + + private void PartialFlush( + bool isLast) + { + if (isLast) + { + WriteNewPacketLength(partialOffset); + outStr.Write(partialBuffer, 0, partialOffset); + } + else + { + outStr.WriteByte((byte)(0xE0 | partialPower)); + outStr.Write(partialBuffer, 0, partialBufferLength); + } + + partialOffset = 0; + } + + private void WritePartial( + byte b) + { + if (partialOffset == partialBufferLength) + { + PartialFlush(false); + } + + partialBuffer[partialOffset++] = b; + } + + private void WritePartial( + byte[] buffer, + int off, + int len) + { + if (partialOffset == partialBufferLength) + { + PartialFlush(false); + } + + if (len <= (partialBufferLength - partialOffset)) + { + Array.Copy(buffer, off, partialBuffer, partialOffset, len); + partialOffset += len; + } + else + { + int diff = partialBufferLength - partialOffset; + Array.Copy(buffer, off, partialBuffer, partialOffset, diff); + off += diff; + len -= diff; + PartialFlush(false); + while (len > partialBufferLength) + { + Array.Copy(buffer, off, partialBuffer, 0, partialBufferLength); + off += partialBufferLength; + len -= partialBufferLength; + PartialFlush(false); + } + Array.Copy(buffer, off, partialBuffer, 0, len); + partialOffset += len; + } + } + public override void WriteByte( + byte value) + { + if (partialBuffer != null) + { + WritePartial(value); + } + else + { + outStr.WriteByte(value); + } + } + public override void Write( + byte[] buffer, + int offset, + int count) + { + if (partialBuffer != null) + { + WritePartial(buffer, offset, count); + } + else + { + outStr.Write(buffer, offset, count); + } + } + + // Additional helper methods to write primitive types + internal virtual void WriteShort( + short n) + { + this.Write( + (byte)(n >> 8), + (byte)n); + } + internal virtual void WriteInt( + int n) + { + this.Write( + (byte)(n >> 24), + (byte)(n >> 16), + (byte)(n >> 8), + (byte)n); + } + internal virtual void WriteLong( + long n) + { + this.Write( + (byte)(n >> 56), + (byte)(n >> 48), + (byte)(n >> 40), + (byte)(n >> 32), + (byte)(n >> 24), + (byte)(n >> 16), + (byte)(n >> 8), + (byte)n); + } + + public void WritePacket( + ContainedPacket p) + { + p.Encode(this); + } + + internal void WritePacket( + PacketTag tag, + byte[] body, + bool oldFormat) + { + this.WriteHeader(tag, oldFormat, false, body.Length); + this.Write(body); + } + + public void WriteObject( + BcpgObject bcpgObject) + { + bcpgObject.Encode(this); + } + + public void WriteObjects( + params BcpgObject[] v) + { + foreach (BcpgObject o in v) + { + o.Encode(this); + } + } + + /// Flush the underlying stream. + public override void Flush() + { + outStr.Flush(); + } + + /// Finish writing out the current packet without closing the underlying stream. + public void Finish() + { + if (partialBuffer != null) + { + PartialFlush(true); + partialBuffer = null; + } + } + + public override void Close() + { + this.Finish(); + outStr.Flush(); + outStr.Close(); + base.Close(); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/CompressedDataPacket.cs b/iTechSharp/srcbc/bcpg/CompressedDataPacket.cs new file mode 100644 index 0000000..2432825 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/CompressedDataPacket.cs @@ -0,0 +1,24 @@ +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Generic compressed data object. + public class CompressedDataPacket + : InputStreamPacket + { + private readonly CompressionAlgorithmTag algorithm; + + internal CompressedDataPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + this.algorithm = (CompressionAlgorithmTag) bcpgIn.ReadByte(); + } + + /// The algorithm tag value. + public CompressionAlgorithmTag Algorithm + { + get { return algorithm; } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/CompressionAlgorithmTags.cs b/iTechSharp/srcbc/bcpg/CompressionAlgorithmTags.cs new file mode 100644 index 0000000..0e45229 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/CompressionAlgorithmTags.cs @@ -0,0 +1,11 @@ +namespace Org.BouncyCastle.Bcpg +{ + /// Basic tags for compression algorithms. + public enum CompressionAlgorithmTag + { + Uncompressed = 0, // Uncompressed + Zip = 1, // ZIP (RFC 1951) + ZLib = 2, // ZLIB (RFC 1950) + BZip2 = 3, // BZ2 + } +} diff --git a/iTechSharp/srcbc/bcpg/ContainedPacket.cs b/iTechSharp/srcbc/bcpg/ContainedPacket.cs new file mode 100644 index 0000000..e8f387c --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ContainedPacket.cs @@ -0,0 +1,22 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic type for a PGP packet. + public abstract class ContainedPacket + : Packet + { + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WritePacket(this); + + return bOut.ToArray(); + } + + public abstract void Encode(BcpgOutputStream bcpgOut); + } +} diff --git a/iTechSharp/srcbc/bcpg/Crc24.cs b/iTechSharp/srcbc/bcpg/Crc24.cs new file mode 100644 index 0000000..97846f4 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/Crc24.cs @@ -0,0 +1,46 @@ +using System; + +namespace Org.BouncyCastle.Bcpg +{ + public class Crc24 + { + private const int Crc24Init = 0x0b704ce; + private const int Crc24Poly = 0x1864cfb; + + private int crc = Crc24Init; + + public Crc24() + { + } + + public void Update( + int b) + { + crc ^= b << 16; + for (int i = 0; i < 8; i++) + { + crc <<= 1; + if ((crc & 0x1000000) != 0) + { + crc ^= Crc24Poly; + } + } + } + + [Obsolete("Use 'Value' property instead")] + public int GetValue() + { + return crc; + } + + public int Value + { + get { return crc; } + } + + public void Reset() + { + crc = Crc24Init; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/DsaPublicBcpgKey.cs b/iTechSharp/srcbc/bcpg/DsaPublicBcpgKey.cs new file mode 100644 index 0000000..6115956 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/DsaPublicBcpgKey.cs @@ -0,0 +1,80 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for a DSA public key. + public class DsaPublicBcpgKey + : BcpgObject, IBcpgKey + { + private readonly MPInteger p, q, g, y; + + /// The stream to read the packet from. + public DsaPublicBcpgKey( + BcpgInputStream bcpgIn) + { + this.p = new MPInteger(bcpgIn); + this.q = new MPInteger(bcpgIn); + this.g = new MPInteger(bcpgIn); + this.y = new MPInteger(bcpgIn); + } + + public DsaPublicBcpgKey( + BigInteger p, + BigInteger q, + BigInteger g, + BigInteger y) + { + this.p = new MPInteger(p); + this.q = new MPInteger(q); + this.g = new MPInteger(g); + this.y = new MPInteger(y); + } + + /// The format, as a string, always "PGP". + public string Format + { + get { return "PGP"; } + } + + /// Return the standard PGP encoding of the key. + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObjects(p, q, g, y); + } + + public BigInteger G + { + get { return g.Value; } + } + + public BigInteger P + { + get { return p.Value; } + } + + public BigInteger Q + { + get { return q.Value; } + } + + public BigInteger Y + { + get { return y.Value; } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/DsaSecretBcpgKey.cs b/iTechSharp/srcbc/bcpg/DsaSecretBcpgKey.cs new file mode 100644 index 0000000..41835d4 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/DsaSecretBcpgKey.cs @@ -0,0 +1,61 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for a DSA secret key. + public class DsaSecretBcpgKey + : BcpgObject, IBcpgKey + { + internal MPInteger x; + + /** + * @param in + */ + public DsaSecretBcpgKey( + BcpgInputStream bcpgIn) + { + this.x = new MPInteger(bcpgIn); + } + + public DsaSecretBcpgKey( + BigInteger x) + { + this.x = new MPInteger(x); + } + + /// The format, as a string, always "PGP". + public string Format + { + get { return "PGP"; } + } + + /// Return the standard PGP encoding of the key. + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObject(x); + } + + /** + * @return x + */ + public BigInteger X + { + get { return x.Value; } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/ElGamalPublicBcpgKey.cs b/iTechSharp/srcbc/bcpg/ElGamalPublicBcpgKey.cs new file mode 100644 index 0000000..808e427 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ElGamalPublicBcpgKey.cs @@ -0,0 +1,71 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for an ElGamal public key. + public class ElGamalPublicBcpgKey + : BcpgObject, IBcpgKey + { + internal MPInteger p, g, y; + + public ElGamalPublicBcpgKey( + BcpgInputStream bcpgIn) + { + this.p = new MPInteger(bcpgIn); + this.g = new MPInteger(bcpgIn); + this.y = new MPInteger(bcpgIn); + } + + public ElGamalPublicBcpgKey( + BigInteger p, + BigInteger g, + BigInteger y) + { + this.p = new MPInteger(p); + this.g = new MPInteger(g); + this.y = new MPInteger(y); + } + + /// The format, as a string, always "PGP". + public string Format + { + get { return "PGP"; } + } + + /// Return the standard PGP encoding of the key. + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public BigInteger P + { + get { return p.Value; } + } + + public BigInteger G + { + get { return g.Value; } + } + + public BigInteger Y + { + get { return y.Value; } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObjects(p, g, y); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/ElGamalSecretBcpgKey.cs b/iTechSharp/srcbc/bcpg/ElGamalSecretBcpgKey.cs new file mode 100644 index 0000000..2d95b29 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ElGamalSecretBcpgKey.cs @@ -0,0 +1,61 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for an ElGamal secret key. + public class ElGamalSecretBcpgKey + : BcpgObject, IBcpgKey + { + internal MPInteger x; + + /** + * @param in + */ + public ElGamalSecretBcpgKey( + BcpgInputStream bcpgIn) + { + this.x = new MPInteger(bcpgIn); + } + + /** + * @param x + */ + public ElGamalSecretBcpgKey( + BigInteger x) + { + this.x = new MPInteger(x); + } + + /// The format, as a string, always "PGP". + public string Format + { + get { return "PGP"; } + } + + public BigInteger X + { + get { return x.Value; } + } + + /// Return the standard PGP encoding of the key. + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObject(x); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/ExperimentalPacket.cs b/iTechSharp/srcbc/bcpg/ExperimentalPacket.cs new file mode 100644 index 0000000..36a254b --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ExperimentalPacket.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for an experimental packet. + public class ExperimentalPacket + : ContainedPacket //, PublicKeyAlgorithmTag + { + private readonly PacketTag tag; + private readonly byte[] contents; + + internal ExperimentalPacket( + PacketTag tag, + BcpgInputStream bcpgIn) + { + this.tag = tag; + + this.contents = bcpgIn.ReadAll(); + } + + public PacketTag Tag + { + get { return tag; } + } + + public byte[] GetContents() + { + return (byte[]) contents.Clone(); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(tag, contents, true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/HashAlgorithmTags.cs b/iTechSharp/srcbc/bcpg/HashAlgorithmTags.cs new file mode 100644 index 0000000..96c0091 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/HashAlgorithmTags.cs @@ -0,0 +1,19 @@ +namespace Org.BouncyCastle.Bcpg +{ + /// Basic tags for hash algorithms. + public enum HashAlgorithmTag + { + MD5 = 1, // MD5 + Sha1 = 2, // SHA-1 + RipeMD160 = 3, // RIPE-MD/160 + DoubleSha = 4, // Reserved for double-width SHA (experimental) + MD2 = 5, // MD2 + Tiger192 = 6, // Reserved for TIGER/192 + Haval5pass160 = 7, // Reserved for HAVAL (5 pass, 160-bit) + + Sha256 = 8, // SHA-256 + Sha384 = 9, // SHA-384 + Sha512 = 10, // SHA-512 + Sha224 = 11, // SHA-224 + } +} diff --git a/iTechSharp/srcbc/bcpg/IBcpgKey.cs b/iTechSharp/srcbc/bcpg/IBcpgKey.cs new file mode 100644 index 0000000..2754617 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/IBcpgKey.cs @@ -0,0 +1,16 @@ +using System; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base interface for a PGP key. + public interface IBcpgKey + { + /// + /// The base format for this key - in the case of the symmetric keys it will generally + /// be raw indicating that the key is just a straight byte representation, for an asymmetric + /// key the format will be PGP, indicating the key is a string of MPIs encoded in PGP format. + /// + /// "RAW" or "PGP". + string Format { get; } + } +} diff --git a/iTechSharp/srcbc/bcpg/InputStreamPacket.cs b/iTechSharp/srcbc/bcpg/InputStreamPacket.cs new file mode 100644 index 0000000..c45efab --- /dev/null +++ b/iTechSharp/srcbc/bcpg/InputStreamPacket.cs @@ -0,0 +1,20 @@ +namespace Org.BouncyCastle.Bcpg +{ + public class InputStreamPacket + : Packet + { + private readonly BcpgInputStream bcpgIn; + + public InputStreamPacket( + BcpgInputStream bcpgIn) + { + this.bcpgIn = bcpgIn; + } + + /// Note: you can only read from this once... + public BcpgInputStream GetInputStream() + { + return bcpgIn; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/LiteralDataPacket.cs b/iTechSharp/srcbc/bcpg/LiteralDataPacket.cs new file mode 100644 index 0000000..819b348 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/LiteralDataPacket.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Generic literal data packet. + public class LiteralDataPacket + : InputStreamPacket + { + private int format; + private string fileName; + private long modDate; + + internal LiteralDataPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + format = bcpgIn.ReadByte(); + int l = bcpgIn.ReadByte(); + + char[] fileNameChars = new char[l]; + for (int i = 0; i != fileNameChars.Length; i++) + { + fileNameChars[i] = (char)bcpgIn.ReadByte(); + } + fileName = new string(fileNameChars); + + modDate = (((uint)bcpgIn.ReadByte() << 24) + | ((uint)bcpgIn.ReadByte() << 16) + | ((uint)bcpgIn.ReadByte() << 8) + | (uint)bcpgIn.ReadByte()) * 1000L; + } + + /// The format tag value. + public int Format + { + get { return format; } + } + + /// The modification time of the file in milli-seconds (since Jan 1, 1970 UTC) + public long ModificationTime + { + get { return modDate; } + } + + public string FileName + { + get { return fileName; } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/MPInteger.cs b/iTechSharp/srcbc/bcpg/MPInteger.cs new file mode 100644 index 0000000..4414072 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/MPInteger.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// A multiple precision integer + public class MPInteger + : BcpgObject + { + private readonly BigInteger val; + + public MPInteger( + BcpgInputStream bcpgIn) + { + if (bcpgIn == null) + throw new ArgumentNullException("bcpgIn"); + + int length = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte(); + byte[] bytes = new byte[(length + 7) / 8]; + + bcpgIn.ReadFully(bytes); + + this.val = new BigInteger(1, bytes); + } + + public MPInteger( + BigInteger val) + { + if (val == null) + throw new ArgumentNullException("val"); + if (val.SignValue < 0) + throw new ArgumentException("Values must be positive", "val"); + + this.val = val; + } + + public BigInteger Value + { + get { return val; } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteShort((short) val.BitLength); + bcpgOut.Write(val.ToByteArrayUnsigned()); + } + + internal static void Encode( + BcpgOutputStream bcpgOut, + BigInteger val) + { + bcpgOut.WriteShort((short) val.BitLength); + bcpgOut.Write(val.ToByteArrayUnsigned()); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/MarkerPacket.cs b/iTechSharp/srcbc/bcpg/MarkerPacket.cs new file mode 100644 index 0000000..4dc4b5a --- /dev/null +++ b/iTechSharp/srcbc/bcpg/MarkerPacket.cs @@ -0,0 +1,24 @@ +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic type for a marker packet. + public class MarkerPacket + : ContainedPacket + { + // "PGP" + byte[] marker = { (byte)0x50, (byte)0x47, (byte)0x50 }; + + public MarkerPacket( + BcpgInputStream bcpgIn) + { + bcpgIn.ReadFully(marker); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.Marker, marker, true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/ModDetectionCodePacket.cs b/iTechSharp/srcbc/bcpg/ModDetectionCodePacket.cs new file mode 100644 index 0000000..6bb2364 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/ModDetectionCodePacket.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for a modification detection code packet. + public class ModDetectionCodePacket + : ContainedPacket + { + private readonly byte[] digest; + + internal ModDetectionCodePacket( + BcpgInputStream bcpgIn) + { + if (bcpgIn == null) + throw new ArgumentNullException("bcpgIn"); + + this.digest = new byte[20]; + bcpgIn.ReadFully(this.digest); + } + + public ModDetectionCodePacket( + byte[] digest) + { + if (digest == null) + throw new ArgumentNullException("digest"); + + this.digest = (byte[]) digest.Clone(); + } + + public byte[] GetDigest() + { + return (byte[]) digest.Clone(); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.ModificationDetectionCode, digest, false); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/OnePassSignaturePacket.cs b/iTechSharp/srcbc/bcpg/OnePassSignaturePacket.cs new file mode 100644 index 0000000..b67df0a --- /dev/null +++ b/iTechSharp/srcbc/bcpg/OnePassSignaturePacket.cs @@ -0,0 +1,93 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Generic signature object + public class OnePassSignaturePacket + : ContainedPacket + { + private int version; + private int sigType; + private HashAlgorithmTag hashAlgorithm; + private PublicKeyAlgorithmTag keyAlgorithm; + private long keyId; + private int nested; + + internal OnePassSignaturePacket( + BcpgInputStream bcpgIn) + { + version = bcpgIn.ReadByte(); + sigType = bcpgIn.ReadByte(); + hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte(); + keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte(); + + keyId |= (long)bcpgIn.ReadByte() << 56; + keyId |= (long)bcpgIn.ReadByte() << 48; + keyId |= (long)bcpgIn.ReadByte() << 40; + keyId |= (long)bcpgIn.ReadByte() << 32; + keyId |= (long)bcpgIn.ReadByte() << 24; + keyId |= (long)bcpgIn.ReadByte() << 16; + keyId |= (long)bcpgIn.ReadByte() << 8; + keyId |= (uint)bcpgIn.ReadByte(); + + nested = bcpgIn.ReadByte(); + } + + public OnePassSignaturePacket( + int sigType, + HashAlgorithmTag hashAlgorithm, + PublicKeyAlgorithmTag keyAlgorithm, + long keyId, + bool isNested) + { + this.version = 3; + this.sigType = sigType; + this.hashAlgorithm = hashAlgorithm; + this.keyAlgorithm = keyAlgorithm; + this.keyId = keyId; + this.nested = (isNested) ? 0 : 1; + } + + public int SignatureType + { + get { return sigType; } + } + + /// The encryption algorithm tag. + public PublicKeyAlgorithmTag KeyAlgorithm + { + get { return keyAlgorithm; } + } + + /// The hash algorithm tag. + public HashAlgorithmTag HashAlgorithm + { + get { return hashAlgorithm; } + } + + public long KeyId + { + get { return keyId; } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.Write( + (byte) version, + (byte) sigType, + (byte) hashAlgorithm, + (byte) keyAlgorithm); + + pOut.WriteLong(keyId); + + pOut.WriteByte((byte) nested); + + bcpgOut.WritePacket(PacketTag.OnePassSignature, bOut.ToArray(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/OutputStreamPacket.cs b/iTechSharp/srcbc/bcpg/OutputStreamPacket.cs new file mode 100644 index 0000000..aa8316d --- /dev/null +++ b/iTechSharp/srcbc/bcpg/OutputStreamPacket.cs @@ -0,0 +1,24 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + public abstract class OutputStreamPacket + { + private readonly BcpgOutputStream bcpgOut; + + internal OutputStreamPacket( + BcpgOutputStream bcpgOut) + { + if (bcpgOut == null) + throw new ArgumentNullException("bcpgOut"); + + this.bcpgOut = bcpgOut; + } + + public abstract BcpgOutputStream Open(); + + public abstract void Close(); + } +} + diff --git a/iTechSharp/srcbc/bcpg/Packet.cs b/iTechSharp/srcbc/bcpg/Packet.cs new file mode 100644 index 0000000..83f6d1f --- /dev/null +++ b/iTechSharp/srcbc/bcpg/Packet.cs @@ -0,0 +1,7 @@ +namespace Org.BouncyCastle.Bcpg +{ + public class Packet + //: PacketTag + { + } +} diff --git a/iTechSharp/srcbc/bcpg/PacketTags.cs b/iTechSharp/srcbc/bcpg/PacketTags.cs new file mode 100644 index 0000000..5a53d4e --- /dev/null +++ b/iTechSharp/srcbc/bcpg/PacketTags.cs @@ -0,0 +1,30 @@ +namespace Org.BouncyCastle.Bcpg +{ + /// Basic PGP packet tag types. + public enum PacketTag + { + Reserved = 0, // Reserved - a packet tag must not have this value + PublicKeyEncryptedSession = 1, // Public-Key Encrypted Session Key Packet + Signature = 2, // Signature Packet + SymmetricKeyEncryptedSessionKey = 3, // Symmetric-Key Encrypted Session Key Packet + OnePassSignature = 4, // One-Pass Signature Packet + SecretKey = 5, // Secret Key Packet + PublicKey = 6, // Public Key Packet + SecretSubkey = 7, // Secret Subkey Packet + CompressedData = 8, // Compressed Data Packet + SymmetricKeyEncrypted = 9, // Symmetrically Encrypted Data Packet + Marker = 10, // Marker Packet + LiteralData = 11, // Literal Data Packet + Trust = 12, // Trust Packet + UserId = 13, // User ID Packet + PublicSubkey = 14, // Public Subkey Packet + UserAttribute = 17, // User attribute + SymmetricEncryptedIntegrityProtected = 18, // Symmetric encrypted, integrity protected + ModificationDetectionCode = 19, // Modification detection code + + Experimental1 = 60, // Private or Experimental Values + Experimental2 = 61, + Experimental3 = 62, + Experimental4 = 63 + } +} diff --git a/iTechSharp/srcbc/bcpg/PublicKeyAlgorithmTags.cs b/iTechSharp/srcbc/bcpg/PublicKeyAlgorithmTags.cs new file mode 100644 index 0000000..85ae548 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/PublicKeyAlgorithmTags.cs @@ -0,0 +1,28 @@ +namespace Org.BouncyCastle.Bcpg +{ + /// Public Key Algorithm tag numbers. + public enum PublicKeyAlgorithmTag + { + RsaGeneral = 1, // RSA (Encrypt or Sign) + RsaEncrypt = 2, // RSA Encrypt-Only + RsaSign = 3, // RSA Sign-Only + ElGamalEncrypt = 16, // Elgamal (Encrypt-Only), see [ELGAMAL] + Dsa = 17, // DSA (Digital Signature Standard) + EC = 18, // Reserved for Elliptic Curve + ECDsa = 19, // Reserved for ECDSA + ElGamalGeneral = 20, // Elgamal (Encrypt or Sign) + DiffieHellman = 21, // Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME) + + Experimental_1 = 100, + Experimental_2 = 101, + Experimental_3 = 102, + Experimental_4 = 103, + Experimental_5 = 104, + Experimental_6 = 105, + Experimental_7 = 106, + Experimental_8 = 107, + Experimental_9 = 108, + Experimental_10 = 109, + Experimental_11 = 110, + } +} diff --git a/iTechSharp/srcbc/bcpg/PublicKeyEncSessionPacket.cs b/iTechSharp/srcbc/bcpg/PublicKeyEncSessionPacket.cs new file mode 100644 index 0000000..d10605f --- /dev/null +++ b/iTechSharp/srcbc/bcpg/PublicKeyEncSessionPacket.cs @@ -0,0 +1,103 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for a PGP public key. + public class PublicKeyEncSessionPacket + : ContainedPacket //, PublicKeyAlgorithmTag + { + private int version; + private long keyId; + private PublicKeyAlgorithmTag algorithm; + private BigInteger[] data; + + internal PublicKeyEncSessionPacket( + BcpgInputStream bcpgIn) + { + version = bcpgIn.ReadByte(); + + keyId |= (long)bcpgIn.ReadByte() << 56; + keyId |= (long)bcpgIn.ReadByte() << 48; + keyId |= (long)bcpgIn.ReadByte() << 40; + keyId |= (long)bcpgIn.ReadByte() << 32; + keyId |= (long)bcpgIn.ReadByte() << 24; + keyId |= (long)bcpgIn.ReadByte() << 16; + keyId |= (long)bcpgIn.ReadByte() << 8; + keyId |= (uint)bcpgIn.ReadByte(); + + algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte(); + + switch ((PublicKeyAlgorithmTag) algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + data = new BigInteger[]{ new MPInteger(bcpgIn).Value }; + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + data = new BigInteger[] + { + new MPInteger(bcpgIn).Value, + new MPInteger(bcpgIn).Value + }; + break; + default: + throw new IOException("unknown PGP public key algorithm encountered"); + } + } + + public PublicKeyEncSessionPacket( + long keyId, + PublicKeyAlgorithmTag algorithm, + BigInteger[] data) + { + this.version = 3; + this.keyId = keyId; + this.algorithm = algorithm; + this.data = (BigInteger[]) data.Clone(); + } + + public int Version + { + get { return version; } + } + + public long KeyId + { + get { return keyId; } + } + + public PublicKeyAlgorithmTag Algorithm + { + get { return algorithm; } + } + + public BigInteger[] GetEncSessionKey() + { + return (BigInteger[]) data.Clone(); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WriteByte((byte) version); + + pOut.WriteLong(keyId); + + pOut.WriteByte((byte)algorithm); + + for (int i = 0; i != data.Length; i++) + { + MPInteger.Encode(pOut, data[i]); + } + + bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/PublicKeyPacket.cs b/iTechSharp/srcbc/bcpg/PublicKeyPacket.cs new file mode 100644 index 0000000..32d4314 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/PublicKeyPacket.cs @@ -0,0 +1,115 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for a PGP public key. + public class PublicKeyPacket + : ContainedPacket //, PublicKeyAlgorithmTag + { + private int version; + private long time; + private int validDays; + private PublicKeyAlgorithmTag algorithm; + private IBcpgKey key; + + internal PublicKeyPacket( + BcpgInputStream bcpgIn) + { + version = bcpgIn.ReadByte(); + + time = ((uint)bcpgIn.ReadByte() << 24) | ((uint)bcpgIn.ReadByte() << 16) + | ((uint)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte(); + + if (version <= 3) + { + validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte(); + } + + algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte(); + + switch ((PublicKeyAlgorithmTag) algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + key = new RsaPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.Dsa: + key = new DsaPublicBcpgKey(bcpgIn); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + key = new ElGamalPublicBcpgKey(bcpgIn); + break; + default: + throw new IOException("unknown PGP public key algorithm encountered"); + } + } + + /// Construct a version 4 public key packet. + public PublicKeyPacket( + PublicKeyAlgorithmTag algorithm, + DateTime time, + IBcpgKey key) + { + this.version = 4; + this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L; + this.algorithm = algorithm; + this.key = key; + } + + public int Version + { + get { return version; } + } + + public PublicKeyAlgorithmTag Algorithm + { + get { return algorithm; } + } + + public int ValidDays + { + get { return validDays; } + } + + public DateTime GetTime() + { + return DateTimeUtilities.UnixMsToDateTime(time * 1000L); + } + + public IBcpgKey Key + { + get { return key; } + } + + public byte[] GetEncodedContents() + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WriteByte((byte) version); + pOut.WriteInt((int) time); + + if (version <= 3) + { + pOut.WriteShort((short) validDays); + } + + pOut.WriteByte((byte) algorithm); + + pOut.WriteObject((BcpgObject)key); + + return bOut.ToArray(); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/PublicSubkeyPacket.cs b/iTechSharp/srcbc/bcpg/PublicSubkeyPacket.cs new file mode 100644 index 0000000..6e1aeda --- /dev/null +++ b/iTechSharp/srcbc/bcpg/PublicSubkeyPacket.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for a PGP public subkey + public class PublicSubkeyPacket + : PublicKeyPacket + { + internal PublicSubkeyPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + } + + /// Construct a version 4 public subkey packet. + public PublicSubkeyPacket( + PublicKeyAlgorithmTag algorithm, + DateTime time, + IBcpgKey key) + : base(algorithm, time, key) + { + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.PublicSubkey, GetEncodedContents(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/RsaPublicBcpgKey.cs b/iTechSharp/srcbc/bcpg/RsaPublicBcpgKey.cs new file mode 100644 index 0000000..fd2313c --- /dev/null +++ b/iTechSharp/srcbc/bcpg/RsaPublicBcpgKey.cs @@ -0,0 +1,66 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for an RSA public key. + public class RsaPublicBcpgKey + : BcpgObject, IBcpgKey + { + private readonly MPInteger n, e; + + /// Construct an RSA public key from the passed in stream. + public RsaPublicBcpgKey( + BcpgInputStream bcpgIn) + { + this.n = new MPInteger(bcpgIn); + this.e = new MPInteger(bcpgIn); + } + + /// The modulus. + /// The public exponent. + public RsaPublicBcpgKey( + BigInteger n, + BigInteger e) + { + this.n = new MPInteger(n); + this.e = new MPInteger(e); + } + + public BigInteger PublicExponent + { + get { return e.Value; } + } + + public BigInteger Modulus + { + get { return n.Value; } + } + + /// The format, as a string, always "PGP". + public string Format + { + get { return "PGP"; } + } + + /// Return the standard PGP encoding of the key. + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObjects(n, e); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/RsaSecretBcpgKey.cs b/iTechSharp/srcbc/bcpg/RsaSecretBcpgKey.cs new file mode 100644 index 0000000..5c04d9f --- /dev/null +++ b/iTechSharp/srcbc/bcpg/RsaSecretBcpgKey.cs @@ -0,0 +1,114 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg +{ + /// Base class for an RSA secret (or priate) key. + public class RsaSecretBcpgKey + : BcpgObject, IBcpgKey + { + private readonly MPInteger d, p, q, u; + private readonly BigInteger expP, expQ, crt; + + public RsaSecretBcpgKey( + BcpgInputStream bcpgIn) + { + this.d = new MPInteger(bcpgIn); + this.p = new MPInteger(bcpgIn); + this.q = new MPInteger(bcpgIn); + this.u = new MPInteger(bcpgIn); + + this.expP = d.Value.Remainder(p.Value.Subtract(BigInteger.One)); + this.expQ = d.Value.Remainder(q.Value.Subtract(BigInteger.One)); + this.crt = q.Value.ModInverse(p.Value); + } + + public RsaSecretBcpgKey( + BigInteger d, + BigInteger p, + BigInteger q) + { + // PGP requires (p < q) + int cmp = p.CompareTo(q); + if (cmp >= 0) + { + if (cmp == 0) + throw new ArgumentException("p and q cannot be equal"); + + BigInteger tmp = p; + p = q; + q = tmp; + } + + this.d = new MPInteger(d); + this.p = new MPInteger(p); + this.q = new MPInteger(q); + this.u = new MPInteger(p.ModInverse(q)); + + this.expP = d.Remainder(p.Subtract(BigInteger.One)); + this.expQ = d.Remainder(q.Subtract(BigInteger.One)); + this.crt = q.ModInverse(p); + } + + public BigInteger Modulus + { + get { return p.Value.Multiply(q.Value); } + } + + public BigInteger PrivateExponent + { + get { return d.Value; } + } + + public BigInteger PrimeP + { + get { return p.Value; } + } + + public BigInteger PrimeQ + { + get { return q.Value; } + } + + public BigInteger PrimeExponentP + { + get { return expP; } + } + + public BigInteger PrimeExponentQ + { + get { return expQ; } + } + + public BigInteger CrtCoefficient + { + get { return crt; } + } + + /// The format, as a string, always "PGP". + public string Format + { + get { return "PGP"; } + } + + /// Return the standard PGP encoding of the key. + public override byte[] GetEncoded() + { + try + { + return base.GetEncoded(); + } + catch (Exception) + { + return null; + } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObjects(d, p, q, u); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/S2k.cs b/iTechSharp/srcbc/bcpg/S2k.cs new file mode 100644 index 0000000..de08c01 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/S2k.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// The string to key specifier class. + public class S2k + : BcpgObject + { + private const int ExpBias = 6; + + public const int Simple = 0; + public const int Salted = 1; + public const int SaltedAndIterated = 3; + public const int GnuDummyS2K = 101; + + internal int type; + internal HashAlgorithmTag algorithm; + internal byte[] iv; + internal int itCount = -1; + internal int protectionMode = -1; + + internal S2k( + Stream inStr) + { + type = inStr.ReadByte(); + algorithm = (HashAlgorithmTag) inStr.ReadByte(); + + // + // if this happens we have a dummy-S2k packet. + // + if (type != GnuDummyS2K) + { + if (type != 0) + { + iv = new byte[8]; + if (Streams.ReadFully(inStr, iv, 0, iv.Length) < iv.Length) + throw new EndOfStreamException(); + + if (type == 3) + { + itCount = inStr.ReadByte(); + } + } + } + else + { + inStr.ReadByte(); // G + inStr.ReadByte(); // N + inStr.ReadByte(); // U + protectionMode = inStr.ReadByte(); // protection mode + } + } + + public S2k( + HashAlgorithmTag algorithm) + { + this.type = 0; + this.algorithm = algorithm; + } + + public S2k( + HashAlgorithmTag algorithm, + byte[] iv) + { + this.type = 1; + this.algorithm = algorithm; + this.iv = iv; + } + + public S2k( + HashAlgorithmTag algorithm, + byte[] iv, + int itCount) + { + this.type = 3; + this.algorithm = algorithm; + this.iv = iv; + this.itCount = itCount; + } + + public int Type + { + get { return type; } + } + + /// The hash algorithm. + public HashAlgorithmTag HashAlgorithm + { + get { return algorithm; } + } + + /// The IV for the key generation algorithm. + public byte[] GetIV() + { + return Arrays.Clone(iv); + } + + [Obsolete("Use 'IterationCount' property instead")] + public long GetIterationCount() + { + return IterationCount; + } + + /// The iteration count + public long IterationCount + { + get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); } + } + + /// The protection mode - only if GnuDummyS2K + public int ProtectionMode + { + get { return protectionMode; } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteByte((byte) type); + bcpgOut.WriteByte((byte) algorithm); + + if (type != GnuDummyS2K) + { + if (type != 0) + { + bcpgOut.Write(iv); + } + + if (type == 3) + { + bcpgOut.WriteByte((byte) itCount); + } + } + else + { + bcpgOut.WriteByte((byte) 'G'); + bcpgOut.WriteByte((byte) 'N'); + bcpgOut.WriteByte((byte) 'U'); + bcpgOut.WriteByte((byte) protectionMode); + } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SecretKeyPacket.cs b/iTechSharp/srcbc/bcpg/SecretKeyPacket.cs new file mode 100644 index 0000000..84114f4 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SecretKeyPacket.cs @@ -0,0 +1,163 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for a PGP secret key. + public class SecretKeyPacket + : ContainedPacket //, PublicKeyAlgorithmTag + { + public const int UsageNone = 0x00; + public const int UsageChecksum = 0xff; + public const int UsageSha1 = 0xfe; + + private PublicKeyPacket pubKeyPacket; + private readonly byte[] secKeyData; + private int s2kUsage; + private SymmetricKeyAlgorithmTag encAlgorithm; + private S2k s2k; + private byte[] iv; + + internal SecretKeyPacket( + BcpgInputStream bcpgIn) + { + pubKeyPacket = new PublicKeyPacket(bcpgIn); + + s2kUsage = bcpgIn.ReadByte(); + + if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1) + { + encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte(); + s2k = new S2k(bcpgIn); + } + else + { + encAlgorithm = (SymmetricKeyAlgorithmTag) s2kUsage; + } + + if (!(s2k != null && s2k.Type == S2k.GnuDummyS2K && s2k.ProtectionMode == 0x01)) + { + if (s2kUsage != 0) + { + if (((int) encAlgorithm) < 7) + { + iv = new byte[8]; + } + else + { + iv = new byte[16]; + } + bcpgIn.ReadFully(iv); + } + } + + secKeyData = bcpgIn.ReadAll(); + } + + public SecretKeyPacket( + PublicKeyPacket pubKeyPacket, + SymmetricKeyAlgorithmTag encAlgorithm, + S2k s2k, + byte[] iv, + byte[] secKeyData) + { + this.pubKeyPacket = pubKeyPacket; + this.encAlgorithm = encAlgorithm; + + if (encAlgorithm != SymmetricKeyAlgorithmTag.Null) + { + this.s2kUsage = UsageChecksum; + } + else + { + this.s2kUsage = UsageNone; + } + + this.s2k = s2k; + this.iv = Arrays.Clone(iv); + this.secKeyData = secKeyData; + } + + public SecretKeyPacket( + PublicKeyPacket pubKeyPacket, + SymmetricKeyAlgorithmTag encAlgorithm, + int s2kUsage, + S2k s2k, + byte[] iv, + byte[] secKeyData) + { + this.pubKeyPacket = pubKeyPacket; + this.encAlgorithm = encAlgorithm; + this.s2kUsage = s2kUsage; + this.s2k = s2k; + this.iv = Arrays.Clone(iv); + this.secKeyData = secKeyData; + } + + public SymmetricKeyAlgorithmTag EncAlgorithm + { + get { return encAlgorithm; } + } + + public int S2kUsage + { + get { return s2kUsage; } + } + + public byte[] GetIV() + { + return Arrays.Clone(iv); + } + + public S2k S2k + { + get { return s2k; } + } + + public PublicKeyPacket PublicKeyPacket + { + get { return pubKeyPacket; } + } + + public byte[] GetSecretKeyData() + { + return secKeyData; + } + + public byte[] GetEncodedContents() + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.Write(pubKeyPacket.GetEncodedContents()); + + pOut.WriteByte((byte) s2kUsage); + + if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1) + { + pOut.WriteByte((byte) encAlgorithm); + pOut.WriteObject(s2k); + } + + if (iv != null) + { + pOut.Write(iv); + } + + if (secKeyData != null && secKeyData.Length > 0) + { + pOut.Write(secKeyData); + } + + return bOut.ToArray(); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.SecretKey, GetEncodedContents(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SecretSubkeyPacket.cs b/iTechSharp/srcbc/bcpg/SecretSubkeyPacket.cs new file mode 100644 index 0000000..8f17469 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SecretSubkeyPacket.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic packet for a PGP secret key. + public class SecretSubkeyPacket + : SecretKeyPacket + { + internal SecretSubkeyPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + } + + public SecretSubkeyPacket( + PublicKeyPacket pubKeyPacket, + SymmetricKeyAlgorithmTag encAlgorithm, + S2k s2k, + byte[] iv, + byte[] secKeyData) + : base(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData) + { + } + + public SecretSubkeyPacket( + PublicKeyPacket pubKeyPacket, + SymmetricKeyAlgorithmTag encAlgorithm, + int s2kUsage, + S2k s2k, + byte[] iv, + byte[] secKeyData) + : base(pubKeyPacket, encAlgorithm, s2kUsage, s2k, iv, secKeyData) + { + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.SecretSubkey, GetEncodedContents(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SignaturePacket.cs b/iTechSharp/srcbc/bcpg/SignaturePacket.cs new file mode 100644 index 0000000..c679970 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SignaturePacket.cs @@ -0,0 +1,459 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Bcpg.Sig; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg +{ + /// Generic signature packet. + public class SignaturePacket + : ContainedPacket //, PublicKeyAlgorithmTag + { + private int version; + private int signatureType; + private long creationTime; + private long keyId; + private PublicKeyAlgorithmTag keyAlgorithm; + private HashAlgorithmTag hashAlgorithm; + private MPInteger[] signature; + private byte[] fingerprint; + private SignatureSubpacket[] hashedData; + private SignatureSubpacket[] unhashedData; + private byte[] signatureEncoding; + + internal SignaturePacket( + BcpgInputStream bcpgIn) + { + version = bcpgIn.ReadByte(); + + if (version == 3 || version == 2) + { +// int l = + bcpgIn.ReadByte(); + + signatureType = bcpgIn.ReadByte(); + creationTime = (((long)bcpgIn.ReadByte() << 24) | ((long)bcpgIn.ReadByte() << 16) + | ((long)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte()) * 1000L; + + keyId |= (long)bcpgIn.ReadByte() << 56; + keyId |= (long)bcpgIn.ReadByte() << 48; + keyId |= (long)bcpgIn.ReadByte() << 40; + keyId |= (long)bcpgIn.ReadByte() << 32; + keyId |= (long)bcpgIn.ReadByte() << 24; + keyId |= (long)bcpgIn.ReadByte() << 16; + keyId |= (long)bcpgIn.ReadByte() << 8; + keyId |= (uint)bcpgIn.ReadByte(); + + keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte(); + hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte(); + } + else if (version == 4) + { + signatureType = bcpgIn.ReadByte(); + keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte(); + hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte(); + + int hashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte(); + byte[] hashed = new byte[hashedLength]; + + bcpgIn.ReadFully(hashed); + + // + // read the signature sub packet data. + // + SignatureSubpacketsParser sIn = new SignatureSubpacketsParser( + new MemoryStream(hashed, false)); + + ArrayList v = new ArrayList(); + SignatureSubpacket sub; + while ((sub = sIn.ReadPacket()) != null) + { + v.Add(sub); + } + + hashedData = new SignatureSubpacket[v.Count]; + + for (int i = 0; i != hashedData.Length; i++) + { + SignatureSubpacket p = (SignatureSubpacket)v[i]; + if (p is IssuerKeyId) + { + keyId = ((IssuerKeyId)p).KeyId; + } + else if (p is SignatureCreationTime) + { + creationTime = DateTimeUtilities.DateTimeToUnixMs( + ((SignatureCreationTime)p).GetTime()); + } + + hashedData[i] = p; + } + + int unhashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte(); + byte[] unhashed = new byte[unhashedLength]; + + bcpgIn.ReadFully(unhashed); + + sIn = new SignatureSubpacketsParser(new MemoryStream(unhashed, false)); + + v.Clear(); + + while ((sub = sIn.ReadPacket()) != null) + { + v.Add(sub); + } + + unhashedData = new SignatureSubpacket[v.Count]; + + for (int i = 0; i != unhashedData.Length; i++) + { + SignatureSubpacket p = (SignatureSubpacket)v[i]; + if (p is IssuerKeyId) + { + keyId = ((IssuerKeyId)p).KeyId; + } + else if (p is SignatureCreationTime) + { + creationTime = DateTimeUtilities.DateTimeToUnixMs( + ((SignatureCreationTime)p).GetTime()); + } + + unhashedData[i] = p; + } + } + else + { + throw new Exception("unsupported version: " + version); + } + + fingerprint = new byte[2]; + bcpgIn.ReadFully(fingerprint); + + switch (keyAlgorithm) + { + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + MPInteger v = new MPInteger(bcpgIn); + signature = new MPInteger[]{ v }; + break; + case PublicKeyAlgorithmTag.Dsa: + MPInteger r = new MPInteger(bcpgIn); + MPInteger s = new MPInteger(bcpgIn); + signature = new MPInteger[]{ r, s }; + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes. + case PublicKeyAlgorithmTag.ElGamalGeneral: + MPInteger p = new MPInteger(bcpgIn); + MPInteger g = new MPInteger(bcpgIn); + MPInteger y = new MPInteger(bcpgIn); + signature = new MPInteger[]{ p, g, y }; + break; + default: + if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11) + { + signature = null; + MemoryStream bOut = new MemoryStream(); + int ch; + while ((ch = bcpgIn.ReadByte()) >= 0) + { + bOut.WriteByte((byte) ch); + } + signatureEncoding = bOut.ToArray(); + } + else + { + throw new IOException("unknown signature key algorithm: " + keyAlgorithm); + } + break; + } + } + + /** + * Generate a version 4 signature packet. + * + * @param signatureType + * @param keyAlgorithm + * @param hashAlgorithm + * @param hashedData + * @param unhashedData + * @param fingerprint + * @param signature + */ + public SignaturePacket( + int signatureType, + long keyId, + PublicKeyAlgorithmTag keyAlgorithm, + HashAlgorithmTag hashAlgorithm, + SignatureSubpacket[] hashedData, + SignatureSubpacket[] unhashedData, + byte[] fingerprint, + MPInteger[] signature) + : this(4, signatureType, keyId, keyAlgorithm, hashAlgorithm, hashedData, unhashedData, fingerprint, signature) + { + } + + /** + * Generate a version 2/3 signature packet. + * + * @param signatureType + * @param keyAlgorithm + * @param hashAlgorithm + * @param fingerprint + * @param signature + */ + public SignaturePacket( + int version, + int signatureType, + long keyId, + PublicKeyAlgorithmTag keyAlgorithm, + HashAlgorithmTag hashAlgorithm, + long creationTime, + byte[] fingerprint, + MPInteger[] signature) + : this(version, signatureType, keyId, keyAlgorithm, hashAlgorithm, null, null, fingerprint, signature) + { + this.creationTime = creationTime; + } + + public SignaturePacket( + int version, + int signatureType, + long keyId, + PublicKeyAlgorithmTag keyAlgorithm, + HashAlgorithmTag hashAlgorithm, + SignatureSubpacket[] hashedData, + SignatureSubpacket[] unhashedData, + byte[] fingerprint, + MPInteger[] signature) + { + this.version = version; + this.signatureType = signatureType; + this.keyId = keyId; + this.keyAlgorithm = keyAlgorithm; + this.hashAlgorithm = hashAlgorithm; + this.hashedData = hashedData; + this.unhashedData = unhashedData; + this.fingerprint = fingerprint; + this.signature = signature; + } + + public int Version + { + get { return version; } + } + + public int SignatureType + { + get { return signatureType; } + } + + /** + * return the keyId + * @return the keyId that created the signature. + */ + public long KeyId + { + get { return keyId; } + } + + /** + * return the signature trailer that must be included with the data + * to reconstruct the signature + * + * @return byte[] + */ + public byte[] GetSignatureTrailer() + { + byte[] trailer = null; + + if (version == 3) + { + trailer = new byte[5]; + + long time = creationTime / 1000L; + + trailer[0] = (byte)signatureType; + trailer[1] = (byte)(time >> 24); + trailer[2] = (byte)(time >> 16); + trailer[3] = (byte)(time >> 8); + trailer[4] = (byte)(time); + } + else + { + MemoryStream sOut = new MemoryStream(); + + sOut.WriteByte((byte)this.Version); + sOut.WriteByte((byte)this.SignatureType); + sOut.WriteByte((byte)this.KeyAlgorithm); + sOut.WriteByte((byte)this.HashAlgorithm); + + MemoryStream hOut = new MemoryStream(); + SignatureSubpacket[] hashed = this.GetHashedSubPackets(); + + for (int i = 0; i != hashed.Length; i++) + { + hashed[i].Encode(hOut); + } + + byte[] data = hOut.ToArray(); + + sOut.WriteByte((byte)(data.Length >> 8)); + sOut.WriteByte((byte)data.Length); + sOut.Write(data, 0, data.Length); + + byte[] hData = sOut.ToArray(); + + sOut.WriteByte((byte)this.Version); + sOut.WriteByte((byte)0xff); + sOut.WriteByte((byte)(hData.Length>> 24)); + sOut.WriteByte((byte)(hData.Length >> 16)); + sOut.WriteByte((byte)(hData.Length >> 8)); + sOut.WriteByte((byte)(hData.Length)); + + trailer = sOut.ToArray(); + } + + return trailer; + } + + public PublicKeyAlgorithmTag KeyAlgorithm + { + get { return keyAlgorithm; } + } + + public HashAlgorithmTag HashAlgorithm + { + get { return hashAlgorithm; } + } + + /** + * return the signature as a set of integers - note this is normalised to be the + * ASN.1 encoding of what appears in the signature packet. + */ + public MPInteger[] GetSignature() + { + return signature; + } + + /** + * Return the byte encoding of the signature section. + * @return uninterpreted signature bytes. + */ + public byte[] GetSignatureBytes() + { + if (signatureEncoding != null) + { + return (byte[]) signatureEncoding.Clone(); + } + + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream bcOut = new BcpgOutputStream(bOut); + + foreach (MPInteger sigObj in signature) + { + try + { + bcOut.WriteObject(sigObj); + } + catch (IOException e) + { + throw new Exception("internal error: " + e); + } + } + + return bOut.ToArray(); + } + + public SignatureSubpacket[] GetHashedSubPackets() + { + return hashedData; + } + + public SignatureSubpacket[] GetUnhashedSubPackets() + { + return unhashedData; + } + + /// Return the creation time in milliseconds since 1 Jan., 1970 UTC. + public long CreationTime + { + get { return creationTime; } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WriteByte((byte) version); + + if (version == 3 || version == 2) + { + pOut.Write( + 5, // the length of the next block + (byte) signatureType); + + pOut.WriteInt((int)(creationTime / 1000L)); + + pOut.WriteLong(keyId); + + pOut.Write( + (byte) keyAlgorithm, + (byte) hashAlgorithm); + } + else if (version == 4) + { + pOut.Write( + (byte) signatureType, + (byte) keyAlgorithm, + (byte) hashAlgorithm); + + EncodeLengthAndData(pOut, GetEncodedSubpackets(hashedData)); + + EncodeLengthAndData(pOut, GetEncodedSubpackets(unhashedData)); + } + else + { + throw new IOException("unknown version: " + version); + } + + pOut.Write(fingerprint); + + if (signature != null) + { + pOut.WriteObjects(signature); + } + else + { + pOut.Write(signatureEncoding); + } + + bcpgOut.WritePacket(PacketTag.Signature, bOut.ToArray(), true); + } + + private static void EncodeLengthAndData( + BcpgOutputStream pOut, + byte[] data) + { + pOut.WriteShort((short) data.Length); + pOut.Write(data); + } + + private static byte[] GetEncodedSubpackets( + SignatureSubpacket[] ps) + { + MemoryStream sOut = new MemoryStream(); + + foreach (SignatureSubpacket p in ps) + { + p.Encode(sOut); + } + + return sOut.ToArray(); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SignatureSubpacket.cs b/iTechSharp/srcbc/bcpg/SignatureSubpacket.cs new file mode 100644 index 0000000..ac26f8a --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SignatureSubpacket.cs @@ -0,0 +1,76 @@ +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic type for a PGP Signature sub-packet. + public class SignatureSubpacket + { + private readonly SignatureSubpacketTag type; + private readonly bool critical; + + internal readonly byte[] data; + + protected internal SignatureSubpacket( + SignatureSubpacketTag type, + bool critical, + byte[] data) + { + this.type = type; + this.critical = critical; + this.data = data; + } + + public SignatureSubpacketTag SubpacketType + { + get { return type; } + } + + public bool IsCritical() + { + return critical; + } + + /// Return the generic data making up the packet. + public byte[] GetData() + { + return (byte[]) data.Clone(); + } + + public void Encode( + Stream os) + { + int bodyLen = data.Length + 1; + + if (bodyLen < 192) + { + os.WriteByte((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192)); + os.WriteByte((byte)bodyLen); + } + else + { + os.WriteByte(0xff); + os.WriteByte((byte)(bodyLen >> 24)); + os.WriteByte((byte)(bodyLen >> 16)); + os.WriteByte((byte)(bodyLen >> 8)); + os.WriteByte((byte)bodyLen); + } + + if (critical) + { + os.WriteByte((byte)(0x80 | (int) type)); + } + else + { + os.WriteByte((byte) type); + } + + os.Write(data, 0, data.Length); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SignatureSubpacketTags.cs b/iTechSharp/srcbc/bcpg/SignatureSubpacketTags.cs new file mode 100644 index 0000000..1aa2480 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SignatureSubpacketTags.cs @@ -0,0 +1,30 @@ +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic PGP signature sub-packet tag types. + */ + public enum SignatureSubpacketTag + { + CreationTime = 2, // signature creation time + ExpireTime = 3, // signature expiration time + Exportable = 4, // exportable certification + TrustSig = 5, // trust signature + RegExp = 6, // regular expression + Revocable = 7, // revocable + KeyExpireTime = 9, // key expiration time + Placeholder = 10, // placeholder for backward compatibility + PreferredSymmetricAlgorithms = 11, // preferred symmetric algorithms + RevocationKey = 12, // revocation key + IssuerKeyId = 16, // issuer key ID + NotationData = 20, // notation data + PreferredHashAlgorithms = 21, // preferred hash algorithms + PreferredCompressionAlgorithms = 22, // preferred compression algorithms + KeyServerPreferences = 23, // key server preferences + PreferredKeyServer = 24, // preferred key server + PrimaryUserId = 25, // primary user id + PolicyUrl = 26, // policy URL + KeyFlags = 27, // key flags + SignerUserId = 28, // signer's user id + RevocationReason = 29 // reason for revocation + } +} diff --git a/iTechSharp/srcbc/bcpg/SignatureSubpacketsReader.cs b/iTechSharp/srcbc/bcpg/SignatureSubpacketsReader.cs new file mode 100644 index 0000000..8dd1af3 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SignatureSubpacketsReader.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using Org.BouncyCastle.Bcpg.Sig; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * reader for signature sub-packets + */ + public class SignatureSubpacketsParser + { + private readonly Stream input; + + public SignatureSubpacketsParser( + Stream input) + { + this.input = input; + } + + public SignatureSubpacket ReadPacket() + { + int l = input.ReadByte(); + if (l < 0) + return null; + + int bodyLen = 0; + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192; + } + else if (l == 255) + { + bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16) + | (input.ReadByte() << 8) | input.ReadByte(); + } + else + { + // TODO Error? + } + + int tag = input.ReadByte(); + if (tag < 0) + throw new EndOfStreamException("unexpected EOF reading signature sub packet"); + + byte[] data = new byte[bodyLen - 1]; + if (Streams.ReadFully(input, data) < data.Length) + throw new EndOfStreamException(); + + bool isCritical = ((tag & 0x80) != 0); + SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f); + switch (type) + { + case SignatureSubpacketTag.CreationTime: + return new SignatureCreationTime(isCritical, data); + case SignatureSubpacketTag.KeyExpireTime: + return new KeyExpirationTime(isCritical, data); + case SignatureSubpacketTag.ExpireTime: + return new SignatureExpirationTime(isCritical, data); + case SignatureSubpacketTag.Revocable: + return new Revocable(isCritical, data); + case SignatureSubpacketTag.Exportable: + return new Exportable(isCritical, data); + case SignatureSubpacketTag.IssuerKeyId: + return new IssuerKeyId(isCritical, data); + case SignatureSubpacketTag.TrustSig: + return new TrustSignature(isCritical, data); + case SignatureSubpacketTag.PreferredCompressionAlgorithms: + case SignatureSubpacketTag.PreferredHashAlgorithms: + case SignatureSubpacketTag.PreferredSymmetricAlgorithms: + return new PreferredAlgorithms(type, isCritical, data); + case SignatureSubpacketTag.KeyFlags: + return new KeyFlags(isCritical, data); + case SignatureSubpacketTag.PrimaryUserId: + return new PrimaryUserId(isCritical, data); + case SignatureSubpacketTag.SignerUserId: + return new SignerUserId(isCritical, data); + case SignatureSubpacketTag.NotationData: + return new NotationData(isCritical, data); + } + return new SignatureSubpacket(type, isCritical, data); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SymmetricEncDataPacket.cs b/iTechSharp/srcbc/bcpg/SymmetricEncDataPacket.cs new file mode 100644 index 0000000..17ee55b --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SymmetricEncDataPacket.cs @@ -0,0 +1,15 @@ +using System; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic type for a symmetric key encrypted packet. + public class SymmetricEncDataPacket + : InputStreamPacket + { + public SymmetricEncDataPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SymmetricEncIntegrityPacket.cs b/iTechSharp/srcbc/bcpg/SymmetricEncIntegrityPacket.cs new file mode 100644 index 0000000..a9b6d06 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SymmetricEncIntegrityPacket.cs @@ -0,0 +1,18 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + public class SymmetricEncIntegrityPacket + : InputStreamPacket + { + internal readonly int version; + + internal SymmetricEncIntegrityPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + version = bcpgIn.ReadByte(); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/SymmetricKeyAlgorithmTags.cs b/iTechSharp/srcbc/bcpg/SymmetricKeyAlgorithmTags.cs new file mode 100644 index 0000000..7633b1d --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SymmetricKeyAlgorithmTags.cs @@ -0,0 +1,20 @@ +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic tags for symmetric key algorithms + */ + public enum SymmetricKeyAlgorithmTag + { + Null = 0, // Plaintext or unencrypted data + Idea = 1, // IDEA [IDEA] + TripleDes = 2, // Triple-DES (DES-EDE, as per spec -168 bit key derived from 192) + Cast5 = 3, // Cast5 (128 bit key, as per RFC 2144) + Blowfish = 4, // Blowfish (128 bit key, 16 rounds) [Blowfish] + Safer = 5, // Safer-SK128 (13 rounds) [Safer] + Des = 6, // Reserved for DES/SK + Aes128 = 7, // Reserved for AES with 128-bit key + Aes192 = 8, // Reserved for AES with 192-bit key + Aes256 = 9, // Reserved for AES with 256-bit key + Twofish = 10 // Reserved for Twofish + } +} diff --git a/iTechSharp/srcbc/bcpg/SymmetricKeyEncSessionPacket.cs b/iTechSharp/srcbc/bcpg/SymmetricKeyEncSessionPacket.cs new file mode 100644 index 0000000..0381fa3 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/SymmetricKeyEncSessionPacket.cs @@ -0,0 +1,91 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic type for a symmetric encrypted session key packet + */ + public class SymmetricKeyEncSessionPacket + : ContainedPacket + { + private int version; + private SymmetricKeyAlgorithmTag encAlgorithm; + private S2k s2k; + private readonly byte[] secKeyData; + + public SymmetricKeyEncSessionPacket( + BcpgInputStream bcpgIn) + { + version = bcpgIn.ReadByte(); + encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte(); + + s2k = new S2k(bcpgIn); + + secKeyData = bcpgIn.ReadAll(); + } + + public SymmetricKeyEncSessionPacket( + SymmetricKeyAlgorithmTag encAlgorithm, + S2k s2k, + byte[] secKeyData) + { + this.version = 4; + this.encAlgorithm = encAlgorithm; + this.s2k = s2k; + this.secKeyData = secKeyData; + } + + /** + * @return int + */ + public SymmetricKeyAlgorithmTag EncAlgorithm + { + get { return encAlgorithm; } + } + + /** + * @return S2k + */ + public S2k S2k + { + get { return s2k; } + } + + /** + * @return byte[] + */ + public byte[] GetSecKeyData() + { + return secKeyData; + } + + /** + * @return int + */ + public int Version + { + get { return version; } + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.Write( + (byte) version, + (byte) encAlgorithm); + + pOut.WriteObject(s2k); + + if (secKeyData != null && secKeyData.Length > 0) + { + pOut.Write(secKeyData); + } + + bcpgOut.WritePacket(PacketTag.SymmetricKeyEncryptedSessionKey, bOut.ToArray(), true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/TrustPacket.cs b/iTechSharp/srcbc/bcpg/TrustPacket.cs new file mode 100644 index 0000000..6f1969c --- /dev/null +++ b/iTechSharp/srcbc/bcpg/TrustPacket.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /// Basic type for a trust packet. + public class TrustPacket + : ContainedPacket + { + private readonly byte[] levelAndTrustAmount; + + public TrustPacket( + BcpgInputStream bcpgIn) + { + MemoryStream bOut = new MemoryStream(); + + int ch; + while ((ch = bcpgIn.ReadByte()) >= 0) + { + bOut.WriteByte((byte) ch); + } + + levelAndTrustAmount = bOut.ToArray(); + } + + public TrustPacket( + int trustCode) + { + this.levelAndTrustAmount = new byte[]{ (byte) trustCode }; + } + + public byte[] GetLevelAndTrustAmount() + { + return (byte[]) levelAndTrustAmount.Clone(); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.Trust, levelAndTrustAmount, true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/UserAttributePacket.cs b/iTechSharp/srcbc/bcpg/UserAttributePacket.cs new file mode 100644 index 0000000..c0501c5 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/UserAttributePacket.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic type for a user attribute packet. + */ + public class UserAttributePacket + : ContainedPacket + { + private readonly UserAttributeSubpacket[] subpackets; + + public UserAttributePacket( + BcpgInputStream bcpgIn) + { + UserAttributeSubpacketsParser sIn = new UserAttributeSubpacketsParser(bcpgIn); + UserAttributeSubpacket sub; + + ArrayList v = new ArrayList(); + while ((sub = sIn.ReadPacket()) != null) + { + v.Add(sub); + } + + subpackets = new UserAttributeSubpacket[v.Count]; + + for (int i = 0; i != subpackets.Length; i++) + { + subpackets[i] = (UserAttributeSubpacket)v[i]; + } + } + + public UserAttributePacket( + UserAttributeSubpacket[] subpackets) + { + this.subpackets = subpackets; + } + + public UserAttributeSubpacket[] GetSubpackets() + { + return subpackets; + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + MemoryStream bOut = new MemoryStream(); + + for (int i = 0; i != subpackets.Length; i++) + { + subpackets[i].Encode(bOut); + } + + bcpgOut.WritePacket(PacketTag.UserAttribute, bOut.ToArray(), false); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/UserAttributeSubpacket.cs b/iTechSharp/srcbc/bcpg/UserAttributeSubpacket.cs new file mode 100644 index 0000000..bd49d21 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/UserAttributeSubpacket.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic type for a user attribute sub-packet. + */ + public class UserAttributeSubpacket + { + private readonly UserAttributeSubpacketTag type; + private readonly byte[] data; + + internal UserAttributeSubpacket( + UserAttributeSubpacketTag type, + byte[] data) + { + this.type = type; + this.data = data; + } + + public UserAttributeSubpacketTag SubpacketType + { + get { return type; } + } + + /** + * return the generic data making up the packet. + */ + public byte[] GetData() + { + return data; + } + + public void Encode( + Stream os) + { + int bodyLen = data.Length + 1; + + if (bodyLen < 192) + { + os.WriteByte((byte)bodyLen); + } + else if (bodyLen <= 8383) + { + bodyLen -= 192; + + os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192)); + os.WriteByte((byte)bodyLen); + } + else + { + os.WriteByte(0xff); + os.WriteByte((byte)(bodyLen >> 24)); + os.WriteByte((byte)(bodyLen >> 16)); + os.WriteByte((byte)(bodyLen >> 8)); + os.WriteByte((byte)bodyLen); + } + + os.WriteByte((byte) type); + os.Write(data, 0, data.Length); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + UserAttributeSubpacket other = obj as UserAttributeSubpacket; + + if (other == null) + return false; + + return type == other.type + && Arrays.AreEqual(data, other.data); + } + + public override int GetHashCode() + { + return type.GetHashCode() ^ Arrays.GetHashCode(data); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/UserAttributeSubpacketTags.cs b/iTechSharp/srcbc/bcpg/UserAttributeSubpacketTags.cs new file mode 100644 index 0000000..7a9cd1d --- /dev/null +++ b/iTechSharp/srcbc/bcpg/UserAttributeSubpacketTags.cs @@ -0,0 +1,10 @@ +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic PGP user attribute sub-packet tag types. + */ + public enum UserAttributeSubpacketTag + { + ImageAttribute = 1 + } +} diff --git a/iTechSharp/srcbc/bcpg/UserAttributeSubpacketsReader.cs b/iTechSharp/srcbc/bcpg/UserAttributeSubpacketsReader.cs new file mode 100644 index 0000000..2e5ea0f --- /dev/null +++ b/iTechSharp/srcbc/bcpg/UserAttributeSubpacketsReader.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using Org.BouncyCastle.Bcpg.Attr; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * reader for user attribute sub-packets + */ + public class UserAttributeSubpacketsParser + { + private readonly Stream input; + + public UserAttributeSubpacketsParser( + Stream input) + { + this.input = input; + } + + public UserAttributeSubpacket ReadPacket() + { + int l = input.ReadByte(); + if (l < 0) + return null; + + int bodyLen = 0; + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192; + } + else if (l == 255) + { + bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16) + | (input.ReadByte() << 8) | input.ReadByte(); + } + else + { + // TODO Error? + } + + int tag = input.ReadByte(); + if (tag < 0) + throw new EndOfStreamException("unexpected EOF reading user attribute sub packet"); + + byte[] data = new byte[bodyLen - 1]; + if (Streams.ReadFully(input, data) < data.Length) + throw new EndOfStreamException(); + + UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag; + switch (type) + { + case UserAttributeSubpacketTag.ImageAttribute: + return new ImageAttrib(data); + } + return new UserAttributeSubpacket(type, data); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/UserIdPacket.cs b/iTechSharp/srcbc/bcpg/UserIdPacket.cs new file mode 100644 index 0000000..a175e74 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/UserIdPacket.cs @@ -0,0 +1,37 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic type for a user ID packet. + */ + public class UserIdPacket + : ContainedPacket + { + private readonly byte[] idData; + + public UserIdPacket( + BcpgInputStream bcpgIn) + { + this.idData = bcpgIn.ReadAll(); + } + + public UserIdPacket( + string id) + { + this.idData = Encoding.UTF8.GetBytes(id); + } + + public string GetId() + { + return Encoding.UTF8.GetString(idData, 0, idData.Length); + } + + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.UserId, idData, true); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/attr/ImageAttrib.cs b/iTechSharp/srcbc/bcpg/attr/ImageAttrib.cs new file mode 100644 index 0000000..7349079 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/attr/ImageAttrib.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Bcpg.Attr +{ + /// Basic type for a image attribute packet. + public class ImageAttrib + : UserAttributeSubpacket + { + public enum Format : byte + { + Jpeg = 1 + } + + private static readonly byte[] Zeroes = new byte[12]; + + private int hdrLength; + private int _version; + private int _encoding; + private byte[] imageData; + + public ImageAttrib( + byte[] data) + : base(UserAttributeSubpacketTag.ImageAttribute, data) + { + hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff); + _version = data[2] & 0xff; + _encoding = data[3] & 0xff; + + imageData = new byte[data.Length - hdrLength]; + Array.Copy(data, hdrLength, imageData, 0, imageData.Length); + } + + public ImageAttrib( + Format imageType, + byte[] imageData) + : this(ToByteArray(imageType, imageData)) + { + } + + private static byte[] ToByteArray( + Format imageType, + byte[] imageData) + { + MemoryStream bOut = new MemoryStream(); + bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01); + bOut.WriteByte((byte) imageType); + bOut.Write(Zeroes, 0, Zeroes.Length); + bOut.Write(imageData, 0, imageData.Length); + return bOut.ToArray(); + } + + public int Version + { + get { return _version; } + } + + public int Encoding + { + get { return _encoding; } + } + + public byte[] GetImageData() + { + return imageData; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/Exportable.cs b/iTechSharp/srcbc/bcpg/sig/Exportable.cs new file mode 100644 index 0000000..4455c38 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/Exportable.cs @@ -0,0 +1,47 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature creation time. + */ + public class Exportable + : SignatureSubpacket + { + private static byte[] BooleanToByteArray(bool val) + { + byte[] data = new byte[1]; + + if (val) + { + data[0] = 1; + return data; + } + else + { + return data; + } + } + + public Exportable( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.Exportable, critical, data) + { + } + + public Exportable( + bool critical, + bool isExportable) + : base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable)) + { + } + + public bool IsExportable() + { + return data[0] != 0; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/IssuerKeyId.cs b/iTechSharp/srcbc/bcpg/sig/IssuerKeyId.cs new file mode 100644 index 0000000..91490d3 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/IssuerKeyId.cs @@ -0,0 +1,61 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature creation time. + */ + public class IssuerKeyId + : SignatureSubpacket + { + protected static byte[] KeyIdToBytes( + long keyId) + { + byte[] data = new byte[8]; + + data[0] = (byte)(keyId >> 56); + data[1] = (byte)(keyId >> 48); + data[2] = (byte)(keyId >> 40); + data[3] = (byte)(keyId >> 32); + data[4] = (byte)(keyId >> 24); + data[5] = (byte)(keyId >> 16); + data[6] = (byte)(keyId >> 8); + data[7] = (byte)keyId; + + return data; + } + + public IssuerKeyId( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.IssuerKeyId, critical, data) + { + } + + public IssuerKeyId( + bool critical, + long keyId) + : base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId)) + { + } + + public long KeyId + { + get + { + long keyId = ((long)(data[0] & 0xff) << 56) + | ((long)(data[1] & 0xff) << 48) + | ((long)(data[2] & 0xff) << 40) + | ((long)(data[3] & 0xff) << 32) + | ((long)(data[4] & 0xff) << 24) + | ((long)(data[5] & 0xff) << 16) + | ((long)(data[6] & 0xff) << 8) + | ((long)data[7] & 0xff); + + return keyId; + } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/KeyExpirationTime.cs b/iTechSharp/srcbc/bcpg/sig/KeyExpirationTime.cs new file mode 100644 index 0000000..23b4cac --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/KeyExpirationTime.cs @@ -0,0 +1,56 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving time after creation at which the key expires. + */ + public class KeyExpirationTime + : SignatureSubpacket + { + protected static byte[] TimeToBytes( + long t) + { + byte[] data = new byte[4]; + + data[0] = (byte)(t >> 24); + data[1] = (byte)(t >> 16); + data[2] = (byte)(t >> 8); + data[3] = (byte)t; + + return data; + } + + public KeyExpirationTime( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.KeyExpireTime, critical, data) + { + } + + public KeyExpirationTime( + bool critical, + long seconds) + : base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds)) + { + } + + /** + * Return the number of seconds after creation time a key is valid for. + * + * @return second count for key validity. + */ + public long Time + { + get + { + long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16) + | ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff); + + return time; + } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/KeyFlags.cs b/iTechSharp/srcbc/bcpg/sig/KeyFlags.cs new file mode 100644 index 0000000..9c4b6d5 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/KeyFlags.cs @@ -0,0 +1,36 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * Packet holding the key flag values. + */ + public class KeyFlags + : SignatureSubpacket + { + private static byte[] IntToByteArray( + int v) + { + return new byte[]{ (byte) v }; + } + + public KeyFlags( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.KeyFlags, critical, data) + { + } + + public KeyFlags( + bool critical, + int flags) + : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags)) + { + } + + public int Flags + { + get { return data[0] & 0xff; } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/NotationData.cs b/iTechSharp/srcbc/bcpg/sig/NotationData.cs new file mode 100644 index 0000000..1c2c804 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/NotationData.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; +using System.Text; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * Class provided a NotationData object according to + * RFC2440, Chapter 5.2.3.15. Notation Data + */ + public class NotationData + : SignatureSubpacket + { + public const int HeaderFlagLength = 4; + public const int HeaderNameLength = 2; + public const int HeaderValueLength = 2; + + public NotationData( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.NotationData, critical, data) + { + } + + public NotationData( + bool critical, + bool humanReadable, + string notationName, + string notationValue) + : base(SignatureSubpacketTag.NotationData, critical, + createData(humanReadable, notationName, notationValue)) + { + } + + private static byte[] createData( + bool humanReadable, + string notationName, + string notationValue) + { + MemoryStream os = new MemoryStream(); + + // (4 octets of flags, 2 octets of name length (M), + // 2 octets of value length (N), + // M octets of name data, + // N octets of value data) + + // flags + os.WriteByte(humanReadable ? (byte)0x80 : (byte)0x00); + os.WriteByte(0x0); + os.WriteByte(0x0); + os.WriteByte(0x0); + + byte[] nameData, valueData = null; + int nameLength, valueLength; + + nameData = Encoding.UTF8.GetBytes(notationName); + nameLength = System.Math.Min(nameData.Length, 0xFF); + + valueData = Encoding.UTF8.GetBytes(notationValue); + valueLength = System.Math.Min(valueData.Length, 0xFF); + + // name length + os.WriteByte((byte)(nameLength >> 8)); + os.WriteByte((byte)(nameLength >> 0)); + + // value length + os.WriteByte((byte)(valueLength >> 8)); + os.WriteByte((byte)(valueLength >> 0)); + + // name + os.Write(nameData, 0, nameLength); + + // value + os.Write(valueData, 0, valueLength); + + return os.ToArray(); + } + + public bool IsHumanReadable + { + get { return data[0] == (byte)0x80; } + } + + public string GetNotationName() + { + int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); + int namePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength; + + return Encoding.UTF8.GetString(data, namePos, nameLength); + } + + public string GetNotationValue() + { + int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); + int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0)); + int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength; + + return Encoding.UTF8.GetString(data, valuePos, valueLength); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/PreferredAlgorithms.cs b/iTechSharp/srcbc/bcpg/sig/PreferredAlgorithms.cs new file mode 100644 index 0000000..0f282a3 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/PreferredAlgorithms.cs @@ -0,0 +1,54 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature creation time. + */ + public class PreferredAlgorithms + : SignatureSubpacket + { + private static byte[] IntToByteArray( + int[] v) + { + byte[] data = new byte[v.Length]; + + for (int i = 0; i != v.Length; i++) + { + data[i] = (byte)v[i]; + } + + return data; + } + + public PreferredAlgorithms( + SignatureSubpacketTag type, + bool critical, + byte[] data) + : base(type, critical, data) + { + } + + public PreferredAlgorithms( + SignatureSubpacketTag type, + bool critical, + int[] preferences) + : base(type, critical, IntToByteArray(preferences)) + { + } + + public int[] GetPreferences() + { + int[] v = new int[data.Length]; + + for (int i = 0; i != v.Length; i++) + { + v[i] = data[i] & 0xff; + } + + return v; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/PrimaryUserId.cs b/iTechSharp/srcbc/bcpg/sig/PrimaryUserId.cs new file mode 100644 index 0000000..fc0353a --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/PrimaryUserId.cs @@ -0,0 +1,48 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving whether or not the signature is signed using the primary user ID for the key. + */ + public class PrimaryUserId + : SignatureSubpacket + { + private static byte[] BooleanToByteArray( + bool val) + { + byte[] data = new byte[1]; + + if (val) + { + data[0] = 1; + return data; + } + else + { + return data; + } + } + + public PrimaryUserId( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.PrimaryUserId, critical, data) + { + } + + public PrimaryUserId( + bool critical, + bool isPrimaryUserId) + : base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId)) + { + } + + public bool IsPrimaryUserId() + { + return data[0] != 0; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/Revocable.cs b/iTechSharp/srcbc/bcpg/sig/Revocable.cs new file mode 100644 index 0000000..b5e94fe --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/Revocable.cs @@ -0,0 +1,48 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving whether or not is revocable. + */ + public class Revocable + : SignatureSubpacket + { + private static byte[] BooleanToByteArray( + bool value) + { + byte[] data = new byte[1]; + + if (value) + { + data[0] = 1; + return data; + } + else + { + return data; + } + } + + public Revocable( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.Revocable, critical, data) + { + } + + public Revocable( + bool critical, + bool isRevocable) + : base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable)) + { + } + + public bool IsRevocable() + { + return data[0] != 0; + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/SignatureCreationTime.cs b/iTechSharp/srcbc/bcpg/sig/SignatureCreationTime.cs new file mode 100644 index 0000000..e6f241f --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/SignatureCreationTime.cs @@ -0,0 +1,47 @@ +using System; + +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature creation time. + */ + public class SignatureCreationTime + : SignatureSubpacket + { + protected static byte[] TimeToBytes( + DateTime time) + { + long t = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L; + byte[] data = new byte[4]; + data[0] = (byte)(t >> 24); + data[1] = (byte)(t >> 16); + data[2] = (byte)(t >> 8); + data[3] = (byte)t; + return data; + } + public SignatureCreationTime( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.CreationTime, critical, data) + { + } + public SignatureCreationTime( + bool critical, + DateTime date) + : base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date)) + { + } + public DateTime GetTime() + { + long time = (long)( + ((uint)data[0] << 24) + | ((uint)data[1] << 16) + | ((uint)data[2] << 8) + | ((uint)data[3]) + ); + return DateTimeUtilities.UnixMsToDateTime(time * 1000L); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/SignatureExpirationTime.cs b/iTechSharp/srcbc/bcpg/sig/SignatureExpirationTime.cs new file mode 100644 index 0000000..7fddf57 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/SignatureExpirationTime.cs @@ -0,0 +1,54 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature expiration time. + */ + public class SignatureExpirationTime + : SignatureSubpacket + { + protected static byte[] TimeToBytes( + long t) + { + byte[] data = new byte[4]; + + data[0] = (byte)(t >> 24); + data[1] = (byte)(t >> 16); + data[2] = (byte)(t >> 8); + data[3] = (byte)t; + + return data; + } + + public SignatureExpirationTime( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.ExpireTime, critical, data) + { + } + + public SignatureExpirationTime( + bool critical, + long seconds) + : base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds)) + { + } + + /** + * return time in seconds before signature expires after creation time. + */ + public long Time + { + get + { + long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16) + | ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff); + + return time; + } + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/SignerUserId.cs b/iTechSharp/srcbc/bcpg/sig/SignerUserId.cs new file mode 100644 index 0000000..98cc808 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/SignerUserId.cs @@ -0,0 +1,52 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving the User ID of the signer. + */ + public class SignerUserId + : SignatureSubpacket + { + private static byte[] UserIdToBytes( + string id) + { + byte[] idData = new byte[id.Length]; + + for (int i = 0; i != id.Length; i++) + { + idData[i] = (byte)id[i]; + } + + return idData; + } + + public SignerUserId( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.SignerUserId, critical, data) + { + } + + public SignerUserId( + bool critical, + string userId) + : base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId)) + { + } + + public string GetId() + { + char[] chars = new char[data.Length]; + + for (int i = 0; i != chars.Length; i++) + { + chars[i] = (char)(data[i] & 0xff); + } + + return new string(chars); + } + } +} diff --git a/iTechSharp/srcbc/bcpg/sig/TrustSignature.cs b/iTechSharp/srcbc/bcpg/sig/TrustSignature.cs new file mode 100644 index 0000000..46d2db2 --- /dev/null +++ b/iTechSharp/srcbc/bcpg/sig/TrustSignature.cs @@ -0,0 +1,56 @@ +using System; + + + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving signature creation time. + */ + public class TrustSignature + : SignatureSubpacket + { + private static byte[] IntToByteArray( + int v1, + int v2) + { + byte[] data = new byte[2]; + + data[0] = (byte)v1; + data[1] = (byte)v2; + + return data; + } + + public TrustSignature( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.TrustSig, critical, data) + { + } + + public TrustSignature( + bool critical, + int depth, + int trustAmount) + : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount)) + { + } + + public int Depth + { + get + { + return data[0] & 0xff; + } + } + + public int TrustAmount + { + get + { + return data[1] & 0xff; + } + } + } +} diff --git a/iTechSharp/srcbc/cms/BaseDigestCalculator.cs b/iTechSharp/srcbc/cms/BaseDigestCalculator.cs new file mode 100644 index 0000000..3dcbca7 --- /dev/null +++ b/iTechSharp/srcbc/cms/BaseDigestCalculator.cs @@ -0,0 +1,23 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Cms +{ + internal class BaseDigestCalculator + : IDigestCalculator + { + private readonly byte[] digest; + + internal BaseDigestCalculator( + byte[] digest) + { + this.digest = digest; + } + + public byte[] GetDigest() + { + return Arrays.Clone(digest); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSAttributeTableGenerationException.cs b/iTechSharp/srcbc/cms/CMSAttributeTableGenerationException.cs new file mode 100644 index 0000000..2bc8ce5 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSAttributeTableGenerationException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Cms +{ + public class CmsAttributeTableGenerationException + : CmsException + { + public CmsAttributeTableGenerationException() + { + } + + public CmsAttributeTableGenerationException( + string name) + : base(name) + { + } + + public CmsAttributeTableGenerationException( + string name, + Exception e) + : base(name, e) + { + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSAttributeTableGenerator.cs b/iTechSharp/srcbc/cms/CMSAttributeTableGenerator.cs new file mode 100644 index 0000000..92c9a29 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSAttributeTableGenerator.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.Cms; + +namespace Org.BouncyCastle.Cms +{ + /// + /// The 'Signature' parameter is only available when generating unsigned attributes. + /// + public enum CmsAttributeTableParameter + { +// const string ContentType = "contentType"; +// const string Digest = "digest"; +// const string Signature = "encryptedDigest"; +// const string DigestAlgorithmIdentifier = "digestAlgID"; + + ContentType, Digest, Signature, DigestAlgorithmIdentifier + } + + public interface CmsAttributeTableGenerator + { + AttributeTable GetAttributes(IDictionary parameters); + } +} diff --git a/iTechSharp/srcbc/cms/CMSCompressedData.cs b/iTechSharp/srcbc/cms/CMSCompressedData.cs new file mode 100644 index 0000000..c305efe --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSCompressedData.cs @@ -0,0 +1,73 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Utilities.Zlib; + +namespace Org.BouncyCastle.Cms +{ + /** + * containing class for an CMS Compressed Data object + */ + public class CmsCompressedData + { + internal ContentInfo contentInfo; + + public CmsCompressedData( + byte[] compressedData) + : this(CmsUtilities.ReadContentInfo(compressedData)) + { + } + + public CmsCompressedData( + Stream compressedDataStream) + : this(CmsUtilities.ReadContentInfo(compressedDataStream)) + { + } + + public CmsCompressedData( + ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + } + + public byte[] GetContent() + { + CompressedData comData = CompressedData.GetInstance(contentInfo.Content); + ContentInfo content = comData.EncapContentInfo; + + Asn1OctetString bytes = (Asn1OctetString) content.Content; + ZInflaterInputStream zIn = new ZInflaterInputStream(bytes.GetOctetStream()); + + try + { + return CmsUtilities.StreamToByteArray(zIn); + } + catch (IOException e) + { + throw new CmsException("exception reading compressed stream.", e); + } + finally + { + zIn.Close(); + } + } + + /** + * return the ContentInfo + */ + public ContentInfo ContentInfo + { + get { return contentInfo; } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return contentInfo.GetEncoded(); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSCompressedDataGenerator.cs b/iTechSharp/srcbc/cms/CMSCompressedDataGenerator.cs new file mode 100644 index 0000000..b68de0c --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSCompressedDataGenerator.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Zlib; + +namespace Org.BouncyCastle.Cms +{ + /** + * General class for generating a compressed CMS message. + *

      + * A simple example of usage.

      + *

      + *

      +    *      CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator();
      +    *      CMSCompressedData data = fact.Generate(content, algorithm);
      +    * 
      + *

      + */ + public class CmsCompressedDataGenerator + { + public const string ZLib = "1.2.840.113549.1.9.16.3.8"; + + public CmsCompressedDataGenerator() + { + } + + /** + * Generate an object that contains an CMS Compressed Data + */ + public CmsCompressedData Generate( + CmsProcessable content, + string compressionOid) + { + AlgorithmIdentifier comAlgId; + Asn1OctetString comOcts; + + try + { + MemoryStream bOut = new MemoryStream(); + ZDeflaterOutputStream zOut = new ZDeflaterOutputStream(bOut); + + content.Write(zOut); + + zOut.Close(); + + comAlgId = new AlgorithmIdentifier( + new DerObjectIdentifier(compressionOid), + null); + + comOcts = new BerOctetString(bOut.ToArray()); + } + catch (IOException e) + { + throw new CmsException("exception encoding data.", e); + } + + ContentInfo comContent = new ContentInfo(CmsObjectIdentifiers.Data, comOcts); + ContentInfo contentInfo = new ContentInfo( + CmsObjectIdentifiers.CompressedData, + new CompressedData(comAlgId, comContent)); + + return new CmsCompressedData(contentInfo); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSCompressedDataParser.cs b/iTechSharp/srcbc/cms/CMSCompressedDataParser.cs new file mode 100644 index 0000000..f45ece5 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSCompressedDataParser.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Utilities.Zlib; + +namespace Org.BouncyCastle.Cms +{ + /** + * Class for reading a CMS Compressed Data stream. + *
      +    *     CMSCompressedDataParser cp = new CMSCompressedDataParser(inputStream);
      +    *
      +    *     process(cp.GetContent().GetContentStream());
      +    * 
      + * Note: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + *
      +    *      CMSCompressedDataParser     ep = new CMSCompressedDataParser(new BufferedInputStream(inputStream, bufSize));
      +    *  
      + * where bufSize is a suitably large buffer size. + */ + public class CmsCompressedDataParser + : CmsContentInfoParser + { + public CmsCompressedDataParser( + byte[] compressedData) + : this(new MemoryStream(compressedData, false)) + { + } + + public CmsCompressedDataParser( + Stream compressedData) + : base(compressedData) + { + } + + public CmsTypedStream GetContent() + { + try + { + CompressedDataParser comData = new CompressedDataParser((Asn1SequenceParser)this.contentInfo.GetContent(Asn1Tags.Sequence)); + ContentInfoParser content = comData.GetEncapContentInfo(); + + Asn1OctetStringParser bytes = (Asn1OctetStringParser)content.GetContent(Asn1Tags.OctetString); + + return new CmsTypedStream(content.ContentType.ToString(), new ZInflaterInputStream(bytes.GetOctetStream())); + } + catch (IOException e) + { + throw new CmsException("IOException reading compressed content.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSCompressedDataStreamGenerator.cs b/iTechSharp/srcbc/cms/CMSCompressedDataStreamGenerator.cs new file mode 100644 index 0000000..b72ca31 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSCompressedDataStreamGenerator.cs @@ -0,0 +1,124 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.Utilities.Zlib; + +namespace Org.BouncyCastle.Cms +{ + /** + * General class for generating a compressed CMS message stream. + *

      + * A simple example of usage. + *

      + *
      +	*      CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
      +	*
      +	*      Stream cOut = gen.Open(outputStream, CMSCompressedDataStreamGenerator.ZLIB);
      +	*
      +	*      cOut.Write(data);
      +	*
      +	*      cOut.Close();
      +	* 
      + */ + public class CmsCompressedDataStreamGenerator + { + public const string ZLib = "1.2.840.113549.1.9.16.3.8"; + + /** + * base constructor + */ + public CmsCompressedDataStreamGenerator() + { + } + + public Stream Open( + Stream outStream, + string compressionOID) + { + return Open(outStream, CmsObjectIdentifiers.Data.Id, compressionOID); + } + + public Stream Open( + Stream outStream, + string contentOID, + string compressionOID) + { + BerSequenceGenerator sGen = new BerSequenceGenerator(outStream); + + sGen.AddObject(CmsObjectIdentifiers.CompressedData); + + // + // Compressed Data + // + BerSequenceGenerator cGen = new BerSequenceGenerator( + sGen.GetRawOutputStream(), 0, true); + + // CMSVersion + cGen.AddObject(new DerInteger(0)); + + // CompressionAlgorithmIdentifier + cGen.AddObject(new AlgorithmIdentifier(new DerObjectIdentifier(ZLib))); + + // + // Encapsulated ContentInfo + // + BerSequenceGenerator eiGen = new BerSequenceGenerator(cGen.GetRawOutputStream()); + + eiGen.AddObject(new DerObjectIdentifier(contentOID)); + + BerOctetStringGenerator octGen = new BerOctetStringGenerator( + eiGen.GetRawOutputStream(), 0, true); + + return new CmsCompressedOutputStream( + new ZDeflaterOutputStream(octGen.GetOctetOutputStream()), sGen, cGen, eiGen); + } + + private class CmsCompressedOutputStream + : BaseOutputStream + { + private ZDeflaterOutputStream _out; + private BerSequenceGenerator _sGen; + private BerSequenceGenerator _cGen; + private BerSequenceGenerator _eiGen; + + internal CmsCompressedOutputStream( + ZDeflaterOutputStream outStream, + BerSequenceGenerator sGen, + BerSequenceGenerator cGen, + BerSequenceGenerator eiGen) + { + _out = outStream; + _sGen = sGen; + _cGen = cGen; + _eiGen = eiGen; + } + + public override void WriteByte( + byte b) + { + _out.WriteByte(b); + } + + public override void Write( + byte[] bytes, + int off, + int len) + { + _out.Write(bytes, off, len); + } + + public override void Close() + { + _out.Close(); + _eiGen.Close(); + _cGen.Close(); + _sGen.Close(); + base.Close(); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSContentInfoParser.cs b/iTechSharp/srcbc/cms/CMSContentInfoParser.cs new file mode 100644 index 0000000..04ac4cb --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSContentInfoParser.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; + +namespace Org.BouncyCastle.Cms +{ + public class CmsContentInfoParser + { + protected ContentInfoParser contentInfo; + protected Stream data; + + protected CmsContentInfoParser( + Stream data) + { + if (data == null) + throw new ArgumentNullException("data"); + + this.data = data; + + try + { + Asn1StreamParser inStream = new Asn1StreamParser(data, CmsUtilities.MaximumMemory); + + this.contentInfo = new ContentInfoParser((Asn1SequenceParser)inStream.ReadObject()); + } + catch (IOException e) + { + throw new CmsException("IOException reading content.", e); + } + catch (InvalidCastException e) + { + throw new CmsException("Unexpected object reading content.", e); + } + } + + /** + * Close the underlying data stream. + * @throws IOException if the close fails. + */ + public void Close() + { + this.data.Close(); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSEnvelopedData.cs b/iTechSharp/srcbc/cms/CMSEnvelopedData.cs new file mode 100644 index 0000000..206af0e --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSEnvelopedData.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Cms +{ + /** + * containing class for an CMS Enveloped Data object + */ + public class CmsEnvelopedData + { + internal RecipientInformationStore recipientInfoStore; + internal ContentInfo contentInfo; + + private AlgorithmIdentifier encAlg; + private Asn1Set unprotectedAttributes; + + public CmsEnvelopedData( + byte[] envelopedData) + : this(CmsUtilities.ReadContentInfo(envelopedData)) + { + } + + public CmsEnvelopedData( + Stream envelopedData) + : this(CmsUtilities.ReadContentInfo(envelopedData)) + { + } + + public CmsEnvelopedData( + ContentInfo contentInfo) + { + this.contentInfo = contentInfo; + + EnvelopedData envData = EnvelopedData.GetInstance(contentInfo.Content); + + // + // read the encrypted content info + // + EncryptedContentInfo encInfo = envData.EncryptedContentInfo; + + this.encAlg = encInfo.ContentEncryptionAlgorithm; + + // + // load the RecipientInfoStore + // + Asn1Set s = envData.RecipientInfos; + IList infos = new ArrayList(); + byte[] contentOctets = encInfo.EncryptedContent.GetOctets(); + + foreach (Asn1Encodable ae in s) + { + RecipientInfo info = RecipientInfo.GetInstance(ae); + MemoryStream contentStream = new MemoryStream(contentOctets, false); + + object type = info.Info; + + if (type is KeyTransRecipientInfo) + { + infos.Add(new KeyTransRecipientInformation( + (KeyTransRecipientInfo) type, encAlg, contentStream)); + } + else if (type is KekRecipientInfo) + { + infos.Add(new KekRecipientInformation( + (KekRecipientInfo) type, encAlg, contentStream)); + } + else if (type is KeyAgreeRecipientInfo) + { + infos.Add(new KeyAgreeRecipientInformation( + (KeyAgreeRecipientInfo) type, encAlg, contentStream)); + } + else if (type is PasswordRecipientInfo) + { + infos.Add(new PasswordRecipientInformation( + (PasswordRecipientInfo) type, encAlg, contentStream)); + } + } + + this.recipientInfoStore = new RecipientInformationStore(infos); + this.unprotectedAttributes = envData.UnprotectedAttrs; + } + + public AlgorithmIdentifier EncryptionAlgorithmID + { + get { return encAlg; } + } + + /** + * return the object identifier for the content encryption algorithm. + */ + public string EncryptionAlgOid + { + get { return encAlg.ObjectID.Id; } + } + + /** + * return a store of the intended recipients for this message + */ + public RecipientInformationStore GetRecipientInfos() + { + return recipientInfoStore; + } + + /** + * return the ContentInfo + */ + public ContentInfo ContentInfo + { + get { return contentInfo; } + } + + /** + * return a table of the unprotected attributes indexed by + * the OID of the attribute. + */ + public Asn1.Cms.AttributeTable GetUnprotectedAttributes() + { + if (unprotectedAttributes == null) + return null; + + return new Asn1.Cms.AttributeTable(unprotectedAttributes); + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return contentInfo.GetEncoded(); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSEnvelopedDataGenerator.cs b/iTechSharp/srcbc/cms/CMSEnvelopedDataGenerator.cs new file mode 100644 index 0000000..c103ac0 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSEnvelopedDataGenerator.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /// + /// General class for generating a CMS enveloped-data message. + /// + /// A simple example of usage. + /// + ///
      +    ///      CmsEnvelopedDataGenerator  fact = new CmsEnvelopedDataGenerator();
      +    ///
      +    ///      fact.AddKeyTransRecipient(cert);
      +    ///
      +    ///      CmsEnvelopedData         data = fact.Generate(content, algorithm);
      +    /// 
      + ///
      + public class CmsEnvelopedDataGenerator + : CmsEnvelopedGenerator + { + public CmsEnvelopedDataGenerator() + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsEnvelopedDataGenerator( + SecureRandom rand) + : base(rand) + { + } + + /// + /// Generate an enveloped object that contains a CMS Enveloped Data + /// object using the passed in key generator. + /// + private CmsEnvelopedData Generate( + CmsProcessable content, + string encryptionOid, + CipherKeyGenerator keyGen) + { + AlgorithmIdentifier encAlgId = null; + KeyParameter encKey; + Asn1OctetString encContent; + + try + { + byte[] encKeyBytes = keyGen.GenerateKey(); + encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes); + + Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes); + + ICipherParameters cipherParameters; + encAlgId = GetAlgorithmIdentifier( + encryptionOid, encKey, asn1Params, out cipherParameters); + + IBufferedCipher cipher = CipherUtilities.GetCipher(encryptionOid); + cipher.Init(true, new ParametersWithRandom(cipherParameters, rand)); + + MemoryStream bOut = new MemoryStream(); + CipherStream cOut = new CipherStream(bOut, null, cipher); + + content.Write(cOut); + + cOut.Close(); + + encContent = new BerOctetString(bOut.ToArray()); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + catch (IOException e) + { + throw new CmsException("exception decoding algorithm parameters.", e); + } + + + Asn1EncodableVector recipientInfos = new Asn1EncodableVector(); + + foreach (RecipientInf recipient in recipientInfs) + { + try + { + recipientInfos.Add(recipient.ToRecipientInfo(encKey, rand)); + } + catch (IOException e) + { + throw new CmsException("encoding error.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key inappropriate for algorithm.", e); + } + catch (GeneralSecurityException e) + { + throw new CmsException("error making encrypted content.", e); + } + } + + EncryptedContentInfo eci = new EncryptedContentInfo( + PkcsObjectIdentifiers.Data, + encAlgId, + encContent); + + Asn1.Cms.ContentInfo contentInfo = new Asn1.Cms.ContentInfo( + PkcsObjectIdentifiers.EnvelopedData, + new EnvelopedData(null, new DerSet(recipientInfos), eci, null)); + + return new CmsEnvelopedData(contentInfo); + } + + /// Generate an enveloped object that contains an CMS Enveloped Data object. + public CmsEnvelopedData Generate( + CmsProcessable content, + string encryptionOid) + { + try + { + CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); + + keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength)); + + return Generate(content, encryptionOid, keyGen); + } + catch (SecurityUtilityException e) + { + throw new CmsException("can't find key generation algorithm.", e); + } + } + + /// Generate an enveloped object that contains an CMS Enveloped Data object. + public CmsEnvelopedData Generate( + CmsProcessable content, + string encryptionOid, + int keySize) + { + try + { + CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); + + keyGen.Init(new KeyGenerationParameters(rand, keySize)); + + return Generate(content, encryptionOid, keyGen); + } + catch (SecurityUtilityException e) + { + throw new CmsException("can't find key generation algorithm.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSEnvelopedDataParser.cs b/iTechSharp/srcbc/cms/CMSEnvelopedDataParser.cs new file mode 100644 index 0000000..39f39ac --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSEnvelopedDataParser.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Cms +{ + /** + * Parsing class for an CMS Enveloped Data object from an input stream. + *

      + * Note: that because we are in a streaming mode only one recipient can be tried and it is important + * that the methods on the parser are called in the appropriate order. + *

      + *

      + * Example of use - assuming the first recipient matches the private key we have. + *

      +    *      CmsEnvelopedDataParser     ep = new CmsEnvelopedDataParser(inputStream);
      +    *
      +    *      RecipientInformationStore  recipients = ep.GetRecipientInfos();
      +    *
      +    *      Collection  c = recipients.getRecipients();
      +    *      Iterator    it = c.iterator();
      +    *
      +    *      if (it.hasNext())
      +    *      {
      +    *          RecipientInformation   recipient = (RecipientInformation)it.next();
      +    *
      +    *          CMSTypedStream recData = recipient.getContentStream(privateKey);
      +    *
      +    *          processDataStream(recData.getContentStream());
      +    *      }
      +    *  
      + * Note: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + *
      +    *          CmsEnvelopedDataParser     ep = new CmsEnvelopedDataParser(new BufferedInputStream(inputStream, bufSize));
      +    *  
      + * where bufSize is a suitably large buffer size. + *

      + */ + public class CmsEnvelopedDataParser + : CmsContentInfoParser + { + internal RecipientInformationStore recipientInfoStore; + internal EnvelopedDataParser envelopedData; + + private AlgorithmIdentifier _encAlg; + private Asn1.Cms.AttributeTable _unprotectedAttributes; + private bool _attrNotRead; + + public CmsEnvelopedDataParser( + byte[] envelopedData) + : this(new MemoryStream(envelopedData, false)) + { + } + + public CmsEnvelopedDataParser( + Stream envelopedData) + : base(envelopedData) + { + this._attrNotRead = true; + this.envelopedData = new EnvelopedDataParser( + (Asn1SequenceParser)this.contentInfo.GetContent(Asn1Tags.Sequence)); + + // + // load the RecipientInfoStore + // + Asn1SetParser s = this.envelopedData.GetRecipientInfos(); + IList baseInfos = new ArrayList(); + + IAsn1Convertible entry; + while ((entry = s.ReadObject()) != null) + { + baseInfos.Add(RecipientInfo.GetInstance(entry.ToAsn1Object())); + } + + // + // read the encrypted content info + // + EncryptedContentInfoParser encInfo = this.envelopedData.GetEncryptedContentInfo(); + + this._encAlg = encInfo.ContentEncryptionAlgorithm; + + // + // prime the recipients + // + IList infos = new ArrayList(); + Stream dataStream = ((Asn1OctetStringParser)encInfo.GetEncryptedContent(Asn1Tags.OctetString)).GetOctetStream(); + + foreach (Asn1.Cms.RecipientInfo info in baseInfos) + { + Asn1Encodable recipInfo = info.Info; + if (recipInfo is Asn1.Cms.KeyTransRecipientInfo) + { + infos.Add(new KeyTransRecipientInformation( + (KeyTransRecipientInfo) recipInfo, _encAlg, dataStream)); + } + else if (recipInfo is Asn1.Cms.KekRecipientInfo) + { + infos.Add(new KekRecipientInformation( + (KekRecipientInfo) recipInfo, _encAlg, dataStream)); + } + else if (recipInfo is KeyAgreeRecipientInfo) + { + infos.Add(new KeyAgreeRecipientInformation( + (KeyAgreeRecipientInfo) recipInfo, _encAlg, dataStream)); + } + else if (recipInfo is PasswordRecipientInfo) + { + infos.Add(new PasswordRecipientInformation( + (PasswordRecipientInfo) recipInfo, _encAlg, dataStream)); + } + } + + this.recipientInfoStore = new RecipientInformationStore(infos); + } + + public AlgorithmIdentifier EncryptionAlgorithmID + { + get { return _encAlg; } + } + + /** + * return the object identifier for the content encryption algorithm. + */ + public string EncryptionAlgOid + { + get { return _encAlg.ObjectID.Id; } + } + + /** + * return the ASN.1 encoded encryption algorithm parameters, or null if + * there aren't any. + */ + public Asn1Object EncryptionAlgParams + { + get + { + Asn1Encodable ae = _encAlg.Parameters; + + return ae == null ? null : ae.ToAsn1Object(); + } + } + + /** + * return a store of the intended recipients for this message + */ + public RecipientInformationStore GetRecipientInfos() + { + return this.recipientInfoStore; + } + + /** + * return a table of the unprotected attributes indexed by + * the OID of the attribute. + * @throws IOException + */ + public Asn1.Cms.AttributeTable GetUnprotectedAttributes() + { + if (_unprotectedAttributes == null && _attrNotRead) + { + Asn1SetParser asn1Set = this.envelopedData.GetUnprotectedAttrs(); + + _attrNotRead = false; + + if (asn1Set != null) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + IAsn1Convertible o; + + while ((o = asn1Set.ReadObject()) != null) + { + Asn1SequenceParser seq = (Asn1SequenceParser)o; + + v.Add(seq.ToAsn1Object()); + } + + _unprotectedAttributes = new Asn1.Cms.AttributeTable(new DerSet(v)); + } + } + + return _unprotectedAttributes; + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSEnvelopedDataStreamGenerator.cs b/iTechSharp/srcbc/cms/CMSEnvelopedDataStreamGenerator.cs new file mode 100644 index 0000000..22696fd --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSEnvelopedDataStreamGenerator.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * General class for generating a CMS enveloped-data message stream. + *

      + * A simple example of usage. + *

      +	*      CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
      +	*
      +	*      edGen.AddKeyTransRecipient(cert);
      +	*
      +	*      MemoryStream  bOut = new MemoryStream();
      +	*
      +	*      Stream out = edGen.Open(
      +	*                              bOut, CMSEnvelopedDataGenerator.AES128_CBC);*
      +	*      out.Write(data);
      +	*
      +	*      out.Close();
      +	* 
      + *

      + */ + public class CmsEnvelopedDataStreamGenerator + : CmsEnvelopedGenerator + { + private object _originatorInfo = null; + private object _unprotectedAttributes = null; + private int _bufferSize; + private bool _berEncodeRecipientSet; + + public CmsEnvelopedDataStreamGenerator() + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsEnvelopedDataStreamGenerator( + SecureRandom rand) + : base(rand) + { + } + + /// Set the underlying string size for encapsulated data. + /// Length of octet strings to buffer the data. + public void SetBufferSize( + int bufferSize) + { + _bufferSize = bufferSize; + } + + /// Use a BER Set to store the recipient information. + public void SetBerEncodeRecipients( + bool berEncodeRecipientSet) + { + _berEncodeRecipientSet = berEncodeRecipientSet; + } + + private DerInteger Version + { + get + { + int version = (_originatorInfo != null || _unprotectedAttributes != null) + ? 2 + : 0; + + return new DerInteger(version); + } + } + + /// + /// Generate an enveloped object that contains an CMS Enveloped Data + /// object using the passed in key generator. + /// + private Stream Open( + Stream outStream, + string encryptionOid, + CipherKeyGenerator keyGen) + { + byte[] encKeyBytes = keyGen.GenerateKey(); + KeyParameter encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes); + + Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes); + + ICipherParameters cipherParameters; + AlgorithmIdentifier encAlgID = GetAlgorithmIdentifier( + encryptionOid, encKey, asn1Params, out cipherParameters); + + Asn1EncodableVector recipientInfos = new Asn1EncodableVector(); + + foreach (RecipientInf recipient in recipientInfs) + { + try + { + recipientInfos.Add(recipient.ToRecipientInfo(encKey, rand)); + } + catch (IOException e) + { + throw new CmsException("encoding error.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key inappropriate for algorithm.", e); + } + catch (GeneralSecurityException e) + { + throw new CmsException("error making encrypted content.", e); + } + } + + return Open(outStream, encAlgID, cipherParameters, recipientInfos); + } + + private Stream Open( + Stream outStream, + AlgorithmIdentifier encAlgID, + ICipherParameters cipherParameters, + Asn1EncodableVector recipientInfos) + { + try + { + // + // ContentInfo + // + BerSequenceGenerator cGen = new BerSequenceGenerator(outStream); + + cGen.AddObject(CmsObjectIdentifiers.EnvelopedData); + + // + // Encrypted Data + // + BerSequenceGenerator envGen = new BerSequenceGenerator( + cGen.GetRawOutputStream(), 0, true); + + envGen.AddObject(this.Version); + + Asn1Generator recipGen = _berEncodeRecipientSet + ? (Asn1Generator) new BerSetGenerator(envGen.GetRawOutputStream()) + : new DerSetGenerator(envGen.GetRawOutputStream()); + + foreach (Asn1Encodable ae in recipientInfos) + { + recipGen.AddObject(ae); + } + + recipGen.Close(); + + BerSequenceGenerator eiGen = new BerSequenceGenerator( + envGen.GetRawOutputStream()); + + eiGen.AddObject(PkcsObjectIdentifiers.Data); + eiGen.AddObject(encAlgID); + + BerOctetStringGenerator octGen = new BerOctetStringGenerator( + eiGen.GetRawOutputStream(), 0, false); + Stream octetOutputStream = octGen.GetOctetOutputStream(_bufferSize); + + IBufferedCipher cipher = CipherUtilities.GetCipher(encAlgID.ObjectID); + cipher.Init(true, new ParametersWithRandom(cipherParameters, rand)); + CipherStream cOut = new CipherStream(octetOutputStream, null, cipher); + + return new CmsEnvelopedDataOutputStream(cOut, cGen, envGen, eiGen); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + catch (IOException e) + { + throw new CmsException("exception decoding algorithm parameters.", e); + } + } + + /** + * generate an enveloped object that contains an CMS Enveloped Data object + * @throws IOException + */ + public Stream Open( + Stream outStream, + string encryptionOid) + { + CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); + + keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength)); + + return Open(outStream, encryptionOid, keyGen); + } + + /** + * generate an enveloped object that contains an CMS Enveloped Data object + * @throws IOException + */ + public Stream Open( + Stream outStream, + string encryptionOid, + int keySize) + { + CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); + + keyGen.Init(new KeyGenerationParameters(rand, keySize)); + + return Open(outStream, encryptionOid, keyGen); + } + + private class CmsEnvelopedDataOutputStream + : BaseOutputStream + { + private CipherStream _out; + private BerSequenceGenerator _cGen; + private BerSequenceGenerator _envGen; + private BerSequenceGenerator _eiGen; + + public CmsEnvelopedDataOutputStream( + CipherStream outStream, + BerSequenceGenerator cGen, + BerSequenceGenerator envGen, + BerSequenceGenerator eiGen) + { + _out = outStream; + _cGen = cGen; + _envGen = envGen; + _eiGen = eiGen; + } + + public override void WriteByte( + byte b) + { + _out.WriteByte(b); + } + + public override void Write( + byte[] bytes, + int off, + int len) + { + _out.Write(bytes, off, len); + } + + public override void Close() + { + _out.Close(); + _eiGen.Close(); + + // [TODO] unprotected attributes go here + + _envGen.Close(); + _cGen.Close(); + base.Close(); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSEnvelopedGenerator.cs b/iTechSharp/srcbc/cms/CMSEnvelopedGenerator.cs new file mode 100644 index 0000000..3f115e3 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSEnvelopedGenerator.cs @@ -0,0 +1,551 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * General class for generating a CMS enveloped-data message. + * + * A simple example of usage. + * + *
      +	*      CMSEnvelopedDataGenerator  fact = new CMSEnvelopedDataGenerator();
      +	*
      +	*      fact.addKeyTransRecipient(cert);
      +	*
      +	*      CMSEnvelopedData         data = fact.generate(content, algorithm, "BC");
      +	* 
      + */ + public class CmsEnvelopedGenerator + { + internal static readonly short[] rc2Table = + { + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab + }; + + internal static readonly short[] rc2Ekb = + { + 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, + 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, + 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, + 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, + 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, + 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, + 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, + 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, + 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, + 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, + 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, + 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, + 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, + 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, + 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, + 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd + }; + + + // TODO Create named constants for all of these + public static readonly string DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc.Id; + public static readonly string RC2Cbc = PkcsObjectIdentifiers.RC2Cbc.Id; + public const string IdeaCbc = "1.3.6.1.4.1.188.7.1.1.2"; + public const string Cast5Cbc = "1.2.840.113533.7.66.10"; + public static readonly string Aes128Cbc = NistObjectIdentifiers.IdAes128Cbc.Id; + public static readonly string Aes192Cbc = NistObjectIdentifiers.IdAes192Cbc.Id; + public static readonly string Aes256Cbc = NistObjectIdentifiers.IdAes256Cbc.Id; + public static readonly string Camellia128Cbc = NttObjectIdentifiers.IdCamellia128Cbc.Id; + public static readonly string Camellia192Cbc = NttObjectIdentifiers.IdCamellia192Cbc.Id; + public static readonly string Camellia256Cbc = NttObjectIdentifiers.IdCamellia256Cbc.Id; + public static readonly string SeedCbc = KisaObjectIdentifiers.IdSeedCbc.Id; + + public static readonly string DesEde3Wrap = PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id; + public static readonly string Aes128Wrap = NistObjectIdentifiers.IdAes128Wrap.Id; + public static readonly string Aes192Wrap = NistObjectIdentifiers.IdAes192Wrap.Id; + public static readonly string Aes256Wrap = NistObjectIdentifiers.IdAes256Wrap.Id; + public static readonly string Camellia128Wrap = NttObjectIdentifiers.IdCamellia128Wrap.Id; + public static readonly string Camellia192Wrap = NttObjectIdentifiers.IdCamellia192Wrap.Id; + public static readonly string Camellia256Wrap = NttObjectIdentifiers.IdCamellia256Wrap.Id; + public static readonly string SeedWrap = KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id; + + public static readonly string ECDHSha1Kdf = X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id; + + internal static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance; + + internal readonly IList recipientInfs = new ArrayList(); + internal readonly SecureRandom rand; + + protected class RecipientInf + { + private readonly X509Certificate cert; + private AlgorithmIdentifier keyEncAlg; + private readonly AsymmetricKeyParameter pubKey; + private readonly Asn1OctetString subKeyId; + + private readonly string secKeyAlgorithm; + private readonly KeyParameter secKey; + private readonly KekIdentifier secKeyId; + + private readonly OriginatorIdentifierOrKey originator; + private const Asn1OctetString ukm = null; + + private readonly AlgorithmIdentifier derivationAlg; + + internal RecipientInf( + X509Certificate cert) + { + this.cert = cert; + this.pubKey = cert.GetPublicKey(); + + try + { + TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + + keyEncAlg = tbs.SubjectPublicKeyInfo.AlgorithmID; + } +// catch (IOException e) + catch (Exception) + { + throw new ArgumentException("can't extract key algorithm from this cert"); + } +// catch (CertificateEncodingException) +// { +// throw new ArgumentException("can't extract tbs structure from this cert"); +// } + } + + internal RecipientInf( + AsymmetricKeyParameter pubKey, + Asn1OctetString subKeyId) + { + this.pubKey = pubKey; + this.subKeyId = subKeyId; + + try + { + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey); + + keyEncAlg = info.AlgorithmID; + } + catch (IOException) + { + throw new ArgumentException("can't extract key algorithm from this key"); + } + } + + internal RecipientInf( + string secKeyAlgorithm, // TODO Can get this from secKey? + KeyParameter secKey, + KekIdentifier secKeyId) + { + this.secKeyAlgorithm = secKeyAlgorithm; + this.secKey = secKey; + this.secKeyId = secKeyId; + + if (secKeyAlgorithm.StartsWith("DES")) + { + keyEncAlg = new AlgorithmIdentifier( + PkcsObjectIdentifiers.IdAlgCms3DesWrap, + DerNull.Instance); + } + else if (secKeyAlgorithm.StartsWith("RC2")) + { + keyEncAlg = new AlgorithmIdentifier( + PkcsObjectIdentifiers.IdAlgCmsRC2Wrap, + new DerInteger(58)); + } + else if (secKeyAlgorithm.StartsWith("AES")) + { + int length = secKey.GetKey().Length * 8; + DerObjectIdentifier wrapOid; + + if (length == 128) + { + wrapOid = NistObjectIdentifiers.IdAes128Wrap; + } + else if (length == 192) + { + wrapOid = NistObjectIdentifiers.IdAes192Wrap; + } + else if (length == 256) + { + wrapOid = NistObjectIdentifiers.IdAes256Wrap; + } + else + { + throw new ArgumentException("illegal keysize in AES"); + } + + keyEncAlg = new AlgorithmIdentifier(wrapOid); // parameters absent + } + else if (secKeyAlgorithm.StartsWith("SEED")) + { + // parameters absent + keyEncAlg = new AlgorithmIdentifier(KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap); + } + else if (secKeyAlgorithm.StartsWith("CAMELLIA")) + { + int length = secKey.GetKey().Length * 8; + DerObjectIdentifier wrapOid; + + if (length == 128) + { + wrapOid = NttObjectIdentifiers.IdCamellia128Wrap; + } + else if (length == 192) + { + wrapOid = NttObjectIdentifiers.IdCamellia192Wrap; + } + else if (length == 256) + { + wrapOid = NttObjectIdentifiers.IdCamellia256Wrap; + } + else + { + throw new ArgumentException("illegal keysize in Camellia"); + } + + keyEncAlg = new AlgorithmIdentifier(wrapOid); // parameters must be absent + } + else + { + throw new ArgumentException("unknown algorithm"); + } + } + + public RecipientInf( + string secKeyAlgorithm, // TODO Can get this from secKey? + KeyParameter secKey, + string algorithm, + string wrapOid, + OriginatorIdentifierOrKey originator, + X509Certificate cert) + { + DerSequence paramSeq = new DerSequence( + new DerObjectIdentifier(wrapOid), + DerNull.Instance); + + this.secKeyAlgorithm = secKeyAlgorithm; + this.secKey = secKey; + this.keyEncAlg = new AlgorithmIdentifier(new DerObjectIdentifier(algorithm), paramSeq); + this.originator = originator; + this.cert = cert; + } + + public RecipientInf( + string secKeyAlgorithm, // TODO Can get this from secKey? + KeyParameter secKey, + AlgorithmIdentifier derivationAlg) + { + this.secKeyAlgorithm = secKeyAlgorithm; + this.secKey = secKey; + this.derivationAlg = derivationAlg; + } + + internal RecipientInfo ToRecipientInfo( + KeyParameter key, + SecureRandom random) + { + byte[] keyBytes = key.GetKey(); + + if (pubKey != null) + { + IWrapper keyWrapper = Helper.CreateWrapper(keyEncAlg.ObjectID.Id); + + keyWrapper.Init(true, new ParametersWithRandom(pubKey, random)); + + Asn1OctetString encKey = new DerOctetString( + keyWrapper.Wrap(keyBytes, 0, keyBytes.Length)); + + RecipientIdentifier recipId; + if (cert != null) + { + TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + + Asn1.Cms.IssuerAndSerialNumber encSid = new Asn1.Cms.IssuerAndSerialNumber( + tbs.Issuer, tbs.SerialNumber.Value); + + recipId = new RecipientIdentifier(encSid); + } + else + { + recipId = new RecipientIdentifier(subKeyId); + } + + return new RecipientInfo(new KeyTransRecipientInfo(recipId, keyEncAlg, encKey)); + } + else if (originator != null) + { + IWrapper keyWrapper = Helper.CreateWrapper( + DerObjectIdentifier.GetInstance( + Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id); + + keyWrapper.Init(true, new ParametersWithRandom(secKey, random)); + + Asn1OctetString encKey = new DerOctetString( + keyWrapper.Wrap(keyBytes, 0, keyBytes.Length)); + + RecipientEncryptedKey rKey = new RecipientEncryptedKey( + new KeyAgreeRecipientIdentifier( + new Asn1.Cms.IssuerAndSerialNumber( + PrincipalUtilities.GetIssuerX509Principal(cert), + cert.SerialNumber)), + encKey); + + return new RecipientInfo( + new KeyAgreeRecipientInfo(originator, ukm, keyEncAlg, new DerSequence(rKey))); + } + else if (derivationAlg != null) + { + string rfc3211WrapperName = Helper.GetRfc3211WrapperName(secKeyAlgorithm); + IWrapper keyWrapper = Helper.CreateWrapper(rfc3211WrapperName); + + + // Note: In Java build, the IV is automatically generated in JCE layer + int ivLength = rfc3211WrapperName.StartsWith("DESEDE") ? 8 : 16; + byte[] iv = new byte[ivLength]; + random.NextBytes(iv); + + + ICipherParameters parameters = new ParametersWithIV(secKey, iv); + keyWrapper.Init(true, new ParametersWithRandom(parameters, random)); + + Asn1OctetString encKey = new DerOctetString( + keyWrapper.Wrap(keyBytes, 0, keyBytes.Length)); + +// byte[] iv = keyWrapper.GetIV(); + + DerSequence seq = new DerSequence( + new DerObjectIdentifier(secKeyAlgorithm), + new DerOctetString(iv)); + + keyEncAlg = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgPwriKek, seq); + + return new RecipientInfo(new PasswordRecipientInfo(derivationAlg, keyEncAlg, encKey)); + } + else + { + IWrapper keyWrapper = Helper.CreateWrapper(keyEncAlg.ObjectID.Id); + + keyWrapper.Init(true, new ParametersWithRandom(secKey, random)); + + Asn1OctetString encKey = new DerOctetString( + keyWrapper.Wrap(keyBytes, 0, keyBytes.Length)); + + return new RecipientInfo(new KekRecipientInfo(secKeyId, keyEncAlg, encKey)); + } + } + } + + public CmsEnvelopedGenerator() + : this(new SecureRandom()) + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsEnvelopedGenerator( + SecureRandom rand) + { + this.rand = rand; + } + + /** + * add a recipient. + * + * @param cert recipient's public key certificate + * @exception ArgumentException if there is a problem with the certificate + */ + public void AddKeyTransRecipient( + X509Certificate cert) + { + recipientInfs.Add(new RecipientInf(cert)); + } + + /** + * add a recipient + * + * @param key the public key used by the recipient + * @param subKeyId the identifier for the recipient's public key + * @exception ArgumentException if there is a problem with the key + */ + public void AddKeyTransRecipient( + AsymmetricKeyParameter pubKey, + byte[] subKeyId) + { + recipientInfs.Add(new CmsEnvelopedGenerator.RecipientInf(pubKey, new DerOctetString(subKeyId))); + } + + /** + * add a KEK recipient. + * @param key the secret key to use for wrapping + * @param keyIdentifier the byte string that identifies the key + */ + public void AddKekRecipient( + string keyAlgorithm, // TODO Remove need for this parameter + KeyParameter key, + byte[] keyIdentifier) + { + recipientInfs.Add(new RecipientInf(keyAlgorithm, key, new KekIdentifier(keyIdentifier, null, null))); + } + + public void AddPasswordRecipient( + CmsPbeKey pbeKey, + string kekAlgorithmOid) + { + Pbkdf2Params p = new Pbkdf2Params(pbeKey.Salt, pbeKey.IterationCount); + KeyParameter secretKey = pbeKey.GetEncoded(kekAlgorithmOid); + recipientInfs.Add(new RecipientInf(kekAlgorithmOid, secretKey, new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPbkdf2, p))); + } + + /** + * Add a key agreement based recipient. + * + * @param agreementAlgorithm key agreement algorithm to use. + * @param senderPrivateKey private key to initialise sender side of agreement with. + * @param senderPublicKey sender public key to include with message. + * @param recipientCert recipient's public key certificate. + * @param cekWrapAlgorithm OID for key wrapping algorithm to use. + * @exception SecurityUtilityException if the algorithm requested cannot be found + * @exception InvalidKeyException if the keys are inappropriate for the algorithm specified + */ + public void AddKeyAgreementRecipient( + string agreementAlgorithm, + AsymmetricKeyParameter senderPrivateKey, + AsymmetricKeyParameter senderPublicKey, + X509Certificate recipientCert, + string cekWrapAlgorithm) + { + if (!senderPrivateKey.IsPrivate) + throw new ArgumentException("Expected private key", "senderPrivateKey"); + if (senderPublicKey.IsPrivate) + throw new ArgumentException("Expected public key", "senderPublicKey"); + + IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf( + agreementAlgorithm, cekWrapAlgorithm); + + agreement.Init(new ParametersWithRandom(senderPrivateKey, rand)); + + BigInteger secretNum = agreement.CalculateAgreement(recipientCert.GetPublicKey()); + + try + { + SubjectPublicKeyInfo oPubKeyInfo = + SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(senderPublicKey); + + OriginatorIdentifierOrKey originator = new OriginatorIdentifierOrKey( + new OriginatorPublicKey( + new AlgorithmIdentifier(oPubKeyInfo.AlgorithmID.ObjectID, DerNull.Instance), + oPubKeyInfo.PublicKeyData.GetBytes())); + + // TODO Fix the way bytes are derived from the secret + byte[] secretBytes = secretNum.ToByteArrayUnsigned(); + KeyParameter secret = ParameterUtilities.CreateKeyParameter( + cekWrapAlgorithm, secretBytes); + + recipientInfs.Add( + new RecipientInf(cekWrapAlgorithm, secret, agreementAlgorithm, + cekWrapAlgorithm, originator, recipientCert)); + } + catch (IOException e) + { + throw new InvalidKeyException("cannot extract originator public key: " + e); + } + } + + protected internal virtual AlgorithmIdentifier GetAlgorithmIdentifier( + string encryptionOid, + KeyParameter encKey, + Asn1Encodable asn1Params, + out ICipherParameters cipherParameters) + { + Asn1Object asn1Object; + if (asn1Params != null) + { + asn1Object = asn1Params.ToAsn1Object(); + cipherParameters = ParameterUtilities.GetCipherParameters( + encryptionOid, encKey, asn1Object); + } + else + { + asn1Object = DerNull.Instance; + cipherParameters = encKey; + } + + return new AlgorithmIdentifier( + new DerObjectIdentifier(encryptionOid), + asn1Object); + } + + protected internal virtual Asn1Encodable GenerateAsn1Parameters( + string encryptionOid, + byte[] encKeyBytes) + { + Asn1Encodable asn1Params = null; + + try + { + if (encryptionOid.Equals(RC2Cbc)) + { + byte[] iv = new byte[8]; + rand.NextBytes(iv); + + // TODO Is this detailed repeat of Java version really necessary? + int effKeyBits = encKeyBytes.Length * 8; + int parameterVersion; + + if (effKeyBits < 256) + { + parameterVersion = rc2Table[effKeyBits]; + } + else + { + parameterVersion = effKeyBits; + } + + asn1Params = new RC2CbcParameter(parameterVersion, iv); + } + else + { + asn1Params = ParameterUtilities.GenerateParameters(encryptionOid, rand); + } + } + catch (SecurityUtilityException) + { + // No problem... no parameters generated + } + + return asn1Params; + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSEnvelopedHelper.cs b/iTechSharp/srcbc/cms/CMSEnvelopedHelper.cs new file mode 100644 index 0000000..a904f5a --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSEnvelopedHelper.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Cms +{ + class CmsEnvelopedHelper + { + internal static readonly CmsEnvelopedHelper Instance = new CmsEnvelopedHelper(); + + private static readonly IDictionary KeySizes = new Hashtable(); + private static readonly IDictionary Ciphers = new Hashtable(); + private static readonly IDictionary BaseCipherNames = new Hashtable(); +// private static readonly IDictionary CipherAlgNames = new Hashtable(); + + static CmsEnvelopedHelper() + { + KeySizes.Add(CmsEnvelopedGenerator.DesEde3Cbc, 192); + KeySizes.Add(CmsEnvelopedGenerator.Aes128Cbc, 128); + KeySizes.Add(CmsEnvelopedGenerator.Aes192Cbc, 192); + KeySizes.Add(CmsEnvelopedGenerator.Aes256Cbc, 256); + + BaseCipherNames.Add(CmsEnvelopedGenerator.DesEde3Cbc, "DESEDE"); + BaseCipherNames.Add(CmsEnvelopedGenerator.Aes128Cbc, "AES"); + BaseCipherNames.Add(CmsEnvelopedGenerator.Aes192Cbc, "AES"); + BaseCipherNames.Add(CmsEnvelopedGenerator.Aes256Cbc, "AES"); + +// CipherAlgNames.Add(CmsEnvelopedGenerator.DesEde3Cbc, "DESEDE/CBC/PKCS5Padding"); +// CipherAlgNames.Add(CmsEnvelopedGenerator.Aes128Cbc, "AES/CBC/PKCS5Padding"); +// CipherAlgNames.Add(CmsEnvelopedGenerator.Aes192Cbc, "AES/CBC/PKCS5Padding"); +// CipherAlgNames.Add(CmsEnvelopedGenerator.Aes256Cbc, "AES/CBC/PKCS5Padding"); + } + + private string GetAsymmetricEncryptionAlgName( + string encryptionAlgOid) + { + if (PkcsObjectIdentifiers.RsaEncryption.Id.Equals(encryptionAlgOid)) + { + return "RSA/ECB/PKCS1Padding"; + } + + return encryptionAlgOid; + } + + internal IBufferedCipher CreateAsymmetricCipher( + string encryptionOid) + { + try + { + return CipherUtilities.GetCipher(encryptionOid); + } + catch (SecurityUtilityException) + { + return CipherUtilities.GetCipher(GetAsymmetricEncryptionAlgName(encryptionOid)); + } + } + + internal IWrapper CreateWrapper( + string encryptionOid) + { + try + { + return WrapperUtilities.GetWrapper(encryptionOid); + } + catch (SecurityUtilityException) + { + return WrapperUtilities.GetWrapper(GetAsymmetricEncryptionAlgName(encryptionOid)); + } + } + + internal string GetRfc3211WrapperName( + string oid) + { + if (oid == null) + throw new ArgumentNullException("oid"); + + string alg = (string) BaseCipherNames[oid]; + + if (alg == null) + throw new ArgumentException("no name for " + oid, "oid"); + + return alg + "RFC3211Wrap"; + } + + internal int GetKeySize( + string oid) + { + if (!KeySizes.Contains(oid)) + { + throw new ArgumentException("no keysize for " + oid, "oid"); + } + + return (int) KeySizes[oid]; + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSException.cs b/iTechSharp/srcbc/cms/CMSException.cs new file mode 100644 index 0000000..09a424e --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Cms +{ + public class CmsException + : Exception + { + public CmsException() + { + } + + public CmsException( + string name) + : base(name) + { + } + + public CmsException( + string name, + Exception e) + : base(name, e) + { + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSPBEKey.cs b/iTechSharp/srcbc/cms/CMSPBEKey.cs new file mode 100644 index 0000000..b7c9cf4 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSPBEKey.cs @@ -0,0 +1,68 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +//import javax.crypto.interfaces.PBEKey; + +namespace Org.BouncyCastle.Cms +{ + public abstract class CmsPbeKey + // TODO Create an equivalent interface somewhere? + // : PBEKey + : ICipherParameters + { + private readonly string password; + private readonly byte[] salt; + private readonly int iterationCount; + + public CmsPbeKey( + string password, + byte[] salt, + int iterationCount) + { + this.password = password; + this.salt = Arrays.Clone(salt); + this.iterationCount = iterationCount; + } + + public string Password + { + get { return password; } + } + + public byte[] Salt + { + get { return Arrays.Clone(salt); } + } + + [Obsolete("Use 'Salt' property instead")] + public byte[] GetSalt() + { + return Salt; + } + + public int IterationCount + { + get { return iterationCount; } + } + + public string Algorithm + { + get { return "PKCS5S2"; } + } + + public string Format + { + get { return "RAW"; } + } + + public byte[] GetEncoded() + { + return null; + } + + internal abstract KeyParameter GetEncoded(string algorithmOid); + } +} diff --git a/iTechSharp/srcbc/cms/CMSProcessable.cs b/iTechSharp/srcbc/cms/CMSProcessable.cs new file mode 100644 index 0000000..2a82689 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSProcessable.cs @@ -0,0 +1,27 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Cms +{ + public interface CmsProcessable + { + /// + /// Return a stream from which the data can be read. + /// + /// + /// This routine may be called more than once, but previous returned + /// streams should be closed first. + /// + Stream Read(); + + /// + /// Generic routine to copy out the data we want processed. + /// + /// + /// This routine may be called multiple times. + /// + void Write(Stream outStream); + + object GetContent(); + } +} diff --git a/iTechSharp/srcbc/cms/CMSProcessableByteArray.cs b/iTechSharp/srcbc/cms/CMSProcessableByteArray.cs new file mode 100644 index 0000000..dd00bab --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSProcessableByteArray.cs @@ -0,0 +1,36 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Cms +{ + /** + * a holding class for a byte array of data to be processed. + */ + public class CmsProcessableByteArray + : CmsProcessable + { + private readonly byte[] bytes; + + public CmsProcessableByteArray( + byte[] bytes) + { + this.bytes = bytes; + } + + public virtual Stream Read() + { + return new MemoryStream(bytes, false); + } + + public virtual void Write(Stream zOut) + { + zOut.Write(bytes, 0, bytes.Length); + } + + /// A clone of the byte array + public virtual object GetContent() + { + return bytes.Clone(); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSProcessableFile.cs b/iTechSharp/srcbc/cms/CMSProcessableFile.cs new file mode 100644 index 0000000..216ae1f --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSProcessableFile.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Cms +{ + /** + * a holding class for a file of data to be processed. + */ + public class CmsProcessableFile + : CmsProcessable + { + private const int DefaultBufSize = 32 * 1024; + + private readonly FileInfo _file; + private readonly int _bufSize; + + public CmsProcessableFile( + FileInfo file) + : this(file, DefaultBufSize) + { + } + + public CmsProcessableFile( + FileInfo file, + int bufSize) + { + _file = file; + _bufSize = bufSize; + } + + public virtual Stream Read() + { + return new FileStream( + _file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, _bufSize); + } + + public virtual void Write( + Stream zOut) + { + Stream inStr = Read(); + Streams.PipeAll(inStr, zOut); + inStr.Close(); + } + + /// The file handle + public virtual object GetContent() + { + return _file; + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSSignedData.cs b/iTechSharp/srcbc/cms/CMSSignedData.cs new file mode 100644 index 0000000..40cfcb3 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSSignedData.cs @@ -0,0 +1,430 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + /** + * general class for handling a pkcs7-signature message. + * + * A simple example of usage - note, in the example below the validity of + * the certificate isn't verified, just the fact that one of the certs + * matches the given signer... + * + *
      +	*  IX509Store              certs = s.GetCertificates();
      +	*  SignerInformationStore  signers = s.GetSignerInfos();
      +	*
      +	*  foreach (SignerInformation signer in signers.GetSigners())
      +	*  {
      +	*      ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
      +	*      X509Certificate cert = (X509Certificate) certList[0];
      +	*
      +	*      if (signer.Verify(cert.GetPublicKey()))
      +	*      {
      +	*          verified++;
      +	*      }
      +	*  }
      +	* 
      + */ + public class CmsSignedData + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private readonly CmsProcessable signedContent; + private SignedData signedData; + private ContentInfo contentInfo; + private SignerInformationStore signerInfoStore; + private IX509Store attrCertStore; + private IX509Store certificateStore; + private IX509Store crlStore; + private IDictionary hashes; + + private CmsSignedData( + CmsSignedData c) + { + this.signedData = c.signedData; + this.contentInfo = c.contentInfo; + this.signedContent = c.signedContent; + this.signerInfoStore = c.signerInfoStore; + } + + public CmsSignedData( + byte[] sigBlock) + : this(CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false))) + { + } + + public CmsSignedData( + CmsProcessable signedContent, + byte[] sigBlock) + : this(signedContent, CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false))) + { + } + + /** + * Content with detached signature, digests precomputed + * + * @param hashes a map of precomputed digests for content indexed by name of hash. + * @param sigBlock the signature object. + */ + public CmsSignedData( + IDictionary hashes, + byte[] sigBlock) + : this(hashes, CmsUtilities.ReadContentInfo(sigBlock)) + { + } + + /** + * base constructor - content with detached signature. + * + * @param signedContent the content that was signed. + * @param sigData the signature object. + */ + public CmsSignedData( + CmsProcessable signedContent, + Stream sigData) + : this(signedContent, CmsUtilities.ReadContentInfo(sigData)) + { + } + + /** + * base constructor - with encapsulated content + */ + public CmsSignedData( + Stream sigData) + : this(CmsUtilities.ReadContentInfo(sigData)) + { + } + + public CmsSignedData( + CmsProcessable signedContent, + ContentInfo sigData) + { + this.signedContent = signedContent; + this.contentInfo = sigData; + this.signedData = SignedData.GetInstance(contentInfo.Content); + } + + public CmsSignedData( + IDictionary hashes, + ContentInfo sigData) + { + this.hashes = hashes; + this.contentInfo = sigData; + this.signedData = SignedData.GetInstance(contentInfo.Content); + } + + public CmsSignedData( + ContentInfo sigData) + { + this.contentInfo = sigData; + this.signedData = SignedData.GetInstance(contentInfo.Content); + + // + // this can happen if the signed message is sent simply to send a + // certificate chain. + // + if (signedData.EncapContentInfo.Content != null) + { + this.signedContent = new CmsProcessableByteArray( + ((Asn1OctetString)(signedData.EncapContentInfo.Content)).GetOctets()); + } +// else +// { +// this.signedContent = null; +// } + } + + /// Return the version number for this object. + public int Version + { + get { return signedData.Version.Value.IntValue; } + } + + /** + * return the collection of signers that are associated with the + * signatures for the message. + */ + public SignerInformationStore GetSignerInfos() + { + if (signerInfoStore == null) + { + IList signerInfos = new ArrayList(); + Asn1Set s = signedData.SignerInfos; + + foreach (object obj in s) + { + SignerInfo info = SignerInfo.GetInstance(obj); + DerObjectIdentifier contentType = signedData.EncapContentInfo.ContentType; + + if (hashes == null) + { + signerInfos.Add(new SignerInformation(info, contentType, signedContent, null)); + } + else + { + byte[] hash = (byte[]) hashes[info.DigestAlgorithm.ObjectID.Id]; + + signerInfos.Add(new SignerInformation(info, contentType, null, new BaseDigestCalculator(hash))); + } + } + + signerInfoStore = new SignerInformationStore(signerInfos); + } + + return signerInfoStore; + } + + /** + * return a X509Store containing the attribute certificates, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of attribute certificates + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetAttributeCertificates( + string type) + { + if (attrCertStore == null) + { + attrCertStore = Helper.CreateAttributeStore(type, signedData.Certificates); + } + + return attrCertStore; + } + + /** + * return a X509Store containing the public key certificates, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of public key certificates + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetCertificates( + string type) + { + if (certificateStore == null) + { + certificateStore = Helper.CreateCertificateStore(type, signedData.Certificates); + } + + return certificateStore; + } + + /** + * return a X509Store containing CRLs, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of CRLs + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetCrls( + string type) + { + if (crlStore == null) + { + crlStore = Helper.CreateCrlStore(type, signedData.CRLs); + } + + return crlStore; + } + + /** + * Return the a string representation of the OID associated with the + * encapsulated content info structure carried in the signed data. + * + * @return the OID for the content type. + */ + public string SignedContentTypeOid + { + get { return signedData.EncapContentInfo.ContentType.Id; } + } + + public CmsProcessable SignedContent + { + get { return signedContent; } + } + + /** + * return the ContentInfo + */ + public ContentInfo ContentInfo + { + get { return contentInfo; } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return contentInfo.GetEncoded(); + } + + /** + * Replace the signerinformation store associated with this + * CmsSignedData object with the new one passed in. You would + * probably only want to do this if you wanted to change the unsigned + * attributes associated with a signer, or perhaps delete one. + * + * @param signedData the signed data object to be used as a base. + * @param signerInformationStore the new signer information store to use. + * @return a new signed data object. + */ + public static CmsSignedData ReplaceSigners( + CmsSignedData signedData, + SignerInformationStore signerInformationStore) + { + // + // copy + // + CmsSignedData cms = new CmsSignedData(signedData); + + // + // replace the store + // + cms.signerInfoStore = signerInformationStore; + + // + // replace the signers in the SignedData object + // + Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); + Asn1EncodableVector vec = new Asn1EncodableVector(); + + foreach (SignerInformation signer in signerInformationStore.GetSigners()) + { + digestAlgs.Add(FixAlgID(signer.DigestAlgorithmID)); + vec.Add(signer.ToSignerInfo()); + } + + Asn1Set digests = new DerSet(digestAlgs); + Asn1Set signers = new DerSet(vec); + Asn1Sequence sD = (Asn1Sequence)signedData.signedData.ToAsn1Object(); + + // + // signers are the last item in the sequence. + // + vec = new Asn1EncodableVector( + sD[0], // version + digests); + + for (int i = 2; i != sD.Count - 1; i++) + { + vec.Add(sD[i]); + } + + vec.Add(signers); + + cms.signedData = SignedData.GetInstance(new BerSequence(vec)); + + // + // replace the contentInfo with the new one + // + cms.contentInfo = new ContentInfo(cms.contentInfo.ContentType, cms.signedData); + + return cms; + } + + /** + * Replace the certificate and CRL information associated with this + * CmsSignedData object with the new one passed in. + * + * @param signedData the signed data object to be used as a base. + * @param x509Certs the new certificates to be used. + * @param x509Crls the new CRLs to be used. + * @return a new signed data object. + * @exception CmsException if there is an error processing the stores + */ + public static CmsSignedData ReplaceCertificatesAndCrls( + CmsSignedData signedData, + IX509Store x509Certs, + IX509Store x509Crls, + IX509Store x509AttrCerts) + { + if (x509AttrCerts != null) + throw Platform.CreateNotImplementedException("Currently can't replace attribute certificates"); + + // + // copy + // + CmsSignedData cms = new CmsSignedData(signedData); + + // + // replace the certs and crls in the SignedData object + // + Asn1Set certs = null; + try + { + Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList( + CmsUtilities.GetCertificatesFromStore(x509Certs)); + + if (asn1Set.Count != 0) + { + certs = asn1Set; + } + } + catch (X509StoreException e) + { + throw new CmsException("error getting certificates from store", e); + } + + Asn1Set crls = null; + try + { + Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList( + CmsUtilities.GetCrlsFromStore(x509Crls)); + + if (asn1Set.Count != 0) + { + crls = asn1Set; + } + } + catch (X509StoreException e) + { + throw new CmsException("error getting CRLs from store", e); + } + + // + // replace the CMS structure. + // + SignedData old = signedData.signedData; + cms.signedData = new SignedData( + old.DigestAlgorithms, + old.EncapContentInfo, + certs, + crls, + old.SignerInfos); + + // + // replace the contentInfo with the new one + // + cms.contentInfo = new ContentInfo(cms.contentInfo.ContentType, cms.signedData); + + return cms; + } + + private static AlgorithmIdentifier FixAlgID( + AlgorithmIdentifier algId) + { + if (algId.Parameters == null) + return new AlgorithmIdentifier(algId.ObjectID, DerNull.Instance); + + return algId; + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSSignedDataGenerator.cs b/iTechSharp/srcbc/cms/CMSSignedDataGenerator.cs new file mode 100644 index 0000000..5315881 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSSignedDataGenerator.cs @@ -0,0 +1,501 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * general class for generating a pkcs7-signature message. + *

      + * A simple example of usage. + * + *

      +     *      IX509Store certs...
      +     *      IX509Store crls...
      +     *      CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
      +     *
      +     *      gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
      +     *      gen.AddCertificates(certs);
      +     *      gen.AddCrls(crls);
      +     *
      +     *      CmsSignedData data = gen.Generate(content);
      +     * 
      + *

      + */ + public class CmsSignedDataGenerator + : CmsSignedGenerator + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private readonly ArrayList signerInfs = new ArrayList(); + + internal class DigOutputStream + : BaseOutputStream + { + private readonly IDigest dig; + + public DigOutputStream( + IDigest dig) + { + this.dig = dig; + } + + public override void Write( + byte[] b, + int off, + int len) + { + dig.BlockUpdate(b, off, len); + } + + public override void WriteByte( + byte b) + { + dig.Update(b); + } + } + + internal class SigOutputStream + : BaseOutputStream + { + private readonly ISigner sig; + + public SigOutputStream( + ISigner sig) + { + this.sig = sig; + } + + public override void Write( + byte[] b, + int off, + int len) + { + try + { + sig.BlockUpdate(b, off, len); + } + catch (SignatureException e) + { + throw new IOException("signature problem: " + e); + } + } + + public override void WriteByte( + byte b) + { + try + { + sig.Update(b); + } + catch (SignatureException e) + { + throw new IOException("signature problem: " + e); + } + } + } + + private class SignerInf + { + CmsSignedGenerator outer; + AsymmetricKeyParameter key; + X509Certificate cert; + string digestOID; + string encOID; + CmsAttributeTableGenerator sAttr; + CmsAttributeTableGenerator unsAttr; + Asn1.Cms.AttributeTable baseSignedTable; + + internal SignerInf( + CmsSignedGenerator outer, + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string encOID) + { + this.outer = outer; + this.key = key; + this.cert = cert; + this.digestOID = digestOID; + this.encOID = encOID; + } + + internal SignerInf( + CmsSignedGenerator outer, + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string encOID, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + Asn1.Cms.AttributeTable baseSignedTable) + { + this.outer = outer; + this.key = key; + this.cert = cert; + this.digestOID = digestOID; + this.encOID = encOID; + this.sAttr = sAttr; + this.unsAttr = unsAttr; + this.baseSignedTable = baseSignedTable; + } + + internal AsymmetricKeyParameter GetKey() + { + return key; + } + + internal X509Certificate GetCertificate() + { + return cert; + } + + internal AlgorithmIdentifier DigestAlgorithmID + { + get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), null); } + } + + internal string DigestAlgOid + { + get { return digestOID; } + } + + internal Asn1Object DigestAlgParams + { + get { return null; } + } + + internal AlgorithmIdentifier EncryptionAlgorithmID + { + get { return new AlgorithmIdentifier(new DerObjectIdentifier(encOID), DerNull.Instance); } + } + + internal string EncryptionAlgOid + { + get { return encOID; } + } + + internal CmsAttributeTableGenerator SignedAttributes + { + get { return sAttr; } + } + + internal CmsAttributeTableGenerator UnsignedAttributes + { + get { return unsAttr; } + } + + internal Asn1.Cms.SignerInfo ToSignerInfo( + DerObjectIdentifier contentType, + CmsProcessable content, + SecureRandom random, + bool isCounterSignature) + { + AlgorithmIdentifier digAlgId = new AlgorithmIdentifier( + new DerObjectIdentifier(this.DigestAlgOid), DerNull.Instance); + AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(this.EncryptionAlgOid); + string digestName = Helper.GetDigestAlgName(digestOID); + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); + ISigner sig = Helper.GetSignatureInstance(signatureName); + IDigest dig = Helper.GetDigestInstance(digestName); + + byte[] hash = null; + + if (content != null) + { + content.Write(new DigOutputStream(dig)); + + hash = DigestUtilities.DoFinal(dig); + + outer._digests.Add(digestOID, hash.Clone()); + } + + IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash); + Asn1.Cms.AttributeTable signed = (sAttr != null) +// ? sAttr.GetAttributes(Collections.unmodifiableMap(parameters)) + ? sAttr.GetAttributes(parameters) + : null; + + if (isCounterSignature) + { + Hashtable ats = signed.ToHashtable(); + + ats.Remove(CmsAttributes.ContentType); + + signed = new Asn1.Cms.AttributeTable(ats); + } + + Asn1Set signedAttr = outer.GetAttributeSet(signed); + + + // + // sig must be composed from the DER encoding. + // + byte[] tmp; + if (signedAttr != null) + { + tmp = signedAttr.GetEncoded(Asn1Encodable.Der); + } + else + { + MemoryStream bOut = new MemoryStream(); + content.Write(bOut); + tmp = bOut.ToArray(); + } + + sig.Init(true, new ParametersWithRandom(key, random)); + sig.BlockUpdate(tmp, 0, tmp.Length); + + Asn1OctetString encDigest = new DerOctetString(sig.GenerateSignature()); + + IDictionary baseParameters = outer.GetBaseParameters(contentType, digAlgId, hash); + baseParameters[CmsAttributeTableParameter.Signature] = encDigest.GetOctets().Clone(); + + Asn1.Cms.AttributeTable unsigned = (unsAttr != null) +// ? unsAttr.GetAttributes(Collections.unmodifiableMap(baseParameters)) + ? unsAttr.GetAttributes(baseParameters) + : null; + + Asn1Set unsignedAttr = outer.GetAttributeSet(unsigned); + + X509Certificate cert = this.GetCertificate(); + TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + Asn1.Cms.IssuerAndSerialNumber encSid = new Asn1.Cms.IssuerAndSerialNumber( + tbs.Issuer, tbs.SerialNumber.Value); + + return new Asn1.Cms.SignerInfo(new SignerIdentifier(encSid), digAlgId, + signedAttr, encAlgId, encDigest, unsignedAttr); + } + } + + public CmsSignedDataGenerator() + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsSignedDataGenerator( + SecureRandom rand) + : base(rand) + { + } + + /** + * add a signer - no attributes other than the default ones will be + * provided here. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + new DefaultSignedAttributeTableGenerator(), null, null)); + } + + /** + * add a signer with extra signed/unsigned attributes. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + new DefaultSignedAttributeTableGenerator(signedAttr), + new SimpleAttributeTableGenerator(unsignedAttr), + signedAttr)); + } + + /** + * add a signer with extra signed/unsigned attributes based on generators. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID, + CmsAttributeTableGenerator signedAttrGen, + CmsAttributeTableGenerator unsignedAttrGen) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + signedAttrGen, unsignedAttrGen, null)); + } + + private static AlgorithmIdentifier FixAlgID( + AlgorithmIdentifier algId) + { + if (algId.Parameters == null) + return new AlgorithmIdentifier(algId.ObjectID, DerNull.Instance); + + return algId; + } + + /** + * generate a signed object that for a CMS Signed Data object + */ + public CmsSignedData Generate( + CmsProcessable content) + { + return Generate(content, false); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + */ + public CmsSignedData Generate( + string signedContentType, + CmsProcessable content, + bool encapsulate) + { + Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); + Asn1EncodableVector signerInfos = new Asn1EncodableVector(); + + _digests.Clear(); // clear the current preserved digest state + + // + // add the precalculated SignerInfo objects. + // + foreach (SignerInformation signer in _signers) + { + digestAlgs.Add(FixAlgID(signer.DigestAlgorithmID)); + signerInfos.Add(signer.ToSignerInfo()); + } + + // + // add the SignerInfo objects + // + DerObjectIdentifier contentTypeOID; + bool isCounterSignature; + + if (signedContentType != null) + { + contentTypeOID = new DerObjectIdentifier(signedContentType); + isCounterSignature = false; + } + else + { + contentTypeOID = CmsObjectIdentifiers.Data; + isCounterSignature = true; + } + + foreach (SignerInf signer in signerInfs) + { + try + { + digestAlgs.Add(FixAlgID(signer.DigestAlgorithmID)); + signerInfos.Add(signer.ToSignerInfo(contentTypeOID, content, rand, isCounterSignature)); + } + catch (IOException e) + { + throw new CmsException("encoding error.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key inappropriate for signature.", e); + } + catch (SignatureException e) + { + throw new CmsException("error creating signature.", e); + } + catch (CertificateEncodingException e) + { + throw new CmsException("error creating sid.", e); + } + } + + Asn1Set certificates = null; + + if (_certs.Count != 0) + { + certificates = CmsUtilities.CreateBerSetFromList(_certs); + } + + Asn1Set certrevlist = null; + + if (_crls.Count != 0) + { + certrevlist = CmsUtilities.CreateBerSetFromList(_crls); + } + + Asn1OctetString octs = null; + if (encapsulate) + { + MemoryStream bOut = new MemoryStream(); + try + { + content.Write(bOut); + } + catch (IOException e) + { + throw new CmsException("encapsulation error.", e); + } + + octs = new BerOctetString(bOut.ToArray()); + } + + Asn1.Cms.ContentInfo encInfo = new Asn1.Cms.ContentInfo(contentTypeOID, octs); + + Asn1.Cms.SignedData sd = new Asn1.Cms.SignedData( + new DerSet(digestAlgs), + encInfo, + certificates, + certrevlist, + new DerSet(signerInfos)); + + Asn1.Cms.ContentInfo contentInfo = new Asn1.Cms.ContentInfo( + PkcsObjectIdentifiers.SignedData, sd); + + return new CmsSignedData(content, contentInfo); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". + */ + public CmsSignedData Generate( + CmsProcessable content, + bool encapsulate) + { + return this.Generate(Data, content, encapsulate); + } + + /** + * generate a set of one or more SignerInformation objects representing counter signatures on + * the passed in SignerInformation object. + * + * @param signer the signer to be countersigned + * @param sigProvider the provider to be used for counter signing. + * @return a store containing the signers. + */ + public SignerInformationStore GenerateCounterSigners( + SignerInformation signer) + { + return this.Generate(null, new CmsProcessableByteArray(signer.GetSignature()), false).GetSignerInfos(); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSSignedDataParser.cs b/iTechSharp/srcbc/cms/CMSSignedDataParser.cs new file mode 100644 index 0000000..7de56de --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSSignedDataParser.cs @@ -0,0 +1,565 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + /** + * Parsing class for an CMS Signed Data object from an input stream. + *

      + * Note: that because we are in a streaming mode only one signer can be tried and it is important + * that the methods on the parser are called in the appropriate order. + *

      + *

      + * A simple example of usage for an encapsulated signature. + *

      + *

      + * Two notes: first, in the example below the validity of + * the certificate isn't verified, just the fact that one of the certs + * matches the given signer, and, second, because we are in a streaming + * mode the order of the operations is important. + *

      + *
      +	*      CmsSignedDataParser     sp = new CmsSignedDataParser(encapSigData);
      +	*
      +	*      sp.GetSignedContent().Drain();
      +	*
      +	*      IX509Store              certs = sp.GetCertificates();
      +	*      SignerInformationStore  signers = sp.GetSignerInfos();
      +	*
      +	*      foreach (SignerInformation signer in signers.GetSigners())
      +	*      {
      +	*          ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
      +	*          X509Certificate cert = (X509Certificate) certList[0];
      +	*
      +	*          Console.WriteLine("verify returns: " + signer.Verify(cert));
      +	*      }
      +	* 
      + * Note also: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + *
      +	*          CmsSignedDataParser     ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
      +	*  
      + * where bufSize is a suitably large buffer size. + */ + public class CmsSignedDataParser + : CmsContentInfoParser + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private SignedDataParser _signedData; + private CmsTypedStream _signedContent; + private IDictionary _digests; + + private SignerInformationStore _signerInfoStore; + private Asn1Set _certSet, _crlSet; + private bool _isCertCrlParsed; + private IX509Store _attributeStore; + private IX509Store _certificateStore; + private IX509Store _crlStore; + + public CmsSignedDataParser( + byte[] sigBlock) + : this(new MemoryStream(sigBlock, false)) + { + } + + public CmsSignedDataParser( + CmsTypedStream signedContent, + byte[] sigBlock) + : this(signedContent, new MemoryStream(sigBlock, false)) + { + } + + /** + * base constructor - with encapsulated content + */ + public CmsSignedDataParser( + Stream sigData) + : this(null, sigData) + { + } + + /** + * base constructor + * + * @param signedContent the content that was signed. + * @param sigData the signature object. + */ + public CmsSignedDataParser( + CmsTypedStream signedContent, + Stream sigData) + : base(sigData) + { + try + { + this._signedContent = signedContent; + this._signedData = SignedDataParser.GetInstance(this.contentInfo.GetContent(Asn1Tags.Sequence)); + this._digests = new Hashtable(); + + Asn1SetParser digAlgs = _signedData.GetDigestAlgorithms(); + IAsn1Convertible o; + + while ((o = digAlgs.ReadObject()) != null) + { + AlgorithmIdentifier id = AlgorithmIdentifier.GetInstance(o.ToAsn1Object()); + + try + { + string digestName = Helper.GetDigestAlgName(id.ObjectID.Id); + IDigest dig = Helper.GetDigestInstance(digestName); + + this._digests[digestName] = dig; + } + catch (SecurityUtilityException) + { + // ignore + } + } + + // + // If the message is simply a certificate chain message GetContent() may return null. + // + ContentInfoParser cont = _signedData.GetEncapContentInfo(); + Asn1OctetStringParser octs = (Asn1OctetStringParser) + cont.GetContent(Asn1Tags.OctetString); + + if (octs != null) + { + CmsTypedStream ctStr = new CmsTypedStream( + cont.ContentType.Id, octs.GetOctetStream()); + + if (_signedContent == null) + { + this._signedContent = ctStr; + } + else + { + // + // content passed in, need to read past empty encapsulated content info object if present + // + ctStr.Drain(); + } + } + } + catch (IOException e) + { + throw new CmsException("io exception: " + e.Message, e); + } + + if (_digests.Count < 1) + { + throw new CmsException("no digests could be created for message."); + } + } + + /** + * Return the version number for the SignedData object + * + * @return the version number + */ + public int Version + { + get { return _signedData.Version.Value.IntValue; } + } + + /** + * return the collection of signers that are associated with the + * signatures for the message. + * @throws CmsException + */ + public SignerInformationStore GetSignerInfos() + { + if (_signerInfoStore == null) + { + PopulateCertCrlSets(); + + IList signerInfos = new ArrayList(); + IDictionary hashes = new Hashtable(); + + foreach (object digestKey in _digests.Keys) + { + hashes[digestKey] = DigestUtilities.DoFinal( + (IDigest)_digests[digestKey]); + } + + try + { + Asn1SetParser s = _signedData.GetSignerInfos(); + IAsn1Convertible o; + + while ((o = s.ReadObject()) != null) + { + SignerInfo info = SignerInfo.GetInstance(o.ToAsn1Object()); + string digestName = Helper.GetDigestAlgName( + info.DigestAlgorithm.ObjectID.Id); + + byte[] hash = (byte[]) hashes[digestName]; + DerObjectIdentifier oid = new DerObjectIdentifier(_signedContent.ContentType); + + signerInfos.Add(new SignerInformation(info, oid, null, new BaseDigestCalculator(hash))); + } + } + catch (IOException e) + { + throw new CmsException("io exception: " + e.Message, e); + } + + _signerInfoStore = new SignerInformationStore(signerInfos); + } + + return _signerInfoStore; + } + + /** + * return a X509Store containing the attribute certificates, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of attribute certificates + * @exception org.bouncycastle.x509.NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetAttributeCertificates( + string type) + { + if (_attributeStore == null) + { + PopulateCertCrlSets(); + + _attributeStore = Helper.CreateAttributeStore(type, _certSet); + } + + return _attributeStore; + } + + /** + * return a X509Store containing the public key certificates, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of public key certificates + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetCertificates( + string type) + { + if (_certificateStore == null) + { + PopulateCertCrlSets(); + + _certificateStore = Helper.CreateCertificateStore(type, _certSet); + } + + return _certificateStore; + } + + /** + * return a X509Store containing CRLs, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of CRLs + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetCrls( + string type) + { + if (_crlStore == null) + { + PopulateCertCrlSets(); + + _crlStore = Helper.CreateCrlStore(type, _crlSet); + } + + return _crlStore; + } + + private void PopulateCertCrlSets() + { + if (_isCertCrlParsed) + return; + + _isCertCrlParsed = true; + + try + { + // care! Streaming - Must process the GetCertificates() result before calling GetCrls() + _certSet = GetAsn1Set(_signedData.GetCertificates()); + _crlSet = GetAsn1Set(_signedData.GetCrls()); + } + catch (IOException e) + { + throw new CmsException("problem parsing cert/crl sets", e); + } + } + + public CmsTypedStream GetSignedContent() + { + if (_signedContent == null) + { + return null; + } + + Stream digStream = _signedContent.ContentStream; + + foreach (IDigest digest in _digests.Values) + { + digStream = new DigestStream(digStream, digest, null); + } + + return new CmsTypedStream(_signedContent.ContentType, digStream); + } + + /** + * Replace the signerinformation store associated with the passed + * in message contained in the stream original with the new one passed in. + * You would probably only want to do this if you wanted to change the unsigned + * attributes associated with a signer, or perhaps delete one. + *

      + * The output stream is returned unclosed. + *

      + * @param original the signed data stream to be used as a base. + * @param signerInformationStore the new signer information store to use. + * @param out the stream to Write the new signed data object to. + * @return out. + */ + public static Stream ReplaceSigners( + Stream original, + SignerInformationStore signerInformationStore, + Stream outStr) + { + Asn1StreamParser inStr = new Asn1StreamParser(original, CmsUtilities.MaximumMemory); + ContentInfoParser contentInfo = new ContentInfoParser((Asn1SequenceParser)inStr.ReadObject()); + SignedDataParser signedData = SignedDataParser.GetInstance(contentInfo.GetContent(Asn1Tags.Sequence)); + + BerSequenceGenerator sGen = new BerSequenceGenerator(outStr); + + sGen.AddObject(CmsObjectIdentifiers.SignedData); + + BerSequenceGenerator sigGen = new BerSequenceGenerator(sGen.GetRawOutputStream(), 0, true); + + // version number + sigGen.AddObject(signedData.Version); + + // digests + signedData.GetDigestAlgorithms().ToAsn1Object(); // skip old ones + + Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); + + foreach (SignerInformation signer in signerInformationStore.GetSigners()) + { + digestAlgs.Add(FixAlgID(signer.DigestAlgorithmID)); + } + + WriteToGenerator(sigGen, new DerSet(digestAlgs)); + + // encap content info + ContentInfoParser encapContentInfo = signedData.GetEncapContentInfo(); + + BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); + + eiGen.AddObject(encapContentInfo.ContentType); + + Asn1OctetStringParser octs = (Asn1OctetStringParser)encapContentInfo.GetContent(Asn1Tags.OctetString); + + if (octs != null) + { + PipeOctetString(octs, eiGen.GetRawOutputStream()); + } + + eiGen.Close(); + + + WriteSetToGeneratorTagged(sigGen, signedData.GetCertificates(), 0); + WriteSetToGeneratorTagged(sigGen, signedData.GetCrls(), 1); + + + Asn1EncodableVector signerInfos = new Asn1EncodableVector(); + foreach (SignerInformation signer in signerInformationStore.GetSigners()) + { + signerInfos.Add(signer.ToSignerInfo()); + } + + WriteToGenerator(sigGen, new DerSet(signerInfos)); + + sigGen.Close(); + + sGen.Close(); + + return outStr; + } + + /** + * Replace the certificate and CRL information associated with this + * CMSSignedData object with the new one passed in. + *

      + * The output stream is returned unclosed. + *

      + * @param original the signed data stream to be used as a base. + * @param certsAndCrls the new certificates and CRLs to be used. + * @param out the stream to Write the new signed data object to. + * @return out. + * @exception CmsException if there is an error processing the CertStore + */ + public static Stream ReplaceCertificatesAndCrls( + Stream original, + IX509Store x509Certs, + IX509Store x509Crls, + IX509Store x509AttrCerts, + Stream outStr) + { + if (x509AttrCerts != null) + throw Platform.CreateNotImplementedException("Currently can't replace attribute certificates"); + + Asn1StreamParser inStr = new Asn1StreamParser(original, CmsUtilities.MaximumMemory); + ContentInfoParser contentInfo = new ContentInfoParser((Asn1SequenceParser)inStr.ReadObject()); + SignedDataParser signedData = SignedDataParser.GetInstance(contentInfo.GetContent(Asn1Tags.Sequence)); + + BerSequenceGenerator sGen = new BerSequenceGenerator(outStr); + + sGen.AddObject(CmsObjectIdentifiers.SignedData); + + BerSequenceGenerator sigGen = new BerSequenceGenerator(sGen.GetRawOutputStream(), 0, true); + + // version number + sigGen.AddObject(signedData.Version); + + // digests + WriteToGenerator(sigGen, signedData.GetDigestAlgorithms().ToAsn1Object()); + + // encap content info + ContentInfoParser encapContentInfo = signedData.GetEncapContentInfo(); + + BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); + + eiGen.AddObject(encapContentInfo.ContentType); + + Asn1OctetStringParser octs = (Asn1OctetStringParser) + encapContentInfo.GetContent(Asn1Tags.OctetString); + + if (octs != null) + { + PipeOctetString(octs, eiGen.GetRawOutputStream()); + } + + eiGen.Close(); + + // + // skip existing certs and CRLs + // + GetAsn1Set(signedData.GetCertificates()); + GetAsn1Set(signedData.GetCrls()); + + // + // replace the certs and crls in the SignedData object + // + Asn1Set certs; + try + { + certs = CmsUtilities.CreateBerSetFromList( + CmsUtilities.GetCertificatesFromStore(x509Certs)); + } + catch (X509StoreException e) + { + throw new CmsException("error getting certs from certStore", e); + } + + if (certs.Count > 0) + { + WriteToGenerator(sigGen, new DerTaggedObject(false, 0, certs)); + } + + Asn1Set crls; + try + { + crls = CmsUtilities.CreateBerSetFromList( + CmsUtilities.GetCrlsFromStore(x509Crls)); + } + catch (X509StoreException e) + { + throw new CmsException("error getting crls from certStore", e); + } + + if (crls.Count > 0) + { + WriteToGenerator(sigGen, new DerTaggedObject(false, 1, crls)); + } + + WriteToGenerator(sigGen, signedData.GetSignerInfos().ToAsn1Object()); + + sigGen.Close(); + + sGen.Close(); + + return outStr; + } + + private static AlgorithmIdentifier FixAlgID( + AlgorithmIdentifier algId) + { + if (algId.Parameters == null) + return new AlgorithmIdentifier(algId.ObjectID, DerNull.Instance); + + return algId; + } + + private static void WriteSetToGeneratorTagged( + Asn1Generator asn1Gen, + Asn1SetParser asn1SetParser, + int tagNo) + { + Asn1Set asn1Set = GetAsn1Set(asn1SetParser); + + if (asn1Set != null) + { + Asn1TaggedObject taggedObj = (asn1SetParser is BerSetParser) + ? new BerTaggedObject(false, tagNo, asn1Set) + : new DerTaggedObject(false, tagNo, asn1Set); + + WriteToGenerator(asn1Gen, taggedObj); + } + } + + private static Asn1Set GetAsn1Set( + Asn1SetParser asn1SetParser) + { + return asn1SetParser == null + ? null + : Asn1Set.GetInstance(asn1SetParser.ToAsn1Object()); + } + + private static void WriteToGenerator( + Asn1Generator ag, + Asn1Encodable ae) + { + byte[] encoded = ae.GetEncoded(); + ag.GetRawOutputStream().Write(encoded, 0, encoded.Length); + } + + private static void PipeOctetString( + Asn1OctetStringParser octs, + Stream output) + { + BerOctetStringGenerator octGen = new BerOctetStringGenerator(output, 0, true); + // TODO Allow specification of a specific fragment size? + Stream outOctets = octGen.GetOctetOutputStream(); + Streams.PipeAll(octs.GetOctetStream(), outOctets); + outOctets.Close(); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSSignedDataStreamGenerator.cs b/iTechSharp/srcbc/cms/CMSSignedDataStreamGenerator.cs new file mode 100644 index 0000000..755c6c7 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSSignedDataStreamGenerator.cs @@ -0,0 +1,690 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * General class for generating a pkcs7-signature message stream. + *

      + * A simple example of usage. + *

      + *
      +    *      IX509Store                   certs...
      +    *      CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
      +    *
      +    *      gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
      +    *
      +    *      gen.AddCertificates(certs);
      +    *
      +    *      Stream sigOut = gen.Open(bOut);
      +    *
      +    *      sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
      +    *
      +    *      sigOut.Close();
      +    * 
      + */ + public class CmsSignedDataStreamGenerator + : CmsSignedGenerator + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private readonly ArrayList _signerInfs = new ArrayList(); + private readonly ArrayList _messageDigests = new ArrayList(); + private int _bufferSize; + + private class SignerInf + { + private readonly CmsSignedDataStreamGenerator outer; + + AsymmetricKeyParameter _key; + X509Certificate _cert; + string _digestOID; + string _encOID; + CmsAttributeTableGenerator _sAttr; + CmsAttributeTableGenerator _unsAttr; + IDigest _digest; + ISigner _signature; + + internal SignerInf( + CmsSignedDataStreamGenerator outer, + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string encOID, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + IDigest digest, + ISigner signature) + { + this.outer = outer; + + _key = key; + _cert = cert; + _digestOID = digestOID; + _encOID = encOID; + _sAttr = sAttr; + _unsAttr = unsAttr; + _digest = digest; + _signature = signature; + } + + internal AsymmetricKeyParameter Key + { + get { return _key; } + } + + internal X509Certificate Certificate + { + get { return _cert; } + } + + internal AlgorithmIdentifier DigestAlgorithmID + { + get { return new AlgorithmIdentifier(new DerObjectIdentifier(_digestOID), null); } + } + + internal string DigestAlgOid + { + get { return _digestOID; } + } + + internal Asn1Object DigestAlgParams + { + get { return null; } + } + + internal string EncryptionAlgOid + { + get { return _encOID; } + } + +// internal Asn1.Cms.AttributeTable SignedAttributes +// { +// get { return _sAttr; } +// } +// +// internal Asn1.Cms.AttributeTable UnsignedAttributes +// { +// get { return _unsAttr; } +// } + + internal SignerInfo ToSignerInfo( + DerObjectIdentifier contentType) + { + AlgorithmIdentifier digAlgId = new AlgorithmIdentifier( + new DerObjectIdentifier(this.DigestAlgOid), DerNull.Instance); + AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(this.EncryptionAlgOid); + + byte[] hash = DigestUtilities.DoFinal(_digest); + + outer._digests.Add(_digestOID, hash.Clone()); + + IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash); + + Asn1.Cms.AttributeTable signed = (_sAttr != null) +// ? _sAttr.GetAttributes(Collections.unmodifiableMap(parameters)) + ? _sAttr.GetAttributes(parameters) + : null; + + Asn1Set signedAttr = outer.GetAttributeSet(signed); + + // + // sig must be composed from the DER encoding. + // + byte[] tmp; + if (signedAttr != null) + { + tmp = signedAttr.GetEncoded(Asn1Encodable.Der); + } + else + { + throw new Exception("signatures without signed attributes not implemented."); + } + + _signature.BlockUpdate(tmp, 0, tmp.Length); + + Asn1OctetString encDigest = new DerOctetString(_signature.GenerateSignature()); + + parameters = outer.GetBaseParameters(contentType, digAlgId, hash); + parameters[CmsAttributeTableParameter.Signature] = encDigest.GetOctets().Clone(); + + Asn1.Cms.AttributeTable unsigned = (_unsAttr != null) +// ? _unsAttr.getAttributes(Collections.unmodifiableMap(parameters)) + ? _unsAttr.GetAttributes(parameters) + : null; + + Asn1Set unsignedAttr = outer.GetAttributeSet(unsigned); + + X509Certificate cert = this.Certificate; + TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + IssuerAndSerialNumber encSid = new IssuerAndSerialNumber( + tbs.Issuer, tbs.SerialNumber.Value); + + return new SignerInfo(new SignerIdentifier(encSid), digAlgId, + signedAttr, encAlgId, encDigest, unsignedAttr); + } + + } + + public CmsSignedDataStreamGenerator() + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsSignedDataStreamGenerator( + SecureRandom rand) + : base(rand) + { + } + + /** + * Set the underlying string size for encapsulated data + * + * @param bufferSize length of octet strings to buffer the data. + */ + public void SetBufferSize( + int bufferSize) + { + _bufferSize = bufferSize; + } + + /** + * add a signer - no attributes other than the default ones will be + * provided here. + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID) + { + AddSigner(privateKey, cert, digestOID, + new DefaultSignedAttributeTableGenerator(), null); + } + + /** + * add a signer with extra signed/unsigned attributes. + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + AddSigner(privateKey, cert, digestOID, + new DefaultSignedAttributeTableGenerator(signedAttr), + new SimpleAttributeTableGenerator(unsignedAttr)); + } + + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID, + CmsAttributeTableGenerator signedAttrGenerator, + CmsAttributeTableGenerator unsignedAttrGenerator) + { + string encOID = GetEncOid(privateKey, digestOID); + string digestName = Helper.GetDigestAlgName(digestOID); + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); + ISigner sig = Helper.GetSignatureInstance(signatureName); + IDigest dig = Helper.GetDigestInstance(digestName); + + sig.Init(true, new ParametersWithRandom(privateKey, rand)); + + _signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + signedAttrGenerator, unsignedAttrGenerator, dig, sig)); + _messageDigests.Add(dig); + } + + private static AlgorithmIdentifier FixAlgID( + AlgorithmIdentifier algId) + { + if (algId.Parameters == null) + return new AlgorithmIdentifier(algId.ObjectID, DerNull.Instance); + + return algId; + } + + /** + * generate a signed object that for a CMS Signed Data object + */ + public Stream Open( + Stream outStream) + { + return Open(outStream, false); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". + */ + public Stream Open( + Stream outStream, + bool encapsulate) + { + return Open(outStream, Data, encapsulate); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". If dataOutputStream is non null the data + * being signed will be written to the stream as it is processed. + * @param out stream the CMS object is to be written to. + * @param encapsulate true if data should be encapsulated. + * @param dataOutputStream output stream to copy the data being signed to. + */ + public Stream Open( + Stream outStream, + bool encapsulate, + Stream dataOutputStream) + { + return Open(outStream, Data, encapsulate, dataOutputStream); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + */ + public Stream Open( + Stream outStream, + string signedContentType, + bool encapsulate) + { + return Open(outStream, signedContentType, encapsulate, null); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + * @param out stream the CMS object is to be written to. + * @param signedContentType OID for data to be signed. + * @param encapsulate true if data should be encapsulated. + * @param dataOutputStream output stream to copy the data being signed to. + */ + public Stream Open( + Stream outStream, + string signedContentType, + bool encapsulate, + Stream dataOutputStream) + { + if (outStream == null) + throw new ArgumentNullException("outStream"); + if (!outStream.CanWrite) + throw new ArgumentException("Expected writeable stream", "outStream"); + if (dataOutputStream != null && !dataOutputStream.CanWrite) + throw new ArgumentException("Expected writeable stream", "dataOutputStream"); + + // + // ContentInfo + // + BerSequenceGenerator sGen = new BerSequenceGenerator(outStream); + + sGen.AddObject(CmsObjectIdentifiers.SignedData); + + // + // Signed Data + // + BerSequenceGenerator sigGen = new BerSequenceGenerator( + sGen.GetRawOutputStream(), 0, true); + + sigGen.AddObject(CalculateVersion(signedContentType)); + + Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); + + // + // add the precalculated SignerInfo digest algorithms. + // + foreach (SignerInformation signer in _signers) + { + digestAlgs.Add(FixAlgID(signer.DigestAlgorithmID)); + } + + // + // add the new digests + // + foreach (SignerInf signer in _signerInfs) + { + digestAlgs.Add(FixAlgID(signer.DigestAlgorithmID)); + } + + { + byte[] tmp = new DerSet(digestAlgs).GetEncoded(); + sigGen.GetRawOutputStream().Write(tmp, 0, tmp.Length); + } + + BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); + + eiGen.AddObject(new DerObjectIdentifier(signedContentType)); + + Stream digStream; + if (encapsulate) + { + BerOctetStringGenerator octGen = new BerOctetStringGenerator( + eiGen.GetRawOutputStream(), 0, true); + + digStream = octGen.GetOctetOutputStream(_bufferSize); + + if (dataOutputStream != null) + { + digStream = new TeeOutputStream(dataOutputStream, digStream); + } + } + else + { + if (dataOutputStream != null) + { + digStream = dataOutputStream; + } + else + { + digStream = new NullOutputStream(); + } + } + + foreach (IDigest d in _messageDigests) + { + digStream = new DigestStream(digStream, null, d); + } + + return new CmsSignedDataOutputStream(this, digStream, signedContentType, sGen, sigGen, eiGen); + } + + // RFC3852, section 5.1: + // IF ((certificates is present) AND + // (any certificates with a type of other are present)) OR + // ((crls is present) AND + // (any crls with a type of other are present)) + // THEN version MUST be 5 + // ELSE + // IF (certificates is present) AND + // (any version 2 attribute certificates are present) + // THEN version MUST be 4 + // ELSE + // IF ((certificates is present) AND + // (any version 1 attribute certificates are present)) OR + // (any SignerInfo structures are version 3) OR + // (encapContentInfo eContentType is other than id-data) + // THEN version MUST be 3 + // ELSE version MUST be 1 + // + private DerInteger CalculateVersion( + string contentOid) + { + bool otherCert = false; + bool otherCrl = false; + bool attrCertV1Found = false; + bool attrCertV2Found = false; + + if (_certs != null) + { + foreach (object obj in _certs) + { + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tagged = (Asn1TaggedObject) obj; + + if (tagged.TagNo == 1) + { + attrCertV1Found = true; + } + else if (tagged.TagNo == 2) + { + attrCertV2Found = true; + } + else if (tagged.TagNo == 3) + { + otherCert = true; + break; + } + } + } + } + + if (otherCert) + { + return new DerInteger(5); + } + + if (_crls != null) + { + foreach (object obj in _crls) + { + if (obj is Asn1TaggedObject) + { + otherCrl = true; + break; + } + } + } + + if (otherCrl) + { + return new DerInteger(5); + } + + if (attrCertV2Found) + { + return new DerInteger(4); + } + + if (attrCertV1Found) + { + return new DerInteger(3); + } + + if (contentOid.Equals(Data) + && !CheckForVersion3(_signers)) + { + return new DerInteger(1); + } + + return new DerInteger(3); + } + + private bool CheckForVersion3( + IList signerInfos) + { + foreach (SignerInformation si in signerInfos) + { + SignerInfo s = SignerInfo.GetInstance(si.ToSignerInfo()); + + if (s.Version.Value.IntValue == 3) + { + return true; + } + } + + return false; + } + + private class NullOutputStream + : BaseOutputStream + { + public override void WriteByte( + byte b) + { + // do nothing + } + + public override void Write( + byte[] buffer, + int offset, + int count) + { + // do nothing + } + } + + private class TeeOutputStream + : BaseOutputStream + { + private readonly Stream s1, s2; + + public TeeOutputStream(Stream dataOutputStream, Stream digStream) + { + Debug.Assert(dataOutputStream.CanWrite); + Debug.Assert(digStream.CanWrite); + + this.s1 = dataOutputStream; + this.s2 = digStream; + } + + public override void Write(byte[] buffer, int offset, int count) + { + s1.Write(buffer, offset, count); + s2.Write(buffer, offset, count); + } + + public override void WriteByte(byte b) + { + s1.WriteByte(b); + s2.WriteByte(b); + } + + public override void Close() + { + s1.Close(); + s2.Close(); + } + } + + private class CmsSignedDataOutputStream + : BaseOutputStream + { + private readonly CmsSignedDataStreamGenerator outer; + + private Stream _out; + private DerObjectIdentifier _contentOID; + private BerSequenceGenerator _sGen; + private BerSequenceGenerator _sigGen; + private BerSequenceGenerator _eiGen; + + public CmsSignedDataOutputStream( + CmsSignedDataStreamGenerator outer, + Stream outStream, + string contentOID, + BerSequenceGenerator sGen, + BerSequenceGenerator sigGen, + BerSequenceGenerator eiGen) + { + this.outer = outer; + + _out = outStream; + _contentOID = new DerObjectIdentifier(contentOID); + _sGen = sGen; + _sigGen = sigGen; + _eiGen = eiGen; + } + + public override void WriteByte( + byte b) + { + _out.WriteByte(b); + } + + public override void Write( + byte[] bytes, + int off, + int len) + { + _out.Write(bytes, off, len); + } + + public override void Close() + { + _out.Close(); + _eiGen.Close(); + + outer._digests.Clear(); // clear the current preserved digest state + + if (outer._certs.Count > 0) + { + Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs); + + WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs)); + } + + if (outer._crls.Count > 0) + { + Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls); + + WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls)); + } + + // + // add the precalculated SignerInfo objects. + // + Asn1EncodableVector signerInfos = new Asn1EncodableVector(); + + foreach (SignerInformation signer in outer._signers) + { + signerInfos.Add(signer.ToSignerInfo()); + } + + // + // add the SignerInfo objects + // + foreach (SignerInf signer in outer._signerInfs) + { + try + { + signerInfos.Add(signer.ToSignerInfo(_contentOID)); + } + catch (IOException e) + { + throw new IOException("encoding error." + e); + } + catch (SignatureException e) + { + throw new IOException("error creating signature." + e); + } + catch (CertificateEncodingException e) + { + throw new IOException("error creating sid." + e); + } + } + + WriteToGenerator(_sigGen, new DerSet(signerInfos)); + + _sigGen.Close(); + _sGen.Close(); + base.Close(); + } + + private static void WriteToGenerator( + Asn1Generator ag, + Asn1Encodable ae) + { + byte[] encoded = ae.GetEncoded(); + ag.GetRawOutputStream().Write(encoded, 0, encoded.Length); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSSignedGenerator.cs b/iTechSharp/srcbc/cms/CMSSignedGenerator.cs new file mode 100644 index 0000000..7bb5e17 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSSignedGenerator.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + public class CmsSignedGenerator + { + /** + * Default type for the signed data. + */ + public static readonly string Data = PkcsObjectIdentifiers.Data.Id; + + public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id; + public static readonly string DigestSha224 = NistObjectIdentifiers.IdSha224.Id; + public static readonly string DigestSha256 = NistObjectIdentifiers.IdSha256.Id; + public static readonly string DigestSha384 = NistObjectIdentifiers.IdSha384.Id; + public static readonly string DigestSha512 = NistObjectIdentifiers.IdSha512.Id; + public static readonly string DigestMD5 = PkcsObjectIdentifiers.MD5.Id; + public static readonly string DigestGost3411 = CryptoProObjectIdentifiers.GostR3411.Id; + public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id; + public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id; + public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id; + + public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id; + public static readonly string EncryptionDsa = X9ObjectIdentifiers.IdDsaWithSha1.Id; + public static readonly string EncryptionECDsa = X9ObjectIdentifiers.ECDsaWithSha1.Id; + public static readonly string EncryptionRsaPss = PkcsObjectIdentifiers.IdRsassaPss.Id; + public static readonly string EncryptionGost3410 = CryptoProObjectIdentifiers.GostR3410x94.Id; + public static readonly string EncryptionECGost3410 = CryptoProObjectIdentifiers.GostR3410x2001.Id; + + private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id; + private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id; + private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id; + private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id; + private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id; + + private static readonly ISet noParams = new HashSet(); + private static readonly Hashtable ecAlgorithms = new Hashtable(); + + static CmsSignedGenerator() + { + noParams.Add(EncryptionDsa); +// noParams.Add(EncryptionECDsa); + noParams.Add(EncryptionECDsaWithSha1); + noParams.Add(EncryptionECDsaWithSha224); + noParams.Add(EncryptionECDsaWithSha256); + noParams.Add(EncryptionECDsaWithSha384); + noParams.Add(EncryptionECDsaWithSha512); + + ecAlgorithms.Add(DigestSha1, EncryptionECDsaWithSha1); + ecAlgorithms.Add(DigestSha224, EncryptionECDsaWithSha224); + ecAlgorithms.Add(DigestSha256, EncryptionECDsaWithSha256); + ecAlgorithms.Add(DigestSha384, EncryptionECDsaWithSha384); + ecAlgorithms.Add(DigestSha512, EncryptionECDsaWithSha512); + } + + internal ArrayList _certs = new ArrayList(); + internal ArrayList _crls = new ArrayList(); + internal ArrayList _signers = new ArrayList(); + internal IDictionary _digests = new Hashtable(); + + protected readonly SecureRandom rand; + + protected CmsSignedGenerator() + : this(new SecureRandom()) + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + protected CmsSignedGenerator( + SecureRandom rand) + { + this.rand = rand; + } + + protected string GetEncOid( + AsymmetricKeyParameter key, + string digestOID) + { + string encOID = null; + + if (key is RsaKeyParameters) + { + if (!((RsaKeyParameters) key).IsPrivate) + throw new ArgumentException("Expected RSA private key"); + + encOID = EncryptionRsa; + } + else if (key is DsaPrivateKeyParameters) + { + if (!digestOID.Equals(DigestSha1)) + throw new ArgumentException("can't mix DSA with anything but SHA1"); + + encOID = EncryptionDsa; + } + else if (key is ECPrivateKeyParameters) + { + ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters) key; + string algName = ecPrivKey.AlgorithmName; + + if (algName == "ECGOST3410") + { + encOID = EncryptionECGost3410; + } + else + { + // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does? + encOID = (string) ecAlgorithms[digestOID]; + + if (encOID == null) + throw new ArgumentException("can't mix ECDSA with anything but SHA family digests"); + } + } + else if (key is Gost3410PrivateKeyParameters) + { + encOID = EncryptionGost3410; + } + else + { + throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid"); + } + + return encOID; + } + + internal static AlgorithmIdentifier GetEncAlgorithmIdentifier( + string encOid) + { + if (noParams.Contains(encOid)) + { + return new AlgorithmIdentifier(new DerObjectIdentifier(encOid)); + } + + return new AlgorithmIdentifier(new DerObjectIdentifier(encOid), DerNull.Instance); + } + + internal protected virtual IDictionary GetBaseParameters( + DerObjectIdentifier contentType, + AlgorithmIdentifier digAlgId, + byte[] hash) + { + IDictionary param = new Hashtable(); + + param[CmsAttributeTableParameter.ContentType] = contentType; + param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId; + + if (hash != null) + { + param[CmsAttributeTableParameter.Digest] = hash.Clone(); + } + + return param; + } + + internal protected virtual Asn1Set GetAttributeSet( + Asn1.Cms.AttributeTable attr) + { + return attr == null + ? null + : new DerSet(attr.ToAsn1EncodableVector()); + } + + public void AddCertificates( + IX509Store certStore) + { + _certs.AddRange(CmsUtilities.GetCertificatesFromStore(certStore)); + } + + public void AddCrls( + IX509Store crlStore) + { + _crls.AddRange(CmsUtilities.GetCrlsFromStore(crlStore)); + } + + /** + * Add the attribute certificates contained in the passed in store to the + * generator. + * + * @param store a store of Version 2 attribute certificates + * @throws CmsException if an error occurse processing the store. + */ + public void AddAttributeCertificates( + IX509Store store) + { + try + { + foreach (IX509AttributeCertificate attrCert in store.GetMatches(null)) + { + _certs.Add(new DerTaggedObject(false, 2, + AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded())))); + } + } + catch (Exception e) + { + throw new CmsException("error processing attribute certs", e); + } + } + + /** + * Add a store of precalculated signers to the generator. + * + * @param signerStore store of signers + */ + public void AddSigners( + SignerInformationStore signerStore) + { + foreach (object o in signerStore.GetSigners()) + { + _signers.Add(o); + } + } + + /** + * Return a map of oids and byte arrays representing the digests calculated on the content during + * the last generate. + * + * @return a map of oids (as String objects) and byte[] representing digests. + */ + public IDictionary GetGeneratedDigests() + { + return new Hashtable(_digests); + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSSignedHelper.cs b/iTechSharp/srcbc/cms/CMSSignedHelper.cs new file mode 100644 index 0000000..2bcc09c --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSSignedHelper.cs @@ -0,0 +1,332 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Iana; +using Org.BouncyCastle.Asn1.Misc; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + internal class CmsSignedHelper + { + internal static readonly CmsSignedHelper Instance = new CmsSignedHelper(); + + private static readonly Hashtable encryptionAlgs = new Hashtable(); + private static readonly Hashtable digestAlgs = new Hashtable(); + private static readonly Hashtable digestAliases = new Hashtable(); + + private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption) + { + string alias = oid.Id; + digestAlgs.Add(alias, digest); + encryptionAlgs.Add(alias, encryption); + } + + static CmsSignedHelper() + { + AddEntries(NistObjectIdentifiers.DsaWithSha224, "SHA224", "DSA"); + AddEntries(NistObjectIdentifiers.DsaWithSha256, "SHA256", "DSA"); + AddEntries(NistObjectIdentifiers.DsaWithSha384, "SHA384", "DSA"); + AddEntries(NistObjectIdentifiers.DsaWithSha512, "SHA512", "DSA"); + AddEntries(OiwObjectIdentifiers.DsaWithSha1, "SHA1", "DSA"); + AddEntries(OiwObjectIdentifiers.MD4WithRsa, "MD4", "RSA"); + AddEntries(OiwObjectIdentifiers.MD4WithRsaEncryption, "MD4", "RSA"); + AddEntries(OiwObjectIdentifiers.MD5WithRsa, "MD5", "RSA"); + AddEntries(OiwObjectIdentifiers.Sha1WithRsa, "SHA1", "RSA"); + AddEntries(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2", "RSA"); + AddEntries(PkcsObjectIdentifiers.MD4WithRsaEncryption, "MD4", "RSA"); + AddEntries(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5", "RSA"); + AddEntries(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1", "RSA"); + AddEntries(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224", "RSA"); + AddEntries(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256", "RSA"); + AddEntries(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384", "RSA"); + AddEntries(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512", "RSA"); + AddEntries(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1", "ECDSA"); + AddEntries(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224", "ECDSA"); + AddEntries(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256", "ECDSA"); + AddEntries(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384", "ECDSA"); + AddEntries(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512", "ECDSA"); + AddEntries(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1", "DSA"); + + encryptionAlgs.Add(X9ObjectIdentifiers.IdDsa.Id, "DSA"); + encryptionAlgs.Add(PkcsObjectIdentifiers.RsaEncryption.Id, "RSA"); + encryptionAlgs.Add(TeleTrusTObjectIdentifiers.TeleTrusTRsaSignatureAlgorithm, "RSA"); + encryptionAlgs.Add(X509ObjectIdentifiers.IdEARsa.Id, "RSA"); + encryptionAlgs.Add(CmsSignedGenerator.EncryptionRsaPss, "RSAandMGF1"); + encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x94.Id, "GOST3410"); + encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x2001.Id, "ECGOST3410"); + encryptionAlgs.Add("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410"); + encryptionAlgs.Add("1.3.6.1.4.1.5849.1.1.5", "GOST3410"); + + digestAlgs.Add(PkcsObjectIdentifiers.MD2.Id, "MD2"); + digestAlgs.Add(PkcsObjectIdentifiers.MD4.Id, "MD4"); + digestAlgs.Add(PkcsObjectIdentifiers.MD5.Id, "MD5"); + digestAlgs.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1"); + digestAlgs.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224"); + digestAlgs.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256"); + digestAlgs.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384"); + digestAlgs.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512"); + digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128"); + digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160"); + digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256"); + digestAlgs.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411"); + digestAlgs.Add("1.3.6.1.4.1.5849.1.2.1", "GOST3411"); + + digestAliases.Add("SHA1", new string[] { "SHA-1" }); + digestAliases.Add("SHA224", new string[] { "SHA-224" }); + digestAliases.Add("SHA256", new string[] { "SHA-256" }); + digestAliases.Add("SHA384", new string[] { "SHA-384" }); + digestAliases.Add("SHA512", new string[] { "SHA-512" }); + } + + /** + * Return the digest algorithm using one of the standard JCA string + * representations rather than the algorithm identifier (if possible). + */ + internal string GetDigestAlgName( + string digestAlgOid) + { + string algName = (string)digestAlgs[digestAlgOid]; + + if (algName != null) + { + return algName; + } + + return digestAlgOid; + } + + internal string[] GetDigestAliases( + string algName) + { + string[] aliases = (string[]) digestAliases[algName]; + + return aliases == null ? new String[0] : (string[]) aliases.Clone(); + } + + /** + * Return the digest encryption algorithm using one of the standard + * JCA string representations rather than the algorithm identifier (if + * possible). + */ + internal string GetEncryptionAlgName( + string encryptionAlgOid) + { + string algName = (string) encryptionAlgs[encryptionAlgOid]; + + if (algName != null) + { + return algName; + } + + return encryptionAlgOid; + } + + internal IDigest GetDigestInstance( + string algorithm) + { + try + { + return DigestUtilities.GetDigest(algorithm); + } + catch (SecurityUtilityException e) + { + // This is probably superfluous on C#, since no provider infrastructure, + // assuming DigestUtilities already knows all the aliases + foreach (string alias in GetDigestAliases(algorithm)) + { + try { return DigestUtilities.GetDigest(alias); } + catch (SecurityUtilityException) {} + } + throw e; + } + } + + internal ISigner GetSignatureInstance( + string algorithm) + { + return SignerUtilities.GetSigner(algorithm); + } + + internal IX509Store CreateAttributeStore( + string type, + Asn1Set certSet) + { + IList certs = new ArrayList(); + + if (certSet != null) + { + foreach (Asn1Encodable ae in certSet) + { + try + { + Asn1Object obj = ae.ToAsn1Object(); + + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tagged = (Asn1TaggedObject)obj; + + if (tagged.TagNo == 2) + { + certs.Add( + new X509V2AttributeCertificate( + Asn1Sequence.GetInstance(tagged, false).GetEncoded())); + } + } + } + catch (Exception ex) + { + throw new CmsException("can't re-encode attribute certificate!", ex); + } + } + } + + try + { + return X509StoreFactory.Create( + "AttributeCertificate/" + type, + new X509CollectionStoreParameters(certs)); + } + catch (ArgumentException e) + { + throw new CmsException("can't setup the X509Store", e); + } + } + + internal IX509Store CreateCertificateStore( + string type, + Asn1Set certSet) + { + IList certs = new ArrayList(); + + if (certSet != null) + { + AddCertsFromSet(certs, certSet); + } + + try + { + return X509StoreFactory.Create( + "Certificate/" + type, + new X509CollectionStoreParameters(certs)); + } + catch (ArgumentException e) + { + throw new CmsException("can't setup the X509Store", e); + } + } + + internal IX509Store CreateCrlStore( + string type, + Asn1Set crlSet) + { + IList crls = new ArrayList(); + + if (crlSet != null) + { + AddCrlsFromSet(crls, crlSet); + } + + try + { + return X509StoreFactory.Create( + "CRL/" + type, + new X509CollectionStoreParameters(crls)); + } + catch (ArgumentException e) + { + throw new CmsException("can't setup the X509Store", e); + } + } + + private void AddCertsFromSet( + IList certs, + Asn1Set certSet) + { + X509CertificateParser cf = new X509CertificateParser(); + + foreach (Asn1Encodable ae in certSet) + { + try + { + Asn1Object obj = ae.ToAsn1Object(); + + if (obj is Asn1Sequence) + { + // TODO Build certificate directly from sequence? + certs.Add(cf.ReadCertificate(obj.GetEncoded())); + } + } + catch (Exception ex) + { + throw new CmsException("can't re-encode certificate!", ex); + } + } + } + + private void AddCrlsFromSet( + IList crls, + Asn1Set crlSet) + { + X509CrlParser cf = new X509CrlParser(); + + foreach (Asn1Encodable ae in crlSet) + { + try + { + // TODO Build CRL directly from ae.ToAsn1Object()? + crls.Add(cf.ReadCrl(ae.GetEncoded())); + } + catch (Exception ex) + { + throw new CmsException("can't re-encode CRL!", ex); + } + } + } + + internal AlgorithmIdentifier FixAlgID( + AlgorithmIdentifier algId) + { + if (algId.Parameters == null) + return new AlgorithmIdentifier(algId.ObjectID, DerNull.Instance); + + return algId; + } + + private bool anyCertHasTypeOther() + { + // not supported + return false; + } + + private bool anyCertHasV1Attribute() + { + // obsolete + return false; + } + + private bool anyCertHasV2Attribute() + { + // TODO + return false; + } + + private bool anyCrlHasTypeOther() + { + // not supported + return false; + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSTypedStream.cs b/iTechSharp/srcbc/cms/CMSTypedStream.cs new file mode 100644 index 0000000..1eb8493 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSTypedStream.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Cms +{ + public class CmsTypedStream + { + private const int BufferSize = 32 * 1024; + + private readonly string _oid; + private readonly Stream _in; + private readonly int _bufSize; + + public CmsTypedStream( + Stream inStream) + : this(PkcsObjectIdentifiers.Data.Id, inStream, BufferSize) + { + } + + public CmsTypedStream( + string oid, + Stream inStream) + : this(oid, inStream, BufferSize) + { + } + + public CmsTypedStream( + string oid, + Stream inStream, + int bufSize) + { + _oid = oid; + _bufSize = bufSize; + _in = new FullReaderStream(inStream, bufSize); + } + + public string ContentType + { + get { return _oid; } + } + + public Stream ContentStream + { + get { return _in; } + } + + public void Drain() + { + Streams.Drain(_in); + _in.Close(); + } + + private class FullReaderStream + : BaseInputStream + { + internal Stream _stream; + + internal FullReaderStream( + Stream inStream, + int bufSize) + { + _stream = inStream; + } + + public override int ReadByte() + { + return _stream.ReadByte(); + } + + public override int Read( + byte[] buf, + int off, + int len) + { + return Streams.ReadFully(_stream, buf, off, len); + } + + public override void Close() + { + _stream.Close(); + base.Close(); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/CMSUtils.cs b/iTechSharp/srcbc/cms/CMSUtils.cs new file mode 100644 index 0000000..d1784c2 --- /dev/null +++ b/iTechSharp/srcbc/cms/CMSUtils.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + internal class CmsUtilities + { + // TODO Is there a .NET equivalent to this? +// private static readonly Runtime RUNTIME = Runtime.getRuntime(); + + internal static int MaximumMemory + { + get + { + // TODO Is there a .NET equivalent to this? + long maxMem = int.MaxValue;//RUNTIME.maxMemory(); + + if (maxMem > int.MaxValue) + { + return int.MaxValue; + } + + return (int)maxMem; + } + } + + internal static ContentInfo ReadContentInfo( + byte[] input) + { + // enforce limit checking as from a byte array + return ReadContentInfo(new Asn1InputStream(input)); + } + + internal static ContentInfo ReadContentInfo( + Stream input) + { + // enforce some limit checking + return ReadContentInfo(new Asn1InputStream(input, MaximumMemory)); + } + + private static ContentInfo ReadContentInfo( + Asn1InputStream aIn) + { + try + { + return ContentInfo.GetInstance(aIn.ReadObject()); + } + catch (IOException e) + { + throw new CmsException("IOException reading content.", e); + } + catch (InvalidCastException e) + { + throw new CmsException("Malformed content.", e); + } + catch (ArgumentException e) + { + throw new CmsException("Malformed content.", e); + } + } + + public static byte[] StreamToByteArray( + Stream inStream) + { + return Streams.ReadAll(inStream); + } + + public static IList GetCertificatesFromStore( + IX509Store certStore) + { + try + { + IList certs = new ArrayList(); + + if (certStore != null) + { + foreach (X509Certificate c in certStore.GetMatches(null)) + { + certs.Add( + X509CertificateStructure.GetInstance( + Asn1Object.FromByteArray(c.GetEncoded()))); + } + } + + return certs; + } + catch (CertificateEncodingException e) + { + throw new CmsException("error encoding certs", e); + } + catch (Exception e) + { + throw new CmsException("error processing certs", e); + } + } + + public static IList GetCrlsFromStore( + IX509Store crlStore) + { + try + { + IList crls = new ArrayList(); + + if (crlStore != null) + { + foreach (X509Crl c in crlStore.GetMatches(null)) + { + crls.Add( + CertificateList.GetInstance( + Asn1Object.FromByteArray(c.GetEncoded()))); + } + } + + return crls; + } + catch (CrlException e) + { + throw new CmsException("error encoding crls", e); + } + catch (Exception e) + { + throw new CmsException("error processing crls", e); + } + } + + public static Asn1Set CreateBerSetFromList( + IList berObjects) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + foreach (Asn1Encodable ae in berObjects) + { + v.Add(ae); + } + + return new BerSet(v); + } + + public static Asn1Set CreateDerSetFromList( + IList derObjects) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + foreach (Asn1Encodable ae in derObjects) + { + v.Add(ae); + } + + return new DerSet(v); + } + } +} diff --git a/iTechSharp/srcbc/cms/CounterSignatureDigestCalculator.cs b/iTechSharp/srcbc/cms/CounterSignatureDigestCalculator.cs new file mode 100644 index 0000000..023e3c3 --- /dev/null +++ b/iTechSharp/srcbc/cms/CounterSignatureDigestCalculator.cs @@ -0,0 +1,29 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Cms +{ + internal class CounterSignatureDigestCalculator + : IDigestCalculator + { + private readonly string alg; + private readonly byte[] data; + + internal CounterSignatureDigestCalculator( + string alg, + byte[] data) + { + this.alg = alg; + this.data = data; + } + + public byte[] GetDigest() + { + IDigest digest = CmsSignedHelper.Instance.GetDigestInstance(alg); + digest.BlockUpdate(data, 0, data.Length); + return DigestUtilities.DoFinal(digest); + } + } +} diff --git a/iTechSharp/srcbc/cms/DefaultSignedAttributeTableGenerator.cs b/iTechSharp/srcbc/cms/DefaultSignedAttributeTableGenerator.cs new file mode 100644 index 0000000..95f0713 --- /dev/null +++ b/iTechSharp/srcbc/cms/DefaultSignedAttributeTableGenerator.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; + +namespace Org.BouncyCastle.Cms +{ + /** + * Default signed attributes generator. + */ + public class DefaultSignedAttributeTableGenerator + : CmsAttributeTableGenerator + { + private readonly Hashtable table; + + /** + * Initialise to use all defaults + */ + public DefaultSignedAttributeTableGenerator() + { + table = new Hashtable(); + } + + /** + * Initialise with some extra attributes or overrides. + * + * @param attributeTable initial attribute table to use. + */ + public DefaultSignedAttributeTableGenerator( + AttributeTable attributeTable) + { + if (attributeTable != null) + { + table = attributeTable.ToHashtable(); + } + else + { + table = new Hashtable(); + } + } + + /** + * Create a standard attribute table from the passed in parameters - this will + * normally include contentType, signingTime, and messageDigest. If the constructor + * using an AttributeTable was used, entries in it for contentType, signingTime, and + * messageDigest will override the generated ones. + * + * @param parameters source parameters for table generation. + * + * @return a filled in Hashtable of attributes. + */ + protected virtual Hashtable createStandardAttributeTable( + IDictionary parameters) + { + Hashtable std = (Hashtable)table.Clone(); + + if (!std.ContainsKey(CmsAttributes.ContentType)) + { + Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.ContentType, + new DerSet((DerObjectIdentifier)parameters[CmsAttributeTableParameter.ContentType])); + std[attr.AttrType] = attr; + } + + if (!std.ContainsKey(CmsAttributes.SigningTime)) + { + Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute( + CmsAttributes.SigningTime, new DerSet(new Time(DateTime.UtcNow))); + std[attr.AttrType] = attr; + } + + if (!std.ContainsKey(CmsAttributes.MessageDigest)) + { + byte[] hash = (byte[])parameters[CmsAttributeTableParameter.Digest]; + Asn1.Cms.Attribute attr; + + if (hash != null) + { + attr = new Asn1.Cms.Attribute( + CmsAttributes.MessageDigest, new DerSet(new DerOctetString(hash))); + } + else + { + attr = new Asn1.Cms.Attribute( + CmsAttributes.MessageDigest, new DerSet(DerNull.Instance)); + } + + std[attr.AttrType] = attr; + } + + return std; + } + + /** + * @param parameters source parameters + * @return the populated attribute table + */ + public virtual AttributeTable GetAttributes( + IDictionary parameters) + { + return new AttributeTable(createStandardAttributeTable(parameters)); + } + } +} diff --git a/iTechSharp/srcbc/cms/IDigestCalculator.cs b/iTechSharp/srcbc/cms/IDigestCalculator.cs new file mode 100644 index 0000000..3661e40 --- /dev/null +++ b/iTechSharp/srcbc/cms/IDigestCalculator.cs @@ -0,0 +1,9 @@ +using System; + +namespace Org.BouncyCastle.Cms +{ + internal interface IDigestCalculator + { + byte[] GetDigest(); + } +} diff --git a/iTechSharp/srcbc/cms/KEKRecipientInformation.cs b/iTechSharp/srcbc/cms/KEKRecipientInformation.cs new file mode 100644 index 0000000..7d9b57c --- /dev/null +++ b/iTechSharp/srcbc/cms/KEKRecipientInformation.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Cms +{ + /** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a secret key known to the other side. + */ + public class KekRecipientInformation + : RecipientInformation + { + private KekRecipientInfo _info; +// private AlgorithmIdentifier _encAlg; + + public KekRecipientInformation( + KekRecipientInfo info, + AlgorithmIdentifier encAlg, + Stream data) + : base(encAlg, AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm), data) + { + this._info = info; + this._encAlg = encAlg; + this._rid = new RecipientID(); + + KekIdentifier kekId = info.KekID; + + _rid.KeyIdentifier = kekId.KeyIdentifier.GetOctets(); + } + + /** + * decrypt the content and return an input stream. + */ + public override CmsTypedStream GetContentStream( + ICipherParameters key) + { + try + { + byte[] encryptedKey = _info.EncryptedKey.GetOctets(); + IWrapper keyWrapper = WrapperUtilities.GetWrapper(_keyEncAlg.ObjectID.Id); + + keyWrapper.Init(false, key); + + KeyParameter sKey = ParameterUtilities.CreateKeyParameter( + _encAlg.ObjectID, keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length)); + + return GetContentFromSessionKey(sKey); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/KeyAgreeRecipientInformation.cs b/iTechSharp/srcbc/cms/KeyAgreeRecipientInformation.cs new file mode 100644 index 0000000..acd70c1 --- /dev/null +++ b/iTechSharp/srcbc/cms/KeyAgreeRecipientInformation.cs @@ -0,0 +1,122 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using key agreement. + */ + public class KeyAgreeRecipientInformation + : RecipientInformation + { + private KeyAgreeRecipientInfo _info; +// private AlgorithmIdentifier _encAlg; + private Asn1OctetString _encryptedKey; + + public KeyAgreeRecipientInformation( + KeyAgreeRecipientInfo info, + AlgorithmIdentifier encAlg, + Stream data) + : base(encAlg, AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm), data) + { + _info = info; +// _encAlg = encAlg; + + try + { + Asn1Sequence s = _info.RecipientEncryptedKeys; + RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(s[0]); + + Asn1.Cms.IssuerAndSerialNumber iAnds = id.Identifier.IssuerAndSerialNumber; + +// byte[] issuerBytes = iAnds.Name.GetEncoded(); + + _rid = new RecipientID(); +// _rid.SetIssuer(issuerBytes); + _rid.Issuer = iAnds.Name; + _rid.SerialNumber = iAnds.SerialNumber.Value; + + _encryptedKey = id.EncryptedKey; + } + catch (IOException e) + { + throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e); + } + } + + /** + * decrypt the content and return an input stream. + */ + public override CmsTypedStream GetContentStream( +// Key key) + ICipherParameters key) + { + if (!(key is AsymmetricKeyParameter)) + throw new ArgumentException("KeyAgreement requires asymmetric key", "key"); + + AsymmetricKeyParameter privKey = (AsymmetricKeyParameter) key; + + if (!privKey.IsPrivate) + throw new ArgumentException("Expected private key", "key"); + + try + { + OriginatorPublicKey origK = _info.Originator.OriginatorKey; + PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey); + SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(privInfo.AlgorithmID, origK.PublicKey.GetBytes()); + AsymmetricKeyParameter pubKey = PublicKeyFactory.CreateKey(pubInfo); + + string wrapAlg = DerObjectIdentifier.GetInstance( + Asn1Sequence.GetInstance(_keyEncAlg.Parameters)[0]).Id; + + IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf( + _keyEncAlg.ObjectID, wrapAlg); + + agreement.Init(privKey); + + BigInteger wKeyNum = agreement.CalculateAgreement(pubKey); + // TODO Fix the way bytes are derived from the secret + byte[] wKeyBytes = wKeyNum.ToByteArrayUnsigned(); + KeyParameter wKey = ParameterUtilities.CreateKeyParameter(wrapAlg, wKeyBytes); + + IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg); + + keyCipher.Init(false, wKey); + + AlgorithmIdentifier aid = _encAlg; + string alg = aid.ObjectID.Id; + + byte[] encryptedKey = _encryptedKey.GetOctets(); + byte[] sKeyBytes = keyCipher.Unwrap(encryptedKey, 0, encryptedKey.Length); + + KeyParameter sKey = ParameterUtilities.CreateKeyParameter(alg, sKeyBytes); + + return GetContentFromSessionKey(sKey); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + catch (Exception e) + { + throw new CmsException("originator key invalid.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/KeyTransRecipientInformation.cs b/iTechSharp/srcbc/cms/KeyTransRecipientInformation.cs new file mode 100644 index 0000000..bb73900 --- /dev/null +++ b/iTechSharp/srcbc/cms/KeyTransRecipientInformation.cs @@ -0,0 +1,111 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Asn1Pkcs = Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * the KeyTransRecipientInformation class for a recipient who has been sent a secret + * key encrypted using their public key that needs to be used to + * extract the message. + */ + public class KeyTransRecipientInformation + : RecipientInformation + { + private KeyTransRecipientInfo _info; +// private new AlgorithmIdentifier _encAlg; + + public KeyTransRecipientInformation( + KeyTransRecipientInfo info, + AlgorithmIdentifier encAlg, + Stream data) + : base(encAlg, AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm), data) + { + this._info = info; +// this._encAlg = encAlg; + this._rid = new RecipientID(); + + RecipientIdentifier r = info.RecipientIdentifier; + + try + { + if (r.IsTagged) + { + Asn1OctetString octs = Asn1OctetString.GetInstance(r.ID); + + _rid.SubjectKeyIdentifier = octs.GetOctets(); + } + else + { + IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.GetInstance(r.ID); + + _rid.Issuer = iAnds.Name; + _rid.SerialNumber = iAnds.SerialNumber.Value; + } + } + catch (IOException) + { + throw new ArgumentException("invalid rid in KeyTransRecipientInformation"); + } + } + + private string GetExchangeEncryptionAlgorithmName( + DerObjectIdentifier oid) + { + if (Asn1Pkcs.PkcsObjectIdentifiers.RsaEncryption.Equals(oid)) + { + return "RSA//PKCS1Padding"; + } + + return oid.Id; + } + + /** + * decrypt the content and return it as a byte array. + */ + public override CmsTypedStream GetContentStream( + ICipherParameters key) + { + byte[] encryptedKey = _info.EncryptedKey.GetOctets(); + string keyExchangeAlgorithm = GetExchangeEncryptionAlgorithmName(_keyEncAlg.ObjectID); + + try + { + IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyExchangeAlgorithm); + + keyWrapper.Init(false, key); + + KeyParameter sKey = ParameterUtilities.CreateKeyParameter( + _encAlg.ObjectID, keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length)); + + return GetContentFromSessionKey(sKey); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } +// catch (IllegalBlockSizeException e) + catch (DataLengthException e) + { + throw new CmsException("illegal blocksize in message.", e); + } +// catch (BadPaddingException e) + catch (InvalidCipherTextException e) + { + throw new CmsException("bad padding in message.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/PKCS5Scheme2PBEKey.cs b/iTechSharp/srcbc/cms/PKCS5Scheme2PBEKey.cs new file mode 100644 index 0000000..ffa884d --- /dev/null +++ b/iTechSharp/srcbc/cms/PKCS5Scheme2PBEKey.cs @@ -0,0 +1,35 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Cms +{ + public class Pkcs5Scheme2PbeKey + : CmsPbeKey + { + public Pkcs5Scheme2PbeKey( + string password, + byte[] salt, + int iterationCount) + : base(password, salt, iterationCount) + { + } + + internal override KeyParameter GetEncoded( + string algorithmOid) + { + Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); + + gen.Init( + PbeParametersGenerator.Pkcs5PasswordToBytes(this.Password), + this.Salt, + this.IterationCount); + + return (KeyParameter) gen.GenerateDerivedParameters( + algorithmOid, + CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid)); + } + } +} diff --git a/iTechSharp/srcbc/cms/PasswordRecipientInformation.cs b/iTechSharp/srcbc/cms/PasswordRecipientInformation.cs new file mode 100644 index 0000000..701ff5d --- /dev/null +++ b/iTechSharp/srcbc/cms/PasswordRecipientInformation.cs @@ -0,0 +1,74 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Cms +{ + /** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a password. + */ + public class PasswordRecipientInformation + : RecipientInformation + { + private readonly PasswordRecipientInfo _info; +// private readonly AlgorithmIdentifier _encAlg; + + public PasswordRecipientInformation( + PasswordRecipientInfo info, + AlgorithmIdentifier encAlg, + Stream data) + : base(encAlg, AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm), data) + { + this._info = info; +// this._encAlg = encAlg; + this._rid = new RecipientID(); + } + + /** + * decrypt the content and return an input stream. + */ + public override CmsTypedStream GetContentStream( + ICipherParameters key) + { + try + { + AlgorithmIdentifier kekAlg = AlgorithmIdentifier.GetInstance(_info.KeyEncryptionAlgorithm); + Asn1Sequence kekAlgParams = (Asn1Sequence)kekAlg.Parameters; + byte[] encryptedKey = _info.EncryptedKey.GetOctets(); + string kekAlgName = DerObjectIdentifier.GetInstance(kekAlgParams[0]).Id; + string cName = CmsEnvelopedHelper.Instance.GetRfc3211WrapperName(kekAlgName); + IWrapper keyWrapper = WrapperUtilities.GetWrapper(cName); + + byte[] iv = Asn1OctetString.GetInstance(kekAlgParams[1]).GetOctets(); + + ICipherParameters parameters = ((CmsPbeKey)key).GetEncoded(kekAlgName); + parameters = new ParametersWithIV(parameters, iv); + + keyWrapper.Init(false, parameters); + + AlgorithmIdentifier aid = _encAlg; + string alg = aid.ObjectID.Id; + + KeyParameter sKey = ParameterUtilities.CreateKeyParameter( + alg, keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length)); + + return GetContentFromSessionKey(sKey); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/cms/RecipientId.cs b/iTechSharp/srcbc/cms/RecipientId.cs new file mode 100644 index 0000000..88c8f56 --- /dev/null +++ b/iTechSharp/srcbc/cms/RecipientId.cs @@ -0,0 +1,58 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + public class RecipientID + : X509CertStoreSelector + { + private byte[] keyIdentifier; + + public byte[] KeyIdentifier + { + get { return Arrays.Clone(keyIdentifier); } + set { keyIdentifier = Arrays.Clone(value); } + } + + public override int GetHashCode() + { + int code = Arrays.GetHashCode(keyIdentifier) + ^ Arrays.GetHashCode(this.SubjectKeyIdentifier); + + BigInteger serialNumber = this.SerialNumber; + if (serialNumber != null) + { + code ^= serialNumber.GetHashCode(); + } + + string issuer = this.IssuerAsString; + if (issuer != null) + { + code ^= issuer.GetHashCode(); + } + + return code; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + RecipientID id = obj as RecipientID; + + if (id == null) + return false; + + return Arrays.AreEqual(keyIdentifier, id.keyIdentifier) + && Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier) + && Platform.Equals(SerialNumber, id.SerialNumber) + && Platform.Equals(IssuerAsString, id.IssuerAsString); + } + } +} diff --git a/iTechSharp/srcbc/cms/RecipientInformation.cs b/iTechSharp/srcbc/cms/RecipientInformation.cs new file mode 100644 index 0000000..f629adf --- /dev/null +++ b/iTechSharp/srcbc/cms/RecipientInformation.cs @@ -0,0 +1,137 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Cms +{ + public abstract class RecipientInformation + { + internal RecipientID _rid = new RecipientID(); + internal AlgorithmIdentifier _encAlg; + internal AlgorithmIdentifier _keyEncAlg; + internal Stream _data; + + internal RecipientInformation( + AlgorithmIdentifier encAlg, + AlgorithmIdentifier keyEncAlg, + Stream data) + { + if (!data.CanRead) + throw new ArgumentException("Expected input stream", "data"); + + this._encAlg = encAlg; + this._keyEncAlg = keyEncAlg; + this._data = data; + } + + public RecipientID RecipientID + { + get { return _rid; } + } + + public AlgorithmIdentifier KeyEncryptionAlgorithmID + { + get { return _keyEncAlg; } + } + + /** + * return the object identifier for the key encryption algorithm. + * @return OID for key encryption algorithm. + */ + public string KeyEncryptionAlgOid + { + get { return _keyEncAlg.ObjectID.Id; } + } + + /** + * return the ASN.1 encoded key encryption algorithm parameters, or null if + * there aren't any. + * @return ASN.1 encoding of key encryption algorithm parameters. + */ + public Asn1Object KeyEncryptionAlgParams + { + get + { + Asn1Encodable ae = _keyEncAlg.Parameters; + + return ae == null ? null : ae.ToAsn1Object(); + } + } + + internal CmsTypedStream GetContentFromSessionKey( + KeyParameter sKey) + { + try + { + IBufferedCipher cipher = CipherUtilities.GetCipher(_encAlg.ObjectID); + + Asn1Encodable asn1Enc = _encAlg.Parameters; + Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object(); + + ICipherParameters cipherParameters = sKey; + + if (asn1Params != null && !(asn1Params is Asn1Null)) + { + cipherParameters = ParameterUtilities.GetCipherParameters( + _encAlg.ObjectID, cipherParameters, asn1Params); + } + else + { + string alg = _encAlg.ObjectID.Id; + if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc) + || alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc) + || alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc)) + { + cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]); + } + } + + cipher.Init(false, cipherParameters); + + return new CmsTypedStream(new CipherStream(_data, cipher, null)); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + catch (IOException e) + { + throw new CmsException("error decoding algorithm parameters.", e); + } + } + + public byte[] GetContent( + ICipherParameters key) + { + try + { + if (_data is MemoryStream) + { +// _data.Reset(); + _data.Seek(0L, SeekOrigin.Begin); + } + + return CmsUtilities.StreamToByteArray(GetContentStream(key).ContentStream); + } + catch (IOException e) + { + throw new Exception("unable to parse internal stream: " + e); + } + } + + public abstract CmsTypedStream GetContentStream(ICipherParameters key); + } +} diff --git a/iTechSharp/srcbc/cms/RecipientInformationStore.cs b/iTechSharp/srcbc/cms/RecipientInformationStore.cs new file mode 100644 index 0000000..df8017f --- /dev/null +++ b/iTechSharp/srcbc/cms/RecipientInformationStore.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Cms +{ + public class RecipientInformationStore + { + private readonly ArrayList all; //ArrayList[RecipientInformation] + private readonly Hashtable table = new Hashtable(); // Hashtable[RecipientID, ArrayList[RecipientInformation]] + + public RecipientInformationStore( + ICollection recipientInfos) + { + foreach (RecipientInformation recipientInformation in recipientInfos) + { + RecipientID rid = recipientInformation.RecipientID; + ArrayList list = (ArrayList) table[rid]; + + if (list == null) + { + table[rid] = list = new ArrayList(1); + } + + list.Add(recipientInformation); + } + + this.all = new ArrayList(recipientInfos); + } + + /** + * Return the first RecipientInformation object that matches the + * passed in selector. Null if there are no matches. + * + * @param selector to identify a recipient + * @return a single RecipientInformation object. Null if none matches. + */ + public RecipientInformation GetFirstRecipient( + RecipientID selector) + { + ArrayList list = (ArrayList) table[selector]; + + return list == null ? null : (RecipientInformation) list[0]; + } + + /** + * Return the number of recipients in the collection. + * + * @return number of recipients identified. + */ + public int Count + { + get { return all.Count; } + } + + /** + * Return all recipients in the collection + * + * @return a collection of recipients. + */ + public ICollection GetRecipients() + { + return new ArrayList(all); + } + + /** + * Return possible empty collection with recipients matching the passed in RecipientID + * + * @param selector a recipient id to select against. + * @return a collection of RecipientInformation objects. + */ + public ICollection GetRecipients( + RecipientID selector) + { + ArrayList list = (ArrayList) table[selector]; + + return list == null ? new ArrayList() : new ArrayList(list); + } + } +} diff --git a/iTechSharp/srcbc/cms/SignerId.cs b/iTechSharp/srcbc/cms/SignerId.cs new file mode 100644 index 0000000..030caa2 --- /dev/null +++ b/iTechSharp/srcbc/cms/SignerId.cs @@ -0,0 +1,51 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + /** + * a basic index for a signer. + */ + public class SignerID + : X509CertStoreSelector + { + public override int GetHashCode() + { + int code = Arrays.GetHashCode(this.SubjectKeyIdentifier); + + BigInteger serialNumber = this.SerialNumber; + if (serialNumber != null) + { + code ^= serialNumber.GetHashCode(); + } + + string issuer = this.IssuerAsString; + if (issuer != null) + { + code ^= issuer.GetHashCode(); + } + + return code; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return false; + + SignerID id = obj as SignerID; + + if (id == null) + return false; + + return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier) + && Platform.Equals(SerialNumber, id.SerialNumber) + && Platform.Equals(IssuerAsString, id.IssuerAsString); + } + } +} diff --git a/iTechSharp/srcbc/cms/SignerInformation.cs b/iTechSharp/srcbc/cms/SignerInformation.cs new file mode 100644 index 0000000..e1989be --- /dev/null +++ b/iTechSharp/srcbc/cms/SignerInformation.cs @@ -0,0 +1,631 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * an expanded SignerInfo block from a CMS Signed message + */ + public class SignerInformation + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private SignerID sid; + private SignerInfo info; + private AlgorithmIdentifier digestAlgorithm; + private AlgorithmIdentifier encryptionAlgorithm; + private Asn1Set signedAttributes; + private Asn1Set unsignedAttributes; + private CmsProcessable content; + private byte[] signature; + private DerObjectIdentifier contentType; + private IDigestCalculator digestCalculator; + private byte[] resultDigest; + + internal SignerInformation( + SignerInfo info, + DerObjectIdentifier contentType, + CmsProcessable content, + IDigestCalculator digestCalculator) + { + this.info = info; + this.sid = new SignerID(); + this.contentType = contentType; + + try + { + SignerIdentifier s = info.SignerID; + + if (s.IsTagged) + { + Asn1OctetString octs = Asn1OctetString.GetInstance(s.ID); + + sid.SubjectKeyIdentifier = octs.GetOctets(); + } + else + { + Asn1.Cms.IssuerAndSerialNumber iAnds = + Asn1.Cms.IssuerAndSerialNumber.GetInstance(s.ID); + + sid.Issuer = iAnds.Name; + sid.SerialNumber = iAnds.SerialNumber.Value; + } + } + catch (IOException) + { + throw new ArgumentException("invalid sid in SignerInfo"); + } + + this.digestAlgorithm = info.DigestAlgorithm; + this.signedAttributes = info.AuthenticatedAttributes; + this.unsignedAttributes = info.UnauthenticatedAttributes; + this.encryptionAlgorithm = info.DigestEncryptionAlgorithm; + this.signature = info.EncryptedDigest.GetOctets(); + + this.content = content; + this.digestCalculator = digestCalculator; + } + + public SignerID SignerID + { + get { return sid; } + } + + /** + * return the version number for this objects underlying SignerInfo structure. + */ + public int Version + { + get { return info.Version.Value.IntValue; } + } + + public AlgorithmIdentifier DigestAlgorithmID + { + get { return digestAlgorithm; } + } + + /** + * return the object identifier for the signature. + */ + public string DigestAlgOid + { + get { return digestAlgorithm.ObjectID.Id; } + } + + /** + * return the signature parameters, or null if there aren't any. + */ + public Asn1Object DigestAlgParams + { + get + { + Asn1Encodable ae = digestAlgorithm.Parameters; + + return ae == null ? null : ae.ToAsn1Object(); + } + } + + /** + * return the content digest that was calculated during verification. + */ + public byte[] GetContentDigest() + { + if (resultDigest == null) + { + throw new InvalidOperationException("method can only be called after verify."); + } + + return (byte[])resultDigest.Clone(); + } + + public AlgorithmIdentifier EncryptionAlgorithmID + { + get { return encryptionAlgorithm; } + } + + /** + * return the object identifier for the signature. + */ + public string EncryptionAlgOid + { + get { return encryptionAlgorithm.ObjectID.Id; } + } + + /** + * return the signature/encryption algorithm parameters, or null if + * there aren't any. + */ + public Asn1Object EncryptionAlgParams + { + get + { + Asn1Encodable ae = encryptionAlgorithm.Parameters; + + return ae == null ? null : ae.ToAsn1Object(); + } + } + + /** + * return a table of the signed attributes - indexed by + * the OID of the attribute. + */ + public Asn1.Cms.AttributeTable SignedAttributes + { + get + { + return signedAttributes == null + ? null + : new Asn1.Cms.AttributeTable(signedAttributes); + } + } + + /** + * return a table of the unsigned attributes indexed by + * the OID of the attribute. + */ + public Asn1.Cms.AttributeTable UnsignedAttributes + { + get + { + return unsignedAttributes == null + ? null + : new Asn1.Cms.AttributeTable(unsignedAttributes); + } + } + + /** + * return the encoded signature + */ + public byte[] GetSignature() + { + return (byte[]) signature.Clone(); + } + + /** + * Return a SignerInformationStore containing the counter signatures attached to this + * signer. If no counter signatures are present an empty store is returned. + */ + public SignerInformationStore GetCounterSignatures() + { + Asn1.Cms.AttributeTable unsignedAttributeTable = UnsignedAttributes; + if (unsignedAttributeTable == null) + { + return new SignerInformationStore(new ArrayList(0)); + } + + IList counterSignatures = new ArrayList(); + + Asn1.Cms.Attribute counterSignatureAttribute = unsignedAttributeTable[CmsAttributes.CounterSignature]; + if (counterSignatureAttribute != null) + { + Asn1Set values = counterSignatureAttribute.AttrValues; + counterSignatures = new ArrayList(values.Count); + + foreach (Asn1Encodable asn1Obj in values) + { + SignerInfo si = SignerInfo.GetInstance(asn1Obj.ToAsn1Object()); + + string digestName = CmsSignedHelper.Instance.GetDigestAlgName(si.DigestAlgorithm.ObjectID.Id); + + counterSignatures.Add(new SignerInformation(si, CmsAttributes.CounterSignature, null, new CounterSignatureDigestCalculator(digestName, GetSignature()))); + } + } + + return new SignerInformationStore(counterSignatures); + } + + /** + * return the DER encoding of the signed attributes. + * @throws IOException if an encoding error occurs. + */ + public byte[] GetEncodedSignedAttributes() + { + return signedAttributes == null + ? null + : signedAttributes.GetEncoded(Asn1Encodable.Der); + } + + private bool DoVerify( + AsymmetricKeyParameter key, + Asn1.Cms.AttributeTable signedAttrTable) + { + string digestName = Helper.GetDigestAlgName(this.DigestAlgOid); + IDigest digest = Helper.GetDigestInstance(digestName); + + DerObjectIdentifier sigAlgOid = this.encryptionAlgorithm.ObjectID; + Asn1Encodable sigParams = this.encryptionAlgorithm.Parameters; + ISigner sig; + + if (sigAlgOid.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdRsassaPss)) + { + // RFC 4056 + // When the id-RSASSA-PSS algorithm identifier is used for a signature, + // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params. + if (sigParams == null) + throw new CmsException("RSASSA-PSS signature must specify algorithm parameters"); + + try + { + // TODO Provide abstract configuration mechanism + + Asn1.Pkcs.RsassaPssParameters pss = Asn1.Pkcs.RsassaPssParameters.GetInstance( + sigParams.ToAsn1Object()); + + if (!pss.HashAlgorithm.ObjectID.Equals(this.digestAlgorithm.ObjectID)) + throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm"); + if (!pss.MaskGenAlgorithm.ObjectID.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdMgf1)) + throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF"); + + IDigest pssDigest = DigestUtilities.GetDigest(pss.HashAlgorithm.ObjectID); + int saltLen = pss.SaltLength.Value.IntValue; + byte trailer = (byte) pss.TrailerField.Value.IntValue; + + sig = new Crypto.Signers.PssSigner(new RsaBlindedEngine(), pssDigest, saltLen, trailer); + } + catch (Exception e) + { + throw new CmsException("failed to set RSASSA-PSS signature parameters", e); + } + } + else + { + // TODO Probably too strong a check at the moment +// if (sigParams != null) +// throw new CmsException("unrecognised signature parameters provided"); + + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid); + + sig = Helper.GetSignatureInstance(signatureName); + } + + try + { + sig.Init(false, key); + + if (signedAttributes == null) + { + if (content != null) + { + content.Write(new CmsSignedDataGenerator.SigOutputStream(sig)); + content.Write(new CmsSignedDataGenerator.DigOutputStream(digest)); + + resultDigest = DigestUtilities.DoFinal(digest); + } + else + { + resultDigest = digestCalculator.GetDigest(); + + // need to decrypt signature and check message bytes + return VerifyDigest(resultDigest, key, this.GetSignature()); + } + } + else + { + byte[] hash; + if (content != null) + { + content.Write( + new CmsSignedDataGenerator.DigOutputStream(digest)); + + hash = DigestUtilities.DoFinal(digest); + } + else if (digestCalculator != null) + { + hash = digestCalculator.GetDigest(); + } + else + { + hash = null; + } + + resultDigest = hash; + + Asn1.Cms.Attribute dig = signedAttrTable[Asn1.Cms.CmsAttributes.MessageDigest]; + Asn1.Cms.Attribute type = signedAttrTable[Asn1.Cms.CmsAttributes.ContentType]; + + if (dig == null) + { + throw new SignatureException("no hash for content found in signed attributes"); + } + + if (type == null && !contentType.Equals(CmsAttributes.CounterSignature)) + { + throw new SignatureException("no content type id found in signed attributes"); + } + + Asn1Object hashObj = dig.AttrValues[0].ToAsn1Object(); + + if (hashObj is Asn1OctetString) + { + byte[] signedHash = ((Asn1OctetString)hashObj).GetOctets(); + + if (!Arrays.AreEqual(hash, signedHash)) + { + throw new SignatureException("content hash found in signed attributes different"); + } + } + else if (hashObj is DerNull) + { + if (hash != null) + { + throw new SignatureException("NULL hash found in signed attributes when one expected"); + } + } + + if (type != null) + { + DerObjectIdentifier typeOID = (DerObjectIdentifier)type.AttrValues[0]; + + if (!typeOID.Equals(contentType)) + { + throw new SignatureException("contentType in signed attributes different"); + } + } + + byte[] tmp = this.GetEncodedSignedAttributes(); + sig.BlockUpdate(tmp, 0, tmp.Length); + } + + return sig.VerifySignature(this.GetSignature()); + } + catch (InvalidKeyException e) + { + throw new CmsException( + "key not appropriate to signature in message.", e); + } + catch (IOException e) + { + throw new CmsException( + "can't process mime object to create signature.", e); + } + catch (SignatureException e) + { + throw new CmsException( + "invalid signature format in message: " + e.Message, e); + } + } + + private bool IsNull( + Asn1Encodable o) + { + return (o is Asn1Null) || (o == null); + } + + private DigestInfo DerDecode( + byte[] encoding) + { + if (encoding[0] != (int)(Asn1Tags.Constructed | Asn1Tags.Sequence)) + { + throw new IOException("not a digest info object"); + } + + DigestInfo digInfo = DigestInfo.GetInstance(Asn1Object.FromByteArray(encoding)); + + // length check to avoid Bleichenbacher vulnerability + + if (digInfo.GetEncoded().Length != encoding.Length) + { + throw new CmsException("malformed RSA signature"); + } + + return digInfo; + } + + private bool VerifyDigest( + byte[] digest, + AsymmetricKeyParameter key, + byte[] signature) + { + string algorithm = Helper.GetEncryptionAlgName(this.EncryptionAlgOid); + + try + { + if (algorithm.Equals("RSA")) + { + IBufferedCipher c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); + + c.Init(false, key); + + byte[] decrypt = c.DoFinal(signature); + + DigestInfo digInfo = DerDecode(decrypt); + + if (!digInfo.AlgorithmID.ObjectID.Equals(digestAlgorithm.ObjectID)) + { + return false; + } + + if (!IsNull(digInfo.AlgorithmID.Parameters)) + { + return false; + } + + byte[] sigHash = digInfo.GetDigest(); + + return Arrays.AreEqual(digest, sigHash); + } + else if (algorithm.Equals("DSA")) + { + ISigner sig = SignerUtilities.GetSigner("NONEwithDSA"); + + sig.Init(false, key); + + sig.BlockUpdate(digest, 0, digest.Length); + + return sig.VerifySignature(signature); + } + else + { + throw new CmsException("algorithm: " + algorithm + " not supported in base signatures."); + } + } + catch (SecurityUtilityException e) + { + throw e; + } + catch (GeneralSecurityException e) + { + throw new CmsException("Exception processing signature: " + e, e); + } + catch (IOException e) + { + throw new CmsException("Exception decoding signature: " + e, e); + } + } + + /** + * verify that the given public key succesfully handles and confirms the + * signature associated with this signer. + */ + public bool Verify( + AsymmetricKeyParameter pubKey) + { + if (pubKey.IsPrivate) + throw new ArgumentException("Expected public key", "pubKey"); + + return DoVerify(pubKey, this.SignedAttributes); + } + + /** + * verify that the given certificate successfully handles and confirms + * the signature associated with this signer and, if a signingTime + * attribute is available, that the certificate was valid at the time the + * signature was generated. + */ + public bool Verify( + X509Certificate cert) + { + Asn1.Cms.AttributeTable attr = this.SignedAttributes; + + if (attr != null) + { + Asn1EncodableVector v = attr.GetAll(CmsAttributes.SigningTime); + switch (v.Count) + { + case 0: + break; + case 1: + { + Asn1.Cms.Attribute t = (Asn1.Cms.Attribute) v[0]; + Debug.Assert(t != null); + + Asn1Set attrValues = t.AttrValues; + if (attrValues.Count != 1) + throw new CmsException("A signing-time attribute MUST have a single attribute value"); + + Asn1.Cms.Time time = Asn1.Cms.Time.GetInstance(attrValues[0].ToAsn1Object()); + + cert.CheckValidity(time.Date); + break; + } + default: + throw new CmsException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the signing-time attribute"); + } + } + + return DoVerify(cert.GetPublicKey(), attr); + } + + /** + * Return the base ASN.1 CMS structure that this object contains. + * + * @return an object containing a CMS SignerInfo structure. + */ + public SignerInfo ToSignerInfo() + { + return info; + } + + /** + * Return a signer information object with the passed in unsigned + * attributes replacing the ones that are current associated with + * the object passed in. + * + * @param signerInformation the signerInfo to be used as the basis. + * @param unsignedAttributes the unsigned attributes to add. + * @return a copy of the original SignerInformationObject with the changed attributes. + */ + public static SignerInformation ReplaceUnsignedAttributes( + SignerInformation signerInformation, + Asn1.Cms.AttributeTable unsignedAttributes) + { + SignerInfo sInfo = signerInformation.info; + Asn1Set unsignedAttr = null; + + if (unsignedAttributes != null) + { + unsignedAttr = new DerSet(unsignedAttributes.ToAsn1EncodableVector()); + } + + return new SignerInformation( + new SignerInfo( + sInfo.SignerID, + sInfo.DigestAlgorithm, + sInfo.AuthenticatedAttributes, + sInfo.DigestEncryptionAlgorithm, + sInfo.EncryptedDigest, + unsignedAttr), + signerInformation.contentType, + signerInformation.content, + null); + } + + /** + * Return a signer information object with passed in SignerInformationStore representing counter + * signatures attached as an unsigned attribute. + * + * @param signerInformation the signerInfo to be used as the basis. + * @param counterSigners signer info objects carrying counter signature. + * @return a copy of the original SignerInformationObject with the changed attributes. + */ + public static SignerInformation AddCounterSigners( + SignerInformation signerInformation, + SignerInformationStore counterSigners) + { + SignerInfo sInfo = signerInformation.info; + Asn1.Cms.AttributeTable unsignedAttr = signerInformation.UnsignedAttributes; + Asn1EncodableVector v; + + if (unsignedAttr != null) + { + v = unsignedAttr.ToAsn1EncodableVector(); + } + else + { + v = new Asn1EncodableVector(); + } + + Asn1EncodableVector sigs = new Asn1EncodableVector(); + + foreach (SignerInformation sigInf in counterSigners.GetSigners()) + { + sigs.Add(sigInf.ToSignerInfo()); + } + + v.Add(new Asn1.Cms.Attribute(CmsAttributes.CounterSignature, new DerSet(sigs))); + + return new SignerInformation( + new SignerInfo( + sInfo.SignerID, + sInfo.DigestAlgorithm, + sInfo.AuthenticatedAttributes, + sInfo.DigestEncryptionAlgorithm, + sInfo.EncryptedDigest, + new DerSet(v)), + signerInformation.contentType, + signerInformation.content, + null); + } + } +} diff --git a/iTechSharp/srcbc/cms/SignerInformationStore.cs b/iTechSharp/srcbc/cms/SignerInformationStore.cs new file mode 100644 index 0000000..b44381c --- /dev/null +++ b/iTechSharp/srcbc/cms/SignerInformationStore.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Cms +{ + public class SignerInformationStore + { + private readonly ArrayList all; //ArrayList[SignerInformation] + private readonly Hashtable table = new Hashtable(); // Hashtable[SignerID, ArrayList[SignerInformation]] + + public SignerInformationStore( + ICollection signerInfos) + { + foreach (SignerInformation signer in signerInfos) + { + SignerID sid = signer.SignerID; + ArrayList list = (ArrayList) table[sid]; + + if (list == null) + { + table[sid] = list = new ArrayList(1); + } + + list.Add(signer); + } + + this.all = new ArrayList(signerInfos); + } + + /** + * Return the first SignerInformation object that matches the + * passed in selector. Null if there are no matches. + * + * @param selector to identify a signer + * @return a single SignerInformation object. Null if none matches. + */ + public SignerInformation GetFirstSigner( + SignerID selector) + { + ArrayList list = (ArrayList) table[selector]; + + return list == null ? null : (SignerInformation) list[0]; + } + + /// The number of signers in the collection. + public int Count + { + get { return all.Count; } + } + + /// An ICollection of all signers in the collection + public ICollection GetSigners() + { + return new ArrayList(all); + } + + /** + * Return possible empty collection with signers matching the passed in SignerID + * + * @param selector a signer id to select against. + * @return a collection of SignerInformation objects. + */ + public ICollection GetSigners( + SignerID selector) + { + ArrayList list = (ArrayList) table[selector]; + + return list == null ? new ArrayList() : new ArrayList(list); + } + } +} diff --git a/iTechSharp/srcbc/cms/SimpleAttributeTableGenerator.cs b/iTechSharp/srcbc/cms/SimpleAttributeTableGenerator.cs new file mode 100644 index 0000000..b3df21c --- /dev/null +++ b/iTechSharp/srcbc/cms/SimpleAttributeTableGenerator.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.Cms; + +namespace Org.BouncyCastle.Cms +{ + /** + * Basic generator that just returns a preconstructed attribute table + */ + public class SimpleAttributeTableGenerator + : CmsAttributeTableGenerator + { + private readonly AttributeTable attributes; + + public SimpleAttributeTableGenerator( + AttributeTable attributes) + { + this.attributes = attributes; + } + + public virtual AttributeTable GetAttributes( + IDictionary parameters) + { + return attributes; + } + } +} diff --git a/iTechSharp/srcbc/crypto/AsymmetricCipherKeyPair.cs b/iTechSharp/srcbc/crypto/AsymmetricCipherKeyPair.cs new file mode 100644 index 0000000..b00a3dc --- /dev/null +++ b/iTechSharp/srcbc/crypto/AsymmetricCipherKeyPair.cs @@ -0,0 +1,52 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * a holding class for public/private parameter pairs. + */ + public class AsymmetricCipherKeyPair + { + private readonly AsymmetricKeyParameter publicParameter; + private readonly AsymmetricKeyParameter privateParameter; + + /** + * basic constructor. + * + * @param publicParam a public key parameters object. + * @param privateParam the corresponding private key parameters. + */ + public AsymmetricCipherKeyPair( + AsymmetricKeyParameter publicParameter, + AsymmetricKeyParameter privateParameter) + { + if (publicParameter.IsPrivate) + throw new ArgumentException("Expected a public key", "publicParameter"); + if (!privateParameter.IsPrivate) + throw new ArgumentException("Expected a private key", "privateParameter"); + + this.publicParameter = publicParameter; + this.privateParameter = privateParameter; + } + + /** + * return the public key parameters. + * + * @return the public key parameters. + */ + public AsymmetricKeyParameter Public + { + get { return publicParameter; } + } + + /** + * return the private key parameters. + * + * @return the private key parameters. + */ + public AsymmetricKeyParameter Private + { + get { return privateParameter; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/AsymmetricKeyParameter.cs b/iTechSharp/srcbc/crypto/AsymmetricKeyParameter.cs new file mode 100644 index 0000000..076c101 --- /dev/null +++ b/iTechSharp/srcbc/crypto/AsymmetricKeyParameter.cs @@ -0,0 +1,47 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto +{ + public class AsymmetricKeyParameter + : ICipherParameters + { + private readonly bool privateKey; + + public AsymmetricKeyParameter( + bool privateKey) + { + this.privateKey = privateKey; + } + + public bool IsPrivate + { + get { return privateKey; } + } + + public override bool Equals( + object obj) + { + AsymmetricKeyParameter other = obj as AsymmetricKeyParameter; + + if (other == null) + { + return false; + } + + return Equals(other); + } + + protected bool Equals( + AsymmetricKeyParameter other) + { + return privateKey == other.privateKey; + } + + public override int GetHashCode() + { + return privateKey.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/BufferedAeadBlockCipher.cs b/iTechSharp/srcbc/crypto/BufferedAeadBlockCipher.cs new file mode 100644 index 0000000..87413b6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/BufferedAeadBlockCipher.cs @@ -0,0 +1,259 @@ +using System; + +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto +{ + /** + * The AEAD block ciphers already handle buffering internally, so this class + * just takes care of implementing IBufferedCipher methods. + */ + public class BufferedAeadBlockCipher + : BufferedCipherBase + { + private readonly IAeadBlockCipher cipher; + + public BufferedAeadBlockCipher( + IAeadBlockCipher cipher) + { + if (cipher == null) + throw new ArgumentNullException("cipher"); + + this.cipher = cipher; + } + + public override string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + cipher.Init(forEncryption, parameters); + } + + /** + * return the blocksize for the underlying cipher. + * + * @return the blocksize for the underlying cipher. + */ + public override int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public override int GetUpdateOutputSize( + int length) + { + return cipher.GetUpdateOutputSize(length); + } + + /** + * return the size of the output buffer required for an update plus a + * doFinal with an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with len bytes of input. + */ + public override int GetOutputSize( + int length) + { + return cipher.GetOutputSize(length); + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + return cipher.ProcessByte(input, output, outOff); + } + + public override byte[] ProcessByte( + byte input) + { + int outLength = GetUpdateOutputSize(1); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessByte(input, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (input == null) + throw new ArgumentNullException("input"); + if (length < 1) + return null; + + int outLength = GetUpdateOutputSize(length); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessBytes(input, inOff, length, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param len the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + return cipher.ProcessBytes(input, inOff, length, output, outOff); + } + + public override byte[] DoFinal() + { + byte[] outBytes = EmptyBuffer; + + int length = GetOutputSize(0); + if (length > 0) + { + outBytes = new byte[length]; + + int pos = DoFinal(outBytes, 0); + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + + return outBytes; + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int inLen) + { + if (input == null) + throw new ArgumentNullException("input"); + + int length = GetOutputSize(inLen); + + byte[] outBytes = EmptyBuffer; + + if (length > 0) + { + outBytes = new byte[length]; + + int pos = (inLen > 0) + ? ProcessBytes(input, inOff, inLen, outBytes, 0) + : 0; + + pos += DoFinal(outBytes, pos); + + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + + return outBytes; + } + + /** + * Process the last block in the buffer. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output, or the input is not block size aligned and should be. + * @exception InvalidOperationException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if padding is expected and not found. + * @exception DataLengthException if the input is not block size + * aligned. + */ + public override int DoFinal( + byte[] output, + int outOff) + { + return cipher.DoFinal(output, outOff); + } + + /** + * Reset the buffer and cipher. After resetting the object is in the same + * state as it was after the last init (if there was one). + */ + public override void Reset() + { + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/BufferedAsymmetricBlockCipher.cs b/iTechSharp/srcbc/crypto/BufferedAsymmetricBlockCipher.cs new file mode 100644 index 0000000..09ec59f --- /dev/null +++ b/iTechSharp/srcbc/crypto/BufferedAsymmetricBlockCipher.cs @@ -0,0 +1,152 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Crypto.Engines; + +namespace Org.BouncyCastle.Crypto +{ + /** + * a buffer wrapper for an asymmetric block cipher, allowing input + * to be accumulated in a piecemeal fashion until final processing. + */ + public class BufferedAsymmetricBlockCipher + : BufferedCipherBase + { + private readonly IAsymmetricBlockCipher cipher; + + private byte[] buffer; + private int bufOff; + + /** + * base constructor. + * + * @param cipher the cipher this buffering object wraps. + */ + public BufferedAsymmetricBlockCipher( + IAsymmetricBlockCipher cipher) + { + this.cipher = cipher; + } + + /** + * return the amount of data sitting in the buffer. + * + * @return the amount of data sitting in the buffer. + */ + internal int GetBufferPosition() + { + return bufOff; + } + + public override string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + public override int GetBlockSize() + { + return cipher.GetInputBlockSize(); + } + + public override int GetOutputSize( + int length) + { + return cipher.GetOutputBlockSize(); + } + + public override int GetUpdateOutputSize( + int length) + { + return 0; + } + + /** + * initialise the buffer and the underlying cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + */ + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + Reset(); + + cipher.Init(forEncryption, parameters); + + // + // we allow for an extra byte where people are using their own padding + // mechanisms on a raw cipher. + // + this.buffer = new byte[cipher.GetInputBlockSize() + (forEncryption ? 1 : 0)]; + this.bufOff = 0; + } + + public override byte[] ProcessByte( + byte input) + { + if (bufOff >= buffer.Length) + throw new DataLengthException("attempt to process message to long for cipher"); + + buffer[bufOff++] = input; + return null; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (length < 1) + return null; + + if (input == null) + throw new ArgumentNullException("input"); + if (bufOff + length > buffer.Length) + throw new DataLengthException("attempt to process message to long for cipher"); + + Array.Copy(input, inOff, buffer, bufOff, length); + bufOff += length; + return null; + } + + /** + * process the contents of the buffer using the underlying + * cipher. + * + * @return the result of the encryption/decryption process on the + * buffer. + * @exception InvalidCipherTextException if we are given a garbage block. + */ + public override byte[] DoFinal() + { + byte[] outBytes = bufOff > 0 + ? cipher.ProcessBlock(buffer, 0, bufOff) + : EmptyBuffer; + + Reset(); + + return outBytes; + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int length) + { + ProcessBytes(input, inOff, length); + return DoFinal(); + } + + /// Reset the buffer + public override void Reset() + { + if (buffer != null) + { + Array.Clear(buffer, 0, buffer.Length); + bufOff = 0; + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/BufferedBlockCipher.cs b/iTechSharp/srcbc/crypto/BufferedBlockCipher.cs new file mode 100644 index 0000000..0fad6d8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/BufferedBlockCipher.cs @@ -0,0 +1,372 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto +{ + /** + * A wrapper class that allows block ciphers to be used to process data in + * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the + * buffer is full and more data is being added, or on a doFinal. + *

      + * Note: in the case where the underlying cipher is either a CFB cipher or an + * OFB one the last block may not be a multiple of the block size. + *

      + */ + public class BufferedBlockCipher + : BufferedCipherBase + { + internal byte[] buf; + internal int bufOff; + internal bool forEncryption; + internal IBlockCipher cipher; + + /** + * constructor for subclasses + */ + protected BufferedBlockCipher() + { + } + + /** + * Create a buffered block cipher without padding. + * + * @param cipher the underlying block cipher this buffering object wraps. + * false otherwise. + */ + public BufferedBlockCipher( + IBlockCipher cipher) + { + if (cipher == null) + throw new ArgumentNullException("cipher"); + + this.cipher = cipher; + buf = new byte[cipher.GetBlockSize()]; + bufOff = 0; + } + + public override string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + Reset(); + + cipher.Init(forEncryption, parameters); + } + + /** + * return the blocksize for the underlying cipher. + * + * @return the blocksize for the underlying cipher. + */ + public override int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public override int GetUpdateOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + return total - leftOver; + } + + /** + * return the size of the output buffer required for an update plus a + * doFinal with an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with len bytes of input. + */ + public override int GetOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + if (leftOver == 0) + { + return total; + } + return total - leftOver + buf.Length; + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + buf[bufOff++] = input; + + if (bufOff == buf.Length) + { + if ((outOff + buf.Length) > output.Length) + throw new DataLengthException("output buffer too short"); + + bufOff = 0; + return cipher.ProcessBlock(buf, 0, output, outOff); + } + + return 0; + } + + public override byte[] ProcessByte( + byte input) + { + int outLength = GetUpdateOutputSize(1); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessByte(input, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (input == null) + throw new ArgumentNullException("input"); + if (length < 1) + return null; + + int outLength = GetUpdateOutputSize(length); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessBytes(input, inOff, length, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param len the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (length < 1) + { + if (length < 0) + throw new ArgumentException("Can't have a negative input length!"); + + return 0; + } + + int blockSize = GetBlockSize(); + int outLength = GetUpdateOutputSize(length); + + if (outLength > 0) + { + if ((outOff + outLength) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.Length - bufOff; + if (length > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + resultLen += cipher.ProcessBlock(buf, 0, output, outOff); + bufOff = 0; + length -= gapLen; + inOff += gapLen; + while (length > buf.Length) + { + resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen); + length -= blockSize; + inOff += blockSize; + } + } + Array.Copy(input, inOff, buf, bufOff, length); + bufOff += length; + if (bufOff == buf.Length) + { + resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); + bufOff = 0; + } + return resultLen; + } + + public override byte[] DoFinal() + { + byte[] outBytes = EmptyBuffer; + + int length = GetOutputSize(0); + if (length > 0) + { + outBytes = new byte[length]; + + int pos = DoFinal(outBytes, 0); + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + + return outBytes; + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int inLen) + { + if (input == null) + throw new ArgumentNullException("input"); + + int length = GetOutputSize(inLen); + + byte[] outBytes = EmptyBuffer; + + if (length > 0) + { + outBytes = new byte[length]; + + int pos = (inLen > 0) + ? ProcessBytes(input, inOff, inLen, outBytes, 0) + : 0; + + pos += DoFinal(outBytes, pos); + + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + + return outBytes; + } + + /** + * Process the last block in the buffer. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output, or the input is not block size aligned and should be. + * @exception InvalidOperationException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if padding is expected and not found. + * @exception DataLengthException if the input is not block size + * aligned. + */ + public override int DoFinal( + byte[] output, + int outOff) + { + if (bufOff != 0) + { + if (!cipher.IsPartialBlockOkay) + { + throw new DataLengthException("data not block size aligned"); + } + + if (outOff + bufOff > output.Length) + { + throw new DataLengthException("output buffer too short for DoFinal()"); + } + + // NB: Can't copy directly, or we may write too much output + cipher.ProcessBlock(buf, 0, buf, 0); + Array.Copy(buf, 0, output, outOff, bufOff); + } + + int resultLen = bufOff; + + Reset(); + + return resultLen; + } + + /** + * Reset the buffer and cipher. After resetting the object is in the same + * state as it was after the last init (if there was one). + */ + public override void Reset() + { + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/BufferedCipherBase.cs b/iTechSharp/srcbc/crypto/BufferedCipherBase.cs new file mode 100644 index 0000000..9d86102 --- /dev/null +++ b/iTechSharp/srcbc/crypto/BufferedCipherBase.cs @@ -0,0 +1,113 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + public abstract class BufferedCipherBase + : IBufferedCipher + { + protected static readonly byte[] EmptyBuffer = new byte[0]; + + public abstract string AlgorithmName { get; } + + public abstract void Init(bool forEncryption, ICipherParameters parameters); + + public abstract int GetBlockSize(); + + public abstract int GetOutputSize(int inputLen); + public abstract int GetUpdateOutputSize(int inputLen); + + public abstract byte[] ProcessByte(byte input); + + public virtual int ProcessByte( + byte input, + byte[] output, + int outOff) + { + byte[] outBytes = ProcessByte(input); + if (outBytes == null) + return 0; + if (outOff + outBytes.Length > output.Length) + throw new DataLengthException("output buffer too short"); + outBytes.CopyTo(output, outOff); + return outBytes.Length; + } + + public virtual byte[] ProcessBytes( + byte[] input) + { + return ProcessBytes(input, 0, input.Length); + } + + public abstract byte[] ProcessBytes(byte[] input, int inOff, int length); + + public virtual int ProcessBytes( + byte[] input, + byte[] output, + int outOff) + { + return ProcessBytes(input, 0, input.Length, output, outOff); + } + + public virtual int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + byte[] outBytes = ProcessBytes(input, inOff, length); + if (outBytes == null) + return 0; + if (outOff + outBytes.Length > output.Length) + throw new DataLengthException("output buffer too short"); + outBytes.CopyTo(output, outOff); + return outBytes.Length; + } + + public abstract byte[] DoFinal(); + + public virtual byte[] DoFinal( + byte[] input) + { + return DoFinal(input, 0, input.Length); + } + + public abstract byte[] DoFinal( + byte[] input, + int inOff, + int length); + + public virtual int DoFinal( + byte[] output, + int outOff) + { + byte[] outBytes = DoFinal(); + if (outOff + outBytes.Length > output.Length) + throw new DataLengthException("output buffer too short"); + outBytes.CopyTo(output, outOff); + return outBytes.Length; + } + + public virtual int DoFinal( + byte[] input, + byte[] output, + int outOff) + { + return DoFinal(input, 0, input.Length, output, outOff); + } + + public virtual int DoFinal( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + int len = ProcessBytes(input, inOff, length, output, outOff); + len += DoFinal(output, outOff + len); + return len; + } + + public abstract void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/BufferedIesCipher.cs b/iTechSharp/srcbc/crypto/BufferedIesCipher.cs new file mode 100644 index 0000000..6dab4ae --- /dev/null +++ b/iTechSharp/srcbc/crypto/BufferedIesCipher.cs @@ -0,0 +1,113 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto +{ + public class BufferedIesCipher + : BufferedCipherBase + { + private readonly IesEngine engine; + private bool forEncryption; + private MemoryStream buffer = new MemoryStream(); + + public BufferedIesCipher( + IesEngine engine) + { + if (engine == null) + throw new ArgumentNullException("engine"); + + this.engine = engine; + } + + public override string AlgorithmName + { + // TODO Create IESEngine.AlgorithmName + get { return "IES"; } + } + + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + // TODO + throw Platform.CreateNotImplementedException("IES"); + } + + public override int GetBlockSize() + { + return 0; + } + + public override int GetOutputSize( + int inputLen) + { + if (engine == null) + throw new InvalidOperationException("cipher not initialised"); + + int baseLen = inputLen + (int) buffer.Length; + return forEncryption + ? baseLen + 20 + : baseLen - 20; + } + + public override int GetUpdateOutputSize( + int inputLen) + { + return 0; + } + + public override byte[] ProcessByte( + byte input) + { + buffer.WriteByte(input); + return null; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (input == null) + throw new ArgumentNullException("input"); + if (inOff < 0) + throw new ArgumentException("inOff"); + if (length < 0) + throw new ArgumentException("length"); + if (inOff + length > input.Length) + throw new ArgumentException("invalid offset/length specified for input array"); + + buffer.Write(input, inOff, length); + return null; + } + + public override byte[] DoFinal() + { + byte[] buf = buffer.ToArray(); + + Reset(); + + return engine.ProcessBlock(buf, 0, buf.Length); + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int length) + { + ProcessBytes(input, inOff, length); + return DoFinal(); + } + + public override void Reset() + { + buffer.SetLength(0); + } + } +} diff --git a/iTechSharp/srcbc/crypto/BufferedStreamCipher.cs b/iTechSharp/srcbc/crypto/BufferedStreamCipher.cs new file mode 100644 index 0000000..2d4987b --- /dev/null +++ b/iTechSharp/srcbc/crypto/BufferedStreamCipher.cs @@ -0,0 +1,131 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto +{ + public class BufferedStreamCipher + : BufferedCipherBase + { + private readonly IStreamCipher cipher; + + public BufferedStreamCipher( + IStreamCipher cipher) + { + if (cipher == null) + throw new ArgumentNullException("cipher"); + + this.cipher = cipher; + } + + public override string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + cipher.Init(forEncryption, parameters); + } + + public override int GetBlockSize() + { + return 0; + } + + public override int GetOutputSize( + int inputLen) + { + return inputLen; + } + + public override int GetUpdateOutputSize( + int inputLen) + { + return inputLen; + } + + public override byte[] ProcessByte( + byte input) + { + return new byte[]{ cipher.ReturnByte(input) }; + } + + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + if (outOff >= output.Length) + throw new DataLengthException("output buffer too short"); + + output[outOff] = cipher.ReturnByte(input); + return 1; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (length < 1) + return null; + + byte[] output = new byte[length]; + cipher.ProcessBytes(input, inOff, length, output, 0); + return output; + } + + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (length < 1) + return 0; + + if (length > 0) + { + cipher.ProcessBytes(input, inOff, length, output, outOff); + } + + return length; + } + + public override byte[] DoFinal() + { + Reset(); + + return EmptyBuffer; + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int length) + { + if (length < 1) + return EmptyBuffer; + + byte[] output = ProcessBytes(input, inOff, length); + + Reset(); + + return output; + } + + public override void Reset() + { + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/CipherKeyGenerator.cs b/iTechSharp/srcbc/crypto/CipherKeyGenerator.cs new file mode 100644 index 0000000..5d00d34 --- /dev/null +++ b/iTechSharp/srcbc/crypto/CipherKeyGenerator.cs @@ -0,0 +1,83 @@ +using System; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto +{ + /** + * The base class for symmetric, or secret, cipher key generators. + */ + public class CipherKeyGenerator + { + protected internal SecureRandom random; + protected internal int strength; + private bool uninitialised = true; + private int defaultStrength; + + public CipherKeyGenerator() + { + } + + internal CipherKeyGenerator( + int defaultStrength) + { + if (defaultStrength < 1) + throw new ArgumentException("strength must be a positive value", "defaultStrength"); + + this.defaultStrength = defaultStrength; + } + + public int DefaultStrength + { + get { return defaultStrength; } + } + + /** + * initialise the key generator. + * + * @param param the parameters to be used for key generation + */ + public void Init( + KeyGenerationParameters parameters) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + + this.uninitialised = false; + + engineInit(parameters); + } + + protected virtual void engineInit( + KeyGenerationParameters parameters) + { + this.random = parameters.Random; + this.strength = (parameters.Strength + 7) / 8; + } + + /** + * Generate a secret key. + * + * @return a byte array containing the key value. + */ + public byte[] GenerateKey() + { + if (uninitialised) + { + if (defaultStrength < 1) + throw new InvalidOperationException("Generator has not been initialised"); + + uninitialised = false; + + engineInit(new KeyGenerationParameters(new SecureRandom(), defaultStrength)); + } + + return engineGenerateKey(); + } + + protected virtual byte[] engineGenerateKey() + { + return random.GenerateSeed(strength); + } + } +} diff --git a/iTechSharp/srcbc/crypto/CryptoException.cs b/iTechSharp/srcbc/crypto/CryptoException.cs new file mode 100644 index 0000000..05b6b49 --- /dev/null +++ b/iTechSharp/srcbc/crypto/CryptoException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + public abstract class CryptoException + : Exception + { + protected CryptoException() + { + } + + protected CryptoException( + string message) + : base(message) + { + } + + protected CryptoException( + string message, + Exception exception) + : base(message, exception) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/DataLengthException.cs b/iTechSharp/srcbc/crypto/DataLengthException.cs new file mode 100644 index 0000000..8bd695b --- /dev/null +++ b/iTechSharp/srcbc/crypto/DataLengthException.cs @@ -0,0 +1,39 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * this exception is thrown if a buffer that is meant to have output + * copied into it turns out to be too short, or if we've been given + * insufficient input. In general this exception will Get thrown rather + * than an ArrayOutOfBounds exception. + */ + public class DataLengthException + : CryptoException + { + /** + * base constructor. + */ + public DataLengthException() + { + } + + /** + * create a DataLengthException with the given message. + * + * @param message the message to be carried with the exception. + */ + public DataLengthException( + string message) + : base(message) + { + } + + public DataLengthException( + string message, + Exception exception) + : base(message, exception) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/IAsymmetricBlockCipher.cs b/iTechSharp/srcbc/crypto/IAsymmetricBlockCipher.cs new file mode 100644 index 0000000..455cfaa --- /dev/null +++ b/iTechSharp/srcbc/crypto/IAsymmetricBlockCipher.cs @@ -0,0 +1,30 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// Base interface for a public/private key block cipher. + public interface IAsymmetricBlockCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// Initialise for encryption if true, for decryption if false. + /// The key or other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); + + /// The maximum size, in bytes, an input block may be. + int GetInputBlockSize(); + + /// The maximum size, in bytes, an output block will be. + int GetOutputBlockSize(); + + /// Process a block. + /// The input buffer. + /// The offset into inBuf that the input block begins. + /// The length of the input block. + /// Input decrypts improperly. + /// Input is too large for the cipher. + byte[] ProcessBlock(byte[] inBuf, int inOff, int inLen); + } +} diff --git a/iTechSharp/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs new file mode 100644 index 0000000..9ec5dfa --- /dev/null +++ b/iTechSharp/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs @@ -0,0 +1,24 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * interface that a public/private key pair generator should conform to. + */ + public interface IAsymmetricCipherKeyPairGenerator + { + /** + * intialise the key pair generator. + * + * @param the parameters the key pair is to be initialised with. + */ + void Init(KeyGenerationParameters parameters); + + /** + * return an AsymmetricCipherKeyPair containing the Generated keys. + * + * @return an AsymmetricCipherKeyPair containing the Generated keys. + */ + AsymmetricCipherKeyPair GenerateKeyPair(); + } +} diff --git a/iTechSharp/srcbc/crypto/IBasicAgreement.cs b/iTechSharp/srcbc/crypto/IBasicAgreement.cs new file mode 100644 index 0000000..8bd363d --- /dev/null +++ b/iTechSharp/srcbc/crypto/IBasicAgreement.cs @@ -0,0 +1,24 @@ +using System; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto +{ + /** + * The basic interface that basic Diffie-Hellman implementations + * conforms to. + */ + public interface IBasicAgreement + { + /** + * initialise the agreement engine. + */ + void Init(ICipherParameters parameters); + + /** + * given a public key from a given party calculate the next + * message in the agreement sequence. + */ + BigInteger CalculateAgreement(ICipherParameters pubKey); + } + +} diff --git a/iTechSharp/srcbc/crypto/IBlockCipher.cs b/iTechSharp/srcbc/crypto/IBlockCipher.cs new file mode 100644 index 0000000..a3ad6d6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IBlockCipher.cs @@ -0,0 +1,36 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// Base interface for a symmetric key block cipher. + public interface IBlockCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// Initialise for encryption if true, for decryption if false. + /// The key or other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); + + /// The block size for this cipher, in bytes. + int GetBlockSize(); + + /// Indicates whether this cipher can handle partial blocks. + bool IsPartialBlockOkay { get; } + + /// Process a block. + /// The input buffer. + /// The offset into inBuf that the input block begins. + /// The output buffer. + /// The offset into outBuf to write the output block. + /// If input block is wrong size, or outBuf too small. + /// The number of bytes processed and produced. + int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff); + + /// + /// Reset the cipher to the same state as it was after the last init (if there was one). + /// + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/IBufferedCipher.cs b/iTechSharp/srcbc/crypto/IBufferedCipher.cs new file mode 100644 index 0000000..69dec95 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IBufferedCipher.cs @@ -0,0 +1,44 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// Block cipher engines are expected to conform to this interface. + public interface IBufferedCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// If true the cipher is initialised for encryption, + /// if false for decryption. + /// The key and other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); + + int GetBlockSize(); + + int GetOutputSize(int inputLen); + + int GetUpdateOutputSize(int inputLen); + + byte[] ProcessByte(byte input); + int ProcessByte(byte input, byte[] output, int outOff); + + byte[] ProcessBytes(byte[] input); + byte[] ProcessBytes(byte[] input, int inOff, int length); + int ProcessBytes(byte[] input, byte[] output, int outOff); + int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff); + + byte[] DoFinal(); + byte[] DoFinal(byte[] input); + byte[] DoFinal(byte[] input, int inOff, int length); + int DoFinal(byte[] output, int outOff); + int DoFinal(byte[] input, byte[] output, int outOff); + int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff); + + /// + /// Reset the cipher. After resetting the cipher is in the same state + /// as it was after the last init (if there was one). + /// + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/ICipherParameters.cs b/iTechSharp/srcbc/crypto/ICipherParameters.cs new file mode 100644 index 0000000..fff0941 --- /dev/null +++ b/iTechSharp/srcbc/crypto/ICipherParameters.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * all parameter classes implement this. + */ + public interface ICipherParameters + { + } +} diff --git a/iTechSharp/srcbc/crypto/IDSA.cs b/iTechSharp/srcbc/crypto/IDSA.cs new file mode 100644 index 0000000..46056d8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IDSA.cs @@ -0,0 +1,40 @@ +using System; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto +{ + /** + * interface for classes implementing the Digital Signature Algorithm + */ + public interface IDsa + { + string AlgorithmName { get; } + + /** + * initialise the signer for signature generation or signature + * verification. + * + * @param forSigning true if we are generating a signature, false + * otherwise. + * @param param key parameters for signature generation. + */ + void Init(bool forSigning, ICipherParameters parameters); + + /** + * sign the passed in message (usually the output of a hash function). + * + * @param message the message to be signed. + * @return two big integers representing the r and s values respectively. + */ + BigInteger[] GenerateSignature(byte[] message); + + /** + * verify the message message against the signature values r and s. + * + * @param message the message that was supposed to have been signed. + * @param r the r signature value. + * @param s the s signature value. + */ + bool VerifySignature(byte[] message, BigInteger r, BigInteger s); + } +} diff --git a/iTechSharp/srcbc/crypto/IDerivationFunction.cs b/iTechSharp/srcbc/crypto/IDerivationFunction.cs new file mode 100644 index 0000000..7f289f7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IDerivationFunction.cs @@ -0,0 +1,24 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * base interface for general purpose byte derivation functions. + */ + public interface IDerivationFunction + { + void Init(IDerivationParameters parameters); + + /** + * return the message digest used as the basis for the function + */ + IDigest Digest + { + get; + } + + int GenerateBytes(byte[] output, int outOff, int length); + //throws DataLengthException, ArgumentException; + } + +} diff --git a/iTechSharp/srcbc/crypto/IDerivationParameters.cs b/iTechSharp/srcbc/crypto/IDerivationParameters.cs new file mode 100644 index 0000000..f1c8485 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IDerivationParameters.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * Parameters for key/byte stream derivation classes + */ + public interface IDerivationParameters + { + } +} diff --git a/iTechSharp/srcbc/crypto/IDigest.cs b/iTechSharp/srcbc/crypto/IDigest.cs new file mode 100644 index 0000000..6769dcc --- /dev/null +++ b/iTechSharp/srcbc/crypto/IDigest.cs @@ -0,0 +1,61 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * interface that a message digest conforms to. + */ + public interface IDigest + { + /** + * return the algorithm name + * + * @return the algorithm name + */ + string AlgorithmName { get; } + + /** + * return the size, in bytes, of the digest produced by this message digest. + * + * @return the size, in bytes, of the digest produced by this message digest. + */ + int GetDigestSize(); + + /** + * return the size, in bytes, of the internal buffer used by this digest. + * + * @return the size, in bytes, of the internal buffer used by this digest. + */ + int GetByteLength(); + + /** + * update the message digest with a single byte. + * + * @param inByte the input byte to be entered. + */ + void Update(byte input); + + /** + * update the message digest with a block of bytes. + * + * @param input the byte array containing the data. + * @param inOff the offset into the byte array where the data starts. + * @param len the length of the data. + */ + void BlockUpdate(byte[] input, int inOff, int length); + + /** + * Close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * + * @param output the array the digest is to be copied into. + * @param outOff the offset into the out array the digest is to start at. + */ + int DoFinal(byte[] output, int outOff); + + /** + * reset the digest back to it's initial state. + */ + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/IMac.cs b/iTechSharp/srcbc/crypto/IMac.cs new file mode 100644 index 0000000..03a86e8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IMac.cs @@ -0,0 +1,69 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * The base interface for implementations of message authentication codes (MACs). + */ + public interface IMac + { + /** + * Initialise the MAC. + * + * @param param the key and other data required by the MAC. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + void Init(ICipherParameters parameters); + + /** + * Return the name of the algorithm the MAC implements. + * + * @return the name of the algorithm the MAC implements. + */ + string AlgorithmName { get; } + + /** + * Return the block size for this MAC (in bytes). + * + * @return the block size for this MAC in bytes. + */ + int GetMacSize(); + + /** + * add a single byte to the mac for processing. + * + * @param in the byte to be processed. + * @exception InvalidOperationException if the MAC is not initialised. + */ + void Update(byte input); + + /** + * @param in the array containing the input. + * @param inOff the index in the array the data begins at. + * @param len the length of the input starting at inOff. + * @exception InvalidOperationException if the MAC is not initialised. + * @exception DataLengthException if there isn't enough data in in. + */ + void BlockUpdate(byte[] input, int inOff, int len); + + /** + * Compute the final stage of the MAC writing the output to the out + * parameter. + *

      + * doFinal leaves the MAC in the same state it was after the last init. + *

      + * @param out the array the MAC is to be output to. + * @param outOff the offset into the out buffer the output is to start at. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the MAC is not initialised. + */ + int DoFinal(byte[] output, int outOff); + + /** + * Reset the MAC. At the end of resetting the MAC should be in the + * in the same state it was after the last init (if there was one). + */ + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/ISigner.cs b/iTechSharp/srcbc/crypto/ISigner.cs new file mode 100644 index 0000000..e03bbf4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/ISigner.cs @@ -0,0 +1,50 @@ + +using System; +using System.Text; + +namespace Org.BouncyCastle.Crypto +{ + public interface ISigner + { + /** + * Return the name of the algorithm the signer implements. + * + * @return the name of the algorithm the signer implements. + */ + string AlgorithmName { get; } + + /** + * Initialise the signer for signing or verification. + * + * @param forSigning true if for signing, false otherwise + * @param param necessary parameters. + */ + void Init(bool forSigning, ICipherParameters parameters); + + /** + * update the internal digest with the byte b + */ + void Update(byte input); + + /** + * update the internal digest with the byte array in + */ + void BlockUpdate(byte[] input, int inOff, int length); + + /** + * Generate a signature for the message we've been loaded with using + * the key we were initialised with. + */ + byte[] GenerateSignature(); + /** + * return true if the internal state represents the signature described + * in the passed in array. + */ + bool VerifySignature(byte[] signature); + + /** + * reset the internal state + */ + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/ISignerWithRecovery.cs b/iTechSharp/srcbc/crypto/ISignerWithRecovery.cs new file mode 100644 index 0000000..b78a42a --- /dev/null +++ b/iTechSharp/srcbc/crypto/ISignerWithRecovery.cs @@ -0,0 +1,28 @@ + +using System; +using System.Text; + +namespace Org.BouncyCastle.Crypto +{ + /** + * Signer with message recovery. + */ + public interface ISignerWithRecovery + : ISigner + { + /** + * Returns true if the signer has recovered the full message as + * part of signature verification. + * + * @return true if full message recovered. + */ + bool HasFullMessage(); + + /** + * Returns a reference to what message was recovered (if any). + * + * @return full/partial message, null if nothing. + */ + byte[] GetRecoveredMessage(); + } +} diff --git a/iTechSharp/srcbc/crypto/IStreamCipher.cs b/iTechSharp/srcbc/crypto/IStreamCipher.cs new file mode 100644 index 0000000..8e575a7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IStreamCipher.cs @@ -0,0 +1,45 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// The interface stream ciphers conform to. + public interface IStreamCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// If true the cipher is initialised for encryption, + /// if false for decryption. + /// The key and other data required by the cipher. + /// + /// If the parameters argument is inappropriate. + /// + void Init(bool forEncryption, ICipherParameters parameters); + + /// encrypt/decrypt a single byte returning the result. + /// the byte to be processed. + /// the result of processing the input byte. + byte ReturnByte(byte input); + + /// + /// Process a block of bytes from input putting the result into output. + /// + /// The input byte array. + /// + /// The offset into input where the data to be processed starts. + /// + /// The number of bytes to be processed. + /// The output buffer the processed bytes go into. + /// + /// The offset into output the processed data starts at. + /// + /// If the output buffer is too small. + void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff); + + /// + /// Reset the cipher to the same state as it was after the last init (if there was one). + /// + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/IWrapper.cs b/iTechSharp/srcbc/crypto/IWrapper.cs new file mode 100644 index 0000000..58202b3 --- /dev/null +++ b/iTechSharp/srcbc/crypto/IWrapper.cs @@ -0,0 +1,18 @@ +using System; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto +{ + public interface IWrapper + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + void Init(bool forWrapping, ICipherParameters parameters); + + byte[] Wrap(byte[] input, int inOff, int length); + + byte[] Unwrap(byte[] input, int inOff, int length); + } +} diff --git a/iTechSharp/srcbc/crypto/InvalidCipherTextException.cs b/iTechSharp/srcbc/crypto/InvalidCipherTextException.cs new file mode 100644 index 0000000..598ea27 --- /dev/null +++ b/iTechSharp/srcbc/crypto/InvalidCipherTextException.cs @@ -0,0 +1,37 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /** + * this exception is thrown whenever we find something we don't expect in a + * message. + */ + public class InvalidCipherTextException + : CryptoException + { + /** + * base constructor. + */ + public InvalidCipherTextException() + { + } + + /** + * create a InvalidCipherTextException with the given message. + * + * @param message the message to be carried with the exception. + */ + public InvalidCipherTextException( + string message) + : base(message) + { + } + + public InvalidCipherTextException( + string message, + Exception exception) + : base(message, exception) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/KeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/KeyGenerationParameters.cs new file mode 100644 index 0000000..0cb6b07 --- /dev/null +++ b/iTechSharp/srcbc/crypto/KeyGenerationParameters.cs @@ -0,0 +1,55 @@ +using System; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto +{ + /** + * The base class for parameters to key generators. + */ + public class KeyGenerationParameters + { + private SecureRandom random; + private int strength; + + /** + * initialise the generator with a source of randomness + * and a strength (in bits). + * + * @param random the random byte source. + * @param strength the size, in bits, of the keys we want to produce. + */ + public KeyGenerationParameters( + SecureRandom random, + int strength) + { + if (random == null) + throw new ArgumentNullException("random"); + if (strength < 1) + throw new ArgumentException("strength must be a positive value", "strength"); + + this.random = random; + this.strength = strength; + } + + /** + * return the random source associated with this + * generator. + * + * @return the generators random source. + */ + public SecureRandom Random + { + get { return random; } + } + + /** + * return the bit strength for keys produced by this generator, + * + * @return the strength of the keys this generator produces (in bits). + */ + public int Strength + { + get { return strength; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/MaxBytesExceededException.cs b/iTechSharp/srcbc/crypto/MaxBytesExceededException.cs new file mode 100644 index 0000000..9fa28ab --- /dev/null +++ b/iTechSharp/srcbc/crypto/MaxBytesExceededException.cs @@ -0,0 +1,29 @@ +using System; + +namespace Org.BouncyCastle.Crypto +{ + /// + /// This exception is thrown whenever a cipher requires a change of key, iv + /// or similar after x amount of bytes enciphered + /// + public class MaxBytesExceededException + : CryptoException + { + public MaxBytesExceededException() + { + } + + public MaxBytesExceededException( + string message) + : base(message) + { + } + + public MaxBytesExceededException( + string message, + Exception e) + : base(message, e) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/PbeParametersGenerator.cs b/iTechSharp/srcbc/crypto/PbeParametersGenerator.cs new file mode 100644 index 0000000..c198af6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/PbeParametersGenerator.cs @@ -0,0 +1,169 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto +{ + /** + * super class for all Password Based Encyrption (Pbe) parameter generator classes. + */ + public abstract class PbeParametersGenerator + { + protected byte[] mPassword; + protected byte[] mSalt; + protected int mIterationCount; + + /** + * base constructor. + */ + protected PbeParametersGenerator() + { + } + + /** + * initialise the Pbe generator. + * + * @param password the password converted into bytes (see below). + * @param salt the salt to be mixed with the password. + * @param iterationCount the number of iterations the "mixing" function + * is to be applied for. + */ + public virtual void Init( + byte[] password, + byte[] salt, + int iterationCount) + { + if (password == null) + throw new ArgumentNullException("password"); + if (salt == null) + throw new ArgumentNullException("salt"); + + this.mPassword = Arrays.Clone(password); + this.mSalt = Arrays.Clone(salt); + this.mIterationCount = iterationCount; + } + + public virtual byte[] Password + { + get { return Arrays.Clone(mPassword); } + } + + /** + * return the password byte array. + * + * @return the password byte array. + */ + [Obsolete("Use 'Password' property")] + public byte[] GetPassword() + { + return Password; + } + + public virtual byte[] Salt + { + get { return Arrays.Clone(mSalt); } + } + + /** + * return the salt byte array. + * + * @return the salt byte array. + */ + [Obsolete("Use 'Salt' property")] + public byte[] GetSalt() + { + return Salt; + } + + /** + * return the iteration count. + * + * @return the iteration count. + */ + public virtual int IterationCount + { + get { return mIterationCount; } + } + + /** + * Generate derived parameters for a key of length keySize. + * + * @param keySize the length, in bits, of the key required. + * @return a parameters object representing a key. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public abstract ICipherParameters GenerateDerivedParameters(int keySize); + public abstract ICipherParameters GenerateDerivedParameters(string algorithm, int keySize); + + /** + * Generate derived parameters for a key of length keySize, and + * an initialisation vector (IV) of length ivSize. + * + * @param keySize the length, in bits, of the key required. + * @param ivSize the length, in bits, of the iv required. + * @return a parameters object representing a key and an IV. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public abstract ICipherParameters GenerateDerivedParameters(int keySize, int ivSize); + public abstract ICipherParameters GenerateDerivedParameters(string algorithm, int keySize, int ivSize); + + /** + * Generate derived parameters for a key of length keySize, specifically + * for use with a MAC. + * + * @param keySize the length, in bits, of the key required. + * @return a parameters object representing a key. + */ + public abstract ICipherParameters GenerateDerivedMacParameters(int keySize); + + /** + * converts a password to a byte array according to the scheme in + * Pkcs5 (ascii, no padding) + * + * @param password a character array reqpresenting the password. + * @return a byte array representing the password. + */ + public static byte[] Pkcs5PasswordToBytes( + char[] password) + { + return Encoding.ASCII.GetBytes(password); + } + + public static byte[] Pkcs5PasswordToBytes( + string password) + { + return Encoding.ASCII.GetBytes(password); + } + + /** + * converts a password to a byte array according to the scheme in + * Pkcs12 (unicode, big endian, 2 zero pad bytes at the end). + * + * @param password a character array representing the password. + * @return a byte array representing the password. + */ + public static byte[] Pkcs12PasswordToBytes( + char[] password) + { + return Pkcs12PasswordToBytes(password, false); + } + + public static byte[] Pkcs12PasswordToBytes( + char[] password, + bool wrongPkcs12Zero) + { + if (password.Length < 1) + { + return new byte[wrongPkcs12Zero ? 2 : 0]; + } + + // +1 for extra 2 pad bytes. + byte[] bytes = new byte[(password.Length + 1) * 2]; + + Encoding.BigEndianUnicode.GetBytes(password, 0, password.Length, bytes, 0); + + return bytes; + } + } +} diff --git a/iTechSharp/srcbc/crypto/StreamBlockCipher.cs b/iTechSharp/srcbc/crypto/StreamBlockCipher.cs new file mode 100644 index 0000000..ef2a8b6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/StreamBlockCipher.cs @@ -0,0 +1,109 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto +{ + /** + * a wrapper for block ciphers with a single byte block size, so that they + * can be treated like stream ciphers. + */ + public class StreamBlockCipher + : IStreamCipher + { + private readonly IBlockCipher cipher; + private readonly byte[] oneByte = new byte[1]; + + /** + * basic constructor. + * + * @param cipher the block cipher to be wrapped. + * @exception ArgumentException if the cipher has a block size other than + * one. + */ + public StreamBlockCipher( + IBlockCipher cipher) + { + if (cipher == null) + throw new ArgumentNullException("cipher"); + if (cipher.GetBlockSize() != 1) + throw new ArgumentException("block cipher block size != 1.", "cipher"); + + this.cipher = cipher; + } + + /** + * initialise the underlying cipher. + * + * @param forEncryption true if we are setting up for encryption, false otherwise. + * @param param the necessary parameters for the underlying cipher to be initialised. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + cipher.Init(forEncryption, parameters); + } + + /** + * return the name of the algorithm we are wrapping. + * + * @return the name of the algorithm we are wrapping. + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + /** + * encrypt/decrypt a single byte returning the result. + * + * @param in the byte to be processed. + * @return the result of processing the input byte. + */ + public byte ReturnByte( + byte input) + { + oneByte[0] = input; + + cipher.ProcessBlock(oneByte, 0, oneByte, 0); + + return oneByte[0]; + } + + /** + * process a block of bytes from in putting the result into out. + * + * @param in the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + * @param out the output buffer the processed bytes go into. + * @param outOff the offset into the output byte array the processed data stars at. + * @exception DataLengthException if the output buffer is too small. + */ + public void ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (outOff + length > output.Length) + throw new DataLengthException("output buffer too small in ProcessBytes()"); + + for (int i = 0; i != length; i++) + { + cipher.ProcessBlock(input, inOff + i, output, outOff + i); + } + } + + /** + * reset the underlying cipher. This leaves it in the same state + * it was at after the last init (if there was one). + */ + public void Reset() + { + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/agreement/DHAgreement.cs b/iTechSharp/srcbc/crypto/agreement/DHAgreement.cs new file mode 100644 index 0000000..0519ce3 --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/DHAgreement.cs @@ -0,0 +1,89 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + /** + * a Diffie-Hellman key exchange engine. + *

      + * note: This uses MTI/A0 key agreement in order to make the key agreement + * secure against passive attacks. If you're doing Diffie-Hellman and both + * parties have long term public keys you should look at using this. For + * further information have a look at RFC 2631.

      + *

      + * It's possible to extend this to more than two parties as well, for the moment + * that is left as an exercise for the reader.

      + */ + public class DHAgreement + { + private DHPrivateKeyParameters key; + private DHParameters dhParams; + private BigInteger privateValue; + private SecureRandom random; + + public void Init( + ICipherParameters parameters) + { + AsymmetricKeyParameter kParam; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + + this.random = rParam.Random; + kParam = (AsymmetricKeyParameter)rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + kParam = (AsymmetricKeyParameter)parameters; + } + + if (!(kParam is DHPrivateKeyParameters)) + { + throw new ArgumentException("DHEngine expects DHPrivateKeyParameters"); + } + + this.key = (DHPrivateKeyParameters)kParam; + this.dhParams = key.Parameters; + } + + /** + * calculate our initial message. + */ + public BigInteger CalculateMessage() + { + int bits = dhParams.P.BitLength - 1; + + // TODO Should the generated numbers always have length 'P.BitLength - 1'? + this.privateValue = new BigInteger(bits, random).SetBit(bits - 1); + + return dhParams.G.ModPow(privateValue, dhParams.P); + } + + /** + * given a message from a given party and the corresponding public key + * calculate the next message in the agreement sequence. In this case + * this will represent the shared secret. + */ + public BigInteger CalculateAgreement( + DHPublicKeyParameters pub, + BigInteger message) + { + if (pub == null) + throw new ArgumentNullException("pub"); + if (message == null) + throw new ArgumentNullException("message"); + + if (!pub.Parameters.Equals(dhParams)) + { + throw new ArgumentException("Diffie-Hellman public key has wrong parameters."); + } + + return message.ModPow(key.X, dhParams.P).Multiply(pub.Y.ModPow(privateValue, dhParams.P)).Mod(dhParams.P); + } + } +} diff --git a/iTechSharp/srcbc/crypto/agreement/DHBasicAgreement.cs b/iTechSharp/srcbc/crypto/agreement/DHBasicAgreement.cs new file mode 100644 index 0000000..5a52770 --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/DHBasicAgreement.cs @@ -0,0 +1,60 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + /** + * a Diffie-Hellman key agreement class. + *

      + * note: This is only the basic algorithm, it doesn't take advantage of + * long term public keys if they are available. See the DHAgreement class + * for a "better" implementation.

      + */ + public class DHBasicAgreement + : IBasicAgreement + { + private DHPrivateKeyParameters key; + private DHParameters dhParams; + + public void Init( + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + if (!(parameters is DHPrivateKeyParameters)) + { + throw new ArgumentException("DHEngine expects DHPrivateKeyParameters"); + } + + this.key = (DHPrivateKeyParameters) parameters; + this.dhParams = key.Parameters; + } + + /** + * given a short term public key from a given party calculate the next + * message in the agreement sequence. + */ + public BigInteger CalculateAgreement( + ICipherParameters pubKey) + { + if (this.key == null) + throw new InvalidOperationException("Agreement algorithm not initialised"); + + DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey; + + if (!pub.Parameters.Equals(dhParams)) + { + throw new ArgumentException("Diffie-Hellman public key has wrong parameters."); + } + + return pub.Y.ModPow(key.X, dhParams.P); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/agreement/ECDHBasicAgreement.cs b/iTechSharp/srcbc/crypto/agreement/ECDHBasicAgreement.cs new file mode 100644 index 0000000..0870f8e --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/ECDHBasicAgreement.cs @@ -0,0 +1,50 @@ +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + /** + * P1363 7.2.1 ECSVDP-DH + * + * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive, + * Diffie-Hellman version. It is based on the work of [DH76], [Mil86], + * and [Kob87]. This primitive derives a shared secret value from one + * party's private key and another party's public key, where both have + * the same set of EC domain parameters. If two parties correctly + * execute this primitive, they will produce the same output. This + * primitive can be invoked by a scheme to derive a shared secret key; + * specifically, it may be used with the schemes ECKAS-DH1 and + * DL/ECKAS-DH2. It assumes that the input keys are valid (see also + * Section 7.2.2). + */ + public class ECDHBasicAgreement + : IBasicAgreement + { + private ECPrivateKeyParameters key; + + public void Init( + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + this.key = (ECPrivateKeyParameters) parameters; + } + + public virtual BigInteger CalculateAgreement( + ICipherParameters pubKey) + { + ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey; + ECPoint P = pub.Q.Multiply(key.D); + + // if ( p.IsInfinity ) throw new Exception("d*Q == infinity"); + + return P.X.ToBigInteger(); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/agreement/ECDHCBasicAgreement.cs b/iTechSharp/srcbc/crypto/agreement/ECDHCBasicAgreement.cs new file mode 100644 index 0000000..905d241 --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/ECDHCBasicAgreement.cs @@ -0,0 +1,58 @@ +using System; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + /** + * P1363 7.2.2 ECSVDP-DHC + * + * ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive, + * Diffie-Hellman version with cofactor multiplication. It is based on + * the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This + * primitive derives a shared secret value from one party's private key + * and another party's public key, where both have the same set of EC + * domain parameters. If two parties correctly execute this primitive, + * they will produce the same output. This primitive can be invoked by a + * scheme to derive a shared secret key; specifically, it may be used + * with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the + * validity of the input public key (see also Section 7.2.1). + *

      + * Note: As stated P1363 compatibility mode with ECDH can be preset, and + * in this case the implementation doesn't have a ECDH compatibility mode + * (if you want that just use ECDHBasicAgreement and note they both implement + * BasicAgreement!).

      + */ + public class ECDHCBasicAgreement + : IBasicAgreement + { + private ECPrivateKeyParameters key; + + public void Init( + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + this.key = (ECPrivateKeyParameters)parameters; + } + + public BigInteger CalculateAgreement( + ICipherParameters pubKey) + { + ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey; + ECDomainParameters parameters = pub.Parameters; + ECPoint P = pub.Q.Multiply(parameters.H.Multiply(key.D)); + + // if ( p.IsInfinity ) throw new Exception("Invalid public key"); + + return P.X.ToBigInteger(); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/iTechSharp/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs new file mode 100644 index 0000000..9c66e95 --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto.Agreement.Kdf; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + public class ECDHWithKdfBasicAgreement + : ECDHBasicAgreement + { + private static readonly Hashtable algorithms = new Hashtable(); + + static ECDHWithKdfBasicAgreement() + { + algorithms.Add(NistObjectIdentifiers.IdAes128Cbc.Id, 128); + algorithms.Add(NistObjectIdentifiers.IdAes192Cbc.Id, 192); + algorithms.Add(NistObjectIdentifiers.IdAes256Cbc.Id, 256); + algorithms.Add(NistObjectIdentifiers.IdAes128Wrap.Id, 128); + algorithms.Add(NistObjectIdentifiers.IdAes192Wrap.Id, 192); + algorithms.Add(NistObjectIdentifiers.IdAes256Wrap.Id, 256); + algorithms.Add(PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id, 192); + } + + private readonly string algorithm; + private readonly IDerivationFunction kdf; + + public ECDHWithKdfBasicAgreement( + string algorithm, + IDerivationFunction kdf) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + if (!algorithms.Contains(algorithm)) + throw new ArgumentException("Unknown algorithm", "algorithm"); + if (kdf == null) + throw new ArgumentNullException("kdf"); + + this.algorithm = algorithm; + this.kdf = kdf; + } + + public override BigInteger CalculateAgreement( + ICipherParameters pubKey) + { + BigInteger result = base.CalculateAgreement(pubKey); + + int keySize = (int) algorithms[algorithm]; + + DHKdfParameters dhKdfParams = new DHKdfParameters( + new DerObjectIdentifier(algorithm), + keySize, + // TODO Fix the way bytes are derived from the secret + result.ToByteArrayUnsigned()); + + kdf.Init(dhKdfParams); + + byte[] keyBytes = new byte[keySize / 8]; + kdf.GenerateBytes(keyBytes, 0, keyBytes.Length); + + return new BigInteger(1, keyBytes); + } + } +} diff --git a/iTechSharp/srcbc/crypto/agreement/kdf/DHKdfParameters.cs b/iTechSharp/srcbc/crypto/agreement/kdf/DHKdfParameters.cs new file mode 100644 index 0000000..f6c9e60 --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/kdf/DHKdfParameters.cs @@ -0,0 +1,57 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Crypto.Agreement.Kdf +{ + public class DHKdfParameters + : IDerivationParameters + { + private readonly DerObjectIdentifier algorithm; + private readonly int keySize; + private readonly byte[] z; + private readonly byte[] extraInfo; + + public DHKdfParameters( + DerObjectIdentifier algorithm, + int keySize, + byte[] z) + : this(algorithm, keySize, z, null) + { + } + + public DHKdfParameters( + DerObjectIdentifier algorithm, + int keySize, + byte[] z, + byte[] extraInfo) + { + this.algorithm = algorithm; + this.keySize = keySize; + this.z = z; // TODO Clone? + this.extraInfo = extraInfo; + } + + public DerObjectIdentifier Algorithm + { + get { return algorithm; } + } + + public int KeySize + { + get { return keySize; } + } + + public byte[] GetZ() + { + // TODO Clone? + return z; + } + + public byte[] GetExtraInfo() + { + // TODO Clone? + return extraInfo; + } + } +} diff --git a/iTechSharp/srcbc/crypto/agreement/kdf/DHKekGenerator.cs b/iTechSharp/srcbc/crypto/agreement/kdf/DHKekGenerator.cs new file mode 100644 index 0000000..fa29215 --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/kdf/DHKekGenerator.cs @@ -0,0 +1,129 @@ +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Crypto.Agreement.Kdf +{ + /** + * RFC 2631 Diffie-hellman KEK derivation function. + */ + public class DHKekGenerator + : IDerivationFunction + { + private readonly IDigest digest; + + private DerObjectIdentifier algorithm; + private int keySize; + private byte[] z; + private byte[] partyAInfo; + + public DHKekGenerator( + IDigest digest) + { + this.digest = digest; + } + + public void Init( + IDerivationParameters param) + { + DHKdfParameters parameters = (DHKdfParameters)param; + + this.algorithm = parameters.Algorithm; + this.keySize = parameters.KeySize; + this.z = parameters.GetZ(); // TODO Clone? + this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone? + } + + public IDigest Digest + { + get { return digest; } + } + + public int GenerateBytes( + byte[] outBytes, + int outOff, + int len) + { + if ((outBytes.Length - len) < outOff) + { + throw new DataLengthException("output buffer too small"); + } + + long oBytes = len; + int outLen = digest.GetDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + { + throw new ArgumentException("Output length too large"); + } + + int cThreshold = (int)((oBytes + outLen - 1) / outLen); + + byte[] dig = new byte[digest.GetDigestSize()]; + + int counter = 1; + + for (int i = 0; i < cThreshold; i++) + { + digest.BlockUpdate(z, 0, z.Length); + + // KeySpecificInfo + DerSequence keyInfo = new DerSequence( + algorithm, + new DerOctetString(integerToBytes(counter))); + + // OtherInfo + Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo); + + if (partyAInfo != null) + { + v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo))); + } + + v1.Add(new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize)))); + + byte[] other = new DerSequence(v1).GetDerEncoded(); + + digest.BlockUpdate(other, 0, other.Length); + + digest.DoFinal(dig, 0); + + if (len > outLen) + { + Array.Copy(dig, 0, outBytes, outOff, outLen); + outOff += outLen; + len -= outLen; + } + else + { + Array.Copy(dig, 0, outBytes, outOff, len); + } + + counter++; + } + + digest.Reset(); + + return len; + } + + private byte[] integerToBytes( + int keySize) + { + byte[] val = new byte[4]; + + val[0] = (byte)(keySize >> 24); + val[1] = (byte)(keySize >> 16); + val[2] = (byte)(keySize >> 8); + val[3] = (byte)keySize; + + return val; + } + } +} diff --git a/iTechSharp/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs b/iTechSharp/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs new file mode 100644 index 0000000..1fa893e --- /dev/null +++ b/iTechSharp/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs @@ -0,0 +1,70 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Agreement.Kdf +{ + /** + * X9.63 based key derivation function for ECDH CMS. + */ + public class ECDHKekGenerator + : IDerivationFunction + { + private readonly IDerivationFunction kdf; + + private DerObjectIdentifier algorithm; + private int keySize; + private byte[] z; + + public ECDHKekGenerator( + IDigest digest) + { + this.kdf = new Kdf2BytesGenerator(digest); + } + + public void Init( + IDerivationParameters param) + { + DHKdfParameters parameters = (DHKdfParameters)param; + + this.algorithm = parameters.Algorithm; + this.keySize = parameters.KeySize; + this.z = parameters.GetZ(); // TODO Clone? + } + + public IDigest Digest + { + get { return kdf.Digest; } + } + + public int GenerateBytes( + byte[] outBytes, + int outOff, + int len) + { + // ECC-CMS-SharedInfo + DerSequence s = new DerSequence( + new AlgorithmIdentifier(algorithm, DerNull.Instance), + new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize)))); + + kdf.Init(new KdfParameters(z, s.GetDerEncoded())); + + return kdf.GenerateBytes(outBytes, outOff, len); + } + + private byte[] integerToBytes(int keySize) + { + byte[] val = new byte[4]; + + val[0] = (byte)(keySize >> 24); + val[1] = (byte)(keySize >> 16); + val[2] = (byte)(keySize >> 8); + val[3] = (byte)keySize; + + return val; + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/GOST3411Digest.cs b/iTechSharp/srcbc/crypto/digests/GOST3411Digest.cs new file mode 100644 index 0000000..3055733 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/GOST3411Digest.cs @@ -0,0 +1,338 @@ +using System; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * implementation of GOST R 34.11-94 + */ + public class Gost3411Digest + : IDigest + { + private const int DIGEST_LENGTH = 32; + + private byte[] H = new byte[32], L = new byte[32], + M = new byte[32], Sum = new byte[32]; + private byte[][] C = new byte[4][]; + + private byte[] xBuf = new byte[32]; + private int xBufOff; + private long byteCount; + + private readonly IBlockCipher cipher = new Gost28147Engine(); + + /** + * Standard constructor + */ + public Gost3411Digest() + { + // TODO Is it possible to declare multi-dimensional arrays as in Java? + for (int i = 0; i < 4; ++i) + { + C[i] = new byte[32]; + } + + cipher.Init(true, new ParametersWithSBox(null, Gost28147Engine.GetSBox("D-A"))); + + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Gost3411Digest(Gost3411Digest t) + : this() + { +// cipher.Init(true, new ParametersWithSBox(null, Gost28147Engine.GetSBox("D-A"))); +// +// Reset(); + + Array.Copy(t.H, 0, this.H, 0, t.H.Length); + Array.Copy(t.L, 0, this.L, 0, t.L.Length); + Array.Copy(t.M, 0, this.M, 0, t.M.Length); + Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length); + Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length); + Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length); + Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length); + Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length); + + this.xBufOff = t.xBufOff; + this.byteCount = t.byteCount; + } + + public string AlgorithmName + { + get { return "Gost3411"; } + } + + public int GetDigestSize() + { + return DIGEST_LENGTH; + } + + public void Update( + byte input) + { + xBuf[xBufOff++] = input; + if (xBufOff == xBuf.Length) + { + sumByteArray(xBuf); // calc sum M + processBlock(xBuf, 0); + xBufOff = 0; + } + byteCount++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + while ((xBufOff != 0) && (length > 0)) + { + Update(input[inOff]); + inOff++; + length--; + } + + while (length > xBuf.Length) + { + Array.Copy(input, inOff, xBuf, 0, xBuf.Length); + + sumByteArray(xBuf); // calc sum M + processBlock(xBuf, 0); + inOff += xBuf.Length; + length -= xBuf.Length; + byteCount += xBuf.Length; + } + + // load in the remainder. + while (length > 0) + { + Update(input[inOff]); + inOff++; + length--; + } + } + + // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 + private byte[] K = new byte[32]; + + private byte[] P(byte[] input) + { + int fourK = 0; + for(int k = 0; k < 8; k++) + { + K[fourK++] = input[k]; + K[fourK++] = input[8 + k]; + K[fourK++] = input[16 + k]; + K[fourK++] = input[24 + k]; + } + + return K; + } + + //A (x) = (x0 ^ x1) || x3 || x2 || x1 + byte[] a = new byte[8]; + private byte[] A(byte[] input) + { + for(int j=0; j<8; j++) + { + a[j]=(byte)(input[j] ^ input[j+8]); + } + + Array.Copy(input, 8, input, 0, 24); + Array.Copy(a, 0, input, 24, 8); + + return input; + } + + //Encrypt function, ECB mode + private void E(byte[] key, byte[] s, int sOff, byte[] input, int inOff) + { + cipher.Init(true, new KeyParameter(key)); + + cipher.ProcessBlock(input, inOff, s, sOff); + } + + // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 + internal short[] wS = new short[16], w_S = new short[16]; + + private void fw(byte[] input) + { + cpyBytesToShort(input, wS); + w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]); + Array.Copy(wS, 1, w_S, 0, 15); + cpyShortToBytes(w_S, input); + } + + // block processing + internal byte[] S = new byte[32], U = new byte[32], V = new byte[32], W = new byte[32]; + + private void processBlock(byte[] input, int inOff) + { + Array.Copy(input, inOff, M, 0, 32); + + //key step 1 + + // H = h3 || h2 || h1 || h0 + // S = s3 || s2 || s1 || s0 + H.CopyTo(U, 0); + M.CopyTo(V, 0); + for (int j=0; j<32; j++) + { + W[j] = (byte)(U[j]^V[j]); + } + // Encrypt gost28147-ECB + E(P(W), S, 0, H, 0); // s0 = EK0 [h0] + + //keys step 2,3,4 + for (int i=1; i<4; i++) + { + byte[] tmpA = A(U); + for (int j=0; j<32; j++) + { + U[j] = (byte)(tmpA[j] ^ C[i][j]); + } + V = A(A(V)); + for (int j=0; j<32; j++) + { + W[j] = (byte)(U[j]^V[j]); + } + // Encrypt gost28147-ECB + E(P(W), S, i * 8, H, i * 8); // si = EKi [hi] + } + + // x(M, H) = y61(H^y(M^y12(S))) + for(int n = 0; n < 12; n++) + { + fw(S); + } + for(int n = 0; n < 32; n++) + { + S[n] = (byte)(S[n] ^ M[n]); + } + + fw(S); + + for(int n = 0; n < 32; n++) + { + S[n] = (byte)(H[n] ^ S[n]); + } + for(int n = 0; n < 61; n++) + { + fw(S); + } + Array.Copy(S, 0, H, 0, H.Length); + } + + private void finish() + { + LongToBytes(byteCount * 8, L, 0); // get length into L (byteCount * 8 = bitCount) + + while (xBufOff != 0) + { + Update((byte)0); + } + + processBlock(L, 0); + processBlock(Sum, 0); + } + + public int DoFinal( + byte[] output, + int outOff) + { + finish(); + + H.CopyTo(output, outOff); + + Reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables to the IV values. + */ + private static readonly byte[] C2 = { + 0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF, + (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00, + 0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF, + (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF + }; + + public void Reset() + { + byteCount = 0; + xBufOff = 0; + + Array.Clear(H, 0, H.Length); + Array.Clear(L, 0, L.Length); + Array.Clear(M, 0, M.Length); + Array.Clear(C[1], 0, C[1].Length); // real index C = +1 because index array with 0. + Array.Clear(C[3], 0, C[3].Length); + Array.Clear(Sum, 0, Sum.Length); + Array.Clear(xBuf, 0, xBuf.Length); + + C2.CopyTo(C[2], 0); + } + + // 256 bitsblock modul -> (Sum + a mod (2^256)) + private void sumByteArray( + byte[] input) + { + int carry = 0; + + for (int i = 0; i != Sum.Length; i++) + { + int sum = (Sum[i] & 0xff) + (input[i] & 0xff) + carry; + + Sum[i] = (byte)sum; + + carry = sum >> 8; + } + } + + // TODO Refactor as utility function + private static void LongToBytes( + long r, + byte[] output, + int outOff) + { + output[outOff + 7] = (byte)(r >> 56); + output[outOff + 6] = (byte)(r >> 48); + output[outOff + 5] = (byte)(r >> 40); + output[outOff + 4] = (byte)(r >> 32); + output[outOff + 3] = (byte)(r >> 24); + output[outOff + 2] = (byte)(r >> 16); + output[outOff + 1] = (byte)(r >> 8); + output[outOff] = (byte)r; + } + + private static void cpyBytesToShort(byte[] S, short[] wS) + { + for(int i = 0; i < S.Length / 2; i++) + { + wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF)); + } + } + + private static void cpyShortToBytes(short[] wS, byte[] S) + { + for(int i=0; i> 8); + S[i*2] = (byte)wS[i]; + } + } + + public int GetByteLength() + { + return 32; + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/GeneralDigest.cs b/iTechSharp/srcbc/crypto/digests/GeneralDigest.cs new file mode 100644 index 0000000..3e36124 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/GeneralDigest.cs @@ -0,0 +1,118 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * base implementation of MD4 family style digest as outlined in + * "Handbook of Applied Cryptography", pages 344 - 347. + */ + public abstract class GeneralDigest + : IDigest + { + private const int BYTE_LENGTH = 64; + + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + internal GeneralDigest() + { + xBuf = new byte[4]; + } + + internal GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.Length]; + Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void Update(byte input) + { + xBuf[xBufOff++] = input; + + if (xBufOff == xBuf.Length) + { + ProcessWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + // + // fill the current word + // + while ((xBufOff != 0) && (length > 0)) + { + Update(input[inOff]); + inOff++; + length--; + } + + // + // process whole words. + // + while (length > xBuf.Length) + { + ProcessWord(input, inOff); + + inOff += xBuf.Length; + length -= xBuf.Length; + byteCount += xBuf.Length; + } + + // + // load in the remainder. + // + while (length > 0) + { + Update(input[inOff]); + + inOff++; + length--; + } + } + + public void Finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + Update((byte)128); + + while (xBufOff != 0) Update((byte)0); + ProcessLength(bitLength); + ProcessBlock(); + } + + public virtual void Reset() + { + byteCount = 0; + xBufOff = 0; + for ( int i = 0; i < xBuf.Length; i++ ) xBuf[i] = 0; + } + + public int GetByteLength() + { + return BYTE_LENGTH; + } + + internal abstract void ProcessWord(byte[] input, int inOff); + internal abstract void ProcessLength(long bitLength); + internal abstract void ProcessBlock(); + public abstract string AlgorithmName { get; } + public abstract int GetDigestSize(); + public abstract int DoFinal(byte[] output, int outOff); + } +} diff --git a/iTechSharp/srcbc/crypto/digests/LongDigest.cs b/iTechSharp/srcbc/crypto/digests/LongDigest.cs new file mode 100644 index 0000000..24f817a --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/LongDigest.cs @@ -0,0 +1,380 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * Base class for SHA-384 and SHA-512. + */ + public abstract class LongDigest + : IDigest + { + private int MyByteLength = 128; + + private byte[] xBuf; + private int xBufOff; + + private long byteCount1; + private long byteCount2; + + internal long H1, H2, H3, H4, H5, H6, H7, H8; + + private long[] W = new long[80]; + private int wOff; + + /** + * Constructor for variable length word + */ + internal LongDigest() + { + xBuf = new byte[8]; + + Reset(); + } + + /** + * Copy constructor. We are using copy constructors in place + * of the object.Clone() interface as this interface is not + * supported by J2ME. + */ + internal LongDigest( + LongDigest t) + { + xBuf = new byte[t.xBuf.Length]; + Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length); + + xBufOff = t.xBufOff; + byteCount1 = t.byteCount1; + byteCount2 = t.byteCount2; + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + + Array.Copy(t.W, 0, W, 0, t.W.Length); + wOff = t.wOff; + } + + public void Update( + byte input) + { + xBuf[xBufOff++] = input; + + if (xBufOff == xBuf.Length) + { + ProcessWord(xBuf, 0); + xBufOff = 0; + } + + byteCount1++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + // + // fill the current word + // + while ((xBufOff != 0) && (length > 0)) + { + Update(input[inOff]); + + inOff++; + length--; + } + + // + // process whole words. + // + while (length > xBuf.Length) + { + ProcessWord(input, inOff); + + inOff += xBuf.Length; + length -= xBuf.Length; + byteCount1 += xBuf.Length; + } + + // + // load in the remainder. + // + while (length > 0) + { + Update(input[inOff]); + + inOff++; + length--; + } + } + + public void Finish() + { + AdjustByteCounts(); + + long lowBitLength = byteCount1 << 3; + long hiBitLength = byteCount2; + + // + // add the pad bytes. + // + Update((byte)128); + + while (xBufOff != 0) + { + Update((byte)0); + } + + ProcessLength(lowBitLength, hiBitLength); + + ProcessBlock(); + } + + public virtual void Reset() + { + byteCount1 = 0; + byteCount2 = 0; + + xBufOff = 0; + for ( int i = 0; i < xBuf.Length; i++ ) + { + xBuf[i] = 0; + } + + wOff = 0; + for (int i = 0; i != W.Length; i++) + { + W[i] = 0; + } + } + + internal void ProcessWord( + byte[] input, + int inOff) + { + W[wOff++] = ((long)(input[inOff] & 0xff) << 56) + | ((long)(input[inOff + 1] & 0xff) << 48) + | ((long)(input[inOff + 2] & 0xff) << 40) + | ((long)(input[inOff + 3] & 0xff) << 32) + | ((long)(input[inOff + 4] & 0xff) << 24) + | ((long)(input[inOff + 5] & 0xff) << 16) + | ((long)(input[inOff + 6] & 0xff) << 8) + | ((uint)(input[inOff + 7] & 0xff) ); + + if (wOff == 16) + { + ProcessBlock(); + } + } + + internal static void UnpackWord( + long word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)((ulong) word >> 56); + outBytes[outOff + 1] = (byte)((ulong) word >> 48); + outBytes[outOff + 2] = (byte)((ulong) word >> 40); + outBytes[outOff + 3] = (byte)((ulong) word >> 32); + outBytes[outOff + 4] = (byte)((ulong) word >> 24); + outBytes[outOff + 5] = (byte)((ulong) word >> 16); + outBytes[outOff + 6] = (byte)((ulong) word >> 8); + outBytes[outOff + 7] = (byte)word; + } + + /** + * adjust the byte counts so that byteCount2 represents the + * upper long (less 3 bits) word of the byte count. + */ + private void AdjustByteCounts() + { + if (byteCount1 > 0x1fffffffffffffffL) + { + byteCount2 += (long) ((ulong) byteCount1 >> 61); + byteCount1 &= 0x1fffffffffffffffL; + } + } + + internal void ProcessLength( + long lowW, + long hiW) + { + if (wOff > 14) + { + ProcessBlock(); + } + + W[14] = hiW; + W[15] = lowW; + } + + internal void ProcessBlock() + { + AdjustByteCounts(); + + // + // expand 16 word block into 80 word blocks. + // + for (int ti = 16; ti <= 79; ++ti) + { + W[ti] = Sigma1(W[ti - 2]) + W[ti - 7] + Sigma0(W[ti - 15]) + W[ti - 16]; + } + + // + // set up working variables. + // + long a = H1; + long b = H2; + long c = H3; + long d = H4; + long e = H5; + long f = H6; + long g = H7; + long h = H8; + + int t = 0; + for(int i = 0; i < 10; i ++) + { + // t = 8 * i + h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++]; + d += h; + h += Sum0(a) + Maj(a, b, c); + + // t = 8 * i + 1 + g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++]; + c += g; + g += Sum0(h) + Maj(h, a, b); + + // t = 8 * i + 2 + f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++]; + b += f; + f += Sum0(g) + Maj(g, h, a); + + // t = 8 * i + 3 + e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++]; + a += e; + e += Sum0(f) + Maj(f, g, h); + + // t = 8 * i + 4 + d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++]; + h += d; + d += Sum0(e) + Maj(e, f, g); + + // t = 8 * i + 5 + c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++]; + g += c; + c += Sum0(d) + Maj(d, e, f); + + // t = 8 * i + 6 + b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++]; + f += b; + b += Sum0(c) + Maj(c, d, e); + + // t = 8 * i + 7 + a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++]; + e += a; + a += Sum0(b) + Maj(b, c, d); + } + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + H5 += e; + H6 += f; + H7 += g; + H8 += h; + + // + // reset the offset and clean out the word buffer. + // + wOff = 0; + + Array.Clear(W, 0, 16); + } + + /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */ + private static long Ch( + long x, + long y, + long z) + { + return ((x & y) ^ ((~x) & z)); + } + + private static long Maj( + long x, + long y, + long z) + { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + private static long Sum0( + long x) + { + return ((x << 36)|((long)((ulong)x >> 28))) ^ ((x << 30)|((long)((ulong)x >> 34))) ^ ((x << 25)|((long)((ulong)x >> 39))); + } + + private static long Sum1( + long x) + { + return ((x << 50)|((long)((ulong)x >> 14))) ^ ((x << 46)|((long)((ulong)x >> 18))) ^ ((x << 23)|((long)((ulong)x >> 41))); + } + + private static long Sigma0( + long x) + { + return ((x << 63)|((long)((ulong)x >> 1))) ^ ((x << 56)|((long)((ulong)x >> 8))) ^ ((long)((ulong)x >> 7)); + } + + private static long Sigma1( + long x) + { + return ((x << 45)|((long)((ulong)x >> 19))) ^ ((x << 3)|((long)((ulong)x >> 61))) ^ ((long)((ulong)x >> 6)); + } + + /* SHA-384 and SHA-512 Constants + * (represent the first 64 bits of the fractional parts of the + * cube roots of the first sixty-four prime numbers) + */ + internal static readonly long[] K = + { + unchecked((long) 0x428a2f98d728ae22L), unchecked((long) 0x7137449123ef65cdL), unchecked((long) 0xb5c0fbcfec4d3b2fL), unchecked((long) 0xe9b5dba58189dbbcL), + unchecked((long) 0x3956c25bf348b538L), unchecked((long) 0x59f111f1b605d019L), unchecked((long) 0x923f82a4af194f9bL), unchecked((long) 0xab1c5ed5da6d8118L), + unchecked((long) 0xd807aa98a3030242L), unchecked((long) 0x12835b0145706fbeL), unchecked((long) 0x243185be4ee4b28cL), unchecked((long) 0x550c7dc3d5ffb4e2L), + unchecked((long) 0x72be5d74f27b896fL), unchecked((long) 0x80deb1fe3b1696b1L), unchecked((long) 0x9bdc06a725c71235L), unchecked((long) 0xc19bf174cf692694L), + unchecked((long) 0xe49b69c19ef14ad2L), unchecked((long) 0xefbe4786384f25e3L), unchecked((long) 0x0fc19dc68b8cd5b5L), unchecked((long) 0x240ca1cc77ac9c65L), + unchecked((long) 0x2de92c6f592b0275L), unchecked((long) 0x4a7484aa6ea6e483L), unchecked((long) 0x5cb0a9dcbd41fbd4L), unchecked((long) 0x76f988da831153b5L), + unchecked((long) 0x983e5152ee66dfabL), unchecked((long) 0xa831c66d2db43210L), unchecked((long) 0xb00327c898fb213fL), unchecked((long) 0xbf597fc7beef0ee4L), + unchecked((long) 0xc6e00bf33da88fc2L), unchecked((long) 0xd5a79147930aa725L), unchecked((long) 0x06ca6351e003826fL), unchecked((long) 0x142929670a0e6e70L), + unchecked((long) 0x27b70a8546d22ffcL), unchecked((long) 0x2e1b21385c26c926L), unchecked((long) 0x4d2c6dfc5ac42aedL), unchecked((long) 0x53380d139d95b3dfL), + unchecked((long) 0x650a73548baf63deL), unchecked((long) 0x766a0abb3c77b2a8L), unchecked((long) 0x81c2c92e47edaee6L), unchecked((long) 0x92722c851482353bL), + unchecked((long) 0xa2bfe8a14cf10364L), unchecked((long) 0xa81a664bbc423001L), unchecked((long) 0xc24b8b70d0f89791L), unchecked((long) 0xc76c51a30654be30L), + unchecked((long) 0xd192e819d6ef5218L), unchecked((long) 0xd69906245565a910L), unchecked((long) 0xf40e35855771202aL), unchecked((long) 0x106aa07032bbd1b8L), + unchecked((long) 0x19a4c116b8d2d0c8L), unchecked((long) 0x1e376c085141ab53L), unchecked((long) 0x2748774cdf8eeb99L), unchecked((long) 0x34b0bcb5e19b48a8L), + unchecked((long) 0x391c0cb3c5c95a63L), unchecked((long) 0x4ed8aa4ae3418acbL), unchecked((long) 0x5b9cca4f7763e373L), unchecked((long) 0x682e6ff3d6b2b8a3L), + unchecked((long) 0x748f82ee5defb2fcL), unchecked((long) 0x78a5636f43172f60L), unchecked((long) 0x84c87814a1f0ab72L), unchecked((long) 0x8cc702081a6439ecL), + unchecked((long) 0x90befffa23631e28L), unchecked((long) 0xa4506cebde82bde9L), unchecked((long) 0xbef9a3f7b2c67915L), unchecked((long) 0xc67178f2e372532bL), + unchecked((long) 0xca273eceea26619cL), unchecked((long) 0xd186b8c721c0c207L), unchecked((long) 0xeada7dd6cde0eb1eL), unchecked((long) 0xf57d4f7fee6ed178L), + unchecked((long) 0x06f067aa72176fbaL), unchecked((long) 0x0a637dc5a2c898a6L), unchecked((long) 0x113f9804bef90daeL), unchecked((long) 0x1b710b35131c471bL), + unchecked((long) 0x28db77f523047d84L), unchecked((long) 0x32caab7b40c72493L), unchecked((long) 0x3c9ebe0a15c9bebcL), unchecked((long) 0x431d67c49c100d4cL), + unchecked((long) 0x4cc5d4becb3e42b6L), unchecked((long) 0x597f299cfc657e2aL), unchecked((long) 0x5fcb6fab3ad6faecL), unchecked((long) 0x6c44198c4a475817L) + }; + + public int GetByteLength() + { + return MyByteLength; + } + + public abstract string AlgorithmName { get; } + public abstract int GetDigestSize(); + public abstract int DoFinal(byte[] output, int outOff); + } +} diff --git a/iTechSharp/srcbc/crypto/digests/MD2Digest.cs b/iTechSharp/srcbc/crypto/digests/MD2Digest.cs new file mode 100644 index 0000000..78c696f --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/MD2Digest.cs @@ -0,0 +1,247 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Digests +{ + + /** + * implementation of MD2 + * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992 + */ + public class MD2Digest + : IDigest + { + private const int DigestLength = 16; + private const int BYTE_LENGTH = 16; + + /* X buffer */ + private byte[] X = new byte[48]; + private int xOff; + + /* M buffer */ + + private byte[] M = new byte[16]; + private int mOff; + + /* check sum */ + + private byte[] C = new byte[16]; + private int COff; + + public MD2Digest() + { + Reset(); + } + public MD2Digest(MD2Digest t) + { + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + Array.Copy(t.M, 0, M, 0, t.M.Length); + mOff = t.mOff; + Array.Copy(t.C, 0, C, 0, t.C.Length); + COff = t.COff; + } + /** + * return the algorithm name + * + * @return the algorithm name + */ + public string AlgorithmName + { + get { return "MD2"; } + } + + public int GetDigestSize() + { + return DigestLength; + } + + public int GetByteLength() + { + return BYTE_LENGTH; + } + + /** + * Close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * + * @param out the array the digest is to be copied into. + * @param outOff the offset into the out array the digest is to start at. + */ + public int DoFinal(byte[] output, int outOff) + { + // add padding + byte paddingByte = (byte)(M.Length - mOff); + for (int i=mOff;i 0)) + { + Update(input[inOff]); + inOff++; + length--; + } + + // + // process whole words. + // + while (length > 16) + { + Array.Copy(input,inOff,M,0,16); + ProcessChecksum(M); + ProcessBlock(M); + length -= 16; + inOff += 16; + } + + // + // load in the remainder. + // + while (length > 0) + { + Update(input[inOff]); + inOff++; + length--; + } + } + + internal void ProcessChecksum(byte[] m) + { + int L = C[15]; + for (int i=0;i<16;i++) + { + C[i] ^= S[(m[i] ^ L) & 0xff]; + L = C[i]; + } + } + internal void ProcessBlock(byte[] m) + { + for (int i=0;i<16;i++) + { + X[i+16] = m[i]; + X[i+32] = (byte)(m[i] ^ X[i]); + } + // encrypt block + int t = 0; + + for (int j=0;j<18;j++) + { + for (int k=0;k<48;k++) + { + t = X[k] ^= S[t]; + t = t & 0xff; + } + t = (t + j)%256; + } + } + + + + // 256-byte random permutation constructed from the digits of PI + private static readonly byte[] S = { + (byte)41,(byte)46,(byte)67,(byte)201,(byte)162,(byte)216,(byte)124, + (byte)1,(byte)61,(byte)54,(byte)84,(byte)161,(byte)236,(byte)240, + (byte)6,(byte)19,(byte)98,(byte)167,(byte)5,(byte)243,(byte)192, + (byte)199,(byte)115,(byte)140,(byte)152,(byte)147,(byte)43,(byte)217, + (byte)188,(byte)76,(byte)130,(byte)202,(byte)30,(byte)155,(byte)87, + (byte)60,(byte)253,(byte)212,(byte)224,(byte)22,(byte)103,(byte)66, + (byte)111,(byte)24,(byte)138,(byte)23,(byte)229,(byte)18,(byte)190, + (byte)78,(byte)196,(byte)214,(byte)218,(byte)158,(byte)222,(byte)73, + (byte)160,(byte)251,(byte)245,(byte)142,(byte)187,(byte)47,(byte)238, + (byte)122,(byte)169,(byte)104,(byte)121,(byte)145,(byte)21,(byte)178, + (byte)7,(byte)63,(byte)148,(byte)194,(byte)16,(byte)137,(byte)11, + (byte)34,(byte)95,(byte)33,(byte)128,(byte)127,(byte)93,(byte)154, + (byte)90,(byte)144,(byte)50,(byte)39,(byte)53,(byte)62,(byte)204, + (byte)231,(byte)191,(byte)247,(byte)151,(byte)3,(byte)255,(byte)25, + (byte)48,(byte)179,(byte)72,(byte)165,(byte)181,(byte)209,(byte)215, + (byte)94,(byte)146,(byte)42,(byte)172,(byte)86,(byte)170,(byte)198, + (byte)79,(byte)184,(byte)56,(byte)210,(byte)150,(byte)164,(byte)125, + (byte)182,(byte)118,(byte)252,(byte)107,(byte)226,(byte)156,(byte)116, + (byte)4,(byte)241,(byte)69,(byte)157,(byte)112,(byte)89,(byte)100, + (byte)113,(byte)135,(byte)32,(byte)134,(byte)91,(byte)207,(byte)101, + (byte)230,(byte)45,(byte)168,(byte)2,(byte)27,(byte)96,(byte)37, + (byte)173,(byte)174,(byte)176,(byte)185,(byte)246,(byte)28,(byte)70, + (byte)97,(byte)105,(byte)52,(byte)64,(byte)126,(byte)15,(byte)85, + (byte)71,(byte)163,(byte)35,(byte)221,(byte)81,(byte)175,(byte)58, + (byte)195,(byte)92,(byte)249,(byte)206,(byte)186,(byte)197,(byte)234, + (byte)38,(byte)44,(byte)83,(byte)13,(byte)110,(byte)133,(byte)40, + (byte)132, 9,(byte)211,(byte)223,(byte)205,(byte)244,(byte)65, + (byte)129,(byte)77,(byte)82,(byte)106,(byte)220,(byte)55,(byte)200, + (byte)108,(byte)193,(byte)171,(byte)250,(byte)36,(byte)225,(byte)123, + (byte)8,(byte)12,(byte)189,(byte)177,(byte)74,(byte)120,(byte)136, + (byte)149,(byte)139,(byte)227,(byte)99,(byte)232,(byte)109,(byte)233, + (byte)203,(byte)213,(byte)254,(byte)59,(byte)0,(byte)29,(byte)57, + (byte)242,(byte)239,(byte)183,(byte)14,(byte)102,(byte)88,(byte)208, + (byte)228,(byte)166,(byte)119,(byte)114,(byte)248,(byte)235,(byte)117, + (byte)75,(byte)10,(byte)49,(byte)68,(byte)80,(byte)180,(byte)143, + (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51, + (byte)159,(byte)17,(byte)131,(byte)20 + }; + } + +} diff --git a/iTechSharp/srcbc/crypto/digests/MD4Digest.cs b/iTechSharp/srcbc/crypto/digests/MD4Digest.cs new file mode 100644 index 0000000..bc4eae0 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/MD4Digest.cs @@ -0,0 +1,271 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for + * Computer Science and RSA Data Security, Inc. + *

      + * NOTE: This algorithm is only included for backwards compatibility + * with legacy applications, it's not secure, don't use it for anything new!

      + */ + public class MD4Digest + : GeneralDigest + { + private const int DigestLength = 16; + + private int H1, H2, H3, H4; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public MD4Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public MD4Digest(MD4Digest t) : base(t) + { + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "MD4"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)((ulong) bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)word; + outBytes[outOff + 1] = (byte)((uint) word >> 8); + outBytes[outOff + 2] = (byte)((uint) word >> 16); + outBytes[outOff + 3] = (byte)((uint) word >> 24); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 4); + UnpackWord(H3, output, outOff + 8); + UnpackWord(H4, output, outOff + 12); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables to the IV values. + */ + public override void Reset() + { + base.Reset(); + + H1 = unchecked((int) 0x67452301); + H2 = unchecked((int) 0xefcdab89); + H3 = unchecked((int) 0x98badcfe); + H4 = unchecked((int) 0x10325476); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + // + // round 1 left rotates + // + private const int S11 = 3; + private const int S12 = 7; + private const int S13 = 11; + private const int S14 = 19; + + // + // round 2 left rotates + // + private const int S21 = 3; + private const int S22 = 5; + private const int S23 = 9; + private const int S24 = 13; + + // + // round 3 left rotates + // + private const int S31 = 3; + private const int S32 = 9; + private const int S33 = 11; + private const int S34 = 15; + + /* + * rotate int x left n bits. + */ + private int RotateLeft( + int x, + int n) + { + return (x << n) | (int) ((uint) x >> (32 - n)); + } + + /* + * F, G, H and I are the basic MD4 functions. + */ + private int F( + int u, + int v, + int w) + { + return (u & v) | (~u & w); + } + + private int G( + int u, + int v, + int w) + { + return (u & v) | (u & w) | (v & w); + } + + private int H( + int u, + int v, + int w) + { + return u ^ v ^ w; + } + + internal override void ProcessBlock() + { + int a = H1; + int b = H2; + int c = H3; + int d = H4; + + // + // Round 1 - F cycle, 16 times. + // + a = RotateLeft((a + F(b, c, d) + X[ 0]), S11); + d = RotateLeft((d + F(a, b, c) + X[ 1]), S12); + c = RotateLeft((c + F(d, a, b) + X[ 2]), S13); + b = RotateLeft((b + F(c, d, a) + X[ 3]), S14); + a = RotateLeft((a + F(b, c, d) + X[ 4]), S11); + d = RotateLeft((d + F(a, b, c) + X[ 5]), S12); + c = RotateLeft((c + F(d, a, b) + X[ 6]), S13); + b = RotateLeft((b + F(c, d, a) + X[ 7]), S14); + a = RotateLeft((a + F(b, c, d) + X[ 8]), S11); + d = RotateLeft((d + F(a, b, c) + X[ 9]), S12); + c = RotateLeft((c + F(d, a, b) + X[10]), S13); + b = RotateLeft((b + F(c, d, a) + X[11]), S14); + a = RotateLeft((a + F(b, c, d) + X[12]), S11); + d = RotateLeft((d + F(a, b, c) + X[13]), S12); + c = RotateLeft((c + F(d, a, b) + X[14]), S13); + b = RotateLeft((b + F(c, d, a) + X[15]), S14); + + // + // Round 2 - G cycle, 16 times. + // + a = RotateLeft((a + G(b, c, d) + X[ 0] + 0x5a827999), S21); + d = RotateLeft((d + G(a, b, c) + X[ 4] + 0x5a827999), S22); + c = RotateLeft((c + G(d, a, b) + X[ 8] + 0x5a827999), S23); + b = RotateLeft((b + G(c, d, a) + X[12] + 0x5a827999), S24); + a = RotateLeft((a + G(b, c, d) + X[ 1] + 0x5a827999), S21); + d = RotateLeft((d + G(a, b, c) + X[ 5] + 0x5a827999), S22); + c = RotateLeft((c + G(d, a, b) + X[ 9] + 0x5a827999), S23); + b = RotateLeft((b + G(c, d, a) + X[13] + 0x5a827999), S24); + a = RotateLeft((a + G(b, c, d) + X[ 2] + 0x5a827999), S21); + d = RotateLeft((d + G(a, b, c) + X[ 6] + 0x5a827999), S22); + c = RotateLeft((c + G(d, a, b) + X[10] + 0x5a827999), S23); + b = RotateLeft((b + G(c, d, a) + X[14] + 0x5a827999), S24); + a = RotateLeft((a + G(b, c, d) + X[ 3] + 0x5a827999), S21); + d = RotateLeft((d + G(a, b, c) + X[ 7] + 0x5a827999), S22); + c = RotateLeft((c + G(d, a, b) + X[11] + 0x5a827999), S23); + b = RotateLeft((b + G(c, d, a) + X[15] + 0x5a827999), S24); + + // + // Round 3 - H cycle, 16 times. + // + a = RotateLeft((a + H(b, c, d) + X[ 0] + 0x6ed9eba1), S31); + d = RotateLeft((d + H(a, b, c) + X[ 8] + 0x6ed9eba1), S32); + c = RotateLeft((c + H(d, a, b) + X[ 4] + 0x6ed9eba1), S33); + b = RotateLeft((b + H(c, d, a) + X[12] + 0x6ed9eba1), S34); + a = RotateLeft((a + H(b, c, d) + X[ 2] + 0x6ed9eba1), S31); + d = RotateLeft((d + H(a, b, c) + X[10] + 0x6ed9eba1), S32); + c = RotateLeft((c + H(d, a, b) + X[ 6] + 0x6ed9eba1), S33); + b = RotateLeft((b + H(c, d, a) + X[14] + 0x6ed9eba1), S34); + a = RotateLeft((a + H(b, c, d) + X[ 1] + 0x6ed9eba1), S31); + d = RotateLeft((d + H(a, b, c) + X[ 9] + 0x6ed9eba1), S32); + c = RotateLeft((c + H(d, a, b) + X[ 5] + 0x6ed9eba1), S33); + b = RotateLeft((b + H(c, d, a) + X[13] + 0x6ed9eba1), S34); + a = RotateLeft((a + H(b, c, d) + X[ 3] + 0x6ed9eba1), S31); + d = RotateLeft((d + H(a, b, c) + X[11] + 0x6ed9eba1), S32); + c = RotateLeft((c + H(d, a, b) + X[ 7] + 0x6ed9eba1), S33); + b = RotateLeft((b + H(c, d, a) + X[15] + 0x6ed9eba1), S34); + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/digests/MD5Digest.cs b/iTechSharp/srcbc/crypto/digests/MD5Digest.cs new file mode 100644 index 0000000..50d93e4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/MD5Digest.cs @@ -0,0 +1,301 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347. + */ + public class MD5Digest + : GeneralDigest + { + private const int DigestLength = 16; + + private int H1, H2, H3, H4; // IV's + + private int[] X = new int[16]; + private int xOff; + + public MD5Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public MD5Digest(MD5Digest t) + : base(t) + { + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "MD5"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)((ulong) bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)word; + outBytes[outOff + 1] = (byte)((uint) word >> 8); + outBytes[outOff + 2] = (byte)((uint) word >> 16); + outBytes[outOff + 3] = (byte)((uint) word >> 24); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 4); + UnpackWord(H3, output, outOff + 8); + UnpackWord(H4, output, outOff + 12); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables to the IV values. + */ + public override void Reset() + { + base.Reset(); + + H1 = unchecked((int) 0x67452301); + H2 = unchecked((int) 0xefcdab89); + H3 = unchecked((int) 0x98badcfe); + H4 = unchecked((int) 0x10325476); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + // + // round 1 left rotates + // + private static readonly int S11 = 7; + private static readonly int S12 = 12; + private static readonly int S13 = 17; + private static readonly int S14 = 22; + + // + // round 2 left rotates + // + private static readonly int S21 = 5; + private static readonly int S22 = 9; + private static readonly int S23 = 14; + private static readonly int S24 = 20; + + // + // round 3 left rotates + // + private static readonly int S31 = 4; + private static readonly int S32 = 11; + private static readonly int S33 = 16; + private static readonly int S34 = 23; + + // + // round 4 left rotates + // + private static readonly int S41 = 6; + private static readonly int S42 = 10; + private static readonly int S43 = 15; + private static readonly int S44 = 21; + + /* + * rotate int x left n bits. + */ + private int RotateLeft( + int x, + int n) + { + return (x << n) | (int) ((uint) x >> (32 - n)); + } + + /* + * F, G, H and I are the basic MD5 functions. + */ + private int F( + int u, + int v, + int w) + { + return (u & v) | (~u & w); + } + + private int G( + int u, + int v, + int w) + { + return (u & w) | (v & ~w); + } + + private int H( + int u, + int v, + int w) + { + return u ^ v ^ w; + } + + private int K( + int u, + int v, + int w) + { + return v ^ (u | ~w); + } + + internal override void ProcessBlock() + { + int a = H1; + int b = H2; + int c = H3; + int d = H4; + + // + // Round 1 - F cycle, 16 times. + // + a = RotateLeft((a + F(b, c, d) + X[ 0] + unchecked((int) 0xd76aa478)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[ 1] + unchecked((int) 0xe8c7b756)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[ 2] + unchecked((int) 0x242070db)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[ 3] + unchecked((int) 0xc1bdceee)), S14) + c; + a = RotateLeft((a + F(b, c, d) + X[ 4] + unchecked((int) 0xf57c0faf)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[ 5] + unchecked((int) 0x4787c62a)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[ 6] + unchecked((int) 0xa8304613)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[ 7] + unchecked((int) 0xfd469501)), S14) + c; + a = RotateLeft((a + F(b, c, d) + X[ 8] + unchecked((int) 0x698098d8)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[ 9] + unchecked((int) 0x8b44f7af)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[10] + unchecked((int) 0xffff5bb1)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[11] + unchecked((int) 0x895cd7be)), S14) + c; + a = RotateLeft((a + F(b, c, d) + X[12] + unchecked((int) 0x6b901122)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[13] + unchecked((int) 0xfd987193)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[14] + unchecked((int) 0xa679438e)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[15] + unchecked((int) 0x49b40821)), S14) + c; + + // + // Round 2 - G cycle, 16 times. + // + a = RotateLeft((a + G(b, c, d) + X[ 1] + unchecked((int) 0xf61e2562)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[ 6] + unchecked((int) 0xc040b340)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[11] + unchecked((int) 0x265e5a51)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[ 0] + unchecked((int) 0xe9b6c7aa)), S24) + c; + a = RotateLeft((a + G(b, c, d) + X[ 5] + unchecked((int) 0xd62f105d)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[10] + unchecked((int) 0x02441453)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[15] + unchecked((int) 0xd8a1e681)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[ 4] + unchecked((int) 0xe7d3fbc8)), S24) + c; + a = RotateLeft((a + G(b, c, d) + X[ 9] + unchecked((int) 0x21e1cde6)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[14] + unchecked((int) 0xc33707d6)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[ 3] + unchecked((int) 0xf4d50d87)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[ 8] + unchecked((int) 0x455a14ed)), S24) + c; + a = RotateLeft((a + G(b, c, d) + X[13] + unchecked((int) 0xa9e3e905)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[ 2] + unchecked((int) 0xfcefa3f8)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[ 7] + unchecked((int) 0x676f02d9)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[12] + unchecked((int) 0x8d2a4c8a)), S24) + c; + + // + // Round 3 - H cycle, 16 times. + // + a = RotateLeft((a + H(b, c, d) + X[ 5] + unchecked((int) 0xfffa3942)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[ 8] + unchecked((int) 0x8771f681)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[11] + unchecked((int) 0x6d9d6122)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[14] + unchecked((int) 0xfde5380c)), S34) + c; + a = RotateLeft((a + H(b, c, d) + X[ 1] + unchecked((int) 0xa4beea44)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[ 4] + unchecked((int) 0x4bdecfa9)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[ 7] + unchecked((int) 0xf6bb4b60)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[10] + unchecked((int) 0xbebfbc70)), S34) + c; + a = RotateLeft((a + H(b, c, d) + X[13] + unchecked((int) 0x289b7ec6)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[ 0] + unchecked((int) 0xeaa127fa)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[ 3] + unchecked((int) 0xd4ef3085)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[ 6] + unchecked((int) 0x04881d05)), S34) + c; + a = RotateLeft((a + H(b, c, d) + X[ 9] + unchecked((int) 0xd9d4d039)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[12] + unchecked((int) 0xe6db99e5)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[15] + unchecked((int) 0x1fa27cf8)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[ 2] + unchecked((int) 0xc4ac5665)), S34) + c; + + // + // Round 4 - K cycle, 16 times. + // + a = RotateLeft((a + K(b, c, d) + X[ 0] + unchecked((int) 0xf4292244)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[ 7] + unchecked((int) 0x432aff97)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[14] + unchecked((int) 0xab9423a7)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[ 5] + unchecked((int) 0xfc93a039)), S44) + c; + a = RotateLeft((a + K(b, c, d) + X[12] + unchecked((int) 0x655b59c3)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[ 3] + unchecked((int) 0x8f0ccc92)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[10] + unchecked((int) 0xffeff47d)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[ 1] + unchecked((int) 0x85845dd1)), S44) + c; + a = RotateLeft((a + K(b, c, d) + X[ 8] + unchecked((int) 0x6fa87e4f)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[15] + unchecked((int) 0xfe2ce6e0)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[ 6] + unchecked((int) 0xa3014314)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[13] + unchecked((int) 0x4e0811a1)), S44) + c; + a = RotateLeft((a + K(b, c, d) + X[ 4] + unchecked((int) 0xf7537e82)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[11] + unchecked((int) 0xbd3af235)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[ 2] + unchecked((int) 0x2ad7d2bb)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[ 9] + unchecked((int) 0xeb86d391)), S44) + c; + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/digests/RipeMD128Digest.cs b/iTechSharp/srcbc/crypto/digests/RipeMD128Digest.cs new file mode 100644 index 0000000..8977583 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/RipeMD128Digest.cs @@ -0,0 +1,462 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * implementation of RipeMD128 + */ + public class RipeMD128Digest + : GeneralDigest + { + private const int DigestLength = 16; + + private int H0, H1, H2, H3; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public RipeMD128Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public RipeMD128Digest(RipeMD128Digest t) : base(t) + { + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "RIPEMD128"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)((ulong) bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)word; + outBytes[outOff + 1] = (byte)((uint) word >> 8); + outBytes[outOff + 2] = (byte)((uint) word >> 16); + outBytes[outOff + 3] = (byte)((uint) word >> 24); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H0, output, outOff); + UnpackWord(H1, output, outOff + 4); + UnpackWord(H2, output, outOff + 8); + UnpackWord(H3, output, outOff + 12); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables to the IV values. + */ + public override void Reset() + { + base.Reset(); + + H0 = unchecked((int) 0x67452301); + H1 = unchecked((int) 0xefcdab89); + H2 = unchecked((int) 0x98badcfe); + H3 = unchecked((int) 0x10325476); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (int) ((uint) x >> (32 - n)); + } + + /* + * f1,f2,f3,f4 are the basic RipeMD128 functions. + */ + + /* + * F + */ + private int F1( + int x, + int y, + int z) + { + return x ^ y ^ z; + } + + /* + * G + */ + private int F2( + int x, + int y, + int z) + { + return (x & y) | (~x & z); + } + + /* + * H + */ + private int F3( + int x, + int y, + int z) + { + return (x | ~y) ^ z; + } + + /* + * I + */ + private int F4( + int x, + int y, + int z) + { + return (x & z) | (y & ~z); + } + + private int F1( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F1(b, c, d) + x, s); + } + + private int F2( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F2(b, c, d) + x + unchecked((int) 0x5a827999), s); + } + + private int F3( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F3(b, c, d) + x + unchecked((int) 0x6ed9eba1), s); + } + + private int F4( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F4(b, c, d) + x + unchecked((int) 0x8f1bbcdc), s); + } + + private int FF1( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F1(b, c, d) + x, s); + } + + private int FF2( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F2(b, c, d) + x + unchecked((int) 0x6d703ef3), s); + } + + private int FF3( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F3(b, c, d) + x + unchecked((int) 0x5c4dd124), s); + } + + private int FF4( + int a, + int b, + int c, + int d, + int x, + int s) + { + return RL(a + F4(b, c, d) + x + unchecked((int) 0x50a28be6), s); + } + + internal override void ProcessBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + + a = aa = H0; + b = bb = H1; + c = cc = H2; + d = dd = H3; + + // + // Round 1 + // + a = F1(a, b, c, d, X[ 0], 11); + d = F1(d, a, b, c, X[ 1], 14); + c = F1(c, d, a, b, X[ 2], 15); + b = F1(b, c, d, a, X[ 3], 12); + a = F1(a, b, c, d, X[ 4], 5); + d = F1(d, a, b, c, X[ 5], 8); + c = F1(c, d, a, b, X[ 6], 7); + b = F1(b, c, d, a, X[ 7], 9); + a = F1(a, b, c, d, X[ 8], 11); + d = F1(d, a, b, c, X[ 9], 13); + c = F1(c, d, a, b, X[10], 14); + b = F1(b, c, d, a, X[11], 15); + a = F1(a, b, c, d, X[12], 6); + d = F1(d, a, b, c, X[13], 7); + c = F1(c, d, a, b, X[14], 9); + b = F1(b, c, d, a, X[15], 8); + + // + // Round 2 + // + a = F2(a, b, c, d, X[ 7], 7); + d = F2(d, a, b, c, X[ 4], 6); + c = F2(c, d, a, b, X[13], 8); + b = F2(b, c, d, a, X[ 1], 13); + a = F2(a, b, c, d, X[10], 11); + d = F2(d, a, b, c, X[ 6], 9); + c = F2(c, d, a, b, X[15], 7); + b = F2(b, c, d, a, X[ 3], 15); + a = F2(a, b, c, d, X[12], 7); + d = F2(d, a, b, c, X[ 0], 12); + c = F2(c, d, a, b, X[ 9], 15); + b = F2(b, c, d, a, X[ 5], 9); + a = F2(a, b, c, d, X[ 2], 11); + d = F2(d, a, b, c, X[14], 7); + c = F2(c, d, a, b, X[11], 13); + b = F2(b, c, d, a, X[ 8], 12); + + // + // Round 3 + // + a = F3(a, b, c, d, X[ 3], 11); + d = F3(d, a, b, c, X[10], 13); + c = F3(c, d, a, b, X[14], 6); + b = F3(b, c, d, a, X[ 4], 7); + a = F3(a, b, c, d, X[ 9], 14); + d = F3(d, a, b, c, X[15], 9); + c = F3(c, d, a, b, X[ 8], 13); + b = F3(b, c, d, a, X[ 1], 15); + a = F3(a, b, c, d, X[ 2], 14); + d = F3(d, a, b, c, X[ 7], 8); + c = F3(c, d, a, b, X[ 0], 13); + b = F3(b, c, d, a, X[ 6], 6); + a = F3(a, b, c, d, X[13], 5); + d = F3(d, a, b, c, X[11], 12); + c = F3(c, d, a, b, X[ 5], 7); + b = F3(b, c, d, a, X[12], 5); + + // + // Round 4 + // + a = F4(a, b, c, d, X[ 1], 11); + d = F4(d, a, b, c, X[ 9], 12); + c = F4(c, d, a, b, X[11], 14); + b = F4(b, c, d, a, X[10], 15); + a = F4(a, b, c, d, X[ 0], 14); + d = F4(d, a, b, c, X[ 8], 15); + c = F4(c, d, a, b, X[12], 9); + b = F4(b, c, d, a, X[ 4], 8); + a = F4(a, b, c, d, X[13], 9); + d = F4(d, a, b, c, X[ 3], 14); + c = F4(c, d, a, b, X[ 7], 5); + b = F4(b, c, d, a, X[15], 6); + a = F4(a, b, c, d, X[14], 8); + d = F4(d, a, b, c, X[ 5], 6); + c = F4(c, d, a, b, X[ 6], 5); + b = F4(b, c, d, a, X[ 2], 12); + + // + // Parallel round 1 + // + aa = FF4(aa, bb, cc, dd, X[ 5], 8); + dd = FF4(dd, aa, bb, cc, X[14], 9); + cc = FF4(cc, dd, aa, bb, X[ 7], 9); + bb = FF4(bb, cc, dd, aa, X[ 0], 11); + aa = FF4(aa, bb, cc, dd, X[ 9], 13); + dd = FF4(dd, aa, bb, cc, X[ 2], 15); + cc = FF4(cc, dd, aa, bb, X[11], 15); + bb = FF4(bb, cc, dd, aa, X[ 4], 5); + aa = FF4(aa, bb, cc, dd, X[13], 7); + dd = FF4(dd, aa, bb, cc, X[ 6], 7); + cc = FF4(cc, dd, aa, bb, X[15], 8); + bb = FF4(bb, cc, dd, aa, X[ 8], 11); + aa = FF4(aa, bb, cc, dd, X[ 1], 14); + dd = FF4(dd, aa, bb, cc, X[10], 14); + cc = FF4(cc, dd, aa, bb, X[ 3], 12); + bb = FF4(bb, cc, dd, aa, X[12], 6); + + // + // Parallel round 2 + // + aa = FF3(aa, bb, cc, dd, X[ 6], 9); + dd = FF3(dd, aa, bb, cc, X[11], 13); + cc = FF3(cc, dd, aa, bb, X[ 3], 15); + bb = FF3(bb, cc, dd, aa, X[ 7], 7); + aa = FF3(aa, bb, cc, dd, X[ 0], 12); + dd = FF3(dd, aa, bb, cc, X[13], 8); + cc = FF3(cc, dd, aa, bb, X[ 5], 9); + bb = FF3(bb, cc, dd, aa, X[10], 11); + aa = FF3(aa, bb, cc, dd, X[14], 7); + dd = FF3(dd, aa, bb, cc, X[15], 7); + cc = FF3(cc, dd, aa, bb, X[ 8], 12); + bb = FF3(bb, cc, dd, aa, X[12], 7); + aa = FF3(aa, bb, cc, dd, X[ 4], 6); + dd = FF3(dd, aa, bb, cc, X[ 9], 15); + cc = FF3(cc, dd, aa, bb, X[ 1], 13); + bb = FF3(bb, cc, dd, aa, X[ 2], 11); + + // + // Parallel round 3 + // + aa = FF2(aa, bb, cc, dd, X[15], 9); + dd = FF2(dd, aa, bb, cc, X[ 5], 7); + cc = FF2(cc, dd, aa, bb, X[ 1], 15); + bb = FF2(bb, cc, dd, aa, X[ 3], 11); + aa = FF2(aa, bb, cc, dd, X[ 7], 8); + dd = FF2(dd, aa, bb, cc, X[14], 6); + cc = FF2(cc, dd, aa, bb, X[ 6], 6); + bb = FF2(bb, cc, dd, aa, X[ 9], 14); + aa = FF2(aa, bb, cc, dd, X[11], 12); + dd = FF2(dd, aa, bb, cc, X[ 8], 13); + cc = FF2(cc, dd, aa, bb, X[12], 5); + bb = FF2(bb, cc, dd, aa, X[ 2], 14); + aa = FF2(aa, bb, cc, dd, X[10], 13); + dd = FF2(dd, aa, bb, cc, X[ 0], 13); + cc = FF2(cc, dd, aa, bb, X[ 4], 7); + bb = FF2(bb, cc, dd, aa, X[13], 5); + + // + // Parallel round 4 + // + aa = FF1(aa, bb, cc, dd, X[ 8], 15); + dd = FF1(dd, aa, bb, cc, X[ 6], 5); + cc = FF1(cc, dd, aa, bb, X[ 4], 8); + bb = FF1(bb, cc, dd, aa, X[ 1], 11); + aa = FF1(aa, bb, cc, dd, X[ 3], 14); + dd = FF1(dd, aa, bb, cc, X[11], 14); + cc = FF1(cc, dd, aa, bb, X[15], 6); + bb = FF1(bb, cc, dd, aa, X[ 0], 14); + aa = FF1(aa, bb, cc, dd, X[ 5], 6); + dd = FF1(dd, aa, bb, cc, X[12], 9); + cc = FF1(cc, dd, aa, bb, X[ 2], 12); + bb = FF1(bb, cc, dd, aa, X[13], 9); + aa = FF1(aa, bb, cc, dd, X[ 9], 12); + dd = FF1(dd, aa, bb, cc, X[ 7], 5); + cc = FF1(cc, dd, aa, bb, X[10], 15); + bb = FF1(bb, cc, dd, aa, X[14], 8); + + dd += c + H1; // final result for H0 + + // + // combine the results + // + H1 = H2 + d + aa; + H2 = H3 + a + bb; + H3 = H0 + b + cc; + H0 = dd; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/digests/RipeMD160Digest.cs b/iTechSharp/srcbc/crypto/digests/RipeMD160Digest.cs new file mode 100644 index 0000000..8ce52ae --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/RipeMD160Digest.cs @@ -0,0 +1,423 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * implementation of RipeMD see, + * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html + */ + public class RipeMD160Digest + : GeneralDigest + { + private const int DigestLength = 20; + + private int H0, H1, H2, H3, H4; // IV's + + private int[] X = new int[16]; + private int xOff; + + /** + * Standard constructor + */ + public RipeMD160Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public RipeMD160Digest(RipeMD160Digest t) : base(t) + { + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "RIPEMD160"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)((ulong) bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)word; + outBytes[outOff + 1] = (byte)((uint) word >> 8); + outBytes[outOff + 2] = (byte)((uint) word >> 16); + outBytes[outOff + 3] = (byte)((uint) word >> 24); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H0, output, outOff); + UnpackWord(H1, output, outOff + 4); + UnpackWord(H2, output, outOff + 8); + UnpackWord(H3, output, outOff + 12); + UnpackWord(H4, output, outOff + 16); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables to the IV values. + */ + public override void Reset() + { + base.Reset(); + + H0 = unchecked((int) 0x67452301); + H1 = unchecked((int) 0xefcdab89); + H2 = unchecked((int) 0x98badcfe); + H3 = unchecked((int) 0x10325476); + H4 = unchecked((int) 0xc3d2e1f0); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (int) ((uint) x >> (32 - n)); + } + + /* + * f1,f2,f3,f4,f5 are the basic RipeMD160 functions. + */ + + /* + * rounds 0-15 + */ + private int F1( + int x, + int y, + int z) + { + return x ^ y ^ z; + } + + /* + * rounds 16-31 + */ + private int F2( + int x, + int y, + int z) + { + return (x & y) | (~x & z); + } + + /* + * rounds 32-47 + */ + private int F3( + int x, + int y, + int z) + { + return (x | ~y) ^ z; + } + + /* + * rounds 48-63 + */ + private int F4( + int x, + int y, + int z) + { + return (x & z) | (y & ~z); + } + + /* + * rounds 64-79 + */ + private int F5( + int x, + int y, + int z) + { + return x ^ (y | ~z); + } + + internal override void ProcessBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + int e, ee; + + a = aa = H0; + b = bb = H1; + c = cc = H2; + d = dd = H3; + e = ee = H4; + + // + // Rounds 1 - 16 + // + // left + a = RL(a + F1(b,c,d) + X[ 0], 11) + e; c = RL(c, 10); + e = RL(e + F1(a,b,c) + X[ 1], 14) + d; b = RL(b, 10); + d = RL(d + F1(e,a,b) + X[ 2], 15) + c; a = RL(a, 10); + c = RL(c + F1(d,e,a) + X[ 3], 12) + b; e = RL(e, 10); + b = RL(b + F1(c,d,e) + X[ 4], 5) + a; d = RL(d, 10); + a = RL(a + F1(b,c,d) + X[ 5], 8) + e; c = RL(c, 10); + e = RL(e + F1(a,b,c) + X[ 6], 7) + d; b = RL(b, 10); + d = RL(d + F1(e,a,b) + X[ 7], 9) + c; a = RL(a, 10); + c = RL(c + F1(d,e,a) + X[ 8], 11) + b; e = RL(e, 10); + b = RL(b + F1(c,d,e) + X[ 9], 13) + a; d = RL(d, 10); + a = RL(a + F1(b,c,d) + X[10], 14) + e; c = RL(c, 10); + e = RL(e + F1(a,b,c) + X[11], 15) + d; b = RL(b, 10); + d = RL(d + F1(e,a,b) + X[12], 6) + c; a = RL(a, 10); + c = RL(c + F1(d,e,a) + X[13], 7) + b; e = RL(e, 10); + b = RL(b + F1(c,d,e) + X[14], 9) + a; d = RL(d, 10); + a = RL(a + F1(b,c,d) + X[15], 8) + e; c = RL(c, 10); + + // right + aa = RL(aa + F5(bb,cc,dd) + X[ 5] + unchecked((int) 0x50a28be6), 8) + ee; cc = RL(cc, 10); + ee = RL(ee + F5(aa,bb,cc) + X[14] + unchecked((int) 0x50a28be6), 9) + dd; bb = RL(bb, 10); + dd = RL(dd + F5(ee,aa,bb) + X[ 7] + unchecked((int) 0x50a28be6), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F5(dd,ee,aa) + X[ 0] + unchecked((int) 0x50a28be6), 11) + bb; ee = RL(ee, 10); + bb = RL(bb + F5(cc,dd,ee) + X[ 9] + unchecked((int) 0x50a28be6), 13) + aa; dd = RL(dd, 10); + aa = RL(aa + F5(bb,cc,dd) + X[ 2] + unchecked((int) 0x50a28be6), 15) + ee; cc = RL(cc, 10); + ee = RL(ee + F5(aa,bb,cc) + X[11] + unchecked((int) 0x50a28be6), 15) + dd; bb = RL(bb, 10); + dd = RL(dd + F5(ee,aa,bb) + X[ 4] + unchecked((int) 0x50a28be6), 5) + cc; aa = RL(aa, 10); + cc = RL(cc + F5(dd,ee,aa) + X[13] + unchecked((int) 0x50a28be6), 7) + bb; ee = RL(ee, 10); + bb = RL(bb + F5(cc,dd,ee) + X[ 6] + unchecked((int) 0x50a28be6), 7) + aa; dd = RL(dd, 10); + aa = RL(aa + F5(bb,cc,dd) + X[15] + unchecked((int) 0x50a28be6), 8) + ee; cc = RL(cc, 10); + ee = RL(ee + F5(aa,bb,cc) + X[ 8] + unchecked((int) 0x50a28be6), 11) + dd; bb = RL(bb, 10); + dd = RL(dd + F5(ee,aa,bb) + X[ 1] + unchecked((int) 0x50a28be6), 14) + cc; aa = RL(aa, 10); + cc = RL(cc + F5(dd,ee,aa) + X[10] + unchecked((int) 0x50a28be6), 14) + bb; ee = RL(ee, 10); + bb = RL(bb + F5(cc,dd,ee) + X[ 3] + unchecked((int) 0x50a28be6), 12) + aa; dd = RL(dd, 10); + aa = RL(aa + F5(bb,cc,dd) + X[12] + unchecked((int) 0x50a28be6), 6) + ee; cc = RL(cc, 10); + + // + // Rounds 16-31 + // + // left + e = RL(e + F2(a,b,c) + X[ 7] + unchecked((int) 0x5a827999), 7) + d; b = RL(b, 10); + d = RL(d + F2(e,a,b) + X[ 4] + unchecked((int) 0x5a827999), 6) + c; a = RL(a, 10); + c = RL(c + F2(d,e,a) + X[13] + unchecked((int) 0x5a827999), 8) + b; e = RL(e, 10); + b = RL(b + F2(c,d,e) + X[ 1] + unchecked((int) 0x5a827999), 13) + a; d = RL(d, 10); + a = RL(a + F2(b,c,d) + X[10] + unchecked((int) 0x5a827999), 11) + e; c = RL(c, 10); + e = RL(e + F2(a,b,c) + X[ 6] + unchecked((int) 0x5a827999), 9) + d; b = RL(b, 10); + d = RL(d + F2(e,a,b) + X[15] + unchecked((int) 0x5a827999), 7) + c; a = RL(a, 10); + c = RL(c + F2(d,e,a) + X[ 3] + unchecked((int) 0x5a827999), 15) + b; e = RL(e, 10); + b = RL(b + F2(c,d,e) + X[12] + unchecked((int) 0x5a827999), 7) + a; d = RL(d, 10); + a = RL(a + F2(b,c,d) + X[ 0] + unchecked((int) 0x5a827999), 12) + e; c = RL(c, 10); + e = RL(e + F2(a,b,c) + X[ 9] + unchecked((int) 0x5a827999), 15) + d; b = RL(b, 10); + d = RL(d + F2(e,a,b) + X[ 5] + unchecked((int) 0x5a827999), 9) + c; a = RL(a, 10); + c = RL(c + F2(d,e,a) + X[ 2] + unchecked((int) 0x5a827999), 11) + b; e = RL(e, 10); + b = RL(b + F2(c,d,e) + X[14] + unchecked((int) 0x5a827999), 7) + a; d = RL(d, 10); + a = RL(a + F2(b,c,d) + X[11] + unchecked((int) 0x5a827999), 13) + e; c = RL(c, 10); + e = RL(e + F2(a,b,c) + X[ 8] + unchecked((int) 0x5a827999), 12) + d; b = RL(b, 10); + + // right + ee = RL(ee + F4(aa,bb,cc) + X[ 6] + unchecked((int) 0x5c4dd124), 9) + dd; bb = RL(bb, 10); + dd = RL(dd + F4(ee,aa,bb) + X[11] + unchecked((int) 0x5c4dd124), 13) + cc; aa = RL(aa, 10); + cc = RL(cc + F4(dd,ee,aa) + X[ 3] + unchecked((int) 0x5c4dd124), 15) + bb; ee = RL(ee, 10); + bb = RL(bb + F4(cc,dd,ee) + X[ 7] + unchecked((int) 0x5c4dd124), 7) + aa; dd = RL(dd, 10); + aa = RL(aa + F4(bb,cc,dd) + X[ 0] + unchecked((int) 0x5c4dd124), 12) + ee; cc = RL(cc, 10); + ee = RL(ee + F4(aa,bb,cc) + X[13] + unchecked((int) 0x5c4dd124), 8) + dd; bb = RL(bb, 10); + dd = RL(dd + F4(ee,aa,bb) + X[ 5] + unchecked((int) 0x5c4dd124), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F4(dd,ee,aa) + X[10] + unchecked((int) 0x5c4dd124), 11) + bb; ee = RL(ee, 10); + bb = RL(bb + F4(cc,dd,ee) + X[14] + unchecked((int) 0x5c4dd124), 7) + aa; dd = RL(dd, 10); + aa = RL(aa + F4(bb,cc,dd) + X[15] + unchecked((int) 0x5c4dd124), 7) + ee; cc = RL(cc, 10); + ee = RL(ee + F4(aa,bb,cc) + X[ 8] + unchecked((int) 0x5c4dd124), 12) + dd; bb = RL(bb, 10); + dd = RL(dd + F4(ee,aa,bb) + X[12] + unchecked((int) 0x5c4dd124), 7) + cc; aa = RL(aa, 10); + cc = RL(cc + F4(dd,ee,aa) + X[ 4] + unchecked((int) 0x5c4dd124), 6) + bb; ee = RL(ee, 10); + bb = RL(bb + F4(cc,dd,ee) + X[ 9] + unchecked((int) 0x5c4dd124), 15) + aa; dd = RL(dd, 10); + aa = RL(aa + F4(bb,cc,dd) + X[ 1] + unchecked((int) 0x5c4dd124), 13) + ee; cc = RL(cc, 10); + ee = RL(ee + F4(aa,bb,cc) + X[ 2] + unchecked((int) 0x5c4dd124), 11) + dd; bb = RL(bb, 10); + + // + // Rounds 32-47 + // + // left + d = RL(d + F3(e,a,b) + X[ 3] + unchecked((int) 0x6ed9eba1), 11) + c; a = RL(a, 10); + c = RL(c + F3(d,e,a) + X[10] + unchecked((int) 0x6ed9eba1), 13) + b; e = RL(e, 10); + b = RL(b + F3(c,d,e) + X[14] + unchecked((int) 0x6ed9eba1), 6) + a; d = RL(d, 10); + a = RL(a + F3(b,c,d) + X[ 4] + unchecked((int) 0x6ed9eba1), 7) + e; c = RL(c, 10); + e = RL(e + F3(a,b,c) + X[ 9] + unchecked((int) 0x6ed9eba1), 14) + d; b = RL(b, 10); + d = RL(d + F3(e,a,b) + X[15] + unchecked((int) 0x6ed9eba1), 9) + c; a = RL(a, 10); + c = RL(c + F3(d,e,a) + X[ 8] + unchecked((int) 0x6ed9eba1), 13) + b; e = RL(e, 10); + b = RL(b + F3(c,d,e) + X[ 1] + unchecked((int) 0x6ed9eba1), 15) + a; d = RL(d, 10); + a = RL(a + F3(b,c,d) + X[ 2] + unchecked((int) 0x6ed9eba1), 14) + e; c = RL(c, 10); + e = RL(e + F3(a,b,c) + X[ 7] + unchecked((int) 0x6ed9eba1), 8) + d; b = RL(b, 10); + d = RL(d + F3(e,a,b) + X[ 0] + unchecked((int) 0x6ed9eba1), 13) + c; a = RL(a, 10); + c = RL(c + F3(d,e,a) + X[ 6] + unchecked((int) 0x6ed9eba1), 6) + b; e = RL(e, 10); + b = RL(b + F3(c,d,e) + X[13] + unchecked((int) 0x6ed9eba1), 5) + a; d = RL(d, 10); + a = RL(a + F3(b,c,d) + X[11] + unchecked((int) 0x6ed9eba1), 12) + e; c = RL(c, 10); + e = RL(e + F3(a,b,c) + X[ 5] + unchecked((int) 0x6ed9eba1), 7) + d; b = RL(b, 10); + d = RL(d + F3(e,a,b) + X[12] + unchecked((int) 0x6ed9eba1), 5) + c; a = RL(a, 10); + + // right + dd = RL(dd + F3(ee,aa,bb) + X[15] + unchecked((int) 0x6d703ef3), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F3(dd,ee,aa) + X[ 5] + unchecked((int) 0x6d703ef3), 7) + bb; ee = RL(ee, 10); + bb = RL(bb + F3(cc,dd,ee) + X[ 1] + unchecked((int) 0x6d703ef3), 15) + aa; dd = RL(dd, 10); + aa = RL(aa + F3(bb,cc,dd) + X[ 3] + unchecked((int) 0x6d703ef3), 11) + ee; cc = RL(cc, 10); + ee = RL(ee + F3(aa,bb,cc) + X[ 7] + unchecked((int) 0x6d703ef3), 8) + dd; bb = RL(bb, 10); + dd = RL(dd + F3(ee,aa,bb) + X[14] + unchecked((int) 0x6d703ef3), 6) + cc; aa = RL(aa, 10); + cc = RL(cc + F3(dd,ee,aa) + X[ 6] + unchecked((int) 0x6d703ef3), 6) + bb; ee = RL(ee, 10); + bb = RL(bb + F3(cc,dd,ee) + X[ 9] + unchecked((int) 0x6d703ef3), 14) + aa; dd = RL(dd, 10); + aa = RL(aa + F3(bb,cc,dd) + X[11] + unchecked((int) 0x6d703ef3), 12) + ee; cc = RL(cc, 10); + ee = RL(ee + F3(aa,bb,cc) + X[ 8] + unchecked((int) 0x6d703ef3), 13) + dd; bb = RL(bb, 10); + dd = RL(dd + F3(ee,aa,bb) + X[12] + unchecked((int) 0x6d703ef3), 5) + cc; aa = RL(aa, 10); + cc = RL(cc + F3(dd,ee,aa) + X[ 2] + unchecked((int) 0x6d703ef3), 14) + bb; ee = RL(ee, 10); + bb = RL(bb + F3(cc,dd,ee) + X[10] + unchecked((int) 0x6d703ef3), 13) + aa; dd = RL(dd, 10); + aa = RL(aa + F3(bb,cc,dd) + X[ 0] + unchecked((int) 0x6d703ef3), 13) + ee; cc = RL(cc, 10); + ee = RL(ee + F3(aa,bb,cc) + X[ 4] + unchecked((int) 0x6d703ef3), 7) + dd; bb = RL(bb, 10); + dd = RL(dd + F3(ee,aa,bb) + X[13] + unchecked((int) 0x6d703ef3), 5) + cc; aa = RL(aa, 10); + + // + // Rounds 48-63 + // + // left + c = RL(c + F4(d,e,a) + X[ 1] + unchecked((int) 0x8f1bbcdc), 11) + b; e = RL(e, 10); + b = RL(b + F4(c,d,e) + X[ 9] + unchecked((int) 0x8f1bbcdc), 12) + a; d = RL(d, 10); + a = RL(a + F4(b,c,d) + X[11] + unchecked((int) 0x8f1bbcdc), 14) + e; c = RL(c, 10); + e = RL(e + F4(a,b,c) + X[10] + unchecked((int) 0x8f1bbcdc), 15) + d; b = RL(b, 10); + d = RL(d + F4(e,a,b) + X[ 0] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10); + c = RL(c + F4(d,e,a) + X[ 8] + unchecked((int) 0x8f1bbcdc), 15) + b; e = RL(e, 10); + b = RL(b + F4(c,d,e) + X[12] + unchecked((int) 0x8f1bbcdc), 9) + a; d = RL(d, 10); + a = RL(a + F4(b,c,d) + X[ 4] + unchecked((int) 0x8f1bbcdc), 8) + e; c = RL(c, 10); + e = RL(e + F4(a,b,c) + X[13] + unchecked((int) 0x8f1bbcdc), 9) + d; b = RL(b, 10); + d = RL(d + F4(e,a,b) + X[ 3] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10); + c = RL(c + F4(d,e,a) + X[ 7] + unchecked((int) 0x8f1bbcdc), 5) + b; e = RL(e, 10); + b = RL(b + F4(c,d,e) + X[15] + unchecked((int) 0x8f1bbcdc), 6) + a; d = RL(d, 10); + a = RL(a + F4(b,c,d) + X[14] + unchecked((int) 0x8f1bbcdc), 8) + e; c = RL(c, 10); + e = RL(e + F4(a,b,c) + X[ 5] + unchecked((int) 0x8f1bbcdc), 6) + d; b = RL(b, 10); + d = RL(d + F4(e,a,b) + X[ 6] + unchecked((int) 0x8f1bbcdc), 5) + c; a = RL(a, 10); + c = RL(c + F4(d,e,a) + X[ 2] + unchecked((int) 0x8f1bbcdc), 12) + b; e = RL(e, 10); + + // right + cc = RL(cc + F2(dd,ee,aa) + X[ 8] + unchecked((int) 0x7a6d76e9), 15) + bb; ee = RL(ee, 10); + bb = RL(bb + F2(cc,dd,ee) + X[ 6] + unchecked((int) 0x7a6d76e9), 5) + aa; dd = RL(dd, 10); + aa = RL(aa + F2(bb,cc,dd) + X[ 4] + unchecked((int) 0x7a6d76e9), 8) + ee; cc = RL(cc, 10); + ee = RL(ee + F2(aa,bb,cc) + X[ 1] + unchecked((int) 0x7a6d76e9), 11) + dd; bb = RL(bb, 10); + dd = RL(dd + F2(ee,aa,bb) + X[ 3] + unchecked((int) 0x7a6d76e9), 14) + cc; aa = RL(aa, 10); + cc = RL(cc + F2(dd,ee,aa) + X[11] + unchecked((int) 0x7a6d76e9), 14) + bb; ee = RL(ee, 10); + bb = RL(bb + F2(cc,dd,ee) + X[15] + unchecked((int) 0x7a6d76e9), 6) + aa; dd = RL(dd, 10); + aa = RL(aa + F2(bb,cc,dd) + X[ 0] + unchecked((int) 0x7a6d76e9), 14) + ee; cc = RL(cc, 10); + ee = RL(ee + F2(aa,bb,cc) + X[ 5] + unchecked((int) 0x7a6d76e9), 6) + dd; bb = RL(bb, 10); + dd = RL(dd + F2(ee,aa,bb) + X[12] + unchecked((int) 0x7a6d76e9), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F2(dd,ee,aa) + X[ 2] + unchecked((int) 0x7a6d76e9), 12) + bb; ee = RL(ee, 10); + bb = RL(bb + F2(cc,dd,ee) + X[13] + unchecked((int) 0x7a6d76e9), 9) + aa; dd = RL(dd, 10); + aa = RL(aa + F2(bb,cc,dd) + X[ 9] + unchecked((int) 0x7a6d76e9), 12) + ee; cc = RL(cc, 10); + ee = RL(ee + F2(aa,bb,cc) + X[ 7] + unchecked((int) 0x7a6d76e9), 5) + dd; bb = RL(bb, 10); + dd = RL(dd + F2(ee,aa,bb) + X[10] + unchecked((int) 0x7a6d76e9), 15) + cc; aa = RL(aa, 10); + cc = RL(cc + F2(dd,ee,aa) + X[14] + unchecked((int) 0x7a6d76e9), 8) + bb; ee = RL(ee, 10); + + // + // Rounds 64-79 + // + // left + b = RL(b + F5(c,d,e) + X[ 4] + unchecked((int) 0xa953fd4e), 9) + a; d = RL(d, 10); + a = RL(a + F5(b,c,d) + X[ 0] + unchecked((int) 0xa953fd4e), 15) + e; c = RL(c, 10); + e = RL(e + F5(a,b,c) + X[ 5] + unchecked((int) 0xa953fd4e), 5) + d; b = RL(b, 10); + d = RL(d + F5(e,a,b) + X[ 9] + unchecked((int) 0xa953fd4e), 11) + c; a = RL(a, 10); + c = RL(c + F5(d,e,a) + X[ 7] + unchecked((int) 0xa953fd4e), 6) + b; e = RL(e, 10); + b = RL(b + F5(c,d,e) + X[12] + unchecked((int) 0xa953fd4e), 8) + a; d = RL(d, 10); + a = RL(a + F5(b,c,d) + X[ 2] + unchecked((int) 0xa953fd4e), 13) + e; c = RL(c, 10); + e = RL(e + F5(a,b,c) + X[10] + unchecked((int) 0xa953fd4e), 12) + d; b = RL(b, 10); + d = RL(d + F5(e,a,b) + X[14] + unchecked((int) 0xa953fd4e), 5) + c; a = RL(a, 10); + c = RL(c + F5(d,e,a) + X[ 1] + unchecked((int) 0xa953fd4e), 12) + b; e = RL(e, 10); + b = RL(b + F5(c,d,e) + X[ 3] + unchecked((int) 0xa953fd4e), 13) + a; d = RL(d, 10); + a = RL(a + F5(b,c,d) + X[ 8] + unchecked((int) 0xa953fd4e), 14) + e; c = RL(c, 10); + e = RL(e + F5(a,b,c) + X[11] + unchecked((int) 0xa953fd4e), 11) + d; b = RL(b, 10); + d = RL(d + F5(e,a,b) + X[ 6] + unchecked((int) 0xa953fd4e), 8) + c; a = RL(a, 10); + c = RL(c + F5(d,e,a) + X[15] + unchecked((int) 0xa953fd4e), 5) + b; e = RL(e, 10); + b = RL(b + F5(c,d,e) + X[13] + unchecked((int) 0xa953fd4e), 6) + a; d = RL(d, 10); + + // right + bb = RL(bb + F1(cc,dd,ee) + X[12], 8) + aa; dd = RL(dd, 10); + aa = RL(aa + F1(bb,cc,dd) + X[15], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + F1(aa,bb,cc) + X[10], 12) + dd; bb = RL(bb, 10); + dd = RL(dd + F1(ee,aa,bb) + X[ 4], 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F1(dd,ee,aa) + X[ 1], 12) + bb; ee = RL(ee, 10); + bb = RL(bb + F1(cc,dd,ee) + X[ 5], 5) + aa; dd = RL(dd, 10); + aa = RL(aa + F1(bb,cc,dd) + X[ 8], 14) + ee; cc = RL(cc, 10); + ee = RL(ee + F1(aa,bb,cc) + X[ 7], 6) + dd; bb = RL(bb, 10); + dd = RL(dd + F1(ee,aa,bb) + X[ 6], 8) + cc; aa = RL(aa, 10); + cc = RL(cc + F1(dd,ee,aa) + X[ 2], 13) + bb; ee = RL(ee, 10); + bb = RL(bb + F1(cc,dd,ee) + X[13], 6) + aa; dd = RL(dd, 10); + aa = RL(aa + F1(bb,cc,dd) + X[14], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + F1(aa,bb,cc) + X[ 0], 15) + dd; bb = RL(bb, 10); + dd = RL(dd + F1(ee,aa,bb) + X[ 3], 13) + cc; aa = RL(aa, 10); + cc = RL(cc + F1(dd,ee,aa) + X[ 9], 11) + bb; ee = RL(ee, 10); + bb = RL(bb + F1(cc,dd,ee) + X[11], 11) + aa; dd = RL(dd, 10); + + dd += c + H1; + H1 = H2 + d + ee; + H2 = H3 + e + aa; + H3 = H4 + a + bb; + H4 = H0 + b + cc; + H0 = dd; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/digests/RipeMD256Digest.cs b/iTechSharp/srcbc/crypto/digests/RipeMD256Digest.cs new file mode 100644 index 0000000..950e94f --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/RipeMD256Digest.cs @@ -0,0 +1,409 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /// + ///

      Implementation of RipeMD256.

      + ///

      Note: this algorithm offers the same level of security as RipeMD128.

      + ///
      + public class RipeMD256Digest + : GeneralDigest + { + public override string AlgorithmName + { + get { return "RIPEMD256"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + private const int DigestLength = 32; + + private int H0, H1, H2, H3, H4, H5, H6, H7; // IV's + + private int[] X = new int[16]; + private int xOff; + + /// Standard constructor + public RipeMD256Digest() + { + Reset(); + } + + /// Copy constructor. This will copy the state of the provided + /// message digest. + /// + public RipeMD256Digest(RipeMD256Digest t):base(t) + { + + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)((ulong)bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)(uint)word; + outBytes[outOff + 1] = (byte)((uint)word >> 8); + outBytes[outOff + 2] = (byte)((uint)word >> 16); + outBytes[outOff + 3] = (byte)((uint)word >> 24); + } + + public override int DoFinal(byte[] output, int outOff) + { + Finish(); + + UnpackWord(H0, output, outOff); + UnpackWord(H1, output, outOff + 4); + UnpackWord(H2, output, outOff + 8); + UnpackWord(H3, output, outOff + 12); + UnpackWord(H4, output, outOff + 16); + UnpackWord(H5, output, outOff + 20); + UnpackWord(H6, output, outOff + 24); + UnpackWord(H7, output, outOff + 28); + + Reset(); + + return DigestLength; + } + + /// reset the chaining variables to the IV values. + public override void Reset() + { + base.Reset(); + + H0 = unchecked((int)0x67452301); + H1 = unchecked((int)0xefcdab89); + H2 = unchecked((int)0x98badcfe); + H3 = unchecked((int)0x10325476); + H4 = unchecked((int)0x76543210); + H5 = unchecked((int)0xFEDCBA98); + H6 = unchecked((int)0x89ABCDEF); + H7 = unchecked((int)0x01234567); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (int)((uint)x >> (32 - n)); + } + + /* + * f1,f2,f3,f4 are the basic RipeMD128 functions. + */ + + /* + * F + */ + private int F1(int x, int y, int z) + { + return x ^ y ^ z; + } + + /* + * G + */ + private int F2(int x, int y, int z) + { + return (x & y) | (~ x & z); + } + + /* + * H + */ + private int F3(int x, int y, int z) + { + return (x | ~ y) ^ z; + } + + /* + * I + */ + private int F4(int x, int y, int z) + { + return (x & z) | (y & ~ z); + } + + private int F1(int a, int b, int c, int d, int x, int s) + { + return RL(a + F1(b, c, d) + x, s); + } + + private int F2(int a, int b, int c, int d, int x, int s) + { + return RL(a + F2(b, c, d) + x + unchecked((int)0x5a827999), s); + } + + private int F3(int a, int b, int c, int d, int x, int s) + { + return RL(a + F3(b, c, d) + x + unchecked((int)0x6ed9eba1), s); + } + + private int F4(int a, int b, int c, int d, int x, int s) + { + return RL(a + F4(b, c, d) + x + unchecked((int)0x8f1bbcdc), s); + } + + private int FF1(int a, int b, int c, int d, int x, int s) + { + return RL(a + F1(b, c, d) + x, s); + } + + private int FF2(int a, int b, int c, int d, int x, int s) + { + return RL(a + F2(b, c, d) + x + unchecked((int)0x6d703ef3), s); + } + + private int FF3(int a, int b, int c, int d, int x, int s) + { + return RL(a + F3(b, c, d) + x + unchecked((int)0x5c4dd124), s); + } + + private int FF4(int a, int b, int c, int d, int x, int s) + { + return RL(a + F4(b, c, d) + x + unchecked((int)0x50a28be6), s); + } + + internal override void ProcessBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + int t; + + a = H0; + b = H1; + c = H2; + d = H3; + aa = H4; + bb = H5; + cc = H6; + dd = H7; + + // + // Round 1 + // + + a = F1(a, b, c, d, X[0], 11); + d = F1(d, a, b, c, X[1], 14); + c = F1(c, d, a, b, X[2], 15); + b = F1(b, c, d, a, X[3], 12); + a = F1(a, b, c, d, X[4], 5); + d = F1(d, a, b, c, X[5], 8); + c = F1(c, d, a, b, X[6], 7); + b = F1(b, c, d, a, X[7], 9); + a = F1(a, b, c, d, X[8], 11); + d = F1(d, a, b, c, X[9], 13); + c = F1(c, d, a, b, X[10], 14); + b = F1(b, c, d, a, X[11], 15); + a = F1(a, b, c, d, X[12], 6); + d = F1(d, a, b, c, X[13], 7); + c = F1(c, d, a, b, X[14], 9); + b = F1(b, c, d, a, X[15], 8); + + aa = FF4(aa, bb, cc, dd, X[5], 8); + dd = FF4(dd, aa, bb, cc, X[14], 9); + cc = FF4(cc, dd, aa, bb, X[7], 9); + bb = FF4(bb, cc, dd, aa, X[0], 11); + aa = FF4(aa, bb, cc, dd, X[9], 13); + dd = FF4(dd, aa, bb, cc, X[2], 15); + cc = FF4(cc, dd, aa, bb, X[11], 15); + bb = FF4(bb, cc, dd, aa, X[4], 5); + aa = FF4(aa, bb, cc, dd, X[13], 7); + dd = FF4(dd, aa, bb, cc, X[6], 7); + cc = FF4(cc, dd, aa, bb, X[15], 8); + bb = FF4(bb, cc, dd, aa, X[8], 11); + aa = FF4(aa, bb, cc, dd, X[1], 14); + dd = FF4(dd, aa, bb, cc, X[10], 14); + cc = FF4(cc, dd, aa, bb, X[3], 12); + bb = FF4(bb, cc, dd, aa, X[12], 6); + + t = a; a = aa; aa = t; + + // + // Round 2 + // + a = F2(a, b, c, d, X[7], 7); + d = F2(d, a, b, c, X[4], 6); + c = F2(c, d, a, b, X[13], 8); + b = F2(b, c, d, a, X[1], 13); + a = F2(a, b, c, d, X[10], 11); + d = F2(d, a, b, c, X[6], 9); + c = F2(c, d, a, b, X[15], 7); + b = F2(b, c, d, a, X[3], 15); + a = F2(a, b, c, d, X[12], 7); + d = F2(d, a, b, c, X[0], 12); + c = F2(c, d, a, b, X[9], 15); + b = F2(b, c, d, a, X[5], 9); + a = F2(a, b, c, d, X[2], 11); + d = F2(d, a, b, c, X[14], 7); + c = F2(c, d, a, b, X[11], 13); + b = F2(b, c, d, a, X[8], 12); + + aa = FF3(aa, bb, cc, dd, X[6], 9); + dd = FF3(dd, aa, bb, cc, X[11], 13); + cc = FF3(cc, dd, aa, bb, X[3], 15); + bb = FF3(bb, cc, dd, aa, X[7], 7); + aa = FF3(aa, bb, cc, dd, X[0], 12); + dd = FF3(dd, aa, bb, cc, X[13], 8); + cc = FF3(cc, dd, aa, bb, X[5], 9); + bb = FF3(bb, cc, dd, aa, X[10], 11); + aa = FF3(aa, bb, cc, dd, X[14], 7); + dd = FF3(dd, aa, bb, cc, X[15], 7); + cc = FF3(cc, dd, aa, bb, X[8], 12); + bb = FF3(bb, cc, dd, aa, X[12], 7); + aa = FF3(aa, bb, cc, dd, X[4], 6); + dd = FF3(dd, aa, bb, cc, X[9], 15); + cc = FF3(cc, dd, aa, bb, X[1], 13); + bb = FF3(bb, cc, dd, aa, X[2], 11); + + t = b; b = bb; bb = t; + + // + // Round 3 + // + a = F3(a, b, c, d, X[3], 11); + d = F3(d, a, b, c, X[10], 13); + c = F3(c, d, a, b, X[14], 6); + b = F3(b, c, d, a, X[4], 7); + a = F3(a, b, c, d, X[9], 14); + d = F3(d, a, b, c, X[15], 9); + c = F3(c, d, a, b, X[8], 13); + b = F3(b, c, d, a, X[1], 15); + a = F3(a, b, c, d, X[2], 14); + d = F3(d, a, b, c, X[7], 8); + c = F3(c, d, a, b, X[0], 13); + b = F3(b, c, d, a, X[6], 6); + a = F3(a, b, c, d, X[13], 5); + d = F3(d, a, b, c, X[11], 12); + c = F3(c, d, a, b, X[5], 7); + b = F3(b, c, d, a, X[12], 5); + + aa = FF2(aa, bb, cc, dd, X[15], 9); + dd = FF2(dd, aa, bb, cc, X[5], 7); + cc = FF2(cc, dd, aa, bb, X[1], 15); + bb = FF2(bb, cc, dd, aa, X[3], 11); + aa = FF2(aa, bb, cc, dd, X[7], 8); + dd = FF2(dd, aa, bb, cc, X[14], 6); + cc = FF2(cc, dd, aa, bb, X[6], 6); + bb = FF2(bb, cc, dd, aa, X[9], 14); + aa = FF2(aa, bb, cc, dd, X[11], 12); + dd = FF2(dd, aa, bb, cc, X[8], 13); + cc = FF2(cc, dd, aa, bb, X[12], 5); + bb = FF2(bb, cc, dd, aa, X[2], 14); + aa = FF2(aa, bb, cc, dd, X[10], 13); + dd = FF2(dd, aa, bb, cc, X[0], 13); + cc = FF2(cc, dd, aa, bb, X[4], 7); + bb = FF2(bb, cc, dd, aa, X[13], 5); + + t = c; c = cc; cc = t; + + // + // Round 4 + // + a = F4(a, b, c, d, X[1], 11); + d = F4(d, a, b, c, X[9], 12); + c = F4(c, d, a, b, X[11], 14); + b = F4(b, c, d, a, X[10], 15); + a = F4(a, b, c, d, X[0], 14); + d = F4(d, a, b, c, X[8], 15); + c = F4(c, d, a, b, X[12], 9); + b = F4(b, c, d, a, X[4], 8); + a = F4(a, b, c, d, X[13], 9); + d = F4(d, a, b, c, X[3], 14); + c = F4(c, d, a, b, X[7], 5); + b = F4(b, c, d, a, X[15], 6); + a = F4(a, b, c, d, X[14], 8); + d = F4(d, a, b, c, X[5], 6); + c = F4(c, d, a, b, X[6], 5); + b = F4(b, c, d, a, X[2], 12); + + aa = FF1(aa, bb, cc, dd, X[8], 15); + dd = FF1(dd, aa, bb, cc, X[6], 5); + cc = FF1(cc, dd, aa, bb, X[4], 8); + bb = FF1(bb, cc, dd, aa, X[1], 11); + aa = FF1(aa, bb, cc, dd, X[3], 14); + dd = FF1(dd, aa, bb, cc, X[11], 14); + cc = FF1(cc, dd, aa, bb, X[15], 6); + bb = FF1(bb, cc, dd, aa, X[0], 14); + aa = FF1(aa, bb, cc, dd, X[5], 6); + dd = FF1(dd, aa, bb, cc, X[12], 9); + cc = FF1(cc, dd, aa, bb, X[2], 12); + bb = FF1(bb, cc, dd, aa, X[13], 9); + aa = FF1(aa, bb, cc, dd, X[9], 12); + dd = FF1(dd, aa, bb, cc, X[7], 5); + cc = FF1(cc, dd, aa, bb, X[10], 15); + bb = FF1(bb, cc, dd, aa, X[14], 8); + + t = d; d = dd; dd = t; + + H0 += a; + H1 += b; + H2 += c; + H3 += d; + H4 += aa; + H5 += bb; + H6 += cc; + H7 += dd; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/RipeMD320Digest.cs b/iTechSharp/srcbc/crypto/digests/RipeMD320Digest.cs new file mode 100644 index 0000000..25c74ba --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/RipeMD320Digest.cs @@ -0,0 +1,438 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /// + ///

      Implementation of RipeMD 320.

      + ///

      Note: this algorithm offers the same level of security as RipeMD160.

      + ///
      + public class RipeMD320Digest + : GeneralDigest + { + public override string AlgorithmName + { + get { return "RIPEMD320"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + private const int DigestLength = 40; + + private int H0, H1, H2, H3, H4, H5, H6, H7, H8, H9; // IV's + + private int[] X = new int[16]; + private int xOff; + + /// Standard constructor + public RipeMD320Digest() + { + Reset(); + } + + /// Copy constructor. This will copy the state of the provided + /// message digest. + /// + public RipeMD320Digest(RipeMD320Digest t) + : base(t) + { + + H0 = t.H0; + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + H9 = t.H9; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)(bitLength & 0xffffffff); + X[15] = (int)((ulong)bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)word; + outBytes[outOff + 1] = (byte)((uint)word >> 8); + outBytes[outOff + 2] = (byte)((uint)word >> 16); + outBytes[outOff + 3] = (byte)((uint)word >> 24); + } + + public override int DoFinal(byte[] output, int outOff) + { + Finish(); + + UnpackWord(H0, output, outOff); + UnpackWord(H1, output, outOff + 4); + UnpackWord(H2, output, outOff + 8); + UnpackWord(H3, output, outOff + 12); + UnpackWord(H4, output, outOff + 16); + UnpackWord(H5, output, outOff + 20); + UnpackWord(H6, output, outOff + 24); + UnpackWord(H7, output, outOff + 28); + UnpackWord(H8, output, outOff + 32); + UnpackWord(H9, output, outOff + 36); + + Reset(); + + return DigestLength; + } + + /// reset the chaining variables to the IV values. + public override void Reset() + { + base.Reset(); + + H0 = unchecked((int) 0x67452301); + H1 = unchecked((int) 0xefcdab89); + H2 = unchecked((int) 0x98badcfe); + H3 = unchecked((int) 0x10325476); + H4 = unchecked((int) 0xc3d2e1f0); + H5 = unchecked((int) 0x76543210); + H6 = unchecked((int) 0xFEDCBA98); + H7 = unchecked((int) 0x89ABCDEF); + H8 = unchecked((int) 0x01234567); + H9 = unchecked((int) 0x3C2D1E0F); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + /* + * rotate int x left n bits. + */ + private int RL( + int x, + int n) + { + return (x << n) | (int)(((uint)x) >> (32 - n)); + } + + /* + * f1,f2,f3,f4,f5 are the basic RipeMD160 functions. + */ + + /* + * rounds 0-15 + */ + private int F1(int x, int y, int z) + { + return x ^ y ^ z; + } + + /* + * rounds 16-31 + */ + private int F2(int x, int y, int z) + { + return (x & y) | (~ x & z); + } + + /* + * rounds 32-47 + */ + private int F3(int x, int y, int z) + { + return (x | ~ y) ^ z; + } + + /* + * rounds 48-63 + */ + private int F4(int x, int y, int z) + { + return (x & z) | (y & ~ z); + } + + /* + * rounds 64-79 + */ + private int F5(int x, int y, int z) + { + return x ^ (y | ~z); + } + + internal override void ProcessBlock() + { + int a, aa; + int b, bb; + int c, cc; + int d, dd; + int e, ee; + int t; + + a = H0; + b = H1; + c = H2; + d = H3; + e = H4; + aa = H5; + bb = H6; + cc = H7; + dd = H8; + ee = H9; + + // + // Rounds 1 - 16 + // + // left + a = RL(a + F1(b, c, d) + X[0], 11) + e; c = RL(c, 10); + e = RL(e + F1(a, b, c) + X[1], 14) + d; b = RL(b, 10); + d = RL(d + F1(e, a, b) + X[2], 15) + c; a = RL(a, 10); + c = RL(c + F1(d, e, a) + X[3], 12) + b; e = RL(e, 10); + b = RL(b + F1(c, d, e) + X[4], 5) + a; d = RL(d, 10); + a = RL(a + F1(b, c, d) + X[5], 8) + e; c = RL(c, 10); + e = RL(e + F1(a, b, c) + X[6], 7) + d; b = RL(b, 10); + d = RL(d + F1(e, a, b) + X[7], 9) + c; a = RL(a, 10); + c = RL(c + F1(d, e, a) + X[8], 11) + b; e = RL(e, 10); + b = RL(b + F1(c, d, e) + X[9], 13) + a; d = RL(d, 10); + a = RL(a + F1(b, c, d) + X[10], 14) + e; c = RL(c, 10); + e = RL(e + F1(a, b, c) + X[11], 15) + d; b = RL(b, 10); + d = RL(d + F1(e, a, b) + X[12], 6) + c; a = RL(a, 10); + c = RL(c + F1(d, e, a) + X[13], 7) + b; e = RL(e, 10); + b = RL(b + F1(c, d, e) + X[14], 9) + a; d = RL(d, 10); + a = RL(a + F1(b, c, d) + X[15], 8) + e; c = RL(c, 10); + + // right + aa = RL(aa + F5(bb, cc, dd) + X[5] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10); + ee = RL(ee + F5(aa, bb, cc) + X[14] + unchecked((int)0x50a28be6), 9) + dd; bb = RL(bb, 10); + dd = RL(dd + F5(ee, aa, bb) + X[7] + unchecked((int)0x50a28be6), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F5(dd, ee, aa) + X[0] + unchecked((int)0x50a28be6), 11) + bb; ee = RL(ee, 10); + bb = RL(bb + F5(cc, dd, ee) + X[9] + unchecked((int)0x50a28be6), 13) + aa; dd = RL(dd, 10); + aa = RL(aa + F5(bb, cc, dd) + X[2] + unchecked((int)0x50a28be6), 15) + ee; cc = RL(cc, 10); + ee = RL(ee + F5(aa, bb, cc) + X[11] + unchecked((int)0x50a28be6), 15) + dd; bb = RL(bb, 10); + dd = RL(dd + F5(ee, aa, bb) + X[4] + unchecked((int)0x50a28be6), 5) + cc; aa = RL(aa, 10); + cc = RL(cc + F5(dd, ee, aa) + X[13] + unchecked((int)0x50a28be6), 7) + bb; ee = RL(ee, 10); + bb = RL(bb + F5(cc, dd, ee) + X[6] + unchecked((int)0x50a28be6), 7) + aa; dd = RL(dd, 10); + aa = RL(aa + F5(bb, cc, dd) + X[15] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10); + ee = RL(ee + F5(aa, bb, cc) + X[8] + unchecked((int)0x50a28be6), 11) + dd; bb = RL(bb, 10); + dd = RL(dd + F5(ee, aa, bb) + X[1] + unchecked((int)0x50a28be6), 14) + cc; aa = RL(aa, 10); + cc = RL(cc + F5(dd, ee, aa) + X[10] + unchecked((int)0x50a28be6), 14) + bb; ee = RL(ee, 10); + bb = RL(bb + F5(cc, dd, ee) + X[3] + unchecked((int)0x50a28be6), 12) + aa; dd = RL(dd, 10); + aa = RL(aa + F5(bb, cc, dd) + X[12] + unchecked((int)0x50a28be6), 6) + ee; cc = RL(cc, 10); + + t = a; a = aa; aa = t; + // + // Rounds 16-31 + // + // left + e = RL(e + F2(a, b, c) + X[7] + unchecked((int)0x5a827999), 7) + d; b = RL(b, 10); + d = RL(d + F2(e, a, b) + X[4] + unchecked((int)0x5a827999), 6) + c; a = RL(a, 10); + c = RL(c + F2(d, e, a) + X[13] + unchecked((int)0x5a827999), 8) + b; e = RL(e, 10); + b = RL(b + F2(c, d, e) + X[1] + unchecked((int)0x5a827999), 13) + a; d = RL(d, 10); + a = RL(a + F2(b, c, d) + X[10] + unchecked((int)0x5a827999), 11) + e; c = RL(c, 10); + e = RL(e + F2(a, b, c) + X[6] + unchecked((int)0x5a827999), 9) + d; b = RL(b, 10); + d = RL(d + F2(e, a, b) + X[15] + unchecked((int)0x5a827999), 7) + c; a = RL(a, 10); + c = RL(c + F2(d, e, a) + X[3] + unchecked((int)0x5a827999), 15) + b; e = RL(e, 10); + b = RL(b + F2(c, d, e) + X[12] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10); + a = RL(a + F2(b, c, d) + X[0] + unchecked((int)0x5a827999), 12) + e; c = RL(c, 10); + e = RL(e + F2(a, b, c) + X[9] + unchecked((int)0x5a827999), 15) + d; b = RL(b, 10); + d = RL(d + F2(e, a, b) + X[5] + unchecked((int)0x5a827999), 9) + c; a = RL(a, 10); + c = RL(c + F2(d, e, a) + X[2] + unchecked((int)0x5a827999), 11) + b; e = RL(e, 10); + b = RL(b + F2(c, d, e) + X[14] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10); + a = RL(a + F2(b, c, d) + X[11] + unchecked((int)0x5a827999), 13) + e; c = RL(c, 10); + e = RL(e + F2(a, b, c) + X[8] + unchecked((int)0x5a827999), 12) + d; b = RL(b, 10); + + // right + ee = RL(ee + F4(aa, bb, cc) + X[6] + unchecked((int)0x5c4dd124), 9) + dd; bb = RL(bb, 10); + dd = RL(dd + F4(ee, aa, bb) + X[11] + unchecked((int)0x5c4dd124), 13) + cc; aa = RL(aa, 10); + cc = RL(cc + F4(dd, ee, aa) + X[3] + unchecked((int)0x5c4dd124), 15) + bb; ee = RL(ee, 10); + bb = RL(bb + F4(cc, dd, ee) + X[7] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10); + aa = RL(aa + F4(bb, cc, dd) + X[0] + unchecked((int)0x5c4dd124), 12) + ee; cc = RL(cc, 10); + ee = RL(ee + F4(aa, bb, cc) + X[13] + unchecked((int)0x5c4dd124), 8) + dd; bb = RL(bb, 10); + dd = RL(dd + F4(ee, aa, bb) + X[5] + unchecked((int)0x5c4dd124), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F4(dd, ee, aa) + X[10] + unchecked((int)0x5c4dd124), 11) + bb; ee = RL(ee, 10); + bb = RL(bb + F4(cc, dd, ee) + X[14] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10); + aa = RL(aa + F4(bb, cc, dd) + X[15] + unchecked((int)0x5c4dd124), 7) + ee; cc = RL(cc, 10); + ee = RL(ee + F4(aa, bb, cc) + X[8] + unchecked((int)0x5c4dd124), 12) + dd; bb = RL(bb, 10); + dd = RL(dd + F4(ee, aa, bb) + X[12] + unchecked((int)0x5c4dd124), 7) + cc; aa = RL(aa, 10); + cc = RL(cc + F4(dd, ee, aa) + X[4] + unchecked((int)0x5c4dd124), 6) + bb; ee = RL(ee, 10); + bb = RL(bb + F4(cc, dd, ee) + X[9] + unchecked((int)0x5c4dd124), 15) + aa; dd = RL(dd, 10); + aa = RL(aa + F4(bb, cc, dd) + X[1] + unchecked((int)0x5c4dd124), 13) + ee; cc = RL(cc, 10); + ee = RL(ee + F4(aa, bb, cc) + X[2] + unchecked((int)0x5c4dd124), 11) + dd; bb = RL(bb, 10); + + t = b; b = bb; bb = t; + + // + // Rounds 32-47 + // + // left + d = RL(d + F3(e, a, b) + X[3] + unchecked((int)0x6ed9eba1), 11) + c; a = RL(a, 10); + c = RL(c + F3(d, e, a) + X[10] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10); + b = RL(b + F3(c, d, e) + X[14] + unchecked((int)0x6ed9eba1), 6) + a; d = RL(d, 10); + a = RL(a + F3(b, c, d) + X[4] + unchecked((int)0x6ed9eba1), 7) + e; c = RL(c, 10); + e = RL(e + F3(a, b, c) + X[9] + unchecked((int)0x6ed9eba1), 14) + d; b = RL(b, 10); + d = RL(d + F3(e, a, b) + X[15] + unchecked((int)0x6ed9eba1), 9) + c; a = RL(a, 10); + c = RL(c + F3(d, e, a) + X[8] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10); + b = RL(b + F3(c, d, e) + X[1] + unchecked((int)0x6ed9eba1), 15) + a; d = RL(d, 10); + a = RL(a + F3(b, c, d) + X[2] + unchecked((int)0x6ed9eba1), 14) + e; c = RL(c, 10); + e = RL(e + F3(a, b, c) + X[7] + unchecked((int)0x6ed9eba1), 8) + d; b = RL(b, 10); + d = RL(d + F3(e, a, b) + X[0] + unchecked((int)0x6ed9eba1), 13) + c; a = RL(a, 10); + c = RL(c + F3(d, e, a) + X[6] + unchecked((int)0x6ed9eba1), 6) + b; e = RL(e, 10); + b = RL(b + F3(c, d, e) + X[13] + unchecked((int)0x6ed9eba1), 5) + a; d = RL(d, 10); + a = RL(a + F3(b, c, d) + X[11] + unchecked((int)0x6ed9eba1), 12) + e; c = RL(c, 10); + e = RL(e + F3(a, b, c) + X[5] + unchecked((int)0x6ed9eba1), 7) + d; b = RL(b, 10); + d = RL(d + F3(e, a, b) + X[12] + unchecked((int)0x6ed9eba1), 5) + c; a = RL(a, 10); + + // right + dd = RL(dd + F3(ee, aa, bb) + X[15] + unchecked((int)0x6d703ef3), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F3(dd, ee, aa) + X[5] + unchecked((int)0x6d703ef3), 7) + bb; ee = RL(ee, 10); + bb = RL(bb + F3(cc, dd, ee) + X[1] + unchecked((int)0x6d703ef3), 15) + aa; dd = RL(dd, 10); + aa = RL(aa + F3(bb, cc, dd) + X[3] + unchecked((int)0x6d703ef3), 11) + ee; cc = RL(cc, 10); + ee = RL(ee + F3(aa, bb, cc) + X[7] + unchecked((int)0x6d703ef3), 8) + dd; bb = RL(bb, 10); + dd = RL(dd + F3(ee, aa, bb) + X[14] + unchecked((int)0x6d703ef3), 6) + cc; aa = RL(aa, 10); + cc = RL(cc + F3(dd, ee, aa) + X[6] + unchecked((int)0x6d703ef3), 6) + bb; ee = RL(ee, 10); + bb = RL(bb + F3(cc, dd, ee) + X[9] + unchecked((int)0x6d703ef3), 14) + aa; dd = RL(dd, 10); + aa = RL(aa + F3(bb, cc, dd) + X[11] + unchecked((int)0x6d703ef3), 12) + ee; cc = RL(cc, 10); + ee = RL(ee + F3(aa, bb, cc) + X[8] + unchecked((int)0x6d703ef3), 13) + dd; bb = RL(bb, 10); + dd = RL(dd + F3(ee, aa, bb) + X[12] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10); + cc = RL(cc + F3(dd, ee, aa) + X[2] + unchecked((int)0x6d703ef3), 14) + bb; ee = RL(ee, 10); + bb = RL(bb + F3(cc, dd, ee) + X[10] + unchecked((int)0x6d703ef3), 13) + aa; dd = RL(dd, 10); + aa = RL(aa + F3(bb, cc, dd) + X[0] + unchecked((int)0x6d703ef3), 13) + ee; cc = RL(cc, 10); + ee = RL(ee + F3(aa, bb, cc) + X[4] + unchecked((int)0x6d703ef3), 7) + dd; bb = RL(bb, 10); + dd = RL(dd + F3(ee, aa, bb) + X[13] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10); + + t = c; c = cc; cc = t; + + // + // Rounds 48-63 + // + // left + c = RL(c + F4(d, e, a) + X[1] + unchecked((int)0x8f1bbcdc), 11) + b; e = RL(e, 10); + b = RL(b + F4(c, d, e) + X[9] + unchecked((int)0x8f1bbcdc), 12) + a; d = RL(d, 10); + a = RL(a + F4(b, c, d) + X[11] + unchecked((int)0x8f1bbcdc), 14) + e; c = RL(c, 10); + e = RL(e + F4(a, b, c) + X[10] + unchecked((int)0x8f1bbcdc), 15) + d; b = RL(b, 10); + d = RL(d + F4(e, a, b) + X[0] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10); + c = RL(c + F4(d, e, a) + X[8] + unchecked((int)0x8f1bbcdc), 15) + b; e = RL(e, 10); + b = RL(b + F4(c, d, e) + X[12] + unchecked((int)0x8f1bbcdc), 9) + a; d = RL(d, 10); + a = RL(a + F4(b, c, d) + X[4] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10); + e = RL(e + F4(a, b, c) + X[13] + unchecked((int)0x8f1bbcdc), 9) + d; b = RL(b, 10); + d = RL(d + F4(e, a, b) + X[3] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10); + c = RL(c + F4(d, e, a) + X[7] + unchecked((int)0x8f1bbcdc), 5) + b; e = RL(e, 10); + b = RL(b + F4(c, d, e) + X[15] + unchecked((int)0x8f1bbcdc), 6) + a; d = RL(d, 10); + a = RL(a + F4(b, c, d) + X[14] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10); + e = RL(e + F4(a, b, c) + X[5] + unchecked((int)0x8f1bbcdc), 6) + d; b = RL(b, 10); + d = RL(d + F4(e, a, b) + X[6] + unchecked((int)0x8f1bbcdc), 5) + c; a = RL(a, 10); + c = RL(c + F4(d, e, a) + X[2] + unchecked((int)0x8f1bbcdc), 12) + b; e = RL(e, 10); + + // right + cc = RL(cc + F2(dd, ee, aa) + X[8] + unchecked((int)0x7a6d76e9), 15) + bb; ee = RL(ee, 10); + bb = RL(bb + F2(cc, dd, ee) + X[6] + unchecked((int)0x7a6d76e9), 5) + aa; dd = RL(dd, 10); + aa = RL(aa + F2(bb, cc, dd) + X[4] + unchecked((int)0x7a6d76e9), 8) + ee; cc = RL(cc, 10); + ee = RL(ee + F2(aa, bb, cc) + X[1] + unchecked((int)0x7a6d76e9), 11) + dd; bb = RL(bb, 10); + dd = RL(dd + F2(ee, aa, bb) + X[3] + unchecked((int)0x7a6d76e9), 14) + cc; aa = RL(aa, 10); + cc = RL(cc + F2(dd, ee, aa) + X[11] + unchecked((int)0x7a6d76e9), 14) + bb; ee = RL(ee, 10); + bb = RL(bb + F2(cc, dd, ee) + X[15] + unchecked((int)0x7a6d76e9), 6) + aa; dd = RL(dd, 10); + aa = RL(aa + F2(bb, cc, dd) + X[0] + unchecked((int)0x7a6d76e9), 14) + ee; cc = RL(cc, 10); + ee = RL(ee + F2(aa, bb, cc) + X[5] + unchecked((int)0x7a6d76e9), 6) + dd; bb = RL(bb, 10); + dd = RL(dd + F2(ee, aa, bb) + X[12] + unchecked((int)0x7a6d76e9), 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F2(dd, ee, aa) + X[2] + unchecked((int)0x7a6d76e9), 12) + bb; ee = RL(ee, 10); + bb = RL(bb + F2(cc, dd, ee) + X[13] + unchecked((int)0x7a6d76e9), 9) + aa; dd = RL(dd, 10); + aa = RL(aa + F2(bb, cc, dd) + X[9] + unchecked((int)0x7a6d76e9), 12) + ee; cc = RL(cc, 10); + ee = RL(ee + F2(aa, bb, cc) + X[7] + unchecked((int)0x7a6d76e9), 5) + dd; bb = RL(bb, 10); + dd = RL(dd + F2(ee, aa, bb) + X[10] + unchecked((int)0x7a6d76e9), 15) + cc; aa = RL(aa, 10); + cc = RL(cc + F2(dd, ee, aa) + X[14] + unchecked((int)0x7a6d76e9), 8) + bb; ee = RL(ee, 10); + + t = d; d = dd; dd = t; + + // + // Rounds 64-79 + // + // left + b = RL(b + F5(c, d, e) + X[4] + unchecked((int)0xa953fd4e), 9) + a; d = RL(d, 10); + a = RL(a + F5(b, c, d) + X[0] + unchecked((int)0xa953fd4e), 15) + e; c = RL(c, 10); + e = RL(e + F5(a, b, c) + X[5] + unchecked((int)0xa953fd4e), 5) + d; b = RL(b, 10); + d = RL(d + F5(e, a, b) + X[9] + unchecked((int)0xa953fd4e), 11) + c; a = RL(a, 10); + c = RL(c + F5(d, e, a) + X[7] + unchecked((int)0xa953fd4e), 6) + b; e = RL(e, 10); + b = RL(b + F5(c, d, e) + X[12] + unchecked((int)0xa953fd4e), 8) + a; d = RL(d, 10); + a = RL(a + F5(b, c, d) + X[2] + unchecked((int)0xa953fd4e), 13) + e; c = RL(c, 10); + e = RL(e + F5(a, b, c) + X[10] + unchecked((int)0xa953fd4e), 12) + d; b = RL(b, 10); + d = RL(d + F5(e, a, b) + X[14] + unchecked((int)0xa953fd4e), 5) + c; a = RL(a, 10); + c = RL(c + F5(d, e, a) + X[1] + unchecked((int)0xa953fd4e), 12) + b; e = RL(e, 10); + b = RL(b + F5(c, d, e) + X[3] + unchecked((int)0xa953fd4e), 13) + a; d = RL(d, 10); + a = RL(a + F5(b, c, d) + X[8] + unchecked((int)0xa953fd4e), 14) + e; c = RL(c, 10); + e = RL(e + F5(a, b, c) + X[11] + unchecked((int)0xa953fd4e), 11) + d; b = RL(b, 10); + d = RL(d + F5(e, a, b) + X[6] + unchecked((int)0xa953fd4e), 8) + c; a = RL(a, 10); + c = RL(c + F5(d, e, a) + X[15] + unchecked((int)0xa953fd4e), 5) + b; e = RL(e, 10); + b = RL(b + F5(c, d, e) + X[13] + unchecked((int)0xa953fd4e), 6) + a; d = RL(d, 10); + + // right + bb = RL(bb + F1(cc, dd, ee) + X[12], 8) + aa; dd = RL(dd, 10); + aa = RL(aa + F1(bb, cc, dd) + X[15], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + F1(aa, bb, cc) + X[10], 12) + dd; bb = RL(bb, 10); + dd = RL(dd + F1(ee, aa, bb) + X[4], 9) + cc; aa = RL(aa, 10); + cc = RL(cc + F1(dd, ee, aa) + X[1], 12) + bb; ee = RL(ee, 10); + bb = RL(bb + F1(cc, dd, ee) + X[5], 5) + aa; dd = RL(dd, 10); + aa = RL(aa + F1(bb, cc, dd) + X[8], 14) + ee; cc = RL(cc, 10); + ee = RL(ee + F1(aa, bb, cc) + X[7], 6) + dd; bb = RL(bb, 10); + dd = RL(dd + F1(ee, aa, bb) + X[6], 8) + cc; aa = RL(aa, 10); + cc = RL(cc + F1(dd, ee, aa) + X[2], 13) + bb; ee = RL(ee, 10); + bb = RL(bb + F1(cc, dd, ee) + X[13], 6) + aa; dd = RL(dd, 10); + aa = RL(aa + F1(bb, cc, dd) + X[14], 5) + ee; cc = RL(cc, 10); + ee = RL(ee + F1(aa, bb, cc) + X[0], 15) + dd; bb = RL(bb, 10); + dd = RL(dd + F1(ee, aa, bb) + X[3], 13) + cc; aa = RL(aa, 10); + cc = RL(cc + F1(dd, ee, aa) + X[9], 11) + bb; ee = RL(ee, 10); + bb = RL(bb + F1(cc, dd, ee) + X[11], 11) + aa; dd = RL(dd, 10); + + // + // do (e, ee) swap as part of assignment. + // + + H0 += a; + H1 += b; + H2 += c; + H3 += d; + H4 += ee; + H5 += aa; + H6 += bb; + H7 += cc; + H8 += dd; + H9 += e; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/Sha1Digest.cs b/iTechSharp/srcbc/crypto/digests/Sha1Digest.cs new file mode 100644 index 0000000..3ceaf1c --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/Sha1Digest.cs @@ -0,0 +1,285 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + + /** + * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. + * + * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 + * is the "endienness" of the word processing! + */ + public class Sha1Digest + : GeneralDigest + { + private const int DigestLength = 20; + + private int H1, H2, H3, H4, H5; + + private int[] X = new int[80]; + private int xOff; + + public Sha1Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha1Digest(Sha1Digest t) + : base(t) + { + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "SHA-1"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = ((input[inOff] & 0xff) << 24) | ((input[inOff + 1] & 0xff) << 16) + | ((input[inOff + 2] & 0xff) << 8) | ((input[inOff + 3] & 0xff)); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + private static void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff++] = (byte)((uint)word >> 24); + outBytes[outOff++] = (byte)((uint)word >> 16); + outBytes[outOff++] = (byte)((uint)word >> 8); + outBytes[outOff++] = (byte)word; + } + + internal override void ProcessLength(long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)((ulong) bitLength >> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 4); + UnpackWord(H3, output, outOff + 8); + UnpackWord(H4, output, outOff + 12); + UnpackWord(H5, output, outOff + 16); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables + */ + public override void Reset() + { + base.Reset(); + + H1 = unchecked( (int) 0x67452301 ); + H2 = unchecked( (int) 0xefcdab89 ); + H3 = unchecked( (int) 0x98badcfe ); + H4 = unchecked( (int) 0x10325476 ); + H5 = unchecked( (int) 0xc3d2e1f0 ); + + xOff = 0; + for (int i = 0; i != X.Length; i++) X[i] = 0; + } + + // + // Additive constants + // + private const int Y1 = unchecked( (int) 0x5a827999); + private const int Y2 = unchecked( (int) 0x6ed9eba1); + private const int Y3 = unchecked( (int) 0x8f1bbcdc); + private const int Y4 = unchecked( (int) 0xca62c1d6); + + private static int F( + int u, + int v, + int w) + { + return ((u & v) | ((~u) & w)); + } + + private static int H( + int u, + int v, + int w) + { + return (u ^ v ^ w); + } + + private static int G( + int u, + int v, + int w) + { + return ((u & v) | (u & w) | (v & w)); + } + + internal override void ProcessBlock() + { + // + // expand 16 word block into 80 word block. + // + for (int i = 16; i < 80; i++) + { + int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; + X[i] = t << 1 | (int)((uint)t >> 31); + } + + // + // set up working variables. + // + int A = H1; + int B = H2; + int C = H3; + int D = H4; + int E = H5; + + // + // round 1 + // + int idx = 0; + + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1 + // B = rotateLeft(B, 30) + E += (A << 5 | (int)((uint)A >> 27)) + F(B, C, D) + X[idx++] + Y1; + B = B << 30 | (int)((uint)B >> 2); + + D += (E << 5 | (int)((uint)E >> 27)) + F(A, B, C) + X[idx++] + Y1; + A = A << 30 | (int)((uint)A >> 2); + + C += (D << 5 | (int)((uint)D >> 27)) + F(E, A, B) + X[idx++] + Y1; + E = E << 30 | (int)((uint)E >> 2); + + B += (C << 5 | (int)((uint)C >> 27)) + F(D, E, A) + X[idx++] + Y1; + D = D << 30 | (int)((uint)D >> 2); + + A += (B << 5 | (int)((uint)B >> 27)) + F(C, D, E) + X[idx++] + Y1; + C = C << 30 | (int)((uint)C >> 2); + } + + // + // round 2 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2 + // B = rotateLeft(B, 30) + E += (A << 5 | (int)((uint)A >> 27)) + H(B, C, D) + X[idx++] + Y2; + B = B << 30 | (int)((uint)B >> 2); + + D += (E << 5 | (int)((uint)E >> 27)) + H(A, B, C) + X[idx++] + Y2; + A = A << 30 | (int)((uint)A >> 2); + + C += (D << 5 | (int)((uint)D >> 27)) + H(E, A, B) + X[idx++] + Y2; + E = E << 30 | (int)((uint)E >> 2); + + B += (C << 5 | (int)((uint)C >> 27)) + H(D, E, A) + X[idx++] + Y2; + D = D << 30 | (int)((uint)D >> 2); + + A += (B << 5 | (int)((uint)B >> 27)) + H(C, D, E) + X[idx++] + Y2; + C = C << 30 | (int)((uint)C >> 2); + } + + // + // round 3 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3 + // B = rotateLeft(B, 30) + E += (A << 5 | (int)((uint)A >> 27)) + G(B, C, D) + X[idx++] + Y3; + B = B << 30 | (int)((uint)B >> 2); + + D += (E << 5 | (int)((uint)E >> 27)) + G(A, B, C) + X[idx++] + Y3; + A = A << 30 | (int)((uint)A >> 2); + + C += (D << 5 | (int)((uint)D >> 27)) + G(E, A, B) + X[idx++] + Y3; + E = E << 30 | (int)((uint)E >> 2); + + B += (C << 5 | (int)((uint)C >> 27)) + G(D, E, A) + X[idx++] + Y3; + D = D << 30 | (int)((uint)D >> 2); + + A += (B << 5 | (int)((uint)B >> 27)) + G(C, D, E) + X[idx++] + Y3; + C = C << 30 | (int)((uint)C >> 2); + } + + // + // round 4 + // + for (int j = 0; j <= 3; j++) + { + // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4 + // B = rotateLeft(B, 30) + E += (A << 5 | (int)((uint)A >> 27)) + H(B, C, D) + X[idx++] + Y4; + B = B << 30 | (int)((uint)B >> 2); + + D += (E << 5 | (int)((uint)E >> 27)) + H(A, B, C) + X[idx++] + Y4; + A = A << 30 | (int)((uint)A >> 2); + + C += (D << 5 | (int)((uint)D >> 27)) + H(E, A, B) + X[idx++] + Y4; + E = E << 30 | (int)((uint)E >> 2); + + B += (C << 5 | (int)((uint)C >> 27)) + H(D, E, A) + X[idx++] + Y4; + D = D << 30 | (int)((uint)D >> 2); + + A += (B << 5 | (int)((uint)B >> 27)) + H(C, D, E) + X[idx++] + Y4; + C = C << 30 | (int)((uint)C >> 2); + } + + H1 += A; + H2 += B; + H3 += C; + H4 += D; + H5 += E; + + // + // reset start of the buffer. + // + xOff = 0; + for (int i = 0; i < 16; i++) + { + X[i] = 0; + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/Sha224Digest.cs b/iTechSharp/srcbc/crypto/digests/Sha224Digest.cs new file mode 100644 index 0000000..ca1fe45 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/Sha224Digest.cs @@ -0,0 +1,287 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * SHA-224 as described in RFC 3874 + *
      +     *         block  word  digest
      +     * SHA-1   512    32    160
      +     * SHA-224 512    32    224
      +     * SHA-256 512    32    256
      +     * SHA-384 1024   64    384
      +     * SHA-512 1024   64    512
      +     * 
      + */ + public class Sha224Digest + : GeneralDigest + { + private const int DigestLength = 28; + + private int H1, H2, H3, H4, H5, H6, H7, H8; + + private int[] X = new int[64]; + private int xOff; + + /** + * Standard constructor + */ + public Sha224Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha224Digest( + Sha224Digest t) + : base(t) + { + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "SHA-224"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = ((input[inOff] & 0xff) << 24) | ((input[inOff + 1] & 0xff) << 16) + | ((input[inOff + 2] & 0xff) << 8) | ((input[inOff + 3] & 0xff)); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)((uint) word >> 24); + outBytes[outOff + 1] = (byte)((uint) word >> 16); + outBytes[outOff + 2] = (byte)((uint) word >> 8); + outBytes[outOff + 3] = (byte)word; + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)((ulong) bitLength >> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 4); + UnpackWord(H3, output, outOff + 8); + UnpackWord(H4, output, outOff + 12); + UnpackWord(H5, output, outOff + 16); + UnpackWord(H6, output, outOff + 20); + UnpackWord(H7, output, outOff + 24); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables + */ + public override void Reset() + { + base.Reset(); + + /* SHA-224 initial hash value + */ + + unchecked + { + H1 = (int) 0xc1059ed8; + H2 = (int) 0x367cd507; + H3 = (int) 0x3070dd17; + H4 = (int) 0xf70e5939; + H5 = (int) 0xffc00b31; + H6 = (int) 0x68581511; + H7 = (int) 0x64f98fa7; + H8 = (int) 0xbefa4fa4; + } + + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + internal override void ProcessBlock() + { + // + // expand 16 word block into 64 word blocks. + // + for (int ti = 16; ti <= 63; ti++) + { + X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16]; + } + + // + // set up working variables. + // + int a = H1; + int b = H2; + int c = H3; + int d = H4; + int e = H5; + int f = H6; + int g = H7; + int h = H8; + + int t = 0; + for(int i = 0; i < 8; i ++) + { + // t = 8 * i + h += Sum1(e) + Ch(e, f, g) + (int)K[t] + X[t++]; + d += h; + h += Sum0(a) + Maj(a, b, c); + + // t = 8 * i + 1 + g += Sum1(d) + Ch(d, e, f) + (int)K[t] + X[t++]; + c += g; + g += Sum0(h) + Maj(h, a, b); + + // t = 8 * i + 2 + f += Sum1(c) + Ch(c, d, e) + (int)K[t] + X[t++]; + b += f; + f += Sum0(g) + Maj(g, h, a); + + // t = 8 * i + 3 + e += Sum1(b) + Ch(b, c, d) + (int)K[t] + X[t++]; + a += e; + e += Sum0(f) + Maj(f, g, h); + + // t = 8 * i + 4 + d += Sum1(a) + Ch(a, b, c) + (int)K[t] + X[t++]; + h += d; + d += Sum0(e) + Maj(e, f, g); + + // t = 8 * i + 5 + c += Sum1(h) + Ch(h, a, b) + (int)K[t] + X[t++]; + g += c; + c += Sum0(d) + Maj(d, e, f); + + // t = 8 * i + 6 + b += Sum1(g) + Ch(g, h, a) + (int)K[t] + X[t++]; + f += b; + b += Sum0(c) + Maj(c, d, e); + + // t = 8 * i + 7 + a += Sum1(f) + Ch(f, g, h) + (int)K[t] + X[t++]; + e += a; + a += Sum0(b) + Maj(b, c, d); + } + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + H5 += e; + H6 += f; + H7 += g; + H8 += h; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + + Array.Clear(X, 0, 16); + } + + /* SHA-224 functions */ + private static int Ch( + int x, + int y, + int z) + { + return ((x & y) ^ ((~x) & z)); + } + + private static int Maj( + int x, + int y, + int z) + { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + private static int Sum0( + int x) + { + return (((int)((uint)x >> 2)) | (x << 30)) ^ (((int)((uint)x >> 13)) | (x << 19)) ^ (((int)((uint)x >> 22)) | (x << 10)); + } + + private static int Sum1( + int x) + { + return (((int)((uint)x >> 6)) | (x << 26)) ^ (((int)((uint)x >> 11)) | (x << 21)) ^ (((int)((uint)x >> 25)) | (x << 7)); + } + + private static int Theta0( + int x) + { + return (((int)((uint)x >> 7)) | (x << 25)) ^ (((int)((uint)x >> 18)) | (x << 14)) ^ ((int)((uint)x >> 3)); + } + + private static int Theta1( + int x) + { + return (((int)((uint)x >> 17)) | (x << 15)) ^ (((int)((uint)x >> 19)) | (x << 13)) ^ ((int)((uint)x >> 10)); + } + + /* SHA-224 Constants + * (represent the first 32 bits of the fractional parts of the + * cube roots of the first sixty-four prime numbers) + */ + internal static readonly uint[] K = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + } +} diff --git a/iTechSharp/srcbc/crypto/digests/Sha256Digest.cs b/iTechSharp/srcbc/crypto/digests/Sha256Digest.cs new file mode 100644 index 0000000..274116d --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/Sha256Digest.cs @@ -0,0 +1,310 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * Draft FIPS 180-2 implementation of SHA-256. Note: As this is + * based on a draft this implementation is subject to change. + * + *
      +    *         block  word  digest
      +    * SHA-1   512    32    160
      +    * SHA-256 512    32    256
      +    * SHA-384 1024   64    384
      +    * SHA-512 1024   64    512
      +    * 
      + */ + public class Sha256Digest + : GeneralDigest + { + private const int DigestLength = 32; + + private int H1, H2, H3, H4, H5, H6, H7, H8; + + private int[] X = new int[64]; + private int xOff; + + public Sha256Digest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha256Digest(Sha256Digest t) : base(t) + { + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "SHA-256"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff++] = ((input[inOff] & 0xff) << 24) | ((input[inOff + 1] & 0xff) << 16) + | ((input[inOff + 2] & 0xff) << 8) | ((input[inOff + 3] & 0xff)); + + if (xOff == 16) + { + ProcessBlock(); + } + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)((uint) word >> 24); + outBytes[outOff + 1] = (byte)((uint) word >> 16); + outBytes[outOff + 2] = (byte)((uint) word >> 8); + outBytes[outOff + 3] = (byte)word; + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (int)((ulong) bitLength >> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 4); + UnpackWord(H3, output, outOff + 8); + UnpackWord(H4, output, outOff + 12); + UnpackWord(H5, output, outOff + 16); + UnpackWord(H6, output, outOff + 20); + UnpackWord(H7, output, outOff + 24); + UnpackWord(H8, output, outOff + 28); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables + */ + public override void Reset() + { + base.Reset(); + + /* SHA-256 initial hash value + * The first 32 bits of the fractional parts of the square roots + * of the first eight prime numbers + */ + unchecked + { + H1 = (int) 0x6a09e667; + H2 = (int) 0xbb67ae85; + H3 = (int) 0x3c6ef372; + H4 = (int) 0xa54ff53a; + H5 = (int) 0x510e527f; + H6 = (int) 0x9b05688c; + H7 = (int) 0x1f83d9ab; + H8 = (int) 0x5be0cd19; + } + + xOff = 0; + for (int i = 0; i != X.Length; i++) + { + X[i] = 0; + } + } + + internal override void ProcessBlock() + { + // + // expand 16 word block into 64 word blocks. + // + for (int ti = 16; ti <= 63; ti++) + { + X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16]; + } + + // + // set up working variables. + // + int a = H1; + int b = H2; + int c = H3; + int d = H4; + int e = H5; + int f = H6; + int g = H7; + int h = H8; + + int t = 0; + for(int i = 0; i < 8; i ++) + { + // t = 8 * i + h += Sum1(e) + Ch(e, f, g) + K[t] + X[t++]; + d += h; + h += Sum0(a) + Maj(a, b, c); + + // t = 8 * i + 1 + g += Sum1(d) + Ch(d, e, f) + K[t] + X[t++]; + c += g; + g += Sum0(h) + Maj(h, a, b); + + // t = 8 * i + 2 + f += Sum1(c) + Ch(c, d, e) + K[t] + X[t++]; + b += f; + f += Sum0(g) + Maj(g, h, a); + + // t = 8 * i + 3 + e += Sum1(b) + Ch(b, c, d) + K[t] + X[t++]; + a += e; + e += Sum0(f) + Maj(f, g, h); + + // t = 8 * i + 4 + d += Sum1(a) + Ch(a, b, c) + K[t] + X[t++]; + h += d; + d += Sum0(e) + Maj(e, f, g); + + // t = 8 * i + 5 + c += Sum1(h) + Ch(h, a, b) + K[t] + X[t++]; + g += c; + c += Sum0(d) + Maj(d, e, f); + + // t = 8 * i + 6 + b += Sum1(g) + Ch(g, h, a) + K[t] + X[t++]; + f += b; + b += Sum0(c) + Maj(c, d, e); + + // t = 8 * i + 7 + a += Sum1(f) + Ch(f, g, h) + K[t] + X[t++]; + e += a; + a += Sum0(b) + Maj(b, c, d); + } + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + H5 += e; + H6 += f; + H7 += g; + H8 += h; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + + Array.Clear(X, 0, 16); + } + + /* SHA-256 functions */ + private static int Ch( + int x, + int y, + int z) + { + return ((x & y) ^ ((~x) & z)); + } + + private static int Maj( + int x, + int y, + int z) + { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + private static int Sum0( + int x) + { + return (((int)((uint)x >> 2)) | (x << 30)) ^ (((int)((uint)x >> 13)) | (x << 19)) ^ (((int)((uint)x >> 22)) | (x << 10)); + } + + private static int Sum1( + int x) + { + return (((int)((uint)x >> 6)) | (x << 26)) ^ (((int)((uint)x >> 11)) | (x << 21)) ^ (((int)((uint)x >> 25)) | (x << 7)); + } + + private static int Theta0( + int x) + { + return (((int)((uint)x >> 7)) | (x << 25)) ^ (((int)((uint)x >> 18)) | (x << 14)) ^ ((int)((uint)x >> 3)); + } + + private static int Theta1( + int x) + { + return (((int)((uint)x >> 17)) | (x << 15)) ^ (((int)((uint)x >> 19)) | (x << 13)) ^ ((int)((uint)x >> 10)); + } + + /* SHA-256 Constants + * (represent the first 32 bits of the fractional parts of the + * cube roots of the first sixty-four prime numbers) + */ + internal static readonly int[] K = { + unchecked ((int) 0x428a2f98), unchecked ((int) 0x71374491), + unchecked ((int) 0xb5c0fbcf), unchecked ((int) 0xe9b5dba5), + unchecked ((int) 0x3956c25b), unchecked ((int) 0x59f111f1), + unchecked ((int) 0x923f82a4), unchecked ((int) 0xab1c5ed5), + unchecked ((int) 0xd807aa98), unchecked ((int) 0x12835b01), + unchecked ((int) 0x243185be), unchecked ((int) 0x550c7dc3), + unchecked ((int) 0x72be5d74), unchecked ((int) 0x80deb1fe), + unchecked ((int) 0x9bdc06a7), unchecked ((int) 0xc19bf174), + unchecked ((int) 0xe49b69c1), unchecked ((int) 0xefbe4786), + unchecked ((int) 0x0fc19dc6), unchecked ((int) 0x240ca1cc), + unchecked ((int) 0x2de92c6f), unchecked ((int) 0x4a7484aa), + unchecked ((int) 0x5cb0a9dc), unchecked ((int) 0x76f988da), + unchecked ((int) 0x983e5152), unchecked ((int) 0xa831c66d), + unchecked ((int) 0xb00327c8), unchecked ((int) 0xbf597fc7), + unchecked ((int) 0xc6e00bf3), unchecked ((int) 0xd5a79147), + unchecked ((int) 0x06ca6351), unchecked ((int) 0x14292967), + unchecked ((int) 0x27b70a85), unchecked ((int) 0x2e1b2138), + unchecked ((int) 0x4d2c6dfc), unchecked ((int) 0x53380d13), + unchecked ((int) 0x650a7354), unchecked ((int) 0x766a0abb), + unchecked ((int) 0x81c2c92e), unchecked ((int) 0x92722c85), + unchecked ((int) 0xa2bfe8a1), unchecked ((int) 0xa81a664b), + unchecked ((int) 0xc24b8b70), unchecked ((int) 0xc76c51a3), + unchecked ((int) 0xd192e819), unchecked ((int) 0xd6990624), + unchecked ((int) 0xf40e3585), unchecked ((int) 0x106aa070), + unchecked ((int) 0x19a4c116), unchecked ((int) 0x1e376c08), + unchecked ((int) 0x2748774c), unchecked ((int) 0x34b0bcb5), + unchecked ((int) 0x391c0cb3), unchecked ((int) 0x4ed8aa4a), + unchecked ((int) 0x5b9cca4f), unchecked ((int) 0x682e6ff3), + unchecked ((int) 0x748f82ee), unchecked ((int) 0x78a5636f), + unchecked ((int) 0x84c87814), unchecked ((int) 0x8cc70208), + unchecked ((int) 0x90befffa), unchecked ((int) 0xa4506ceb), + unchecked ((int) 0xbef9a3f7), unchecked ((int) 0xc67178f2) + }; + } +} diff --git a/iTechSharp/srcbc/crypto/digests/Sha384Digest.cs b/iTechSharp/srcbc/crypto/digests/Sha384Digest.cs new file mode 100644 index 0000000..0488c40 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/Sha384Digest.cs @@ -0,0 +1,85 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * Draft FIPS 180-2 implementation of SHA-384. Note: As this is + * based on a draft this implementation is subject to change. + * + *
      +     *         block  word  digest
      +     * SHA-1   512    32    160
      +     * SHA-256 512    32    256
      +     * SHA-384 1024   64    384
      +     * SHA-512 1024   64    512
      +     * 
      + */ + public class Sha384Digest + : LongDigest + { + private const int DigestLength = 48; + + public Sha384Digest() + { + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha384Digest( + Sha384Digest t) + : base(t) + { + } + + public override string AlgorithmName + { + get { return "SHA-384"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 8); + UnpackWord(H3, output, outOff + 16); + UnpackWord(H4, output, outOff + 24); + UnpackWord(H5, output, outOff + 32); + UnpackWord(H6, output, outOff + 40); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables + */ + public override void Reset() + { + base.Reset(); + + /* SHA-384 initial hash value + * The first 64 bits of the fractional parts of the square roots + * of the 9th through 16th prime numbers + */ + H1 = unchecked((long) 0xcbbb9d5dc1059ed8L); + H2 = unchecked((long) 0x629a292a367cd507L); + H3 = unchecked((long) 0x9159015a3070dd17L); + H4 = unchecked((long) 0x152fecd8f70e5939L); + H5 = unchecked((long) 0x67332667ffc00b31L); + H6 = unchecked((long) 0x8eb44a8768581511L); + H7 = unchecked((long) 0xdb0c2e0d64f98fa7L); + H8 = unchecked((long) 0x47b5481dbefa4fa4L); + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/Sha512Digest.cs b/iTechSharp/srcbc/crypto/digests/Sha512Digest.cs new file mode 100644 index 0000000..30eefdd --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/Sha512Digest.cs @@ -0,0 +1,88 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * Draft FIPS 180-2 implementation of SHA-512. Note: As this is + * based on a draft this implementation is subject to change. + * + *
      +     *         block  word  digest
      +     * SHA-1   512    32    160
      +     * SHA-256 512    32    256
      +     * SHA-384 1024   64    384
      +     * SHA-512 1024   64    512
      +     * 
      + */ + public class Sha512Digest + : LongDigest + { + private const int DigestLength = 64; + + public Sha512Digest() + { + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha512Digest( + Sha512Digest t) + : base(t) + { + } + + public override string AlgorithmName + { + get { return "SHA-512"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 8); + UnpackWord(H3, output, outOff + 16); + UnpackWord(H4, output, outOff + 24); + UnpackWord(H5, output, outOff + 32); + UnpackWord(H6, output, outOff + 40); + UnpackWord(H7, output, outOff + 48); + UnpackWord(H8, output, outOff + 56); + + Reset(); + + return DigestLength; + + } + + /** + * reset the chaining variables + */ + public override void Reset() + { + base.Reset(); + + /* SHA-512 initial hash value + * The first 64 bits of the fractional parts of the square roots + * of the first eight prime numbers + */ + H1 = unchecked((long) 0x6a09e667f3bcc908L); + H2 = unchecked((long) 0xbb67ae8584caa73bL); + H3 = unchecked((long) 0x3c6ef372fe94f82bL); + H4 = unchecked((long) 0xa54ff53a5f1d36f1L); + H5 = unchecked((long) 0x510e527fade682d1L); + H6 = unchecked((long) 0x9b05688c2b3e6c1fL); + H7 = unchecked((long) 0x1f83d9abfb41bd6bL); + H8 = unchecked((long) 0x5be0cd19137e2179L); + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/ShortenedDigest.cs b/iTechSharp/srcbc/crypto/digests/ShortenedDigest.cs new file mode 100644 index 0000000..9e4d99e --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/ShortenedDigest.cs @@ -0,0 +1,82 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * Wrapper class that reduces the output length of a particular digest to + * only the first n bytes of the digest function. + */ + public class ShortenedDigest + : IDigest + { + private IDigest baseDigest; + private int length; + + /** + * Base constructor. + * + * @param baseDigest underlying digest to use. + * @param length length in bytes of the output of doFinal. + * @exception ArgumentException if baseDigest is null, or length is greater than baseDigest.GetDigestSize(). + */ + public ShortenedDigest( + IDigest baseDigest, + int length) + { + if (baseDigest == null) + { + throw new ArgumentNullException("baseDigest"); + } + + if (length > baseDigest.GetDigestSize()) + { + throw new ArgumentException("baseDigest output not large enough to support length"); + } + + this.baseDigest = baseDigest; + this.length = length; + } + + public string AlgorithmName + { + get { return baseDigest.AlgorithmName + "(" + length * 8 + ")"; } + } + + public int GetDigestSize() + { + return length; + } + + public void Update(byte input) + { + baseDigest.Update(input); + } + + public void BlockUpdate(byte[] input, int inOff, int length) + { + baseDigest.BlockUpdate(input, inOff, length); + } + + public int DoFinal(byte[] output, int outOff) + { + byte[] tmp = new byte[baseDigest.GetDigestSize()]; + + baseDigest.DoFinal(tmp, 0); + + Array.Copy(tmp, 0, output, outOff, length); + + return length; + } + + public void Reset() + { + baseDigest.Reset(); + } + + public int GetByteLength() + { + return baseDigest.GetByteLength(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/TigerDigest.cs b/iTechSharp/srcbc/crypto/digests/TigerDigest.cs new file mode 100644 index 0000000..b8c9a76 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/TigerDigest.cs @@ -0,0 +1,868 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * implementation of Tiger based on: + * + * http://www.cs.technion.ac.il/~biham/Reports/Tiger + */ + public class TigerDigest + : IDigest + { + private const int MyByteLength = 64; + + /* + * S-Boxes. + */ + private static readonly long[] t1 = { + unchecked((long) 0x02AAB17CF7E90C5EL) /* 0 */, unchecked((long) 0xAC424B03E243A8ECL) /* 1 */, + unchecked((long) 0x72CD5BE30DD5FCD3L) /* 2 */, unchecked((long) 0x6D019B93F6F97F3AL) /* 3 */, + unchecked((long) 0xCD9978FFD21F9193L) /* 4 */, unchecked((long) 0x7573A1C9708029E2L) /* 5 */, + unchecked((long) 0xB164326B922A83C3L) /* 6 */, unchecked((long) 0x46883EEE04915870L) /* 7 */, + unchecked((long) 0xEAACE3057103ECE6L) /* 8 */, unchecked((long) 0xC54169B808A3535CL) /* 9 */, + unchecked((long) 0x4CE754918DDEC47CL) /* 10 */, unchecked((long) 0x0AA2F4DFDC0DF40CL) /* 11 */, + unchecked((long) 0x10B76F18A74DBEFAL) /* 12 */, unchecked((long) 0xC6CCB6235AD1AB6AL) /* 13 */, + unchecked((long) 0x13726121572FE2FFL) /* 14 */, unchecked((long) 0x1A488C6F199D921EL) /* 15 */, + unchecked((long) 0x4BC9F9F4DA0007CAL) /* 16 */, unchecked((long) 0x26F5E6F6E85241C7L) /* 17 */, + unchecked((long) 0x859079DBEA5947B6L) /* 18 */, unchecked((long) 0x4F1885C5C99E8C92L) /* 19 */, + unchecked((long) 0xD78E761EA96F864BL) /* 20 */, unchecked((long) 0x8E36428C52B5C17DL) /* 21 */, + unchecked((long) 0x69CF6827373063C1L) /* 22 */, unchecked((long) 0xB607C93D9BB4C56EL) /* 23 */, + unchecked((long) 0x7D820E760E76B5EAL) /* 24 */, unchecked((long) 0x645C9CC6F07FDC42L) /* 25 */, + unchecked((long) 0xBF38A078243342E0L) /* 26 */, unchecked((long) 0x5F6B343C9D2E7D04L) /* 27 */, + unchecked((long) 0xF2C28AEB600B0EC6L) /* 28 */, unchecked((long) 0x6C0ED85F7254BCACL) /* 29 */, + unchecked((long) 0x71592281A4DB4FE5L) /* 30 */, unchecked((long) 0x1967FA69CE0FED9FL) /* 31 */, + unchecked((long) 0xFD5293F8B96545DBL) /* 32 */, unchecked((long) 0xC879E9D7F2A7600BL) /* 33 */, + unchecked((long) 0x860248920193194EL) /* 34 */, unchecked((long) 0xA4F9533B2D9CC0B3L) /* 35 */, + unchecked((long) 0x9053836C15957613L) /* 36 */, unchecked((long) 0xDB6DCF8AFC357BF1L) /* 37 */, + unchecked((long) 0x18BEEA7A7A370F57L) /* 38 */, unchecked((long) 0x037117CA50B99066L) /* 39 */, + unchecked((long) 0x6AB30A9774424A35L) /* 40 */, unchecked((long) 0xF4E92F02E325249BL) /* 41 */, + unchecked((long) 0x7739DB07061CCAE1L) /* 42 */, unchecked((long) 0xD8F3B49CECA42A05L) /* 43 */, + unchecked((long) 0xBD56BE3F51382F73L) /* 44 */, unchecked((long) 0x45FAED5843B0BB28L) /* 45 */, + unchecked((long) 0x1C813D5C11BF1F83L) /* 46 */, unchecked((long) 0x8AF0E4B6D75FA169L) /* 47 */, + unchecked((long) 0x33EE18A487AD9999L) /* 48 */, unchecked((long) 0x3C26E8EAB1C94410L) /* 49 */, + unchecked((long) 0xB510102BC0A822F9L) /* 50 */, unchecked((long) 0x141EEF310CE6123BL) /* 51 */, + unchecked((long) 0xFC65B90059DDB154L) /* 52 */, unchecked((long) 0xE0158640C5E0E607L) /* 53 */, + unchecked((long) 0x884E079826C3A3CFL) /* 54 */, unchecked((long) 0x930D0D9523C535FDL) /* 55 */, + unchecked((long) 0x35638D754E9A2B00L) /* 56 */, unchecked((long) 0x4085FCCF40469DD5L) /* 57 */, + unchecked((long) 0xC4B17AD28BE23A4CL) /* 58 */, unchecked((long) 0xCAB2F0FC6A3E6A2EL) /* 59 */, + unchecked((long) 0x2860971A6B943FCDL) /* 60 */, unchecked((long) 0x3DDE6EE212E30446L) /* 61 */, + unchecked((long) 0x6222F32AE01765AEL) /* 62 */, unchecked((long) 0x5D550BB5478308FEL) /* 63 */, + unchecked((long) 0xA9EFA98DA0EDA22AL) /* 64 */, unchecked((long) 0xC351A71686C40DA7L) /* 65 */, + unchecked((long) 0x1105586D9C867C84L) /* 66 */, unchecked((long) 0xDCFFEE85FDA22853L) /* 67 */, + unchecked((long) 0xCCFBD0262C5EEF76L) /* 68 */, unchecked((long) 0xBAF294CB8990D201L) /* 69 */, + unchecked((long) 0xE69464F52AFAD975L) /* 70 */, unchecked((long) 0x94B013AFDF133E14L) /* 71 */, + unchecked((long) 0x06A7D1A32823C958L) /* 72 */, unchecked((long) 0x6F95FE5130F61119L) /* 73 */, + unchecked((long) 0xD92AB34E462C06C0L) /* 74 */, unchecked((long) 0xED7BDE33887C71D2L) /* 75 */, + unchecked((long) 0x79746D6E6518393EL) /* 76 */, unchecked((long) 0x5BA419385D713329L) /* 77 */, + unchecked((long) 0x7C1BA6B948A97564L) /* 78 */, unchecked((long) 0x31987C197BFDAC67L) /* 79 */, + unchecked((long) 0xDE6C23C44B053D02L) /* 80 */, unchecked((long) 0x581C49FED002D64DL) /* 81 */, + unchecked((long) 0xDD474D6338261571L) /* 82 */, unchecked((long) 0xAA4546C3E473D062L) /* 83 */, + unchecked((long) 0x928FCE349455F860L) /* 84 */, unchecked((long) 0x48161BBACAAB94D9L) /* 85 */, + unchecked((long) 0x63912430770E6F68L) /* 86 */, unchecked((long) 0x6EC8A5E602C6641CL) /* 87 */, + unchecked((long) 0x87282515337DDD2BL) /* 88 */, unchecked((long) 0x2CDA6B42034B701BL) /* 89 */, + unchecked((long) 0xB03D37C181CB096DL) /* 90 */, unchecked((long) 0xE108438266C71C6FL) /* 91 */, + unchecked((long) 0x2B3180C7EB51B255L) /* 92 */, unchecked((long) 0xDF92B82F96C08BBCL) /* 93 */, + unchecked((long) 0x5C68C8C0A632F3BAL) /* 94 */, unchecked((long) 0x5504CC861C3D0556L) /* 95 */, + unchecked((long) 0xABBFA4E55FB26B8FL) /* 96 */, unchecked((long) 0x41848B0AB3BACEB4L) /* 97 */, + unchecked((long) 0xB334A273AA445D32L) /* 98 */, unchecked((long) 0xBCA696F0A85AD881L) /* 99 */, + unchecked((long) 0x24F6EC65B528D56CL) /* 100 */, unchecked((long) 0x0CE1512E90F4524AL) /* 101 */, + unchecked((long) 0x4E9DD79D5506D35AL) /* 102 */, unchecked((long) 0x258905FAC6CE9779L) /* 103 */, + unchecked((long) 0x2019295B3E109B33L) /* 104 */, unchecked((long) 0xF8A9478B73A054CCL) /* 105 */, + unchecked((long) 0x2924F2F934417EB0L) /* 106 */, unchecked((long) 0x3993357D536D1BC4L) /* 107 */, + unchecked((long) 0x38A81AC21DB6FF8BL) /* 108 */, unchecked((long) 0x47C4FBF17D6016BFL) /* 109 */, + unchecked((long) 0x1E0FAADD7667E3F5L) /* 110 */, unchecked((long) 0x7ABCFF62938BEB96L) /* 111 */, + unchecked((long) 0xA78DAD948FC179C9L) /* 112 */, unchecked((long) 0x8F1F98B72911E50DL) /* 113 */, + unchecked((long) 0x61E48EAE27121A91L) /* 114 */, unchecked((long) 0x4D62F7AD31859808L) /* 115 */, + unchecked((long) 0xECEBA345EF5CEAEBL) /* 116 */, unchecked((long) 0xF5CEB25EBC9684CEL) /* 117 */, + unchecked((long) 0xF633E20CB7F76221L) /* 118 */, unchecked((long) 0xA32CDF06AB8293E4L) /* 119 */, + unchecked((long) 0x985A202CA5EE2CA4L) /* 120 */, unchecked((long) 0xCF0B8447CC8A8FB1L) /* 121 */, + unchecked((long) 0x9F765244979859A3L) /* 122 */, unchecked((long) 0xA8D516B1A1240017L) /* 123 */, + unchecked((long) 0x0BD7BA3EBB5DC726L) /* 124 */, unchecked((long) 0xE54BCA55B86ADB39L) /* 125 */, + unchecked((long) 0x1D7A3AFD6C478063L) /* 126 */, unchecked((long) 0x519EC608E7669EDDL) /* 127 */, + unchecked((long) 0x0E5715A2D149AA23L) /* 128 */, unchecked((long) 0x177D4571848FF194L) /* 129 */, + unchecked((long) 0xEEB55F3241014C22L) /* 130 */, unchecked((long) 0x0F5E5CA13A6E2EC2L) /* 131 */, + unchecked((long) 0x8029927B75F5C361L) /* 132 */, unchecked((long) 0xAD139FABC3D6E436L) /* 133 */, + unchecked((long) 0x0D5DF1A94CCF402FL) /* 134 */, unchecked((long) 0x3E8BD948BEA5DFC8L) /* 135 */, + unchecked((long) 0xA5A0D357BD3FF77EL) /* 136 */, unchecked((long) 0xA2D12E251F74F645L) /* 137 */, + unchecked((long) 0x66FD9E525E81A082L) /* 138 */, unchecked((long) 0x2E0C90CE7F687A49L) /* 139 */, + unchecked((long) 0xC2E8BCBEBA973BC5L) /* 140 */, unchecked((long) 0x000001BCE509745FL) /* 141 */, + unchecked((long) 0x423777BBE6DAB3D6L) /* 142 */, unchecked((long) 0xD1661C7EAEF06EB5L) /* 143 */, + unchecked((long) 0xA1781F354DAACFD8L) /* 144 */, unchecked((long) 0x2D11284A2B16AFFCL) /* 145 */, + unchecked((long) 0xF1FC4F67FA891D1FL) /* 146 */, unchecked((long) 0x73ECC25DCB920ADAL) /* 147 */, + unchecked((long) 0xAE610C22C2A12651L) /* 148 */, unchecked((long) 0x96E0A810D356B78AL) /* 149 */, + unchecked((long) 0x5A9A381F2FE7870FL) /* 150 */, unchecked((long) 0xD5AD62EDE94E5530L) /* 151 */, + unchecked((long) 0xD225E5E8368D1427L) /* 152 */, unchecked((long) 0x65977B70C7AF4631L) /* 153 */, + unchecked((long) 0x99F889B2DE39D74FL) /* 154 */, unchecked((long) 0x233F30BF54E1D143L) /* 155 */, + unchecked((long) 0x9A9675D3D9A63C97L) /* 156 */, unchecked((long) 0x5470554FF334F9A8L) /* 157 */, + unchecked((long) 0x166ACB744A4F5688L) /* 158 */, unchecked((long) 0x70C74CAAB2E4AEADL) /* 159 */, + unchecked((long) 0xF0D091646F294D12L) /* 160 */, unchecked((long) 0x57B82A89684031D1L) /* 161 */, + unchecked((long) 0xEFD95A5A61BE0B6BL) /* 162 */, unchecked((long) 0x2FBD12E969F2F29AL) /* 163 */, + unchecked((long) 0x9BD37013FEFF9FE8L) /* 164 */, unchecked((long) 0x3F9B0404D6085A06L) /* 165 */, + unchecked((long) 0x4940C1F3166CFE15L) /* 166 */, unchecked((long) 0x09542C4DCDF3DEFBL) /* 167 */, + unchecked((long) 0xB4C5218385CD5CE3L) /* 168 */, unchecked((long) 0xC935B7DC4462A641L) /* 169 */, + unchecked((long) 0x3417F8A68ED3B63FL) /* 170 */, unchecked((long) 0xB80959295B215B40L) /* 171 */, + unchecked((long) 0xF99CDAEF3B8C8572L) /* 172 */, unchecked((long) 0x018C0614F8FCB95DL) /* 173 */, + unchecked((long) 0x1B14ACCD1A3ACDF3L) /* 174 */, unchecked((long) 0x84D471F200BB732DL) /* 175 */, + unchecked((long) 0xC1A3110E95E8DA16L) /* 176 */, unchecked((long) 0x430A7220BF1A82B8L) /* 177 */, + unchecked((long) 0xB77E090D39DF210EL) /* 178 */, unchecked((long) 0x5EF4BD9F3CD05E9DL) /* 179 */, + unchecked((long) 0x9D4FF6DA7E57A444L) /* 180 */, unchecked((long) 0xDA1D60E183D4A5F8L) /* 181 */, + unchecked((long) 0xB287C38417998E47L) /* 182 */, unchecked((long) 0xFE3EDC121BB31886L) /* 183 */, + unchecked((long) 0xC7FE3CCC980CCBEFL) /* 184 */, unchecked((long) 0xE46FB590189BFD03L) /* 185 */, + unchecked((long) 0x3732FD469A4C57DCL) /* 186 */, unchecked((long) 0x7EF700A07CF1AD65L) /* 187 */, + unchecked((long) 0x59C64468A31D8859L) /* 188 */, unchecked((long) 0x762FB0B4D45B61F6L) /* 189 */, + unchecked((long) 0x155BAED099047718L) /* 190 */, unchecked((long) 0x68755E4C3D50BAA6L) /* 191 */, + unchecked((long) 0xE9214E7F22D8B4DFL) /* 192 */, unchecked((long) 0x2ADDBF532EAC95F4L) /* 193 */, + unchecked((long) 0x32AE3909B4BD0109L) /* 194 */, unchecked((long) 0x834DF537B08E3450L) /* 195 */, + unchecked((long) 0xFA209DA84220728DL) /* 196 */, unchecked((long) 0x9E691D9B9EFE23F7L) /* 197 */, + unchecked((long) 0x0446D288C4AE8D7FL) /* 198 */, unchecked((long) 0x7B4CC524E169785BL) /* 199 */, + unchecked((long) 0x21D87F0135CA1385L) /* 200 */, unchecked((long) 0xCEBB400F137B8AA5L) /* 201 */, + unchecked((long) 0x272E2B66580796BEL) /* 202 */, unchecked((long) 0x3612264125C2B0DEL) /* 203 */, + unchecked((long) 0x057702BDAD1EFBB2L) /* 204 */, unchecked((long) 0xD4BABB8EACF84BE9L) /* 205 */, + unchecked((long) 0x91583139641BC67BL) /* 206 */, unchecked((long) 0x8BDC2DE08036E024L) /* 207 */, + unchecked((long) 0x603C8156F49F68EDL) /* 208 */, unchecked((long) 0xF7D236F7DBEF5111L) /* 209 */, + unchecked((long) 0x9727C4598AD21E80L) /* 210 */, unchecked((long) 0xA08A0896670A5FD7L) /* 211 */, + unchecked((long) 0xCB4A8F4309EBA9CBL) /* 212 */, unchecked((long) 0x81AF564B0F7036A1L) /* 213 */, + unchecked((long) 0xC0B99AA778199ABDL) /* 214 */, unchecked((long) 0x959F1EC83FC8E952L) /* 215 */, + unchecked((long) 0x8C505077794A81B9L) /* 216 */, unchecked((long) 0x3ACAAF8F056338F0L) /* 217 */, + unchecked((long) 0x07B43F50627A6778L) /* 218 */, unchecked((long) 0x4A44AB49F5ECCC77L) /* 219 */, + unchecked((long) 0x3BC3D6E4B679EE98L) /* 220 */, unchecked((long) 0x9CC0D4D1CF14108CL) /* 221 */, + unchecked((long) 0x4406C00B206BC8A0L) /* 222 */, unchecked((long) 0x82A18854C8D72D89L) /* 223 */, + unchecked((long) 0x67E366B35C3C432CL) /* 224 */, unchecked((long) 0xB923DD61102B37F2L) /* 225 */, + unchecked((long) 0x56AB2779D884271DL) /* 226 */, unchecked((long) 0xBE83E1B0FF1525AFL) /* 227 */, + unchecked((long) 0xFB7C65D4217E49A9L) /* 228 */, unchecked((long) 0x6BDBE0E76D48E7D4L) /* 229 */, + unchecked((long) 0x08DF828745D9179EL) /* 230 */, unchecked((long) 0x22EA6A9ADD53BD34L) /* 231 */, + unchecked((long) 0xE36E141C5622200AL) /* 232 */, unchecked((long) 0x7F805D1B8CB750EEL) /* 233 */, + unchecked((long) 0xAFE5C7A59F58E837L) /* 234 */, unchecked((long) 0xE27F996A4FB1C23CL) /* 235 */, + unchecked((long) 0xD3867DFB0775F0D0L) /* 236 */, unchecked((long) 0xD0E673DE6E88891AL) /* 237 */, + unchecked((long) 0x123AEB9EAFB86C25L) /* 238 */, unchecked((long) 0x30F1D5D5C145B895L) /* 239 */, + unchecked((long) 0xBB434A2DEE7269E7L) /* 240 */, unchecked((long) 0x78CB67ECF931FA38L) /* 241 */, + unchecked((long) 0xF33B0372323BBF9CL) /* 242 */, unchecked((long) 0x52D66336FB279C74L) /* 243 */, + unchecked((long) 0x505F33AC0AFB4EAAL) /* 244 */, unchecked((long) 0xE8A5CD99A2CCE187L) /* 245 */, + unchecked((long) 0x534974801E2D30BBL) /* 246 */, unchecked((long) 0x8D2D5711D5876D90L) /* 247 */, + unchecked((long) 0x1F1A412891BC038EL) /* 248 */, unchecked((long) 0xD6E2E71D82E56648L) /* 249 */, + unchecked((long) 0x74036C3A497732B7L) /* 250 */, unchecked((long) 0x89B67ED96361F5ABL) /* 251 */, + unchecked((long) 0xFFED95D8F1EA02A2L) /* 252 */, unchecked((long) 0xE72B3BD61464D43DL) /* 253 */, + unchecked((long) 0xA6300F170BDC4820L) /* 254 */, unchecked((long) 0xEBC18760ED78A77AL) /* 255 */, + }; + + private static readonly long[] t2 = { + unchecked((long) 0xE6A6BE5A05A12138L) /* 256 */, unchecked((long) 0xB5A122A5B4F87C98L) /* 257 */, + unchecked((long) 0x563C6089140B6990L) /* 258 */, unchecked((long) 0x4C46CB2E391F5DD5L) /* 259 */, + unchecked((long) 0xD932ADDBC9B79434L) /* 260 */, unchecked((long) 0x08EA70E42015AFF5L) /* 261 */, + unchecked((long) 0xD765A6673E478CF1L) /* 262 */, unchecked((long) 0xC4FB757EAB278D99L) /* 263 */, + unchecked((long) 0xDF11C6862D6E0692L) /* 264 */, unchecked((long) 0xDDEB84F10D7F3B16L) /* 265 */, + unchecked((long) 0x6F2EF604A665EA04L) /* 266 */, unchecked((long) 0x4A8E0F0FF0E0DFB3L) /* 267 */, + unchecked((long) 0xA5EDEEF83DBCBA51L) /* 268 */, unchecked((long) 0xFC4F0A2A0EA4371EL) /* 269 */, + unchecked((long) 0xE83E1DA85CB38429L) /* 270 */, unchecked((long) 0xDC8FF882BA1B1CE2L) /* 271 */, + unchecked((long) 0xCD45505E8353E80DL) /* 272 */, unchecked((long) 0x18D19A00D4DB0717L) /* 273 */, + unchecked((long) 0x34A0CFEDA5F38101L) /* 274 */, unchecked((long) 0x0BE77E518887CAF2L) /* 275 */, + unchecked((long) 0x1E341438B3C45136L) /* 276 */, unchecked((long) 0xE05797F49089CCF9L) /* 277 */, + unchecked((long) 0xFFD23F9DF2591D14L) /* 278 */, unchecked((long) 0x543DDA228595C5CDL) /* 279 */, + unchecked((long) 0x661F81FD99052A33L) /* 280 */, unchecked((long) 0x8736E641DB0F7B76L) /* 281 */, + unchecked((long) 0x15227725418E5307L) /* 282 */, unchecked((long) 0xE25F7F46162EB2FAL) /* 283 */, + unchecked((long) 0x48A8B2126C13D9FEL) /* 284 */, unchecked((long) 0xAFDC541792E76EEAL) /* 285 */, + unchecked((long) 0x03D912BFC6D1898FL) /* 286 */, unchecked((long) 0x31B1AAFA1B83F51BL) /* 287 */, + unchecked((long) 0xF1AC2796E42AB7D9L) /* 288 */, unchecked((long) 0x40A3A7D7FCD2EBACL) /* 289 */, + unchecked((long) 0x1056136D0AFBBCC5L) /* 290 */, unchecked((long) 0x7889E1DD9A6D0C85L) /* 291 */, + unchecked((long) 0xD33525782A7974AAL) /* 292 */, unchecked((long) 0xA7E25D09078AC09BL) /* 293 */, + unchecked((long) 0xBD4138B3EAC6EDD0L) /* 294 */, unchecked((long) 0x920ABFBE71EB9E70L) /* 295 */, + unchecked((long) 0xA2A5D0F54FC2625CL) /* 296 */, unchecked((long) 0xC054E36B0B1290A3L) /* 297 */, + unchecked((long) 0xF6DD59FF62FE932BL) /* 298 */, unchecked((long) 0x3537354511A8AC7DL) /* 299 */, + unchecked((long) 0xCA845E9172FADCD4L) /* 300 */, unchecked((long) 0x84F82B60329D20DCL) /* 301 */, + unchecked((long) 0x79C62CE1CD672F18L) /* 302 */, unchecked((long) 0x8B09A2ADD124642CL) /* 303 */, + unchecked((long) 0xD0C1E96A19D9E726L) /* 304 */, unchecked((long) 0x5A786A9B4BA9500CL) /* 305 */, + unchecked((long) 0x0E020336634C43F3L) /* 306 */, unchecked((long) 0xC17B474AEB66D822L) /* 307 */, + unchecked((long) 0x6A731AE3EC9BAAC2L) /* 308 */, unchecked((long) 0x8226667AE0840258L) /* 309 */, + unchecked((long) 0x67D4567691CAECA5L) /* 310 */, unchecked((long) 0x1D94155C4875ADB5L) /* 311 */, + unchecked((long) 0x6D00FD985B813FDFL) /* 312 */, unchecked((long) 0x51286EFCB774CD06L) /* 313 */, + unchecked((long) 0x5E8834471FA744AFL) /* 314 */, unchecked((long) 0xF72CA0AEE761AE2EL) /* 315 */, + unchecked((long) 0xBE40E4CDAEE8E09AL) /* 316 */, unchecked((long) 0xE9970BBB5118F665L) /* 317 */, + unchecked((long) 0x726E4BEB33DF1964L) /* 318 */, unchecked((long) 0x703B000729199762L) /* 319 */, + unchecked((long) 0x4631D816F5EF30A7L) /* 320 */, unchecked((long) 0xB880B5B51504A6BEL) /* 321 */, + unchecked((long) 0x641793C37ED84B6CL) /* 322 */, unchecked((long) 0x7B21ED77F6E97D96L) /* 323 */, + unchecked((long) 0x776306312EF96B73L) /* 324 */, unchecked((long) 0xAE528948E86FF3F4L) /* 325 */, + unchecked((long) 0x53DBD7F286A3F8F8L) /* 326 */, unchecked((long) 0x16CADCE74CFC1063L) /* 327 */, + unchecked((long) 0x005C19BDFA52C6DDL) /* 328 */, unchecked((long) 0x68868F5D64D46AD3L) /* 329 */, + unchecked((long) 0x3A9D512CCF1E186AL) /* 330 */, unchecked((long) 0x367E62C2385660AEL) /* 331 */, + unchecked((long) 0xE359E7EA77DCB1D7L) /* 332 */, unchecked((long) 0x526C0773749ABE6EL) /* 333 */, + unchecked((long) 0x735AE5F9D09F734BL) /* 334 */, unchecked((long) 0x493FC7CC8A558BA8L) /* 335 */, + unchecked((long) 0xB0B9C1533041AB45L) /* 336 */, unchecked((long) 0x321958BA470A59BDL) /* 337 */, + unchecked((long) 0x852DB00B5F46C393L) /* 338 */, unchecked((long) 0x91209B2BD336B0E5L) /* 339 */, + unchecked((long) 0x6E604F7D659EF19FL) /* 340 */, unchecked((long) 0xB99A8AE2782CCB24L) /* 341 */, + unchecked((long) 0xCCF52AB6C814C4C7L) /* 342 */, unchecked((long) 0x4727D9AFBE11727BL) /* 343 */, + unchecked((long) 0x7E950D0C0121B34DL) /* 344 */, unchecked((long) 0x756F435670AD471FL) /* 345 */, + unchecked((long) 0xF5ADD442615A6849L) /* 346 */, unchecked((long) 0x4E87E09980B9957AL) /* 347 */, + unchecked((long) 0x2ACFA1DF50AEE355L) /* 348 */, unchecked((long) 0xD898263AFD2FD556L) /* 349 */, + unchecked((long) 0xC8F4924DD80C8FD6L) /* 350 */, unchecked((long) 0xCF99CA3D754A173AL) /* 351 */, + unchecked((long) 0xFE477BACAF91BF3CL) /* 352 */, unchecked((long) 0xED5371F6D690C12DL) /* 353 */, + unchecked((long) 0x831A5C285E687094L) /* 354 */, unchecked((long) 0xC5D3C90A3708A0A4L) /* 355 */, + unchecked((long) 0x0F7F903717D06580L) /* 356 */, unchecked((long) 0x19F9BB13B8FDF27FL) /* 357 */, + unchecked((long) 0xB1BD6F1B4D502843L) /* 358 */, unchecked((long) 0x1C761BA38FFF4012L) /* 359 */, + unchecked((long) 0x0D1530C4E2E21F3BL) /* 360 */, unchecked((long) 0x8943CE69A7372C8AL) /* 361 */, + unchecked((long) 0xE5184E11FEB5CE66L) /* 362 */, unchecked((long) 0x618BDB80BD736621L) /* 363 */, + unchecked((long) 0x7D29BAD68B574D0BL) /* 364 */, unchecked((long) 0x81BB613E25E6FE5BL) /* 365 */, + unchecked((long) 0x071C9C10BC07913FL) /* 366 */, unchecked((long) 0xC7BEEB7909AC2D97L) /* 367 */, + unchecked((long) 0xC3E58D353BC5D757L) /* 368 */, unchecked((long) 0xEB017892F38F61E8L) /* 369 */, + unchecked((long) 0xD4EFFB9C9B1CC21AL) /* 370 */, unchecked((long) 0x99727D26F494F7ABL) /* 371 */, + unchecked((long) 0xA3E063A2956B3E03L) /* 372 */, unchecked((long) 0x9D4A8B9A4AA09C30L) /* 373 */, + unchecked((long) 0x3F6AB7D500090FB4L) /* 374 */, unchecked((long) 0x9CC0F2A057268AC0L) /* 375 */, + unchecked((long) 0x3DEE9D2DEDBF42D1L) /* 376 */, unchecked((long) 0x330F49C87960A972L) /* 377 */, + unchecked((long) 0xC6B2720287421B41L) /* 378 */, unchecked((long) 0x0AC59EC07C00369CL) /* 379 */, + unchecked((long) 0xEF4EAC49CB353425L) /* 380 */, unchecked((long) 0xF450244EEF0129D8L) /* 381 */, + unchecked((long) 0x8ACC46E5CAF4DEB6L) /* 382 */, unchecked((long) 0x2FFEAB63989263F7L) /* 383 */, + unchecked((long) 0x8F7CB9FE5D7A4578L) /* 384 */, unchecked((long) 0x5BD8F7644E634635L) /* 385 */, + unchecked((long) 0x427A7315BF2DC900L) /* 386 */, unchecked((long) 0x17D0C4AA2125261CL) /* 387 */, + unchecked((long) 0x3992486C93518E50L) /* 388 */, unchecked((long) 0xB4CBFEE0A2D7D4C3L) /* 389 */, + unchecked((long) 0x7C75D6202C5DDD8DL) /* 390 */, unchecked((long) 0xDBC295D8E35B6C61L) /* 391 */, + unchecked((long) 0x60B369D302032B19L) /* 392 */, unchecked((long) 0xCE42685FDCE44132L) /* 393 */, + unchecked((long) 0x06F3DDB9DDF65610L) /* 394 */, unchecked((long) 0x8EA4D21DB5E148F0L) /* 395 */, + unchecked((long) 0x20B0FCE62FCD496FL) /* 396 */, unchecked((long) 0x2C1B912358B0EE31L) /* 397 */, + unchecked((long) 0xB28317B818F5A308L) /* 398 */, unchecked((long) 0xA89C1E189CA6D2CFL) /* 399 */, + unchecked((long) 0x0C6B18576AAADBC8L) /* 400 */, unchecked((long) 0xB65DEAA91299FAE3L) /* 401 */, + unchecked((long) 0xFB2B794B7F1027E7L) /* 402 */, unchecked((long) 0x04E4317F443B5BEBL) /* 403 */, + unchecked((long) 0x4B852D325939D0A6L) /* 404 */, unchecked((long) 0xD5AE6BEEFB207FFCL) /* 405 */, + unchecked((long) 0x309682B281C7D374L) /* 406 */, unchecked((long) 0xBAE309A194C3B475L) /* 407 */, + unchecked((long) 0x8CC3F97B13B49F05L) /* 408 */, unchecked((long) 0x98A9422FF8293967L) /* 409 */, + unchecked((long) 0x244B16B01076FF7CL) /* 410 */, unchecked((long) 0xF8BF571C663D67EEL) /* 411 */, + unchecked((long) 0x1F0D6758EEE30DA1L) /* 412 */, unchecked((long) 0xC9B611D97ADEB9B7L) /* 413 */, + unchecked((long) 0xB7AFD5887B6C57A2L) /* 414 */, unchecked((long) 0x6290AE846B984FE1L) /* 415 */, + unchecked((long) 0x94DF4CDEACC1A5FDL) /* 416 */, unchecked((long) 0x058A5BD1C5483AFFL) /* 417 */, + unchecked((long) 0x63166CC142BA3C37L) /* 418 */, unchecked((long) 0x8DB8526EB2F76F40L) /* 419 */, + unchecked((long) 0xE10880036F0D6D4EL) /* 420 */, unchecked((long) 0x9E0523C9971D311DL) /* 421 */, + unchecked((long) 0x45EC2824CC7CD691L) /* 422 */, unchecked((long) 0x575B8359E62382C9L) /* 423 */, + unchecked((long) 0xFA9E400DC4889995L) /* 424 */, unchecked((long) 0xD1823ECB45721568L) /* 425 */, + unchecked((long) 0xDAFD983B8206082FL) /* 426 */, unchecked((long) 0xAA7D29082386A8CBL) /* 427 */, + unchecked((long) 0x269FCD4403B87588L) /* 428 */, unchecked((long) 0x1B91F5F728BDD1E0L) /* 429 */, + unchecked((long) 0xE4669F39040201F6L) /* 430 */, unchecked((long) 0x7A1D7C218CF04ADEL) /* 431 */, + unchecked((long) 0x65623C29D79CE5CEL) /* 432 */, unchecked((long) 0x2368449096C00BB1L) /* 433 */, + unchecked((long) 0xAB9BF1879DA503BAL) /* 434 */, unchecked((long) 0xBC23ECB1A458058EL) /* 435 */, + unchecked((long) 0x9A58DF01BB401ECCL) /* 436 */, unchecked((long) 0xA070E868A85F143DL) /* 437 */, + unchecked((long) 0x4FF188307DF2239EL) /* 438 */, unchecked((long) 0x14D565B41A641183L) /* 439 */, + unchecked((long) 0xEE13337452701602L) /* 440 */, unchecked((long) 0x950E3DCF3F285E09L) /* 441 */, + unchecked((long) 0x59930254B9C80953L) /* 442 */, unchecked((long) 0x3BF299408930DA6DL) /* 443 */, + unchecked((long) 0xA955943F53691387L) /* 444 */, unchecked((long) 0xA15EDECAA9CB8784L) /* 445 */, + unchecked((long) 0x29142127352BE9A0L) /* 446 */, unchecked((long) 0x76F0371FFF4E7AFBL) /* 447 */, + unchecked((long) 0x0239F450274F2228L) /* 448 */, unchecked((long) 0xBB073AF01D5E868BL) /* 449 */, + unchecked((long) 0xBFC80571C10E96C1L) /* 450 */, unchecked((long) 0xD267088568222E23L) /* 451 */, + unchecked((long) 0x9671A3D48E80B5B0L) /* 452 */, unchecked((long) 0x55B5D38AE193BB81L) /* 453 */, + unchecked((long) 0x693AE2D0A18B04B8L) /* 454 */, unchecked((long) 0x5C48B4ECADD5335FL) /* 455 */, + unchecked((long) 0xFD743B194916A1CAL) /* 456 */, unchecked((long) 0x2577018134BE98C4L) /* 457 */, + unchecked((long) 0xE77987E83C54A4ADL) /* 458 */, unchecked((long) 0x28E11014DA33E1B9L) /* 459 */, + unchecked((long) 0x270CC59E226AA213L) /* 460 */, unchecked((long) 0x71495F756D1A5F60L) /* 461 */, + unchecked((long) 0x9BE853FB60AFEF77L) /* 462 */, unchecked((long) 0xADC786A7F7443DBFL) /* 463 */, + unchecked((long) 0x0904456173B29A82L) /* 464 */, unchecked((long) 0x58BC7A66C232BD5EL) /* 465 */, + unchecked((long) 0xF306558C673AC8B2L) /* 466 */, unchecked((long) 0x41F639C6B6C9772AL) /* 467 */, + unchecked((long) 0x216DEFE99FDA35DAL) /* 468 */, unchecked((long) 0x11640CC71C7BE615L) /* 469 */, + unchecked((long) 0x93C43694565C5527L) /* 470 */, unchecked((long) 0xEA038E6246777839L) /* 471 */, + unchecked((long) 0xF9ABF3CE5A3E2469L) /* 472 */, unchecked((long) 0x741E768D0FD312D2L) /* 473 */, + unchecked((long) 0x0144B883CED652C6L) /* 474 */, unchecked((long) 0xC20B5A5BA33F8552L) /* 475 */, + unchecked((long) 0x1AE69633C3435A9DL) /* 476 */, unchecked((long) 0x97A28CA4088CFDECL) /* 477 */, + unchecked((long) 0x8824A43C1E96F420L) /* 478 */, unchecked((long) 0x37612FA66EEEA746L) /* 479 */, + unchecked((long) 0x6B4CB165F9CF0E5AL) /* 480 */, unchecked((long) 0x43AA1C06A0ABFB4AL) /* 481 */, + unchecked((long) 0x7F4DC26FF162796BL) /* 482 */, unchecked((long) 0x6CBACC8E54ED9B0FL) /* 483 */, + unchecked((long) 0xA6B7FFEFD2BB253EL) /* 484 */, unchecked((long) 0x2E25BC95B0A29D4FL) /* 485 */, + unchecked((long) 0x86D6A58BDEF1388CL) /* 486 */, unchecked((long) 0xDED74AC576B6F054L) /* 487 */, + unchecked((long) 0x8030BDBC2B45805DL) /* 488 */, unchecked((long) 0x3C81AF70E94D9289L) /* 489 */, + unchecked((long) 0x3EFF6DDA9E3100DBL) /* 490 */, unchecked((long) 0xB38DC39FDFCC8847L) /* 491 */, + unchecked((long) 0x123885528D17B87EL) /* 492 */, unchecked((long) 0xF2DA0ED240B1B642L) /* 493 */, + unchecked((long) 0x44CEFADCD54BF9A9L) /* 494 */, unchecked((long) 0x1312200E433C7EE6L) /* 495 */, + unchecked((long) 0x9FFCC84F3A78C748L) /* 496 */, unchecked((long) 0xF0CD1F72248576BBL) /* 497 */, + unchecked((long) 0xEC6974053638CFE4L) /* 498 */, unchecked((long) 0x2BA7B67C0CEC4E4CL) /* 499 */, + unchecked((long) 0xAC2F4DF3E5CE32EDL) /* 500 */, unchecked((long) 0xCB33D14326EA4C11L) /* 501 */, + unchecked((long) 0xA4E9044CC77E58BCL) /* 502 */, unchecked((long) 0x5F513293D934FCEFL) /* 503 */, + unchecked((long) 0x5DC9645506E55444L) /* 504 */, unchecked((long) 0x50DE418F317DE40AL) /* 505 */, + unchecked((long) 0x388CB31A69DDE259L) /* 506 */, unchecked((long) 0x2DB4A83455820A86L) /* 507 */, + unchecked((long) 0x9010A91E84711AE9L) /* 508 */, unchecked((long) 0x4DF7F0B7B1498371L) /* 509 */, + unchecked((long) 0xD62A2EABC0977179L) /* 510 */, unchecked((long) 0x22FAC097AA8D5C0EL) /* 511 */, + }; + + private static readonly long[] t3 = { + unchecked((long) 0xF49FCC2FF1DAF39BL) /* 512 */, unchecked((long) 0x487FD5C66FF29281L) /* 513 */, + unchecked((long) 0xE8A30667FCDCA83FL) /* 514 */, unchecked((long) 0x2C9B4BE3D2FCCE63L) /* 515 */, + unchecked((long) 0xDA3FF74B93FBBBC2L) /* 516 */, unchecked((long) 0x2FA165D2FE70BA66L) /* 517 */, + unchecked((long) 0xA103E279970E93D4L) /* 518 */, unchecked((long) 0xBECDEC77B0E45E71L) /* 519 */, + unchecked((long) 0xCFB41E723985E497L) /* 520 */, unchecked((long) 0xB70AAA025EF75017L) /* 521 */, + unchecked((long) 0xD42309F03840B8E0L) /* 522 */, unchecked((long) 0x8EFC1AD035898579L) /* 523 */, + unchecked((long) 0x96C6920BE2B2ABC5L) /* 524 */, unchecked((long) 0x66AF4163375A9172L) /* 525 */, + unchecked((long) 0x2174ABDCCA7127FBL) /* 526 */, unchecked((long) 0xB33CCEA64A72FF41L) /* 527 */, + unchecked((long) 0xF04A4933083066A5L) /* 528 */, unchecked((long) 0x8D970ACDD7289AF5L) /* 529 */, + unchecked((long) 0x8F96E8E031C8C25EL) /* 530 */, unchecked((long) 0xF3FEC02276875D47L) /* 531 */, + unchecked((long) 0xEC7BF310056190DDL) /* 532 */, unchecked((long) 0xF5ADB0AEBB0F1491L) /* 533 */, + unchecked((long) 0x9B50F8850FD58892L) /* 534 */, unchecked((long) 0x4975488358B74DE8L) /* 535 */, + unchecked((long) 0xA3354FF691531C61L) /* 536 */, unchecked((long) 0x0702BBE481D2C6EEL) /* 537 */, + unchecked((long) 0x89FB24057DEDED98L) /* 538 */, unchecked((long) 0xAC3075138596E902L) /* 539 */, + unchecked((long) 0x1D2D3580172772EDL) /* 540 */, unchecked((long) 0xEB738FC28E6BC30DL) /* 541 */, + unchecked((long) 0x5854EF8F63044326L) /* 542 */, unchecked((long) 0x9E5C52325ADD3BBEL) /* 543 */, + unchecked((long) 0x90AA53CF325C4623L) /* 544 */, unchecked((long) 0xC1D24D51349DD067L) /* 545 */, + unchecked((long) 0x2051CFEEA69EA624L) /* 546 */, unchecked((long) 0x13220F0A862E7E4FL) /* 547 */, + unchecked((long) 0xCE39399404E04864L) /* 548 */, unchecked((long) 0xD9C42CA47086FCB7L) /* 549 */, + unchecked((long) 0x685AD2238A03E7CCL) /* 550 */, unchecked((long) 0x066484B2AB2FF1DBL) /* 551 */, + unchecked((long) 0xFE9D5D70EFBF79ECL) /* 552 */, unchecked((long) 0x5B13B9DD9C481854L) /* 553 */, + unchecked((long) 0x15F0D475ED1509ADL) /* 554 */, unchecked((long) 0x0BEBCD060EC79851L) /* 555 */, + unchecked((long) 0xD58C6791183AB7F8L) /* 556 */, unchecked((long) 0xD1187C5052F3EEE4L) /* 557 */, + unchecked((long) 0xC95D1192E54E82FFL) /* 558 */, unchecked((long) 0x86EEA14CB9AC6CA2L) /* 559 */, + unchecked((long) 0x3485BEB153677D5DL) /* 560 */, unchecked((long) 0xDD191D781F8C492AL) /* 561 */, + unchecked((long) 0xF60866BAA784EBF9L) /* 562 */, unchecked((long) 0x518F643BA2D08C74L) /* 563 */, + unchecked((long) 0x8852E956E1087C22L) /* 564 */, unchecked((long) 0xA768CB8DC410AE8DL) /* 565 */, + unchecked((long) 0x38047726BFEC8E1AL) /* 566 */, unchecked((long) 0xA67738B4CD3B45AAL) /* 567 */, + unchecked((long) 0xAD16691CEC0DDE19L) /* 568 */, unchecked((long) 0xC6D4319380462E07L) /* 569 */, + unchecked((long) 0xC5A5876D0BA61938L) /* 570 */, unchecked((long) 0x16B9FA1FA58FD840L) /* 571 */, + unchecked((long) 0x188AB1173CA74F18L) /* 572 */, unchecked((long) 0xABDA2F98C99C021FL) /* 573 */, + unchecked((long) 0x3E0580AB134AE816L) /* 574 */, unchecked((long) 0x5F3B05B773645ABBL) /* 575 */, + unchecked((long) 0x2501A2BE5575F2F6L) /* 576 */, unchecked((long) 0x1B2F74004E7E8BA9L) /* 577 */, + unchecked((long) 0x1CD7580371E8D953L) /* 578 */, unchecked((long) 0x7F6ED89562764E30L) /* 579 */, + unchecked((long) 0xB15926FF596F003DL) /* 580 */, unchecked((long) 0x9F65293DA8C5D6B9L) /* 581 */, + unchecked((long) 0x6ECEF04DD690F84CL) /* 582 */, unchecked((long) 0x4782275FFF33AF88L) /* 583 */, + unchecked((long) 0xE41433083F820801L) /* 584 */, unchecked((long) 0xFD0DFE409A1AF9B5L) /* 585 */, + unchecked((long) 0x4325A3342CDB396BL) /* 586 */, unchecked((long) 0x8AE77E62B301B252L) /* 587 */, + unchecked((long) 0xC36F9E9F6655615AL) /* 588 */, unchecked((long) 0x85455A2D92D32C09L) /* 589 */, + unchecked((long) 0xF2C7DEA949477485L) /* 590 */, unchecked((long) 0x63CFB4C133A39EBAL) /* 591 */, + unchecked((long) 0x83B040CC6EBC5462L) /* 592 */, unchecked((long) 0x3B9454C8FDB326B0L) /* 593 */, + unchecked((long) 0x56F56A9E87FFD78CL) /* 594 */, unchecked((long) 0x2DC2940D99F42BC6L) /* 595 */, + unchecked((long) 0x98F7DF096B096E2DL) /* 596 */, unchecked((long) 0x19A6E01E3AD852BFL) /* 597 */, + unchecked((long) 0x42A99CCBDBD4B40BL) /* 598 */, unchecked((long) 0xA59998AF45E9C559L) /* 599 */, + unchecked((long) 0x366295E807D93186L) /* 600 */, unchecked((long) 0x6B48181BFAA1F773L) /* 601 */, + unchecked((long) 0x1FEC57E2157A0A1DL) /* 602 */, unchecked((long) 0x4667446AF6201AD5L) /* 603 */, + unchecked((long) 0xE615EBCACFB0F075L) /* 604 */, unchecked((long) 0xB8F31F4F68290778L) /* 605 */, + unchecked((long) 0x22713ED6CE22D11EL) /* 606 */, unchecked((long) 0x3057C1A72EC3C93BL) /* 607 */, + unchecked((long) 0xCB46ACC37C3F1F2FL) /* 608 */, unchecked((long) 0xDBB893FD02AAF50EL) /* 609 */, + unchecked((long) 0x331FD92E600B9FCFL) /* 610 */, unchecked((long) 0xA498F96148EA3AD6L) /* 611 */, + unchecked((long) 0xA8D8426E8B6A83EAL) /* 612 */, unchecked((long) 0xA089B274B7735CDCL) /* 613 */, + unchecked((long) 0x87F6B3731E524A11L) /* 614 */, unchecked((long) 0x118808E5CBC96749L) /* 615 */, + unchecked((long) 0x9906E4C7B19BD394L) /* 616 */, unchecked((long) 0xAFED7F7E9B24A20CL) /* 617 */, + unchecked((long) 0x6509EADEEB3644A7L) /* 618 */, unchecked((long) 0x6C1EF1D3E8EF0EDEL) /* 619 */, + unchecked((long) 0xB9C97D43E9798FB4L) /* 620 */, unchecked((long) 0xA2F2D784740C28A3L) /* 621 */, + unchecked((long) 0x7B8496476197566FL) /* 622 */, unchecked((long) 0x7A5BE3E6B65F069DL) /* 623 */, + unchecked((long) 0xF96330ED78BE6F10L) /* 624 */, unchecked((long) 0xEEE60DE77A076A15L) /* 625 */, + unchecked((long) 0x2B4BEE4AA08B9BD0L) /* 626 */, unchecked((long) 0x6A56A63EC7B8894EL) /* 627 */, + unchecked((long) 0x02121359BA34FEF4L) /* 628 */, unchecked((long) 0x4CBF99F8283703FCL) /* 629 */, + unchecked((long) 0x398071350CAF30C8L) /* 630 */, unchecked((long) 0xD0A77A89F017687AL) /* 631 */, + unchecked((long) 0xF1C1A9EB9E423569L) /* 632 */, unchecked((long) 0x8C7976282DEE8199L) /* 633 */, + unchecked((long) 0x5D1737A5DD1F7ABDL) /* 634 */, unchecked((long) 0x4F53433C09A9FA80L) /* 635 */, + unchecked((long) 0xFA8B0C53DF7CA1D9L) /* 636 */, unchecked((long) 0x3FD9DCBC886CCB77L) /* 637 */, + unchecked((long) 0xC040917CA91B4720L) /* 638 */, unchecked((long) 0x7DD00142F9D1DCDFL) /* 639 */, + unchecked((long) 0x8476FC1D4F387B58L) /* 640 */, unchecked((long) 0x23F8E7C5F3316503L) /* 641 */, + unchecked((long) 0x032A2244E7E37339L) /* 642 */, unchecked((long) 0x5C87A5D750F5A74BL) /* 643 */, + unchecked((long) 0x082B4CC43698992EL) /* 644 */, unchecked((long) 0xDF917BECB858F63CL) /* 645 */, + unchecked((long) 0x3270B8FC5BF86DDAL) /* 646 */, unchecked((long) 0x10AE72BB29B5DD76L) /* 647 */, + unchecked((long) 0x576AC94E7700362BL) /* 648 */, unchecked((long) 0x1AD112DAC61EFB8FL) /* 649 */, + unchecked((long) 0x691BC30EC5FAA427L) /* 650 */, unchecked((long) 0xFF246311CC327143L) /* 651 */, + unchecked((long) 0x3142368E30E53206L) /* 652 */, unchecked((long) 0x71380E31E02CA396L) /* 653 */, + unchecked((long) 0x958D5C960AAD76F1L) /* 654 */, unchecked((long) 0xF8D6F430C16DA536L) /* 655 */, + unchecked((long) 0xC8FFD13F1BE7E1D2L) /* 656 */, unchecked((long) 0x7578AE66004DDBE1L) /* 657 */, + unchecked((long) 0x05833F01067BE646L) /* 658 */, unchecked((long) 0xBB34B5AD3BFE586DL) /* 659 */, + unchecked((long) 0x095F34C9A12B97F0L) /* 660 */, unchecked((long) 0x247AB64525D60CA8L) /* 661 */, + unchecked((long) 0xDCDBC6F3017477D1L) /* 662 */, unchecked((long) 0x4A2E14D4DECAD24DL) /* 663 */, + unchecked((long) 0xBDB5E6D9BE0A1EEBL) /* 664 */, unchecked((long) 0x2A7E70F7794301ABL) /* 665 */, + unchecked((long) 0xDEF42D8A270540FDL) /* 666 */, unchecked((long) 0x01078EC0A34C22C1L) /* 667 */, + unchecked((long) 0xE5DE511AF4C16387L) /* 668 */, unchecked((long) 0x7EBB3A52BD9A330AL) /* 669 */, + unchecked((long) 0x77697857AA7D6435L) /* 670 */, unchecked((long) 0x004E831603AE4C32L) /* 671 */, + unchecked((long) 0xE7A21020AD78E312L) /* 672 */, unchecked((long) 0x9D41A70C6AB420F2L) /* 673 */, + unchecked((long) 0x28E06C18EA1141E6L) /* 674 */, unchecked((long) 0xD2B28CBD984F6B28L) /* 675 */, + unchecked((long) 0x26B75F6C446E9D83L) /* 676 */, unchecked((long) 0xBA47568C4D418D7FL) /* 677 */, + unchecked((long) 0xD80BADBFE6183D8EL) /* 678 */, unchecked((long) 0x0E206D7F5F166044L) /* 679 */, + unchecked((long) 0xE258A43911CBCA3EL) /* 680 */, unchecked((long) 0x723A1746B21DC0BCL) /* 681 */, + unchecked((long) 0xC7CAA854F5D7CDD3L) /* 682 */, unchecked((long) 0x7CAC32883D261D9CL) /* 683 */, + unchecked((long) 0x7690C26423BA942CL) /* 684 */, unchecked((long) 0x17E55524478042B8L) /* 685 */, + unchecked((long) 0xE0BE477656A2389FL) /* 686 */, unchecked((long) 0x4D289B5E67AB2DA0L) /* 687 */, + unchecked((long) 0x44862B9C8FBBFD31L) /* 688 */, unchecked((long) 0xB47CC8049D141365L) /* 689 */, + unchecked((long) 0x822C1B362B91C793L) /* 690 */, unchecked((long) 0x4EB14655FB13DFD8L) /* 691 */, + unchecked((long) 0x1ECBBA0714E2A97BL) /* 692 */, unchecked((long) 0x6143459D5CDE5F14L) /* 693 */, + unchecked((long) 0x53A8FBF1D5F0AC89L) /* 694 */, unchecked((long) 0x97EA04D81C5E5B00L) /* 695 */, + unchecked((long) 0x622181A8D4FDB3F3L) /* 696 */, unchecked((long) 0xE9BCD341572A1208L) /* 697 */, + unchecked((long) 0x1411258643CCE58AL) /* 698 */, unchecked((long) 0x9144C5FEA4C6E0A4L) /* 699 */, + unchecked((long) 0x0D33D06565CF620FL) /* 700 */, unchecked((long) 0x54A48D489F219CA1L) /* 701 */, + unchecked((long) 0xC43E5EAC6D63C821L) /* 702 */, unchecked((long) 0xA9728B3A72770DAFL) /* 703 */, + unchecked((long) 0xD7934E7B20DF87EFL) /* 704 */, unchecked((long) 0xE35503B61A3E86E5L) /* 705 */, + unchecked((long) 0xCAE321FBC819D504L) /* 706 */, unchecked((long) 0x129A50B3AC60BFA6L) /* 707 */, + unchecked((long) 0xCD5E68EA7E9FB6C3L) /* 708 */, unchecked((long) 0xB01C90199483B1C7L) /* 709 */, + unchecked((long) 0x3DE93CD5C295376CL) /* 710 */, unchecked((long) 0xAED52EDF2AB9AD13L) /* 711 */, + unchecked((long) 0x2E60F512C0A07884L) /* 712 */, unchecked((long) 0xBC3D86A3E36210C9L) /* 713 */, + unchecked((long) 0x35269D9B163951CEL) /* 714 */, unchecked((long) 0x0C7D6E2AD0CDB5FAL) /* 715 */, + unchecked((long) 0x59E86297D87F5733L) /* 716 */, unchecked((long) 0x298EF221898DB0E7L) /* 717 */, + unchecked((long) 0x55000029D1A5AA7EL) /* 718 */, unchecked((long) 0x8BC08AE1B5061B45L) /* 719 */, + unchecked((long) 0xC2C31C2B6C92703AL) /* 720 */, unchecked((long) 0x94CC596BAF25EF42L) /* 721 */, + unchecked((long) 0x0A1D73DB22540456L) /* 722 */, unchecked((long) 0x04B6A0F9D9C4179AL) /* 723 */, + unchecked((long) 0xEFFDAFA2AE3D3C60L) /* 724 */, unchecked((long) 0xF7C8075BB49496C4L) /* 725 */, + unchecked((long) 0x9CC5C7141D1CD4E3L) /* 726 */, unchecked((long) 0x78BD1638218E5534L) /* 727 */, + unchecked((long) 0xB2F11568F850246AL) /* 728 */, unchecked((long) 0xEDFABCFA9502BC29L) /* 729 */, + unchecked((long) 0x796CE5F2DA23051BL) /* 730 */, unchecked((long) 0xAAE128B0DC93537CL) /* 731 */, + unchecked((long) 0x3A493DA0EE4B29AEL) /* 732 */, unchecked((long) 0xB5DF6B2C416895D7L) /* 733 */, + unchecked((long) 0xFCABBD25122D7F37L) /* 734 */, unchecked((long) 0x70810B58105DC4B1L) /* 735 */, + unchecked((long) 0xE10FDD37F7882A90L) /* 736 */, unchecked((long) 0x524DCAB5518A3F5CL) /* 737 */, + unchecked((long) 0x3C9E85878451255BL) /* 738 */, unchecked((long) 0x4029828119BD34E2L) /* 739 */, + unchecked((long) 0x74A05B6F5D3CECCBL) /* 740 */, unchecked((long) 0xB610021542E13ECAL) /* 741 */, + unchecked((long) 0x0FF979D12F59E2ACL) /* 742 */, unchecked((long) 0x6037DA27E4F9CC50L) /* 743 */, + unchecked((long) 0x5E92975A0DF1847DL) /* 744 */, unchecked((long) 0xD66DE190D3E623FEL) /* 745 */, + unchecked((long) 0x5032D6B87B568048L) /* 746 */, unchecked((long) 0x9A36B7CE8235216EL) /* 747 */, + unchecked((long) 0x80272A7A24F64B4AL) /* 748 */, unchecked((long) 0x93EFED8B8C6916F7L) /* 749 */, + unchecked((long) 0x37DDBFF44CCE1555L) /* 750 */, unchecked((long) 0x4B95DB5D4B99BD25L) /* 751 */, + unchecked((long) 0x92D3FDA169812FC0L) /* 752 */, unchecked((long) 0xFB1A4A9A90660BB6L) /* 753 */, + unchecked((long) 0x730C196946A4B9B2L) /* 754 */, unchecked((long) 0x81E289AA7F49DA68L) /* 755 */, + unchecked((long) 0x64669A0F83B1A05FL) /* 756 */, unchecked((long) 0x27B3FF7D9644F48BL) /* 757 */, + unchecked((long) 0xCC6B615C8DB675B3L) /* 758 */, unchecked((long) 0x674F20B9BCEBBE95L) /* 759 */, + unchecked((long) 0x6F31238275655982L) /* 760 */, unchecked((long) 0x5AE488713E45CF05L) /* 761 */, + unchecked((long) 0xBF619F9954C21157L) /* 762 */, unchecked((long) 0xEABAC46040A8EAE9L) /* 763 */, + unchecked((long) 0x454C6FE9F2C0C1CDL) /* 764 */, unchecked((long) 0x419CF6496412691CL) /* 765 */, + unchecked((long) 0xD3DC3BEF265B0F70L) /* 766 */, unchecked((long) 0x6D0E60F5C3578A9EL) /* 767 */, + }; + + private static readonly long[] t4 = { + unchecked((long) 0x5B0E608526323C55L) /* 768 */, unchecked((long) 0x1A46C1A9FA1B59F5L) /* 769 */, + unchecked((long) 0xA9E245A17C4C8FFAL) /* 770 */, unchecked((long) 0x65CA5159DB2955D7L) /* 771 */, + unchecked((long) 0x05DB0A76CE35AFC2L) /* 772 */, unchecked((long) 0x81EAC77EA9113D45L) /* 773 */, + unchecked((long) 0x528EF88AB6AC0A0DL) /* 774 */, unchecked((long) 0xA09EA253597BE3FFL) /* 775 */, + unchecked((long) 0x430DDFB3AC48CD56L) /* 776 */, unchecked((long) 0xC4B3A67AF45CE46FL) /* 777 */, + unchecked((long) 0x4ECECFD8FBE2D05EL) /* 778 */, unchecked((long) 0x3EF56F10B39935F0L) /* 779 */, + unchecked((long) 0x0B22D6829CD619C6L) /* 780 */, unchecked((long) 0x17FD460A74DF2069L) /* 781 */, + unchecked((long) 0x6CF8CC8E8510ED40L) /* 782 */, unchecked((long) 0xD6C824BF3A6ECAA7L) /* 783 */, + unchecked((long) 0x61243D581A817049L) /* 784 */, unchecked((long) 0x048BACB6BBC163A2L) /* 785 */, + unchecked((long) 0xD9A38AC27D44CC32L) /* 786 */, unchecked((long) 0x7FDDFF5BAAF410ABL) /* 787 */, + unchecked((long) 0xAD6D495AA804824BL) /* 788 */, unchecked((long) 0xE1A6A74F2D8C9F94L) /* 789 */, + unchecked((long) 0xD4F7851235DEE8E3L) /* 790 */, unchecked((long) 0xFD4B7F886540D893L) /* 791 */, + unchecked((long) 0x247C20042AA4BFDAL) /* 792 */, unchecked((long) 0x096EA1C517D1327CL) /* 793 */, + unchecked((long) 0xD56966B4361A6685L) /* 794 */, unchecked((long) 0x277DA5C31221057DL) /* 795 */, + unchecked((long) 0x94D59893A43ACFF7L) /* 796 */, unchecked((long) 0x64F0C51CCDC02281L) /* 797 */, + unchecked((long) 0x3D33BCC4FF6189DBL) /* 798 */, unchecked((long) 0xE005CB184CE66AF1L) /* 799 */, + unchecked((long) 0xFF5CCD1D1DB99BEAL) /* 800 */, unchecked((long) 0xB0B854A7FE42980FL) /* 801 */, + unchecked((long) 0x7BD46A6A718D4B9FL) /* 802 */, unchecked((long) 0xD10FA8CC22A5FD8CL) /* 803 */, + unchecked((long) 0xD31484952BE4BD31L) /* 804 */, unchecked((long) 0xC7FA975FCB243847L) /* 805 */, + unchecked((long) 0x4886ED1E5846C407L) /* 806 */, unchecked((long) 0x28CDDB791EB70B04L) /* 807 */, + unchecked((long) 0xC2B00BE2F573417FL) /* 808 */, unchecked((long) 0x5C9590452180F877L) /* 809 */, + unchecked((long) 0x7A6BDDFFF370EB00L) /* 810 */, unchecked((long) 0xCE509E38D6D9D6A4L) /* 811 */, + unchecked((long) 0xEBEB0F00647FA702L) /* 812 */, unchecked((long) 0x1DCC06CF76606F06L) /* 813 */, + unchecked((long) 0xE4D9F28BA286FF0AL) /* 814 */, unchecked((long) 0xD85A305DC918C262L) /* 815 */, + unchecked((long) 0x475B1D8732225F54L) /* 816 */, unchecked((long) 0x2D4FB51668CCB5FEL) /* 817 */, + unchecked((long) 0xA679B9D9D72BBA20L) /* 818 */, unchecked((long) 0x53841C0D912D43A5L) /* 819 */, + unchecked((long) 0x3B7EAA48BF12A4E8L) /* 820 */, unchecked((long) 0x781E0E47F22F1DDFL) /* 821 */, + unchecked((long) 0xEFF20CE60AB50973L) /* 822 */, unchecked((long) 0x20D261D19DFFB742L) /* 823 */, + unchecked((long) 0x16A12B03062A2E39L) /* 824 */, unchecked((long) 0x1960EB2239650495L) /* 825 */, + unchecked((long) 0x251C16FED50EB8B8L) /* 826 */, unchecked((long) 0x9AC0C330F826016EL) /* 827 */, + unchecked((long) 0xED152665953E7671L) /* 828 */, unchecked((long) 0x02D63194A6369570L) /* 829 */, + unchecked((long) 0x5074F08394B1C987L) /* 830 */, unchecked((long) 0x70BA598C90B25CE1L) /* 831 */, + unchecked((long) 0x794A15810B9742F6L) /* 832 */, unchecked((long) 0x0D5925E9FCAF8C6CL) /* 833 */, + unchecked((long) 0x3067716CD868744EL) /* 834 */, unchecked((long) 0x910AB077E8D7731BL) /* 835 */, + unchecked((long) 0x6A61BBDB5AC42F61L) /* 836 */, unchecked((long) 0x93513EFBF0851567L) /* 837 */, + unchecked((long) 0xF494724B9E83E9D5L) /* 838 */, unchecked((long) 0xE887E1985C09648DL) /* 839 */, + unchecked((long) 0x34B1D3C675370CFDL) /* 840 */, unchecked((long) 0xDC35E433BC0D255DL) /* 841 */, + unchecked((long) 0xD0AAB84234131BE0L) /* 842 */, unchecked((long) 0x08042A50B48B7EAFL) /* 843 */, + unchecked((long) 0x9997C4EE44A3AB35L) /* 844 */, unchecked((long) 0x829A7B49201799D0L) /* 845 */, + unchecked((long) 0x263B8307B7C54441L) /* 846 */, unchecked((long) 0x752F95F4FD6A6CA6L) /* 847 */, + unchecked((long) 0x927217402C08C6E5L) /* 848 */, unchecked((long) 0x2A8AB754A795D9EEL) /* 849 */, + unchecked((long) 0xA442F7552F72943DL) /* 850 */, unchecked((long) 0x2C31334E19781208L) /* 851 */, + unchecked((long) 0x4FA98D7CEAEE6291L) /* 852 */, unchecked((long) 0x55C3862F665DB309L) /* 853 */, + unchecked((long) 0xBD0610175D53B1F3L) /* 854 */, unchecked((long) 0x46FE6CB840413F27L) /* 855 */, + unchecked((long) 0x3FE03792DF0CFA59L) /* 856 */, unchecked((long) 0xCFE700372EB85E8FL) /* 857 */, + unchecked((long) 0xA7BE29E7ADBCE118L) /* 858 */, unchecked((long) 0xE544EE5CDE8431DDL) /* 859 */, + unchecked((long) 0x8A781B1B41F1873EL) /* 860 */, unchecked((long) 0xA5C94C78A0D2F0E7L) /* 861 */, + unchecked((long) 0x39412E2877B60728L) /* 862 */, unchecked((long) 0xA1265EF3AFC9A62CL) /* 863 */, + unchecked((long) 0xBCC2770C6A2506C5L) /* 864 */, unchecked((long) 0x3AB66DD5DCE1CE12L) /* 865 */, + unchecked((long) 0xE65499D04A675B37L) /* 866 */, unchecked((long) 0x7D8F523481BFD216L) /* 867 */, + unchecked((long) 0x0F6F64FCEC15F389L) /* 868 */, unchecked((long) 0x74EFBE618B5B13C8L) /* 869 */, + unchecked((long) 0xACDC82B714273E1DL) /* 870 */, unchecked((long) 0xDD40BFE003199D17L) /* 871 */, + unchecked((long) 0x37E99257E7E061F8L) /* 872 */, unchecked((long) 0xFA52626904775AAAL) /* 873 */, + unchecked((long) 0x8BBBF63A463D56F9L) /* 874 */, unchecked((long) 0xF0013F1543A26E64L) /* 875 */, + unchecked((long) 0xA8307E9F879EC898L) /* 876 */, unchecked((long) 0xCC4C27A4150177CCL) /* 877 */, + unchecked((long) 0x1B432F2CCA1D3348L) /* 878 */, unchecked((long) 0xDE1D1F8F9F6FA013L) /* 879 */, + unchecked((long) 0x606602A047A7DDD6L) /* 880 */, unchecked((long) 0xD237AB64CC1CB2C7L) /* 881 */, + unchecked((long) 0x9B938E7225FCD1D3L) /* 882 */, unchecked((long) 0xEC4E03708E0FF476L) /* 883 */, + unchecked((long) 0xFEB2FBDA3D03C12DL) /* 884 */, unchecked((long) 0xAE0BCED2EE43889AL) /* 885 */, + unchecked((long) 0x22CB8923EBFB4F43L) /* 886 */, unchecked((long) 0x69360D013CF7396DL) /* 887 */, + unchecked((long) 0x855E3602D2D4E022L) /* 888 */, unchecked((long) 0x073805BAD01F784CL) /* 889 */, + unchecked((long) 0x33E17A133852F546L) /* 890 */, unchecked((long) 0xDF4874058AC7B638L) /* 891 */, + unchecked((long) 0xBA92B29C678AA14AL) /* 892 */, unchecked((long) 0x0CE89FC76CFAADCDL) /* 893 */, + unchecked((long) 0x5F9D4E0908339E34L) /* 894 */, unchecked((long) 0xF1AFE9291F5923B9L) /* 895 */, + unchecked((long) 0x6E3480F60F4A265FL) /* 896 */, unchecked((long) 0xEEBF3A2AB29B841CL) /* 897 */, + unchecked((long) 0xE21938A88F91B4ADL) /* 898 */, unchecked((long) 0x57DFEFF845C6D3C3L) /* 899 */, + unchecked((long) 0x2F006B0BF62CAAF2L) /* 900 */, unchecked((long) 0x62F479EF6F75EE78L) /* 901 */, + unchecked((long) 0x11A55AD41C8916A9L) /* 902 */, unchecked((long) 0xF229D29084FED453L) /* 903 */, + unchecked((long) 0x42F1C27B16B000E6L) /* 904 */, unchecked((long) 0x2B1F76749823C074L) /* 905 */, + unchecked((long) 0x4B76ECA3C2745360L) /* 906 */, unchecked((long) 0x8C98F463B91691BDL) /* 907 */, + unchecked((long) 0x14BCC93CF1ADE66AL) /* 908 */, unchecked((long) 0x8885213E6D458397L) /* 909 */, + unchecked((long) 0x8E177DF0274D4711L) /* 910 */, unchecked((long) 0xB49B73B5503F2951L) /* 911 */, + unchecked((long) 0x10168168C3F96B6BL) /* 912 */, unchecked((long) 0x0E3D963B63CAB0AEL) /* 913 */, + unchecked((long) 0x8DFC4B5655A1DB14L) /* 914 */, unchecked((long) 0xF789F1356E14DE5CL) /* 915 */, + unchecked((long) 0x683E68AF4E51DAC1L) /* 916 */, unchecked((long) 0xC9A84F9D8D4B0FD9L) /* 917 */, + unchecked((long) 0x3691E03F52A0F9D1L) /* 918 */, unchecked((long) 0x5ED86E46E1878E80L) /* 919 */, + unchecked((long) 0x3C711A0E99D07150L) /* 920 */, unchecked((long) 0x5A0865B20C4E9310L) /* 921 */, + unchecked((long) 0x56FBFC1FE4F0682EL) /* 922 */, unchecked((long) 0xEA8D5DE3105EDF9BL) /* 923 */, + unchecked((long) 0x71ABFDB12379187AL) /* 924 */, unchecked((long) 0x2EB99DE1BEE77B9CL) /* 925 */, + unchecked((long) 0x21ECC0EA33CF4523L) /* 926 */, unchecked((long) 0x59A4D7521805C7A1L) /* 927 */, + unchecked((long) 0x3896F5EB56AE7C72L) /* 928 */, unchecked((long) 0xAA638F3DB18F75DCL) /* 929 */, + unchecked((long) 0x9F39358DABE9808EL) /* 930 */, unchecked((long) 0xB7DEFA91C00B72ACL) /* 931 */, + unchecked((long) 0x6B5541FD62492D92L) /* 932 */, unchecked((long) 0x6DC6DEE8F92E4D5BL) /* 933 */, + unchecked((long) 0x353F57ABC4BEEA7EL) /* 934 */, unchecked((long) 0x735769D6DA5690CEL) /* 935 */, + unchecked((long) 0x0A234AA642391484L) /* 936 */, unchecked((long) 0xF6F9508028F80D9DL) /* 937 */, + unchecked((long) 0xB8E319A27AB3F215L) /* 938 */, unchecked((long) 0x31AD9C1151341A4DL) /* 939 */, + unchecked((long) 0x773C22A57BEF5805L) /* 940 */, unchecked((long) 0x45C7561A07968633L) /* 941 */, + unchecked((long) 0xF913DA9E249DBE36L) /* 942 */, unchecked((long) 0xDA652D9B78A64C68L) /* 943 */, + unchecked((long) 0x4C27A97F3BC334EFL) /* 944 */, unchecked((long) 0x76621220E66B17F4L) /* 945 */, + unchecked((long) 0x967743899ACD7D0BL) /* 946 */, unchecked((long) 0xF3EE5BCAE0ED6782L) /* 947 */, + unchecked((long) 0x409F753600C879FCL) /* 948 */, unchecked((long) 0x06D09A39B5926DB6L) /* 949 */, + unchecked((long) 0x6F83AEB0317AC588L) /* 950 */, unchecked((long) 0x01E6CA4A86381F21L) /* 951 */, + unchecked((long) 0x66FF3462D19F3025L) /* 952 */, unchecked((long) 0x72207C24DDFD3BFBL) /* 953 */, + unchecked((long) 0x4AF6B6D3E2ECE2EBL) /* 954 */, unchecked((long) 0x9C994DBEC7EA08DEL) /* 955 */, + unchecked((long) 0x49ACE597B09A8BC4L) /* 956 */, unchecked((long) 0xB38C4766CF0797BAL) /* 957 */, + unchecked((long) 0x131B9373C57C2A75L) /* 958 */, unchecked((long) 0xB1822CCE61931E58L) /* 959 */, + unchecked((long) 0x9D7555B909BA1C0CL) /* 960 */, unchecked((long) 0x127FAFDD937D11D2L) /* 961 */, + unchecked((long) 0x29DA3BADC66D92E4L) /* 962 */, unchecked((long) 0xA2C1D57154C2ECBCL) /* 963 */, + unchecked((long) 0x58C5134D82F6FE24L) /* 964 */, unchecked((long) 0x1C3AE3515B62274FL) /* 965 */, + unchecked((long) 0xE907C82E01CB8126L) /* 966 */, unchecked((long) 0xF8ED091913E37FCBL) /* 967 */, + unchecked((long) 0x3249D8F9C80046C9L) /* 968 */, unchecked((long) 0x80CF9BEDE388FB63L) /* 969 */, + unchecked((long) 0x1881539A116CF19EL) /* 970 */, unchecked((long) 0x5103F3F76BD52457L) /* 971 */, + unchecked((long) 0x15B7E6F5AE47F7A8L) /* 972 */, unchecked((long) 0xDBD7C6DED47E9CCFL) /* 973 */, + unchecked((long) 0x44E55C410228BB1AL) /* 974 */, unchecked((long) 0xB647D4255EDB4E99L) /* 975 */, + unchecked((long) 0x5D11882BB8AAFC30L) /* 976 */, unchecked((long) 0xF5098BBB29D3212AL) /* 977 */, + unchecked((long) 0x8FB5EA14E90296B3L) /* 978 */, unchecked((long) 0x677B942157DD025AL) /* 979 */, + unchecked((long) 0xFB58E7C0A390ACB5L) /* 980 */, unchecked((long) 0x89D3674C83BD4A01L) /* 981 */, + unchecked((long) 0x9E2DA4DF4BF3B93BL) /* 982 */, unchecked((long) 0xFCC41E328CAB4829L) /* 983 */, + unchecked((long) 0x03F38C96BA582C52L) /* 984 */, unchecked((long) 0xCAD1BDBD7FD85DB2L) /* 985 */, + unchecked((long) 0xBBB442C16082AE83L) /* 986 */, unchecked((long) 0xB95FE86BA5DA9AB0L) /* 987 */, + unchecked((long) 0xB22E04673771A93FL) /* 988 */, unchecked((long) 0x845358C9493152D8L) /* 989 */, + unchecked((long) 0xBE2A488697B4541EL) /* 990 */, unchecked((long) 0x95A2DC2DD38E6966L) /* 991 */, + unchecked((long) 0xC02C11AC923C852BL) /* 992 */, unchecked((long) 0x2388B1990DF2A87BL) /* 993 */, + unchecked((long) 0x7C8008FA1B4F37BEL) /* 994 */, unchecked((long) 0x1F70D0C84D54E503L) /* 995 */, + unchecked((long) 0x5490ADEC7ECE57D4L) /* 996 */, unchecked((long) 0x002B3C27D9063A3AL) /* 997 */, + unchecked((long) 0x7EAEA3848030A2BFL) /* 998 */, unchecked((long) 0xC602326DED2003C0L) /* 999 */, + unchecked((long) 0x83A7287D69A94086L) /* 1000 */, unchecked((long) 0xC57A5FCB30F57A8AL) /* 1001 */, + unchecked((long) 0xB56844E479EBE779L) /* 1002 */, unchecked((long) 0xA373B40F05DCBCE9L) /* 1003 */, + unchecked((long) 0xD71A786E88570EE2L) /* 1004 */, unchecked((long) 0x879CBACDBDE8F6A0L) /* 1005 */, + unchecked((long) 0x976AD1BCC164A32FL) /* 1006 */, unchecked((long) 0xAB21E25E9666D78BL) /* 1007 */, + unchecked((long) 0x901063AAE5E5C33CL) /* 1008 */, unchecked((long) 0x9818B34448698D90L) /* 1009 */, + unchecked((long) 0xE36487AE3E1E8ABBL) /* 1010 */, unchecked((long) 0xAFBDF931893BDCB4L) /* 1011 */, + unchecked((long) 0x6345A0DC5FBBD519L) /* 1012 */, unchecked((long) 0x8628FE269B9465CAL) /* 1013 */, + unchecked((long) 0x1E5D01603F9C51ECL) /* 1014 */, unchecked((long) 0x4DE44006A15049B7L) /* 1015 */, + unchecked((long) 0xBF6C70E5F776CBB1L) /* 1016 */, unchecked((long) 0x411218F2EF552BEDL) /* 1017 */, + unchecked((long) 0xCB0C0708705A36A3L) /* 1018 */, unchecked((long) 0xE74D14754F986044L) /* 1019 */, + unchecked((long) 0xCD56D9430EA8280EL) /* 1020 */, unchecked((long) 0xC12591D7535F5065L) /* 1021 */, + unchecked((long) 0xC83223F1720AEF96L) /* 1022 */, unchecked((long) 0xC3A0396F7363A51FL) /* 1023 */ + }; + + private const int DigestLength = 24; + + // + // registers + // + private long a, b, c; + private long byteCount; + + // + // buffers + // + private byte[] Buffer = new byte[8]; + private int bOff; + + private long[] x = new long[8]; + private int xOff; + + /** + * Standard constructor + */ + public TigerDigest() + { + Reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public TigerDigest(TigerDigest t) + { + a = t.a; + b = t.b; + c = t.c; + + Array.Copy(t.x, 0, x, 0, t.x.Length); + xOff = t.xOff; + + Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length); + bOff = t.bOff; + + byteCount = t.byteCount; + } + + public string AlgorithmName + { + get { return "Tiger"; } + } + + public int GetDigestSize() + { + return DigestLength; + } + + public int GetByteLength() + { + return MyByteLength; + } + + private void ProcessWord( + byte[] b, + int off) + { + x[xOff++] = ((long)(b[off + 7] & 0xff) << 56) + | ((long)(b[off + 6] & 0xff) << 48) + | ((long)(b[off + 5] & 0xff) << 40) + | ((long)(b[off + 4] & 0xff) << 32) + | ((long)(b[off + 3] & 0xff) << 24) + | ((long)(b[off + 2] & 0xff) << 16) + | ((long)(b[off + 1] & 0xff) << 8) + | ((uint)(b[off + 0] & 0xff)); + + if (xOff == x.Length) + { + ProcessBlock(); + } + + bOff = 0; + } + + public void Update( + byte input) + { + Buffer[bOff++] = input; + + if (bOff == Buffer.Length) + { + ProcessWord(Buffer, 0); + } + + byteCount++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + // + // fill the current word + // + while ((bOff != 0) && (length > 0)) + { + Update(input[inOff]); + + inOff++; + length--; + } + + // + // process whole words. + // + while (length > 8) + { + ProcessWord(input, inOff); + + inOff += 8; + length -= 8; + byteCount += 8; + } + + // + // load in the remainder. + // + while (length > 0) + { + Update(input[inOff]); + + inOff++; + length--; + } + } + + private void RoundABC( + long x, + long mul) + { + c ^= x ; + a -= t1[(int)c & 0xff] ^ t2[(int)(c >> 16) & 0xff] + ^ t3[(int)(c >> 32) & 0xff] ^ t4[(int)(c >> 48) & 0xff]; + b += t4[(int)(c >> 8) & 0xff] ^ t3[(int)(c >> 24) & 0xff] + ^ t2[(int)(c >> 40) & 0xff] ^ t1[(int)(c >> 56) & 0xff]; + b *= mul; + } + + private void RoundBCA( + long x, + long mul) + { + a ^= x ; + b -= t1[(int)a & 0xff] ^ t2[(int)(a >> 16) & 0xff] + ^ t3[(int)(a >> 32) & 0xff] ^ t4[(int)(a >> 48) & 0xff]; + c += t4[(int)(a >> 8) & 0xff] ^ t3[(int)(a >> 24) & 0xff] + ^ t2[(int)(a >> 40) & 0xff] ^ t1[(int)(a >> 56) & 0xff]; + c *= mul; + } + + private void RoundCAB( + long x, + long mul) + { + b ^= x ; + c -= t1[(int)b & 0xff] ^ t2[(int)(b >> 16) & 0xff] + ^ t3[(int)(b >> 32) & 0xff] ^ t4[(int)(b >> 48) & 0xff]; + a += t4[(int)(b >> 8) & 0xff] ^ t3[(int)(b >> 24) & 0xff] + ^ t2[(int)(b >> 40) & 0xff] ^ t1[(int)(b >> 56) & 0xff]; + a *= mul; + } + + private void KeySchedule() + { + x[0] -= x[7] ^ unchecked ((long) 0xA5A5A5A5A5A5A5A5L); + x[1] ^= x[0]; + x[2] += x[1]; + x[3] -= x[2] ^ ((~x[1]) << 19); + x[4] ^= x[3]; + x[5] += x[4]; + x[6] -= x[5] ^ (long) ((ulong) (~x[4]) >> 23); + x[7] ^= x[6]; + x[0] += x[7]; + x[1] -= x[0] ^ ((~x[7]) << 19); + x[2] ^= x[1]; + x[3] += x[2]; + x[4] -= x[3] ^ (long) ((ulong) (~x[2]) >> 23); + x[5] ^= x[4]; + x[6] += x[5]; + x[7] -= x[6] ^ 0x0123456789ABCDEFL; + } + + private void ProcessBlock() + { + // + // save abc + // + long aa = a; + long bb = b; + long cc = c; + + // + // rounds and schedule + // + RoundABC(x[0], 5); + RoundBCA(x[1], 5); + RoundCAB(x[2], 5); + RoundABC(x[3], 5); + RoundBCA(x[4], 5); + RoundCAB(x[5], 5); + RoundABC(x[6], 5); + RoundBCA(x[7], 5); + + KeySchedule(); + + RoundCAB(x[0], 7); + RoundABC(x[1], 7); + RoundBCA(x[2], 7); + RoundCAB(x[3], 7); + RoundABC(x[4], 7); + RoundBCA(x[5], 7); + RoundCAB(x[6], 7); + RoundABC(x[7], 7); + + KeySchedule(); + + RoundBCA(x[0], 9); + RoundCAB(x[1], 9); + RoundABC(x[2], 9); + RoundBCA(x[3], 9); + RoundCAB(x[4], 9); + RoundABC(x[5], 9); + RoundBCA(x[6], 9); + RoundCAB(x[7], 9); + + // + // feed forward + // + a ^= aa; + b -= bb; + c += cc; + + // + // clear the x buffer + // + xOff = 0; + for (int i = 0; i != x.Length; i++) + { + x[i] = 0; + } + } + + private void UnpackWord( + long r, + byte[] output, + int outOff) + { + output[outOff + 7] = (byte)(r >> 56); + output[outOff + 6] = (byte)(r >> 48); + output[outOff + 5] = (byte)(r >> 40); + output[outOff + 4] = (byte)(r >> 32); + output[outOff + 3] = (byte)(r >> 24); + output[outOff + 2] = (byte)(r >> 16); + output[outOff + 1] = (byte)(r >> 8); + output[outOff] = (byte)r; + } + + private void ProcessLength( + long bitLength) + { + x[7] = bitLength; + } + + private void Finish() + { + long bitLength = (byteCount << 3); + + Update((byte)0x01); + + while (bOff != 0) + { + Update((byte)0); + } + + ProcessLength(bitLength); + + ProcessBlock(); + } + + public int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + UnpackWord(a, output, outOff); + UnpackWord(b, output, outOff + 8); + UnpackWord(c, output, outOff + 16); + + Reset(); + + return DigestLength; + } + + /** + * reset the chaining variables + */ + public void Reset() + { + a = unchecked((long) 0x0123456789ABCDEFL); + b = unchecked((long) 0xFEDCBA9876543210L); + c = unchecked((long) 0xF096A5B4C3B2E187L); + + xOff = 0; + for (int i = 0; i != x.Length; i++) + { + x[i] = 0; + } + + bOff = 0; + for (int i = 0; i != Buffer.Length; i++) + { + Buffer[i] = 0; + } + + byteCount = 0; + } + } +} diff --git a/iTechSharp/srcbc/crypto/digests/WhirlpoolDigest.cs b/iTechSharp/srcbc/crypto/digests/WhirlpoolDigest.cs new file mode 100644 index 0000000..df83f45 --- /dev/null +++ b/iTechSharp/srcbc/crypto/digests/WhirlpoolDigest.cs @@ -0,0 +1,397 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Digests +{ + /** + * Implementation of WhirlpoolDigest, based on Java source published by Barreto + * and Rijmen. + * + */ + public sealed class WhirlpoolDigest : IDigest + { + private const int BYTE_LENGTH = 64; + + private const int DIGEST_LENGTH_BYTES = 512 / 8; + private const int ROUNDS = 10; + private const int REDUCTION_POLYNOMIAL = 0x011d; // 2^8 + 2^4 + 2^3 + 2 + 1; + + private static readonly int[] SBOX = + { + 0x18, 0x23, 0xc6, 0xe8, 0x87, 0xb8, 0x01, 0x4f, 0x36, 0xa6, 0xd2, 0xf5, 0x79, 0x6f, 0x91, 0x52, + 0x60, 0xbc, 0x9b, 0x8e, 0xa3, 0x0c, 0x7b, 0x35, 0x1d, 0xe0, 0xd7, 0xc2, 0x2e, 0x4b, 0xfe, 0x57, + 0x15, 0x77, 0x37, 0xe5, 0x9f, 0xf0, 0x4a, 0xda, 0x58, 0xc9, 0x29, 0x0a, 0xb1, 0xa0, 0x6b, 0x85, + 0xbd, 0x5d, 0x10, 0xf4, 0xcb, 0x3e, 0x05, 0x67, 0xe4, 0x27, 0x41, 0x8b, 0xa7, 0x7d, 0x95, 0xd8, + 0xfb, 0xee, 0x7c, 0x66, 0xdd, 0x17, 0x47, 0x9e, 0xca, 0x2d, 0xbf, 0x07, 0xad, 0x5a, 0x83, 0x33, + 0x63, 0x02, 0xaa, 0x71, 0xc8, 0x19, 0x49, 0xd9, 0xf2, 0xe3, 0x5b, 0x88, 0x9a, 0x26, 0x32, 0xb0, + 0xe9, 0x0f, 0xd5, 0x80, 0xbe, 0xcd, 0x34, 0x48, 0xff, 0x7a, 0x90, 0x5f, 0x20, 0x68, 0x1a, 0xae, + 0xb4, 0x54, 0x93, 0x22, 0x64, 0xf1, 0x73, 0x12, 0x40, 0x08, 0xc3, 0xec, 0xdb, 0xa1, 0x8d, 0x3d, + 0x97, 0x00, 0xcf, 0x2b, 0x76, 0x82, 0xd6, 0x1b, 0xb5, 0xaf, 0x6a, 0x50, 0x45, 0xf3, 0x30, 0xef, + 0x3f, 0x55, 0xa2, 0xea, 0x65, 0xba, 0x2f, 0xc0, 0xde, 0x1c, 0xfd, 0x4d, 0x92, 0x75, 0x06, 0x8a, + 0xb2, 0xe6, 0x0e, 0x1f, 0x62, 0xd4, 0xa8, 0x96, 0xf9, 0xc5, 0x25, 0x59, 0x84, 0x72, 0x39, 0x4c, + 0x5e, 0x78, 0x38, 0x8c, 0xd1, 0xa5, 0xe2, 0x61, 0xb3, 0x21, 0x9c, 0x1e, 0x43, 0xc7, 0xfc, 0x04, + 0x51, 0x99, 0x6d, 0x0d, 0xfa, 0xdf, 0x7e, 0x24, 0x3b, 0xab, 0xce, 0x11, 0x8f, 0x4e, 0xb7, 0xeb, + 0x3c, 0x81, 0x94, 0xf7, 0xb9, 0x13, 0x2c, 0xd3, 0xe7, 0x6e, 0xc4, 0x03, 0x56, 0x44, 0x7f, 0xa9, + 0x2a, 0xbb, 0xc1, 0x53, 0xdc, 0x0b, 0x9d, 0x6c, 0x31, 0x74, 0xf6, 0x46, 0xac, 0x89, 0x14, 0xe1, + 0x16, 0x3a, 0x69, 0x09, 0x70, 0xb6, 0xd0, 0xed, 0xcc, 0x42, 0x98, 0xa4, 0x28, 0x5c, 0xf8, 0x86 + }; + + private static readonly long[] C0 = new long[256]; + private static readonly long[] C1 = new long[256]; + private static readonly long[] C2 = new long[256]; + private static readonly long[] C3 = new long[256]; + private static readonly long[] C4 = new long[256]; + private static readonly long[] C5 = new long[256]; + private static readonly long[] C6 = new long[256]; + private static readonly long[] C7 = new long[256]; + + private readonly long[] _rc = new long[ROUNDS + 1]; + + /* + * increment() can be implemented in this way using 2 arrays or + * by having some temporary variables that are used to set the + * value provided by EIGHT[i] and carry within the loop. + * + * not having done any timing, this seems likely to be faster + * at the slight expense of 32*(sizeof short) bytes + */ + private static readonly short[] EIGHT = new short[BITCOUNT_ARRAY_SIZE]; + + static WhirlpoolDigest() + { + EIGHT[BITCOUNT_ARRAY_SIZE - 1] = 8; + + for (int i = 0; i < 256; i++) + { + int v1 = SBOX[i]; + int v2 = maskWithReductionPolynomial(v1 << 1); + int v4 = maskWithReductionPolynomial(v2 << 1); + int v5 = v4 ^ v1; + int v8 = maskWithReductionPolynomial(v4 << 1); + int v9 = v8 ^ v1; + + C0[i] = packIntoLong(v1, v1, v4, v1, v8, v5, v2, v9); + C1[i] = packIntoLong(v9, v1, v1, v4, v1, v8, v5, v2); + C2[i] = packIntoLong(v2, v9, v1, v1, v4, v1, v8, v5); + C3[i] = packIntoLong(v5, v2, v9, v1, v1, v4, v1, v8); + C4[i] = packIntoLong(v8, v5, v2, v9, v1, v1, v4, v1); + C5[i] = packIntoLong(v1, v8, v5, v2, v9, v1, v1, v4); + C6[i] = packIntoLong(v4, v1, v8, v5, v2, v9, v1, v1); + C7[i] = packIntoLong(v1, v4, v1, v8, v5, v2, v9, v1); + } + } + + public WhirlpoolDigest() + { + _rc[0] = 0L; + for (int r = 1; r <= ROUNDS; r++) + { + int i = 8 * (r - 1); + _rc[r] = (long)((ulong)C0[i] & 0xff00000000000000L) ^ + (C1[i + 1] & (long) 0x00ff000000000000L) ^ + (C2[i + 2] & (long) 0x0000ff0000000000L) ^ + (C3[i + 3] & (long) 0x000000ff00000000L) ^ + (C4[i + 4] & (long) 0x00000000ff000000L) ^ + (C5[i + 5] & (long) 0x0000000000ff0000L) ^ + (C6[i + 6] & (long) 0x000000000000ff00L) ^ + (C7[i + 7] & (long) 0x00000000000000ffL); + } + } + + private static long packIntoLong(int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0) + { + return + ((long)b7 << 56) ^ + ((long)b6 << 48) ^ + ((long)b5 << 40) ^ + ((long)b4 << 32) ^ + ((long)b3 << 24) ^ + ((long)b2 << 16) ^ + ((long)b1 << 8) ^ + b0; + } + + /* + * int's are used to prevent sign extension. The values that are really being used are + * actually just 0..255 + */ + private static int maskWithReductionPolynomial(int input) + { + int rv = input; + if (rv >= 0x100L) // high bit set + { + rv ^= REDUCTION_POLYNOMIAL; // reduced by the polynomial + } + return rv; + } + + // --------------------------------------------------------------------------------------// + + // -- buffer information -- + private const int BITCOUNT_ARRAY_SIZE = 32; + private byte[] _buffer = new byte[64]; + private int _bufferPos; + private short[] _bitCount = new short[BITCOUNT_ARRAY_SIZE]; + + // -- internal hash state -- + private long[] _hash = new long[8]; + private long[] _K = new long[8]; // the round key + private long[] _L = new long[8]; + private long[] _block = new long[8]; // mu (buffer) + private long[] _state = new long[8]; // the current "cipher" state + + + + /** + * Copy constructor. This will copy the state of the provided message + * digest. + */ + public WhirlpoolDigest(WhirlpoolDigest originalDigest) + { + Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length); + + Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length); + + this._bufferPos = originalDigest._bufferPos; + Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length); + + // -- internal hash state -- + Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length); + Array.Copy(originalDigest._K, 0, _K, 0, _K.Length); + Array.Copy(originalDigest._L, 0, _L, 0, _L.Length); + Array.Copy(originalDigest._block, 0, _block, 0, _block.Length); + Array.Copy(originalDigest._state, 0, _state, 0, _state.Length); + } + + public string AlgorithmName + { + get { return "Whirlpool"; } + } + + public int GetDigestSize() + { + return DIGEST_LENGTH_BYTES; + } + + public int DoFinal(byte[] output, int outOff) + { + // sets output[outOff] .. output[outOff+DIGEST_LENGTH_BYTES] + finish(); + + for (int i = 0; i < 8; i++) + { + convertLongToByteArray(_hash[i], output, outOff + (i * 8)); + } + + Reset(); + + return GetDigestSize(); + } + + /** + * Reset the chaining variables + */ + public void Reset() + { + // set variables to null, blank, whatever + _bufferPos = 0; + Array.Clear(_bitCount, 0, _bitCount.Length); + Array.Clear(_buffer, 0, _buffer.Length); + Array.Clear(_hash, 0, _hash.Length); + Array.Clear(_K, 0, _K.Length); + Array.Clear(_L, 0, _L.Length); + Array.Clear(_block, 0, _block.Length); + Array.Clear(_state, 0, _state.Length); + } + + // this takes a buffer of information and fills the block + private void processFilledBuffer() + { + // copies into the block... + for (int i = 0; i < _state.Length; i++) + { + _block[i] = bytesToLongFromBuffer(_buffer, i * 8); + } + processBlock(); + _bufferPos = 0; + Array.Clear(_buffer, 0, _buffer.Length); + } + + private static long bytesToLongFromBuffer(byte[] buffer, int startPos) + { + long rv = (((buffer[startPos + 0] & 0xffL) << 56) | + ((buffer[startPos + 1] & 0xffL) << 48) | + ((buffer[startPos + 2] & 0xffL) << 40) | + ((buffer[startPos + 3] & 0xffL) << 32) | + ((buffer[startPos + 4] & 0xffL) << 24) | + ((buffer[startPos + 5] & 0xffL) << 16) | + ((buffer[startPos + 6] & 0xffL) << 8) | + ((buffer[startPos + 7]) & 0xffL)); + + return rv; + } + + private static void convertLongToByteArray(long inputLong, byte[] outputArray, int offSet) + { + for (int i = 0; i < 8; i++) + { + outputArray[offSet + i] = (byte)((inputLong >> (56 - (i * 8))) & 0xff); + } + } + + private void processBlock() + { + // buffer contents have been transferred to the _block[] array via + // processFilledBuffer + + // compute and apply K^0 + for (int i = 0; i < 8; i++) + { + _state[i] = _block[i] ^ (_K[i] = _hash[i]); + } + + // iterate over the rounds + for (int round = 1; round <= ROUNDS; round++) + { + for (int i = 0; i < 8; i++) + { + _L[i] = 0; + _L[i] ^= C0[(int)(_K[(i - 0) & 7] >> 56) & 0xff]; + _L[i] ^= C1[(int)(_K[(i - 1) & 7] >> 48) & 0xff]; + _L[i] ^= C2[(int)(_K[(i - 2) & 7] >> 40) & 0xff]; + _L[i] ^= C3[(int)(_K[(i - 3) & 7] >> 32) & 0xff]; + _L[i] ^= C4[(int)(_K[(i - 4) & 7] >> 24) & 0xff]; + _L[i] ^= C5[(int)(_K[(i - 5) & 7] >> 16) & 0xff]; + _L[i] ^= C6[(int)(_K[(i - 6) & 7] >> 8) & 0xff]; + _L[i] ^= C7[(int)(_K[(i - 7) & 7]) & 0xff]; + } + + Array.Copy(_L, 0, _K, 0, _K.Length); + + _K[0] ^= _rc[round]; + + // apply the round transformation + for (int i = 0; i < 8; i++) + { + _L[i] = _K[i]; + + _L[i] ^= C0[(int)(_state[(i - 0) & 7] >> 56) & 0xff]; + _L[i] ^= C1[(int)(_state[(i - 1) & 7] >> 48) & 0xff]; + _L[i] ^= C2[(int)(_state[(i - 2) & 7] >> 40) & 0xff]; + _L[i] ^= C3[(int)(_state[(i - 3) & 7] >> 32) & 0xff]; + _L[i] ^= C4[(int)(_state[(i - 4) & 7] >> 24) & 0xff]; + _L[i] ^= C5[(int)(_state[(i - 5) & 7] >> 16) & 0xff]; + _L[i] ^= C6[(int)(_state[(i - 6) & 7] >> 8) & 0xff]; + _L[i] ^= C7[(int)(_state[(i - 7) & 7]) & 0xff]; + } + + // save the current state + Array.Copy(_L, 0, _state, 0, _state.Length); + } + + // apply Miuaguchi-Preneel compression + for (int i = 0; i < 8; i++) + { + _hash[i] ^= _state[i] ^ _block[i]; + } + + } + + public void Update(byte input) + { + _buffer[_bufferPos] = input; + + //Console.WriteLine("adding to buffer = "+_buffer[_bufferPos]); + + ++_bufferPos; + + if (_bufferPos == _buffer.Length) + { + processFilledBuffer(); + } + + increment(); + } + + private void increment() + { + int carry = 0; + for (int i = _bitCount.Length - 1; i >= 0; i--) + { + int sum = (_bitCount[i] & 0xff) + EIGHT[i] + carry; + + carry = sum >> 8; + _bitCount[i] = (short)(sum & 0xff); + } + } + + public void BlockUpdate(byte[] input, int inOff, int length) + { + while (length > 0) + { + Update(input[inOff]); + ++inOff; + --length; + } + + } + + private void finish() + { + /* + * this makes a copy of the current bit length. at the expense of an + * object creation of 32 bytes rather than providing a _stopCounting + * boolean which was the alternative I could think of. + */ + byte[] bitLength = copyBitLength(); + + _buffer[_bufferPos++] |= 0x80; + + if (_bufferPos == _buffer.Length) + { + processFilledBuffer(); + } + + /* + * Final block contains + * [ ... data .... ][0][0][0][ length ] + * + * if [ length ] cannot fit. Need to create a new block. + */ + if (_bufferPos > 32) + { + while (_bufferPos != 0) + { + Update((byte)0); + } + } + + while (_bufferPos <= 32) + { + Update((byte)0); + } + + // copy the length information to the final 32 bytes of the + // 64 byte block.... + Array.Copy(bitLength, 0, _buffer, 32, bitLength.Length); + + processFilledBuffer(); + } + + private byte[] copyBitLength() + { + byte[] rv = new byte[BITCOUNT_ARRAY_SIZE]; + for (int i = 0; i < rv.Length; i++) + { + rv[i] = (byte)(_bitCount[i] & 0xff); + } + return rv; + } + + public int GetByteLength() + { + return BYTE_LENGTH; + } + } +} diff --git a/iTechSharp/srcbc/crypto/encodings/ISO9796d1Encoding.cs b/iTechSharp/srcbc/crypto/encodings/ISO9796d1Encoding.cs new file mode 100644 index 0000000..586a5b9 --- /dev/null +++ b/iTechSharp/srcbc/crypto/encodings/ISO9796d1Encoding.cs @@ -0,0 +1,253 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Encodings +{ + /** + * ISO 9796-1 padding. Note in the light of recent results you should + * only use this with RSA (rather than the "simpler" Rabin keys) and you + * should never use it with anything other than a hash (ie. even if the + * message is small don't sign the message, sign it's hash) or some "random" + * value. See your favorite search engine for details. + */ + public class ISO9796d1Encoding + : IAsymmetricBlockCipher + { + private static readonly byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf, + 0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 }; + private static readonly byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc, + 0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 }; + + private readonly IAsymmetricBlockCipher engine; + private bool forEncryption; + private int bitSize; + private int padBits = 0; + + public ISO9796d1Encoding( + IAsymmetricBlockCipher cipher) + { + this.engine = cipher; + } + + public string AlgorithmName + { + get { return engine.AlgorithmName + "/ISO9796-1Padding"; } + } + + public IAsymmetricBlockCipher GetUnderlyingCipher() + { + return engine; + } + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + RsaKeyParameters kParam; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + kParam = (RsaKeyParameters)rParam.Parameters; + } + else + { + kParam = (RsaKeyParameters)parameters; + } + + engine.Init(forEncryption, parameters); + + bitSize = kParam.Modulus.BitLength; + + this.forEncryption = forEncryption; + } + + /** + * return the input block size. The largest message we can process + * is (key_size_in_bits + 3)/16, which in our world comes to + * key_size_in_bytes / 2. + */ + public int GetInputBlockSize() + { + int baseBlockSize = engine.GetInputBlockSize(); + + if (forEncryption) + { + return (baseBlockSize + 1) / 2; + } + else + { + return baseBlockSize; + } + } + + /** + * return the maximum possible size for the output. + */ + public int GetOutputBlockSize() + { + int baseBlockSize = engine.GetOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return (baseBlockSize + 1) / 2; + } + } + + /** + * set the number of bits in the next message to be treated as + * pad bits. + */ + public void SetPadBits( + int padBits) + { + if (padBits > 7) + { + throw new ArgumentException("padBits > 7"); + } + + this.padBits = padBits; + } + + /** + * retrieve the number of pad bits in the last decoded message. + */ + public int GetPadBits() + { + return padBits; + } + + public byte[] ProcessBlock( + byte[] input, + int inOff, + int length) + { + if (forEncryption) + { + return EncodeBlock(input, inOff, length); + } + else + { + return DecodeBlock(input, inOff, length); + } + } + + private byte[] EncodeBlock( + byte[] input, + int inOff, + int inLen) + { + byte[] block = new byte[(bitSize + 7) / 8]; + int r = padBits + 1; + int z = inLen; + int t = (bitSize + 13) / 16; + + for (int i = 0; i < t; i += z) + { + if (i > t - z) + { + Array.Copy(input, inOff + inLen - (t - i), + block, block.Length - t, t - i); + } + else + { + Array.Copy(input, inOff, block, block.Length - (i + z), z); + } + } + + for (int i = block.Length - 2 * t; i != block.Length; i += 2) + { + byte val = block[block.Length - t + i / 2]; + + block[i] = (byte)((shadows[(uint) (val & 0xff) >> 4] << 4) + | shadows[val & 0x0f]); + block[i + 1] = val; + } + + block[block.Length - 2 * z] ^= (byte) r; + block[block.Length - 1] = (byte)((block[block.Length - 1] << 4) | 0x06); + + int maxBit = (8 - (bitSize - 1) % 8); + int offSet = 0; + + if (maxBit != 8) + { + block[0] &= (byte) ((ushort) 0xff >> maxBit); + block[0] |= (byte) ((ushort) 0x80 >> maxBit); + } + else + { + block[0] = 0x00; + block[1] |= 0x80; + offSet = 1; + } + + return engine.ProcessBlock(block, offSet, block.Length - offSet); + } + + /** + * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string + */ + private byte[] DecodeBlock( + byte[] input, + int inOff, + int inLen) + { + byte[] block = engine.ProcessBlock(input, inOff, inLen); + int r = 1; + int t = (bitSize + 13) / 16; + + if ((block[block.Length - 1] & 0x0f) != 0x6) + { + throw new InvalidCipherTextException("invalid forcing byte in block"); + } + + block[block.Length - 1] = + (byte)(((ushort)(block[block.Length - 1] & 0xff) >> 4) + | ((inverse[(block[block.Length - 2] & 0xff) >> 4]) << 4)); + + block[0] = (byte)((shadows[(uint) (block[1] & 0xff) >> 4] << 4) + | shadows[block[1] & 0x0f]); + + bool boundaryFound = false; + int boundary = 0; + + for (int i = block.Length - 1; i >= block.Length - 2 * t; i -= 2) + { + int val = ((shadows[(uint) (block[i] & 0xff) >> 4] << 4) + | shadows[block[i] & 0x0f]); + + if (((block[i - 1] ^ val) & 0xff) != 0) + { + if (!boundaryFound) + { + boundaryFound = true; + r = (block[i - 1] ^ val) & 0xff; + boundary = i - 1; + } + else + { + throw new InvalidCipherTextException("invalid tsums in block"); + } + } + } + + block[boundary] = 0; + + byte[] nblock = new byte[(block.Length - boundary) / 2]; + + for (int i = 0; i < nblock.Length; i++) + { + nblock[i] = block[2 * i + boundary + 1]; + } + + padBits = r - 1; + + return nblock; + } + } +} diff --git a/iTechSharp/srcbc/crypto/encodings/OaepEncoding.cs b/iTechSharp/srcbc/crypto/encodings/OaepEncoding.cs new file mode 100644 index 0000000..aff4a79 --- /dev/null +++ b/iTechSharp/srcbc/crypto/encodings/OaepEncoding.cs @@ -0,0 +1,334 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Encodings +{ + /** + * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2. + */ + public class OaepEncoding + : IAsymmetricBlockCipher + { + private byte[] defHash; + private IDigest hash; + + private IAsymmetricBlockCipher engine; + private SecureRandom random; + private bool forEncryption; + + public OaepEncoding( + IAsymmetricBlockCipher cipher) + : this(cipher, new Sha1Digest(), null) + { + } + + public OaepEncoding( + IAsymmetricBlockCipher cipher, + IDigest hash) + : this(cipher, hash, null) + { + } + + public OaepEncoding( + IAsymmetricBlockCipher cipher, + IDigest hash, + byte[] encodingParams) + { + this.engine = cipher; + this.hash = hash; + this.defHash = new byte[hash.GetDigestSize()]; + + if (encodingParams != null) + { + hash.BlockUpdate(encodingParams, 0, encodingParams.Length); + } + + hash.DoFinal(defHash, 0); + } + + public IAsymmetricBlockCipher GetUnderlyingCipher() + { + return engine; + } + + public string AlgorithmName + { + get { return engine.AlgorithmName + "/OAEPPadding"; } + } + + public void Init( + bool forEncryption, + ICipherParameters param) + { + if (param is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + this.random = rParam.Random; + } + else + { + this.random = new SecureRandom(); + } + + engine.Init(forEncryption, param); + + this.forEncryption = forEncryption; + } + + public int GetInputBlockSize() + { + int baseBlockSize = engine.GetInputBlockSize(); + + if (forEncryption) + { + return baseBlockSize - 1 - 2 * defHash.Length; + } + else + { + return baseBlockSize; + } + } + + public int GetOutputBlockSize() + { + int baseBlockSize = engine.GetOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return baseBlockSize - 1 - 2 * defHash.Length; + } + } + + public byte[] ProcessBlock( + byte[] inBytes, + int inOff, + int inLen) + { + if (forEncryption) + { + return encodeBlock(inBytes, inOff, inLen); + } + else + { + return decodeBlock(inBytes, inOff, inLen); + } + } + + private byte[] encodeBlock( + byte[] inBytes, + int inOff, + int inLen) + { + byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length]; + + // + // copy in the message + // + Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen); + + // + // add sentinel + // + block[block.Length - inLen - 1] = 0x01; + + // + // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0) + // + + // + // add the hash of the encoding params. + // + Array.Copy(defHash, 0, block, defHash.Length, defHash.Length); + + // + // generate the seed. + // + byte[] seed = random.GenerateSeed(defHash.Length); + + // + // mask the message block. + // + byte[] mask = maskGeneratorFunction1(seed, 0, seed.Length, block.Length - defHash.Length); + + for (int i = defHash.Length; i != block.Length; i++) + { + block[i] ^= mask[i - defHash.Length]; + } + + // + // add in the seed + // + Array.Copy(seed, 0, block, 0, defHash.Length); + + // + // mask the seed. + // + mask = maskGeneratorFunction1( + block, defHash.Length, block.Length - defHash.Length, defHash.Length); + + for (int i = 0; i != defHash.Length; i++) + { + block[i] ^= mask[i]; + } + + return engine.ProcessBlock(block, 0, block.Length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block turns out to + * be badly formatted. + */ + private byte[] decodeBlock( + byte[] inBytes, + int inOff, + int inLen) + { + byte[] data = engine.ProcessBlock(inBytes, inOff, inLen); + byte[] block = null; + + // + // as we may have zeros in our leading bytes for the block we produced + // on encryption, we need to make sure our decrypted block comes back + // the same size. + // + if (data.Length < engine.GetOutputBlockSize()) + { + block = new byte[engine.GetOutputBlockSize()]; + + Array.Copy(data, 0, block, block.Length - data.Length, data.Length); + } + else + { + block = data; + } + + if (block.Length < (2 * defHash.Length) + 1) + { + throw new InvalidCipherTextException("data too short"); + } + + // + // unmask the seed. + // + byte[] mask = maskGeneratorFunction1( + block, defHash.Length, block.Length - defHash.Length, defHash.Length); + + for (int i = 0; i != defHash.Length; i++) + { + block[i] ^= mask[i]; + } + + // + // unmask the message block. + // + mask = maskGeneratorFunction1(block, 0, defHash.Length, block.Length - defHash.Length); + + for (int i = defHash.Length; i != block.Length; i++) + { + block[i] ^= mask[i - defHash.Length]; + } + + // + // check the hash of the encoding params. + // + for (int i = 0; i != defHash.Length; i++) + { + if (defHash[i] != block[defHash.Length + i]) + { + throw new InvalidCipherTextException("data hash wrong"); + } + } + + // + // find the data block + // + int start; + for (start = 2 * defHash.Length; start != block.Length; start++) + { + if (block[start] == 1 || block[start] != 0) + { + break; + } + } + + if (start >= (block.Length - 1) || block[start] != 1) + { + throw new InvalidCipherTextException("data start wrong " + start); + } + + start++; + + // + // extract the data block + // + byte[] output = new byte[block.Length - start]; + + Array.Copy(block, start, output, 0, output.Length); + + return output; + } + + /** + * int to octet string. + */ + private void ItoOSP( + int i, + byte[] sp) + { + sp[0] = (byte)((uint)i >> 24); + sp[1] = (byte)((uint)i >> 16); + sp[2] = (byte)((uint)i >> 8); + sp[3] = (byte)((uint)i >> 0); + } + + /** + * mask generator function, as described in PKCS1v2. + */ + private byte[] maskGeneratorFunction1( + byte[] Z, + int zOff, + int zLen, + int length) + { + byte[] mask = new byte[length]; + byte[] hashBuf = new byte[defHash.Length]; + byte[] C = new byte[4]; + int counter = 0; + + hash.Reset(); + + do + { + ItoOSP(counter, C); + + hash.BlockUpdate(Z, zOff, zLen); + hash.BlockUpdate(C, 0, C.Length); + hash.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * defHash.Length, defHash.Length); + } + while (++counter < (length / defHash.Length)); + + if ((counter * defHash.Length) < length) + { + ItoOSP(counter, C); + + hash.BlockUpdate(Z, zOff, zLen); + hash.BlockUpdate(C, 0, C.Length); + hash.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * defHash.Length, mask.Length - (counter * defHash.Length)); + } + + return mask; + } + } +} + diff --git a/iTechSharp/srcbc/crypto/encodings/Pkcs1Encoding.cs b/iTechSharp/srcbc/crypto/encodings/Pkcs1Encoding.cs new file mode 100644 index 0000000..f8204c2 --- /dev/null +++ b/iTechSharp/srcbc/crypto/encodings/Pkcs1Encoding.cs @@ -0,0 +1,229 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Encodings +{ + /** + * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this + * depends on your application - see Pkcs1 Version 2 for details. + */ + public class Pkcs1Encoding + : IAsymmetricBlockCipher + { + /** + * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to + * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false. + */ + public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict"; + + private const int HeaderLength = 10; + + /** + * The same effect can be achieved by setting the static property directly + *

      + * The static property is checked during construction of the encoding object, it is set to + * true by default. + *

      + */ + public static bool StrictLengthEnabled + { + get { return strictLengthEnabled[0]; } + set { strictLengthEnabled[0] = value; } + } + + private static readonly bool[] strictLengthEnabled; + + static Pkcs1Encoding() + { + string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty); + + strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")}; + } + + + private SecureRandom random; + private IAsymmetricBlockCipher engine; + private bool forEncryption; + private bool forPrivateKey; + private bool useStrictLength; + + /** + * Basic constructor. + * @param cipher + */ + public Pkcs1Encoding( + IAsymmetricBlockCipher cipher) + { + this.engine = cipher; + this.useStrictLength = StrictLengthEnabled; + } + + public IAsymmetricBlockCipher GetUnderlyingCipher() + { + return engine; + } + + public string AlgorithmName + { + get { return engine.AlgorithmName + "/PKCS1Padding"; } + } + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + AsymmetricKeyParameter kParam; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + + this.random = rParam.Random; + kParam = (AsymmetricKeyParameter)rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + kParam = (AsymmetricKeyParameter)parameters; + } + + engine.Init(forEncryption, parameters); + + this.forPrivateKey = kParam.IsPrivate; + this.forEncryption = forEncryption; + } + + public int GetInputBlockSize() + { + int baseBlockSize = engine.GetInputBlockSize(); + + return forEncryption + ? baseBlockSize - HeaderLength + : baseBlockSize; + } + + public int GetOutputBlockSize() + { + int baseBlockSize = engine.GetOutputBlockSize(); + + return forEncryption + ? baseBlockSize + : baseBlockSize - HeaderLength; + } + + public byte[] ProcessBlock( + byte[] input, + int inOff, + int length) + { + return forEncryption + ? EncodeBlock(input, inOff, length) + : DecodeBlock(input, inOff, length); + } + + private byte[] EncodeBlock( + byte[] input, + int inOff, + int inLen) + { + byte[] block = new byte[engine.GetInputBlockSize()]; + + if (forPrivateKey) + { + block[0] = 0x01; // type code 1 + + for (int i = 1; i != block.Length - inLen - 1; i++) + { + block[i] = (byte)0xFF; + } + } + else + { + random.NextBytes(block); // random fill + + block[0] = 0x02; // type code 2 + + // + // a zero byte marks the end of the padding, so all + // the pad bytes must be non-zero. + // + for (int i = 1; i != block.Length - inLen - 1; i++) + { + while (block[i] == 0) + { + block[i] = (byte)random.NextInt(); + } + } + } + + block[block.Length - inLen - 1] = 0x00; // mark the end of the padding + Array.Copy(input, inOff, block, block.Length - inLen, inLen); + + return engine.ProcessBlock(block, 0, block.Length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format. + */ + private byte[] DecodeBlock( + byte[] input, + int inOff, + int inLen) + { + byte[] block = engine.ProcessBlock(input, inOff, inLen); + + if (block.Length < GetOutputBlockSize()) + { + throw new InvalidCipherTextException("block truncated"); + } + + byte type = block[0]; + + if (type != 1 && type != 2) + { + throw new InvalidCipherTextException("unknown block type"); + } + + if (useStrictLength && block.Length != engine.GetOutputBlockSize()) + { + throw new InvalidCipherTextException("block incorrect size"); + } + + // + // find and extract the message block. + // + int start; + for (start = 1; start != block.Length; start++) + { + byte pad = block[start]; + + if (pad == 0) + { + break; + } + + if (type == 1 && pad != (byte)0xff) + { + throw new InvalidCipherTextException("block padding incorrect"); + } + } + + start++; // data should start at the next byte + + if (start >= block.Length || start < HeaderLength) + { + throw new InvalidCipherTextException("no data in block"); + } + + byte[] result = new byte[block.Length - start]; + + Array.Copy(block, start, result, 0, result.Length); + + return result; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/AesEngine.cs b/iTechSharp/srcbc/crypto/engines/AesEngine.cs new file mode 100644 index 0000000..676d7dd --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/AesEngine.cs @@ -0,0 +1,550 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + + /** + * an implementation of the AES (Rijndael), from FIPS-197. + *

      + * For further details see: http://csrc.nist.gov/encryption/aes/. + * + * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + * + * There are three levels of tradeoff of speed vs memory + * Because java has no preprocessor, they are written as three separate classes from which to choose + * + * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption + * and 4 for decryption. + * + * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, + * adding 12 rotate operations per round to compute the values contained in the other tables from + * the contents of the first. + * + * The slowest version uses no static tables at all and computes the values in each round. + *

      + *

      + * This file contains the middle performance version with 2Kbytes of static tables for round precomputation. + *

      + */ + public class AesEngine + : IBlockCipher + { + // The S box + private static readonly byte[] S = + { + 99, 124, 119, 123, 242, 107, 111, 197, + 48, 1, 103, 43, 254, 215, 171, 118, + 202, 130, 201, 125, 250, 89, 71, 240, + 173, 212, 162, 175, 156, 164, 114, 192, + 183, 253, 147, 38, 54, 63, 247, 204, + 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, + 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, + 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, + 106, 203, 190, 57, 74, 76, 88, 207, + 208, 239, 170, 251, 67, 77, 51, 133, + 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, + 188, 182, 218, 33, 16, 255, 243, 210, + 205, 12, 19, 236, 95, 151, 68, 23, + 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, + 70, 238, 184, 20, 222, 94, 11, 219, + 224, 50, 58, 10, 73, 6, 36, 92, + 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, + 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, + 232, 221, 116, 31, 75, 189, 139, 138, + 112, 62, 181, 102, 72, 3, 246, 14, + 97, 53, 87, 185, 134, 193, 29, 158, + 225, 248, 152, 17, 105, 217, 142, 148, + 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, + 65, 153, 45, 15, 176, 84, 187, 22, + }; + + // The inverse S-box + private static readonly byte[] Si = + { + 82, 9, 106, 213, 48, 54, 165, 56, + 191, 64, 163, 158, 129, 243, 215, 251, + 124, 227, 57, 130, 155, 47, 255, 135, + 52, 142, 67, 68, 196, 222, 233, 203, + 84, 123, 148, 50, 166, 194, 35, 61, + 238, 76, 149, 11, 66, 250, 195, 78, + 8, 46, 161, 102, 40, 217, 36, 178, + 118, 91, 162, 73, 109, 139, 209, 37, + 114, 248, 246, 100, 134, 104, 152, 22, + 212, 164, 92, 204, 93, 101, 182, 146, + 108, 112, 72, 80, 253, 237, 185, 218, + 94, 21, 70, 87, 167, 141, 157, 132, + 144, 216, 171, 0, 140, 188, 211, 10, + 247, 228, 88, 5, 184, 179, 69, 6, + 208, 44, 30, 143, 202, 63, 15, 2, + 193, 175, 189, 3, 1, 19, 138, 107, + 58, 145, 17, 65, 79, 103, 220, 234, + 151, 242, 207, 206, 240, 180, 230, 115, + 150, 172, 116, 34, 231, 173, 53, 133, + 226, 249, 55, 232, 28, 117, 223, 110, + 71, 241, 26, 113, 29, 41, 197, 137, + 111, 183, 98, 14, 170, 24, 190, 27, + 252, 86, 62, 75, 198, 210, 121, 32, + 154, 219, 192, 254, 120, 205, 90, 244, + 31, 221, 168, 51, 136, 7, 199, 49, + 177, 18, 16, 89, 39, 128, 236, 95, + 96, 81, 127, 169, 25, 181, 74, 13, + 45, 229, 122, 159, 147, 201, 156, 239, + 160, 224, 59, 77, 174, 42, 245, 176, + 200, 235, 187, 60, 131, 83, 153, 97, + 23, 43, 4, 126, 186, 119, 214, 38, + 225, 105, 20, 99, 85, 33, 12, 125, + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static readonly int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + // precomputation tables of calculations for rounds + private static readonly int[] T0 = + { + unchecked((int) 0xa56363c6), unchecked((int) 0x847c7cf8), unchecked((int) 0x997777ee), unchecked((int) 0x8d7b7bf6), unchecked((int) 0x0df2f2ff), + unchecked((int) 0xbd6b6bd6), unchecked((int) 0xb16f6fde), unchecked((int) 0x54c5c591), unchecked((int) 0x50303060), unchecked((int) 0x03010102), + unchecked((int) 0xa96767ce), unchecked((int) 0x7d2b2b56), unchecked((int) 0x19fefee7), unchecked((int) 0x62d7d7b5), unchecked((int) 0xe6abab4d), + unchecked((int) 0x9a7676ec), unchecked((int) 0x45caca8f), unchecked((int) 0x9d82821f), unchecked((int) 0x40c9c989), unchecked((int) 0x877d7dfa), + unchecked((int) 0x15fafaef), unchecked((int) 0xeb5959b2), unchecked((int) 0xc947478e), unchecked((int) 0x0bf0f0fb), unchecked((int) 0xecadad41), + unchecked((int) 0x67d4d4b3), unchecked((int) 0xfda2a25f), unchecked((int) 0xeaafaf45), unchecked((int) 0xbf9c9c23), unchecked((int) 0xf7a4a453), + unchecked((int) 0x967272e4), unchecked((int) 0x5bc0c09b), unchecked((int) 0xc2b7b775), unchecked((int) 0x1cfdfde1), unchecked((int) 0xae93933d), + unchecked((int) 0x6a26264c), unchecked((int) 0x5a36366c), unchecked((int) 0x413f3f7e), unchecked((int) 0x02f7f7f5), unchecked((int) 0x4fcccc83), + unchecked((int) 0x5c343468), unchecked((int) 0xf4a5a551), unchecked((int) 0x34e5e5d1), unchecked((int) 0x08f1f1f9), unchecked((int) 0x937171e2), + unchecked((int) 0x73d8d8ab), unchecked((int) 0x53313162), unchecked((int) 0x3f15152a), unchecked((int) 0x0c040408), unchecked((int) 0x52c7c795), + unchecked((int) 0x65232346), unchecked((int) 0x5ec3c39d), unchecked((int) 0x28181830), unchecked((int) 0xa1969637), unchecked((int) 0x0f05050a), + unchecked((int) 0xb59a9a2f), unchecked((int) 0x0907070e), unchecked((int) 0x36121224), unchecked((int) 0x9b80801b), unchecked((int) 0x3de2e2df), + unchecked((int) 0x26ebebcd), unchecked((int) 0x6927274e), unchecked((int) 0xcdb2b27f), unchecked((int) 0x9f7575ea), unchecked((int) 0x1b090912), + unchecked((int) 0x9e83831d), unchecked((int) 0x742c2c58), unchecked((int) 0x2e1a1a34), unchecked((int) 0x2d1b1b36), unchecked((int) 0xb26e6edc), + unchecked((int) 0xee5a5ab4), unchecked((int) 0xfba0a05b), unchecked((int) 0xf65252a4), unchecked((int) 0x4d3b3b76), unchecked((int) 0x61d6d6b7), + unchecked((int) 0xceb3b37d), unchecked((int) 0x7b292952), unchecked((int) 0x3ee3e3dd), unchecked((int) 0x712f2f5e), unchecked((int) 0x97848413), + unchecked((int) 0xf55353a6), unchecked((int) 0x68d1d1b9), unchecked((int) 0x00000000), unchecked((int) 0x2cededc1), unchecked((int) 0x60202040), + unchecked((int) 0x1ffcfce3), unchecked((int) 0xc8b1b179), unchecked((int) 0xed5b5bb6), unchecked((int) 0xbe6a6ad4), unchecked((int) 0x46cbcb8d), + unchecked((int) 0xd9bebe67), unchecked((int) 0x4b393972), unchecked((int) 0xde4a4a94), unchecked((int) 0xd44c4c98), unchecked((int) 0xe85858b0), + unchecked((int) 0x4acfcf85), unchecked((int) 0x6bd0d0bb), unchecked((int) 0x2aefefc5), unchecked((int) 0xe5aaaa4f), unchecked((int) 0x16fbfbed), + unchecked((int) 0xc5434386), unchecked((int) 0xd74d4d9a), unchecked((int) 0x55333366), unchecked((int) 0x94858511), unchecked((int) 0xcf45458a), + unchecked((int) 0x10f9f9e9), unchecked((int) 0x06020204), unchecked((int) 0x817f7ffe), unchecked((int) 0xf05050a0), unchecked((int) 0x443c3c78), + unchecked((int) 0xba9f9f25), unchecked((int) 0xe3a8a84b), unchecked((int) 0xf35151a2), unchecked((int) 0xfea3a35d), unchecked((int) 0xc0404080), + unchecked((int) 0x8a8f8f05), unchecked((int) 0xad92923f), unchecked((int) 0xbc9d9d21), unchecked((int) 0x48383870), unchecked((int) 0x04f5f5f1), + unchecked((int) 0xdfbcbc63), unchecked((int) 0xc1b6b677), unchecked((int) 0x75dadaaf), unchecked((int) 0x63212142), unchecked((int) 0x30101020), + unchecked((int) 0x1affffe5), unchecked((int) 0x0ef3f3fd), unchecked((int) 0x6dd2d2bf), unchecked((int) 0x4ccdcd81), unchecked((int) 0x140c0c18), + unchecked((int) 0x35131326), unchecked((int) 0x2fececc3), unchecked((int) 0xe15f5fbe), unchecked((int) 0xa2979735), unchecked((int) 0xcc444488), + unchecked((int) 0x3917172e), unchecked((int) 0x57c4c493), unchecked((int) 0xf2a7a755), unchecked((int) 0x827e7efc), unchecked((int) 0x473d3d7a), + unchecked((int) 0xac6464c8), unchecked((int) 0xe75d5dba), unchecked((int) 0x2b191932), unchecked((int) 0x957373e6), unchecked((int) 0xa06060c0), + unchecked((int) 0x98818119), unchecked((int) 0xd14f4f9e), unchecked((int) 0x7fdcdca3), unchecked((int) 0x66222244), unchecked((int) 0x7e2a2a54), + unchecked((int) 0xab90903b), unchecked((int) 0x8388880b), unchecked((int) 0xca46468c), unchecked((int) 0x29eeeec7), unchecked((int) 0xd3b8b86b), + unchecked((int) 0x3c141428), unchecked((int) 0x79dedea7), unchecked((int) 0xe25e5ebc), unchecked((int) 0x1d0b0b16), unchecked((int) 0x76dbdbad), + unchecked((int) 0x3be0e0db), unchecked((int) 0x56323264), unchecked((int) 0x4e3a3a74), unchecked((int) 0x1e0a0a14), unchecked((int) 0xdb494992), + unchecked((int) 0x0a06060c), unchecked((int) 0x6c242448), unchecked((int) 0xe45c5cb8), unchecked((int) 0x5dc2c29f), unchecked((int) 0x6ed3d3bd), + unchecked((int) 0xefacac43), unchecked((int) 0xa66262c4), unchecked((int) 0xa8919139), unchecked((int) 0xa4959531), unchecked((int) 0x37e4e4d3), + unchecked((int) 0x8b7979f2), unchecked((int) 0x32e7e7d5), unchecked((int) 0x43c8c88b), unchecked((int) 0x5937376e), unchecked((int) 0xb76d6dda), + unchecked((int) 0x8c8d8d01), unchecked((int) 0x64d5d5b1), unchecked((int) 0xd24e4e9c), unchecked((int) 0xe0a9a949), unchecked((int) 0xb46c6cd8), + unchecked((int) 0xfa5656ac), unchecked((int) 0x07f4f4f3), unchecked((int) 0x25eaeacf), unchecked((int) 0xaf6565ca), unchecked((int) 0x8e7a7af4), + unchecked((int) 0xe9aeae47), unchecked((int) 0x18080810), unchecked((int) 0xd5baba6f), unchecked((int) 0x887878f0), unchecked((int) 0x6f25254a), + unchecked((int) 0x722e2e5c), unchecked((int) 0x241c1c38), unchecked((int) 0xf1a6a657), unchecked((int) 0xc7b4b473), unchecked((int) 0x51c6c697), + unchecked((int) 0x23e8e8cb), unchecked((int) 0x7cdddda1), unchecked((int) 0x9c7474e8), unchecked((int) 0x211f1f3e), unchecked((int) 0xdd4b4b96), + unchecked((int) 0xdcbdbd61), unchecked((int) 0x868b8b0d), unchecked((int) 0x858a8a0f), unchecked((int) 0x907070e0), unchecked((int) 0x423e3e7c), + unchecked((int) 0xc4b5b571), unchecked((int) 0xaa6666cc), unchecked((int) 0xd8484890), unchecked((int) 0x05030306), unchecked((int) 0x01f6f6f7), + unchecked((int) 0x120e0e1c), unchecked((int) 0xa36161c2), unchecked((int) 0x5f35356a), unchecked((int) 0xf95757ae), unchecked((int) 0xd0b9b969), + unchecked((int) 0x91868617), unchecked((int) 0x58c1c199), unchecked((int) 0x271d1d3a), unchecked((int) 0xb99e9e27), unchecked((int) 0x38e1e1d9), + unchecked((int) 0x13f8f8eb), unchecked((int) 0xb398982b), unchecked((int) 0x33111122), unchecked((int) 0xbb6969d2), unchecked((int) 0x70d9d9a9), + unchecked((int) 0x898e8e07), unchecked((int) 0xa7949433), unchecked((int) 0xb69b9b2d), unchecked((int) 0x221e1e3c), unchecked((int) 0x92878715), + unchecked((int) 0x20e9e9c9), unchecked((int) 0x49cece87), unchecked((int) 0xff5555aa), unchecked((int) 0x78282850), unchecked((int) 0x7adfdfa5), + unchecked((int) 0x8f8c8c03), unchecked((int) 0xf8a1a159), unchecked((int) 0x80898909), unchecked((int) 0x170d0d1a), unchecked((int) 0xdabfbf65), + unchecked((int) 0x31e6e6d7), unchecked((int) 0xc6424284), unchecked((int) 0xb86868d0), unchecked((int) 0xc3414182), unchecked((int) 0xb0999929), + unchecked((int) 0x772d2d5a), unchecked((int) 0x110f0f1e), unchecked((int) 0xcbb0b07b), unchecked((int) 0xfc5454a8), unchecked((int) 0xd6bbbb6d), + unchecked((int) 0x3a16162c) + }; + + private static readonly int[] Tinv0 = + { + unchecked((int) 0x50a7f451), unchecked((int) 0x5365417e), unchecked((int) 0xc3a4171a), unchecked((int) 0x965e273a), unchecked((int) 0xcb6bab3b), + unchecked((int) 0xf1459d1f), unchecked((int) 0xab58faac), unchecked((int) 0x9303e34b), unchecked((int) 0x55fa3020), unchecked((int) 0xf66d76ad), + unchecked((int) 0x9176cc88), unchecked((int) 0x254c02f5), unchecked((int) 0xfcd7e54f), unchecked((int) 0xd7cb2ac5), unchecked((int) 0x80443526), + unchecked((int) 0x8fa362b5), unchecked((int) 0x495ab1de), unchecked((int) 0x671bba25), unchecked((int) 0x980eea45), unchecked((int) 0xe1c0fe5d), + unchecked((int) 0x02752fc3), unchecked((int) 0x12f04c81), unchecked((int) 0xa397468d), unchecked((int) 0xc6f9d36b), unchecked((int) 0xe75f8f03), + unchecked((int) 0x959c9215), unchecked((int) 0xeb7a6dbf), unchecked((int) 0xda595295), unchecked((int) 0x2d83bed4), unchecked((int) 0xd3217458), + unchecked((int) 0x2969e049), unchecked((int) 0x44c8c98e), unchecked((int) 0x6a89c275), unchecked((int) 0x78798ef4), unchecked((int) 0x6b3e5899), + unchecked((int) 0xdd71b927), unchecked((int) 0xb64fe1be), unchecked((int) 0x17ad88f0), unchecked((int) 0x66ac20c9), unchecked((int) 0xb43ace7d), + unchecked((int) 0x184adf63), unchecked((int) 0x82311ae5), unchecked((int) 0x60335197), unchecked((int) 0x457f5362), unchecked((int) 0xe07764b1), + unchecked((int) 0x84ae6bbb), unchecked((int) 0x1ca081fe), unchecked((int) 0x942b08f9), unchecked((int) 0x58684870), unchecked((int) 0x19fd458f), + unchecked((int) 0x876cde94), unchecked((int) 0xb7f87b52), unchecked((int) 0x23d373ab), unchecked((int) 0xe2024b72), unchecked((int) 0x578f1fe3), + unchecked((int) 0x2aab5566), unchecked((int) 0x0728ebb2), unchecked((int) 0x03c2b52f), unchecked((int) 0x9a7bc586), unchecked((int) 0xa50837d3), + unchecked((int) 0xf2872830), unchecked((int) 0xb2a5bf23), unchecked((int) 0xba6a0302), unchecked((int) 0x5c8216ed), unchecked((int) 0x2b1ccf8a), + unchecked((int) 0x92b479a7), unchecked((int) 0xf0f207f3), unchecked((int) 0xa1e2694e), unchecked((int) 0xcdf4da65), unchecked((int) 0xd5be0506), + unchecked((int) 0x1f6234d1), unchecked((int) 0x8afea6c4), unchecked((int) 0x9d532e34), unchecked((int) 0xa055f3a2), unchecked((int) 0x32e18a05), + unchecked((int) 0x75ebf6a4), unchecked((int) 0x39ec830b), unchecked((int) 0xaaef6040), unchecked((int) 0x069f715e), unchecked((int) 0x51106ebd), + unchecked((int) 0xf98a213e), unchecked((int) 0x3d06dd96), unchecked((int) 0xae053edd), unchecked((int) 0x46bde64d), unchecked((int) 0xb58d5491), + unchecked((int) 0x055dc471), unchecked((int) 0x6fd40604), unchecked((int) 0xff155060), unchecked((int) 0x24fb9819), unchecked((int) 0x97e9bdd6), + unchecked((int) 0xcc434089), unchecked((int) 0x779ed967), unchecked((int) 0xbd42e8b0), unchecked((int) 0x888b8907), unchecked((int) 0x385b19e7), + unchecked((int) 0xdbeec879), unchecked((int) 0x470a7ca1), unchecked((int) 0xe90f427c), unchecked((int) 0xc91e84f8), unchecked((int) 0x00000000), + unchecked((int) 0x83868009), unchecked((int) 0x48ed2b32), unchecked((int) 0xac70111e), unchecked((int) 0x4e725a6c), unchecked((int) 0xfbff0efd), + unchecked((int) 0x5638850f), unchecked((int) 0x1ed5ae3d), unchecked((int) 0x27392d36), unchecked((int) 0x64d90f0a), unchecked((int) 0x21a65c68), + unchecked((int) 0xd1545b9b), unchecked((int) 0x3a2e3624), unchecked((int) 0xb1670a0c), unchecked((int) 0x0fe75793), unchecked((int) 0xd296eeb4), + unchecked((int) 0x9e919b1b), unchecked((int) 0x4fc5c080), unchecked((int) 0xa220dc61), unchecked((int) 0x694b775a), unchecked((int) 0x161a121c), + unchecked((int) 0x0aba93e2), unchecked((int) 0xe52aa0c0), unchecked((int) 0x43e0223c), unchecked((int) 0x1d171b12), unchecked((int) 0x0b0d090e), + unchecked((int) 0xadc78bf2), unchecked((int) 0xb9a8b62d), unchecked((int) 0xc8a91e14), unchecked((int) 0x8519f157), unchecked((int) 0x4c0775af), + unchecked((int) 0xbbdd99ee), unchecked((int) 0xfd607fa3), unchecked((int) 0x9f2601f7), unchecked((int) 0xbcf5725c), unchecked((int) 0xc53b6644), + unchecked((int) 0x347efb5b), unchecked((int) 0x7629438b), unchecked((int) 0xdcc623cb), unchecked((int) 0x68fcedb6), unchecked((int) 0x63f1e4b8), + unchecked((int) 0xcadc31d7), unchecked((int) 0x10856342), unchecked((int) 0x40229713), unchecked((int) 0x2011c684), unchecked((int) 0x7d244a85), + unchecked((int) 0xf83dbbd2), unchecked((int) 0x1132f9ae), unchecked((int) 0x6da129c7), unchecked((int) 0x4b2f9e1d), unchecked((int) 0xf330b2dc), + unchecked((int) 0xec52860d), unchecked((int) 0xd0e3c177), unchecked((int) 0x6c16b32b), unchecked((int) 0x99b970a9), unchecked((int) 0xfa489411), + unchecked((int) 0x2264e947), unchecked((int) 0xc48cfca8), unchecked((int) 0x1a3ff0a0), unchecked((int) 0xd82c7d56), unchecked((int) 0xef903322), + unchecked((int) 0xc74e4987), unchecked((int) 0xc1d138d9), unchecked((int) 0xfea2ca8c), unchecked((int) 0x360bd498), unchecked((int) 0xcf81f5a6), + unchecked((int) 0x28de7aa5), unchecked((int) 0x268eb7da), unchecked((int) 0xa4bfad3f), unchecked((int) 0xe49d3a2c), unchecked((int) 0x0d927850), + unchecked((int) 0x9bcc5f6a), unchecked((int) 0x62467e54), unchecked((int) 0xc2138df6), unchecked((int) 0xe8b8d890), unchecked((int) 0x5ef7392e), + unchecked((int) 0xf5afc382), unchecked((int) 0xbe805d9f), unchecked((int) 0x7c93d069), unchecked((int) 0xa92dd56f), unchecked((int) 0xb31225cf), + unchecked((int) 0x3b99acc8), unchecked((int) 0xa77d1810), unchecked((int) 0x6e639ce8), unchecked((int) 0x7bbb3bdb), unchecked((int) 0x097826cd), + unchecked((int) 0xf418596e), unchecked((int) 0x01b79aec), unchecked((int) 0xa89a4f83), unchecked((int) 0x656e95e6), unchecked((int) 0x7ee6ffaa), + unchecked((int) 0x08cfbc21), unchecked((int) 0xe6e815ef), unchecked((int) 0xd99be7ba), unchecked((int) 0xce366f4a), unchecked((int) 0xd4099fea), + unchecked((int) 0xd67cb029), unchecked((int) 0xafb2a431), unchecked((int) 0x31233f2a), unchecked((int) 0x3094a5c6), unchecked((int) 0xc066a235), + unchecked((int) 0x37bc4e74), unchecked((int) 0xa6ca82fc), unchecked((int) 0xb0d090e0), unchecked((int) 0x15d8a733), unchecked((int) 0x4a9804f1), + unchecked((int) 0xf7daec41), unchecked((int) 0x0e50cd7f), unchecked((int) 0x2ff69117), unchecked((int) 0x8dd64d76), unchecked((int) 0x4db0ef43), + unchecked((int) 0x544daacc), unchecked((int) 0xdf0496e4), unchecked((int) 0xe3b5d19e), unchecked((int) 0x1b886a4c), unchecked((int) 0xb81f2cc1), + unchecked((int) 0x7f516546), unchecked((int) 0x04ea5e9d), unchecked((int) 0x5d358c01), unchecked((int) 0x737487fa), unchecked((int) 0x2e410bfb), + unchecked((int) 0x5a1d67b3), unchecked((int) 0x52d2db92), unchecked((int) 0x335610e9), unchecked((int) 0x1347d66d), unchecked((int) 0x8c61d79a), + unchecked((int) 0x7a0ca137), unchecked((int) 0x8e14f859), unchecked((int) 0x893c13eb), unchecked((int) 0xee27a9ce), unchecked((int) 0x35c961b7), + unchecked((int) 0xede51ce1), unchecked((int) 0x3cb1477a), unchecked((int) 0x59dfd29c), unchecked((int) 0x3f73f255), unchecked((int) 0x79ce1418), + unchecked((int) 0xbf37c773), unchecked((int) 0xeacdf753), unchecked((int) 0x5baafd5f), unchecked((int) 0x146f3ddf), unchecked((int) 0x86db4478), + unchecked((int) 0x81f3afca), unchecked((int) 0x3ec468b9), unchecked((int) 0x2c342438), unchecked((int) 0x5f40a3c2), unchecked((int) 0x72c31d16), + unchecked((int) 0x0c25e2bc), unchecked((int) 0x8b493c28), unchecked((int) 0x41950dff), unchecked((int) 0x7101a839), unchecked((int) 0xdeb30c08), + unchecked((int) 0x9ce4b4d8), unchecked((int) 0x90c15664), unchecked((int) 0x6184cb7b), unchecked((int) 0x70b632d5), unchecked((int) 0x745c6c48), + unchecked((int) 0x4257b8d0) + }; + + private int Shift( + int r, + int shift) + { + return ((int)(((uint) r >> shift) | (uint)(r << (32 - shift)))); + } + + /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + + private const int m1 = unchecked((int) 0x80808080); + private const int m2 = unchecked((int) 0x7f7f7f7f); + private const int m3 = unchecked((int) 0x0000001b); + + private int FFmulX( + int x) + { + return ((int) (((x & m2) << 1) ^ (( (uint) (x & m1) >> 7) * m3))); + } + + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private int Inv_Mcol( + int x) + { + int f2 = FFmulX(x); + int f4 = FFmulX(f2); + int f8 = FFmulX(f4); + int f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + } + + private int SubWord(int x) { + return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + private int[,] GenerateWorkingKey( + byte[] key, + bool forEncryption) + { + int KC = key.Length / 4; // key length in words + int t; + + if ((KC != 4) && (KC != 6) && (KC != 8)) { + throw new ArgumentException("Key length not 128/192/256 bits."); + } + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + int[,] W = new int[ROUNDS+1, 4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + for (int i = 0; i < key.Length; t++) + { + W[t >> 2, t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); + i+=4; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for (int i = KC; (i < k); i++) + { + int temp = W[(i-1)>>2, (i-1)&3]; + if ((i % KC) == 0) { + temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1]; + } else if ((KC > 6) && ((i % KC) == 4)) { + temp = SubWord(temp); + } + + W[i>>2, i&3] = W[(i - KC)>>2, (i-KC)&3] ^ temp; + } + + if (!forEncryption) + { + for (int j = 1; j < ROUNDS; j++) + { + for (int i = 0; i < 4; i++) + { + W[j, i] = Inv_Mcol(W[j, i]); + } + } + } + + return W; + } + + private int ROUNDS; + private int[,] WorkingKey; + private int C0, C1, C2, C3; + private bool forEncryption; + + private const int BLOCK_SIZE = 16; + + /** + * default constructor - 128 bit block size. + */ + public AesEngine() + { + } + + /** + * initialise an AES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + KeyParameter keyParameter = parameters as KeyParameter; + + if (keyParameter == null) + throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name); + + WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption); + + this.forEncryption = forEncryption; + } + + public string AlgorithmName + { + get { return "AES"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (WorkingKey == null) + { + throw new InvalidOperationException("AES engine not initialised"); + } + + if ((inOff + (32 / 2)) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (32 / 2)) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + UnPackBlock(input, inOff); + + if (forEncryption) + { + EncryptBlock(WorkingKey); + } + else + { + DecryptBlock(WorkingKey); + } + + PackBlock(output, outOff); + + return BLOCK_SIZE; + } + + public void Reset() + { + } + + private void UnPackBlock( + byte[] bytes, + int off) + { + int index = off; + + C0 = (bytes[index++] & 0xff); + C0 |= (bytes[index++] & 0xff) << 8; + C0 |= (bytes[index++] & 0xff) << 16; + C0 |= bytes[index++] << 24; + + C1 = (bytes[index++] & 0xff); + C1 |= (bytes[index++] & 0xff) << 8; + C1 |= (bytes[index++] & 0xff) << 16; + C1 |= bytes[index++] << 24; + + C2 = (bytes[index++] & 0xff); + C2 |= (bytes[index++] & 0xff) << 8; + C2 |= (bytes[index++] & 0xff) << 16; + C2 |= bytes[index++] << 24; + + C3 = (bytes[index++] & 0xff); + C3 |= (bytes[index++] & 0xff) << 8; + C3 |= (bytes[index++] & 0xff) << 16; + C3 |= bytes[index++] << 24; + } + + private void PackBlock( + byte[] bytes, + int off) + { + int index = off; + + bytes[index++] = (byte)C0; + bytes[index++] = (byte)(C0 >> 8); + bytes[index++] = (byte)(C0 >> 16); + bytes[index++] = (byte)(C0 >> 24); + + bytes[index++] = (byte)C1; + bytes[index++] = (byte)(C1 >> 8); + bytes[index++] = (byte)(C1 >> 16); + bytes[index++] = (byte)(C1 >> 24); + + bytes[index++] = (byte)C2; + bytes[index++] = (byte)(C2 >> 8); + bytes[index++] = (byte)(C2 >> 16); + bytes[index++] = (byte)(C2 >> 24); + + bytes[index++] = (byte)C3; + bytes[index++] = (byte)(C3 >> 8); + bytes[index++] = (byte)(C3 >> 16); + bytes[index++] = (byte)(C3 >> 24); + } + + private void EncryptBlock( + int[,] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[0, 0]; + C1 ^= KW[0, 1]; + C2 ^= KW[0, 2]; + C3 ^= KW[0, 3]; + + for (r = 1; r < ROUNDS - 1;) + { + r0 = T0[C0&255] ^ Shift(T0[(C1>>8)&255], 24) ^ Shift(T0[(C2>>16)&255],16) ^ Shift(T0[(C3>>24)&255],8) ^ KW[r,0]; + r1 = T0[C1&255] ^ Shift(T0[(C2>>8)&255], 24) ^ Shift(T0[(C3>>16)&255], 16) ^ Shift(T0[(C0>>24)&255], 8) ^ KW[r,1]; + r2 = T0[C2&255] ^ Shift(T0[(C3>>8)&255], 24) ^ Shift(T0[(C0>>16)&255], 16) ^ Shift(T0[(C1>>24)&255], 8) ^ KW[r,2]; + r3 = T0[C3&255] ^ Shift(T0[(C0>>8)&255], 24) ^ Shift(T0[(C1>>16)&255], 16) ^ Shift(T0[(C2>>24)&255], 8) ^ KW[r++,3]; + C0 = T0[r0&255] ^ Shift(T0[(r1>>8)&255], 24) ^ Shift(T0[(r2>>16)&255], 16) ^ Shift(T0[(r3>>24)&255], 8) ^ KW[r,0]; + C1 = T0[r1&255] ^ Shift(T0[(r2>>8)&255], 24) ^ Shift(T0[(r3>>16)&255], 16) ^ Shift(T0[(r0>>24)&255], 8) ^ KW[r,1]; + C2 = T0[r2&255] ^ Shift(T0[(r3>>8)&255], 24) ^ Shift(T0[(r0>>16)&255], 16) ^ Shift(T0[(r1>>24)&255], 8) ^ KW[r,2]; + C3 = T0[r3&255] ^ Shift(T0[(r0>>8)&255], 24) ^ Shift(T0[(r1>>16)&255], 16) ^ Shift(T0[(r2>>24)&255], 8) ^ KW[r++,3]; + } + + r0 = T0[C0&255] ^ Shift(T0[(C1>>8)&255], 24) ^ Shift(T0[(C2>>16)&255], 16) ^ Shift(T0[(C3>>24)&255], 8) ^ KW[r,0]; + r1 = T0[C1&255] ^ Shift(T0[(C2>>8)&255], 24) ^ Shift(T0[(C3>>16)&255], 16) ^ Shift(T0[(C0>>24)&255], 8) ^ KW[r,1]; + r2 = T0[C2&255] ^ Shift(T0[(C3>>8)&255], 24) ^ Shift(T0[(C0>>16)&255], 16) ^ Shift(T0[(C1>>24)&255], 8) ^ KW[r,2]; + r3 = T0[C3&255] ^ Shift(T0[(C0>>8)&255], 24) ^ Shift(T0[(C1>>16)&255], 16) ^ Shift(T0[(C2>>24)&255], 8) ^ KW[r++,3]; + + // the final round's table is a simple function of S so we don't use a whole other four tables for it + + C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0]; + C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1]; + C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2]; + C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3]; + } + + private void DecryptBlock( + int[,] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[ROUNDS,0]; + C1 ^= KW[ROUNDS,1]; + C2 ^= KW[ROUNDS,2]; + C3 ^= KW[ROUNDS,3]; + + for (r = ROUNDS-1; r>1;) + { + r0 = Tinv0[C0&255] ^ Shift(Tinv0[(C3>>8)&255], 24) ^ Shift(Tinv0[(C2>>16)&255], 16) ^ Shift(Tinv0[(C1>>24)&255], 8) ^ KW[r,0]; + r1 = Tinv0[C1&255] ^ Shift(Tinv0[(C0>>8)&255], 24) ^ Shift(Tinv0[(C3>>16)&255], 16) ^ Shift(Tinv0[(C2>>24)&255], 8) ^ KW[r,1]; + r2 = Tinv0[C2&255] ^ Shift(Tinv0[(C1>>8)&255], 24) ^ Shift(Tinv0[(C0>>16)&255], 16) ^ Shift(Tinv0[(C3>>24)&255], 8) ^ KW[r,2]; + r3 = Tinv0[C3&255] ^ Shift(Tinv0[(C2>>8)&255], 24) ^ Shift(Tinv0[(C1>>16)&255], 16) ^ Shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--,3]; + C0 = Tinv0[r0&255] ^ Shift(Tinv0[(r3>>8)&255], 24) ^ Shift(Tinv0[(r2>>16)&255], 16) ^ Shift(Tinv0[(r1>>24)&255], 8) ^ KW[r,0]; + C1 = Tinv0[r1&255] ^ Shift(Tinv0[(r0>>8)&255], 24) ^ Shift(Tinv0[(r3>>16)&255], 16) ^ Shift(Tinv0[(r2>>24)&255], 8) ^ KW[r,1]; + C2 = Tinv0[r2&255] ^ Shift(Tinv0[(r1>>8)&255], 24) ^ Shift(Tinv0[(r0>>16)&255], 16) ^ Shift(Tinv0[(r3>>24)&255], 8) ^ KW[r,2]; + C3 = Tinv0[r3&255] ^ Shift(Tinv0[(r2>>8)&255], 24) ^ Shift(Tinv0[(r1>>16)&255], 16) ^ Shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--,3]; + } + + r0 = Tinv0[C0&255] ^ Shift(Tinv0[(C3>>8)&255], 24) ^ Shift(Tinv0[(C2>>16)&255], 16) ^ Shift(Tinv0[(C1>>24)&255], 8) ^ KW[r,0]; + r1 = Tinv0[C1&255] ^ Shift(Tinv0[(C0>>8)&255], 24) ^ Shift(Tinv0[(C3>>16)&255], 16) ^ Shift(Tinv0[(C2>>24)&255], 8) ^ KW[r,1]; + r2 = Tinv0[C2&255] ^ Shift(Tinv0[(C1>>8)&255], 24) ^ Shift(Tinv0[(C0>>16)&255], 16) ^ Shift(Tinv0[(C3>>24)&255], 8) ^ KW[r,2]; + r3 = Tinv0[C3&255] ^ Shift(Tinv0[(C2>>8)&255], 24) ^ Shift(Tinv0[(C1>>16)&255], 16) ^ Shift(Tinv0[(C0>>24)&255], 8) ^ KW[r,3]; + + // the final round's table is a simple function of Si so we don't use a whole other four tables for it + + C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0]; + C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1]; + C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2]; + C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3]; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/AesFastEngine.cs b/iTechSharp/srcbc/crypto/engines/AesFastEngine.cs new file mode 100644 index 0000000..624f4d1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/AesFastEngine.cs @@ -0,0 +1,865 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * an implementation of the AES (Rijndael)), from FIPS-197. + *

      + * For further details see: http://csrc.nist.gov/encryption/aes/. + * + * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + * + * There are three levels of tradeoff of speed vs memory + * Because java has no preprocessor), they are written as three separate classes from which to choose + * + * The fastest uses 8Kbytes of static tables to precompute round calculations), 4 256 word tables for encryption + * and 4 for decryption. + * + * The middle performance version uses only one 256 word table for each), for a total of 2Kbytes), + * adding 12 rotate operations per round to compute the values contained in the other tables from + * the contents of the first + * + * The slowest version uses no static tables at all and computes the values in each round + *

      + *

      + * This file contains the fast version with 8Kbytes of static tables for round precomputation + *

      + */ + public class AesFastEngine + : IBlockCipher + { + // The S box + private static readonly byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, + (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, + (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, + (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, + (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, + (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, + (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, + (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, + (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, + (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, + (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, + (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, + (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, + (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, + (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, + (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, + (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + // The inverse S-box + private static readonly byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, + (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, + (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, + (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, + (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, + (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, + (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, + (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, + (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, + (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, + (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, + (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, + (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, + (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, + (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, + (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, + (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static readonly int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + // precomputation tables of calculations for rounds + private static readonly int[] T0 = + { + unchecked((int) 0xa56363c6), unchecked((int) 0x847c7cf8), unchecked((int) 0x997777ee), unchecked((int) 0x8d7b7bf6), unchecked((int) 0x0df2f2ff), + unchecked((int) 0xbd6b6bd6), unchecked((int) 0xb16f6fde), unchecked((int) 0x54c5c591), unchecked((int) 0x50303060), unchecked((int) 0x03010102), + unchecked((int) 0xa96767ce), unchecked((int) 0x7d2b2b56), unchecked((int) 0x19fefee7), unchecked((int) 0x62d7d7b5), unchecked((int) 0xe6abab4d), + unchecked((int) 0x9a7676ec), unchecked((int) 0x45caca8f), unchecked((int) 0x9d82821f), unchecked((int) 0x40c9c989), unchecked((int) 0x877d7dfa), + unchecked((int) 0x15fafaef), unchecked((int) 0xeb5959b2), unchecked((int) 0xc947478e), unchecked((int) 0x0bf0f0fb), unchecked((int) 0xecadad41), + unchecked((int) 0x67d4d4b3), unchecked((int) 0xfda2a25f), unchecked((int) 0xeaafaf45), unchecked((int) 0xbf9c9c23), unchecked((int) 0xf7a4a453), + unchecked((int) 0x967272e4), unchecked((int) 0x5bc0c09b), unchecked((int) 0xc2b7b775), unchecked((int) 0x1cfdfde1), unchecked((int) 0xae93933d), + unchecked((int) 0x6a26264c), unchecked((int) 0x5a36366c), unchecked((int) 0x413f3f7e), unchecked((int) 0x02f7f7f5), unchecked((int) 0x4fcccc83), + unchecked((int) 0x5c343468), unchecked((int) 0xf4a5a551), unchecked((int) 0x34e5e5d1), unchecked((int) 0x08f1f1f9), unchecked((int) 0x937171e2), + unchecked((int) 0x73d8d8ab), unchecked((int) 0x53313162), unchecked((int) 0x3f15152a), unchecked((int) 0x0c040408), unchecked((int) 0x52c7c795), + unchecked((int) 0x65232346), unchecked((int) 0x5ec3c39d), unchecked((int) 0x28181830), unchecked((int) 0xa1969637), unchecked((int) 0x0f05050a), + unchecked((int) 0xb59a9a2f), unchecked((int) 0x0907070e), unchecked((int) 0x36121224), unchecked((int) 0x9b80801b), unchecked((int) 0x3de2e2df), + unchecked((int) 0x26ebebcd), unchecked((int) 0x6927274e), unchecked((int) 0xcdb2b27f), unchecked((int) 0x9f7575ea), unchecked((int) 0x1b090912), + unchecked((int) 0x9e83831d), unchecked((int) 0x742c2c58), unchecked((int) 0x2e1a1a34), unchecked((int) 0x2d1b1b36), unchecked((int) 0xb26e6edc), + unchecked((int) 0xee5a5ab4), unchecked((int) 0xfba0a05b), unchecked((int) 0xf65252a4), unchecked((int) 0x4d3b3b76), unchecked((int) 0x61d6d6b7), + unchecked((int) 0xceb3b37d), unchecked((int) 0x7b292952), unchecked((int) 0x3ee3e3dd), unchecked((int) 0x712f2f5e), unchecked((int) 0x97848413), + unchecked((int) 0xf55353a6), unchecked((int) 0x68d1d1b9), unchecked((int) 0x00000000), unchecked((int) 0x2cededc1), unchecked((int) 0x60202040), + unchecked((int) 0x1ffcfce3), unchecked((int) 0xc8b1b179), unchecked((int) 0xed5b5bb6), unchecked((int) 0xbe6a6ad4), unchecked((int) 0x46cbcb8d), + unchecked((int) 0xd9bebe67), unchecked((int) 0x4b393972), unchecked((int) 0xde4a4a94), unchecked((int) 0xd44c4c98), unchecked((int) 0xe85858b0), + unchecked((int) 0x4acfcf85), unchecked((int) 0x6bd0d0bb), unchecked((int) 0x2aefefc5), unchecked((int) 0xe5aaaa4f), unchecked((int) 0x16fbfbed), + unchecked((int) 0xc5434386), unchecked((int) 0xd74d4d9a), unchecked((int) 0x55333366), unchecked((int) 0x94858511), unchecked((int) 0xcf45458a), + unchecked((int) 0x10f9f9e9), unchecked((int) 0x06020204), unchecked((int) 0x817f7ffe), unchecked((int) 0xf05050a0), unchecked((int) 0x443c3c78), + unchecked((int) 0xba9f9f25), unchecked((int) 0xe3a8a84b), unchecked((int) 0xf35151a2), unchecked((int) 0xfea3a35d), unchecked((int) 0xc0404080), + unchecked((int) 0x8a8f8f05), unchecked((int) 0xad92923f), unchecked((int) 0xbc9d9d21), unchecked((int) 0x48383870), unchecked((int) 0x04f5f5f1), + unchecked((int) 0xdfbcbc63), unchecked((int) 0xc1b6b677), unchecked((int) 0x75dadaaf), unchecked((int) 0x63212142), unchecked((int) 0x30101020), + unchecked((int) 0x1affffe5), unchecked((int) 0x0ef3f3fd), unchecked((int) 0x6dd2d2bf), unchecked((int) 0x4ccdcd81), unchecked((int) 0x140c0c18), + unchecked((int) 0x35131326), unchecked((int) 0x2fececc3), unchecked((int) 0xe15f5fbe), unchecked((int) 0xa2979735), unchecked((int) 0xcc444488), + unchecked((int) 0x3917172e), unchecked((int) 0x57c4c493), unchecked((int) 0xf2a7a755), unchecked((int) 0x827e7efc), unchecked((int) 0x473d3d7a), + unchecked((int) 0xac6464c8), unchecked((int) 0xe75d5dba), unchecked((int) 0x2b191932), unchecked((int) 0x957373e6), unchecked((int) 0xa06060c0), + unchecked((int) 0x98818119), unchecked((int) 0xd14f4f9e), unchecked((int) 0x7fdcdca3), unchecked((int) 0x66222244), unchecked((int) 0x7e2a2a54), + unchecked((int) 0xab90903b), unchecked((int) 0x8388880b), unchecked((int) 0xca46468c), unchecked((int) 0x29eeeec7), unchecked((int) 0xd3b8b86b), + unchecked((int) 0x3c141428), unchecked((int) 0x79dedea7), unchecked((int) 0xe25e5ebc), unchecked((int) 0x1d0b0b16), unchecked((int) 0x76dbdbad), + unchecked((int) 0x3be0e0db), unchecked((int) 0x56323264), unchecked((int) 0x4e3a3a74), unchecked((int) 0x1e0a0a14), unchecked((int) 0xdb494992), + unchecked((int) 0x0a06060c), unchecked((int) 0x6c242448), unchecked((int) 0xe45c5cb8), unchecked((int) 0x5dc2c29f), unchecked((int) 0x6ed3d3bd), + unchecked((int) 0xefacac43), unchecked((int) 0xa66262c4), unchecked((int) 0xa8919139), unchecked((int) 0xa4959531), unchecked((int) 0x37e4e4d3), + unchecked((int) 0x8b7979f2), unchecked((int) 0x32e7e7d5), unchecked((int) 0x43c8c88b), unchecked((int) 0x5937376e), unchecked((int) 0xb76d6dda), + unchecked((int) 0x8c8d8d01), unchecked((int) 0x64d5d5b1), unchecked((int) 0xd24e4e9c), unchecked((int) 0xe0a9a949), unchecked((int) 0xb46c6cd8), + unchecked((int) 0xfa5656ac), unchecked((int) 0x07f4f4f3), unchecked((int) 0x25eaeacf), unchecked((int) 0xaf6565ca), unchecked((int) 0x8e7a7af4), + unchecked((int) 0xe9aeae47), unchecked((int) 0x18080810), unchecked((int) 0xd5baba6f), unchecked((int) 0x887878f0), unchecked((int) 0x6f25254a), + unchecked((int) 0x722e2e5c), unchecked((int) 0x241c1c38), unchecked((int) 0xf1a6a657), unchecked((int) 0xc7b4b473), unchecked((int) 0x51c6c697), + unchecked((int) 0x23e8e8cb), unchecked((int) 0x7cdddda1), unchecked((int) 0x9c7474e8), unchecked((int) 0x211f1f3e), unchecked((int) 0xdd4b4b96), + unchecked((int) 0xdcbdbd61), unchecked((int) 0x868b8b0d), unchecked((int) 0x858a8a0f), unchecked((int) 0x907070e0), unchecked((int) 0x423e3e7c), + unchecked((int) 0xc4b5b571), unchecked((int) 0xaa6666cc), unchecked((int) 0xd8484890), unchecked((int) 0x05030306), unchecked((int) 0x01f6f6f7), + unchecked((int) 0x120e0e1c), unchecked((int) 0xa36161c2), unchecked((int) 0x5f35356a), unchecked((int) 0xf95757ae), unchecked((int) 0xd0b9b969), + unchecked((int) 0x91868617), unchecked((int) 0x58c1c199), unchecked((int) 0x271d1d3a), unchecked((int) 0xb99e9e27), unchecked((int) 0x38e1e1d9), + unchecked((int) 0x13f8f8eb), unchecked((int) 0xb398982b), unchecked((int) 0x33111122), unchecked((int) 0xbb6969d2), unchecked((int) 0x70d9d9a9), + unchecked((int) 0x898e8e07), unchecked((int) 0xa7949433), unchecked((int) 0xb69b9b2d), unchecked((int) 0x221e1e3c), unchecked((int) 0x92878715), + unchecked((int) 0x20e9e9c9), unchecked((int) 0x49cece87), unchecked((int) 0xff5555aa), unchecked((int) 0x78282850), unchecked((int) 0x7adfdfa5), + unchecked((int) 0x8f8c8c03), unchecked((int) 0xf8a1a159), unchecked((int) 0x80898909), unchecked((int) 0x170d0d1a), unchecked((int) 0xdabfbf65), + unchecked((int) 0x31e6e6d7), unchecked((int) 0xc6424284), unchecked((int) 0xb86868d0), unchecked((int) 0xc3414182), unchecked((int) 0xb0999929), + unchecked((int) 0x772d2d5a), unchecked((int) 0x110f0f1e), unchecked((int) 0xcbb0b07b), unchecked((int) 0xfc5454a8), unchecked((int) 0xd6bbbb6d), + unchecked((int) 0x3a16162c)}; + + private static readonly int[] T1 = + { + unchecked((int) 0x6363c6a5), unchecked((int) 0x7c7cf884), unchecked((int) 0x7777ee99), unchecked((int) 0x7b7bf68d), unchecked((int) 0xf2f2ff0d), + unchecked((int) 0x6b6bd6bd), unchecked((int) 0x6f6fdeb1), unchecked((int) 0xc5c59154), unchecked((int) 0x30306050), unchecked((int) 0x01010203), + unchecked((int) 0x6767cea9), unchecked((int) 0x2b2b567d), unchecked((int) 0xfefee719), unchecked((int) 0xd7d7b562), unchecked((int) 0xabab4de6), + unchecked((int) 0x7676ec9a), unchecked((int) 0xcaca8f45), unchecked((int) 0x82821f9d), unchecked((int) 0xc9c98940), unchecked((int) 0x7d7dfa87), + unchecked((int) 0xfafaef15), unchecked((int) 0x5959b2eb), unchecked((int) 0x47478ec9), unchecked((int) 0xf0f0fb0b), unchecked((int) 0xadad41ec), + unchecked((int) 0xd4d4b367), unchecked((int) 0xa2a25ffd), unchecked((int) 0xafaf45ea), unchecked((int) 0x9c9c23bf), unchecked((int) 0xa4a453f7), + unchecked((int) 0x7272e496), unchecked((int) 0xc0c09b5b), unchecked((int) 0xb7b775c2), unchecked((int) 0xfdfde11c), unchecked((int) 0x93933dae), + unchecked((int) 0x26264c6a), unchecked((int) 0x36366c5a), unchecked((int) 0x3f3f7e41), unchecked((int) 0xf7f7f502), unchecked((int) 0xcccc834f), + unchecked((int) 0x3434685c), unchecked((int) 0xa5a551f4), unchecked((int) 0xe5e5d134), unchecked((int) 0xf1f1f908), unchecked((int) 0x7171e293), + unchecked((int) 0xd8d8ab73), unchecked((int) 0x31316253), unchecked((int) 0x15152a3f), unchecked((int) 0x0404080c), unchecked((int) 0xc7c79552), + unchecked((int) 0x23234665), unchecked((int) 0xc3c39d5e), unchecked((int) 0x18183028), unchecked((int) 0x969637a1), unchecked((int) 0x05050a0f), + unchecked((int) 0x9a9a2fb5), unchecked((int) 0x07070e09), unchecked((int) 0x12122436), unchecked((int) 0x80801b9b), unchecked((int) 0xe2e2df3d), + unchecked((int) 0xebebcd26), unchecked((int) 0x27274e69), unchecked((int) 0xb2b27fcd), unchecked((int) 0x7575ea9f), unchecked((int) 0x0909121b), + unchecked((int) 0x83831d9e), unchecked((int) 0x2c2c5874), unchecked((int) 0x1a1a342e), unchecked((int) 0x1b1b362d), unchecked((int) 0x6e6edcb2), + unchecked((int) 0x5a5ab4ee), unchecked((int) 0xa0a05bfb), unchecked((int) 0x5252a4f6), unchecked((int) 0x3b3b764d), unchecked((int) 0xd6d6b761), + unchecked((int) 0xb3b37dce), unchecked((int) 0x2929527b), unchecked((int) 0xe3e3dd3e), unchecked((int) 0x2f2f5e71), unchecked((int) 0x84841397), + unchecked((int) 0x5353a6f5), unchecked((int) 0xd1d1b968), unchecked((int) 0x00000000), unchecked((int) 0xededc12c), unchecked((int) 0x20204060), + unchecked((int) 0xfcfce31f), unchecked((int) 0xb1b179c8), unchecked((int) 0x5b5bb6ed), unchecked((int) 0x6a6ad4be), unchecked((int) 0xcbcb8d46), + unchecked((int) 0xbebe67d9), unchecked((int) 0x3939724b), unchecked((int) 0x4a4a94de), unchecked((int) 0x4c4c98d4), unchecked((int) 0x5858b0e8), + unchecked((int) 0xcfcf854a), unchecked((int) 0xd0d0bb6b), unchecked((int) 0xefefc52a), unchecked((int) 0xaaaa4fe5), unchecked((int) 0xfbfbed16), + unchecked((int) 0x434386c5), unchecked((int) 0x4d4d9ad7), unchecked((int) 0x33336655), unchecked((int) 0x85851194), unchecked((int) 0x45458acf), + unchecked((int) 0xf9f9e910), unchecked((int) 0x02020406), unchecked((int) 0x7f7ffe81), unchecked((int) 0x5050a0f0), unchecked((int) 0x3c3c7844), + unchecked((int) 0x9f9f25ba), unchecked((int) 0xa8a84be3), unchecked((int) 0x5151a2f3), unchecked((int) 0xa3a35dfe), unchecked((int) 0x404080c0), + unchecked((int) 0x8f8f058a), unchecked((int) 0x92923fad), unchecked((int) 0x9d9d21bc), unchecked((int) 0x38387048), unchecked((int) 0xf5f5f104), + unchecked((int) 0xbcbc63df), unchecked((int) 0xb6b677c1), unchecked((int) 0xdadaaf75), unchecked((int) 0x21214263), unchecked((int) 0x10102030), + unchecked((int) 0xffffe51a), unchecked((int) 0xf3f3fd0e), unchecked((int) 0xd2d2bf6d), unchecked((int) 0xcdcd814c), unchecked((int) 0x0c0c1814), + unchecked((int) 0x13132635), unchecked((int) 0xececc32f), unchecked((int) 0x5f5fbee1), unchecked((int) 0x979735a2), unchecked((int) 0x444488cc), + unchecked((int) 0x17172e39), unchecked((int) 0xc4c49357), unchecked((int) 0xa7a755f2), unchecked((int) 0x7e7efc82), unchecked((int) 0x3d3d7a47), + unchecked((int) 0x6464c8ac), unchecked((int) 0x5d5dbae7), unchecked((int) 0x1919322b), unchecked((int) 0x7373e695), unchecked((int) 0x6060c0a0), + unchecked((int) 0x81811998), unchecked((int) 0x4f4f9ed1), unchecked((int) 0xdcdca37f), unchecked((int) 0x22224466), unchecked((int) 0x2a2a547e), + unchecked((int) 0x90903bab), unchecked((int) 0x88880b83), unchecked((int) 0x46468cca), unchecked((int) 0xeeeec729), unchecked((int) 0xb8b86bd3), + unchecked((int) 0x1414283c), unchecked((int) 0xdedea779), unchecked((int) 0x5e5ebce2), unchecked((int) 0x0b0b161d), unchecked((int) 0xdbdbad76), + unchecked((int) 0xe0e0db3b), unchecked((int) 0x32326456), unchecked((int) 0x3a3a744e), unchecked((int) 0x0a0a141e), unchecked((int) 0x494992db), + unchecked((int) 0x06060c0a), unchecked((int) 0x2424486c), unchecked((int) 0x5c5cb8e4), unchecked((int) 0xc2c29f5d), unchecked((int) 0xd3d3bd6e), + unchecked((int) 0xacac43ef), unchecked((int) 0x6262c4a6), unchecked((int) 0x919139a8), unchecked((int) 0x959531a4), unchecked((int) 0xe4e4d337), + unchecked((int) 0x7979f28b), unchecked((int) 0xe7e7d532), unchecked((int) 0xc8c88b43), unchecked((int) 0x37376e59), unchecked((int) 0x6d6ddab7), + unchecked((int) 0x8d8d018c), unchecked((int) 0xd5d5b164), unchecked((int) 0x4e4e9cd2), unchecked((int) 0xa9a949e0), unchecked((int) 0x6c6cd8b4), + unchecked((int) 0x5656acfa), unchecked((int) 0xf4f4f307), unchecked((int) 0xeaeacf25), unchecked((int) 0x6565caaf), unchecked((int) 0x7a7af48e), + unchecked((int) 0xaeae47e9), unchecked((int) 0x08081018), unchecked((int) 0xbaba6fd5), unchecked((int) 0x7878f088), unchecked((int) 0x25254a6f), + unchecked((int) 0x2e2e5c72), unchecked((int) 0x1c1c3824), unchecked((int) 0xa6a657f1), unchecked((int) 0xb4b473c7), unchecked((int) 0xc6c69751), + unchecked((int) 0xe8e8cb23), unchecked((int) 0xdddda17c), unchecked((int) 0x7474e89c), unchecked((int) 0x1f1f3e21), unchecked((int) 0x4b4b96dd), + unchecked((int) 0xbdbd61dc), unchecked((int) 0x8b8b0d86), unchecked((int) 0x8a8a0f85), unchecked((int) 0x7070e090), unchecked((int) 0x3e3e7c42), + unchecked((int) 0xb5b571c4), unchecked((int) 0x6666ccaa), unchecked((int) 0x484890d8), unchecked((int) 0x03030605), unchecked((int) 0xf6f6f701), + unchecked((int) 0x0e0e1c12), unchecked((int) 0x6161c2a3), unchecked((int) 0x35356a5f), unchecked((int) 0x5757aef9), unchecked((int) 0xb9b969d0), + unchecked((int) 0x86861791), unchecked((int) 0xc1c19958), unchecked((int) 0x1d1d3a27), unchecked((int) 0x9e9e27b9), unchecked((int) 0xe1e1d938), + unchecked((int) 0xf8f8eb13), unchecked((int) 0x98982bb3), unchecked((int) 0x11112233), unchecked((int) 0x6969d2bb), unchecked((int) 0xd9d9a970), + unchecked((int) 0x8e8e0789), unchecked((int) 0x949433a7), unchecked((int) 0x9b9b2db6), unchecked((int) 0x1e1e3c22), unchecked((int) 0x87871592), + unchecked((int) 0xe9e9c920), unchecked((int) 0xcece8749), unchecked((int) 0x5555aaff), unchecked((int) 0x28285078), unchecked((int) 0xdfdfa57a), + unchecked((int) 0x8c8c038f), unchecked((int) 0xa1a159f8), unchecked((int) 0x89890980), unchecked((int) 0x0d0d1a17), unchecked((int) 0xbfbf65da), + unchecked((int) 0xe6e6d731), unchecked((int) 0x424284c6), unchecked((int) 0x6868d0b8), unchecked((int) 0x414182c3), unchecked((int) 0x999929b0), + unchecked((int) 0x2d2d5a77), unchecked((int) 0x0f0f1e11), unchecked((int) 0xb0b07bcb), unchecked((int) 0x5454a8fc), unchecked((int) 0xbbbb6dd6), + unchecked((int) 0x16162c3a)}; + + private static readonly int[] T2 = + { + unchecked((int) 0x63c6a563), unchecked((int) 0x7cf8847c), unchecked((int) 0x77ee9977), unchecked((int) 0x7bf68d7b), unchecked((int) 0xf2ff0df2), + unchecked((int) 0x6bd6bd6b), unchecked((int) 0x6fdeb16f), unchecked((int) 0xc59154c5), unchecked((int) 0x30605030), unchecked((int) 0x01020301), + unchecked((int) 0x67cea967), unchecked((int) 0x2b567d2b), unchecked((int) 0xfee719fe), unchecked((int) 0xd7b562d7), unchecked((int) 0xab4de6ab), + unchecked((int) 0x76ec9a76), unchecked((int) 0xca8f45ca), unchecked((int) 0x821f9d82), unchecked((int) 0xc98940c9), unchecked((int) 0x7dfa877d), + unchecked((int) 0xfaef15fa), unchecked((int) 0x59b2eb59), unchecked((int) 0x478ec947), unchecked((int) 0xf0fb0bf0), unchecked((int) 0xad41ecad), + unchecked((int) 0xd4b367d4), unchecked((int) 0xa25ffda2), unchecked((int) 0xaf45eaaf), unchecked((int) 0x9c23bf9c), unchecked((int) 0xa453f7a4), + unchecked((int) 0x72e49672), unchecked((int) 0xc09b5bc0), unchecked((int) 0xb775c2b7), unchecked((int) 0xfde11cfd), unchecked((int) 0x933dae93), + unchecked((int) 0x264c6a26), unchecked((int) 0x366c5a36), unchecked((int) 0x3f7e413f), unchecked((int) 0xf7f502f7), unchecked((int) 0xcc834fcc), + unchecked((int) 0x34685c34), unchecked((int) 0xa551f4a5), unchecked((int) 0xe5d134e5), unchecked((int) 0xf1f908f1), unchecked((int) 0x71e29371), + unchecked((int) 0xd8ab73d8), unchecked((int) 0x31625331), unchecked((int) 0x152a3f15), unchecked((int) 0x04080c04), unchecked((int) 0xc79552c7), + unchecked((int) 0x23466523), unchecked((int) 0xc39d5ec3), unchecked((int) 0x18302818), unchecked((int) 0x9637a196), unchecked((int) 0x050a0f05), + unchecked((int) 0x9a2fb59a), unchecked((int) 0x070e0907), unchecked((int) 0x12243612), unchecked((int) 0x801b9b80), unchecked((int) 0xe2df3de2), + unchecked((int) 0xebcd26eb), unchecked((int) 0x274e6927), unchecked((int) 0xb27fcdb2), unchecked((int) 0x75ea9f75), unchecked((int) 0x09121b09), + unchecked((int) 0x831d9e83), unchecked((int) 0x2c58742c), unchecked((int) 0x1a342e1a), unchecked((int) 0x1b362d1b), unchecked((int) 0x6edcb26e), + unchecked((int) 0x5ab4ee5a), unchecked((int) 0xa05bfba0), unchecked((int) 0x52a4f652), unchecked((int) 0x3b764d3b), unchecked((int) 0xd6b761d6), + unchecked((int) 0xb37dceb3), unchecked((int) 0x29527b29), unchecked((int) 0xe3dd3ee3), unchecked((int) 0x2f5e712f), unchecked((int) 0x84139784), + unchecked((int) 0x53a6f553), unchecked((int) 0xd1b968d1), unchecked((int) 0x00000000), unchecked((int) 0xedc12ced), unchecked((int) 0x20406020), + unchecked((int) 0xfce31ffc), unchecked((int) 0xb179c8b1), unchecked((int) 0x5bb6ed5b), unchecked((int) 0x6ad4be6a), unchecked((int) 0xcb8d46cb), + unchecked((int) 0xbe67d9be), unchecked((int) 0x39724b39), unchecked((int) 0x4a94de4a), unchecked((int) 0x4c98d44c), unchecked((int) 0x58b0e858), + unchecked((int) 0xcf854acf), unchecked((int) 0xd0bb6bd0), unchecked((int) 0xefc52aef), unchecked((int) 0xaa4fe5aa), unchecked((int) 0xfbed16fb), + unchecked((int) 0x4386c543), unchecked((int) 0x4d9ad74d), unchecked((int) 0x33665533), unchecked((int) 0x85119485), unchecked((int) 0x458acf45), + unchecked((int) 0xf9e910f9), unchecked((int) 0x02040602), unchecked((int) 0x7ffe817f), unchecked((int) 0x50a0f050), unchecked((int) 0x3c78443c), + unchecked((int) 0x9f25ba9f), unchecked((int) 0xa84be3a8), unchecked((int) 0x51a2f351), unchecked((int) 0xa35dfea3), unchecked((int) 0x4080c040), + unchecked((int) 0x8f058a8f), unchecked((int) 0x923fad92), unchecked((int) 0x9d21bc9d), unchecked((int) 0x38704838), unchecked((int) 0xf5f104f5), + unchecked((int) 0xbc63dfbc), unchecked((int) 0xb677c1b6), unchecked((int) 0xdaaf75da), unchecked((int) 0x21426321), unchecked((int) 0x10203010), + unchecked((int) 0xffe51aff), unchecked((int) 0xf3fd0ef3), unchecked((int) 0xd2bf6dd2), unchecked((int) 0xcd814ccd), unchecked((int) 0x0c18140c), + unchecked((int) 0x13263513), unchecked((int) 0xecc32fec), unchecked((int) 0x5fbee15f), unchecked((int) 0x9735a297), unchecked((int) 0x4488cc44), + unchecked((int) 0x172e3917), unchecked((int) 0xc49357c4), unchecked((int) 0xa755f2a7), unchecked((int) 0x7efc827e), unchecked((int) 0x3d7a473d), + unchecked((int) 0x64c8ac64), unchecked((int) 0x5dbae75d), unchecked((int) 0x19322b19), unchecked((int) 0x73e69573), unchecked((int) 0x60c0a060), + unchecked((int) 0x81199881), unchecked((int) 0x4f9ed14f), unchecked((int) 0xdca37fdc), unchecked((int) 0x22446622), unchecked((int) 0x2a547e2a), + unchecked((int) 0x903bab90), unchecked((int) 0x880b8388), unchecked((int) 0x468cca46), unchecked((int) 0xeec729ee), unchecked((int) 0xb86bd3b8), + unchecked((int) 0x14283c14), unchecked((int) 0xdea779de), unchecked((int) 0x5ebce25e), unchecked((int) 0x0b161d0b), unchecked((int) 0xdbad76db), + unchecked((int) 0xe0db3be0), unchecked((int) 0x32645632), unchecked((int) 0x3a744e3a), unchecked((int) 0x0a141e0a), unchecked((int) 0x4992db49), + unchecked((int) 0x060c0a06), unchecked((int) 0x24486c24), unchecked((int) 0x5cb8e45c), unchecked((int) 0xc29f5dc2), unchecked((int) 0xd3bd6ed3), + unchecked((int) 0xac43efac), unchecked((int) 0x62c4a662), unchecked((int) 0x9139a891), unchecked((int) 0x9531a495), unchecked((int) 0xe4d337e4), + unchecked((int) 0x79f28b79), unchecked((int) 0xe7d532e7), unchecked((int) 0xc88b43c8), unchecked((int) 0x376e5937), unchecked((int) 0x6ddab76d), + unchecked((int) 0x8d018c8d), unchecked((int) 0xd5b164d5), unchecked((int) 0x4e9cd24e), unchecked((int) 0xa949e0a9), unchecked((int) 0x6cd8b46c), + unchecked((int) 0x56acfa56), unchecked((int) 0xf4f307f4), unchecked((int) 0xeacf25ea), unchecked((int) 0x65caaf65), unchecked((int) 0x7af48e7a), + unchecked((int) 0xae47e9ae), unchecked((int) 0x08101808), unchecked((int) 0xba6fd5ba), unchecked((int) 0x78f08878), unchecked((int) 0x254a6f25), + unchecked((int) 0x2e5c722e), unchecked((int) 0x1c38241c), unchecked((int) 0xa657f1a6), unchecked((int) 0xb473c7b4), unchecked((int) 0xc69751c6), + unchecked((int) 0xe8cb23e8), unchecked((int) 0xdda17cdd), unchecked((int) 0x74e89c74), unchecked((int) 0x1f3e211f), unchecked((int) 0x4b96dd4b), + unchecked((int) 0xbd61dcbd), unchecked((int) 0x8b0d868b), unchecked((int) 0x8a0f858a), unchecked((int) 0x70e09070), unchecked((int) 0x3e7c423e), + unchecked((int) 0xb571c4b5), unchecked((int) 0x66ccaa66), unchecked((int) 0x4890d848), unchecked((int) 0x03060503), unchecked((int) 0xf6f701f6), + unchecked((int) 0x0e1c120e), unchecked((int) 0x61c2a361), unchecked((int) 0x356a5f35), unchecked((int) 0x57aef957), unchecked((int) 0xb969d0b9), + unchecked((int) 0x86179186), unchecked((int) 0xc19958c1), unchecked((int) 0x1d3a271d), unchecked((int) 0x9e27b99e), unchecked((int) 0xe1d938e1), + unchecked((int) 0xf8eb13f8), unchecked((int) 0x982bb398), unchecked((int) 0x11223311), unchecked((int) 0x69d2bb69), unchecked((int) 0xd9a970d9), + unchecked((int) 0x8e07898e), unchecked((int) 0x9433a794), unchecked((int) 0x9b2db69b), unchecked((int) 0x1e3c221e), unchecked((int) 0x87159287), + unchecked((int) 0xe9c920e9), unchecked((int) 0xce8749ce), unchecked((int) 0x55aaff55), unchecked((int) 0x28507828), unchecked((int) 0xdfa57adf), + unchecked((int) 0x8c038f8c), unchecked((int) 0xa159f8a1), unchecked((int) 0x89098089), unchecked((int) 0x0d1a170d), unchecked((int) 0xbf65dabf), + unchecked((int) 0xe6d731e6), unchecked((int) 0x4284c642), unchecked((int) 0x68d0b868), unchecked((int) 0x4182c341), unchecked((int) 0x9929b099), + unchecked((int) 0x2d5a772d), unchecked((int) 0x0f1e110f), unchecked((int) 0xb07bcbb0), unchecked((int) 0x54a8fc54), unchecked((int) 0xbb6dd6bb), + unchecked((int) 0x162c3a16)}; + + private static readonly int[] T3 = + { + unchecked((int) 0xc6a56363), unchecked((int) 0xf8847c7c), unchecked((int) 0xee997777), unchecked((int) 0xf68d7b7b), unchecked((int) 0xff0df2f2), + unchecked((int) 0xd6bd6b6b), unchecked((int) 0xdeb16f6f), unchecked((int) 0x9154c5c5), unchecked((int) 0x60503030), unchecked((int) 0x02030101), + unchecked((int) 0xcea96767), unchecked((int) 0x567d2b2b), unchecked((int) 0xe719fefe), unchecked((int) 0xb562d7d7), unchecked((int) 0x4de6abab), + unchecked((int) 0xec9a7676), unchecked((int) 0x8f45caca), unchecked((int) 0x1f9d8282), unchecked((int) 0x8940c9c9), unchecked((int) 0xfa877d7d), + unchecked((int) 0xef15fafa), unchecked((int) 0xb2eb5959), unchecked((int) 0x8ec94747), unchecked((int) 0xfb0bf0f0), unchecked((int) 0x41ecadad), + unchecked((int) 0xb367d4d4), unchecked((int) 0x5ffda2a2), unchecked((int) 0x45eaafaf), unchecked((int) 0x23bf9c9c), unchecked((int) 0x53f7a4a4), + unchecked((int) 0xe4967272), unchecked((int) 0x9b5bc0c0), unchecked((int) 0x75c2b7b7), unchecked((int) 0xe11cfdfd), unchecked((int) 0x3dae9393), + unchecked((int) 0x4c6a2626), unchecked((int) 0x6c5a3636), unchecked((int) 0x7e413f3f), unchecked((int) 0xf502f7f7), unchecked((int) 0x834fcccc), + unchecked((int) 0x685c3434), unchecked((int) 0x51f4a5a5), unchecked((int) 0xd134e5e5), unchecked((int) 0xf908f1f1), unchecked((int) 0xe2937171), + unchecked((int) 0xab73d8d8), unchecked((int) 0x62533131), unchecked((int) 0x2a3f1515), unchecked((int) 0x080c0404), unchecked((int) 0x9552c7c7), + unchecked((int) 0x46652323), unchecked((int) 0x9d5ec3c3), unchecked((int) 0x30281818), unchecked((int) 0x37a19696), unchecked((int) 0x0a0f0505), + unchecked((int) 0x2fb59a9a), unchecked((int) 0x0e090707), unchecked((int) 0x24361212), unchecked((int) 0x1b9b8080), unchecked((int) 0xdf3de2e2), + unchecked((int) 0xcd26ebeb), unchecked((int) 0x4e692727), unchecked((int) 0x7fcdb2b2), unchecked((int) 0xea9f7575), unchecked((int) 0x121b0909), + unchecked((int) 0x1d9e8383), unchecked((int) 0x58742c2c), unchecked((int) 0x342e1a1a), unchecked((int) 0x362d1b1b), unchecked((int) 0xdcb26e6e), + unchecked((int) 0xb4ee5a5a), unchecked((int) 0x5bfba0a0), unchecked((int) 0xa4f65252), unchecked((int) 0x764d3b3b), unchecked((int) 0xb761d6d6), + unchecked((int) 0x7dceb3b3), unchecked((int) 0x527b2929), unchecked((int) 0xdd3ee3e3), unchecked((int) 0x5e712f2f), unchecked((int) 0x13978484), + unchecked((int) 0xa6f55353), unchecked((int) 0xb968d1d1), unchecked((int) 0x00000000), unchecked((int) 0xc12ceded), unchecked((int) 0x40602020), + unchecked((int) 0xe31ffcfc), unchecked((int) 0x79c8b1b1), unchecked((int) 0xb6ed5b5b), unchecked((int) 0xd4be6a6a), unchecked((int) 0x8d46cbcb), + unchecked((int) 0x67d9bebe), unchecked((int) 0x724b3939), unchecked((int) 0x94de4a4a), unchecked((int) 0x98d44c4c), unchecked((int) 0xb0e85858), + unchecked((int) 0x854acfcf), unchecked((int) 0xbb6bd0d0), unchecked((int) 0xc52aefef), unchecked((int) 0x4fe5aaaa), unchecked((int) 0xed16fbfb), + unchecked((int) 0x86c54343), unchecked((int) 0x9ad74d4d), unchecked((int) 0x66553333), unchecked((int) 0x11948585), unchecked((int) 0x8acf4545), + unchecked((int) 0xe910f9f9), unchecked((int) 0x04060202), unchecked((int) 0xfe817f7f), unchecked((int) 0xa0f05050), unchecked((int) 0x78443c3c), + unchecked((int) 0x25ba9f9f), unchecked((int) 0x4be3a8a8), unchecked((int) 0xa2f35151), unchecked((int) 0x5dfea3a3), unchecked((int) 0x80c04040), + unchecked((int) 0x058a8f8f), unchecked((int) 0x3fad9292), unchecked((int) 0x21bc9d9d), unchecked((int) 0x70483838), unchecked((int) 0xf104f5f5), + unchecked((int) 0x63dfbcbc), unchecked((int) 0x77c1b6b6), unchecked((int) 0xaf75dada), unchecked((int) 0x42632121), unchecked((int) 0x20301010), + unchecked((int) 0xe51affff), unchecked((int) 0xfd0ef3f3), unchecked((int) 0xbf6dd2d2), unchecked((int) 0x814ccdcd), unchecked((int) 0x18140c0c), + unchecked((int) 0x26351313), unchecked((int) 0xc32fecec), unchecked((int) 0xbee15f5f), unchecked((int) 0x35a29797), unchecked((int) 0x88cc4444), + unchecked((int) 0x2e391717), unchecked((int) 0x9357c4c4), unchecked((int) 0x55f2a7a7), unchecked((int) 0xfc827e7e), unchecked((int) 0x7a473d3d), + unchecked((int) 0xc8ac6464), unchecked((int) 0xbae75d5d), unchecked((int) 0x322b1919), unchecked((int) 0xe6957373), unchecked((int) 0xc0a06060), + unchecked((int) 0x19988181), unchecked((int) 0x9ed14f4f), unchecked((int) 0xa37fdcdc), unchecked((int) 0x44662222), unchecked((int) 0x547e2a2a), + unchecked((int) 0x3bab9090), unchecked((int) 0x0b838888), unchecked((int) 0x8cca4646), unchecked((int) 0xc729eeee), unchecked((int) 0x6bd3b8b8), + unchecked((int) 0x283c1414), unchecked((int) 0xa779dede), unchecked((int) 0xbce25e5e), unchecked((int) 0x161d0b0b), unchecked((int) 0xad76dbdb), + unchecked((int) 0xdb3be0e0), unchecked((int) 0x64563232), unchecked((int) 0x744e3a3a), unchecked((int) 0x141e0a0a), unchecked((int) 0x92db4949), + unchecked((int) 0x0c0a0606), unchecked((int) 0x486c2424), unchecked((int) 0xb8e45c5c), unchecked((int) 0x9f5dc2c2), unchecked((int) 0xbd6ed3d3), + unchecked((int) 0x43efacac), unchecked((int) 0xc4a66262), unchecked((int) 0x39a89191), unchecked((int) 0x31a49595), unchecked((int) 0xd337e4e4), + unchecked((int) 0xf28b7979), unchecked((int) 0xd532e7e7), unchecked((int) 0x8b43c8c8), unchecked((int) 0x6e593737), unchecked((int) 0xdab76d6d), + unchecked((int) 0x018c8d8d), unchecked((int) 0xb164d5d5), unchecked((int) 0x9cd24e4e), unchecked((int) 0x49e0a9a9), unchecked((int) 0xd8b46c6c), + unchecked((int) 0xacfa5656), unchecked((int) 0xf307f4f4), unchecked((int) 0xcf25eaea), unchecked((int) 0xcaaf6565), unchecked((int) 0xf48e7a7a), + unchecked((int) 0x47e9aeae), unchecked((int) 0x10180808), unchecked((int) 0x6fd5baba), unchecked((int) 0xf0887878), unchecked((int) 0x4a6f2525), + unchecked((int) 0x5c722e2e), unchecked((int) 0x38241c1c), unchecked((int) 0x57f1a6a6), unchecked((int) 0x73c7b4b4), unchecked((int) 0x9751c6c6), + unchecked((int) 0xcb23e8e8), unchecked((int) 0xa17cdddd), unchecked((int) 0xe89c7474), unchecked((int) 0x3e211f1f), unchecked((int) 0x96dd4b4b), + unchecked((int) 0x61dcbdbd), unchecked((int) 0x0d868b8b), unchecked((int) 0x0f858a8a), unchecked((int) 0xe0907070), unchecked((int) 0x7c423e3e), + unchecked((int) 0x71c4b5b5), unchecked((int) 0xccaa6666), unchecked((int) 0x90d84848), unchecked((int) 0x06050303), unchecked((int) 0xf701f6f6), + unchecked((int) 0x1c120e0e), unchecked((int) 0xc2a36161), unchecked((int) 0x6a5f3535), unchecked((int) 0xaef95757), unchecked((int) 0x69d0b9b9), + unchecked((int) 0x17918686), unchecked((int) 0x9958c1c1), unchecked((int) 0x3a271d1d), unchecked((int) 0x27b99e9e), unchecked((int) 0xd938e1e1), + unchecked((int) 0xeb13f8f8), unchecked((int) 0x2bb39898), unchecked((int) 0x22331111), unchecked((int) 0xd2bb6969), unchecked((int) 0xa970d9d9), + unchecked((int) 0x07898e8e), unchecked((int) 0x33a79494), unchecked((int) 0x2db69b9b), unchecked((int) 0x3c221e1e), unchecked((int) 0x15928787), + unchecked((int) 0xc920e9e9), unchecked((int) 0x8749cece), unchecked((int) 0xaaff5555), unchecked((int) 0x50782828), unchecked((int) 0xa57adfdf), + unchecked((int) 0x038f8c8c), unchecked((int) 0x59f8a1a1), unchecked((int) 0x09808989), unchecked((int) 0x1a170d0d), unchecked((int) 0x65dabfbf), + unchecked((int) 0xd731e6e6), unchecked((int) 0x84c64242), unchecked((int) 0xd0b86868), unchecked((int) 0x82c34141), unchecked((int) 0x29b09999), + unchecked((int) 0x5a772d2d), unchecked((int) 0x1e110f0f), unchecked((int) 0x7bcbb0b0), unchecked((int) 0xa8fc5454), unchecked((int) 0x6dd6bbbb), + unchecked((int) 0x2c3a1616)}; + + private static readonly int[] Tinv0 = + { + unchecked((int) 0x50a7f451), unchecked((int) 0x5365417e), unchecked((int) 0xc3a4171a), unchecked((int) 0x965e273a), unchecked((int) 0xcb6bab3b), + unchecked((int) 0xf1459d1f), unchecked((int) 0xab58faac), unchecked((int) 0x9303e34b), unchecked((int) 0x55fa3020), unchecked((int) 0xf66d76ad), + unchecked((int) 0x9176cc88), unchecked((int) 0x254c02f5), unchecked((int) 0xfcd7e54f), unchecked((int) 0xd7cb2ac5), unchecked((int) 0x80443526), + unchecked((int) 0x8fa362b5), unchecked((int) 0x495ab1de), unchecked((int) 0x671bba25), unchecked((int) 0x980eea45), unchecked((int) 0xe1c0fe5d), + unchecked((int) 0x02752fc3), unchecked((int) 0x12f04c81), unchecked((int) 0xa397468d), unchecked((int) 0xc6f9d36b), unchecked((int) 0xe75f8f03), + unchecked((int) 0x959c9215), unchecked((int) 0xeb7a6dbf), unchecked((int) 0xda595295), unchecked((int) 0x2d83bed4), unchecked((int) 0xd3217458), + unchecked((int) 0x2969e049), unchecked((int) 0x44c8c98e), unchecked((int) 0x6a89c275), unchecked((int) 0x78798ef4), unchecked((int) 0x6b3e5899), + unchecked((int) 0xdd71b927), unchecked((int) 0xb64fe1be), unchecked((int) 0x17ad88f0), unchecked((int) 0x66ac20c9), unchecked((int) 0xb43ace7d), + unchecked((int) 0x184adf63), unchecked((int) 0x82311ae5), unchecked((int) 0x60335197), unchecked((int) 0x457f5362), unchecked((int) 0xe07764b1), + unchecked((int) 0x84ae6bbb), unchecked((int) 0x1ca081fe), unchecked((int) 0x942b08f9), unchecked((int) 0x58684870), unchecked((int) 0x19fd458f), + unchecked((int) 0x876cde94), unchecked((int) 0xb7f87b52), unchecked((int) 0x23d373ab), unchecked((int) 0xe2024b72), unchecked((int) 0x578f1fe3), + unchecked((int) 0x2aab5566), unchecked((int) 0x0728ebb2), unchecked((int) 0x03c2b52f), unchecked((int) 0x9a7bc586), unchecked((int) 0xa50837d3), + unchecked((int) 0xf2872830), unchecked((int) 0xb2a5bf23), unchecked((int) 0xba6a0302), unchecked((int) 0x5c8216ed), unchecked((int) 0x2b1ccf8a), + unchecked((int) 0x92b479a7), unchecked((int) 0xf0f207f3), unchecked((int) 0xa1e2694e), unchecked((int) 0xcdf4da65), unchecked((int) 0xd5be0506), + unchecked((int) 0x1f6234d1), unchecked((int) 0x8afea6c4), unchecked((int) 0x9d532e34), unchecked((int) 0xa055f3a2), unchecked((int) 0x32e18a05), + unchecked((int) 0x75ebf6a4), unchecked((int) 0x39ec830b), unchecked((int) 0xaaef6040), unchecked((int) 0x069f715e), unchecked((int) 0x51106ebd), + unchecked((int) 0xf98a213e), unchecked((int) 0x3d06dd96), unchecked((int) 0xae053edd), unchecked((int) 0x46bde64d), unchecked((int) 0xb58d5491), + unchecked((int) 0x055dc471), unchecked((int) 0x6fd40604), unchecked((int) 0xff155060), unchecked((int) 0x24fb9819), unchecked((int) 0x97e9bdd6), + unchecked((int) 0xcc434089), unchecked((int) 0x779ed967), unchecked((int) 0xbd42e8b0), unchecked((int) 0x888b8907), unchecked((int) 0x385b19e7), + unchecked((int) 0xdbeec879), unchecked((int) 0x470a7ca1), unchecked((int) 0xe90f427c), unchecked((int) 0xc91e84f8), unchecked((int) 0x00000000), + unchecked((int) 0x83868009), unchecked((int) 0x48ed2b32), unchecked((int) 0xac70111e), unchecked((int) 0x4e725a6c), unchecked((int) 0xfbff0efd), + unchecked((int) 0x5638850f), unchecked((int) 0x1ed5ae3d), unchecked((int) 0x27392d36), unchecked((int) 0x64d90f0a), unchecked((int) 0x21a65c68), + unchecked((int) 0xd1545b9b), unchecked((int) 0x3a2e3624), unchecked((int) 0xb1670a0c), unchecked((int) 0x0fe75793), unchecked((int) 0xd296eeb4), + unchecked((int) 0x9e919b1b), unchecked((int) 0x4fc5c080), unchecked((int) 0xa220dc61), unchecked((int) 0x694b775a), unchecked((int) 0x161a121c), + unchecked((int) 0x0aba93e2), unchecked((int) 0xe52aa0c0), unchecked((int) 0x43e0223c), unchecked((int) 0x1d171b12), unchecked((int) 0x0b0d090e), + unchecked((int) 0xadc78bf2), unchecked((int) 0xb9a8b62d), unchecked((int) 0xc8a91e14), unchecked((int) 0x8519f157), unchecked((int) 0x4c0775af), + unchecked((int) 0xbbdd99ee), unchecked((int) 0xfd607fa3), unchecked((int) 0x9f2601f7), unchecked((int) 0xbcf5725c), unchecked((int) 0xc53b6644), + unchecked((int) 0x347efb5b), unchecked((int) 0x7629438b), unchecked((int) 0xdcc623cb), unchecked((int) 0x68fcedb6), unchecked((int) 0x63f1e4b8), + unchecked((int) 0xcadc31d7), unchecked((int) 0x10856342), unchecked((int) 0x40229713), unchecked((int) 0x2011c684), unchecked((int) 0x7d244a85), + unchecked((int) 0xf83dbbd2), unchecked((int) 0x1132f9ae), unchecked((int) 0x6da129c7), unchecked((int) 0x4b2f9e1d), unchecked((int) 0xf330b2dc), + unchecked((int) 0xec52860d), unchecked((int) 0xd0e3c177), unchecked((int) 0x6c16b32b), unchecked((int) 0x99b970a9), unchecked((int) 0xfa489411), + unchecked((int) 0x2264e947), unchecked((int) 0xc48cfca8), unchecked((int) 0x1a3ff0a0), unchecked((int) 0xd82c7d56), unchecked((int) 0xef903322), + unchecked((int) 0xc74e4987), unchecked((int) 0xc1d138d9), unchecked((int) 0xfea2ca8c), unchecked((int) 0x360bd498), unchecked((int) 0xcf81f5a6), + unchecked((int) 0x28de7aa5), unchecked((int) 0x268eb7da), unchecked((int) 0xa4bfad3f), unchecked((int) 0xe49d3a2c), unchecked((int) 0x0d927850), + unchecked((int) 0x9bcc5f6a), unchecked((int) 0x62467e54), unchecked((int) 0xc2138df6), unchecked((int) 0xe8b8d890), unchecked((int) 0x5ef7392e), + unchecked((int) 0xf5afc382), unchecked((int) 0xbe805d9f), unchecked((int) 0x7c93d069), unchecked((int) 0xa92dd56f), unchecked((int) 0xb31225cf), + unchecked((int) 0x3b99acc8), unchecked((int) 0xa77d1810), unchecked((int) 0x6e639ce8), unchecked((int) 0x7bbb3bdb), unchecked((int) 0x097826cd), + unchecked((int) 0xf418596e), unchecked((int) 0x01b79aec), unchecked((int) 0xa89a4f83), unchecked((int) 0x656e95e6), unchecked((int) 0x7ee6ffaa), + unchecked((int) 0x08cfbc21), unchecked((int) 0xe6e815ef), unchecked((int) 0xd99be7ba), unchecked((int) 0xce366f4a), unchecked((int) 0xd4099fea), + unchecked((int) 0xd67cb029), unchecked((int) 0xafb2a431), unchecked((int) 0x31233f2a), unchecked((int) 0x3094a5c6), unchecked((int) 0xc066a235), + unchecked((int) 0x37bc4e74), unchecked((int) 0xa6ca82fc), unchecked((int) 0xb0d090e0), unchecked((int) 0x15d8a733), unchecked((int) 0x4a9804f1), + unchecked((int) 0xf7daec41), unchecked((int) 0x0e50cd7f), unchecked((int) 0x2ff69117), unchecked((int) 0x8dd64d76), unchecked((int) 0x4db0ef43), + unchecked((int) 0x544daacc), unchecked((int) 0xdf0496e4), unchecked((int) 0xe3b5d19e), unchecked((int) 0x1b886a4c), unchecked((int) 0xb81f2cc1), + unchecked((int) 0x7f516546), unchecked((int) 0x04ea5e9d), unchecked((int) 0x5d358c01), unchecked((int) 0x737487fa), unchecked((int) 0x2e410bfb), + unchecked((int) 0x5a1d67b3), unchecked((int) 0x52d2db92), unchecked((int) 0x335610e9), unchecked((int) 0x1347d66d), unchecked((int) 0x8c61d79a), + unchecked((int) 0x7a0ca137), unchecked((int) 0x8e14f859), unchecked((int) 0x893c13eb), unchecked((int) 0xee27a9ce), unchecked((int) 0x35c961b7), + unchecked((int) 0xede51ce1), unchecked((int) 0x3cb1477a), unchecked((int) 0x59dfd29c), unchecked((int) 0x3f73f255), unchecked((int) 0x79ce1418), + unchecked((int) 0xbf37c773), unchecked((int) 0xeacdf753), unchecked((int) 0x5baafd5f), unchecked((int) 0x146f3ddf), unchecked((int) 0x86db4478), + unchecked((int) 0x81f3afca), unchecked((int) 0x3ec468b9), unchecked((int) 0x2c342438), unchecked((int) 0x5f40a3c2), unchecked((int) 0x72c31d16), + unchecked((int) 0x0c25e2bc), unchecked((int) 0x8b493c28), unchecked((int) 0x41950dff), unchecked((int) 0x7101a839), unchecked((int) 0xdeb30c08), + unchecked((int) 0x9ce4b4d8), unchecked((int) 0x90c15664), unchecked((int) 0x6184cb7b), unchecked((int) 0x70b632d5), unchecked((int) 0x745c6c48), + unchecked((int) 0x4257b8d0)}; + + private static readonly int[] Tinv1 = + { + unchecked((int) 0xa7f45150), unchecked((int) 0x65417e53), unchecked((int) 0xa4171ac3), unchecked((int) 0x5e273a96), unchecked((int) 0x6bab3bcb), + unchecked((int) 0x459d1ff1), unchecked((int) 0x58faacab), unchecked((int) 0x03e34b93), unchecked((int) 0xfa302055), unchecked((int) 0x6d76adf6), + unchecked((int) 0x76cc8891), unchecked((int) 0x4c02f525), unchecked((int) 0xd7e54ffc), unchecked((int) 0xcb2ac5d7), unchecked((int) 0x44352680), + unchecked((int) 0xa362b58f), unchecked((int) 0x5ab1de49), unchecked((int) 0x1bba2567), unchecked((int) 0x0eea4598), unchecked((int) 0xc0fe5de1), + unchecked((int) 0x752fc302), unchecked((int) 0xf04c8112), unchecked((int) 0x97468da3), unchecked((int) 0xf9d36bc6), unchecked((int) 0x5f8f03e7), + unchecked((int) 0x9c921595), unchecked((int) 0x7a6dbfeb), unchecked((int) 0x595295da), unchecked((int) 0x83bed42d), unchecked((int) 0x217458d3), + unchecked((int) 0x69e04929), unchecked((int) 0xc8c98e44), unchecked((int) 0x89c2756a), unchecked((int) 0x798ef478), unchecked((int) 0x3e58996b), + unchecked((int) 0x71b927dd), unchecked((int) 0x4fe1beb6), unchecked((int) 0xad88f017), unchecked((int) 0xac20c966), unchecked((int) 0x3ace7db4), + unchecked((int) 0x4adf6318), unchecked((int) 0x311ae582), unchecked((int) 0x33519760), unchecked((int) 0x7f536245), unchecked((int) 0x7764b1e0), + unchecked((int) 0xae6bbb84), unchecked((int) 0xa081fe1c), unchecked((int) 0x2b08f994), unchecked((int) 0x68487058), unchecked((int) 0xfd458f19), + unchecked((int) 0x6cde9487), unchecked((int) 0xf87b52b7), unchecked((int) 0xd373ab23), unchecked((int) 0x024b72e2), unchecked((int) 0x8f1fe357), + unchecked((int) 0xab55662a), unchecked((int) 0x28ebb207), unchecked((int) 0xc2b52f03), unchecked((int) 0x7bc5869a), unchecked((int) 0x0837d3a5), + unchecked((int) 0x872830f2), unchecked((int) 0xa5bf23b2), unchecked((int) 0x6a0302ba), unchecked((int) 0x8216ed5c), unchecked((int) 0x1ccf8a2b), + unchecked((int) 0xb479a792), unchecked((int) 0xf207f3f0), unchecked((int) 0xe2694ea1), unchecked((int) 0xf4da65cd), unchecked((int) 0xbe0506d5), + unchecked((int) 0x6234d11f), unchecked((int) 0xfea6c48a), unchecked((int) 0x532e349d), unchecked((int) 0x55f3a2a0), unchecked((int) 0xe18a0532), + unchecked((int) 0xebf6a475), unchecked((int) 0xec830b39), unchecked((int) 0xef6040aa), unchecked((int) 0x9f715e06), unchecked((int) 0x106ebd51), + unchecked((int) 0x8a213ef9), unchecked((int) 0x06dd963d), unchecked((int) 0x053eddae), unchecked((int) 0xbde64d46), unchecked((int) 0x8d5491b5), + unchecked((int) 0x5dc47105), unchecked((int) 0xd406046f), unchecked((int) 0x155060ff), unchecked((int) 0xfb981924), unchecked((int) 0xe9bdd697), + unchecked((int) 0x434089cc), unchecked((int) 0x9ed96777), unchecked((int) 0x42e8b0bd), unchecked((int) 0x8b890788), unchecked((int) 0x5b19e738), + unchecked((int) 0xeec879db), unchecked((int) 0x0a7ca147), unchecked((int) 0x0f427ce9), unchecked((int) 0x1e84f8c9), unchecked((int) 0x00000000), + unchecked((int) 0x86800983), unchecked((int) 0xed2b3248), unchecked((int) 0x70111eac), unchecked((int) 0x725a6c4e), unchecked((int) 0xff0efdfb), + unchecked((int) 0x38850f56), unchecked((int) 0xd5ae3d1e), unchecked((int) 0x392d3627), unchecked((int) 0xd90f0a64), unchecked((int) 0xa65c6821), + unchecked((int) 0x545b9bd1), unchecked((int) 0x2e36243a), unchecked((int) 0x670a0cb1), unchecked((int) 0xe757930f), unchecked((int) 0x96eeb4d2), + unchecked((int) 0x919b1b9e), unchecked((int) 0xc5c0804f), unchecked((int) 0x20dc61a2), unchecked((int) 0x4b775a69), unchecked((int) 0x1a121c16), + unchecked((int) 0xba93e20a), unchecked((int) 0x2aa0c0e5), unchecked((int) 0xe0223c43), unchecked((int) 0x171b121d), unchecked((int) 0x0d090e0b), + unchecked((int) 0xc78bf2ad), unchecked((int) 0xa8b62db9), unchecked((int) 0xa91e14c8), unchecked((int) 0x19f15785), unchecked((int) 0x0775af4c), + unchecked((int) 0xdd99eebb), unchecked((int) 0x607fa3fd), unchecked((int) 0x2601f79f), unchecked((int) 0xf5725cbc), unchecked((int) 0x3b6644c5), + unchecked((int) 0x7efb5b34), unchecked((int) 0x29438b76), unchecked((int) 0xc623cbdc), unchecked((int) 0xfcedb668), unchecked((int) 0xf1e4b863), + unchecked((int) 0xdc31d7ca), unchecked((int) 0x85634210), unchecked((int) 0x22971340), unchecked((int) 0x11c68420), unchecked((int) 0x244a857d), + unchecked((int) 0x3dbbd2f8), unchecked((int) 0x32f9ae11), unchecked((int) 0xa129c76d), unchecked((int) 0x2f9e1d4b), unchecked((int) 0x30b2dcf3), + unchecked((int) 0x52860dec), unchecked((int) 0xe3c177d0), unchecked((int) 0x16b32b6c), unchecked((int) 0xb970a999), unchecked((int) 0x489411fa), + unchecked((int) 0x64e94722), unchecked((int) 0x8cfca8c4), unchecked((int) 0x3ff0a01a), unchecked((int) 0x2c7d56d8), unchecked((int) 0x903322ef), + unchecked((int) 0x4e4987c7), unchecked((int) 0xd138d9c1), unchecked((int) 0xa2ca8cfe), unchecked((int) 0x0bd49836), unchecked((int) 0x81f5a6cf), + unchecked((int) 0xde7aa528), unchecked((int) 0x8eb7da26), unchecked((int) 0xbfad3fa4), unchecked((int) 0x9d3a2ce4), unchecked((int) 0x9278500d), + unchecked((int) 0xcc5f6a9b), unchecked((int) 0x467e5462), unchecked((int) 0x138df6c2), unchecked((int) 0xb8d890e8), unchecked((int) 0xf7392e5e), + unchecked((int) 0xafc382f5), unchecked((int) 0x805d9fbe), unchecked((int) 0x93d0697c), unchecked((int) 0x2dd56fa9), unchecked((int) 0x1225cfb3), + unchecked((int) 0x99acc83b), unchecked((int) 0x7d1810a7), unchecked((int) 0x639ce86e), unchecked((int) 0xbb3bdb7b), unchecked((int) 0x7826cd09), + unchecked((int) 0x18596ef4), unchecked((int) 0xb79aec01), unchecked((int) 0x9a4f83a8), unchecked((int) 0x6e95e665), unchecked((int) 0xe6ffaa7e), + unchecked((int) 0xcfbc2108), unchecked((int) 0xe815efe6), unchecked((int) 0x9be7bad9), unchecked((int) 0x366f4ace), unchecked((int) 0x099fead4), + unchecked((int) 0x7cb029d6), unchecked((int) 0xb2a431af), unchecked((int) 0x233f2a31), unchecked((int) 0x94a5c630), unchecked((int) 0x66a235c0), + unchecked((int) 0xbc4e7437), unchecked((int) 0xca82fca6), unchecked((int) 0xd090e0b0), unchecked((int) 0xd8a73315), unchecked((int) 0x9804f14a), + unchecked((int) 0xdaec41f7), unchecked((int) 0x50cd7f0e), unchecked((int) 0xf691172f), unchecked((int) 0xd64d768d), unchecked((int) 0xb0ef434d), + unchecked((int) 0x4daacc54), unchecked((int) 0x0496e4df), unchecked((int) 0xb5d19ee3), unchecked((int) 0x886a4c1b), unchecked((int) 0x1f2cc1b8), + unchecked((int) 0x5165467f), unchecked((int) 0xea5e9d04), unchecked((int) 0x358c015d), unchecked((int) 0x7487fa73), unchecked((int) 0x410bfb2e), + unchecked((int) 0x1d67b35a), unchecked((int) 0xd2db9252), unchecked((int) 0x5610e933), unchecked((int) 0x47d66d13), unchecked((int) 0x61d79a8c), + unchecked((int) 0x0ca1377a), unchecked((int) 0x14f8598e), unchecked((int) 0x3c13eb89), unchecked((int) 0x27a9ceee), unchecked((int) 0xc961b735), + unchecked((int) 0xe51ce1ed), unchecked((int) 0xb1477a3c), unchecked((int) 0xdfd29c59), unchecked((int) 0x73f2553f), unchecked((int) 0xce141879), + unchecked((int) 0x37c773bf), unchecked((int) 0xcdf753ea), unchecked((int) 0xaafd5f5b), unchecked((int) 0x6f3ddf14), unchecked((int) 0xdb447886), + unchecked((int) 0xf3afca81), unchecked((int) 0xc468b93e), unchecked((int) 0x3424382c), unchecked((int) 0x40a3c25f), unchecked((int) 0xc31d1672), + unchecked((int) 0x25e2bc0c), unchecked((int) 0x493c288b), unchecked((int) 0x950dff41), unchecked((int) 0x01a83971), unchecked((int) 0xb30c08de), + unchecked((int) 0xe4b4d89c), unchecked((int) 0xc1566490), unchecked((int) 0x84cb7b61), unchecked((int) 0xb632d570), unchecked((int) 0x5c6c4874), + unchecked((int) 0x57b8d042)}; + + private static readonly int[] Tinv2 = + { + unchecked((int) 0xf45150a7), unchecked((int) 0x417e5365), unchecked((int) 0x171ac3a4), unchecked((int) 0x273a965e), unchecked((int) 0xab3bcb6b), + unchecked((int) 0x9d1ff145), unchecked((int) 0xfaacab58), unchecked((int) 0xe34b9303), unchecked((int) 0x302055fa), unchecked((int) 0x76adf66d), + unchecked((int) 0xcc889176), unchecked((int) 0x02f5254c), unchecked((int) 0xe54ffcd7), unchecked((int) 0x2ac5d7cb), unchecked((int) 0x35268044), + unchecked((int) 0x62b58fa3), unchecked((int) 0xb1de495a), unchecked((int) 0xba25671b), unchecked((int) 0xea45980e), unchecked((int) 0xfe5de1c0), + unchecked((int) 0x2fc30275), unchecked((int) 0x4c8112f0), unchecked((int) 0x468da397), unchecked((int) 0xd36bc6f9), unchecked((int) 0x8f03e75f), + unchecked((int) 0x9215959c), unchecked((int) 0x6dbfeb7a), unchecked((int) 0x5295da59), unchecked((int) 0xbed42d83), unchecked((int) 0x7458d321), + unchecked((int) 0xe0492969), unchecked((int) 0xc98e44c8), unchecked((int) 0xc2756a89), unchecked((int) 0x8ef47879), unchecked((int) 0x58996b3e), + unchecked((int) 0xb927dd71), unchecked((int) 0xe1beb64f), unchecked((int) 0x88f017ad), unchecked((int) 0x20c966ac), unchecked((int) 0xce7db43a), + unchecked((int) 0xdf63184a), unchecked((int) 0x1ae58231), unchecked((int) 0x51976033), unchecked((int) 0x5362457f), unchecked((int) 0x64b1e077), + unchecked((int) 0x6bbb84ae), unchecked((int) 0x81fe1ca0), unchecked((int) 0x08f9942b), unchecked((int) 0x48705868), unchecked((int) 0x458f19fd), + unchecked((int) 0xde94876c), unchecked((int) 0x7b52b7f8), unchecked((int) 0x73ab23d3), unchecked((int) 0x4b72e202), unchecked((int) 0x1fe3578f), + unchecked((int) 0x55662aab), unchecked((int) 0xebb20728), unchecked((int) 0xb52f03c2), unchecked((int) 0xc5869a7b), unchecked((int) 0x37d3a508), + unchecked((int) 0x2830f287), unchecked((int) 0xbf23b2a5), unchecked((int) 0x0302ba6a), unchecked((int) 0x16ed5c82), unchecked((int) 0xcf8a2b1c), + unchecked((int) 0x79a792b4), unchecked((int) 0x07f3f0f2), unchecked((int) 0x694ea1e2), unchecked((int) 0xda65cdf4), unchecked((int) 0x0506d5be), + unchecked((int) 0x34d11f62), unchecked((int) 0xa6c48afe), unchecked((int) 0x2e349d53), unchecked((int) 0xf3a2a055), unchecked((int) 0x8a0532e1), + unchecked((int) 0xf6a475eb), unchecked((int) 0x830b39ec), unchecked((int) 0x6040aaef), unchecked((int) 0x715e069f), unchecked((int) 0x6ebd5110), + unchecked((int) 0x213ef98a), unchecked((int) 0xdd963d06), unchecked((int) 0x3eddae05), unchecked((int) 0xe64d46bd), unchecked((int) 0x5491b58d), + unchecked((int) 0xc471055d), unchecked((int) 0x06046fd4), unchecked((int) 0x5060ff15), unchecked((int) 0x981924fb), unchecked((int) 0xbdd697e9), + unchecked((int) 0x4089cc43), unchecked((int) 0xd967779e), unchecked((int) 0xe8b0bd42), unchecked((int) 0x8907888b), unchecked((int) 0x19e7385b), + unchecked((int) 0xc879dbee), unchecked((int) 0x7ca1470a), unchecked((int) 0x427ce90f), unchecked((int) 0x84f8c91e), unchecked((int) 0x00000000), + unchecked((int) 0x80098386), unchecked((int) 0x2b3248ed), unchecked((int) 0x111eac70), unchecked((int) 0x5a6c4e72), unchecked((int) 0x0efdfbff), + unchecked((int) 0x850f5638), unchecked((int) 0xae3d1ed5), unchecked((int) 0x2d362739), unchecked((int) 0x0f0a64d9), unchecked((int) 0x5c6821a6), + unchecked((int) 0x5b9bd154), unchecked((int) 0x36243a2e), unchecked((int) 0x0a0cb167), unchecked((int) 0x57930fe7), unchecked((int) 0xeeb4d296), + unchecked((int) 0x9b1b9e91), unchecked((int) 0xc0804fc5), unchecked((int) 0xdc61a220), unchecked((int) 0x775a694b), unchecked((int) 0x121c161a), + unchecked((int) 0x93e20aba), unchecked((int) 0xa0c0e52a), unchecked((int) 0x223c43e0), unchecked((int) 0x1b121d17), unchecked((int) 0x090e0b0d), + unchecked((int) 0x8bf2adc7), unchecked((int) 0xb62db9a8), unchecked((int) 0x1e14c8a9), unchecked((int) 0xf1578519), unchecked((int) 0x75af4c07), + unchecked((int) 0x99eebbdd), unchecked((int) 0x7fa3fd60), unchecked((int) 0x01f79f26), unchecked((int) 0x725cbcf5), unchecked((int) 0x6644c53b), + unchecked((int) 0xfb5b347e), unchecked((int) 0x438b7629), unchecked((int) 0x23cbdcc6), unchecked((int) 0xedb668fc), unchecked((int) 0xe4b863f1), + unchecked((int) 0x31d7cadc), unchecked((int) 0x63421085), unchecked((int) 0x97134022), unchecked((int) 0xc6842011), unchecked((int) 0x4a857d24), + unchecked((int) 0xbbd2f83d), unchecked((int) 0xf9ae1132), unchecked((int) 0x29c76da1), unchecked((int) 0x9e1d4b2f), unchecked((int) 0xb2dcf330), + unchecked((int) 0x860dec52), unchecked((int) 0xc177d0e3), unchecked((int) 0xb32b6c16), unchecked((int) 0x70a999b9), unchecked((int) 0x9411fa48), + unchecked((int) 0xe9472264), unchecked((int) 0xfca8c48c), unchecked((int) 0xf0a01a3f), unchecked((int) 0x7d56d82c), unchecked((int) 0x3322ef90), + unchecked((int) 0x4987c74e), unchecked((int) 0x38d9c1d1), unchecked((int) 0xca8cfea2), unchecked((int) 0xd498360b), unchecked((int) 0xf5a6cf81), + unchecked((int) 0x7aa528de), unchecked((int) 0xb7da268e), unchecked((int) 0xad3fa4bf), unchecked((int) 0x3a2ce49d), unchecked((int) 0x78500d92), + unchecked((int) 0x5f6a9bcc), unchecked((int) 0x7e546246), unchecked((int) 0x8df6c213), unchecked((int) 0xd890e8b8), unchecked((int) 0x392e5ef7), + unchecked((int) 0xc382f5af), unchecked((int) 0x5d9fbe80), unchecked((int) 0xd0697c93), unchecked((int) 0xd56fa92d), unchecked((int) 0x25cfb312), + unchecked((int) 0xacc83b99), unchecked((int) 0x1810a77d), unchecked((int) 0x9ce86e63), unchecked((int) 0x3bdb7bbb), unchecked((int) 0x26cd0978), + unchecked((int) 0x596ef418), unchecked((int) 0x9aec01b7), unchecked((int) 0x4f83a89a), unchecked((int) 0x95e6656e), unchecked((int) 0xffaa7ee6), + unchecked((int) 0xbc2108cf), unchecked((int) 0x15efe6e8), unchecked((int) 0xe7bad99b), unchecked((int) 0x6f4ace36), unchecked((int) 0x9fead409), + unchecked((int) 0xb029d67c), unchecked((int) 0xa431afb2), unchecked((int) 0x3f2a3123), unchecked((int) 0xa5c63094), unchecked((int) 0xa235c066), + unchecked((int) 0x4e7437bc), unchecked((int) 0x82fca6ca), unchecked((int) 0x90e0b0d0), unchecked((int) 0xa73315d8), unchecked((int) 0x04f14a98), + unchecked((int) 0xec41f7da), unchecked((int) 0xcd7f0e50), unchecked((int) 0x91172ff6), unchecked((int) 0x4d768dd6), unchecked((int) 0xef434db0), + unchecked((int) 0xaacc544d), unchecked((int) 0x96e4df04), unchecked((int) 0xd19ee3b5), unchecked((int) 0x6a4c1b88), unchecked((int) 0x2cc1b81f), + unchecked((int) 0x65467f51), unchecked((int) 0x5e9d04ea), unchecked((int) 0x8c015d35), unchecked((int) 0x87fa7374), unchecked((int) 0x0bfb2e41), + unchecked((int) 0x67b35a1d), unchecked((int) 0xdb9252d2), unchecked((int) 0x10e93356), unchecked((int) 0xd66d1347), unchecked((int) 0xd79a8c61), + unchecked((int) 0xa1377a0c), unchecked((int) 0xf8598e14), unchecked((int) 0x13eb893c), unchecked((int) 0xa9ceee27), unchecked((int) 0x61b735c9), + unchecked((int) 0x1ce1ede5), unchecked((int) 0x477a3cb1), unchecked((int) 0xd29c59df), unchecked((int) 0xf2553f73), unchecked((int) 0x141879ce), + unchecked((int) 0xc773bf37), unchecked((int) 0xf753eacd), unchecked((int) 0xfd5f5baa), unchecked((int) 0x3ddf146f), unchecked((int) 0x447886db), + unchecked((int) 0xafca81f3), unchecked((int) 0x68b93ec4), unchecked((int) 0x24382c34), unchecked((int) 0xa3c25f40), unchecked((int) 0x1d1672c3), + unchecked((int) 0xe2bc0c25), unchecked((int) 0x3c288b49), unchecked((int) 0x0dff4195), unchecked((int) 0xa8397101), unchecked((int) 0x0c08deb3), + unchecked((int) 0xb4d89ce4), unchecked((int) 0x566490c1), unchecked((int) 0xcb7b6184), unchecked((int) 0x32d570b6), unchecked((int) 0x6c48745c), + unchecked((int) 0xb8d04257)}; + + private static readonly int[] Tinv3 = + { + unchecked((int) 0x5150a7f4), unchecked((int) 0x7e536541), unchecked((int) 0x1ac3a417), unchecked((int) 0x3a965e27), unchecked((int) 0x3bcb6bab), + unchecked((int) 0x1ff1459d), unchecked((int) 0xacab58fa), unchecked((int) 0x4b9303e3), unchecked((int) 0x2055fa30), unchecked((int) 0xadf66d76), + unchecked((int) 0x889176cc), unchecked((int) 0xf5254c02), unchecked((int) 0x4ffcd7e5), unchecked((int) 0xc5d7cb2a), unchecked((int) 0x26804435), + unchecked((int) 0xb58fa362), unchecked((int) 0xde495ab1), unchecked((int) 0x25671bba), unchecked((int) 0x45980eea), unchecked((int) 0x5de1c0fe), + unchecked((int) 0xc302752f), unchecked((int) 0x8112f04c), unchecked((int) 0x8da39746), unchecked((int) 0x6bc6f9d3), unchecked((int) 0x03e75f8f), + unchecked((int) 0x15959c92), unchecked((int) 0xbfeb7a6d), unchecked((int) 0x95da5952), unchecked((int) 0xd42d83be), unchecked((int) 0x58d32174), + unchecked((int) 0x492969e0), unchecked((int) 0x8e44c8c9), unchecked((int) 0x756a89c2), unchecked((int) 0xf478798e), unchecked((int) 0x996b3e58), + unchecked((int) 0x27dd71b9), unchecked((int) 0xbeb64fe1), unchecked((int) 0xf017ad88), unchecked((int) 0xc966ac20), unchecked((int) 0x7db43ace), + unchecked((int) 0x63184adf), unchecked((int) 0xe582311a), unchecked((int) 0x97603351), unchecked((int) 0x62457f53), unchecked((int) 0xb1e07764), + unchecked((int) 0xbb84ae6b), unchecked((int) 0xfe1ca081), unchecked((int) 0xf9942b08), unchecked((int) 0x70586848), unchecked((int) 0x8f19fd45), + unchecked((int) 0x94876cde), unchecked((int) 0x52b7f87b), unchecked((int) 0xab23d373), unchecked((int) 0x72e2024b), unchecked((int) 0xe3578f1f), + unchecked((int) 0x662aab55), unchecked((int) 0xb20728eb), unchecked((int) 0x2f03c2b5), unchecked((int) 0x869a7bc5), unchecked((int) 0xd3a50837), + unchecked((int) 0x30f28728), unchecked((int) 0x23b2a5bf), unchecked((int) 0x02ba6a03), unchecked((int) 0xed5c8216), unchecked((int) 0x8a2b1ccf), + unchecked((int) 0xa792b479), unchecked((int) 0xf3f0f207), unchecked((int) 0x4ea1e269), unchecked((int) 0x65cdf4da), unchecked((int) 0x06d5be05), + unchecked((int) 0xd11f6234), unchecked((int) 0xc48afea6), unchecked((int) 0x349d532e), unchecked((int) 0xa2a055f3), unchecked((int) 0x0532e18a), + unchecked((int) 0xa475ebf6), unchecked((int) 0x0b39ec83), unchecked((int) 0x40aaef60), unchecked((int) 0x5e069f71), unchecked((int) 0xbd51106e), + unchecked((int) 0x3ef98a21), unchecked((int) 0x963d06dd), unchecked((int) 0xddae053e), unchecked((int) 0x4d46bde6), unchecked((int) 0x91b58d54), + unchecked((int) 0x71055dc4), unchecked((int) 0x046fd406), unchecked((int) 0x60ff1550), unchecked((int) 0x1924fb98), unchecked((int) 0xd697e9bd), + unchecked((int) 0x89cc4340), unchecked((int) 0x67779ed9), unchecked((int) 0xb0bd42e8), unchecked((int) 0x07888b89), unchecked((int) 0xe7385b19), + unchecked((int) 0x79dbeec8), unchecked((int) 0xa1470a7c), unchecked((int) 0x7ce90f42), unchecked((int) 0xf8c91e84), unchecked((int) 0x00000000), + unchecked((int) 0x09838680), unchecked((int) 0x3248ed2b), unchecked((int) 0x1eac7011), unchecked((int) 0x6c4e725a), unchecked((int) 0xfdfbff0e), + unchecked((int) 0x0f563885), unchecked((int) 0x3d1ed5ae), unchecked((int) 0x3627392d), unchecked((int) 0x0a64d90f), unchecked((int) 0x6821a65c), + unchecked((int) 0x9bd1545b), unchecked((int) 0x243a2e36), unchecked((int) 0x0cb1670a), unchecked((int) 0x930fe757), unchecked((int) 0xb4d296ee), + unchecked((int) 0x1b9e919b), unchecked((int) 0x804fc5c0), unchecked((int) 0x61a220dc), unchecked((int) 0x5a694b77), unchecked((int) 0x1c161a12), + unchecked((int) 0xe20aba93), unchecked((int) 0xc0e52aa0), unchecked((int) 0x3c43e022), unchecked((int) 0x121d171b), unchecked((int) 0x0e0b0d09), + unchecked((int) 0xf2adc78b), unchecked((int) 0x2db9a8b6), unchecked((int) 0x14c8a91e), unchecked((int) 0x578519f1), unchecked((int) 0xaf4c0775), + unchecked((int) 0xeebbdd99), unchecked((int) 0xa3fd607f), unchecked((int) 0xf79f2601), unchecked((int) 0x5cbcf572), unchecked((int) 0x44c53b66), + unchecked((int) 0x5b347efb), unchecked((int) 0x8b762943), unchecked((int) 0xcbdcc623), unchecked((int) 0xb668fced), unchecked((int) 0xb863f1e4), + unchecked((int) 0xd7cadc31), unchecked((int) 0x42108563), unchecked((int) 0x13402297), unchecked((int) 0x842011c6), unchecked((int) 0x857d244a), + unchecked((int) 0xd2f83dbb), unchecked((int) 0xae1132f9), unchecked((int) 0xc76da129), unchecked((int) 0x1d4b2f9e), unchecked((int) 0xdcf330b2), + unchecked((int) 0x0dec5286), unchecked((int) 0x77d0e3c1), unchecked((int) 0x2b6c16b3), unchecked((int) 0xa999b970), unchecked((int) 0x11fa4894), + unchecked((int) 0x472264e9), unchecked((int) 0xa8c48cfc), unchecked((int) 0xa01a3ff0), unchecked((int) 0x56d82c7d), unchecked((int) 0x22ef9033), + unchecked((int) 0x87c74e49), unchecked((int) 0xd9c1d138), unchecked((int) 0x8cfea2ca), unchecked((int) 0x98360bd4), unchecked((int) 0xa6cf81f5), + unchecked((int) 0xa528de7a), unchecked((int) 0xda268eb7), unchecked((int) 0x3fa4bfad), unchecked((int) 0x2ce49d3a), unchecked((int) 0x500d9278), + unchecked((int) 0x6a9bcc5f), unchecked((int) 0x5462467e), unchecked((int) 0xf6c2138d), unchecked((int) 0x90e8b8d8), unchecked((int) 0x2e5ef739), + unchecked((int) 0x82f5afc3), unchecked((int) 0x9fbe805d), unchecked((int) 0x697c93d0), unchecked((int) 0x6fa92dd5), unchecked((int) 0xcfb31225), + unchecked((int) 0xc83b99ac), unchecked((int) 0x10a77d18), unchecked((int) 0xe86e639c), unchecked((int) 0xdb7bbb3b), unchecked((int) 0xcd097826), + unchecked((int) 0x6ef41859), unchecked((int) 0xec01b79a), unchecked((int) 0x83a89a4f), unchecked((int) 0xe6656e95), unchecked((int) 0xaa7ee6ff), + unchecked((int) 0x2108cfbc), unchecked((int) 0xefe6e815), unchecked((int) 0xbad99be7), unchecked((int) 0x4ace366f), unchecked((int) 0xead4099f), + unchecked((int) 0x29d67cb0), unchecked((int) 0x31afb2a4), unchecked((int) 0x2a31233f), unchecked((int) 0xc63094a5), unchecked((int) 0x35c066a2), + unchecked((int) 0x7437bc4e), unchecked((int) 0xfca6ca82), unchecked((int) 0xe0b0d090), unchecked((int) 0x3315d8a7), unchecked((int) 0xf14a9804), + unchecked((int) 0x41f7daec), unchecked((int) 0x7f0e50cd), unchecked((int) 0x172ff691), unchecked((int) 0x768dd64d), unchecked((int) 0x434db0ef), + unchecked((int) 0xcc544daa), unchecked((int) 0xe4df0496), unchecked((int) 0x9ee3b5d1), unchecked((int) 0x4c1b886a), unchecked((int) 0xc1b81f2c), + unchecked((int) 0x467f5165), unchecked((int) 0x9d04ea5e), unchecked((int) 0x015d358c), unchecked((int) 0xfa737487), unchecked((int) 0xfb2e410b), + unchecked((int) 0xb35a1d67), unchecked((int) 0x9252d2db), unchecked((int) 0xe9335610), unchecked((int) 0x6d1347d6), unchecked((int) 0x9a8c61d7), + unchecked((int) 0x377a0ca1), unchecked((int) 0x598e14f8), unchecked((int) 0xeb893c13), unchecked((int) 0xceee27a9), unchecked((int) 0xb735c961), + unchecked((int) 0xe1ede51c), unchecked((int) 0x7a3cb147), unchecked((int) 0x9c59dfd2), unchecked((int) 0x553f73f2), unchecked((int) 0x1879ce14), + unchecked((int) 0x73bf37c7), unchecked((int) 0x53eacdf7), unchecked((int) 0x5f5baafd), unchecked((int) 0xdf146f3d), unchecked((int) 0x7886db44), + unchecked((int) 0xca81f3af), unchecked((int) 0xb93ec468), unchecked((int) 0x382c3424), unchecked((int) 0xc25f40a3), unchecked((int) 0x1672c31d), + unchecked((int) 0xbc0c25e2), unchecked((int) 0x288b493c), unchecked((int) 0xff41950d), unchecked((int) 0x397101a8), unchecked((int) 0x08deb30c), + unchecked((int) 0xd89ce4b4), unchecked((int) 0x6490c156), unchecked((int) 0x7b6184cb), unchecked((int) 0xd570b632), unchecked((int) 0x48745c6c), + unchecked((int) 0xd04257b8)}; + + private int Shift( + int r, + int shift) + { + return ((int) ( ( (uint) r >> shift) | + (uint) (r << (32 - shift)) + )); + } + + /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + + private const int m1 = unchecked((int) 0x80808080); + private const int m2 = unchecked((int) 0x7f7f7f7f); + private const int m3 = unchecked((int) 0x0000001b); + private int FFmulX(int x) { + return ( (int) ( ((x & m2) << 1) ^ + (( (uint)(x & m1) >> 7) * m3) + ) ); + } + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private int Inv_Mcol(int x) { + int f2 = FFmulX(x); + int f4 = FFmulX(f2); + int f8 = FFmulX(f4); + int f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + } + + + private int SubWord(int x) { + return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + private int[,] GenerateWorkingKey( + byte[] key, + bool forEncryption) + { + int KC = key.Length / 4; // key length in words + int t; + + if ((KC != 4) && (KC != 6) && (KC != 8)) { + throw new ArgumentException("Key length not 128/192/256 bits."); + } + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + int[,] W = new int[ROUNDS+1,4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + for (int i = 0; i < key.Length; t++) + { + W[t >> 2,t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); + i+=4; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for (int i = KC; (i < k); i++) + { + int temp = W[(i-1)>>2,(i-1)&3]; + if ((i % KC) == 0) { + temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1]; + } else if ((KC > 6) && ((i % KC) == 4)) { + temp = SubWord(temp); + } + + W[i>>2,i&3] = W[(i - KC)>>2,(i-KC)&3] ^ temp; + } + + if (!forEncryption) { + for (int j = 1; j < ROUNDS; j++) { + for (int i = 0; i < 4; i++){ + W[j,i] = Inv_Mcol(W[j,i]); + } + } + } + + return W; + } + + private int ROUNDS; + private int[,] WorkingKey; + private int C0, C1, C2, C3; + private bool forEncryption; + + private const int BLOCK_SIZE = 16; + + /** + * default constructor - 128 bit block size. + */ + public AesFastEngine() + { + } + + /** + * initialise an AES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString()); + + WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption); + this.forEncryption = forEncryption; + } + + public string AlgorithmName + { + get { return "AES"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (WorkingKey == null) + { + throw new InvalidOperationException("AES engine not initialised"); + } + + if ((inOff + (32 / 2)) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (32 / 2)) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (forEncryption) + { + UnPackBlock(input, inOff); + EncryptBlock(WorkingKey); + PackBlock(output, outOff); + } + else + { + UnPackBlock(input, inOff); + DecryptBlock(WorkingKey); + PackBlock(output, outOff); + } + + return BLOCK_SIZE; + } + + public void Reset() + { + } + + private void UnPackBlock( + byte[] bytes, + int off) + { + int index = off; + + C0 = (bytes[index++] & 0xff); + C0 |= (bytes[index++] & 0xff) << 8; + C0 |= (bytes[index++] & 0xff) << 16; + C0 |= bytes[index++] << 24; + + C1 = (bytes[index++] & 0xff); + C1 |= (bytes[index++] & 0xff) << 8; + C1 |= (bytes[index++] & 0xff) << 16; + C1 |= bytes[index++] << 24; + + C2 = (bytes[index++] & 0xff); + C2 |= (bytes[index++] & 0xff) << 8; + C2 |= (bytes[index++] & 0xff) << 16; + C2 |= bytes[index++] << 24; + + C3 = (bytes[index++] & 0xff); + C3 |= (bytes[index++] & 0xff) << 8; + C3 |= (bytes[index++] & 0xff) << 16; + C3 |= bytes[index++] << 24; + } + + private void PackBlock( + byte[] bytes, + int off) + { + int index = off; + + bytes[index++] = (byte)C0; + bytes[index++] = (byte)(C0 >> 8); + bytes[index++] = (byte)(C0 >> 16); + bytes[index++] = (byte)(C0 >> 24); + + bytes[index++] = (byte)C1; + bytes[index++] = (byte)(C1 >> 8); + bytes[index++] = (byte)(C1 >> 16); + bytes[index++] = (byte)(C1 >> 24); + + bytes[index++] = (byte)C2; + bytes[index++] = (byte)(C2 >> 8); + bytes[index++] = (byte)(C2 >> 16); + bytes[index++] = (byte)(C2 >> 24); + + bytes[index++] = (byte)C3; + bytes[index++] = (byte)(C3 >> 8); + bytes[index++] = (byte)(C3 >> 16); + bytes[index++] = (byte)(C3 >> 24); + } + + private void EncryptBlock(int[,] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[0,0]; + C1 ^= KW[0,1]; + C2 ^= KW[0,2]; + C3 ^= KW[0,3]; + + for (r = 1; r < ROUNDS - 1;) { + r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r,0]; + r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r,1]; + r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r,2]; + r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++,3]; + C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r,0]; + C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r,1]; + C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r,2]; + C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++,3]; + } + + r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r,0]; + r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r,1]; + r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r,2]; + r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++,3]; + + // the final round's table is a simple function of S so we don't use a whole other four tables for it + + C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0]; + C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1]; + C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2]; + C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3]; + + } + + private void DecryptBlock(int[,] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[ROUNDS,0]; + C1 ^= KW[ROUNDS,1]; + C2 ^= KW[ROUNDS,2]; + C3 ^= KW[ROUNDS,3]; + + for (r = ROUNDS-1; r>1;) { + r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r,0]; + r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r,1]; + r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r,2]; + r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--,3]; + C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r,0]; + C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r,1]; + C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r,2]; + C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--,3]; + } + + r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r,0]; + r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r,1]; + r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r,2]; + r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r,3]; + + // the final round's table is a simple function of Si so we don't use a whole other four tables for it + + C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0]; + C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1]; + C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2]; + C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3]; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/AesLightEngine.cs b/iTechSharp/srcbc/crypto/engines/AesLightEngine.cs new file mode 100644 index 0000000..40269c6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/AesLightEngine.cs @@ -0,0 +1,438 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * an implementation of the AES (Rijndael), from FIPS-197. + *

      + * For further details see: http://csrc.nist.gov/encryption/aes/. + * + * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + * + * There are three levels of tradeoff of speed vs memory + * Because java has no preprocessor, they are written as three separate classes from which to choose + * + * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption + * and 4 for decryption. + * + * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, + * adding 12 rotate operations per round to compute the values contained in the other tables from + * the contents of the first + * + * The slowest version uses no static tables at all and computes the values + * in each round. + *

      + *

      + * This file contains the slowest performance version with no static tables + * for round precomputation, but it has the smallest foot print. + *

      + */ + public class AesLightEngine + : IBlockCipher + { + // The S box + private static readonly byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, + (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, + (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, + (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, + (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, + (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, + (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, + (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, + (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, + (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, + (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, + (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, + (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, + (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, + (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, + (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, + (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + // The inverse S-box + private static readonly byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, + (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, + (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, + (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, + (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, + (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, + (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, + (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, + (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, + (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, + (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, + (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, + (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, + (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, + (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, + (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, + (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static readonly int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + private int Shift( + int r, + int shift) + { + return ((int) ( ( (uint) r >> shift) | + (uint) (r << (32 - shift)) ) + ); + } + + /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + + private const int m1 = unchecked((int) 0x80808080); + private const int m2 = unchecked((int) 0x7f7f7f7f); + private const int m3 = unchecked((int) 0x0000001b); + + private int FFmulX(int x) + { + return ( (int) ( ((x & m2) << 1) ^ + (( (uint)(x & m1) >> 7) * m3) + ) + ); + } + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private int Mcol(int x) + { + int f2 = FFmulX(x); + return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24); + } + + private int Inv_Mcol(int x) + { + int f2 = FFmulX(x); + int f4 = FFmulX(f2); + int f8 = FFmulX(f4); + int f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + } + + + private int SubWord(int x) + { + return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + private int[,] GenerateWorkingKey( + byte[] key, + bool forEncryption) + { + int KC = key.Length / 4; // key length in words + int t; + + if ((KC != 4) && (KC != 6) && (KC != 8)) { + throw new ArgumentException("Key length not 128/192/256 bits."); + } + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + int[,] W = new int[ROUNDS+1,4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + for (int i = 0; i < key.Length; t++) + { + W[t >> 2,t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); + i+=4; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for (int i = KC; (i < k); i++) + { + int temp = W[(i-1)>>2,(i-1)&3]; + if ((i % KC) == 0) { + temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC)-1]; + } else if ((KC > 6) && ((i % KC) == 4)) { + temp = SubWord(temp); + } + + W[i>>2,i&3] = W[(i - KC)>>2,(i-KC)&3] ^ temp; + } + + if (!forEncryption) { + for (int j = 1; j < ROUNDS; j++) { + for (int i = 0; i < 4; i++){ + W[j,i] = Inv_Mcol(W[j,i]); + } + } + } + + return W; + } + + private int ROUNDS; + private int[,] WorkingKey; + private int C0, C1, C2, C3; + private bool forEncryption; + + private const int BLOCK_SIZE = 16; + + /** + * default constructor - 128 bit block size. + */ + public AesLightEngine() + { + } + + /** + * initialise an AES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString()); + + WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption); + this.forEncryption = forEncryption; + } + + public string AlgorithmName + { + get { return "AES"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (WorkingKey == null) + { + throw new InvalidOperationException("AES engine not initialised"); + } + + if ((inOff + (32 / 2)) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (32 / 2)) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (forEncryption) + { + UnPackBlock(input, inOff); + EncryptBlock(WorkingKey); + PackBlock(output, outOff); + } + else + { + UnPackBlock(input, inOff); + DecryptBlock(WorkingKey); + PackBlock(output, outOff); + } + + return BLOCK_SIZE; + } + + public void Reset() + { + } + + private void UnPackBlock( + byte[] bytes, + int off) + { + int index = off; + + C0 = (bytes[index++] & 0xff); + C0 |= (bytes[index++] & 0xff) << 8; + C0 |= (bytes[index++] & 0xff) << 16; + C0 |= bytes[index++] << 24; + + C1 = (bytes[index++] & 0xff); + C1 |= (bytes[index++] & 0xff) << 8; + C1 |= (bytes[index++] & 0xff) << 16; + C1 |= bytes[index++] << 24; + + C2 = (bytes[index++] & 0xff); + C2 |= (bytes[index++] & 0xff) << 8; + C2 |= (bytes[index++] & 0xff) << 16; + C2 |= bytes[index++] << 24; + + C3 = (bytes[index++] & 0xff); + C3 |= (bytes[index++] & 0xff) << 8; + C3 |= (bytes[index++] & 0xff) << 16; + C3 |= bytes[index++] << 24; + } + + private void PackBlock( + byte[] bytes, + int off) + { + int index = off; + + bytes[index++] = (byte)C0; + bytes[index++] = (byte)(C0 >> 8); + bytes[index++] = (byte)(C0 >> 16); + bytes[index++] = (byte)(C0 >> 24); + + bytes[index++] = (byte)C1; + bytes[index++] = (byte)(C1 >> 8); + bytes[index++] = (byte)(C1 >> 16); + bytes[index++] = (byte)(C1 >> 24); + + bytes[index++] = (byte)C2; + bytes[index++] = (byte)(C2 >> 8); + bytes[index++] = (byte)(C2 >> 16); + bytes[index++] = (byte)(C2 >> 24); + + bytes[index++] = (byte)C3; + bytes[index++] = (byte)(C3 >> 8); + bytes[index++] = (byte)(C3 >> 16); + bytes[index++] = (byte)(C3 >> 24); + } + + private void EncryptBlock(int[,] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[0,0]; + C1 ^= KW[0,1]; + C2 ^= KW[0,2]; + C3 ^= KW[0,3]; + + for (r = 1; r < ROUNDS - 1;) { + r0 = Mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r,0]; + r1 = Mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r,1]; + r2 = Mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r,2]; + r3 = Mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++,3]; + C0 = Mcol((S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24)) ^ KW[r,0]; + C1 = Mcol((S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24)) ^ KW[r,1]; + C2 = Mcol((S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24)) ^ KW[r,2]; + C3 = Mcol((S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24)) ^ KW[r++,3]; + } + + r0 = Mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r,0]; + r1 = Mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r,1]; + r2 = Mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r,2]; + r3 = Mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++,3]; + + // the final round is a simple function of S + + C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r,0]; + C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r,1]; + C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r,2]; + C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r,3]; + + } + + private void DecryptBlock(int[,] KW) + { + int r, r0, r1, r2, r3; + + C0 ^= KW[ROUNDS,0]; + C1 ^= KW[ROUNDS,1]; + C2 ^= KW[ROUNDS,2]; + C3 ^= KW[ROUNDS,3]; + + for (r = ROUNDS-1; r>1;) { + r0 = Inv_Mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r,0]; + r1 = Inv_Mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r,1]; + r2 = Inv_Mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r,2]; + r3 = Inv_Mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--,3]; + C0 = Inv_Mcol((Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24)) ^ KW[r,0]; + C1 = Inv_Mcol((Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24)) ^ KW[r,1]; + C2 = Inv_Mcol((Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24)) ^ KW[r,2]; + C3 = Inv_Mcol((Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24)) ^ KW[r--,3]; + } + + r0 = Inv_Mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r,0]; + r1 = Inv_Mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r,1]; + r2 = Inv_Mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r,2]; + r3 = Inv_Mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r,3]; + + // the final round's table is a simple function of Si + + C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0,0]; + C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0,1]; + C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0,2]; + C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0,3]; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/AesWrapEngine.cs b/iTechSharp/srcbc/crypto/engines/AesWrapEngine.cs new file mode 100644 index 0000000..1ce0154 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/AesWrapEngine.cs @@ -0,0 +1,16 @@ +namespace Org.BouncyCastle.Crypto.Engines +{ + /// + /// An implementation of the AES Key Wrapper from the NIST Key Wrap Specification. + ///

      + /// For further details see: http://csrc.nist.gov/encryption/kms/key-wrap.pdf. + /// + public class AesWrapEngine + : Rfc3394WrapEngine + { + public AesWrapEngine() + : base(new AesEngine()) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/BlowfishEngine.cs b/iTechSharp/srcbc/crypto/engines/BlowfishEngine.cs new file mode 100644 index 0000000..110110e --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/BlowfishEngine.cs @@ -0,0 +1,577 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * A class that provides Blowfish key encryption operations, + * such as encoding data and generating keys. + * All the algorithms herein are from Applied Cryptography + * and implement a simplified cryptography interface. + */ + public sealed class BlowfishEngine + : IBlockCipher + { + private readonly static int[] + KP = { + unchecked((int) 0x243F6A88), unchecked((int) 0x85A308D3), unchecked((int) 0x13198A2E), unchecked((int) 0x03707344), + unchecked((int) 0xA4093822), unchecked((int) 0x299F31D0), unchecked((int) 0x082EFA98), unchecked((int) 0xEC4E6C89), + unchecked((int) 0x452821E6), unchecked((int) 0x38D01377), unchecked((int) 0xBE5466CF), unchecked((int) 0x34E90C6C), + unchecked((int) 0xC0AC29B7), unchecked((int) 0xC97C50DD), unchecked((int) 0x3F84D5B5), unchecked((int) 0xB5470917), + unchecked((int) 0x9216D5D9), unchecked((int) 0x8979FB1B) + }, + + KS0 = { + unchecked((int) 0xD1310BA6), unchecked((int) 0x98DFB5AC), unchecked((int) 0x2FFD72DB), unchecked((int) 0xD01ADFB7), + unchecked((int) 0xB8E1AFED), unchecked((int) 0x6A267E96), unchecked((int) 0xBA7C9045), unchecked((int) 0xF12C7F99), + unchecked((int) 0x24A19947), unchecked((int) 0xB3916CF7), unchecked((int) 0x0801F2E2), unchecked((int) 0x858EFC16), + unchecked((int) 0x636920D8), unchecked((int) 0x71574E69), unchecked((int) 0xA458FEA3), unchecked((int) 0xF4933D7E), + unchecked((int) 0x0D95748F), unchecked((int) 0x728EB658), unchecked((int) 0x718BCD58), unchecked((int) 0x82154AEE), + unchecked((int) 0x7B54A41D), unchecked((int) 0xC25A59B5), unchecked((int) 0x9C30D539), unchecked((int) 0x2AF26013), + unchecked((int) 0xC5D1B023), unchecked((int) 0x286085F0), unchecked((int) 0xCA417918), unchecked((int) 0xB8DB38EF), + unchecked((int) 0x8E79DCB0), unchecked((int) 0x603A180E), unchecked((int) 0x6C9E0E8B), unchecked((int) 0xB01E8A3E), + unchecked((int) 0xD71577C1), unchecked((int) 0xBD314B27), unchecked((int) 0x78AF2FDA), unchecked((int) 0x55605C60), + unchecked((int) 0xE65525F3), unchecked((int) 0xAA55AB94), unchecked((int) 0x57489862), unchecked((int) 0x63E81440), + unchecked((int) 0x55CA396A), unchecked((int) 0x2AAB10B6), unchecked((int) 0xB4CC5C34), unchecked((int) 0x1141E8CE), + unchecked((int) 0xA15486AF), unchecked((int) 0x7C72E993), unchecked((int) 0xB3EE1411), unchecked((int) 0x636FBC2A), + unchecked((int) 0x2BA9C55D), unchecked((int) 0x741831F6), unchecked((int) 0xCE5C3E16), unchecked((int) 0x9B87931E), + unchecked((int) 0xAFD6BA33), unchecked((int) 0x6C24CF5C), unchecked((int) 0x7A325381), unchecked((int) 0x28958677), + unchecked((int) 0x3B8F4898), unchecked((int) 0x6B4BB9AF), unchecked((int) 0xC4BFE81B), unchecked((int) 0x66282193), + unchecked((int) 0x61D809CC), unchecked((int) 0xFB21A991), unchecked((int) 0x487CAC60), unchecked((int) 0x5DEC8032), + unchecked((int) 0xEF845D5D), unchecked((int) 0xE98575B1), unchecked((int) 0xDC262302), unchecked((int) 0xEB651B88), + unchecked((int) 0x23893E81), unchecked((int) 0xD396ACC5), unchecked((int) 0x0F6D6FF3), unchecked((int) 0x83F44239), + unchecked((int) 0x2E0B4482), unchecked((int) 0xA4842004), unchecked((int) 0x69C8F04A), unchecked((int) 0x9E1F9B5E), + unchecked((int) 0x21C66842), unchecked((int) 0xF6E96C9A), unchecked((int) 0x670C9C61), unchecked((int) 0xABD388F0), + unchecked((int) 0x6A51A0D2), unchecked((int) 0xD8542F68), unchecked((int) 0x960FA728), unchecked((int) 0xAB5133A3), + unchecked((int) 0x6EEF0B6C), unchecked((int) 0x137A3BE4), unchecked((int) 0xBA3BF050), unchecked((int) 0x7EFB2A98), + unchecked((int) 0xA1F1651D), unchecked((int) 0x39AF0176), unchecked((int) 0x66CA593E), unchecked((int) 0x82430E88), + unchecked((int) 0x8CEE8619), unchecked((int) 0x456F9FB4), unchecked((int) 0x7D84A5C3), unchecked((int) 0x3B8B5EBE), + unchecked((int) 0xE06F75D8), unchecked((int) 0x85C12073), unchecked((int) 0x401A449F), unchecked((int) 0x56C16AA6), + unchecked((int) 0x4ED3AA62), unchecked((int) 0x363F7706), unchecked((int) 0x1BFEDF72), unchecked((int) 0x429B023D), + unchecked((int) 0x37D0D724), unchecked((int) 0xD00A1248), unchecked((int) 0xDB0FEAD3), unchecked((int) 0x49F1C09B), + unchecked((int) 0x075372C9), unchecked((int) 0x80991B7B), unchecked((int) 0x25D479D8), unchecked((int) 0xF6E8DEF7), + unchecked((int) 0xE3FE501A), unchecked((int) 0xB6794C3B), unchecked((int) 0x976CE0BD), unchecked((int) 0x04C006BA), + unchecked((int) 0xC1A94FB6), unchecked((int) 0x409F60C4), unchecked((int) 0x5E5C9EC2), unchecked((int) 0x196A2463), + unchecked((int) 0x68FB6FAF), unchecked((int) 0x3E6C53B5), unchecked((int) 0x1339B2EB), unchecked((int) 0x3B52EC6F), + unchecked((int) 0x6DFC511F), unchecked((int) 0x9B30952C), unchecked((int) 0xCC814544), unchecked((int) 0xAF5EBD09), + unchecked((int) 0xBEE3D004), unchecked((int) 0xDE334AFD), unchecked((int) 0x660F2807), unchecked((int) 0x192E4BB3), + unchecked((int) 0xC0CBA857), unchecked((int) 0x45C8740F), unchecked((int) 0xD20B5F39), unchecked((int) 0xB9D3FBDB), + unchecked((int) 0x5579C0BD), unchecked((int) 0x1A60320A), unchecked((int) 0xD6A100C6), unchecked((int) 0x402C7279), + unchecked((int) 0x679F25FE), unchecked((int) 0xFB1FA3CC), unchecked((int) 0x8EA5E9F8), unchecked((int) 0xDB3222F8), + unchecked((int) 0x3C7516DF), unchecked((int) 0xFD616B15), unchecked((int) 0x2F501EC8), unchecked((int) 0xAD0552AB), + unchecked((int) 0x323DB5FA), unchecked((int) 0xFD238760), unchecked((int) 0x53317B48), unchecked((int) 0x3E00DF82), + unchecked((int) 0x9E5C57BB), unchecked((int) 0xCA6F8CA0), unchecked((int) 0x1A87562E), unchecked((int) 0xDF1769DB), + unchecked((int) 0xD542A8F6), unchecked((int) 0x287EFFC3), unchecked((int) 0xAC6732C6), unchecked((int) 0x8C4F5573), + unchecked((int) 0x695B27B0), unchecked((int) 0xBBCA58C8), unchecked((int) 0xE1FFA35D), unchecked((int) 0xB8F011A0), + unchecked((int) 0x10FA3D98), unchecked((int) 0xFD2183B8), unchecked((int) 0x4AFCB56C), unchecked((int) 0x2DD1D35B), + unchecked((int) 0x9A53E479), unchecked((int) 0xB6F84565), unchecked((int) 0xD28E49BC), unchecked((int) 0x4BFB9790), + unchecked((int) 0xE1DDF2DA), unchecked((int) 0xA4CB7E33), unchecked((int) 0x62FB1341), unchecked((int) 0xCEE4C6E8), + unchecked((int) 0xEF20CADA), unchecked((int) 0x36774C01), unchecked((int) 0xD07E9EFE), unchecked((int) 0x2BF11FB4), + unchecked((int) 0x95DBDA4D), unchecked((int) 0xAE909198), unchecked((int) 0xEAAD8E71), unchecked((int) 0x6B93D5A0), + unchecked((int) 0xD08ED1D0), unchecked((int) 0xAFC725E0), unchecked((int) 0x8E3C5B2F), unchecked((int) 0x8E7594B7), + unchecked((int) 0x8FF6E2FB), unchecked((int) 0xF2122B64), unchecked((int) 0x8888B812), unchecked((int) 0x900DF01C), + unchecked((int) 0x4FAD5EA0), unchecked((int) 0x688FC31C), unchecked((int) 0xD1CFF191), unchecked((int) 0xB3A8C1AD), + unchecked((int) 0x2F2F2218), unchecked((int) 0xBE0E1777), unchecked((int) 0xEA752DFE), unchecked((int) 0x8B021FA1), + unchecked((int) 0xE5A0CC0F), unchecked((int) 0xB56F74E8), unchecked((int) 0x18ACF3D6), unchecked((int) 0xCE89E299), + unchecked((int) 0xB4A84FE0), unchecked((int) 0xFD13E0B7), unchecked((int) 0x7CC43B81), unchecked((int) 0xD2ADA8D9), + unchecked((int) 0x165FA266), unchecked((int) 0x80957705), unchecked((int) 0x93CC7314), unchecked((int) 0x211A1477), + unchecked((int) 0xE6AD2065), unchecked((int) 0x77B5FA86), unchecked((int) 0xC75442F5), unchecked((int) 0xFB9D35CF), + unchecked((int) 0xEBCDAF0C), unchecked((int) 0x7B3E89A0), unchecked((int) 0xD6411BD3), unchecked((int) 0xAE1E7E49), + unchecked((int) 0x00250E2D), unchecked((int) 0x2071B35E), unchecked((int) 0x226800BB), unchecked((int) 0x57B8E0AF), + unchecked((int) 0x2464369B), unchecked((int) 0xF009B91E), unchecked((int) 0x5563911D), unchecked((int) 0x59DFA6AA), + unchecked((int) 0x78C14389), unchecked((int) 0xD95A537F), unchecked((int) 0x207D5BA2), unchecked((int) 0x02E5B9C5), + unchecked((int) 0x83260376), unchecked((int) 0x6295CFA9), unchecked((int) 0x11C81968), unchecked((int) 0x4E734A41), + unchecked((int) 0xB3472DCA), unchecked((int) 0x7B14A94A), unchecked((int) 0x1B510052), unchecked((int) 0x9A532915), + unchecked((int) 0xD60F573F), unchecked((int) 0xBC9BC6E4), unchecked((int) 0x2B60A476), unchecked((int) 0x81E67400), + unchecked((int) 0x08BA6FB5), unchecked((int) 0x571BE91F), unchecked((int) 0xF296EC6B), unchecked((int) 0x2A0DD915), + unchecked((int) 0xB6636521), unchecked((int) 0xE7B9F9B6), unchecked((int) 0xFF34052E), unchecked((int) 0xC5855664), + unchecked((int) 0x53B02D5D), unchecked((int) 0xA99F8FA1), unchecked((int) 0x08BA4799), unchecked((int) 0x6E85076A) + }, + + KS1 = { + unchecked((int) 0x4B7A70E9), unchecked((int) 0xB5B32944), unchecked((int) 0xDB75092E), unchecked((int) 0xC4192623), + unchecked((int) 0xAD6EA6B0), unchecked((int) 0x49A7DF7D), unchecked((int) 0x9CEE60B8), unchecked((int) 0x8FEDB266), + unchecked((int) 0xECAA8C71), unchecked((int) 0x699A17FF), unchecked((int) 0x5664526C), unchecked((int) 0xC2B19EE1), + unchecked((int) 0x193602A5), unchecked((int) 0x75094C29), unchecked((int) 0xA0591340), unchecked((int) 0xE4183A3E), + unchecked((int) 0x3F54989A), unchecked((int) 0x5B429D65), unchecked((int) 0x6B8FE4D6), unchecked((int) 0x99F73FD6), + unchecked((int) 0xA1D29C07), unchecked((int) 0xEFE830F5), unchecked((int) 0x4D2D38E6), unchecked((int) 0xF0255DC1), + unchecked((int) 0x4CDD2086), unchecked((int) 0x8470EB26), unchecked((int) 0x6382E9C6), unchecked((int) 0x021ECC5E), + unchecked((int) 0x09686B3F), unchecked((int) 0x3EBAEFC9), unchecked((int) 0x3C971814), unchecked((int) 0x6B6A70A1), + unchecked((int) 0x687F3584), unchecked((int) 0x52A0E286), unchecked((int) 0xB79C5305), unchecked((int) 0xAA500737), + unchecked((int) 0x3E07841C), unchecked((int) 0x7FDEAE5C), unchecked((int) 0x8E7D44EC), unchecked((int) 0x5716F2B8), + unchecked((int) 0xB03ADA37), unchecked((int) 0xF0500C0D), unchecked((int) 0xF01C1F04), unchecked((int) 0x0200B3FF), + unchecked((int) 0xAE0CF51A), unchecked((int) 0x3CB574B2), unchecked((int) 0x25837A58), unchecked((int) 0xDC0921BD), + unchecked((int) 0xD19113F9), unchecked((int) 0x7CA92FF6), unchecked((int) 0x94324773), unchecked((int) 0x22F54701), + unchecked((int) 0x3AE5E581), unchecked((int) 0x37C2DADC), unchecked((int) 0xC8B57634), unchecked((int) 0x9AF3DDA7), + unchecked((int) 0xA9446146), unchecked((int) 0x0FD0030E), unchecked((int) 0xECC8C73E), unchecked((int) 0xA4751E41), + unchecked((int) 0xE238CD99), unchecked((int) 0x3BEA0E2F), unchecked((int) 0x3280BBA1), unchecked((int) 0x183EB331), + unchecked((int) 0x4E548B38), unchecked((int) 0x4F6DB908), unchecked((int) 0x6F420D03), unchecked((int) 0xF60A04BF), + unchecked((int) 0x2CB81290), unchecked((int) 0x24977C79), unchecked((int) 0x5679B072), unchecked((int) 0xBCAF89AF), + unchecked((int) 0xDE9A771F), unchecked((int) 0xD9930810), unchecked((int) 0xB38BAE12), unchecked((int) 0xDCCF3F2E), + unchecked((int) 0x5512721F), unchecked((int) 0x2E6B7124), unchecked((int) 0x501ADDE6), unchecked((int) 0x9F84CD87), + unchecked((int) 0x7A584718), unchecked((int) 0x7408DA17), unchecked((int) 0xBC9F9ABC), unchecked((int) 0xE94B7D8C), + unchecked((int) 0xEC7AEC3A), unchecked((int) 0xDB851DFA), unchecked((int) 0x63094366), unchecked((int) 0xC464C3D2), + unchecked((int) 0xEF1C1847), unchecked((int) 0x3215D908), unchecked((int) 0xDD433B37), unchecked((int) 0x24C2BA16), + unchecked((int) 0x12A14D43), unchecked((int) 0x2A65C451), unchecked((int) 0x50940002), unchecked((int) 0x133AE4DD), + unchecked((int) 0x71DFF89E), unchecked((int) 0x10314E55), unchecked((int) 0x81AC77D6), unchecked((int) 0x5F11199B), + unchecked((int) 0x043556F1), unchecked((int) 0xD7A3C76B), unchecked((int) 0x3C11183B), unchecked((int) 0x5924A509), + unchecked((int) 0xF28FE6ED), unchecked((int) 0x97F1FBFA), unchecked((int) 0x9EBABF2C), unchecked((int) 0x1E153C6E), + unchecked((int) 0x86E34570), unchecked((int) 0xEAE96FB1), unchecked((int) 0x860E5E0A), unchecked((int) 0x5A3E2AB3), + unchecked((int) 0x771FE71C), unchecked((int) 0x4E3D06FA), unchecked((int) 0x2965DCB9), unchecked((int) 0x99E71D0F), + unchecked((int) 0x803E89D6), unchecked((int) 0x5266C825), unchecked((int) 0x2E4CC978), unchecked((int) 0x9C10B36A), + unchecked((int) 0xC6150EBA), unchecked((int) 0x94E2EA78), unchecked((int) 0xA5FC3C53), unchecked((int) 0x1E0A2DF4), + unchecked((int) 0xF2F74EA7), unchecked((int) 0x361D2B3D), unchecked((int) 0x1939260F), unchecked((int) 0x19C27960), + unchecked((int) 0x5223A708), unchecked((int) 0xF71312B6), unchecked((int) 0xEBADFE6E), unchecked((int) 0xEAC31F66), + unchecked((int) 0xE3BC4595), unchecked((int) 0xA67BC883), unchecked((int) 0xB17F37D1), unchecked((int) 0x018CFF28), + unchecked((int) 0xC332DDEF), unchecked((int) 0xBE6C5AA5), unchecked((int) 0x65582185), unchecked((int) 0x68AB9802), + unchecked((int) 0xEECEA50F), unchecked((int) 0xDB2F953B), unchecked((int) 0x2AEF7DAD), unchecked((int) 0x5B6E2F84), + unchecked((int) 0x1521B628), unchecked((int) 0x29076170), unchecked((int) 0xECDD4775), unchecked((int) 0x619F1510), + unchecked((int) 0x13CCA830), unchecked((int) 0xEB61BD96), unchecked((int) 0x0334FE1E), unchecked((int) 0xAA0363CF), + unchecked((int) 0xB5735C90), unchecked((int) 0x4C70A239), unchecked((int) 0xD59E9E0B), unchecked((int) 0xCBAADE14), + unchecked((int) 0xEECC86BC), unchecked((int) 0x60622CA7), unchecked((int) 0x9CAB5CAB), unchecked((int) 0xB2F3846E), + unchecked((int) 0x648B1EAF), unchecked((int) 0x19BDF0CA), unchecked((int) 0xA02369B9), unchecked((int) 0x655ABB50), + unchecked((int) 0x40685A32), unchecked((int) 0x3C2AB4B3), unchecked((int) 0x319EE9D5), unchecked((int) 0xC021B8F7), + unchecked((int) 0x9B540B19), unchecked((int) 0x875FA099), unchecked((int) 0x95F7997E), unchecked((int) 0x623D7DA8), + unchecked((int) 0xF837889A), unchecked((int) 0x97E32D77), unchecked((int) 0x11ED935F), unchecked((int) 0x16681281), + unchecked((int) 0x0E358829), unchecked((int) 0xC7E61FD6), unchecked((int) 0x96DEDFA1), unchecked((int) 0x7858BA99), + unchecked((int) 0x57F584A5), unchecked((int) 0x1B227263), unchecked((int) 0x9B83C3FF), unchecked((int) 0x1AC24696), + unchecked((int) 0xCDB30AEB), unchecked((int) 0x532E3054), unchecked((int) 0x8FD948E4), unchecked((int) 0x6DBC3128), + unchecked((int) 0x58EBF2EF), unchecked((int) 0x34C6FFEA), unchecked((int) 0xFE28ED61), unchecked((int) 0xEE7C3C73), + unchecked((int) 0x5D4A14D9), unchecked((int) 0xE864B7E3), unchecked((int) 0x42105D14), unchecked((int) 0x203E13E0), + unchecked((int) 0x45EEE2B6), unchecked((int) 0xA3AAABEA), unchecked((int) 0xDB6C4F15), unchecked((int) 0xFACB4FD0), + unchecked((int) 0xC742F442), unchecked((int) 0xEF6ABBB5), unchecked((int) 0x654F3B1D), unchecked((int) 0x41CD2105), + unchecked((int) 0xD81E799E), unchecked((int) 0x86854DC7), unchecked((int) 0xE44B476A), unchecked((int) 0x3D816250), + unchecked((int) 0xCF62A1F2), unchecked((int) 0x5B8D2646), unchecked((int) 0xFC8883A0), unchecked((int) 0xC1C7B6A3), + unchecked((int) 0x7F1524C3), unchecked((int) 0x69CB7492), unchecked((int) 0x47848A0B), unchecked((int) 0x5692B285), + unchecked((int) 0x095BBF00), unchecked((int) 0xAD19489D), unchecked((int) 0x1462B174), unchecked((int) 0x23820E00), + unchecked((int) 0x58428D2A), unchecked((int) 0x0C55F5EA), unchecked((int) 0x1DADF43E), unchecked((int) 0x233F7061), + unchecked((int) 0x3372F092), unchecked((int) 0x8D937E41), unchecked((int) 0xD65FECF1), unchecked((int) 0x6C223BDB), + unchecked((int) 0x7CDE3759), unchecked((int) 0xCBEE7460), unchecked((int) 0x4085F2A7), unchecked((int) 0xCE77326E), + unchecked((int) 0xA6078084), unchecked((int) 0x19F8509E), unchecked((int) 0xE8EFD855), unchecked((int) 0x61D99735), + unchecked((int) 0xA969A7AA), unchecked((int) 0xC50C06C2), unchecked((int) 0x5A04ABFC), unchecked((int) 0x800BCADC), + unchecked((int) 0x9E447A2E), unchecked((int) 0xC3453484), unchecked((int) 0xFDD56705), unchecked((int) 0x0E1E9EC9), + unchecked((int) 0xDB73DBD3), unchecked((int) 0x105588CD), unchecked((int) 0x675FDA79), unchecked((int) 0xE3674340), + unchecked((int) 0xC5C43465), unchecked((int) 0x713E38D8), unchecked((int) 0x3D28F89E), unchecked((int) 0xF16DFF20), + unchecked((int) 0x153E21E7), unchecked((int) 0x8FB03D4A), unchecked((int) 0xE6E39F2B), unchecked((int) 0xDB83ADF7) + }, + + KS2 = { + unchecked((int) 0xE93D5A68), unchecked((int) 0x948140F7), unchecked((int) 0xF64C261C), unchecked((int) 0x94692934), + unchecked((int) 0x411520F7), unchecked((int) 0x7602D4F7), unchecked((int) 0xBCF46B2E), unchecked((int) 0xD4A20068), + unchecked((int) 0xD4082471), unchecked((int) 0x3320F46A), unchecked((int) 0x43B7D4B7), unchecked((int) 0x500061AF), + unchecked((int) 0x1E39F62E), unchecked((int) 0x97244546), unchecked((int) 0x14214F74), unchecked((int) 0xBF8B8840), + unchecked((int) 0x4D95FC1D), unchecked((int) 0x96B591AF), unchecked((int) 0x70F4DDD3), unchecked((int) 0x66A02F45), + unchecked((int) 0xBFBC09EC), unchecked((int) 0x03BD9785), unchecked((int) 0x7FAC6DD0), unchecked((int) 0x31CB8504), + unchecked((int) 0x96EB27B3), unchecked((int) 0x55FD3941), unchecked((int) 0xDA2547E6), unchecked((int) 0xABCA0A9A), + unchecked((int) 0x28507825), unchecked((int) 0x530429F4), unchecked((int) 0x0A2C86DA), unchecked((int) 0xE9B66DFB), + unchecked((int) 0x68DC1462), unchecked((int) 0xD7486900), unchecked((int) 0x680EC0A4), unchecked((int) 0x27A18DEE), + unchecked((int) 0x4F3FFEA2), unchecked((int) 0xE887AD8C), unchecked((int) 0xB58CE006), unchecked((int) 0x7AF4D6B6), + unchecked((int) 0xAACE1E7C), unchecked((int) 0xD3375FEC), unchecked((int) 0xCE78A399), unchecked((int) 0x406B2A42), + unchecked((int) 0x20FE9E35), unchecked((int) 0xD9F385B9), unchecked((int) 0xEE39D7AB), unchecked((int) 0x3B124E8B), + unchecked((int) 0x1DC9FAF7), unchecked((int) 0x4B6D1856), unchecked((int) 0x26A36631), unchecked((int) 0xEAE397B2), + unchecked((int) 0x3A6EFA74), unchecked((int) 0xDD5B4332), unchecked((int) 0x6841E7F7), unchecked((int) 0xCA7820FB), + unchecked((int) 0xFB0AF54E), unchecked((int) 0xD8FEB397), unchecked((int) 0x454056AC), unchecked((int) 0xBA489527), + unchecked((int) 0x55533A3A), unchecked((int) 0x20838D87), unchecked((int) 0xFE6BA9B7), unchecked((int) 0xD096954B), + unchecked((int) 0x55A867BC), unchecked((int) 0xA1159A58), unchecked((int) 0xCCA92963), unchecked((int) 0x99E1DB33), + unchecked((int) 0xA62A4A56), unchecked((int) 0x3F3125F9), unchecked((int) 0x5EF47E1C), unchecked((int) 0x9029317C), + unchecked((int) 0xFDF8E802), unchecked((int) 0x04272F70), unchecked((int) 0x80BB155C), unchecked((int) 0x05282CE3), + unchecked((int) 0x95C11548), unchecked((int) 0xE4C66D22), unchecked((int) 0x48C1133F), unchecked((int) 0xC70F86DC), + unchecked((int) 0x07F9C9EE), unchecked((int) 0x41041F0F), unchecked((int) 0x404779A4), unchecked((int) 0x5D886E17), + unchecked((int) 0x325F51EB), unchecked((int) 0xD59BC0D1), unchecked((int) 0xF2BCC18F), unchecked((int) 0x41113564), + unchecked((int) 0x257B7834), unchecked((int) 0x602A9C60), unchecked((int) 0xDFF8E8A3), unchecked((int) 0x1F636C1B), + unchecked((int) 0x0E12B4C2), unchecked((int) 0x02E1329E), unchecked((int) 0xAF664FD1), unchecked((int) 0xCAD18115), + unchecked((int) 0x6B2395E0), unchecked((int) 0x333E92E1), unchecked((int) 0x3B240B62), unchecked((int) 0xEEBEB922), + unchecked((int) 0x85B2A20E), unchecked((int) 0xE6BA0D99), unchecked((int) 0xDE720C8C), unchecked((int) 0x2DA2F728), + unchecked((int) 0xD0127845), unchecked((int) 0x95B794FD), unchecked((int) 0x647D0862), unchecked((int) 0xE7CCF5F0), + unchecked((int) 0x5449A36F), unchecked((int) 0x877D48FA), unchecked((int) 0xC39DFD27), unchecked((int) 0xF33E8D1E), + unchecked((int) 0x0A476341), unchecked((int) 0x992EFF74), unchecked((int) 0x3A6F6EAB), unchecked((int) 0xF4F8FD37), + unchecked((int) 0xA812DC60), unchecked((int) 0xA1EBDDF8), unchecked((int) 0x991BE14C), unchecked((int) 0xDB6E6B0D), + unchecked((int) 0xC67B5510), unchecked((int) 0x6D672C37), unchecked((int) 0x2765D43B), unchecked((int) 0xDCD0E804), + unchecked((int) 0xF1290DC7), unchecked((int) 0xCC00FFA3), unchecked((int) 0xB5390F92), unchecked((int) 0x690FED0B), + unchecked((int) 0x667B9FFB), unchecked((int) 0xCEDB7D9C), unchecked((int) 0xA091CF0B), unchecked((int) 0xD9155EA3), + unchecked((int) 0xBB132F88), unchecked((int) 0x515BAD24), unchecked((int) 0x7B9479BF), unchecked((int) 0x763BD6EB), + unchecked((int) 0x37392EB3), unchecked((int) 0xCC115979), unchecked((int) 0x8026E297), unchecked((int) 0xF42E312D), + unchecked((int) 0x6842ADA7), unchecked((int) 0xC66A2B3B), unchecked((int) 0x12754CCC), unchecked((int) 0x782EF11C), + unchecked((int) 0x6A124237), unchecked((int) 0xB79251E7), unchecked((int) 0x06A1BBE6), unchecked((int) 0x4BFB6350), + unchecked((int) 0x1A6B1018), unchecked((int) 0x11CAEDFA), unchecked((int) 0x3D25BDD8), unchecked((int) 0xE2E1C3C9), + unchecked((int) 0x44421659), unchecked((int) 0x0A121386), unchecked((int) 0xD90CEC6E), unchecked((int) 0xD5ABEA2A), + unchecked((int) 0x64AF674E), unchecked((int) 0xDA86A85F), unchecked((int) 0xBEBFE988), unchecked((int) 0x64E4C3FE), + unchecked((int) 0x9DBC8057), unchecked((int) 0xF0F7C086), unchecked((int) 0x60787BF8), unchecked((int) 0x6003604D), + unchecked((int) 0xD1FD8346), unchecked((int) 0xF6381FB0), unchecked((int) 0x7745AE04), unchecked((int) 0xD736FCCC), + unchecked((int) 0x83426B33), unchecked((int) 0xF01EAB71), unchecked((int) 0xB0804187), unchecked((int) 0x3C005E5F), + unchecked((int) 0x77A057BE), unchecked((int) 0xBDE8AE24), unchecked((int) 0x55464299), unchecked((int) 0xBF582E61), + unchecked((int) 0x4E58F48F), unchecked((int) 0xF2DDFDA2), unchecked((int) 0xF474EF38), unchecked((int) 0x8789BDC2), + unchecked((int) 0x5366F9C3), unchecked((int) 0xC8B38E74), unchecked((int) 0xB475F255), unchecked((int) 0x46FCD9B9), + unchecked((int) 0x7AEB2661), unchecked((int) 0x8B1DDF84), unchecked((int) 0x846A0E79), unchecked((int) 0x915F95E2), + unchecked((int) 0x466E598E), unchecked((int) 0x20B45770), unchecked((int) 0x8CD55591), unchecked((int) 0xC902DE4C), + unchecked((int) 0xB90BACE1), unchecked((int) 0xBB8205D0), unchecked((int) 0x11A86248), unchecked((int) 0x7574A99E), + unchecked((int) 0xB77F19B6), unchecked((int) 0xE0A9DC09), unchecked((int) 0x662D09A1), unchecked((int) 0xC4324633), + unchecked((int) 0xE85A1F02), unchecked((int) 0x09F0BE8C), unchecked((int) 0x4A99A025), unchecked((int) 0x1D6EFE10), + unchecked((int) 0x1AB93D1D), unchecked((int) 0x0BA5A4DF), unchecked((int) 0xA186F20F), unchecked((int) 0x2868F169), + unchecked((int) 0xDCB7DA83), unchecked((int) 0x573906FE), unchecked((int) 0xA1E2CE9B), unchecked((int) 0x4FCD7F52), + unchecked((int) 0x50115E01), unchecked((int) 0xA70683FA), unchecked((int) 0xA002B5C4), unchecked((int) 0x0DE6D027), + unchecked((int) 0x9AF88C27), unchecked((int) 0x773F8641), unchecked((int) 0xC3604C06), unchecked((int) 0x61A806B5), + unchecked((int) 0xF0177A28), unchecked((int) 0xC0F586E0), unchecked((int) 0x006058AA), unchecked((int) 0x30DC7D62), + unchecked((int) 0x11E69ED7), unchecked((int) 0x2338EA63), unchecked((int) 0x53C2DD94), unchecked((int) 0xC2C21634), + unchecked((int) 0xBBCBEE56), unchecked((int) 0x90BCB6DE), unchecked((int) 0xEBFC7DA1), unchecked((int) 0xCE591D76), + unchecked((int) 0x6F05E409), unchecked((int) 0x4B7C0188), unchecked((int) 0x39720A3D), unchecked((int) 0x7C927C24), + unchecked((int) 0x86E3725F), unchecked((int) 0x724D9DB9), unchecked((int) 0x1AC15BB4), unchecked((int) 0xD39EB8FC), + unchecked((int) 0xED545578), unchecked((int) 0x08FCA5B5), unchecked((int) 0xD83D7CD3), unchecked((int) 0x4DAD0FC4), + unchecked((int) 0x1E50EF5E), unchecked((int) 0xB161E6F8), unchecked((int) 0xA28514D9), unchecked((int) 0x6C51133C), + unchecked((int) 0x6FD5C7E7), unchecked((int) 0x56E14EC4), unchecked((int) 0x362ABFCE), unchecked((int) 0xDDC6C837), + unchecked((int) 0xD79A3234), unchecked((int) 0x92638212), unchecked((int) 0x670EFA8E), unchecked((int) 0x406000E0) + }, + + KS3 = { + unchecked((int) 0x3A39CE37), unchecked((int) 0xD3FAF5CF), unchecked((int) 0xABC27737), unchecked((int) 0x5AC52D1B), + unchecked((int) 0x5CB0679E), unchecked((int) 0x4FA33742), unchecked((int) 0xD3822740), unchecked((int) 0x99BC9BBE), + unchecked((int) 0xD5118E9D), unchecked((int) 0xBF0F7315), unchecked((int) 0xD62D1C7E), unchecked((int) 0xC700C47B), + unchecked((int) 0xB78C1B6B), unchecked((int) 0x21A19045), unchecked((int) 0xB26EB1BE), unchecked((int) 0x6A366EB4), + unchecked((int) 0x5748AB2F), unchecked((int) 0xBC946E79), unchecked((int) 0xC6A376D2), unchecked((int) 0x6549C2C8), + unchecked((int) 0x530FF8EE), unchecked((int) 0x468DDE7D), unchecked((int) 0xD5730A1D), unchecked((int) 0x4CD04DC6), + unchecked((int) 0x2939BBDB), unchecked((int) 0xA9BA4650), unchecked((int) 0xAC9526E8), unchecked((int) 0xBE5EE304), + unchecked((int) 0xA1FAD5F0), unchecked((int) 0x6A2D519A), unchecked((int) 0x63EF8CE2), unchecked((int) 0x9A86EE22), + unchecked((int) 0xC089C2B8), unchecked((int) 0x43242EF6), unchecked((int) 0xA51E03AA), unchecked((int) 0x9CF2D0A4), + unchecked((int) 0x83C061BA), unchecked((int) 0x9BE96A4D), unchecked((int) 0x8FE51550), unchecked((int) 0xBA645BD6), + unchecked((int) 0x2826A2F9), unchecked((int) 0xA73A3AE1), unchecked((int) 0x4BA99586), unchecked((int) 0xEF5562E9), + unchecked((int) 0xC72FEFD3), unchecked((int) 0xF752F7DA), unchecked((int) 0x3F046F69), unchecked((int) 0x77FA0A59), + unchecked((int) 0x80E4A915), unchecked((int) 0x87B08601), unchecked((int) 0x9B09E6AD), unchecked((int) 0x3B3EE593), + unchecked((int) 0xE990FD5A), unchecked((int) 0x9E34D797), unchecked((int) 0x2CF0B7D9), unchecked((int) 0x022B8B51), + unchecked((int) 0x96D5AC3A), unchecked((int) 0x017DA67D), unchecked((int) 0xD1CF3ED6), unchecked((int) 0x7C7D2D28), + unchecked((int) 0x1F9F25CF), unchecked((int) 0xADF2B89B), unchecked((int) 0x5AD6B472), unchecked((int) 0x5A88F54C), + unchecked((int) 0xE029AC71), unchecked((int) 0xE019A5E6), unchecked((int) 0x47B0ACFD), unchecked((int) 0xED93FA9B), + unchecked((int) 0xE8D3C48D), unchecked((int) 0x283B57CC), unchecked((int) 0xF8D56629), unchecked((int) 0x79132E28), + unchecked((int) 0x785F0191), unchecked((int) 0xED756055), unchecked((int) 0xF7960E44), unchecked((int) 0xE3D35E8C), + unchecked((int) 0x15056DD4), unchecked((int) 0x88F46DBA), unchecked((int) 0x03A16125), unchecked((int) 0x0564F0BD), + unchecked((int) 0xC3EB9E15), unchecked((int) 0x3C9057A2), unchecked((int) 0x97271AEC), unchecked((int) 0xA93A072A), + unchecked((int) 0x1B3F6D9B), unchecked((int) 0x1E6321F5), unchecked((int) 0xF59C66FB), unchecked((int) 0x26DCF319), + unchecked((int) 0x7533D928), unchecked((int) 0xB155FDF5), unchecked((int) 0x03563482), unchecked((int) 0x8ABA3CBB), + unchecked((int) 0x28517711), unchecked((int) 0xC20AD9F8), unchecked((int) 0xABCC5167), unchecked((int) 0xCCAD925F), + unchecked((int) 0x4DE81751), unchecked((int) 0x3830DC8E), unchecked((int) 0x379D5862), unchecked((int) 0x9320F991), + unchecked((int) 0xEA7A90C2), unchecked((int) 0xFB3E7BCE), unchecked((int) 0x5121CE64), unchecked((int) 0x774FBE32), + unchecked((int) 0xA8B6E37E), unchecked((int) 0xC3293D46), unchecked((int) 0x48DE5369), unchecked((int) 0x6413E680), + unchecked((int) 0xA2AE0810), unchecked((int) 0xDD6DB224), unchecked((int) 0x69852DFD), unchecked((int) 0x09072166), + unchecked((int) 0xB39A460A), unchecked((int) 0x6445C0DD), unchecked((int) 0x586CDECF), unchecked((int) 0x1C20C8AE), + unchecked((int) 0x5BBEF7DD), unchecked((int) 0x1B588D40), unchecked((int) 0xCCD2017F), unchecked((int) 0x6BB4E3BB), + unchecked((int) 0xDDA26A7E), unchecked((int) 0x3A59FF45), unchecked((int) 0x3E350A44), unchecked((int) 0xBCB4CDD5), + unchecked((int) 0x72EACEA8), unchecked((int) 0xFA6484BB), unchecked((int) 0x8D6612AE), unchecked((int) 0xBF3C6F47), + unchecked((int) 0xD29BE463), unchecked((int) 0x542F5D9E), unchecked((int) 0xAEC2771B), unchecked((int) 0xF64E6370), + unchecked((int) 0x740E0D8D), unchecked((int) 0xE75B1357), unchecked((int) 0xF8721671), unchecked((int) 0xAF537D5D), + unchecked((int) 0x4040CB08), unchecked((int) 0x4EB4E2CC), unchecked((int) 0x34D2466A), unchecked((int) 0x0115AF84), + unchecked((int) 0xE1B00428), unchecked((int) 0x95983A1D), unchecked((int) 0x06B89FB4), unchecked((int) 0xCE6EA048), + unchecked((int) 0x6F3F3B82), unchecked((int) 0x3520AB82), unchecked((int) 0x011A1D4B), unchecked((int) 0x277227F8), + unchecked((int) 0x611560B1), unchecked((int) 0xE7933FDC), unchecked((int) 0xBB3A792B), unchecked((int) 0x344525BD), + unchecked((int) 0xA08839E1), unchecked((int) 0x51CE794B), unchecked((int) 0x2F32C9B7), unchecked((int) 0xA01FBAC9), + unchecked((int) 0xE01CC87E), unchecked((int) 0xBCC7D1F6), unchecked((int) 0xCF0111C3), unchecked((int) 0xA1E8AAC7), + unchecked((int) 0x1A908749), unchecked((int) 0xD44FBD9A), unchecked((int) 0xD0DADECB), unchecked((int) 0xD50ADA38), + unchecked((int) 0x0339C32A), unchecked((int) 0xC6913667), unchecked((int) 0x8DF9317C), unchecked((int) 0xE0B12B4F), + unchecked((int) 0xF79E59B7), unchecked((int) 0x43F5BB3A), unchecked((int) 0xF2D519FF), unchecked((int) 0x27D9459C), + unchecked((int) 0xBF97222C), unchecked((int) 0x15E6FC2A), unchecked((int) 0x0F91FC71), unchecked((int) 0x9B941525), + unchecked((int) 0xFAE59361), unchecked((int) 0xCEB69CEB), unchecked((int) 0xC2A86459), unchecked((int) 0x12BAA8D1), + unchecked((int) 0xB6C1075E), unchecked((int) 0xE3056A0C), unchecked((int) 0x10D25065), unchecked((int) 0xCB03A442), + unchecked((int) 0xE0EC6E0E), unchecked((int) 0x1698DB3B), unchecked((int) 0x4C98A0BE), unchecked((int) 0x3278E964), + unchecked((int) 0x9F1F9532), unchecked((int) 0xE0D392DF), unchecked((int) 0xD3A0342B), unchecked((int) 0x8971F21E), + unchecked((int) 0x1B0A7441), unchecked((int) 0x4BA3348C), unchecked((int) 0xC5BE7120), unchecked((int) 0xC37632D8), + unchecked((int) 0xDF359F8D), unchecked((int) 0x9B992F2E), unchecked((int) 0xE60B6F47), unchecked((int) 0x0FE3F11D), + unchecked((int) 0xE54CDA54), unchecked((int) 0x1EDAD891), unchecked((int) 0xCE6279CF), unchecked((int) 0xCD3E7E6F), + unchecked((int) 0x1618B166), unchecked((int) 0xFD2C1D05), unchecked((int) 0x848FD2C5), unchecked((int) 0xF6FB2299), + unchecked((int) 0xF523F357), unchecked((int) 0xA6327623), unchecked((int) 0x93A83531), unchecked((int) 0x56CCCD02), + unchecked((int) 0xACF08162), unchecked((int) 0x5A75EBB5), unchecked((int) 0x6E163697), unchecked((int) 0x88D273CC), + unchecked((int) 0xDE966292), unchecked((int) 0x81B949D0), unchecked((int) 0x4C50901B), unchecked((int) 0x71C65614), + unchecked((int) 0xE6C6C7BD), unchecked((int) 0x327A140A), unchecked((int) 0x45E1D006), unchecked((int) 0xC3F27B9A), + unchecked((int) 0xC9AA53FD), unchecked((int) 0x62A80F00), unchecked((int) 0xBB25BFE2), unchecked((int) 0x35BDD2F6), + unchecked((int) 0x71126905), unchecked((int) 0xB2040222), unchecked((int) 0xB6CBCF7C), unchecked((int) 0xCD769C2B), + unchecked((int) 0x53113EC0), unchecked((int) 0x1640E3D3), unchecked((int) 0x38ABBD60), unchecked((int) 0x2547ADF0), + unchecked((int) 0xBA38209C), unchecked((int) 0xF746CE76), unchecked((int) 0x77AFA1C5), unchecked((int) 0x20756060), + unchecked((int) 0x85CBFE4E), unchecked((int) 0x8AE88DD8), unchecked((int) 0x7AAAF9B0), unchecked((int) 0x4CF9AA7E), + unchecked((int) 0x1948C25C), unchecked((int) 0x02FB8A8C), unchecked((int) 0x01C36AE4), unchecked((int) 0xD6EBE1F9), + unchecked((int) 0x90D4F869), unchecked((int) 0xA65CDEA0), unchecked((int) 0x3F09252D), unchecked((int) 0xC208E69F), + unchecked((int) 0xB74E6132), unchecked((int) 0xCE77E25B), unchecked((int) 0x578FDFE3), unchecked((int) 0x3AC372E6) + }; + + //==================================== + // Useful constants + //==================================== + + private static readonly int ROUNDS = 16; + private const int BLOCK_SIZE = 8; // bytes = 64 bits + private static readonly int SBOX_SK = 256; + private static readonly int P_SZ = ROUNDS+2; + + private readonly int[] S0, S1, S2, S3; // the s-boxes + private readonly int[] P; // the p-array + + private bool encrypting; + + private byte[] workingKey; + + public BlowfishEngine() + { + S0 = new int[SBOX_SK]; + S1 = new int[SBOX_SK]; + S2 = new int[SBOX_SK]; + S3 = new int[SBOX_SK]; + P = new int[P_SZ]; + } + + /** + * initialise a Blowfish cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to Blowfish init - " + parameters.GetType().ToString()); + + this.encrypting = forEncryption; + this.workingKey = ((KeyParameter)parameters).GetKey(); + SetKey(this.workingKey); + } + + public string AlgorithmName + { + get { return "Blowfish"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + { + throw new InvalidOperationException("Blowfish not initialised"); + } + + if ((inOff + BLOCK_SIZE) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BLOCK_SIZE) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (encrypting) + { + EncryptBlock(input, inOff, output, outOff); + } + else + { + DecryptBlock(input, inOff, output, outOff); + } + + return BLOCK_SIZE; + } + + public void Reset() + { + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + + private int F(int x) + { + return (( (S0[((uint) x >> 24)] + S1[((uint) x >> 16) & 0xff]) + ^ S2[((uint) x >> 8) & 0xff]) + S3[x & 0xff]); + } + + /** + * apply the encryption cycle to each value pair in the table. + */ + private void ProcessTable( + int xl, + int xr, + int[] table) + { + int size = table.Length; + + for (int s = 0; s < size; s += 2) + { + xl ^= P[0]; + + for (int i = 1; i < ROUNDS; i += 2) + { + xr ^= F(xl) ^ P[i]; + xl ^= F(xr) ^ P[i + 1]; + } + + xr ^= P[ROUNDS + 1]; + + table[s] = xr; + table[s + 1] = xl; + + xr = xl; // end of cycle swap + xl = table[s]; + } + } + + private void SetKey(byte[] key) + { + /* + * - comments are from _Applied Crypto_, Schneier, p338 + * please be careful comparing the two, AC numbers the + * arrays from 1, the enclosed code from 0. + * + * (1) + * Initialise the S-boxes and the P-array, with a fixed string + * This string contains the hexadecimal digits of pi (3.141...) + */ + Array.Copy(KS0, 0, S0, 0, SBOX_SK); + Array.Copy(KS1, 0, S1, 0, SBOX_SK); + Array.Copy(KS2, 0, S2, 0, SBOX_SK); + Array.Copy(KS3, 0, S3, 0, SBOX_SK); + + Array.Copy(KP, 0, P, 0, P_SZ); + + /* + * (2) + * Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the + * second 32-bits of the key, and so on for all bits of the key + * (up to P[17]). Repeatedly cycle through the key bits until the + * entire P-array has been XOR-ed with the key bits + */ + int keyLength = key.Length; + int keyIndex = 0; + + for (int i=0; i < P_SZ; i++) + { + // Get the 32 bits of the key, in 4 * 8 bit chunks + int data = unchecked((int) 0x0000000); + for (int j=0; j < 4; j++) + { + // create a 32 bit block + data = (data << 8) | (key[keyIndex++] & 0xff); + + // wrap when we Get to the end of the key + if (keyIndex >= keyLength) + { + keyIndex = 0; + } + } + // XOR the newly created 32 bit chunk onto the P-array + P[i] ^= data; + } + + /* + * (3) + * Encrypt the all-zero string with the Blowfish algorithm, using + * the subkeys described in (1) and (2) + * + * (4) + * Replace P1 and P2 with the output of step (3) + * + * (5) + * Encrypt the output of step(3) using the Blowfish algorithm, + * with the modified subkeys. + * + * (6) + * Replace P3 and P4 with the output of step (5) + * + * (7) + * Continue the process, replacing all elements of the P-array + * and then all four S-boxes in order, with the output of the + * continuously changing Blowfish algorithm + */ + + ProcessTable(0, 0, P); + ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S0); + ProcessTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1); + ProcessTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2); + ProcessTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3); + } + + /** + * Encrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * The input will be an exact multiple of our blocksize. + */ + private void EncryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int xl = BytesTo32bits(src, srcIndex); + int xr = BytesTo32bits(src, srcIndex+4); + + xl ^= P[0]; + + for (int i = 1; i < ROUNDS; i += 2) + { + xr ^= F(xl) ^ P[i]; + xl ^= F(xr) ^ P[i + 1]; + } + + xr ^= P[ROUNDS + 1]; + + Bits32ToBytes(xr, dst, dstIndex); + Bits32ToBytes(xl, dst, dstIndex + 4); + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * The input will be an exact multiple of our blocksize. + */ + private void DecryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int xl = BytesTo32bits(src, srcIndex); + int xr = BytesTo32bits(src, srcIndex + 4); + + xl ^= P[ROUNDS + 1]; + + for (int i = ROUNDS; i > 0 ; i -= 2) + { + xr ^= F(xl) ^ P[i]; + xl ^= F(xr) ^ P[i - 1]; + } + + xr ^= P[0]; + + Bits32ToBytes(xr, dst, dstIndex); + Bits32ToBytes(xl, dst, dstIndex+4); + } + + private int BytesTo32bits(byte[] b, int i) + { + return ((b[i] & 0xff) << 24) | + ((b[i+1] & 0xff) << 16) | + ((b[i+2] & 0xff) << 8) | + ((b[i+3] & 0xff)); + } + + private void Bits32ToBytes(int inData, byte[] b, int offset) + { + b[offset + 3] = (byte)inData; + b[offset + 2] = (byte)(inData >> 8); + b[offset + 1] = (byte)(inData >> 16); + b[offset] = (byte)(inData >> 24); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/CamelliaEngine.cs b/iTechSharp/srcbc/crypto/engines/CamelliaEngine.cs new file mode 100644 index 0000000..15ade53 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/CamelliaEngine.cs @@ -0,0 +1,579 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Camellia - based on RFC 3713. + */ + public class CamelliaEngine + : IBlockCipher + { + private bool initialised; + private bool _keyIs128; + + private const int BLOCK_SIZE = 16; + + private const long MASK8 = 0xff; + private const long MASK32 = 0xffffffffL; + + private const long SIGMA1 = unchecked((long) 0xA09E667F3BCC908BL); + private const long SIGMA2 = unchecked((long) 0xB67AE8584CAA73B2L); + private const long SIGMA3 = unchecked((long) 0xC6EF372FE94F82BEL); + private const long SIGMA4 = unchecked((long) 0x54FF53A5F1D36F1CL); + private const long SIGMA5 = unchecked((long) 0x10E527FADE682D1DL); + private const long SIGMA6 = unchecked((long) 0xB05688C2B3E6C1FDL); + + private long _kw1, _kw2, _kw3, _kw4; + private long _k1, _k2, _k3, _k4, _k5, _k6, _k7, _k8, _k9, _k10, _k11, _k12, + _k13, _k14, _k15, _k16, _k17, _k18, _k19, _k20, _k21, _k22, _k23, _k24; + private long _ke1, _ke2, _ke3, _ke4, _ke5, _ke6; + + private readonly byte[] SBOX1 = { + (byte)112, (byte)130, (byte)44, (byte)236, (byte)179 , (byte)39, (byte)192, (byte)229, (byte)228, (byte)133 , (byte)87 , (byte)53, (byte)234 , (byte)12, (byte)174 , (byte)65, + (byte)35, (byte)239, (byte)107, (byte)147 , (byte)69 , (byte)25, (byte)165 , (byte)33, (byte)237 , (byte)14 , (byte)79 , (byte)78 , (byte)29, (byte)101, (byte)146, (byte)189, + (byte)134, (byte)184, (byte)175, (byte)143, (byte)124, (byte)235 , (byte)31, (byte)206 , (byte)62 , (byte)48, (byte)220 , (byte)95 , (byte)94, (byte)197 , (byte)11 , (byte)26, + (byte)166, (byte)225, (byte)57, (byte)202, (byte)213 , (byte)71 , (byte)93 , (byte)61, (byte)217 , (byte)1 , (byte)90, (byte)214 , (byte)81 , (byte)86, (byte)108 , (byte)77, + (byte)139, (byte)13, (byte)154, (byte)102, (byte)251, (byte)204, (byte)176 , (byte)45, (byte)116 , (byte)18 , (byte)43 , (byte)32, (byte)240, (byte)177, (byte)132, (byte)153, + (byte)223, (byte)76, (byte)203, (byte)194 , (byte)52, (byte)126, (byte)118 , (byte)5, (byte)109, (byte)183, (byte)169 , (byte)49, (byte)209 , (byte)23 , (byte)4, (byte)215, + (byte)20, (byte)88, (byte)58, (byte)97, (byte)222 , (byte)27 , (byte)17 , (byte)28 , (byte)50 , (byte)15, (byte)156 , (byte)22 , (byte)83 , (byte)24, (byte)242 , (byte)34, + (byte)254, (byte)68, (byte)207, (byte)178, (byte)195, (byte)181, (byte)122, (byte)145 , (byte)36 , (byte)8, (byte)232, (byte)168 , (byte)96, (byte)252, (byte)105 , (byte)80, + (byte)170, (byte)208, (byte)160, (byte)125, (byte)161, (byte)137 , (byte)98, (byte)151 , (byte)84 , (byte)91 , (byte)30, (byte)149, (byte)224, (byte)255, (byte)100, (byte)210, + (byte)16, (byte)196, (byte)0, (byte)72, (byte)163, (byte)247, (byte)117, (byte)219, (byte)138 , (byte)3, (byte)230, (byte)218 , (byte)9 , (byte)63, (byte)221, (byte)148, + (byte)135, (byte)92, (byte)131, (byte)2, (byte)205 , (byte)74, (byte)144 , (byte)51, (byte)115, (byte)103, (byte)246, (byte)243, (byte)157, (byte)127, (byte)191, (byte)226, + (byte)82, (byte)155, (byte)216 , (byte)38, (byte)200 , (byte)55, (byte)198 , (byte)59, (byte)129, (byte)150, (byte)111 , (byte)75 , (byte)19, (byte)190 , (byte)99 , (byte)46, + (byte)233, (byte)121, (byte)167, (byte)140, (byte)159, (byte)110, (byte)188, (byte)142 , (byte)41, (byte)245, (byte)249, (byte)182 , (byte)47, (byte)253, (byte)180 , (byte)89, + (byte)120, (byte)152, (byte)6, (byte)106, (byte)231 , (byte)70, (byte)113, (byte)186, (byte)212 , (byte)37, (byte)171 , (byte)66, (byte)136, (byte)162, (byte)141, (byte)250, + (byte)114, (byte)7, (byte)185 , (byte)85, (byte)248, (byte)238, (byte)172 , (byte)10 , (byte)54 , (byte)73 , (byte)42, (byte)104 , (byte)60 , (byte)56, (byte)241, (byte)164, + (byte)64, (byte)40, (byte)211, (byte)123, (byte)187, (byte)201 , (byte)67, (byte)193 , (byte)21, (byte)227, (byte)173, (byte)244, (byte)119, (byte)199, (byte)128, (byte)158 + }; + + private readonly byte[] SBOX2 = new byte[256]; + private readonly byte[] SBOX3 = new byte[256]; + private readonly byte[] SBOX4 = new byte[256]; + + + public CamelliaEngine() + { + for (int x = 0; x != 256; x++) + { + SBOX2[x] = lRot8(SBOX1[x], 1); + SBOX3[x] = lRot8(SBOX1[x], 7); + SBOX4[x] = SBOX1[lRot8((byte)x, 1) & 0xff]; + } + } + + private void setKey( + bool forEncryption, + byte[] key) + { + long klA, klB; + long krA, krB; + + switch (key.Length) + { + case 16: + _keyIs128 = true; + klA = bytesToWord(key, 0); + klB = bytesToWord(key, 8); + krA = 0; + krB = 0; + break; + case 24: + klA = bytesToWord(key, 0); + klB = bytesToWord(key, 8); + krA = bytesToWord(key, 16); + krB = ~bytesToWord(key, 16); + _keyIs128 = false; + break; + case 32: + klA = bytesToWord(key, 0); + klB = bytesToWord(key, 8); + krA = bytesToWord(key, 16); + krB = bytesToWord(key, 24); + _keyIs128 = false; + break; + default: + throw new ArgumentException("only a key sizes of 128/192/256 are acceptable."); + } + + long d1 = klA ^ krA; + long d2 = klB ^ krB; + + d2 = d2 ^ f(d1, SIGMA1); + d1 = d1 ^ f(d2, SIGMA2); + d1 = d1 ^ klA; + d2 = d2 ^ klB; + d2 = d2 ^ f(d1, SIGMA3); + d1 = d1 ^ f(d2, SIGMA4); + + long kaA = d1; + long kaB = d2; + + if (_keyIs128) + { + if (forEncryption) + { + _kw1 = klA; + _kw2 = klB; + _kw3 = lRot128high(kaA, kaB, 111); + _kw4 = lRot128low(kaA, kaB, 111); + _k1 = kaA; + _k2 = kaB; + _k3 = lRot128high(klA, klB, 15); + _k4 = lRot128low(klA, klB, 15); + _k5 = lRot128high(kaA, kaB, 15); + _k6 = lRot128low(kaA, kaB, 15); + _k7 = lRot128high(klA, klB, 45); + _k8 = lRot128low(klA, klB, 45); + _k9 = lRot128high(kaA, kaB, 45); + _k10 = lRot128low(klA, klB, 60); + _k11 = lRot128high(kaA, kaB, 60); + _k12 = lRot128low(kaA, kaB, 60); + _k13 = lRot128high(klA, klB, 94); + _k14 = lRot128low(klA, klB, 94); + _k15 = lRot128high(kaA, kaB, 94); + _k16 = lRot128low(kaA, kaB, 94); + _k17 = lRot128high(klA, klB, 111); + _k18 = lRot128low(klA, klB, 111); + _ke1 = lRot128high(kaA, kaB, 30); + _ke2 = lRot128low(kaA, kaB, 30); + _ke3 = lRot128high(klA, klB, 77); + _ke4 = lRot128low(klA, klB, 77); + } + else + { + _kw3 = klA; + _kw4 = klB; + _kw1 = lRot128high(kaA, kaB, 111); + _kw2 = lRot128low(kaA, kaB, 111); + _k18 = kaA; + _k17 = kaB; + _k16 = lRot128high(klA, klB, 15); + _k15 = lRot128low(klA, klB, 15); + _k14 = lRot128high(kaA, kaB, 15); + _k13 = lRot128low(kaA, kaB, 15); + _k12 = lRot128high(klA, klB, 45); + _k11 = lRot128low(klA, klB, 45); + _k10 = lRot128high(kaA, kaB, 45); + _k9 = lRot128low(klA, klB, 60); + _k8 = lRot128high(kaA, kaB, 60); + _k7 = lRot128low(kaA, kaB, 60); + _k6 = lRot128high(klA, klB, 94); + _k5 = lRot128low(klA, klB, 94); + _k4 = lRot128high(kaA, kaB, 94); + _k3 = lRot128low(kaA, kaB, 94); + _k2 = lRot128high(klA, klB, 111); + _k1 = lRot128low(klA, klB, 111); + _ke4 = lRot128high(kaA, kaB, 30); + _ke3 = lRot128low(kaA, kaB, 30); + _ke2 = lRot128high(klA, klB, 77); + _ke1 = lRot128low(klA, klB, 77); + } + } + else + { + d1 = kaA ^ krA; + d2 = kaB ^ krB; + d2 = d2 ^ f(d1, SIGMA5); + d1 = d1 ^ f(d2, SIGMA6); + + long kbA = d1; + long kbB = d2; + + if (forEncryption) + { + _kw1 = klA; + _kw2 = klB; + _k1 = kbA; + _k2 = kbB; + _k3 = lRot128high(krA, krB, 15); + _k4 = lRot128low(krA, krB, 15); + _k5 = lRot128high(kaA, kaB, 15); + _k6 = lRot128low(kaA, kaB, 15); + _ke1 = lRot128high(krA, krB, 30); + _ke2 = lRot128low(krA, krB, 30); + _k7 = lRot128high(kbA, kbB, 30); + _k8 = lRot128low(kbA, kbB, 30); + _k9 = lRot128high(klA, klB, 45); + _k10 = lRot128low(klA, klB, 45); + _k11 = lRot128high(kaA, kaB, 45); + _k12 = lRot128low(kaA, kaB, 45); + _ke3 = lRot128high(klA, klB, 60); + _ke4 = lRot128low(klA, klB, 60); + _k13 = lRot128high(krA, krB, 60); + _k14 = lRot128low(krA, krB, 60); + _k15 = lRot128high(kbA, kbB, 60); + _k16 = lRot128low(kbA, kbB, 60); + _k17 = lRot128high(klA, klB, 77); + _k18 = lRot128low(klA, klB, 77); + _ke5 = lRot128high(kaA, kaB, 77); + _ke6 = lRot128low(kaA, kaB, 77); + _k19 = lRot128high(krA, krB, 94); + _k20 = lRot128low(krA, krB, 94); + _k21 = lRot128high(kaA, kaB, 94); + _k22 = lRot128low(kaA, kaB, 94); + _k23 = lRot128high(klA, klB, 111); + _k24 = lRot128low(klA, klB, 111); + _kw3 = lRot128high(kbA, kbB, 111); + _kw4 = lRot128low(kbA, kbB, 111); + } + else + { + _kw3 = klA; + _kw4 = klB; + _kw1 = lRot128high(kbA, kbB, 111); + _kw2 = lRot128low(kbA, kbB, 111); + _k24 = kbA; + _k23 = kbB; + _k22 = lRot128high(krA, krB, 15); + _k21 = lRot128low(krA, krB, 15); + _k20 = lRot128high(kaA, kaB, 15); + _k19 = lRot128low(kaA, kaB, 15); + _k18 = lRot128high(kbA, kbB, 30); + _k17 = lRot128low(kbA, kbB, 30); + _k16 = lRot128high(klA, klB, 45); + _k15 = lRot128low(klA, klB, 45); + _k14 = lRot128high(kaA, kaB, 45); + _k13 = lRot128low(kaA, kaB, 45); + _k12 = lRot128high(krA, krB, 60); + _k11 = lRot128low(krA, krB, 60); + _k10 = lRot128high(kbA, kbB, 60); + _k9 = lRot128low(kbA, kbB, 60); + _k8 = lRot128high(klA, klB, 77); + _k7 = lRot128low(klA, klB, 77); + _k6 = lRot128high(krA, krB, 94); + _k5 = lRot128low(krA, krB, 94); + _k4 = lRot128high(kaA, kaB, 94); + _k3 = lRot128low(kaA, kaB, 94); + _k2 = lRot128high(klA, klB, 111); + _k1 = lRot128low(klA, klB, 111); + _ke6 = lRot128high(krA, krB, 30); + _ke5 = lRot128low(krA, krB, 30); + _ke4 = lRot128high(klA, klB, 60); + _ke3 = lRot128low(klA, klB, 60); + _ke2 = lRot128high(kaA, kaB, 77); + _ke1 = lRot128low(kaA, kaB, 77); + } + } + } + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("only simple KeyParameter expected."); + + setKey(forEncryption, ((KeyParameter)parameters).GetKey()); + + initialised = true; + } + + public string AlgorithmName + { + get { return "Camellia"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (!initialised) + throw new InvalidOperationException("Camellia engine not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (_keyIs128) + { + return processBlock128(input, inOff, output, outOff); + } + else + { + return processBlock192or256(input, inOff, output, outOff); + } + } + + public void Reset() + { + // nothing + } + + private byte lRot8( + byte value, + int rotation) + { +// return (byte)((value << rotation) | ((value & 0xff) >>> (8 - rotation))); + return (byte)((value << rotation) | ((value & 0xff) >> (8 - rotation))); + } + + private int lRot32( + int value, + int rotation) + { + uint uv = (uint) value; +// return (value << rotation) | (value >>> (32 - rotation)); + return (int)((uv << rotation) | (uv >> (32 - rotation))); + } + + private long lRot128high( + long a, + long b, + int rotation) + { + ulong ua = (ulong) a, ub = (ulong) b; + + if (rotation < 64) + { +// a = (a << rotation) | (b >>> (64 - rotation)); + ua = (ua << rotation) | (ub >> (64 - rotation)); + } + else if (rotation == 64) + { + ua = ub; + } + else + { +// a = (b << (rotation - 64)) | (a >>> (64 - (rotation - 64))); + ua = (ub << (rotation - 64)) | (ua >> (64 - (rotation - 64))); + } + +// return a; + return (long) ua; + } + + private long lRot128low( + long a, + long b, + int rotation) + { + ulong ua = (ulong) a, ub = (ulong) b; + + if (rotation < 64) + { +// b = (b << rotation) | (a >>> (64 - rotation)); + ub = (ub << rotation) | (ua >> (64 - rotation)); + } + else if (rotation == 64) + { + ub = ua; + } + else + { +// b = (a << (rotation - 64)) | (b >>> (64 - (rotation - 64))); + ub = (ua << (rotation - 64)) | (ub >> (64 - (rotation - 64))); + } + +// return b; + return (long) ub; + } + + private long fl( + long input, + long ke) + { + int x1 = (int)(input >> 32); + int x2 = (int)input; + int k1 = (int)(ke >> 32); + int k2 = (int)ke; + + x2 = x2 ^ lRot32((x1 & k1), 1); + x1 = x1 ^ (x2 | k2); + + return ((long)x1 << 32) | (x2 & MASK32); + } + + private long flInv( + long input, + long ke) + { + int y1 = (int)(input >> 32); + int y2 = (int)input; + int k1 = (int)(ke >> 32); + int k2 = (int)ke; + + y1 = y1 ^ (y2 | k2); + y2 = y2 ^ lRot32((y1 & k1), 1); + + return ((long)y1 << 32) | (y2 & MASK32); + } + + private long f( + long input, + long ke) + { + long x; + int a, b; + int t1, t2, t3, t4, t5, t6, t7, t8; + int y1, y2, y3, y4, y5, y6, y7, y8; + + x = input ^ ke; + + a = (int)(x >> 32); + b = (int)x; + + t1 = SBOX1[(a >> 24) & 0xff]; + t2 = SBOX2[(a >> 16) & 0xff]; + t3 = SBOX3[(a >> 8) & 0xff]; + t4 = SBOX4[a & 0xff]; + t5 = SBOX2[(b >> 24) & 0xff]; + t6 = SBOX3[(b >> 16) & 0xff]; + t7 = SBOX4[(b >> 8) & 0xff]; + t8 = SBOX1[b & 0xff]; + + y1 = (t1 ^ t3 ^ t4 ^ t6 ^ t7 ^ t8); + y2 = (t1 ^ t2 ^ t4 ^ t5 ^ t7 ^ t8); + y3 = (t1 ^ t2 ^ t3 ^ t5 ^ t6 ^ t8); + y4 = (t2 ^ t3 ^ t4 ^ t5 ^ t6 ^ t7); + y5 = (t1 ^ t2 ^ t6 ^ t7 ^ t8); + y6 = (t2 ^ t3 ^ t5 ^ t7 ^ t8); + y7 = (t3 ^ t4 ^ t5 ^ t6 ^ t8); + y8 = (t1 ^ t4 ^ t5 ^ t6 ^ t7); + + return ((long)y1 << 56) | (((long)y2 & MASK8) << 48) | (((long)y3 & MASK8) << 40) + | (((long)y4 & MASK8) << 32) | (((long)y5 & MASK8) << 24) | (((long)y6 & MASK8) << 16) + | (((long)y7 & MASK8) << 8) | ((long)y8 & MASK8); + } + + private long bytesToWord( + byte[] src, + int srcOff) + { + long word = 0; + + for (int i = 0; i < 8; i++) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void wordToBytes( + long word, + byte[] dst, + int dstOff) + { + ulong uw = (ulong) word; + for (int i = 0; i < 8; i++) + { +// dst[(7 - i) + dstOff] = (byte)word; + dst[(7 - i) + dstOff] = (byte)uw; +// word >>>= 8; + uw >>= 8; + } + } + + private int processBlock128( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + long d1 = bytesToWord(inBytes, inOff); + long d2 = bytesToWord(inBytes, inOff + 8); + + d1 = d1 ^ _kw1; // Prewhitening + d2 = d2 ^ _kw2; + + d2 = d2 ^ f(d1, _k1); // Round 1 + d1 = d1 ^ f(d2, _k2); // Round 2 + d2 = d2 ^ f(d1, _k3); // Round 3 + d1 = d1 ^ f(d2, _k4); // Round 4 + d2 = d2 ^ f(d1, _k5); // Round 5 + d1 = d1 ^ f(d2, _k6); // Round 6 + d1 = fl (d1, _ke1); // FL + d2 = flInv(d2, _ke2); // FLINV + d2 = d2 ^ f(d1, _k7); // Round 7 + d1 = d1 ^ f(d2, _k8); // Round 8 + d2 = d2 ^ f(d1, _k9); // Round 9 + d1 = d1 ^ f(d2, _k10); // Round 10 + d2 = d2 ^ f(d1, _k11); // Round 11 + d1 = d1 ^ f(d2, _k12); // Round 12 + d1 = fl (d1, _ke3); // FL + d2 = flInv(d2, _ke4); // FLINV + + d2 = d2 ^ f(d1, _k13); // Round 13 + d1 = d1 ^ f(d2, _k14); // Round 14 + d2 = d2 ^ f(d1, _k15); // Round 15 + d1 = d1 ^ f(d2, _k16); // Round 16 + d2 = d2 ^ f(d1, _k17); // Round 17 + d1 = d1 ^ f(d2, _k18); // Round 18 + + d2 = d2 ^ _kw3; // Postwhitening + d1 = d1 ^ _kw4; + + wordToBytes(d2, outBytes, outOff); + wordToBytes(d1, outBytes, outOff + 8); + + return BLOCK_SIZE; + } + + private int processBlock192or256( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + long d1 = bytesToWord(inBytes, inOff); + long d2 = bytesToWord(inBytes, inOff + 8); + + d1 = d1 ^ _kw1; // Prewhitening + d2 = d2 ^ _kw2; + + d2 = d2 ^ f(d1, _k1); // Round 1 + d1 = d1 ^ f(d2, _k2); // Round 2 + d2 = d2 ^ f(d1, _k3); // Round 3 + d1 = d1 ^ f(d2, _k4); // Round 4 + d2 = d2 ^ f(d1, _k5); // Round 5 + d1 = d1 ^ f(d2, _k6); // Round 6 + d1 = fl (d1, _ke1); // FL + d2 = flInv(d2, _ke2); // FLINV + d2 = d2 ^ f(d1, _k7); // Round 7 + d1 = d1 ^ f(d2, _k8); // Round 8 + d2 = d2 ^ f(d1, _k9); // Round 9 + d1 = d1 ^ f(d2, _k10); // Round 10 + d2 = d2 ^ f(d1, _k11); // Round 11 + d1 = d1 ^ f(d2, _k12); // Round 12 + d1 = fl (d1, _ke3); // FL + d2 = flInv(d2, _ke4); // FLINV + d2 = d2 ^ f(d1, _k13); // Round 13 + d1 = d1 ^ f(d2, _k14); // Round 14 + d2 = d2 ^ f(d1, _k15); // Round 15 + d1 = d1 ^ f(d2, _k16); // Round 16 + d2 = d2 ^ f(d1, _k17); // Round 17 + d1 = d1 ^ f(d2, _k18); // Round 18 + d1 = fl (d1, _ke5); // FL + d2 = flInv(d2, _ke6); // FLINV + d2 = d2 ^ f(d1, _k19); // Round 19 + d1 = d1 ^ f(d2, _k20); // Round 20 + d2 = d2 ^ f(d1, _k21); // Round 21 + d1 = d1 ^ f(d2, _k22); // Round 22 + d2 = d2 ^ f(d1, _k23); // Round 23 + d1 = d1 ^ f(d2, _k24); // Round 24 + + d2 = d2 ^ _kw3; // Postwhitening + d1 = d1 ^ _kw4; + + wordToBytes(d2, outBytes, outOff); + wordToBytes(d1, outBytes, outOff + 8); + + return BLOCK_SIZE; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/CamelliaWrapEngine.cs b/iTechSharp/srcbc/crypto/engines/CamelliaWrapEngine.cs new file mode 100644 index 0000000..49dc833 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/CamelliaWrapEngine.cs @@ -0,0 +1,16 @@ +namespace Org.BouncyCastle.Crypto.Engines +{ + /// + /// An implementation of the Camellia key wrapper based on RFC 3657/RFC 3394. + ///

      + /// For further details see: http://www.ietf.org/rfc/rfc3657.txt. + /// + public class CamelliaWrapEngine + : Rfc3394WrapEngine + { + public CamelliaWrapEngine() + : base(new CamelliaEngine()) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/Cast5Engine.cs b/iTechSharp/srcbc/crypto/engines/Cast5Engine.cs new file mode 100644 index 0000000..cb50dac --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/Cast5Engine.cs @@ -0,0 +1,829 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * A class that provides CAST key encryption operations, + * such as encoding data and generating keys. + * + * All the algorithms herein are from the Internet RFC's + * + * RFC2144 - Cast5 (64bit block, 40-128bit key) + * RFC2612 - CAST6 (128bit block, 128-256bit key) + * + * and implement a simplified cryptography interface. + */ + public class Cast5Engine + : IBlockCipher + { + internal const int M32 = unchecked((int) 0xffffffff); + + internal static readonly int[] + S1 = { + unchecked((int) 0x30fb40d4), unchecked((int) 0x9fa0ff0b), unchecked((int) 0x6beccd2f), unchecked((int) 0x3f258c7a), unchecked((int) 0x1e213f2f), unchecked((int) 0x9c004dd3), unchecked((int) 0x6003e540), unchecked((int) 0xcf9fc949), + unchecked((int) 0xbfd4af27), unchecked((int) 0x88bbbdb5), unchecked((int) 0xe2034090), unchecked((int) 0x98d09675), unchecked((int) 0x6e63a0e0), unchecked((int) 0x15c361d2), unchecked((int) 0xc2e7661d), unchecked((int) 0x22d4ff8e), + unchecked((int) 0x28683b6f), unchecked((int) 0xc07fd059), unchecked((int) 0xff2379c8), unchecked((int) 0x775f50e2), unchecked((int) 0x43c340d3), unchecked((int) 0xdf2f8656), unchecked((int) 0x887ca41a), unchecked((int) 0xa2d2bd2d), + unchecked((int) 0xa1c9e0d6), unchecked((int) 0x346c4819), unchecked((int) 0x61b76d87), unchecked((int) 0x22540f2f), unchecked((int) 0x2abe32e1), unchecked((int) 0xaa54166b), unchecked((int) 0x22568e3a), unchecked((int) 0xa2d341d0), + unchecked((int) 0x66db40c8), unchecked((int) 0xa784392f), unchecked((int) 0x004dff2f), unchecked((int) 0x2db9d2de), unchecked((int) 0x97943fac), unchecked((int) 0x4a97c1d8), unchecked((int) 0x527644b7), unchecked((int) 0xb5f437a7), + unchecked((int) 0xb82cbaef), unchecked((int) 0xd751d159), unchecked((int) 0x6ff7f0ed), unchecked((int) 0x5a097a1f), unchecked((int) 0x827b68d0), unchecked((int) 0x90ecf52e), unchecked((int) 0x22b0c054), unchecked((int) 0xbc8e5935), + unchecked((int) 0x4b6d2f7f), unchecked((int) 0x50bb64a2), unchecked((int) 0xd2664910), unchecked((int) 0xbee5812d), unchecked((int) 0xb7332290), unchecked((int) 0xe93b159f), unchecked((int) 0xb48ee411), unchecked((int) 0x4bff345d), + unchecked((int) 0xfd45c240), unchecked((int) 0xad31973f), unchecked((int) 0xc4f6d02e), unchecked((int) 0x55fc8165), unchecked((int) 0xd5b1caad), unchecked((int) 0xa1ac2dae), unchecked((int) 0xa2d4b76d), unchecked((int) 0xc19b0c50), + unchecked((int) 0x882240f2), unchecked((int) 0x0c6e4f38), unchecked((int) 0xa4e4bfd7), unchecked((int) 0x4f5ba272), unchecked((int) 0x564c1d2f), unchecked((int) 0xc59c5319), unchecked((int) 0xb949e354), unchecked((int) 0xb04669fe), + unchecked((int) 0xb1b6ab8a), unchecked((int) 0xc71358dd), unchecked((int) 0x6385c545), unchecked((int) 0x110f935d), unchecked((int) 0x57538ad5), unchecked((int) 0x6a390493), unchecked((int) 0xe63d37e0), unchecked((int) 0x2a54f6b3), + unchecked((int) 0x3a787d5f), unchecked((int) 0x6276a0b5), unchecked((int) 0x19a6fcdf), unchecked((int) 0x7a42206a), unchecked((int) 0x29f9d4d5), unchecked((int) 0xf61b1891), unchecked((int) 0xbb72275e), unchecked((int) 0xaa508167), + unchecked((int) 0x38901091), unchecked((int) 0xc6b505eb), unchecked((int) 0x84c7cb8c), unchecked((int) 0x2ad75a0f), unchecked((int) 0x874a1427), unchecked((int) 0xa2d1936b), unchecked((int) 0x2ad286af), unchecked((int) 0xaa56d291), + unchecked((int) 0xd7894360), unchecked((int) 0x425c750d), unchecked((int) 0x93b39e26), unchecked((int) 0x187184c9), unchecked((int) 0x6c00b32d), unchecked((int) 0x73e2bb14), unchecked((int) 0xa0bebc3c), unchecked((int) 0x54623779), + unchecked((int) 0x64459eab), unchecked((int) 0x3f328b82), unchecked((int) 0x7718cf82), unchecked((int) 0x59a2cea6), unchecked((int) 0x04ee002e), unchecked((int) 0x89fe78e6), unchecked((int) 0x3fab0950), unchecked((int) 0x325ff6c2), + unchecked((int) 0x81383f05), unchecked((int) 0x6963c5c8), unchecked((int) 0x76cb5ad6), unchecked((int) 0xd49974c9), unchecked((int) 0xca180dcf), unchecked((int) 0x380782d5), unchecked((int) 0xc7fa5cf6), unchecked((int) 0x8ac31511), + unchecked((int) 0x35e79e13), unchecked((int) 0x47da91d0), unchecked((int) 0xf40f9086), unchecked((int) 0xa7e2419e), unchecked((int) 0x31366241), unchecked((int) 0x051ef495), unchecked((int) 0xaa573b04), unchecked((int) 0x4a805d8d), + unchecked((int) 0x548300d0), unchecked((int) 0x00322a3c), unchecked((int) 0xbf64cddf), unchecked((int) 0xba57a68e), unchecked((int) 0x75c6372b), unchecked((int) 0x50afd341), unchecked((int) 0xa7c13275), unchecked((int) 0x915a0bf5), + unchecked((int) 0x6b54bfab), unchecked((int) 0x2b0b1426), unchecked((int) 0xab4cc9d7), unchecked((int) 0x449ccd82), unchecked((int) 0xf7fbf265), unchecked((int) 0xab85c5f3), unchecked((int) 0x1b55db94), unchecked((int) 0xaad4e324), + unchecked((int) 0xcfa4bd3f), unchecked((int) 0x2deaa3e2), unchecked((int) 0x9e204d02), unchecked((int) 0xc8bd25ac), unchecked((int) 0xeadf55b3), unchecked((int) 0xd5bd9e98), unchecked((int) 0xe31231b2), unchecked((int) 0x2ad5ad6c), + unchecked((int) 0x954329de), unchecked((int) 0xadbe4528), unchecked((int) 0xd8710f69), unchecked((int) 0xaa51c90f), unchecked((int) 0xaa786bf6), unchecked((int) 0x22513f1e), unchecked((int) 0xaa51a79b), unchecked((int) 0x2ad344cc), + unchecked((int) 0x7b5a41f0), unchecked((int) 0xd37cfbad), unchecked((int) 0x1b069505), unchecked((int) 0x41ece491), unchecked((int) 0xb4c332e6), unchecked((int) 0x032268d4), unchecked((int) 0xc9600acc), unchecked((int) 0xce387e6d), + unchecked((int) 0xbf6bb16c), unchecked((int) 0x6a70fb78), unchecked((int) 0x0d03d9c9), unchecked((int) 0xd4df39de), unchecked((int) 0xe01063da), unchecked((int) 0x4736f464), unchecked((int) 0x5ad328d8), unchecked((int) 0xb347cc96), + unchecked((int) 0x75bb0fc3), unchecked((int) 0x98511bfb), unchecked((int) 0x4ffbcc35), unchecked((int) 0xb58bcf6a), unchecked((int) 0xe11f0abc), unchecked((int) 0xbfc5fe4a), unchecked((int) 0xa70aec10), unchecked((int) 0xac39570a), + unchecked((int) 0x3f04442f), unchecked((int) 0x6188b153), unchecked((int) 0xe0397a2e), unchecked((int) 0x5727cb79), unchecked((int) 0x9ceb418f), unchecked((int) 0x1cacd68d), unchecked((int) 0x2ad37c96), unchecked((int) 0x0175cb9d), + unchecked((int) 0xc69dff09), unchecked((int) 0xc75b65f0), unchecked((int) 0xd9db40d8), unchecked((int) 0xec0e7779), unchecked((int) 0x4744ead4), unchecked((int) 0xb11c3274), unchecked((int) 0xdd24cb9e), unchecked((int) 0x7e1c54bd), + unchecked((int) 0xf01144f9), unchecked((int) 0xd2240eb1), unchecked((int) 0x9675b3fd), unchecked((int) 0xa3ac3755), unchecked((int) 0xd47c27af), unchecked((int) 0x51c85f4d), unchecked((int) 0x56907596), unchecked((int) 0xa5bb15e6), + unchecked((int) 0x580304f0), unchecked((int) 0xca042cf1), unchecked((int) 0x011a37ea), unchecked((int) 0x8dbfaadb), unchecked((int) 0x35ba3e4a), unchecked((int) 0x3526ffa0), unchecked((int) 0xc37b4d09), unchecked((int) 0xbc306ed9), + unchecked((int) 0x98a52666), unchecked((int) 0x5648f725), unchecked((int) 0xff5e569d), unchecked((int) 0x0ced63d0), unchecked((int) 0x7c63b2cf), unchecked((int) 0x700b45e1), unchecked((int) 0xd5ea50f1), unchecked((int) 0x85a92872), + unchecked((int) 0xaf1fbda7), unchecked((int) 0xd4234870), unchecked((int) 0xa7870bf3), unchecked((int) 0x2d3b4d79), unchecked((int) 0x42e04198), unchecked((int) 0x0cd0ede7), unchecked((int) 0x26470db8), unchecked((int) 0xf881814c), + unchecked((int) 0x474d6ad7), unchecked((int) 0x7c0c5e5c), unchecked((int) 0xd1231959), unchecked((int) 0x381b7298), unchecked((int) 0xf5d2f4db), unchecked((int) 0xab838653), unchecked((int) 0x6e2f1e23), unchecked((int) 0x83719c9e), + unchecked((int) 0xbd91e046), unchecked((int) 0x9a56456e), unchecked((int) 0xdc39200c), unchecked((int) 0x20c8c571), unchecked((int) 0x962bda1c), unchecked((int) 0xe1e696ff), unchecked((int) 0xb141ab08), unchecked((int) 0x7cca89b9), + unchecked((int) 0x1a69e783), unchecked((int) 0x02cc4843), unchecked((int) 0xa2f7c579), unchecked((int) 0x429ef47d), unchecked((int) 0x427b169c), unchecked((int) 0x5ac9f049), unchecked((int) 0xdd8f0f00), unchecked((int) 0x5c8165bf) + }, + S2 = + { + unchecked((int) 0x1f201094), unchecked((int) 0xef0ba75b), unchecked((int) 0x69e3cf7e), unchecked((int) 0x393f4380), unchecked((int) 0xfe61cf7a), unchecked((int) 0xeec5207a), unchecked((int) 0x55889c94), unchecked((int) 0x72fc0651), + unchecked((int) 0xada7ef79), unchecked((int) 0x4e1d7235), unchecked((int) 0xd55a63ce), unchecked((int) 0xde0436ba), unchecked((int) 0x99c430ef), unchecked((int) 0x5f0c0794), unchecked((int) 0x18dcdb7d), unchecked((int) 0xa1d6eff3), + unchecked((int) 0xa0b52f7b), unchecked((int) 0x59e83605), unchecked((int) 0xee15b094), unchecked((int) 0xe9ffd909), unchecked((int) 0xdc440086), unchecked((int) 0xef944459), unchecked((int) 0xba83ccb3), unchecked((int) 0xe0c3cdfb), + unchecked((int) 0xd1da4181), unchecked((int) 0x3b092ab1), unchecked((int) 0xf997f1c1), unchecked((int) 0xa5e6cf7b), unchecked((int) 0x01420ddb), unchecked((int) 0xe4e7ef5b), unchecked((int) 0x25a1ff41), unchecked((int) 0xe180f806), + unchecked((int) 0x1fc41080), unchecked((int) 0x179bee7a), unchecked((int) 0xd37ac6a9), unchecked((int) 0xfe5830a4), unchecked((int) 0x98de8b7f), unchecked((int) 0x77e83f4e), unchecked((int) 0x79929269), unchecked((int) 0x24fa9f7b), + unchecked((int) 0xe113c85b), unchecked((int) 0xacc40083), unchecked((int) 0xd7503525), unchecked((int) 0xf7ea615f), unchecked((int) 0x62143154), unchecked((int) 0x0d554b63), unchecked((int) 0x5d681121), unchecked((int) 0xc866c359), + unchecked((int) 0x3d63cf73), unchecked((int) 0xcee234c0), unchecked((int) 0xd4d87e87), unchecked((int) 0x5c672b21), unchecked((int) 0x071f6181), unchecked((int) 0x39f7627f), unchecked((int) 0x361e3084), unchecked((int) 0xe4eb573b), + unchecked((int) 0x602f64a4), unchecked((int) 0xd63acd9c), unchecked((int) 0x1bbc4635), unchecked((int) 0x9e81032d), unchecked((int) 0x2701f50c), unchecked((int) 0x99847ab4), unchecked((int) 0xa0e3df79), unchecked((int) 0xba6cf38c), + unchecked((int) 0x10843094), unchecked((int) 0x2537a95e), unchecked((int) 0xf46f6ffe), unchecked((int) 0xa1ff3b1f), unchecked((int) 0x208cfb6a), unchecked((int) 0x8f458c74), unchecked((int) 0xd9e0a227), unchecked((int) 0x4ec73a34), + unchecked((int) 0xfc884f69), unchecked((int) 0x3e4de8df), unchecked((int) 0xef0e0088), unchecked((int) 0x3559648d), unchecked((int) 0x8a45388c), unchecked((int) 0x1d804366), unchecked((int) 0x721d9bfd), unchecked((int) 0xa58684bb), + unchecked((int) 0xe8256333), unchecked((int) 0x844e8212), unchecked((int) 0x128d8098), unchecked((int) 0xfed33fb4), unchecked((int) 0xce280ae1), unchecked((int) 0x27e19ba5), unchecked((int) 0xd5a6c252), unchecked((int) 0xe49754bd), + unchecked((int) 0xc5d655dd), unchecked((int) 0xeb667064), unchecked((int) 0x77840b4d), unchecked((int) 0xa1b6a801), unchecked((int) 0x84db26a9), unchecked((int) 0xe0b56714), unchecked((int) 0x21f043b7), unchecked((int) 0xe5d05860), + unchecked((int) 0x54f03084), unchecked((int) 0x066ff472), unchecked((int) 0xa31aa153), unchecked((int) 0xdadc4755), unchecked((int) 0xb5625dbf), unchecked((int) 0x68561be6), unchecked((int) 0x83ca6b94), unchecked((int) 0x2d6ed23b), + unchecked((int) 0xeccf01db), unchecked((int) 0xa6d3d0ba), unchecked((int) 0xb6803d5c), unchecked((int) 0xaf77a709), unchecked((int) 0x33b4a34c), unchecked((int) 0x397bc8d6), unchecked((int) 0x5ee22b95), unchecked((int) 0x5f0e5304), + unchecked((int) 0x81ed6f61), unchecked((int) 0x20e74364), unchecked((int) 0xb45e1378), unchecked((int) 0xde18639b), unchecked((int) 0x881ca122), unchecked((int) 0xb96726d1), unchecked((int) 0x8049a7e8), unchecked((int) 0x22b7da7b), + unchecked((int) 0x5e552d25), unchecked((int) 0x5272d237), unchecked((int) 0x79d2951c), unchecked((int) 0xc60d894c), unchecked((int) 0x488cb402), unchecked((int) 0x1ba4fe5b), unchecked((int) 0xa4b09f6b), unchecked((int) 0x1ca815cf), + unchecked((int) 0xa20c3005), unchecked((int) 0x8871df63), unchecked((int) 0xb9de2fcb), unchecked((int) 0x0cc6c9e9), unchecked((int) 0x0beeff53), unchecked((int) 0xe3214517), unchecked((int) 0xb4542835), unchecked((int) 0x9f63293c), + unchecked((int) 0xee41e729), unchecked((int) 0x6e1d2d7c), unchecked((int) 0x50045286), unchecked((int) 0x1e6685f3), unchecked((int) 0xf33401c6), unchecked((int) 0x30a22c95), unchecked((int) 0x31a70850), unchecked((int) 0x60930f13), + unchecked((int) 0x73f98417), unchecked((int) 0xa1269859), unchecked((int) 0xec645c44), unchecked((int) 0x52c877a9), unchecked((int) 0xcdff33a6), unchecked((int) 0xa02b1741), unchecked((int) 0x7cbad9a2), unchecked((int) 0x2180036f), + unchecked((int) 0x50d99c08), unchecked((int) 0xcb3f4861), unchecked((int) 0xc26bd765), unchecked((int) 0x64a3f6ab), unchecked((int) 0x80342676), unchecked((int) 0x25a75e7b), unchecked((int) 0xe4e6d1fc), unchecked((int) 0x20c710e6), + unchecked((int) 0xcdf0b680), unchecked((int) 0x17844d3b), unchecked((int) 0x31eef84d), unchecked((int) 0x7e0824e4), unchecked((int) 0x2ccb49eb), unchecked((int) 0x846a3bae), unchecked((int) 0x8ff77888), unchecked((int) 0xee5d60f6), + unchecked((int) 0x7af75673), unchecked((int) 0x2fdd5cdb), unchecked((int) 0xa11631c1), unchecked((int) 0x30f66f43), unchecked((int) 0xb3faec54), unchecked((int) 0x157fd7fa), unchecked((int) 0xef8579cc), unchecked((int) 0xd152de58), + unchecked((int) 0xdb2ffd5e), unchecked((int) 0x8f32ce19), unchecked((int) 0x306af97a), unchecked((int) 0x02f03ef8), unchecked((int) 0x99319ad5), unchecked((int) 0xc242fa0f), unchecked((int) 0xa7e3ebb0), unchecked((int) 0xc68e4906), + unchecked((int) 0xb8da230c), unchecked((int) 0x80823028), unchecked((int) 0xdcdef3c8), unchecked((int) 0xd35fb171), unchecked((int) 0x088a1bc8), unchecked((int) 0xbec0c560), unchecked((int) 0x61a3c9e8), unchecked((int) 0xbca8f54d), + unchecked((int) 0xc72feffa), unchecked((int) 0x22822e99), unchecked((int) 0x82c570b4), unchecked((int) 0xd8d94e89), unchecked((int) 0x8b1c34bc), unchecked((int) 0x301e16e6), unchecked((int) 0x273be979), unchecked((int) 0xb0ffeaa6), + unchecked((int) 0x61d9b8c6), unchecked((int) 0x00b24869), unchecked((int) 0xb7ffce3f), unchecked((int) 0x08dc283b), unchecked((int) 0x43daf65a), unchecked((int) 0xf7e19798), unchecked((int) 0x7619b72f), unchecked((int) 0x8f1c9ba4), + unchecked((int) 0xdc8637a0), unchecked((int) 0x16a7d3b1), unchecked((int) 0x9fc393b7), unchecked((int) 0xa7136eeb), unchecked((int) 0xc6bcc63e), unchecked((int) 0x1a513742), unchecked((int) 0xef6828bc), unchecked((int) 0x520365d6), + unchecked((int) 0x2d6a77ab), unchecked((int) 0x3527ed4b), unchecked((int) 0x821fd216), unchecked((int) 0x095c6e2e), unchecked((int) 0xdb92f2fb), unchecked((int) 0x5eea29cb), unchecked((int) 0x145892f5), unchecked((int) 0x91584f7f), + unchecked((int) 0x5483697b), unchecked((int) 0x2667a8cc), unchecked((int) 0x85196048), unchecked((int) 0x8c4bacea), unchecked((int) 0x833860d4), unchecked((int) 0x0d23e0f9), unchecked((int) 0x6c387e8a), unchecked((int) 0x0ae6d249), + unchecked((int) 0xb284600c), unchecked((int) 0xd835731d), unchecked((int) 0xdcb1c647), unchecked((int) 0xac4c56ea), unchecked((int) 0x3ebd81b3), unchecked((int) 0x230eabb0), unchecked((int) 0x6438bc87), unchecked((int) 0xf0b5b1fa), + unchecked((int) 0x8f5ea2b3), unchecked((int) 0xfc184642), unchecked((int) 0x0a036b7a), unchecked((int) 0x4fb089bd), unchecked((int) 0x649da589), unchecked((int) 0xa345415e), unchecked((int) 0x5c038323), unchecked((int) 0x3e5d3bb9), + unchecked((int) 0x43d79572), unchecked((int) 0x7e6dd07c), unchecked((int) 0x06dfdf1e), unchecked((int) 0x6c6cc4ef), unchecked((int) 0x7160a539), unchecked((int) 0x73bfbe70), unchecked((int) 0x83877605), unchecked((int) 0x4523ecf1) + }, + S3 = + { + unchecked((int) 0x8defc240), unchecked((int) 0x25fa5d9f), unchecked((int) 0xeb903dbf), unchecked((int) 0xe810c907), unchecked((int) 0x47607fff), unchecked((int) 0x369fe44b), unchecked((int) 0x8c1fc644), unchecked((int) 0xaececa90), + unchecked((int) 0xbeb1f9bf), unchecked((int) 0xeefbcaea), unchecked((int) 0xe8cf1950), unchecked((int) 0x51df07ae), unchecked((int) 0x920e8806), unchecked((int) 0xf0ad0548), unchecked((int) 0xe13c8d83), unchecked((int) 0x927010d5), + unchecked((int) 0x11107d9f), unchecked((int) 0x07647db9), unchecked((int) 0xb2e3e4d4), unchecked((int) 0x3d4f285e), unchecked((int) 0xb9afa820), unchecked((int) 0xfade82e0), unchecked((int) 0xa067268b), unchecked((int) 0x8272792e), + unchecked((int) 0x553fb2c0), unchecked((int) 0x489ae22b), unchecked((int) 0xd4ef9794), unchecked((int) 0x125e3fbc), unchecked((int) 0x21fffcee), unchecked((int) 0x825b1bfd), unchecked((int) 0x9255c5ed), unchecked((int) 0x1257a240), + unchecked((int) 0x4e1a8302), unchecked((int) 0xbae07fff), unchecked((int) 0x528246e7), unchecked((int) 0x8e57140e), unchecked((int) 0x3373f7bf), unchecked((int) 0x8c9f8188), unchecked((int) 0xa6fc4ee8), unchecked((int) 0xc982b5a5), + unchecked((int) 0xa8c01db7), unchecked((int) 0x579fc264), unchecked((int) 0x67094f31), unchecked((int) 0xf2bd3f5f), unchecked((int) 0x40fff7c1), unchecked((int) 0x1fb78dfc), unchecked((int) 0x8e6bd2c1), unchecked((int) 0x437be59b), + unchecked((int) 0x99b03dbf), unchecked((int) 0xb5dbc64b), unchecked((int) 0x638dc0e6), unchecked((int) 0x55819d99), unchecked((int) 0xa197c81c), unchecked((int) 0x4a012d6e), unchecked((int) 0xc5884a28), unchecked((int) 0xccc36f71), + unchecked((int) 0xb843c213), unchecked((int) 0x6c0743f1), unchecked((int) 0x8309893c), unchecked((int) 0x0feddd5f), unchecked((int) 0x2f7fe850), unchecked((int) 0xd7c07f7e), unchecked((int) 0x02507fbf), unchecked((int) 0x5afb9a04), + unchecked((int) 0xa747d2d0), unchecked((int) 0x1651192e), unchecked((int) 0xaf70bf3e), unchecked((int) 0x58c31380), unchecked((int) 0x5f98302e), unchecked((int) 0x727cc3c4), unchecked((int) 0x0a0fb402), unchecked((int) 0x0f7fef82), + unchecked((int) 0x8c96fdad), unchecked((int) 0x5d2c2aae), unchecked((int) 0x8ee99a49), unchecked((int) 0x50da88b8), unchecked((int) 0x8427f4a0), unchecked((int) 0x1eac5790), unchecked((int) 0x796fb449), unchecked((int) 0x8252dc15), + unchecked((int) 0xefbd7d9b), unchecked((int) 0xa672597d), unchecked((int) 0xada840d8), unchecked((int) 0x45f54504), unchecked((int) 0xfa5d7403), unchecked((int) 0xe83ec305), unchecked((int) 0x4f91751a), unchecked((int) 0x925669c2), + unchecked((int) 0x23efe941), unchecked((int) 0xa903f12e), unchecked((int) 0x60270df2), unchecked((int) 0x0276e4b6), unchecked((int) 0x94fd6574), unchecked((int) 0x927985b2), unchecked((int) 0x8276dbcb), unchecked((int) 0x02778176), + unchecked((int) 0xf8af918d), unchecked((int) 0x4e48f79e), unchecked((int) 0x8f616ddf), unchecked((int) 0xe29d840e), unchecked((int) 0x842f7d83), unchecked((int) 0x340ce5c8), unchecked((int) 0x96bbb682), unchecked((int) 0x93b4b148), + unchecked((int) 0xef303cab), unchecked((int) 0x984faf28), unchecked((int) 0x779faf9b), unchecked((int) 0x92dc560d), unchecked((int) 0x224d1e20), unchecked((int) 0x8437aa88), unchecked((int) 0x7d29dc96), unchecked((int) 0x2756d3dc), + unchecked((int) 0x8b907cee), unchecked((int) 0xb51fd240), unchecked((int) 0xe7c07ce3), unchecked((int) 0xe566b4a1), unchecked((int) 0xc3e9615e), unchecked((int) 0x3cf8209d), unchecked((int) 0x6094d1e3), unchecked((int) 0xcd9ca341), + unchecked((int) 0x5c76460e), unchecked((int) 0x00ea983b), unchecked((int) 0xd4d67881), unchecked((int) 0xfd47572c), unchecked((int) 0xf76cedd9), unchecked((int) 0xbda8229c), unchecked((int) 0x127dadaa), unchecked((int) 0x438a074e), + unchecked((int) 0x1f97c090), unchecked((int) 0x081bdb8a), unchecked((int) 0x93a07ebe), unchecked((int) 0xb938ca15), unchecked((int) 0x97b03cff), unchecked((int) 0x3dc2c0f8), unchecked((int) 0x8d1ab2ec), unchecked((int) 0x64380e51), + unchecked((int) 0x68cc7bfb), unchecked((int) 0xd90f2788), unchecked((int) 0x12490181), unchecked((int) 0x5de5ffd4), unchecked((int) 0xdd7ef86a), unchecked((int) 0x76a2e214), unchecked((int) 0xb9a40368), unchecked((int) 0x925d958f), + unchecked((int) 0x4b39fffa), unchecked((int) 0xba39aee9), unchecked((int) 0xa4ffd30b), unchecked((int) 0xfaf7933b), unchecked((int) 0x6d498623), unchecked((int) 0x193cbcfa), unchecked((int) 0x27627545), unchecked((int) 0x825cf47a), + unchecked((int) 0x61bd8ba0), unchecked((int) 0xd11e42d1), unchecked((int) 0xcead04f4), unchecked((int) 0x127ea392), unchecked((int) 0x10428db7), unchecked((int) 0x8272a972), unchecked((int) 0x9270c4a8), unchecked((int) 0x127de50b), + unchecked((int) 0x285ba1c8), unchecked((int) 0x3c62f44f), unchecked((int) 0x35c0eaa5), unchecked((int) 0xe805d231), unchecked((int) 0x428929fb), unchecked((int) 0xb4fcdf82), unchecked((int) 0x4fb66a53), unchecked((int) 0x0e7dc15b), + unchecked((int) 0x1f081fab), unchecked((int) 0x108618ae), unchecked((int) 0xfcfd086d), unchecked((int) 0xf9ff2889), unchecked((int) 0x694bcc11), unchecked((int) 0x236a5cae), unchecked((int) 0x12deca4d), unchecked((int) 0x2c3f8cc5), + unchecked((int) 0xd2d02dfe), unchecked((int) 0xf8ef5896), unchecked((int) 0xe4cf52da), unchecked((int) 0x95155b67), unchecked((int) 0x494a488c), unchecked((int) 0xb9b6a80c), unchecked((int) 0x5c8f82bc), unchecked((int) 0x89d36b45), + unchecked((int) 0x3a609437), unchecked((int) 0xec00c9a9), unchecked((int) 0x44715253), unchecked((int) 0x0a874b49), unchecked((int) 0xd773bc40), unchecked((int) 0x7c34671c), unchecked((int) 0x02717ef6), unchecked((int) 0x4feb5536), + unchecked((int) 0xa2d02fff), unchecked((int) 0xd2bf60c4), unchecked((int) 0xd43f03c0), unchecked((int) 0x50b4ef6d), unchecked((int) 0x07478cd1), unchecked((int) 0x006e1888), unchecked((int) 0xa2e53f55), unchecked((int) 0xb9e6d4bc), + unchecked((int) 0xa2048016), unchecked((int) 0x97573833), unchecked((int) 0xd7207d67), unchecked((int) 0xde0f8f3d), unchecked((int) 0x72f87b33), unchecked((int) 0xabcc4f33), unchecked((int) 0x7688c55d), unchecked((int) 0x7b00a6b0), + unchecked((int) 0x947b0001), unchecked((int) 0x570075d2), unchecked((int) 0xf9bb88f8), unchecked((int) 0x8942019e), unchecked((int) 0x4264a5ff), unchecked((int) 0x856302e0), unchecked((int) 0x72dbd92b), unchecked((int) 0xee971b69), + unchecked((int) 0x6ea22fde), unchecked((int) 0x5f08ae2b), unchecked((int) 0xaf7a616d), unchecked((int) 0xe5c98767), unchecked((int) 0xcf1febd2), unchecked((int) 0x61efc8c2), unchecked((int) 0xf1ac2571), unchecked((int) 0xcc8239c2), + unchecked((int) 0x67214cb8), unchecked((int) 0xb1e583d1), unchecked((int) 0xb7dc3e62), unchecked((int) 0x7f10bdce), unchecked((int) 0xf90a5c38), unchecked((int) 0x0ff0443d), unchecked((int) 0x606e6dc6), unchecked((int) 0x60543a49), + unchecked((int) 0x5727c148), unchecked((int) 0x2be98a1d), unchecked((int) 0x8ab41738), unchecked((int) 0x20e1be24), unchecked((int) 0xaf96da0f), unchecked((int) 0x68458425), unchecked((int) 0x99833be5), unchecked((int) 0x600d457d), + unchecked((int) 0x282f9350), unchecked((int) 0x8334b362), unchecked((int) 0xd91d1120), unchecked((int) 0x2b6d8da0), unchecked((int) 0x642b1e31), unchecked((int) 0x9c305a00), unchecked((int) 0x52bce688), unchecked((int) 0x1b03588a), + unchecked((int) 0xf7baefd5), unchecked((int) 0x4142ed9c), unchecked((int) 0xa4315c11), unchecked((int) 0x83323ec5), unchecked((int) 0xdfef4636), unchecked((int) 0xa133c501), unchecked((int) 0xe9d3531c), unchecked((int) 0xee353783) + }, + S4 = + { + unchecked((int) 0x9db30420), unchecked((int) 0x1fb6e9de), unchecked((int) 0xa7be7bef), unchecked((int) 0xd273a298), unchecked((int) 0x4a4f7bdb), unchecked((int) 0x64ad8c57), unchecked((int) 0x85510443), unchecked((int) 0xfa020ed1), + unchecked((int) 0x7e287aff), unchecked((int) 0xe60fb663), unchecked((int) 0x095f35a1), unchecked((int) 0x79ebf120), unchecked((int) 0xfd059d43), unchecked((int) 0x6497b7b1), unchecked((int) 0xf3641f63), unchecked((int) 0x241e4adf), + unchecked((int) 0x28147f5f), unchecked((int) 0x4fa2b8cd), unchecked((int) 0xc9430040), unchecked((int) 0x0cc32220), unchecked((int) 0xfdd30b30), unchecked((int) 0xc0a5374f), unchecked((int) 0x1d2d00d9), unchecked((int) 0x24147b15), + unchecked((int) 0xee4d111a), unchecked((int) 0x0fca5167), unchecked((int) 0x71ff904c), unchecked((int) 0x2d195ffe), unchecked((int) 0x1a05645f), unchecked((int) 0x0c13fefe), unchecked((int) 0x081b08ca), unchecked((int) 0x05170121), + unchecked((int) 0x80530100), unchecked((int) 0xe83e5efe), unchecked((int) 0xac9af4f8), unchecked((int) 0x7fe72701), unchecked((int) 0xd2b8ee5f), unchecked((int) 0x06df4261), unchecked((int) 0xbb9e9b8a), unchecked((int) 0x7293ea25), + unchecked((int) 0xce84ffdf), unchecked((int) 0xf5718801), unchecked((int) 0x3dd64b04), unchecked((int) 0xa26f263b), unchecked((int) 0x7ed48400), unchecked((int) 0x547eebe6), unchecked((int) 0x446d4ca0), unchecked((int) 0x6cf3d6f5), + unchecked((int) 0x2649abdf), unchecked((int) 0xaea0c7f5), unchecked((int) 0x36338cc1), unchecked((int) 0x503f7e93), unchecked((int) 0xd3772061), unchecked((int) 0x11b638e1), unchecked((int) 0x72500e03), unchecked((int) 0xf80eb2bb), + unchecked((int) 0xabe0502e), unchecked((int) 0xec8d77de), unchecked((int) 0x57971e81), unchecked((int) 0xe14f6746), unchecked((int) 0xc9335400), unchecked((int) 0x6920318f), unchecked((int) 0x081dbb99), unchecked((int) 0xffc304a5), + unchecked((int) 0x4d351805), unchecked((int) 0x7f3d5ce3), unchecked((int) 0xa6c866c6), unchecked((int) 0x5d5bcca9), unchecked((int) 0xdaec6fea), unchecked((int) 0x9f926f91), unchecked((int) 0x9f46222f), unchecked((int) 0x3991467d), + unchecked((int) 0xa5bf6d8e), unchecked((int) 0x1143c44f), unchecked((int) 0x43958302), unchecked((int) 0xd0214eeb), unchecked((int) 0x022083b8), unchecked((int) 0x3fb6180c), unchecked((int) 0x18f8931e), unchecked((int) 0x281658e6), + unchecked((int) 0x26486e3e), unchecked((int) 0x8bd78a70), unchecked((int) 0x7477e4c1), unchecked((int) 0xb506e07c), unchecked((int) 0xf32d0a25), unchecked((int) 0x79098b02), unchecked((int) 0xe4eabb81), unchecked((int) 0x28123b23), + unchecked((int) 0x69dead38), unchecked((int) 0x1574ca16), unchecked((int) 0xdf871b62), unchecked((int) 0x211c40b7), unchecked((int) 0xa51a9ef9), unchecked((int) 0x0014377b), unchecked((int) 0x041e8ac8), unchecked((int) 0x09114003), + unchecked((int) 0xbd59e4d2), unchecked((int) 0xe3d156d5), unchecked((int) 0x4fe876d5), unchecked((int) 0x2f91a340), unchecked((int) 0x557be8de), unchecked((int) 0x00eae4a7), unchecked((int) 0x0ce5c2ec), unchecked((int) 0x4db4bba6), + unchecked((int) 0xe756bdff), unchecked((int) 0xdd3369ac), unchecked((int) 0xec17b035), unchecked((int) 0x06572327), unchecked((int) 0x99afc8b0), unchecked((int) 0x56c8c391), unchecked((int) 0x6b65811c), unchecked((int) 0x5e146119), + unchecked((int) 0x6e85cb75), unchecked((int) 0xbe07c002), unchecked((int) 0xc2325577), unchecked((int) 0x893ff4ec), unchecked((int) 0x5bbfc92d), unchecked((int) 0xd0ec3b25), unchecked((int) 0xb7801ab7), unchecked((int) 0x8d6d3b24), + unchecked((int) 0x20c763ef), unchecked((int) 0xc366a5fc), unchecked((int) 0x9c382880), unchecked((int) 0x0ace3205), unchecked((int) 0xaac9548a), unchecked((int) 0xeca1d7c7), unchecked((int) 0x041afa32), unchecked((int) 0x1d16625a), + unchecked((int) 0x6701902c), unchecked((int) 0x9b757a54), unchecked((int) 0x31d477f7), unchecked((int) 0x9126b031), unchecked((int) 0x36cc6fdb), unchecked((int) 0xc70b8b46), unchecked((int) 0xd9e66a48), unchecked((int) 0x56e55a79), + unchecked((int) 0x026a4ceb), unchecked((int) 0x52437eff), unchecked((int) 0x2f8f76b4), unchecked((int) 0x0df980a5), unchecked((int) 0x8674cde3), unchecked((int) 0xedda04eb), unchecked((int) 0x17a9be04), unchecked((int) 0x2c18f4df), + unchecked((int) 0xb7747f9d), unchecked((int) 0xab2af7b4), unchecked((int) 0xefc34d20), unchecked((int) 0x2e096b7c), unchecked((int) 0x1741a254), unchecked((int) 0xe5b6a035), unchecked((int) 0x213d42f6), unchecked((int) 0x2c1c7c26), + unchecked((int) 0x61c2f50f), unchecked((int) 0x6552daf9), unchecked((int) 0xd2c231f8), unchecked((int) 0x25130f69), unchecked((int) 0xd8167fa2), unchecked((int) 0x0418f2c8), unchecked((int) 0x001a96a6), unchecked((int) 0x0d1526ab), + unchecked((int) 0x63315c21), unchecked((int) 0x5e0a72ec), unchecked((int) 0x49bafefd), unchecked((int) 0x187908d9), unchecked((int) 0x8d0dbd86), unchecked((int) 0x311170a7), unchecked((int) 0x3e9b640c), unchecked((int) 0xcc3e10d7), + unchecked((int) 0xd5cad3b6), unchecked((int) 0x0caec388), unchecked((int) 0xf73001e1), unchecked((int) 0x6c728aff), unchecked((int) 0x71eae2a1), unchecked((int) 0x1f9af36e), unchecked((int) 0xcfcbd12f), unchecked((int) 0xc1de8417), + unchecked((int) 0xac07be6b), unchecked((int) 0xcb44a1d8), unchecked((int) 0x8b9b0f56), unchecked((int) 0x013988c3), unchecked((int) 0xb1c52fca), unchecked((int) 0xb4be31cd), unchecked((int) 0xd8782806), unchecked((int) 0x12a3a4e2), + unchecked((int) 0x6f7de532), unchecked((int) 0x58fd7eb6), unchecked((int) 0xd01ee900), unchecked((int) 0x24adffc2), unchecked((int) 0xf4990fc5), unchecked((int) 0x9711aac5), unchecked((int) 0x001d7b95), unchecked((int) 0x82e5e7d2), + unchecked((int) 0x109873f6), unchecked((int) 0x00613096), unchecked((int) 0xc32d9521), unchecked((int) 0xada121ff), unchecked((int) 0x29908415), unchecked((int) 0x7fbb977f), unchecked((int) 0xaf9eb3db), unchecked((int) 0x29c9ed2a), + unchecked((int) 0x5ce2a465), unchecked((int) 0xa730f32c), unchecked((int) 0xd0aa3fe8), unchecked((int) 0x8a5cc091), unchecked((int) 0xd49e2ce7), unchecked((int) 0x0ce454a9), unchecked((int) 0xd60acd86), unchecked((int) 0x015f1919), + unchecked((int) 0x77079103), unchecked((int) 0xdea03af6), unchecked((int) 0x78a8565e), unchecked((int) 0xdee356df), unchecked((int) 0x21f05cbe), unchecked((int) 0x8b75e387), unchecked((int) 0xb3c50651), unchecked((int) 0xb8a5c3ef), + unchecked((int) 0xd8eeb6d2), unchecked((int) 0xe523be77), unchecked((int) 0xc2154529), unchecked((int) 0x2f69efdf), unchecked((int) 0xafe67afb), unchecked((int) 0xf470c4b2), unchecked((int) 0xf3e0eb5b), unchecked((int) 0xd6cc9876), + unchecked((int) 0x39e4460c), unchecked((int) 0x1fda8538), unchecked((int) 0x1987832f), unchecked((int) 0xca007367), unchecked((int) 0xa99144f8), unchecked((int) 0x296b299e), unchecked((int) 0x492fc295), unchecked((int) 0x9266beab), + unchecked((int) 0xb5676e69), unchecked((int) 0x9bd3ddda), unchecked((int) 0xdf7e052f), unchecked((int) 0xdb25701c), unchecked((int) 0x1b5e51ee), unchecked((int) 0xf65324e6), unchecked((int) 0x6afce36c), unchecked((int) 0x0316cc04), + unchecked((int) 0x8644213e), unchecked((int) 0xb7dc59d0), unchecked((int) 0x7965291f), unchecked((int) 0xccd6fd43), unchecked((int) 0x41823979), unchecked((int) 0x932bcdf6), unchecked((int) 0xb657c34d), unchecked((int) 0x4edfd282), + unchecked((int) 0x7ae5290c), unchecked((int) 0x3cb9536b), unchecked((int) 0x851e20fe), unchecked((int) 0x9833557e), unchecked((int) 0x13ecf0b0), unchecked((int) 0xd3ffb372), unchecked((int) 0x3f85c5c1), unchecked((int) 0x0aef7ed2) + }, + S5 = + { + unchecked((int) 0x7ec90c04), unchecked((int) 0x2c6e74b9), unchecked((int) 0x9b0e66df), unchecked((int) 0xa6337911), unchecked((int) 0xb86a7fff), unchecked((int) 0x1dd358f5), unchecked((int) 0x44dd9d44), unchecked((int) 0x1731167f), + unchecked((int) 0x08fbf1fa), unchecked((int) 0xe7f511cc), unchecked((int) 0xd2051b00), unchecked((int) 0x735aba00), unchecked((int) 0x2ab722d8), unchecked((int) 0x386381cb), unchecked((int) 0xacf6243a), unchecked((int) 0x69befd7a), + unchecked((int) 0xe6a2e77f), unchecked((int) 0xf0c720cd), unchecked((int) 0xc4494816), unchecked((int) 0xccf5c180), unchecked((int) 0x38851640), unchecked((int) 0x15b0a848), unchecked((int) 0xe68b18cb), unchecked((int) 0x4caadeff), + unchecked((int) 0x5f480a01), unchecked((int) 0x0412b2aa), unchecked((int) 0x259814fc), unchecked((int) 0x41d0efe2), unchecked((int) 0x4e40b48d), unchecked((int) 0x248eb6fb), unchecked((int) 0x8dba1cfe), unchecked((int) 0x41a99b02), + unchecked((int) 0x1a550a04), unchecked((int) 0xba8f65cb), unchecked((int) 0x7251f4e7), unchecked((int) 0x95a51725), unchecked((int) 0xc106ecd7), unchecked((int) 0x97a5980a), unchecked((int) 0xc539b9aa), unchecked((int) 0x4d79fe6a), + unchecked((int) 0xf2f3f763), unchecked((int) 0x68af8040), unchecked((int) 0xed0c9e56), unchecked((int) 0x11b4958b), unchecked((int) 0xe1eb5a88), unchecked((int) 0x8709e6b0), unchecked((int) 0xd7e07156), unchecked((int) 0x4e29fea7), + unchecked((int) 0x6366e52d), unchecked((int) 0x02d1c000), unchecked((int) 0xc4ac8e05), unchecked((int) 0x9377f571), unchecked((int) 0x0c05372a), unchecked((int) 0x578535f2), unchecked((int) 0x2261be02), unchecked((int) 0xd642a0c9), + unchecked((int) 0xdf13a280), unchecked((int) 0x74b55bd2), unchecked((int) 0x682199c0), unchecked((int) 0xd421e5ec), unchecked((int) 0x53fb3ce8), unchecked((int) 0xc8adedb3), unchecked((int) 0x28a87fc9), unchecked((int) 0x3d959981), + unchecked((int) 0x5c1ff900), unchecked((int) 0xfe38d399), unchecked((int) 0x0c4eff0b), unchecked((int) 0x062407ea), unchecked((int) 0xaa2f4fb1), unchecked((int) 0x4fb96976), unchecked((int) 0x90c79505), unchecked((int) 0xb0a8a774), + unchecked((int) 0xef55a1ff), unchecked((int) 0xe59ca2c2), unchecked((int) 0xa6b62d27), unchecked((int) 0xe66a4263), unchecked((int) 0xdf65001f), unchecked((int) 0x0ec50966), unchecked((int) 0xdfdd55bc), unchecked((int) 0x29de0655), + unchecked((int) 0x911e739a), unchecked((int) 0x17af8975), unchecked((int) 0x32c7911c), unchecked((int) 0x89f89468), unchecked((int) 0x0d01e980), unchecked((int) 0x524755f4), unchecked((int) 0x03b63cc9), unchecked((int) 0x0cc844b2), + unchecked((int) 0xbcf3f0aa), unchecked((int) 0x87ac36e9), unchecked((int) 0xe53a7426), unchecked((int) 0x01b3d82b), unchecked((int) 0x1a9e7449), unchecked((int) 0x64ee2d7e), unchecked((int) 0xcddbb1da), unchecked((int) 0x01c94910), + unchecked((int) 0xb868bf80), unchecked((int) 0x0d26f3fd), unchecked((int) 0x9342ede7), unchecked((int) 0x04a5c284), unchecked((int) 0x636737b6), unchecked((int) 0x50f5b616), unchecked((int) 0xf24766e3), unchecked((int) 0x8eca36c1), + unchecked((int) 0x136e05db), unchecked((int) 0xfef18391), unchecked((int) 0xfb887a37), unchecked((int) 0xd6e7f7d4), unchecked((int) 0xc7fb7dc9), unchecked((int) 0x3063fcdf), unchecked((int) 0xb6f589de), unchecked((int) 0xec2941da), + unchecked((int) 0x26e46695), unchecked((int) 0xb7566419), unchecked((int) 0xf654efc5), unchecked((int) 0xd08d58b7), unchecked((int) 0x48925401), unchecked((int) 0xc1bacb7f), unchecked((int) 0xe5ff550f), unchecked((int) 0xb6083049), + unchecked((int) 0x5bb5d0e8), unchecked((int) 0x87d72e5a), unchecked((int) 0xab6a6ee1), unchecked((int) 0x223a66ce), unchecked((int) 0xc62bf3cd), unchecked((int) 0x9e0885f9), unchecked((int) 0x68cb3e47), unchecked((int) 0x086c010f), + unchecked((int) 0xa21de820), unchecked((int) 0xd18b69de), unchecked((int) 0xf3f65777), unchecked((int) 0xfa02c3f6), unchecked((int) 0x407edac3), unchecked((int) 0xcbb3d550), unchecked((int) 0x1793084d), unchecked((int) 0xb0d70eba), + unchecked((int) 0x0ab378d5), unchecked((int) 0xd951fb0c), unchecked((int) 0xded7da56), unchecked((int) 0x4124bbe4), unchecked((int) 0x94ca0b56), unchecked((int) 0x0f5755d1), unchecked((int) 0xe0e1e56e), unchecked((int) 0x6184b5be), + unchecked((int) 0x580a249f), unchecked((int) 0x94f74bc0), unchecked((int) 0xe327888e), unchecked((int) 0x9f7b5561), unchecked((int) 0xc3dc0280), unchecked((int) 0x05687715), unchecked((int) 0x646c6bd7), unchecked((int) 0x44904db3), + unchecked((int) 0x66b4f0a3), unchecked((int) 0xc0f1648a), unchecked((int) 0x697ed5af), unchecked((int) 0x49e92ff6), unchecked((int) 0x309e374f), unchecked((int) 0x2cb6356a), unchecked((int) 0x85808573), unchecked((int) 0x4991f840), + unchecked((int) 0x76f0ae02), unchecked((int) 0x083be84d), unchecked((int) 0x28421c9a), unchecked((int) 0x44489406), unchecked((int) 0x736e4cb8), unchecked((int) 0xc1092910), unchecked((int) 0x8bc95fc6), unchecked((int) 0x7d869cf4), + unchecked((int) 0x134f616f), unchecked((int) 0x2e77118d), unchecked((int) 0xb31b2be1), unchecked((int) 0xaa90b472), unchecked((int) 0x3ca5d717), unchecked((int) 0x7d161bba), unchecked((int) 0x9cad9010), unchecked((int) 0xaf462ba2), + unchecked((int) 0x9fe459d2), unchecked((int) 0x45d34559), unchecked((int) 0xd9f2da13), unchecked((int) 0xdbc65487), unchecked((int) 0xf3e4f94e), unchecked((int) 0x176d486f), unchecked((int) 0x097c13ea), unchecked((int) 0x631da5c7), + unchecked((int) 0x445f7382), unchecked((int) 0x175683f4), unchecked((int) 0xcdc66a97), unchecked((int) 0x70be0288), unchecked((int) 0xb3cdcf72), unchecked((int) 0x6e5dd2f3), unchecked((int) 0x20936079), unchecked((int) 0x459b80a5), + unchecked((int) 0xbe60e2db), unchecked((int) 0xa9c23101), unchecked((int) 0xeba5315c), unchecked((int) 0x224e42f2), unchecked((int) 0x1c5c1572), unchecked((int) 0xf6721b2c), unchecked((int) 0x1ad2fff3), unchecked((int) 0x8c25404e), + unchecked((int) 0x324ed72f), unchecked((int) 0x4067b7fd), unchecked((int) 0x0523138e), unchecked((int) 0x5ca3bc78), unchecked((int) 0xdc0fd66e), unchecked((int) 0x75922283), unchecked((int) 0x784d6b17), unchecked((int) 0x58ebb16e), + unchecked((int) 0x44094f85), unchecked((int) 0x3f481d87), unchecked((int) 0xfcfeae7b), unchecked((int) 0x77b5ff76), unchecked((int) 0x8c2302bf), unchecked((int) 0xaaf47556), unchecked((int) 0x5f46b02a), unchecked((int) 0x2b092801), + unchecked((int) 0x3d38f5f7), unchecked((int) 0x0ca81f36), unchecked((int) 0x52af4a8a), unchecked((int) 0x66d5e7c0), unchecked((int) 0xdf3b0874), unchecked((int) 0x95055110), unchecked((int) 0x1b5ad7a8), unchecked((int) 0xf61ed5ad), + unchecked((int) 0x6cf6e479), unchecked((int) 0x20758184), unchecked((int) 0xd0cefa65), unchecked((int) 0x88f7be58), unchecked((int) 0x4a046826), unchecked((int) 0x0ff6f8f3), unchecked((int) 0xa09c7f70), unchecked((int) 0x5346aba0), + unchecked((int) 0x5ce96c28), unchecked((int) 0xe176eda3), unchecked((int) 0x6bac307f), unchecked((int) 0x376829d2), unchecked((int) 0x85360fa9), unchecked((int) 0x17e3fe2a), unchecked((int) 0x24b79767), unchecked((int) 0xf5a96b20), + unchecked((int) 0xd6cd2595), unchecked((int) 0x68ff1ebf), unchecked((int) 0x7555442c), unchecked((int) 0xf19f06be), unchecked((int) 0xf9e0659a), unchecked((int) 0xeeb9491d), unchecked((int) 0x34010718), unchecked((int) 0xbb30cab8), + unchecked((int) 0xe822fe15), unchecked((int) 0x88570983), unchecked((int) 0x750e6249), unchecked((int) 0xda627e55), unchecked((int) 0x5e76ffa8), unchecked((int) 0xb1534546), unchecked((int) 0x6d47de08), unchecked((int) 0xefe9e7d4) + }, + S6 = + { + unchecked((int) 0xf6fa8f9d), unchecked((int) 0x2cac6ce1), unchecked((int) 0x4ca34867), unchecked((int) 0xe2337f7c), unchecked((int) 0x95db08e7), unchecked((int) 0x016843b4), unchecked((int) 0xeced5cbc), unchecked((int) 0x325553ac), + unchecked((int) 0xbf9f0960), unchecked((int) 0xdfa1e2ed), unchecked((int) 0x83f0579d), unchecked((int) 0x63ed86b9), unchecked((int) 0x1ab6a6b8), unchecked((int) 0xde5ebe39), unchecked((int) 0xf38ff732), unchecked((int) 0x8989b138), + unchecked((int) 0x33f14961), unchecked((int) 0xc01937bd), unchecked((int) 0xf506c6da), unchecked((int) 0xe4625e7e), unchecked((int) 0xa308ea99), unchecked((int) 0x4e23e33c), unchecked((int) 0x79cbd7cc), unchecked((int) 0x48a14367), + unchecked((int) 0xa3149619), unchecked((int) 0xfec94bd5), unchecked((int) 0xa114174a), unchecked((int) 0xeaa01866), unchecked((int) 0xa084db2d), unchecked((int) 0x09a8486f), unchecked((int) 0xa888614a), unchecked((int) 0x2900af98), + unchecked((int) 0x01665991), unchecked((int) 0xe1992863), unchecked((int) 0xc8f30c60), unchecked((int) 0x2e78ef3c), unchecked((int) 0xd0d51932), unchecked((int) 0xcf0fec14), unchecked((int) 0xf7ca07d2), unchecked((int) 0xd0a82072), + unchecked((int) 0xfd41197e), unchecked((int) 0x9305a6b0), unchecked((int) 0xe86be3da), unchecked((int) 0x74bed3cd), unchecked((int) 0x372da53c), unchecked((int) 0x4c7f4448), unchecked((int) 0xdab5d440), unchecked((int) 0x6dba0ec3), + unchecked((int) 0x083919a7), unchecked((int) 0x9fbaeed9), unchecked((int) 0x49dbcfb0), unchecked((int) 0x4e670c53), unchecked((int) 0x5c3d9c01), unchecked((int) 0x64bdb941), unchecked((int) 0x2c0e636a), unchecked((int) 0xba7dd9cd), + unchecked((int) 0xea6f7388), unchecked((int) 0xe70bc762), unchecked((int) 0x35f29adb), unchecked((int) 0x5c4cdd8d), unchecked((int) 0xf0d48d8c), unchecked((int) 0xb88153e2), unchecked((int) 0x08a19866), unchecked((int) 0x1ae2eac8), + unchecked((int) 0x284caf89), unchecked((int) 0xaa928223), unchecked((int) 0x9334be53), unchecked((int) 0x3b3a21bf), unchecked((int) 0x16434be3), unchecked((int) 0x9aea3906), unchecked((int) 0xefe8c36e), unchecked((int) 0xf890cdd9), + unchecked((int) 0x80226dae), unchecked((int) 0xc340a4a3), unchecked((int) 0xdf7e9c09), unchecked((int) 0xa694a807), unchecked((int) 0x5b7c5ecc), unchecked((int) 0x221db3a6), unchecked((int) 0x9a69a02f), unchecked((int) 0x68818a54), + unchecked((int) 0xceb2296f), unchecked((int) 0x53c0843a), unchecked((int) 0xfe893655), unchecked((int) 0x25bfe68a), unchecked((int) 0xb4628abc), unchecked((int) 0xcf222ebf), unchecked((int) 0x25ac6f48), unchecked((int) 0xa9a99387), + unchecked((int) 0x53bddb65), unchecked((int) 0xe76ffbe7), unchecked((int) 0xe967fd78), unchecked((int) 0x0ba93563), unchecked((int) 0x8e342bc1), unchecked((int) 0xe8a11be9), unchecked((int) 0x4980740d), unchecked((int) 0xc8087dfc), + unchecked((int) 0x8de4bf99), unchecked((int) 0xa11101a0), unchecked((int) 0x7fd37975), unchecked((int) 0xda5a26c0), unchecked((int) 0xe81f994f), unchecked((int) 0x9528cd89), unchecked((int) 0xfd339fed), unchecked((int) 0xb87834bf), + unchecked((int) 0x5f04456d), unchecked((int) 0x22258698), unchecked((int) 0xc9c4c83b), unchecked((int) 0x2dc156be), unchecked((int) 0x4f628daa), unchecked((int) 0x57f55ec5), unchecked((int) 0xe2220abe), unchecked((int) 0xd2916ebf), + unchecked((int) 0x4ec75b95), unchecked((int) 0x24f2c3c0), unchecked((int) 0x42d15d99), unchecked((int) 0xcd0d7fa0), unchecked((int) 0x7b6e27ff), unchecked((int) 0xa8dc8af0), unchecked((int) 0x7345c106), unchecked((int) 0xf41e232f), + unchecked((int) 0x35162386), unchecked((int) 0xe6ea8926), unchecked((int) 0x3333b094), unchecked((int) 0x157ec6f2), unchecked((int) 0x372b74af), unchecked((int) 0x692573e4), unchecked((int) 0xe9a9d848), unchecked((int) 0xf3160289), + unchecked((int) 0x3a62ef1d), unchecked((int) 0xa787e238), unchecked((int) 0xf3a5f676), unchecked((int) 0x74364853), unchecked((int) 0x20951063), unchecked((int) 0x4576698d), unchecked((int) 0xb6fad407), unchecked((int) 0x592af950), + unchecked((int) 0x36f73523), unchecked((int) 0x4cfb6e87), unchecked((int) 0x7da4cec0), unchecked((int) 0x6c152daa), unchecked((int) 0xcb0396a8), unchecked((int) 0xc50dfe5d), unchecked((int) 0xfcd707ab), unchecked((int) 0x0921c42f), + unchecked((int) 0x89dff0bb), unchecked((int) 0x5fe2be78), unchecked((int) 0x448f4f33), unchecked((int) 0x754613c9), unchecked((int) 0x2b05d08d), unchecked((int) 0x48b9d585), unchecked((int) 0xdc049441), unchecked((int) 0xc8098f9b), + unchecked((int) 0x7dede786), unchecked((int) 0xc39a3373), unchecked((int) 0x42410005), unchecked((int) 0x6a091751), unchecked((int) 0x0ef3c8a6), unchecked((int) 0x890072d6), unchecked((int) 0x28207682), unchecked((int) 0xa9a9f7be), + unchecked((int) 0xbf32679d), unchecked((int) 0xd45b5b75), unchecked((int) 0xb353fd00), unchecked((int) 0xcbb0e358), unchecked((int) 0x830f220a), unchecked((int) 0x1f8fb214), unchecked((int) 0xd372cf08), unchecked((int) 0xcc3c4a13), + unchecked((int) 0x8cf63166), unchecked((int) 0x061c87be), unchecked((int) 0x88c98f88), unchecked((int) 0x6062e397), unchecked((int) 0x47cf8e7a), unchecked((int) 0xb6c85283), unchecked((int) 0x3cc2acfb), unchecked((int) 0x3fc06976), + unchecked((int) 0x4e8f0252), unchecked((int) 0x64d8314d), unchecked((int) 0xda3870e3), unchecked((int) 0x1e665459), unchecked((int) 0xc10908f0), unchecked((int) 0x513021a5), unchecked((int) 0x6c5b68b7), unchecked((int) 0x822f8aa0), + unchecked((int) 0x3007cd3e), unchecked((int) 0x74719eef), unchecked((int) 0xdc872681), unchecked((int) 0x073340d4), unchecked((int) 0x7e432fd9), unchecked((int) 0x0c5ec241), unchecked((int) 0x8809286c), unchecked((int) 0xf592d891), + unchecked((int) 0x08a930f6), unchecked((int) 0x957ef305), unchecked((int) 0xb7fbffbd), unchecked((int) 0xc266e96f), unchecked((int) 0x6fe4ac98), unchecked((int) 0xb173ecc0), unchecked((int) 0xbc60b42a), unchecked((int) 0x953498da), + unchecked((int) 0xfba1ae12), unchecked((int) 0x2d4bd736), unchecked((int) 0x0f25faab), unchecked((int) 0xa4f3fceb), unchecked((int) 0xe2969123), unchecked((int) 0x257f0c3d), unchecked((int) 0x9348af49), unchecked((int) 0x361400bc), + unchecked((int) 0xe8816f4a), unchecked((int) 0x3814f200), unchecked((int) 0xa3f94043), unchecked((int) 0x9c7a54c2), unchecked((int) 0xbc704f57), unchecked((int) 0xda41e7f9), unchecked((int) 0xc25ad33a), unchecked((int) 0x54f4a084), + unchecked((int) 0xb17f5505), unchecked((int) 0x59357cbe), unchecked((int) 0xedbd15c8), unchecked((int) 0x7f97c5ab), unchecked((int) 0xba5ac7b5), unchecked((int) 0xb6f6deaf), unchecked((int) 0x3a479c3a), unchecked((int) 0x5302da25), + unchecked((int) 0x653d7e6a), unchecked((int) 0x54268d49), unchecked((int) 0x51a477ea), unchecked((int) 0x5017d55b), unchecked((int) 0xd7d25d88), unchecked((int) 0x44136c76), unchecked((int) 0x0404a8c8), unchecked((int) 0xb8e5a121), + unchecked((int) 0xb81a928a), unchecked((int) 0x60ed5869), unchecked((int) 0x97c55b96), unchecked((int) 0xeaec991b), unchecked((int) 0x29935913), unchecked((int) 0x01fdb7f1), unchecked((int) 0x088e8dfa), unchecked((int) 0x9ab6f6f5), + unchecked((int) 0x3b4cbf9f), unchecked((int) 0x4a5de3ab), unchecked((int) 0xe6051d35), unchecked((int) 0xa0e1d855), unchecked((int) 0xd36b4cf1), unchecked((int) 0xf544edeb), unchecked((int) 0xb0e93524), unchecked((int) 0xbebb8fbd), + unchecked((int) 0xa2d762cf), unchecked((int) 0x49c92f54), unchecked((int) 0x38b5f331), unchecked((int) 0x7128a454), unchecked((int) 0x48392905), unchecked((int) 0xa65b1db8), unchecked((int) 0x851c97bd), unchecked((int) 0xd675cf2f) + }, + S7 = + { + unchecked((int) 0x85e04019), unchecked((int) 0x332bf567), unchecked((int) 0x662dbfff), unchecked((int) 0xcfc65693), unchecked((int) 0x2a8d7f6f), unchecked((int) 0xab9bc912), unchecked((int) 0xde6008a1), unchecked((int) 0x2028da1f), + unchecked((int) 0x0227bce7), unchecked((int) 0x4d642916), unchecked((int) 0x18fac300), unchecked((int) 0x50f18b82), unchecked((int) 0x2cb2cb11), unchecked((int) 0xb232e75c), unchecked((int) 0x4b3695f2), unchecked((int) 0xb28707de), + unchecked((int) 0xa05fbcf6), unchecked((int) 0xcd4181e9), unchecked((int) 0xe150210c), unchecked((int) 0xe24ef1bd), unchecked((int) 0xb168c381), unchecked((int) 0xfde4e789), unchecked((int) 0x5c79b0d8), unchecked((int) 0x1e8bfd43), + unchecked((int) 0x4d495001), unchecked((int) 0x38be4341), unchecked((int) 0x913cee1d), unchecked((int) 0x92a79c3f), unchecked((int) 0x089766be), unchecked((int) 0xbaeeadf4), unchecked((int) 0x1286becf), unchecked((int) 0xb6eacb19), + unchecked((int) 0x2660c200), unchecked((int) 0x7565bde4), unchecked((int) 0x64241f7a), unchecked((int) 0x8248dca9), unchecked((int) 0xc3b3ad66), unchecked((int) 0x28136086), unchecked((int) 0x0bd8dfa8), unchecked((int) 0x356d1cf2), + unchecked((int) 0x107789be), unchecked((int) 0xb3b2e9ce), unchecked((int) 0x0502aa8f), unchecked((int) 0x0bc0351e), unchecked((int) 0x166bf52a), unchecked((int) 0xeb12ff82), unchecked((int) 0xe3486911), unchecked((int) 0xd34d7516), + unchecked((int) 0x4e7b3aff), unchecked((int) 0x5f43671b), unchecked((int) 0x9cf6e037), unchecked((int) 0x4981ac83), unchecked((int) 0x334266ce), unchecked((int) 0x8c9341b7), unchecked((int) 0xd0d854c0), unchecked((int) 0xcb3a6c88), + unchecked((int) 0x47bc2829), unchecked((int) 0x4725ba37), unchecked((int) 0xa66ad22b), unchecked((int) 0x7ad61f1e), unchecked((int) 0x0c5cbafa), unchecked((int) 0x4437f107), unchecked((int) 0xb6e79962), unchecked((int) 0x42d2d816), + unchecked((int) 0x0a961288), unchecked((int) 0xe1a5c06e), unchecked((int) 0x13749e67), unchecked((int) 0x72fc081a), unchecked((int) 0xb1d139f7), unchecked((int) 0xf9583745), unchecked((int) 0xcf19df58), unchecked((int) 0xbec3f756), + unchecked((int) 0xc06eba30), unchecked((int) 0x07211b24), unchecked((int) 0x45c28829), unchecked((int) 0xc95e317f), unchecked((int) 0xbc8ec511), unchecked((int) 0x38bc46e9), unchecked((int) 0xc6e6fa14), unchecked((int) 0xbae8584a), + unchecked((int) 0xad4ebc46), unchecked((int) 0x468f508b), unchecked((int) 0x7829435f), unchecked((int) 0xf124183b), unchecked((int) 0x821dba9f), unchecked((int) 0xaff60ff4), unchecked((int) 0xea2c4e6d), unchecked((int) 0x16e39264), + unchecked((int) 0x92544a8b), unchecked((int) 0x009b4fc3), unchecked((int) 0xaba68ced), unchecked((int) 0x9ac96f78), unchecked((int) 0x06a5b79a), unchecked((int) 0xb2856e6e), unchecked((int) 0x1aec3ca9), unchecked((int) 0xbe838688), + unchecked((int) 0x0e0804e9), unchecked((int) 0x55f1be56), unchecked((int) 0xe7e5363b), unchecked((int) 0xb3a1f25d), unchecked((int) 0xf7debb85), unchecked((int) 0x61fe033c), unchecked((int) 0x16746233), unchecked((int) 0x3c034c28), + unchecked((int) 0xda6d0c74), unchecked((int) 0x79aac56c), unchecked((int) 0x3ce4e1ad), unchecked((int) 0x51f0c802), unchecked((int) 0x98f8f35a), unchecked((int) 0x1626a49f), unchecked((int) 0xeed82b29), unchecked((int) 0x1d382fe3), + unchecked((int) 0x0c4fb99a), unchecked((int) 0xbb325778), unchecked((int) 0x3ec6d97b), unchecked((int) 0x6e77a6a9), unchecked((int) 0xcb658b5c), unchecked((int) 0xd45230c7), unchecked((int) 0x2bd1408b), unchecked((int) 0x60c03eb7), + unchecked((int) 0xb9068d78), unchecked((int) 0xa33754f4), unchecked((int) 0xf430c87d), unchecked((int) 0xc8a71302), unchecked((int) 0xb96d8c32), unchecked((int) 0xebd4e7be), unchecked((int) 0xbe8b9d2d), unchecked((int) 0x7979fb06), + unchecked((int) 0xe7225308), unchecked((int) 0x8b75cf77), unchecked((int) 0x11ef8da4), unchecked((int) 0xe083c858), unchecked((int) 0x8d6b786f), unchecked((int) 0x5a6317a6), unchecked((int) 0xfa5cf7a0), unchecked((int) 0x5dda0033), + unchecked((int) 0xf28ebfb0), unchecked((int) 0xf5b9c310), unchecked((int) 0xa0eac280), unchecked((int) 0x08b9767a), unchecked((int) 0xa3d9d2b0), unchecked((int) 0x79d34217), unchecked((int) 0x021a718d), unchecked((int) 0x9ac6336a), + unchecked((int) 0x2711fd60), unchecked((int) 0x438050e3), unchecked((int) 0x069908a8), unchecked((int) 0x3d7fedc4), unchecked((int) 0x826d2bef), unchecked((int) 0x4eeb8476), unchecked((int) 0x488dcf25), unchecked((int) 0x36c9d566), + unchecked((int) 0x28e74e41), unchecked((int) 0xc2610aca), unchecked((int) 0x3d49a9cf), unchecked((int) 0xbae3b9df), unchecked((int) 0xb65f8de6), unchecked((int) 0x92aeaf64), unchecked((int) 0x3ac7d5e6), unchecked((int) 0x9ea80509), + unchecked((int) 0xf22b017d), unchecked((int) 0xa4173f70), unchecked((int) 0xdd1e16c3), unchecked((int) 0x15e0d7f9), unchecked((int) 0x50b1b887), unchecked((int) 0x2b9f4fd5), unchecked((int) 0x625aba82), unchecked((int) 0x6a017962), + unchecked((int) 0x2ec01b9c), unchecked((int) 0x15488aa9), unchecked((int) 0xd716e740), unchecked((int) 0x40055a2c), unchecked((int) 0x93d29a22), unchecked((int) 0xe32dbf9a), unchecked((int) 0x058745b9), unchecked((int) 0x3453dc1e), + unchecked((int) 0xd699296e), unchecked((int) 0x496cff6f), unchecked((int) 0x1c9f4986), unchecked((int) 0xdfe2ed07), unchecked((int) 0xb87242d1), unchecked((int) 0x19de7eae), unchecked((int) 0x053e561a), unchecked((int) 0x15ad6f8c), + unchecked((int) 0x66626c1c), unchecked((int) 0x7154c24c), unchecked((int) 0xea082b2a), unchecked((int) 0x93eb2939), unchecked((int) 0x17dcb0f0), unchecked((int) 0x58d4f2ae), unchecked((int) 0x9ea294fb), unchecked((int) 0x52cf564c), + unchecked((int) 0x9883fe66), unchecked((int) 0x2ec40581), unchecked((int) 0x763953c3), unchecked((int) 0x01d6692e), unchecked((int) 0xd3a0c108), unchecked((int) 0xa1e7160e), unchecked((int) 0xe4f2dfa6), unchecked((int) 0x693ed285), + unchecked((int) 0x74904698), unchecked((int) 0x4c2b0edd), unchecked((int) 0x4f757656), unchecked((int) 0x5d393378), unchecked((int) 0xa132234f), unchecked((int) 0x3d321c5d), unchecked((int) 0xc3f5e194), unchecked((int) 0x4b269301), + unchecked((int) 0xc79f022f), unchecked((int) 0x3c997e7e), unchecked((int) 0x5e4f9504), unchecked((int) 0x3ffafbbd), unchecked((int) 0x76f7ad0e), unchecked((int) 0x296693f4), unchecked((int) 0x3d1fce6f), unchecked((int) 0xc61e45be), + unchecked((int) 0xd3b5ab34), unchecked((int) 0xf72bf9b7), unchecked((int) 0x1b0434c0), unchecked((int) 0x4e72b567), unchecked((int) 0x5592a33d), unchecked((int) 0xb5229301), unchecked((int) 0xcfd2a87f), unchecked((int) 0x60aeb767), + unchecked((int) 0x1814386b), unchecked((int) 0x30bcc33d), unchecked((int) 0x38a0c07d), unchecked((int) 0xfd1606f2), unchecked((int) 0xc363519b), unchecked((int) 0x589dd390), unchecked((int) 0x5479f8e6), unchecked((int) 0x1cb8d647), + unchecked((int) 0x97fd61a9), unchecked((int) 0xea7759f4), unchecked((int) 0x2d57539d), unchecked((int) 0x569a58cf), unchecked((int) 0xe84e63ad), unchecked((int) 0x462e1b78), unchecked((int) 0x6580f87e), unchecked((int) 0xf3817914), + unchecked((int) 0x91da55f4), unchecked((int) 0x40a230f3), unchecked((int) 0xd1988f35), unchecked((int) 0xb6e318d2), unchecked((int) 0x3ffa50bc), unchecked((int) 0x3d40f021), unchecked((int) 0xc3c0bdae), unchecked((int) 0x4958c24c), + unchecked((int) 0x518f36b2), unchecked((int) 0x84b1d370), unchecked((int) 0x0fedce83), unchecked((int) 0x878ddada), unchecked((int) 0xf2a279c7), unchecked((int) 0x94e01be8), unchecked((int) 0x90716f4b), unchecked((int) 0x954b8aa3) + }, + S8 = + { + unchecked((int) 0xe216300d), unchecked((int) 0xbbddfffc), unchecked((int) 0xa7ebdabd), unchecked((int) 0x35648095), unchecked((int) 0x7789f8b7), unchecked((int) 0xe6c1121b), unchecked((int) 0x0e241600), unchecked((int) 0x052ce8b5), + unchecked((int) 0x11a9cfb0), unchecked((int) 0xe5952f11), unchecked((int) 0xece7990a), unchecked((int) 0x9386d174), unchecked((int) 0x2a42931c), unchecked((int) 0x76e38111), unchecked((int) 0xb12def3a), unchecked((int) 0x37ddddfc), + unchecked((int) 0xde9adeb1), unchecked((int) 0x0a0cc32c), unchecked((int) 0xbe197029), unchecked((int) 0x84a00940), unchecked((int) 0xbb243a0f), unchecked((int) 0xb4d137cf), unchecked((int) 0xb44e79f0), unchecked((int) 0x049eedfd), + unchecked((int) 0x0b15a15d), unchecked((int) 0x480d3168), unchecked((int) 0x8bbbde5a), unchecked((int) 0x669ded42), unchecked((int) 0xc7ece831), unchecked((int) 0x3f8f95e7), unchecked((int) 0x72df191b), unchecked((int) 0x7580330d), + unchecked((int) 0x94074251), unchecked((int) 0x5c7dcdfa), unchecked((int) 0xabbe6d63), unchecked((int) 0xaa402164), unchecked((int) 0xb301d40a), unchecked((int) 0x02e7d1ca), unchecked((int) 0x53571dae), unchecked((int) 0x7a3182a2), + unchecked((int) 0x12a8ddec), unchecked((int) 0xfdaa335d), unchecked((int) 0x176f43e8), unchecked((int) 0x71fb46d4), unchecked((int) 0x38129022), unchecked((int) 0xce949ad4), unchecked((int) 0xb84769ad), unchecked((int) 0x965bd862), + unchecked((int) 0x82f3d055), unchecked((int) 0x66fb9767), unchecked((int) 0x15b80b4e), unchecked((int) 0x1d5b47a0), unchecked((int) 0x4cfde06f), unchecked((int) 0xc28ec4b8), unchecked((int) 0x57e8726e), unchecked((int) 0x647a78fc), + unchecked((int) 0x99865d44), unchecked((int) 0x608bd593), unchecked((int) 0x6c200e03), unchecked((int) 0x39dc5ff6), unchecked((int) 0x5d0b00a3), unchecked((int) 0xae63aff2), unchecked((int) 0x7e8bd632), unchecked((int) 0x70108c0c), + unchecked((int) 0xbbd35049), unchecked((int) 0x2998df04), unchecked((int) 0x980cf42a), unchecked((int) 0x9b6df491), unchecked((int) 0x9e7edd53), unchecked((int) 0x06918548), unchecked((int) 0x58cb7e07), unchecked((int) 0x3b74ef2e), + unchecked((int) 0x522fffb1), unchecked((int) 0xd24708cc), unchecked((int) 0x1c7e27cd), unchecked((int) 0xa4eb215b), unchecked((int) 0x3cf1d2e2), unchecked((int) 0x19b47a38), unchecked((int) 0x424f7618), unchecked((int) 0x35856039), + unchecked((int) 0x9d17dee7), unchecked((int) 0x27eb35e6), unchecked((int) 0xc9aff67b), unchecked((int) 0x36baf5b8), unchecked((int) 0x09c467cd), unchecked((int) 0xc18910b1), unchecked((int) 0xe11dbf7b), unchecked((int) 0x06cd1af8), + unchecked((int) 0x7170c608), unchecked((int) 0x2d5e3354), unchecked((int) 0xd4de495a), unchecked((int) 0x64c6d006), unchecked((int) 0xbcc0c62c), unchecked((int) 0x3dd00db3), unchecked((int) 0x708f8f34), unchecked((int) 0x77d51b42), + unchecked((int) 0x264f620f), unchecked((int) 0x24b8d2bf), unchecked((int) 0x15c1b79e), unchecked((int) 0x46a52564), unchecked((int) 0xf8d7e54e), unchecked((int) 0x3e378160), unchecked((int) 0x7895cda5), unchecked((int) 0x859c15a5), + unchecked((int) 0xe6459788), unchecked((int) 0xc37bc75f), unchecked((int) 0xdb07ba0c), unchecked((int) 0x0676a3ab), unchecked((int) 0x7f229b1e), unchecked((int) 0x31842e7b), unchecked((int) 0x24259fd7), unchecked((int) 0xf8bef472), + unchecked((int) 0x835ffcb8), unchecked((int) 0x6df4c1f2), unchecked((int) 0x96f5b195), unchecked((int) 0xfd0af0fc), unchecked((int) 0xb0fe134c), unchecked((int) 0xe2506d3d), unchecked((int) 0x4f9b12ea), unchecked((int) 0xf215f225), + unchecked((int) 0xa223736f), unchecked((int) 0x9fb4c428), unchecked((int) 0x25d04979), unchecked((int) 0x34c713f8), unchecked((int) 0xc4618187), unchecked((int) 0xea7a6e98), unchecked((int) 0x7cd16efc), unchecked((int) 0x1436876c), + unchecked((int) 0xf1544107), unchecked((int) 0xbedeee14), unchecked((int) 0x56e9af27), unchecked((int) 0xa04aa441), unchecked((int) 0x3cf7c899), unchecked((int) 0x92ecbae6), unchecked((int) 0xdd67016d), unchecked((int) 0x151682eb), + unchecked((int) 0xa842eedf), unchecked((int) 0xfdba60b4), unchecked((int) 0xf1907b75), unchecked((int) 0x20e3030f), unchecked((int) 0x24d8c29e), unchecked((int) 0xe139673b), unchecked((int) 0xefa63fb8), unchecked((int) 0x71873054), + unchecked((int) 0xb6f2cf3b), unchecked((int) 0x9f326442), unchecked((int) 0xcb15a4cc), unchecked((int) 0xb01a4504), unchecked((int) 0xf1e47d8d), unchecked((int) 0x844a1be5), unchecked((int) 0xbae7dfdc), unchecked((int) 0x42cbda70), + unchecked((int) 0xcd7dae0a), unchecked((int) 0x57e85b7a), unchecked((int) 0xd53f5af6), unchecked((int) 0x20cf4d8c), unchecked((int) 0xcea4d428), unchecked((int) 0x79d130a4), unchecked((int) 0x3486ebfb), unchecked((int) 0x33d3cddc), + unchecked((int) 0x77853b53), unchecked((int) 0x37effcb5), unchecked((int) 0xc5068778), unchecked((int) 0xe580b3e6), unchecked((int) 0x4e68b8f4), unchecked((int) 0xc5c8b37e), unchecked((int) 0x0d809ea2), unchecked((int) 0x398feb7c), + unchecked((int) 0x132a4f94), unchecked((int) 0x43b7950e), unchecked((int) 0x2fee7d1c), unchecked((int) 0x223613bd), unchecked((int) 0xdd06caa2), unchecked((int) 0x37df932b), unchecked((int) 0xc4248289), unchecked((int) 0xacf3ebc3), + unchecked((int) 0x5715f6b7), unchecked((int) 0xef3478dd), unchecked((int) 0xf267616f), unchecked((int) 0xc148cbe4), unchecked((int) 0x9052815e), unchecked((int) 0x5e410fab), unchecked((int) 0xb48a2465), unchecked((int) 0x2eda7fa4), + unchecked((int) 0xe87b40e4), unchecked((int) 0xe98ea084), unchecked((int) 0x5889e9e1), unchecked((int) 0xefd390fc), unchecked((int) 0xdd07d35b), unchecked((int) 0xdb485694), unchecked((int) 0x38d7e5b2), unchecked((int) 0x57720101), + unchecked((int) 0x730edebc), unchecked((int) 0x5b643113), unchecked((int) 0x94917e4f), unchecked((int) 0x503c2fba), unchecked((int) 0x646f1282), unchecked((int) 0x7523d24a), unchecked((int) 0xe0779695), unchecked((int) 0xf9c17a8f), + unchecked((int) 0x7a5b2121), unchecked((int) 0xd187b896), unchecked((int) 0x29263a4d), unchecked((int) 0xba510cdf), unchecked((int) 0x81f47c9f), unchecked((int) 0xad1163ed), unchecked((int) 0xea7b5965), unchecked((int) 0x1a00726e), + unchecked((int) 0x11403092), unchecked((int) 0x00da6d77), unchecked((int) 0x4a0cdd61), unchecked((int) 0xad1f4603), unchecked((int) 0x605bdfb0), unchecked((int) 0x9eedc364), unchecked((int) 0x22ebe6a8), unchecked((int) 0xcee7d28a), + unchecked((int) 0xa0e736a0), unchecked((int) 0x5564a6b9), unchecked((int) 0x10853209), unchecked((int) 0xc7eb8f37), unchecked((int) 0x2de705ca), unchecked((int) 0x8951570f), unchecked((int) 0xdf09822b), unchecked((int) 0xbd691a6c), + unchecked((int) 0xaa12e4f2), unchecked((int) 0x87451c0f), unchecked((int) 0xe0f6a27a), unchecked((int) 0x3ada4819), unchecked((int) 0x4cf1764f), unchecked((int) 0x0d771c2b), unchecked((int) 0x67cdb156), unchecked((int) 0x350d8384), + unchecked((int) 0x5938fa0f), unchecked((int) 0x42399ef3), unchecked((int) 0x36997b07), unchecked((int) 0x0e84093d), unchecked((int) 0x4aa93e61), unchecked((int) 0x8360d87b), unchecked((int) 0x1fa98b0c), unchecked((int) 0x1149382c), + unchecked((int) 0xe97625a5), unchecked((int) 0x0614d1b7), unchecked((int) 0x0e25244b), unchecked((int) 0x0c768347), unchecked((int) 0x589e8d82), unchecked((int) 0x0d2059d1), unchecked((int) 0xa466bb1e), unchecked((int) 0xf8da0a82), + unchecked((int) 0x04f19130), unchecked((int) 0xba6e4ec0), unchecked((int) 0x99265164), unchecked((int) 0x1ee7230d), unchecked((int) 0x50b2ad80), unchecked((int) 0xeaee6801), unchecked((int) 0x8db2a283), unchecked((int) 0xea8bf59e) + }; + + //==================================== + // Useful constants + //==================================== + + internal static readonly int MAX_ROUNDS = 16; + internal static readonly int RED_ROUNDS = 12; + + private const int BLOCK_SIZE = 8; // bytes = 64 bits + + private int [] _Kr = new int[17]; // the rotating round key + private int [] _Km = new int[17]; // the masking round key + + private bool _encrypting; + + private byte[] _workingKey; + private int _rounds = MAX_ROUNDS; + + public Cast5Engine() + { + } + + /** + * initialise a CAST cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + parameters.GetType().ToString()); + + _encrypting = forEncryption; + _workingKey = ((KeyParameter)parameters).GetKey(); + SetKey(_workingKey); + } + + public virtual string AlgorithmName + { + get { return "CAST5"; } + } + + public virtual bool IsPartialBlockOkay + { + get { return false; } + } + + public virtual int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + int blockSize = GetBlockSize(); + if (_workingKey == null) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + if ((inOff + blockSize) > input.Length) + throw new DataLengthException("Input buffer too short"); + if ((outOff + blockSize) > output.Length) + throw new DataLengthException("Output buffer too short"); + + if (_encrypting) + { + return EncryptBlock(input, inOff, output, outOff); + } + else + { + return DecryptBlock(input, inOff, output, outOff); + } + } + + public virtual void Reset() + { + } + + public virtual int GetBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + + /* + * Creates the subkeys using the same nomenclature + * as described in RFC2144. + * + * See section 2.4 + */ + internal virtual void SetKey(byte[] key) + { + /* + * Determine the key size here, if required + * + * if keysize <= 80bits, use 12 rounds instead of 16 + * if keysize < 128bits, pad with 0 + * + * Typical key sizes => 40, 64, 80, 128 + */ + + if (key.Length < 11) + { + _rounds = RED_ROUNDS; + } + + int [] z = new int[16]; + int [] x = new int[16]; + + int z03, z47, z8B, zCF; + int x03, x47, x8B, xCF; + + /* copy the key into x */ + for (int i=0; i< key.Length; i++) + { + x[i] = (int)(key[i] & 0xff); + } + + /* + * This will look different because the selection of + * bytes from the input key I've already chosen the + * correct int. + */ + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]]; + _Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]]; + _Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]]; + _Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]]; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]]; + _Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]]; + _Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]]; + _Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]]; + + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]]; + _Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]]; + _Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]]; + _Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]]; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]]; + _Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]]; + _Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]]; + _Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]]; + + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Kr[ 1]=(S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f; + _Kr[ 2]=(S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f; + _Kr[ 3]=(S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f; + _Kr[ 4]=(S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Kr[ 5]=(S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f; + _Kr[ 6]=(S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f; + _Kr[ 7]=(S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f; + _Kr[ 8]=(S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f; + + x03 = IntsTo32bits(x, 0x0); + x47 = IntsTo32bits(x, 0x4); + x8B = IntsTo32bits(x, 0x8); + xCF = IntsTo32bits(x, 0xC); + z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]]; + Bits32ToInts(z03, z, 0x0); + z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]]; + Bits32ToInts(z47, z, 0x4); + z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]]; + Bits32ToInts(z8B, z, 0x8); + zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]]; + Bits32ToInts(zCF, z, 0xC); + _Kr[ 9]=(S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f; + _Kr[10]=(S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f; + _Kr[11]=(S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f; + _Kr[12]=(S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f; + + z03 = IntsTo32bits(z, 0x0); + z47 = IntsTo32bits(z, 0x4); + z8B = IntsTo32bits(z, 0x8); + zCF = IntsTo32bits(z, 0xC); + x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]]; + Bits32ToInts(x03, x, 0x0); + x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]]; + Bits32ToInts(x47, x, 0x4); + x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]]; + Bits32ToInts(x8B, x, 0x8); + xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]]; + Bits32ToInts(xCF, x, 0xC); + _Kr[13]=(S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f; + _Kr[14]=(S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f; + _Kr[15]=(S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f; + _Kr[16]=(S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f; + } + + /** + * Encrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + internal virtual int EncryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int [] result = new int[2]; + + // process the input block + // batch the units up into a 32 bit chunk and go for it + // the array is in bytes, the increment is 8x8 bits = 64 + + int L0 = BytesTo32bits(src, srcIndex); + int R0 = BytesTo32bits(src, srcIndex + 4); + + CAST_Encipher(L0, R0, result); + + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex + 4); + + return BLOCK_SIZE; + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + internal virtual int DecryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int [] result = new int[2]; + + // process the input block + // batch the units up into a 32 bit chunk and go for it + // the array is in bytes, the increment is 8x8 bits = 64 + int L16 = BytesTo32bits(src, srcIndex); + int R16 = BytesTo32bits(src, srcIndex+4); + + CAST_Decipher(L16, R16, result); + + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex+4); + + return BLOCK_SIZE; + } + + /** + * The first of the three processing functions for the + * encryption and decryption. + * + * @param D the input to be processed + * @param Kmi the mask to be used from Km[n] + * @param Kri the rotation value to be used + * + */ + internal static int F1(int D, int Kmi, int Kri) + { + int I = Kmi + D; + I = I << Kri | (int) ((uint) I >> (32-Kri)); + return ((S1[((uint) I >>24)&0xff]^S2[((uint)I>>16)&0xff])-S3[((uint)I>> 8)&0xff])+ + S4[(I )&0xff]; + } + + /** + * The second of the three processing functions for the + * encryption and decryption. + * + * @param D the input to be processed + * @param Kmi the mask to be used from Km[n] + * @param Kri the rotation value to be used + * + */ + internal static int F2(int D, int Kmi, int Kri) + { + int I = Kmi ^ D; + I = I << Kri | (int) ((uint)I >> (32-Kri)); + return ((S1[((uint)I>>24)&0xff]-S2[((uint)I>>16)&0xff])+S3[((uint)I>> 8)&0xff])^ + S4[(I )&0xff]; + } + + /** + * The third of the three processing functions for the + * encryption and decryption. + * + * @param D the input to be processed + * @param Kmi the mask to be used from Km[n] + * @param Kri the rotation value to be used + * + */ + internal static int F3(int D, int Kmi, int Kri) + { + int I = Kmi - D; + I = I << Kri | (int) ((uint)I >> (32-Kri)); + return ((S1[((uint)I>>24)&0xff]+S2[((uint)I>>16)&0xff])^S3[((uint)I>> 8)&0xff])- + S4[(I )&0xff]; + } + + /** + * Does the 16 rounds to encrypt the block. + * + * @param L0 the LH-32bits of the plaintext block + * @param R0 the RH-32bits of the plaintext block + */ + internal void CAST_Encipher(int L0, int R0, int [] result) + { + int Lp = L0; // the previous value, equiv to L[i-1] + int Rp = R0; // equivalent to R[i-1] + + /* + * numbering consistent with paper to make + * checking and validating easier + */ + int Li = L0, Ri = R0; + + for (int i = 1; i<=_rounds ; i++) + { + Lp = Li; + Rp = Ri; + + Li = Rp; + switch (i) + { + case 1: + case 4: + case 7: + case 10: + case 13: + case 16: + Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]); + break; + case 2: + case 5: + case 8: + case 11: + case 14: + Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]); + break; + case 3: + case 6: + case 9: + case 12: + case 15: + Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]); + break; + } + } + + result[0] = Ri; + result[1] = Li; + + return; + } + + internal void CAST_Decipher(int L16, int R16, int [] result) + { + int Lp = L16; // the previous value, equiv to L[i-1] + int Rp = R16; // equivalent to R[i-1] + + /* + * numbering consistent with paper to make + * checking and validating easier + */ + int Li = L16, Ri = R16; + + for (int i = _rounds; i > 0; i--) + { + Lp = Li; + Rp = Ri; + + Li = Rp; + switch (i) + { + case 1: + case 4: + case 7: + case 10: + case 13: + case 16: + Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]); + break; + case 2: + case 5: + case 8: + case 11: + case 14: + Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]); + break; + case 3: + case 6: + case 9: + case 12: + case 15: + Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]); + break; + } + } + + result[0] = Ri; + result[1] = Li; + + return; + } + + internal static void Bits32ToInts(int inData, int[] b, int offset) + { + b[offset + 3] = (inData & 0xff); + b[offset + 2] = (int) (((uint) inData >> 8) & 0xff); + b[offset + 1] = (int) (((uint)inData >> 16) & 0xff); + b[offset] = (int) (((uint)inData >> 24) & 0xff); + } + + internal static int IntsTo32bits(int[] b, int i) + { + int rv = 0; + + rv = ((b[i] & 0xff) << 24) | + ((b[i+1] & 0xff) << 16) | + ((b[i+2] & 0xff) << 8) | + ((b[i+3] & 0xff)); + + return rv; + } + + internal static void Bits32ToBytes(int inData, byte[] b, int offset) + { + b[offset + 3] = (byte)inData; + b[offset + 2] = (byte)((uint)inData >> 8); + b[offset + 1] = (byte)((uint)inData >> 16); + b[offset] = (byte)((uint)inData >> 24); + } + + internal static int BytesTo32bits(byte[] b, int i) + { + return ((b[i] & 0xff) << 24) | + ((b[i+1] & 0xff) << 16) | + ((b[i+2] & 0xff) << 8) | + ((b[i+3] & 0xff)); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/Cast6Engine.cs b/iTechSharp/srcbc/crypto/engines/Cast6Engine.cs new file mode 100644 index 0000000..b2f9f95 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/Cast6Engine.cs @@ -0,0 +1,277 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * A class that provides CAST6 key encryption operations, + * such as encoding data and generating keys. + * + * All the algorithms herein are from the Internet RFC + * + * RFC2612 - CAST6 (128bit block, 128-256bit key) + * + * and implement a simplified cryptography interface. + */ + public sealed class Cast6Engine + : Cast5Engine + { + //==================================== + // Useful constants + //==================================== + private const int ROUNDS = 12; + private const int BLOCK_SIZE = 16; // bytes = 128 bits + + /* + * Put the round and mask keys into an array. + * Kr0[i] => _Kr[i*4 + 0] + */ + private int []_Kr = new int[ROUNDS*4]; // the rotating round key(s) + private int []_Km = new int[ROUNDS*4]; // the masking round key(s) + + /* + * Key setup + */ + private int []_Tr = new int[24 * 8]; + private int []_Tm = new int[24 * 8]; + private int[] _workingKey = new int[8]; + + public Cast6Engine() + { + } + + public override string AlgorithmName + { + get { return "CAST6"; } + } + + public override void Reset() + { + } + + public override int GetBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + /* + * Creates the subkeys using the same nomenclature + * as described in RFC2612. + * + * See section 2.4 + */ + internal override void SetKey( + byte[] key) + { + int Cm = 0x5a827999; + int Mm = 0x6ed9eba1; + int Cr = 19; + int Mr = 17; + /* + * Determine the key size here, if required + * + * if keysize < 256 bytes, pad with 0 + * + * Typical key sizes => 128, 160, 192, 224, 256 + */ + for (int i=0; i< 24; i++) + { + for (int j=0; j< 8; j++) + { + _Tm[i*8 + j] = Cm; + Cm += Mm; //mod 2^32; + _Tr[i*8 + j] = Cr; + Cr = (Cr + Mr) & 0x1f; // mod 32 + } + } + + byte[] tmpKey = new byte[64]; + key.CopyTo(tmpKey, 0); + + // now create ABCDEFGH + for (int i = 0; i < 8; i++) + { + _workingKey[i] = BytesTo32bits(tmpKey, i*4); + } + + // Generate the key schedule + for (int i = 0; i < 12; i++) + { + // KAPPA <- W2i(KAPPA) + int i2 = i*2 *8; + _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]); + _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); + _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); + _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); + _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); + _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); + _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); + _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); + // KAPPA <- W2i+1(KAPPA) + i2 = (i*2 + 1)*8; + _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]); + _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); + _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); + _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); + _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); + _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); + _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); + _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); + // Kr_(i) <- KAPPA + _Kr[i*4] = _workingKey[0] & 0x1f; + _Kr[i*4 + 1] = _workingKey[2] & 0x1f; + _Kr[i*4 + 2] = _workingKey[4] & 0x1f; + _Kr[i*4 + 3] = _workingKey[6] & 0x1f; + // Km_(i) <- KAPPA + _Km[i*4] = _workingKey[7]; + _Km[i*4 + 1] = _workingKey[5]; + _Km[i*4 + 2] = _workingKey[3]; + _Km[i*4 + 3] = _workingKey[1]; + } + } + + /** + * Encrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + internal override int EncryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int[] result = new int[4]; + // process the input block + // batch the units up into 4x32 bit chunks and go for it + int A = BytesTo32bits(src, srcIndex); + int B = BytesTo32bits(src, srcIndex + 4); + int C = BytesTo32bits(src, srcIndex + 8); + int D = BytesTo32bits(src, srcIndex + 12); + CAST_Encipher(A, B, C, D, result); + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex + 4); + Bits32ToBytes(result[2], dst, dstIndex + 8); + Bits32ToBytes(result[3], dst, dstIndex + 12); + return BLOCK_SIZE; + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param src The plaintext buffer + * @param srcIndex An offset into src + * @param dst The ciphertext buffer + * @param dstIndex An offset into dst + */ + internal override int DecryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int[] result = new int[4]; + // process the input block + // batch the units up into 4x32 bit chunks and go for it + int A = BytesTo32bits(src, srcIndex); + int B = BytesTo32bits(src, srcIndex + 4); + int C = BytesTo32bits(src, srcIndex + 8); + int D = BytesTo32bits(src, srcIndex + 12); + CAST_Decipher(A, B, C, D, result); + // now stuff them into the destination block + Bits32ToBytes(result[0], dst, dstIndex); + Bits32ToBytes(result[1], dst, dstIndex + 4); + Bits32ToBytes(result[2], dst, dstIndex + 8); + Bits32ToBytes(result[3], dst, dstIndex + 12); + return BLOCK_SIZE; + } + + /** + * Does the 12 quad rounds rounds to encrypt the block. + * + * @param A the 00-31 bits of the plaintext block + * @param B the 32-63 bits of the plaintext block + * @param C the 64-95 bits of the plaintext block + * @param D the 96-127 bits of the plaintext block + * @param result the resulting ciphertext + */ + private void CAST_Encipher( + int A, + int B, + int C, + int D, + int[] result) + { + for (int i = 0; i < 6; i++) + { + int x = i*4; + // BETA <- Qi(BETA) + C ^= F1(D, _Km[x], _Kr[x]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + } + for (int i = 6; i < 12; i++) + { + int x = i*4; + // BETA <- QBARi(BETA) + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + C ^= F1(D, _Km[x], _Kr[x]); + } + result[0] = A; + result[1] = B; + result[2] = C; + result[3] = D; + } + + /** + * Does the 12 quad rounds rounds to decrypt the block. + * + * @param A the 00-31 bits of the ciphertext block + * @param B the 32-63 bits of the ciphertext block + * @param C the 64-95 bits of the ciphertext block + * @param D the 96-127 bits of the ciphertext block + * @param result the resulting plaintext + */ + private void CAST_Decipher( + int A, + int B, + int C, + int D, + int[] result) + { + for (int i = 0; i < 6; i++) + { + int x = (11-i)*4; + // BETA <- Qi(BETA) + C ^= F1(D, _Km[x], _Kr[x]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + } + for (int i=6; i<12; i++) + { + int x = (11-i)*4; + // BETA <- QBARi(BETA) + D ^= F1(A, _Km[x + 3], _Kr[x + 3]); + A ^= F3(B, _Km[x + 2], _Kr[x + 2]); + B ^= F2(C, _Km[x + 1], _Kr[x + 1]); + C ^= F1(D, _Km[x], _Kr[x]); + } + result[0] = A; + result[1] = B; + result[2] = C; + result[3] = D; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/DesEdeEngine.cs b/iTechSharp/srcbc/crypto/engines/DesEdeEngine.cs new file mode 100644 index 0000000..c06812f --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/DesEdeEngine.cs @@ -0,0 +1,96 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// A class that provides a basic DESede (or Triple DES) engine. + public class DesEdeEngine + : DesEngine + { + private int[] workingKey1, workingKey2, workingKey3; + private bool forEncryption; + + /** + * initialise a DESede cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + { + throw new ArgumentException("invalid parameter passed to DESede init - " + parameters.GetType().ToString()); + } + + byte[] keyMaster = ((KeyParameter)parameters).GetKey(); + byte[] key1 = new byte[8], key2 = new byte[8], key3 = new byte[8]; + this.forEncryption = forEncryption; + if (keyMaster.Length == 24) + { + Array.Copy(keyMaster, 0, key1, 0, key1.Length); + Array.Copy(keyMaster, 8, key2, 0, key2.Length); + Array.Copy(keyMaster, 16, key3, 0, key3.Length); + workingKey1 = GenerateWorkingKey(forEncryption, key1); + workingKey2 = GenerateWorkingKey(!forEncryption, key2); + workingKey3 = GenerateWorkingKey(forEncryption, key3); + } + else // 16 byte key + { + Array.Copy(keyMaster, 0, key1, 0, key1.Length); + Array.Copy(keyMaster, 8, key2, 0, key2.Length); + workingKey1 = GenerateWorkingKey(forEncryption, key1); + workingKey2 = GenerateWorkingKey(!forEncryption, key2); + workingKey3 = workingKey1; + } + } + + public override string AlgorithmName + { + get { return "DESede"; } + } + + public override int GetBlockSize() + { + return BLOCK_SIZE; + } + + public override int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey1 == null) + throw new InvalidOperationException("DESede engine not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (forEncryption) + { + DesFunc(workingKey1, input, inOff, output, outOff); + DesFunc(workingKey2, output, outOff, output, outOff); + DesFunc(workingKey3, output, outOff, output, outOff); + } + else + { + DesFunc(workingKey3, input, inOff, output, outOff); + DesFunc(workingKey2, output, outOff, output, outOff); + DesFunc(workingKey1, output, outOff, output, outOff); + } + + return BLOCK_SIZE; + } + + public override void Reset() + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/DesEdeWrapEngine.cs b/iTechSharp/srcbc/crypto/engines/DesEdeWrapEngine.cs new file mode 100644 index 0000000..62837f5 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/DesEdeWrapEngine.cs @@ -0,0 +1,299 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Wrap keys according to + * + * draft-ietf-smime-key-wrap-01.txt. + *

      + * Note: + *

        + *
      • this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.
      • + *
      • if you are using this to wrap triple-des keys you need to set the + * parity bits on the key and, if it's a two-key triple-des key, pad it + * yourself.
      • + *
      + *

      + */ + public class DesEdeWrapEngine + : IWrapper + { + /** Field engine */ + private CbcBlockCipher engine; + /** Field param */ + private KeyParameter param; + /** Field paramPlusIV */ + private ParametersWithIV paramPlusIV; + /** Field iv */ + private byte[] iv; + /** Field forWrapping */ + private bool forWrapping; + /** Field IV2 */ + private static readonly byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2, + (byte) 0x2c, (byte) 0x79, (byte) 0xe8, + (byte) 0x21, (byte) 0x05 }; + + // + // checksum digest + // + private readonly IDigest sha1 = new Sha1Digest(); + private readonly byte[] digest = new byte[20]; + + /** + * Method init + * + * @param forWrapping + * @param param + */ + public void Init( + bool forWrapping, + ICipherParameters parameters) + { + this.forWrapping = forWrapping; + this.engine = new CbcBlockCipher(new DesEdeEngine()); + + SecureRandom sr; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom pr = (ParametersWithRandom) parameters; + parameters = pr.Parameters; + sr = pr.Random; + } + else + { + sr = new SecureRandom(); + } + + if (parameters is KeyParameter) + { + this.param = (KeyParameter) parameters; + if (this.forWrapping) + { + // Hm, we have no IV but we want to wrap ?!? + // well, then we have to create our own IV. + this.iv = new byte[8]; + sr.NextBytes(iv); + + this.paramPlusIV = new ParametersWithIV(this.param, this.iv); + } + } + else if (parameters is ParametersWithIV) + { + if (!forWrapping) + throw new ArgumentException("You should not supply an IV for unwrapping"); + + this.paramPlusIV = (ParametersWithIV) parameters; + this.iv = this.paramPlusIV.GetIV(); + this.param = (KeyParameter) this.paramPlusIV.Parameters; + + if (this.iv.Length != 8) + throw new ArgumentException("IV is not 8 octets", "parameters"); + } + } + + /** + * Method GetAlgorithmName + * + * @return + */ + public string AlgorithmName + { + get { return "DESede"; } + } + + /** + * Method wrap + * + * @param in + * @param inOff + * @param inLen + * @return + */ + public byte[] Wrap( + byte[] input, + int inOff, + int length) + { + if (!forWrapping) + { + throw new InvalidOperationException("Not initialized for wrapping"); + } + + byte[] keyToBeWrapped = new byte[length]; + Array.Copy(input, inOff, keyToBeWrapped, 0, length); + // Compute the CMS Key Checksum, (section 5.6.1), call this CKS. + byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped); + // Let WKCKS = WK || CKS where || is concatenation. + byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length]; + Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length); + Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length); + // Encrypt WKCKS in CBC mode using KEK as the key and IV as the + // initialization vector. Call the results TEMP1. + byte [] TEMP1 = new byte[WKCKS.Length]; + Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length); + int noOfBlocks = WKCKS.Length / engine.GetBlockSize(); + int extraBytes = WKCKS.Length % engine.GetBlockSize(); + if (extraBytes != 0) { + throw new InvalidOperationException("Not multiple of block length"); + } + engine.Init(true, paramPlusIV); + for (int i = 0; i < noOfBlocks; i++) { + int currentBytePos = i * engine.GetBlockSize(); + engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos); + } + // Left TEMP2 = IV || TEMP1. + byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length]; + Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length); + Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length); + // Reverse the order of the octets in TEMP2 and call the result TEMP3. + byte[] TEMP3 = new byte[TEMP2.Length]; + for (int i = 0; i < TEMP2.Length; i++) { + TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)]; + } + // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector + // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired + // result. It is 40 octets long if a 168 bit key is being wrapped. + ParametersWithIV param2 = new ParametersWithIV(this.param, IV2); + this.engine.Init(true, param2); + for (int i = 0; i < noOfBlocks + 1; i++) { + int currentBytePos = i * engine.GetBlockSize(); + engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos); + } + return TEMP3; + } + + /** + * Method unwrap + * + * @param in + * @param inOff + * @param inLen + * @return + * @throws InvalidCipherTextException + */ + public byte[] Unwrap( + byte[] input, + int inOff, + int length) + { + if (forWrapping) + { + throw new InvalidOperationException("Not set for unwrapping"); + } + if (input == null) + { + throw new InvalidCipherTextException("Null pointer as ciphertext"); + } + if (length % engine.GetBlockSize() != 0) + { + throw new InvalidCipherTextException( + "Ciphertext not multiple of " + engine.GetBlockSize()); + } + + /* + // Check if the length of the cipher text is reasonable given the key + // type. It must be 40 bytes for a 168 bit key and either 32, 40, or + // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported + // or inconsistent with the algorithm for which the key is intended, + // return error. + // + // we do not accept 168 bit keys. it has to be 192 bit. + int lengthA = (estimatedKeyLengthInBit / 8) + 16; + int lengthB = estimatedKeyLengthInBit % 8; + if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) { + throw new XMLSecurityException("empty"); + } + */ + // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK + // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3. + ParametersWithIV param2 = new ParametersWithIV(this.param, IV2); + this.engine.Init(false, param2); + byte [] TEMP3 = new byte[length]; + Array.Copy(input, inOff, TEMP3, 0, length); + for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++) { + int currentBytePos = i * engine.GetBlockSize(); + engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos); + } + // Reverse the order of the octets in TEMP3 and call the result TEMP2. + byte[] TEMP2 = new byte[TEMP3.Length]; + for (int i = 0; i < TEMP3.Length; i++) { + TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)]; + } + // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets. + this.iv = new byte[8]; + byte[] TEMP1 = new byte[TEMP2.Length - 8]; + Array.Copy(TEMP2, 0, this.iv, 0, 8); + Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8); + // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV + // found in the previous step. Call the result WKCKS. + this.paramPlusIV = new ParametersWithIV(this.param, this.iv); + this.engine.Init(false, this.paramPlusIV); + byte[] WKCKS = new byte[TEMP1.Length]; + Array.Copy(TEMP1, 0, WKCKS, 0, TEMP1.Length); + for (int i = 0; i < (WKCKS.Length / engine.GetBlockSize()); i++) { + int currentBytePos = i * engine.GetBlockSize(); + engine.ProcessBlock(WKCKS, currentBytePos, WKCKS, currentBytePos); + } + // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are + // those octets before the CKS. + byte[] result = new byte[WKCKS.Length - 8]; + byte[] CKStoBeVerified = new byte[8]; + Array.Copy(WKCKS, 0, result, 0, WKCKS.Length - 8); + Array.Copy(WKCKS, WKCKS.Length - 8, CKStoBeVerified, 0, 8); + // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare + // with the CKS extracted in the above step. If they are not equal, return error. + if (!CheckCmsKeyChecksum(result, CKStoBeVerified)) { + throw new InvalidCipherTextException( + "Checksum inside ciphertext is corrupted"); + } + // WK is the wrapped key, now extracted for use in data decryption. + return result; + } + + /** + * Some key wrap algorithms make use of the Key Checksum defined + * in CMS [CMS-Algorithms]. This is used to provide an integrity + * check value for the key being wrapped. The algorithm is + * + * - Compute the 20 octet SHA-1 hash on the key being wrapped. + * - Use the first 8 octets of this hash as the checksum value. + * + * @param key + * @return + * @throws Exception + * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum + */ + private byte[] CalculateCmsKeyChecksum( + byte[] key) + { + byte[] result = new byte[8]; + + sha1.BlockUpdate(key, 0, key.Length); + sha1.DoFinal(digest, 0); + + Array.Copy(digest, 0, result, 0, 8); + + return result; + } + + /** + * @param key + * @param checksum + * @return + * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum + */ + private bool CheckCmsKeyChecksum( + byte[] key, + byte[] checksum) + { + return Arrays.AreEqual(CalculateCmsKeyChecksum(key), checksum); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/DesEngine.cs b/iTechSharp/srcbc/crypto/engines/DesEngine.cs new file mode 100644 index 0000000..281129f --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/DesEngine.cs @@ -0,0 +1,493 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// A class that provides a basic DES engine. + public class DesEngine + : IBlockCipher + { + internal const int BLOCK_SIZE = 8; + + private int[] workingKey; + + public virtual int[] GetWorkingKey() + { + return workingKey; + } + + /** + * initialise a DES cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public virtual void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to DES init - " + parameters.GetType().ToString()); + + workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey()); + } + + public virtual string AlgorithmName + { + get { return "DES"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public virtual int GetBlockSize() + { + return BLOCK_SIZE; + } + + public virtual int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + throw new InvalidOperationException("DES engine not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + DesFunc(workingKey, input, inOff, output, outOff); + + return BLOCK_SIZE; + } + + public virtual void Reset() + { + } + + /** + * what follows is mainly taken from "Applied Cryptography", by + * Bruce Schneier, however it also bears great resemblance to Richard + * Outerbridge's D3DES... + */ + + private static readonly short[] Df_Key = + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 + }; + + private static readonly short[] bytebit = + { + 128, 64, 32, 16, 8, 4, 2, 1 + }; + + private static readonly int[] bigbyte = + { + 0x800000, 0x400000, 0x200000, 0x100000, + 0x80000, 0x40000, 0x20000, 0x10000, + 0x8000, 0x4000, 0x2000, 0x1000, + 0x800, 0x400, 0x200, 0x100, + 0x80, 0x40, 0x20, 0x10, + 0x8, 0x4, 0x2, 0x1 + }; + + /* + * Use the key schedule specified in the Standard (ANSI X3.92-1981). + */ + private static readonly byte[] pc1 = + { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 + }; + + private static readonly byte[] totrot = + { + 1, 2, 4, 6, 8, 10, 12, 14, + 15, 17, 19, 21, 23, 25, 27, 28 + }; + + private static readonly byte[] pc2 = + { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 + }; + + private static readonly int[] SP1 = + { + unchecked((int) 0x01010400), unchecked((int) 0x00000000), unchecked((int) 0x00010000), unchecked((int) 0x01010404), + unchecked((int) 0x01010004), unchecked((int) 0x00010404), unchecked((int) 0x00000004), unchecked((int) 0x00010000), + unchecked((int) 0x00000400), unchecked((int) 0x01010400), unchecked((int) 0x01010404), unchecked((int) 0x00000400), + unchecked((int) 0x01000404), unchecked((int) 0x01010004), unchecked((int) 0x01000000), unchecked((int) 0x00000004), + unchecked((int) 0x00000404), unchecked((int) 0x01000400), unchecked((int) 0x01000400), unchecked((int) 0x00010400), + unchecked((int) 0x00010400), unchecked((int) 0x01010000), unchecked((int) 0x01010000), unchecked((int) 0x01000404), + unchecked((int) 0x00010004), unchecked((int) 0x01000004), unchecked((int) 0x01000004), unchecked((int) 0x00010004), + unchecked((int) 0x00000000), unchecked((int) 0x00000404), unchecked((int) 0x00010404), unchecked((int) 0x01000000), + unchecked((int) 0x00010000), unchecked((int) 0x01010404), unchecked((int) 0x00000004), unchecked((int) 0x01010000), + unchecked((int) 0x01010400), unchecked((int) 0x01000000), unchecked((int) 0x01000000), unchecked((int) 0x00000400), + unchecked((int) 0x01010004), unchecked((int) 0x00010000), unchecked((int) 0x00010400), unchecked((int) 0x01000004), + unchecked((int) 0x00000400), unchecked((int) 0x00000004), unchecked((int) 0x01000404), unchecked((int) 0x00010404), + unchecked((int) 0x01010404), unchecked((int) 0x00010004), unchecked((int) 0x01010000), unchecked((int) 0x01000404), + unchecked((int) 0x01000004), unchecked((int) 0x00000404), unchecked((int) 0x00010404), unchecked((int) 0x01010400), + unchecked((int) 0x00000404), unchecked((int) 0x01000400), unchecked((int) 0x01000400), unchecked((int) 0x00000000), + unchecked((int) 0x00010004), unchecked((int) 0x00010400), unchecked((int) 0x00000000), unchecked((int) 0x01010004) + }; + + private static readonly int[] SP2 = + { + unchecked((int) 0x80108020), unchecked((int) 0x80008000), unchecked((int) 0x00008000), unchecked((int) 0x00108020), + unchecked((int) 0x00100000), unchecked((int) 0x00000020), unchecked((int) 0x80100020), unchecked((int) 0x80008020), + unchecked((int) 0x80000020), unchecked((int) 0x80108020), unchecked((int) 0x80108000), unchecked((int) 0x80000000), + unchecked((int) 0x80008000), unchecked((int) 0x00100000), unchecked((int) 0x00000020), unchecked((int) 0x80100020), + unchecked((int) 0x00108000), unchecked((int) 0x00100020), unchecked((int) 0x80008020), unchecked((int) 0x00000000), + unchecked((int) 0x80000000), unchecked((int) 0x00008000), unchecked((int) 0x00108020), unchecked((int) 0x80100000), + unchecked((int) 0x00100020), unchecked((int) 0x80000020), unchecked((int) 0x00000000), unchecked((int) 0x00108000), + unchecked((int) 0x00008020), unchecked((int) 0x80108000), unchecked((int) 0x80100000), unchecked((int) 0x00008020), + unchecked((int) 0x00000000), unchecked((int) 0x00108020), unchecked((int) 0x80100020), unchecked((int) 0x00100000), + unchecked((int) 0x80008020), unchecked((int) 0x80100000), unchecked((int) 0x80108000), unchecked((int) 0x00008000), + unchecked((int) 0x80100000), unchecked((int) 0x80008000), unchecked((int) 0x00000020), unchecked((int) 0x80108020), + unchecked((int) 0x00108020), unchecked((int) 0x00000020), unchecked((int) 0x00008000), unchecked((int) 0x80000000), + unchecked((int) 0x00008020), unchecked((int) 0x80108000), unchecked((int) 0x00100000), unchecked((int) 0x80000020), + unchecked((int) 0x00100020), unchecked((int) 0x80008020), unchecked((int) 0x80000020), unchecked((int) 0x00100020), + unchecked((int) 0x00108000), unchecked((int) 0x00000000), unchecked((int) 0x80008000), unchecked((int) 0x00008020), + unchecked((int) 0x80000000), unchecked((int) 0x80100020), unchecked((int) 0x80108020), unchecked((int) 0x00108000) + }; + + private static readonly int[] SP3 = + { + unchecked((int) 0x00000208), unchecked((int) 0x08020200), unchecked((int) 0x00000000), unchecked((int) 0x08020008), + unchecked((int) 0x08000200), unchecked((int) 0x00000000), unchecked((int) 0x00020208), unchecked((int) 0x08000200), + unchecked((int) 0x00020008), unchecked((int) 0x08000008), unchecked((int) 0x08000008), unchecked((int) 0x00020000), + unchecked((int) 0x08020208), unchecked((int) 0x00020008), unchecked((int) 0x08020000), unchecked((int) 0x00000208), + unchecked((int) 0x08000000), unchecked((int) 0x00000008), unchecked((int) 0x08020200), unchecked((int) 0x00000200), + unchecked((int) 0x00020200), unchecked((int) 0x08020000), unchecked((int) 0x08020008), unchecked((int) 0x00020208), + unchecked((int) 0x08000208), unchecked((int) 0x00020200), unchecked((int) 0x00020000), unchecked((int) 0x08000208), + unchecked((int) 0x00000008), unchecked((int) 0x08020208), unchecked((int) 0x00000200), unchecked((int) 0x08000000), + unchecked((int) 0x08020200), unchecked((int) 0x08000000), unchecked((int) 0x00020008), unchecked((int) 0x00000208), + unchecked((int) 0x00020000), unchecked((int) 0x08020200), unchecked((int) 0x08000200), unchecked((int) 0x00000000), + unchecked((int) 0x00000200), unchecked((int) 0x00020008), unchecked((int) 0x08020208), unchecked((int) 0x08000200), + unchecked((int) 0x08000008), unchecked((int) 0x00000200), unchecked((int) 0x00000000), unchecked((int) 0x08020008), + unchecked((int) 0x08000208), unchecked((int) 0x00020000), unchecked((int) 0x08000000), unchecked((int) 0x08020208), + unchecked((int) 0x00000008), unchecked((int) 0x00020208), unchecked((int) 0x00020200), unchecked((int) 0x08000008), + unchecked((int) 0x08020000), unchecked((int) 0x08000208), unchecked((int) 0x00000208), unchecked((int) 0x08020000), + unchecked((int) 0x00020208), unchecked((int) 0x00000008), unchecked((int) 0x08020008), unchecked((int) 0x00020200) + }; + + private static readonly int[] SP4 = + { + unchecked((int) 0x00802001), unchecked((int) 0x00002081), unchecked((int) 0x00002081), unchecked((int) 0x00000080), + unchecked((int) 0x00802080), unchecked((int) 0x00800081), unchecked((int) 0x00800001), unchecked((int) 0x00002001), + unchecked((int) 0x00000000), unchecked((int) 0x00802000), unchecked((int) 0x00802000), unchecked((int) 0x00802081), + unchecked((int) 0x00000081), unchecked((int) 0x00000000), unchecked((int) 0x00800080), unchecked((int) 0x00800001), + unchecked((int) 0x00000001), unchecked((int) 0x00002000), unchecked((int) 0x00800000), unchecked((int) 0x00802001), + unchecked((int) 0x00000080), unchecked((int) 0x00800000), unchecked((int) 0x00002001), unchecked((int) 0x00002080), + unchecked((int) 0x00800081), unchecked((int) 0x00000001), unchecked((int) 0x00002080), unchecked((int) 0x00800080), + unchecked((int) 0x00002000), unchecked((int) 0x00802080), unchecked((int) 0x00802081), unchecked((int) 0x00000081), + unchecked((int) 0x00800080), unchecked((int) 0x00800001), unchecked((int) 0x00802000), unchecked((int) 0x00802081), + unchecked((int) 0x00000081), unchecked((int) 0x00000000), unchecked((int) 0x00000000), unchecked((int) 0x00802000), + unchecked((int) 0x00002080), unchecked((int) 0x00800080), unchecked((int) 0x00800081), unchecked((int) 0x00000001), + unchecked((int) 0x00802001), unchecked((int) 0x00002081), unchecked((int) 0x00002081), unchecked((int) 0x00000080), + unchecked((int) 0x00802081), unchecked((int) 0x00000081), unchecked((int) 0x00000001), unchecked((int) 0x00002000), + unchecked((int) 0x00800001), unchecked((int) 0x00002001), unchecked((int) 0x00802080), unchecked((int) 0x00800081), + unchecked((int) 0x00002001), unchecked((int) 0x00002080), unchecked((int) 0x00800000), unchecked((int) 0x00802001), + unchecked((int) 0x00000080), unchecked((int) 0x00800000), unchecked((int) 0x00002000), unchecked((int) 0x00802080) + }; + + private static readonly int[] SP5 = + { + unchecked((int) 0x00000100), unchecked((int) 0x02080100), unchecked((int) 0x02080000), unchecked((int) 0x42000100), + unchecked((int) 0x00080000), unchecked((int) 0x00000100), unchecked((int) 0x40000000), unchecked((int) 0x02080000), + unchecked((int) 0x40080100), unchecked((int) 0x00080000), unchecked((int) 0x02000100), unchecked((int) 0x40080100), + unchecked((int) 0x42000100), unchecked((int) 0x42080000), unchecked((int) 0x00080100), unchecked((int) 0x40000000), + unchecked((int) 0x02000000), unchecked((int) 0x40080000), unchecked((int) 0x40080000), unchecked((int) 0x00000000), + unchecked((int) 0x40000100), unchecked((int) 0x42080100), unchecked((int) 0x42080100), unchecked((int) 0x02000100), + unchecked((int) 0x42080000), unchecked((int) 0x40000100), unchecked((int) 0x00000000), unchecked((int) 0x42000000), + unchecked((int) 0x02080100), unchecked((int) 0x02000000), unchecked((int) 0x42000000), unchecked((int) 0x00080100), + unchecked((int) 0x00080000), unchecked((int) 0x42000100), unchecked((int) 0x00000100), unchecked((int) 0x02000000), + unchecked((int) 0x40000000), unchecked((int) 0x02080000), unchecked((int) 0x42000100), unchecked((int) 0x40080100), + unchecked((int) 0x02000100), unchecked((int) 0x40000000), unchecked((int) 0x42080000), unchecked((int) 0x02080100), + unchecked((int) 0x40080100), unchecked((int) 0x00000100), unchecked((int) 0x02000000), unchecked((int) 0x42080000), + unchecked((int) 0x42080100), unchecked((int) 0x00080100), unchecked((int) 0x42000000), unchecked((int) 0x42080100), + unchecked((int) 0x02080000), unchecked((int) 0x00000000), unchecked((int) 0x40080000), unchecked((int) 0x42000000), + unchecked((int) 0x00080100), unchecked((int) 0x02000100), unchecked((int) 0x40000100), unchecked((int) 0x00080000), + unchecked((int) 0x00000000), unchecked((int) 0x40080000), unchecked((int) 0x02080100), unchecked((int) 0x40000100) + }; + + private static readonly int[] SP6 = + { + unchecked((int) 0x20000010), unchecked((int) 0x20400000), unchecked((int) 0x00004000), unchecked((int) 0x20404010), + unchecked((int) 0x20400000), unchecked((int) 0x00000010), unchecked((int) 0x20404010), unchecked((int) 0x00400000), + unchecked((int) 0x20004000), unchecked((int) 0x00404010), unchecked((int) 0x00400000), unchecked((int) 0x20000010), + unchecked((int) 0x00400010), unchecked((int) 0x20004000), unchecked((int) 0x20000000), unchecked((int) 0x00004010), + unchecked((int) 0x00000000), unchecked((int) 0x00400010), unchecked((int) 0x20004010), unchecked((int) 0x00004000), + unchecked((int) 0x00404000), unchecked((int) 0x20004010), unchecked((int) 0x00000010), unchecked((int) 0x20400010), + unchecked((int) 0x20400010), unchecked((int) 0x00000000), unchecked((int) 0x00404010), unchecked((int) 0x20404000), + unchecked((int) 0x00004010), unchecked((int) 0x00404000), unchecked((int) 0x20404000), unchecked((int) 0x20000000), + unchecked((int) 0x20004000), unchecked((int) 0x00000010), unchecked((int) 0x20400010), unchecked((int) 0x00404000), + unchecked((int) 0x20404010), unchecked((int) 0x00400000), unchecked((int) 0x00004010), unchecked((int) 0x20000010), + unchecked((int) 0x00400000), unchecked((int) 0x20004000), unchecked((int) 0x20000000), unchecked((int) 0x00004010), + unchecked((int) 0x20000010), unchecked((int) 0x20404010), unchecked((int) 0x00404000), unchecked((int) 0x20400000), + unchecked((int) 0x00404010), unchecked((int) 0x20404000), unchecked((int) 0x00000000), unchecked((int) 0x20400010), + unchecked((int) 0x00000010), unchecked((int) 0x00004000), unchecked((int) 0x20400000), unchecked((int) 0x00404010), + unchecked((int) 0x00004000), unchecked((int) 0x00400010), unchecked((int) 0x20004010), unchecked((int) 0x00000000), + unchecked((int) 0x20404000), unchecked((int) 0x20000000), unchecked((int) 0x00400010), unchecked((int) 0x20004010) + }; + + private static readonly int[] SP7 = + { + unchecked((int) 0x00200000), unchecked((int) 0x04200002), unchecked((int) 0x04000802), unchecked((int) 0x00000000), + unchecked((int) 0x00000800), unchecked((int) 0x04000802), unchecked((int) 0x00200802), unchecked((int) 0x04200800), + unchecked((int) 0x04200802), unchecked((int) 0x00200000), unchecked((int) 0x00000000), unchecked((int) 0x04000002), + unchecked((int) 0x00000002), unchecked((int) 0x04000000), unchecked((int) 0x04200002), unchecked((int) 0x00000802), + unchecked((int) 0x04000800), unchecked((int) 0x00200802), unchecked((int) 0x00200002), unchecked((int) 0x04000800), + unchecked((int) 0x04000002), unchecked((int) 0x04200000), unchecked((int) 0x04200800), unchecked((int) 0x00200002), + unchecked((int) 0x04200000), unchecked((int) 0x00000800), unchecked((int) 0x00000802), unchecked((int) 0x04200802), + unchecked((int) 0x00200800), unchecked((int) 0x00000002), unchecked((int) 0x04000000), unchecked((int) 0x00200800), + unchecked((int) 0x04000000), unchecked((int) 0x00200800), unchecked((int) 0x00200000), unchecked((int) 0x04000802), + unchecked((int) 0x04000802), unchecked((int) 0x04200002), unchecked((int) 0x04200002), unchecked((int) 0x00000002), + unchecked((int) 0x00200002), unchecked((int) 0x04000000), unchecked((int) 0x04000800), unchecked((int) 0x00200000), + unchecked((int) 0x04200800), unchecked((int) 0x00000802), unchecked((int) 0x00200802), unchecked((int) 0x04200800), + unchecked((int) 0x00000802), unchecked((int) 0x04000002), unchecked((int) 0x04200802), unchecked((int) 0x04200000), + unchecked((int) 0x00200800), unchecked((int) 0x00000000), unchecked((int) 0x00000002), unchecked((int) 0x04200802), + unchecked((int) 0x00000000), unchecked((int) 0x00200802), unchecked((int) 0x04200000), unchecked((int) 0x00000800), + unchecked((int) 0x04000002), unchecked((int) 0x04000800), unchecked((int) 0x00000800), unchecked((int) 0x00200002) + }; + + private static readonly int[] SP8 = + { + unchecked((int) 0x10001040), unchecked((int) 0x00001000), unchecked((int) 0x00040000), unchecked((int) 0x10041040), + unchecked((int) 0x10000000), unchecked((int) 0x10001040), unchecked((int) 0x00000040), unchecked((int) 0x10000000), + unchecked((int) 0x00040040), unchecked((int) 0x10040000), unchecked((int) 0x10041040), unchecked((int) 0x00041000), + unchecked((int) 0x10041000), unchecked((int) 0x00041040), unchecked((int) 0x00001000), unchecked((int) 0x00000040), + unchecked((int) 0x10040000), unchecked((int) 0x10000040), unchecked((int) 0x10001000), unchecked((int) 0x00001040), + unchecked((int) 0x00041000), unchecked((int) 0x00040040), unchecked((int) 0x10040040), unchecked((int) 0x10041000), + unchecked((int) 0x00001040), unchecked((int) 0x00000000), unchecked((int) 0x00000000), unchecked((int) 0x10040040), + unchecked((int) 0x10000040), unchecked((int) 0x10001000), unchecked((int) 0x00041040), unchecked((int) 0x00040000), + unchecked((int) 0x00041040), unchecked((int) 0x00040000), unchecked((int) 0x10041000), unchecked((int) 0x00001000), + unchecked((int) 0x00000040), unchecked((int) 0x10040040), unchecked((int) 0x00001000), unchecked((int) 0x00041040), + unchecked((int) 0x10001000), unchecked((int) 0x00000040), unchecked((int) 0x10000040), unchecked((int) 0x10040000), + unchecked((int) 0x10040040), unchecked((int) 0x10000000), unchecked((int) 0x00040000), unchecked((int) 0x10001040), + unchecked((int) 0x00000000), unchecked((int) 0x10041040), unchecked((int) 0x00040040), unchecked((int) 0x10000040), + unchecked((int) 0x10040000), unchecked((int) 0x10001000), unchecked((int) 0x10001040), unchecked((int) 0x00000000), + unchecked((int) 0x10041040), unchecked((int) 0x00041000), unchecked((int) 0x00041000), unchecked((int) 0x00001040), + unchecked((int) 0x00001040), unchecked((int) 0x00040040), unchecked((int) 0x10000000), unchecked((int) 0x10041000) + }; + + /** + * Generate an integer based working key based on our secret key + * and what we processing we are planning to do. + * + * Acknowledgements for this routine go to James Gillogly and Phil Karn. + * (whoever, and wherever they are!). + */ + protected static int[] GenerateWorkingKey( + bool encrypting, + byte[] key) + { + int[] newKey = new int[32]; + bool[] pc1m = new bool[56]; + bool[] pcr = new bool[56]; + + for (int j = 0; j < 56; j++ ) + { + int l = pc1[j]; + + pc1m[j] = ((key[(uint) l >> 3] & bytebit[l & 07]) != 0); + } + + for (int i = 0; i < 16; i++) + { + int l, m, n; + + if (encrypting) + { + m = i << 1; + } + else + { + m = (15 - i) << 1; + } + + n = m + 1; + newKey[m] = newKey[n] = 0; + + for (int j = 0; j < 28; j++) + { + l = j + totrot[i]; + if ( l < 28 ) + { + pcr[j] = pc1m[l]; + } + else + { + pcr[j] = pc1m[l - 28]; + } + } + + for (int j = 28; j < 56; j++) + { + l = j + totrot[i]; + if (l < 56 ) + { + pcr[j] = pc1m[l]; + } + else + { + pcr[j] = pc1m[l - 28]; + } + } + + for (int j = 0; j < 24; j++) + { + if (pcr[pc2[j]]) + { + newKey[m] |= bigbyte[j]; + } + + if (pcr[pc2[j + 24]]) + { + newKey[n] |= bigbyte[j]; + } + } + } + + // + // store the processed key + // + for (int i = 0; i != 32; i += 2) + { + int i1, i2; + + i1 = newKey[i]; + i2 = newKey[i + 1]; + + newKey[i] = (int) ( (uint) ((i1 & 0x00fc0000) << 6) | + (uint) ((i1 & 0x00000fc0) << 10) | + ((uint) (i2 & 0x00fc0000) >> 10) | + ((uint) (i2 & 0x00000fc0) >> 6)); + + newKey[i + 1] = (int) ( (uint) ((i1 & 0x0003f000) << 12) | + (uint) ((i1 & 0x0000003f) << 16) | + ((uint) (i2 & 0x0003f000) >> 4) | + (uint) (i2 & 0x0000003f)); + } + + return newKey; + } + + /** + * the DES engine. + */ + internal static void DesFunc( + int[] wKey, + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int work, right, left; + + left = (input[inOff + 0] & 0xff) << 24; + left |= (input[inOff + 1] & 0xff) << 16; + left |= (input[inOff + 2] & 0xff) << 8; + left |= (input[inOff + 3] & 0xff); + + right = (input[inOff + 4] & 0xff) << 24; + right |= (input[inOff + 5] & 0xff) << 16; + right |= (input[inOff + 6] & 0xff) << 8; + right |= (input[inOff + 7] & 0xff); + + work = (int) (((uint) left >> 4) ^ right) & unchecked((int) 0x0f0f0f0f); + right ^= work; + left ^= (work << 4); + work = (int) (((uint) left >> 16) ^ right) & unchecked((int) 0x0000ffff); + right ^= work; + left ^= (work << 16); + work = (int) (((uint) right >> 2) ^ left) & unchecked((int) 0x33333333); + left ^= work; + right ^= (work << 2); + work = (int) (((uint) right >> 8) ^ left) & unchecked((int) 0x00ff00ff); + left ^= work; + right ^= (work << 8); + right = (int) ( (uint) (right << 1) | + ( ((uint) right >> 31) & 1 ) + ) & + unchecked((int) 0xffffffff); + work = (left ^ right) & unchecked((int) 0xaaaaaaaa); + left ^= work; + right ^= work; + left = (int) ( (uint) (left << 1) | + ( ((uint) left >> 31) & 1)) & + unchecked((int) 0xffffffff); + + for (int round = 0; round < 8; round++) + { + int fval; + + work = (int) ((uint) (right << 28) | ((uint) right >> 4)); + work ^= wKey[round * 4 + 0]; + fval = SP7[ work & 0x3f]; + fval |= SP5[((uint) work >> 8) & 0x3f]; + fval |= SP3[((uint) work >> 16) & 0x3f]; + fval |= SP1[((uint) work >> 24) & 0x3f]; + work = right ^ wKey[round * 4 + 1]; + fval |= SP8[ work & 0x3f]; + fval |= SP6[((uint) work >> 8) & 0x3f]; + fval |= SP4[((uint) work >> 16) & 0x3f]; + fval |= SP2[((uint) work >> 24) & 0x3f]; + left ^= fval; + work = (int) ((uint) (left << 28) | ((uint) left >> 4)); + work ^= wKey[round * 4 + 2]; + fval = SP7[ work & 0x3f]; + fval |= SP5[((uint) work >> 8) & 0x3f]; + fval |= SP3[((uint) work >> 16) & 0x3f]; + fval |= SP1[((uint) work >> 24) & 0x3f]; + work = left ^ wKey[round * 4 + 3]; + fval |= SP8[ work & 0x3f]; + fval |= SP6[((uint) work >> 8) & 0x3f]; + fval |= SP4[((uint) work >> 16) & 0x3f]; + fval |= SP2[((uint) work >> 24) & 0x3f]; + right ^= fval; + } + + right = (int) ((uint) (right << 31) | ((uint) right >> 1)); + work = (left ^ right) & unchecked((int) 0xaaaaaaaa); + left ^= work; + right ^= work; + left = (int) ((uint) (left << 31) | ((uint) left >> 1)); + work = (int) ((((uint) left >> 8) ^ right) & 0x00ff00ff); + right ^= work; + left ^= (work << 8); + work = (int) ((((uint) left >> 2) ^ right) & 0x33333333); + right ^= work; + left ^= (work << 2); + work = (int) ((((uint) right >> 16) ^ left) & 0x0000ffff); + left ^= work; + right ^= (work << 16); + work = (int) ((((uint) right >> 4) ^ left) & 0x0f0f0f0f); + left ^= work; + right ^= (work << 4); + + outBytes[outOff + 0] = (byte)(((uint) right >> 24) & 0xff); + outBytes[outOff + 1] = (byte)(((uint) right >> 16) & 0xff); + outBytes[outOff + 2] = (byte)(((uint) right >> 8) & 0xff); + outBytes[outOff + 3] = (byte)( right & 0xff); + outBytes[outOff + 4] = (byte)(((uint) left >> 24) & 0xff); + outBytes[outOff + 5] = (byte)(((uint) left >> 16) & 0xff); + outBytes[outOff + 6] = (byte)(((uint) left >> 8) & 0xff); + outBytes[outOff + 7] = (byte)( left & 0xff); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/ElGamalEngine.cs b/iTechSharp/srcbc/crypto/engines/ElGamalEngine.cs new file mode 100644 index 0000000..3d256a0 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/ElGamalEngine.cs @@ -0,0 +1,178 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * this does your basic ElGamal algorithm. + */ + public class ElGamalEngine + : IAsymmetricBlockCipher + { + private ElGamalKeyParameters key; + private SecureRandom random; + private bool forEncryption; + private int bitSize; + + public string AlgorithmName + { + get { return "ElGamal"; } + } + + /** + * initialise the ElGamal engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary ElGamal key parameters. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom p = (ParametersWithRandom) parameters; + + this.key = (ElGamalKeyParameters) p.Parameters; + this.random = p.Random; + } + else + { + this.key = (ElGamalKeyParameters) parameters; + this.random = new SecureRandom(); + } + + this.forEncryption = forEncryption; + this.bitSize = key.Parameters.P.BitLength; + + if (forEncryption) + { + if (!(key is ElGamalPublicKeyParameters)) + { + throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption."); + } + } + else + { + if (!(key is ElGamalPrivateKeyParameters)) + { + throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption."); + } + } + } + + /** + * Return the maximum size for an input block to this engine. + * For ElGamal this is always one byte less than the size of P on + * encryption, and twice the length as the size of P on decryption. + * + * @return maximum size for an input block. + */ + public int GetInputBlockSize() + { + if (forEncryption) + { + return (bitSize - 1) / 8; + } + + return 2 * ((bitSize + 7) / 8); + } + + /** + * Return the maximum size for an output block to this engine. + * For ElGamal this is always one byte less than the size of P on + * decryption, and twice the length as the size of P on encryption. + * + * @return maximum size for an output block. + */ + public int GetOutputBlockSize() + { + if (forEncryption) + { + return 2 * ((bitSize + 7) / 8); + } + + return (bitSize - 1) / 8; + } + + /** + * Process a single block using the basic ElGamal algorithm. + * + * @param in the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param length the length of the data to be processed. + * @return the result of the ElGamal process. + * @exception DataLengthException the input block is too large. + */ + public byte[] ProcessBlock( + byte[] input, + int inOff, + int length) + { + if (key == null) + throw new InvalidOperationException("ElGamal engine not initialised"); + + int maxLength = forEncryption + ? (bitSize - 1 + 7) / 8 + : GetInputBlockSize(); + + if (length > maxLength) + throw new DataLengthException("input too large for ElGamal cipher.\n"); + + BigInteger p = key.Parameters.P; + + byte[] output; + if (key is ElGamalPrivateKeyParameters) // decryption + { + int halfLength = length / 2; + BigInteger gamma = new BigInteger(1, input, inOff, halfLength); + BigInteger phi = new BigInteger(1, input, inOff + halfLength, halfLength); + + ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters) key; + + // a shortcut, which generally relies on p being prime amongst other things. + // if a problem with this shows up, check the p and g values! + BigInteger m = gamma.ModPow(p.Subtract(BigInteger.One).Subtract(priv.X), p).Multiply(phi).Mod(p); + + output = m.ToByteArrayUnsigned(); + } + else // encryption + { + BigInteger tmp = new BigInteger(1, input, inOff, length); + + if (tmp.BitLength >= p.BitLength) + throw new DataLengthException("input too large for ElGamal cipher.\n"); + + + ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters) key; + + BigInteger pSub2 = p.Subtract(BigInteger.Two); + + // TODO In theory, a series of 'k', 'g.ModPow(k, p)' and 'y.ModPow(k, p)' can be pre-calculated + BigInteger k; + do + { + k = new BigInteger(p.BitLength, random); + } + while (k.SignValue == 0 || k.CompareTo(pSub2) > 0); + + BigInteger g = key.Parameters.G; + BigInteger gamma = g.ModPow(k, p); + BigInteger phi = tmp.Multiply(pub.Y.ModPow(k, p)).Mod(p); + + output = new byte[this.GetOutputBlockSize()]; + + // TODO Add methods to allow writing BigInteger to existing byte array? + byte[] out1 = gamma.ToByteArrayUnsigned(); + byte[] out2 = phi.ToByteArrayUnsigned(); + out1.CopyTo(output, output.Length / 2 - out1.Length); + out2.CopyTo(output, output.Length - out2.Length); + } + + return output; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/GOST28147Engine.cs b/iTechSharp/srcbc/crypto/engines/GOST28147Engine.cs new file mode 100644 index 0000000..708abfc --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/GOST28147Engine.cs @@ -0,0 +1,364 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * implementation of GOST 28147-89 + */ + public class Gost28147Engine + : IBlockCipher + { + private const int BlockSize = 8; + private int[] workingKey = null; + private bool forEncryption; + + // these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333 + // This is default S-box! + private readonly byte[] S = { + 0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3, + 0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9, + 0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB, + 0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3, + 0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2, + 0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE, + 0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC, + 0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC + }; + + /* + * class content S-box parameters for encrypting + * getting from, see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-02.txt + */ + private static readonly byte[] ESbox_Test = { + 0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6, + 0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5, + 0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB, + 0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8, + 0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4, + 0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4, + 0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD, + 0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8 + }; + + private static readonly byte[] ESbox_A = { + 0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5, + 0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1, + 0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9, + 0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6, + 0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6, + 0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6, + 0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE, + 0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4 + }; + + private static readonly byte[] ESbox_B = { + 0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF, + 0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE, + 0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4, + 0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8, + 0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3, + 0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5, + 0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE, + 0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC + }; + + private static readonly byte[] ESbox_C = { + 0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3, + 0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3, + 0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB, + 0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4, + 0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7, + 0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD, + 0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7, + 0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8 + }; + + private static readonly byte[] ESbox_D = { + 0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3, + 0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1, + 0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2, + 0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8, + 0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1, + 0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6, + 0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7, + 0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE + }; + + //S-box for digest + private static readonly byte[] DSbox_Test = { + 0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3, + 0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9, + 0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB, + 0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3, + 0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2, + 0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE, + 0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC, + 0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC + }; + + private static readonly byte[] DSbox_A = { + 0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF, + 0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8, + 0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD, + 0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3, + 0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5, + 0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3, + 0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB, + 0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC + }; + + // + // pre-defined sbox table + // + private static readonly Hashtable sBoxes = new Hashtable(); + + static Gost28147Engine() + { + sBoxes.Add("E-TEST", ESbox_Test); + sBoxes.Add("E-A", ESbox_A); + sBoxes.Add("E-B", ESbox_B); + sBoxes.Add("E-C", ESbox_C); + sBoxes.Add("E-D", ESbox_D); + sBoxes.Add("D-TEST", DSbox_Test); + sBoxes.Add("D-A", DSbox_A); + } + + /** + * standard constructor. + */ + public Gost28147Engine() + { + } + + /** + * initialise an Gost28147 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is ParametersWithSBox) + { + ParametersWithSBox param = (ParametersWithSBox)parameters; + + // + // Set the S-Box + // + Array.Copy(param.GetSBox(), 0, this.S, 0, param.GetSBox().Length); + + // + // set key if there is one + // + if (param.Parameters != null) + { + workingKey = generateWorkingKey(forEncryption, + ((KeyParameter)param.Parameters).GetKey()); + } + } + else if (parameters is KeyParameter) + { + workingKey = generateWorkingKey(forEncryption, + ((KeyParameter)parameters).GetKey()); + } + else + { + throw new ArgumentException("invalid parameter passed to Gost28147 init - " + parameters.GetType().Name); + } + } + + public string AlgorithmName + { + get { return "Gost28147"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BlockSize; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + { + throw new InvalidOperationException("Gost28147 engine not initialised"); + } + + if ((inOff + BlockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + BlockSize) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + Gost28147Func(workingKey, input, inOff, output, outOff); + + return BlockSize; + } + + public void Reset() + { + } + + private int[] generateWorkingKey( + bool forEncryption, + byte[] userKey) + { + this.forEncryption = forEncryption; + + if (userKey.Length != 32) + { + throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!"); + } + + int[] key = new int[8]; + for(int i=0; i!=8; i++) + { + key[i] = bytesToint(userKey,i*4); + } + + return key; + } + + private int Gost28147_mainStep(int n1, int key) + { + int cm = (key + n1); // CM1 + + // S-box replacing + + int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4); + om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4); + om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4); + om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4); + om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4); + om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4); + om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4); + om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4); + +// return om << 11 | om >>> (32-11); // 11-leftshift + int omLeft = om << 11; + int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation + + return omLeft | omRight; + } + + private void Gost28147Func( + int[] workingKey, + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + int N1, N2, tmp; //tmp -> for saving N1 + N1 = bytesToint(inBytes, inOff); + N2 = bytesToint(inBytes, inOff + 4); + + if (this.forEncryption) + { + for(int k = 0; k < 3; k++) // 1-24 steps + { + for(int j = 0; j < 8; j++) + { + tmp = N1; + int step = Gost28147_mainStep(N1, workingKey[j]); + N1 = N2 ^ step; // CM2 + N2 = tmp; + } + } + for(int j = 7; j > 0; j--) // 25-31 steps + { + tmp = N1; + N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2 + N2 = tmp; + } + } + else //decrypt + { + for(int j = 0; j < 8; j++) // 1-8 steps + { + tmp = N1; + N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2 + N2 = tmp; + } + for(int k = 0; k < 3; k++) //9-31 steps + { + for(int j = 7; j >= 0; j--) + { + if ((k == 2) && (j==0)) + { + break; // break 32 step + } + tmp = N1; + N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2 + N2 = tmp; + } + } + } + + N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]); // 32 step (N1=N1) + + intTobytes(N1, outBytes, outOff); + intTobytes(N2, outBytes, outOff + 4); + } + + //array of bytes to type int + private static int bytesToint( + byte[] inBytes, + int inOff) + { + return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) + + ((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff); + } + + //int to array of bytes + private static void intTobytes( + int num, + byte[] outBytes, + int outOff) + { + outBytes[outOff + 3] = (byte)(num >> 24); + outBytes[outOff + 2] = (byte)(num >> 16); + outBytes[outOff + 1] = (byte)(num >> 8); + outBytes[outOff] = (byte)num; + } + + /** + * Return the S-Box associated with SBoxName + * @param sBoxName name of the S-Box + * @return byte array representing the S-Box + */ + public static byte[] GetSBox( + string sBoxName) + { + byte[] namedSBox = (byte[])sBoxes[sBoxName.ToUpper(CultureInfo.InvariantCulture)]; + + if (namedSBox == null) + { + throw new ArgumentException("Unknown S-Box - possible types: " + + "\"E-Test\", \"E-A\", \"E-B\", \"E-C\", \"E-D\", \"D-Test\", \"D-A\"."); + } + + return (byte[]) namedSBox.Clone(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/HC128Engine.cs b/iTechSharp/srcbc/crypto/engines/HC128Engine.cs new file mode 100644 index 0000000..dd5e4bd --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/HC128Engine.cs @@ -0,0 +1,241 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * HC-128 is a software-efficient stream cipher created by Hongjun Wu. It + * generates keystream from a 128-bit secret key and a 128-bit initialization + * vector. + *

      + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf + *

      + * It is a third phase candidate in the eStream contest, and is patent-free. + * No attacks are known as of today (April 2007). See + * + * http://www.ecrypt.eu.org/stream/hcp3.html + *

      + */ + public class HC128Engine + : IStreamCipher + { + private uint[] p = new uint[512]; + private uint[] q = new uint[512]; + private uint cnt = 0; + + private static uint F1(uint x) + { + return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3); + } + + private static uint F2(uint x) + { + return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10); + } + + private uint G1(uint x, uint y, uint z) + { + return (RotateRight(x, 10) ^ RotateRight(z, 23)) + RotateRight(y, 8); + } + + private uint G2(uint x, uint y, uint z) + { + return (RotateLeft(x, 10) ^ RotateLeft(z, 23)) + RotateLeft(y, 8); + } + + private static uint RotateLeft(uint x, int bits) + { + return (x << bits) | (x >> -bits); + } + + private static uint RotateRight(uint x, int bits) + { + return (x >> bits) | (x << -bits); + } + + private uint H1(uint x) + { + return q[x & 0xFF] + q[((x >> 16) & 0xFF) + 256]; + } + + private uint H2(uint x) + { + return p[x & 0xFF] + p[((x >> 16) & 0xFF) + 256]; + } + + private static uint Mod1024(uint x) + { + return x & 0x3FF; + } + + private static uint Mod512(uint x) + { + return x & 0x1FF; + } + + private static uint Dim(uint x, uint y) + { + return Mod512(x - y); + } + + private uint Step() + { + uint j = Mod512(cnt); + uint ret; + if (cnt < 512) + { + p[j] += G1(p[Dim(j, 3)], p[Dim(j, 10)], p[Dim(j, 511)]); + ret = H1(p[Dim(j, 12)]) ^ p[j]; + } + else + { + q[j] += G2(q[Dim(j, 3)], q[Dim(j, 10)], q[Dim(j, 511)]); + ret = H2(q[Dim(j, 12)]) ^ q[j]; + } + cnt = Mod1024(cnt + 1); + return ret; + } + + private byte[] key, iv; + private bool initialised; + + private void Init() + { + if (key.Length != 16) + throw new ArgumentException("The key must be 128 bit long"); + + cnt = 0; + + uint[] w = new uint[1280]; + + for (int i = 0; i < 16; i++) + { + w[i >> 3] |= ((uint)key[i] << (i & 0x7)); + } + Array.Copy(w, 0, w, 4, 4); + + for (int i = 0; i < iv.Length && i < 16; i++) + { + w[(i >> 3) + 8] |= ((uint)iv[i] << (i & 0x7)); + } + Array.Copy(w, 8, w, 12, 4); + + for (uint i = 16; i < 1280; i++) + { + w[i] = F2(w[i - 2]) + w[i - 7] + F1(w[i - 15]) + w[i - 16] + i; + } + + Array.Copy(w, 256, p, 0, 512); + Array.Copy(w, 768, q, 0, 512); + + for (int i = 0; i < 512; i++) + { + p[i] = Step(); + } + for (int i = 0; i < 512; i++) + { + q[i] = Step(); + } + + cnt = 0; + } + + public string AlgorithmName + { + get { return "HC-128"; } + } + + /** + * Initialise a HC-128 cipher. + * + * @param forEncryption whether or not we are for encryption. Irrelevant, as + * encryption and decryption are the same. + * @param params the parameters required to set up the cipher. + * @throws ArgumentException if the params argument is + * inappropriate (ie. the key is not 128 bit long). + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + ICipherParameters keyParam = parameters; + + if (parameters is ParametersWithIV) + { + iv = ((ParametersWithIV)parameters).GetIV(); + keyParam = ((ParametersWithIV)parameters).Parameters; + } + else + { + iv = new byte[0]; + } + + if (keyParam is KeyParameter) + { + key = ((KeyParameter)keyParam).GetKey(); + Init(); + } + else + { + throw new ArgumentException( + "Invalid parameter passed to HC128 init - " + parameters.GetType().Name, + "parameters"); + } + + initialised = true; + } + + private byte[] buf = new byte[4]; + private int idx = 0; + + private byte GetByte() + { + if (idx == 0) + { + uint step = Step(); + buf[3] = (byte)step; + step >>= 8; + buf[2] = (byte)step; + step >>= 8; + buf[1] = (byte)step; + step >>= 8; + buf[0] = (byte)step; + } + byte ret = buf[idx]; + idx = idx + 1 & 0x3; + return ret; + } + + public void ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] output, + int outOff) + { + if (!initialised) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + if ((inOff + len) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + len) > output.Length) + throw new DataLengthException("output buffer too short"); + + for (int i = 0; i < len; i++) + { + output[outOff + i] = (byte)(input[inOff + i] ^ GetByte()); + } + } + + public void Reset() + { + idx = 0; + Init(); + } + + public byte ReturnByte(byte input) + { + return (byte)(input ^ GetByte()); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/HC256Engine.cs b/iTechSharp/srcbc/crypto/engines/HC256Engine.cs new file mode 100644 index 0000000..8b18d5d --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/HC256Engine.cs @@ -0,0 +1,207 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * HC-256 is a software-efficient stream cipher created by Hongjun Wu. It + * generates keystream from a 256-bit secret key and a 256-bit initialization + * vector. + *

      + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf + *

      + * Its brother, HC-128, is a third phase candidate in the eStream contest. + * The algorithm is patent-free. No attacks are known as of today (April 2007). + * See + * + * http://www.ecrypt.eu.org/stream/hcp3.html + *

      + */ + public class HC256Engine + : IStreamCipher + { + private uint[] p = new uint[1024]; + private uint[] q = new uint[1024]; + private uint cnt = 0; + + private uint Step() + { + uint j = cnt & 0x3FF; + uint ret; + if (cnt < 1024) + { + uint x = p[(j - 3 & 0x3FF)]; + uint y = p[(j - 1023 & 0x3FF)]; + p[j] += p[(j - 10 & 0x3FF)] + + (RotateRight(x, 10) ^ RotateRight(y, 23)) + + q[((x ^ y) & 0x3FF)]; + + x = p[(j - 12 & 0x3FF)]; + ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256] + + q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768]) + ^ p[j]; + } + else + { + uint x = q[(j - 3 & 0x3FF)]; + uint y = q[(j - 1023 & 0x3FF)]; + q[j] += q[(j - 10 & 0x3FF)] + + (RotateRight(x, 10) ^ RotateRight(y, 23)) + + p[((x ^ y) & 0x3FF)]; + + x = q[(j - 12 & 0x3FF)]; + ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256] + + p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768]) + ^ q[j]; + } + cnt = cnt + 1 & 0x7FF; + return ret; + } + + private byte[] key, iv; + private bool initialised; + + private void Init() + { + if (key.Length != 32) + throw new ArgumentException("The key must be 256 bit long"); + + cnt = 0; + + uint[] w = new uint[2560]; + + for (int i = 0; i < 32; i++) + { + w[i >> 3] |= ((uint)key[i] << (i & 0x7)); + } + + for (int i = 0; i < iv.Length && i < 32; i++) + { + w[(i >> 3) + 8] |= ((uint)iv[i] << (i & 0x7)); + } + + for (uint i = 16; i < 2560; i++) + { + uint x = w[i - 2]; + uint y = w[i - 15]; + w[i] = (RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10)) + + w[i - 7] + + (RotateRight(y, 7) ^ RotateRight(y, 18) ^ (y >> 3)) + + w[i - 16] + i; + } + + Array.Copy(w, 512, p, 0, 1024); + Array.Copy(w, 1536, q, 0, 1024); + + for (int i = 0; i < 4096; i++) + { + Step(); + } + + cnt = 0; + } + + public string AlgorithmName + { + get { return "HC-256"; } + } + + /** + * Initialise a HC-256 cipher. + * + * @param forEncryption whether or not we are for encryption. Irrelevant, as + * encryption and decryption are the same. + * @param params the parameters required to set up the cipher. + * @throws ArgumentException if the params argument is + * inappropriate (ie. the key is not 256 bit long). + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + ICipherParameters keyParam = parameters; + + if (parameters is ParametersWithIV) + { + iv = ((ParametersWithIV)parameters).GetIV(); + keyParam = ((ParametersWithIV)parameters).Parameters; + } + else + { + iv = new byte[0]; + } + + if (keyParam is KeyParameter) + { + key = ((KeyParameter)keyParam).GetKey(); + Init(); + } + else + { + throw new ArgumentException( + "Invalid parameter passed to HC256 init - " + parameters.GetType().Name, + "parameters"); + } + + initialised = true; + } + + private byte[] buf = new byte[4]; + private int idx = 0; + + private byte GetByte() + { + if (idx == 0) + { + uint step = Step(); + buf[3] = (byte)step; + step >>= 8; + buf[2] = (byte)step; + step >>= 8; + buf[1] = (byte)step; + step >>= 8; + buf[0] = (byte)step; + } + byte ret = buf[idx]; + idx = idx + 1 & 0x3; + return ret; + } + + public void ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] output, + int outOff) + { + if (!initialised) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + if ((inOff + len) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + len) > output.Length) + throw new DataLengthException("output buffer too short"); + + for (int i = 0; i < len; i++) + { + output[outOff + i] = (byte)(input[inOff + i] ^ GetByte()); + } + } + + public void Reset() + { + idx = 0; + Init(); + } + + public byte ReturnByte(byte input) + { + return (byte)(input ^ GetByte()); + } + + private static uint RotateRight(uint x, int bits) + { + return (x >> bits) | (x << -bits); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/ISAACEngine.cs b/iTechSharp/srcbc/crypto/engines/ISAACEngine.cs new file mode 100644 index 0000000..1120a41 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/ISAACEngine.cs @@ -0,0 +1,252 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count). + * see: http://www.burtleburtle.net/bob/rand/isaacafa.html + */ + public class IsaacEngine + : IStreamCipher + { + // Constants + private static readonly int sizeL = 8, + stateArraySize = sizeL<<5; // 256 + + // Cipher's internal state + private uint[] engineState = null, // mm + results = null; // randrsl + private uint a = 0, b = 0, c = 0; + + // Engine state + private int index = 0; + private byte[] keyStream = new byte[stateArraySize<<2], // results expanded into bytes + workingKey = null; + private bool initialised = false; + + /** + * initialise an ISAAC cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception ArgumentException if the params argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException( + "invalid parameter passed to ISAAC Init - " + parameters.GetType().Name, + "parameters"); + + /* + * ISAAC encryption and decryption is completely + * symmetrical, so the 'forEncryption' is + * irrelevant. + */ + KeyParameter p = (KeyParameter) parameters; + setKey(p.GetKey()); + } + + public byte ReturnByte( + byte input) + { + if (index == 0) + { + isaac(); + keyStream = intToByteLittle(results); + } + + byte output = (byte)(keyStream[index]^input); + index = (index + 1) & 1023; + + return output; + } + + public void ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] output, + int outOff) + { + if (!initialised) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + if ((inOff + len) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + len) > output.Length) + throw new DataLengthException("output buffer too short"); + + for (int i = 0; i < len; i++) + { + if (index == 0) + { + isaac(); + keyStream = intToByteLittle(results); + } + output[i+outOff] = (byte)(keyStream[index]^input[i+inOff]); + index = (index + 1) & 1023; + } + } + + public string AlgorithmName + { + get { return "ISAAC"; } + } + + public void Reset() + { + setKey(workingKey); + } + + // Private implementation + private void setKey( + byte[] keyBytes) + { + workingKey = keyBytes; + + if (engineState == null) + { + engineState = new uint[stateArraySize]; + } + + if (results == null) + { + results = new uint[stateArraySize]; + } + + int i, j, k; + + // Reset state + for (i = 0; i < stateArraySize; i++) + { + engineState[i] = results[i] = 0; + } + a = b = c = 0; + + // Reset index counter for output + index = 0; + + // Convert the key bytes to ints and put them into results[] for initialization + byte[] t = new byte[keyBytes.Length + (keyBytes.Length & 3)]; + Array.Copy(keyBytes, 0, t, 0, keyBytes.Length); + for (i = 0; i < t.Length; i+=4) + { + results[i>>2] = byteToIntLittle(t, i); + } + + // It has begun? + uint[] abcdefgh = new uint[sizeL]; + + for (i = 0; i < sizeL; i++) + { + abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio) + } + + for (i = 0; i < 4; i++) + { + mix(abcdefgh); + } + + for (i = 0; i < 2; i++) + { + for (j = 0; j < stateArraySize; j+=sizeL) + { + for (k = 0; k < sizeL; k++) + { + abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k]; + } + + mix(abcdefgh); + + for (k = 0; k < sizeL; k++) + { + engineState[j+k] = abcdefgh[k]; + } + } + } + + isaac(); + + initialised = true; + } + + private void isaac() + { + uint x, y; + + b += ++c; + for (int i = 0; i < stateArraySize; i++) + { + x = engineState[i]; + switch (i & 3) + { + case 0: a ^= (a << 13); break; + case 1: a ^= (a >> 6); break; + case 2: a ^= (a << 2); break; + case 3: a ^= (a >> 16); break; + } + a += engineState[(i+128) & 0xFF]; + engineState[i] = y = engineState[(int)((uint)x >> 2) & 0xFF] + a + b; + results[i] = b = engineState[(int)((uint)y >> 10) & 0xFF] + x; + } + } + + private void mix(uint[] x) + { +// x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2]; +// x[1]^=x[2]>>> 2; x[4]+=x[1]; x[2]+=x[3]; +// x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4]; +// x[3]^=x[4]>>>16; x[6]+=x[3]; x[4]+=x[5]; +// x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6]; +// x[5]^=x[6]>>> 4; x[0]+=x[5]; x[6]+=x[7]; +// x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0]; +// x[7]^=x[0]>>> 9; x[2]+=x[7]; x[0]+=x[1]; + x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2]; + x[1]^=x[2]>> 2; x[4]+=x[1]; x[2]+=x[3]; + x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4]; + x[3]^=x[4]>> 16; x[6]+=x[3]; x[4]+=x[5]; + x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6]; + x[5]^=x[6]>> 4; x[0]+=x[5]; x[6]+=x[7]; + x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0]; + x[7]^=x[0]>> 9; x[2]+=x[7]; x[0]+=x[1]; + } + + private uint byteToIntLittle( + byte[] x, + int offset) + { + uint result = (byte) x[offset + 3]; + result = (result << 8) | x[offset + 2]; + result = (result << 8) | x[offset + 1]; + result = (result << 8) | x[offset + 0]; + return result; + } + + private byte[] intToByteLittle( + uint x) + { + byte[] output = new byte[4]; + output[3] = (byte)x; + output[2] = (byte)(x >> 8); + output[1] = (byte)(x >> 16); + output[0] = (byte)(x >> 24); + return output; + } + + private byte[] intToByteLittle( + uint[] x) + { + byte[] output = new byte[4*x.Length]; + for (int i = 0, j = 0; i < x.Length; i++,j+=4) + { + Array.Copy(intToByteLittle(x[i]), 0, output, j, 4); + } + return output; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/IdeaEngine.cs b/iTechSharp/srcbc/crypto/engines/IdeaEngine.cs new file mode 100644 index 0000000..9d2a376 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/IdeaEngine.cs @@ -0,0 +1,333 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * A class that provides a basic International Data Encryption Algorithm (IDEA) engine. + *

      + * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM" + * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the + * end of the mulinv function!). + *

      + *

      + * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/ + *

      + *

      + * Note: This algorithm is patented in the USA, Japan, and Europe including + * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland + * and the United Kingdom. Non-commercial use is free, however any commercial + * products are liable for royalties. Please see + * www.mediacrypt.com for + * further details. This announcement has been included at the request of + * the patent holders. + *

      + */ + public class IdeaEngine + : IBlockCipher + { + private const int BLOCK_SIZE = 8; + private int[] workingKey; + /** + * standard constructor. + */ + public IdeaEngine() + { + } + /** + * initialise an IDEA cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString()); + + workingKey = GenerateWorkingKey(forEncryption, + ((KeyParameter)parameters).GetKey()); + } + + public string AlgorithmName + { + get { return "IDEA"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + { + throw new InvalidOperationException("IDEA engine not initialised"); + } + if ((inOff + BLOCK_SIZE) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + if ((outOff + BLOCK_SIZE) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + IdeaFunc(workingKey, input, inOff, output, outOff); + return BLOCK_SIZE; + } + public void Reset() + { + } + private static readonly int MASK = 0xffff; + private static readonly int BASE = 0x10001; + private int BytesToWord( + byte[] input, + int inOff) + { + return ((input[inOff] << 8) & 0xff00) + (input[inOff + 1] & 0xff); + } + private void WordToBytes( + int word, + byte[] outBytes, + int outOff) + { + outBytes[outOff] = (byte)((uint) word >> 8); + outBytes[outOff + 1] = (byte)word; + } + /** + * return x = x * y where the multiplication is done modulo + * 65537 (0x10001) (as defined in the IDEA specification) and + * a zero input is taken to be 65536 (0x10000). + * + * @param x the x value + * @param y the y value + * @return x = x * y + */ + private int Mul( + int x, + int y) + { + if (x == 0) + { + x = (BASE - y); + } + else if (y == 0) + { + x = (BASE - x); + } + else + { + int p = x * y; + y = p & MASK; + x = (int) ((uint) p >> 16); + x = y - x + ((y < x) ? 1 : 0); + } + return x & MASK; + } + private void IdeaFunc( + int[] workingKey, + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int x0, x1, x2, x3, t0, t1; + int keyOff = 0; + x0 = BytesToWord(input, inOff); + x1 = BytesToWord(input, inOff + 2); + x2 = BytesToWord(input, inOff + 4); + x3 = BytesToWord(input, inOff + 6); + for (int round = 0; round < 8; round++) + { + x0 = Mul(x0, workingKey[keyOff++]); + x1 += workingKey[keyOff++]; + x1 &= MASK; + x2 += workingKey[keyOff++]; + x2 &= MASK; + x3 = Mul(x3, workingKey[keyOff++]); + t0 = x1; + t1 = x2; + x2 ^= x0; + x1 ^= x3; + x2 = Mul(x2, workingKey[keyOff++]); + x1 += x2; + x1 &= MASK; + x1 = Mul(x1, workingKey[keyOff++]); + x2 += x1; + x2 &= MASK; + x0 ^= x1; + x3 ^= x2; + x1 ^= t1; + x2 ^= t0; + } + WordToBytes(Mul(x0, workingKey[keyOff++]), outBytes, outOff); + WordToBytes(x2 + workingKey[keyOff++], outBytes, outOff + 2); /* NB: Order */ + WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4); + WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6); + } + /** + * The following function is used to expand the user key to the encryption + * subkey. The first 16 bytes are the user key, and the rest of the subkey + * is calculated by rotating the previous 16 bytes by 25 bits to the left, + * and so on until the subkey is completed. + */ + private int[] ExpandKey( + byte[] uKey) + { + int[] key = new int[52]; + if (uKey.Length < 16) + { + byte[] tmp = new byte[16]; + Array.Copy(uKey, 0, tmp, tmp.Length - uKey.Length, uKey.Length); + uKey = tmp; + } + for (int i = 0; i < 8; i++) + { + key[i] = BytesToWord(uKey, i * 2); + } + for (int i = 8; i < 52; i++) + { + if ((i & 7) < 6) + { + key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK; + } + else if ((i & 7) == 6) + { + key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK; + } + else + { + key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK; + } + } + return key; + } + /** + * This function computes multiplicative inverse using Euclid's Greatest + * Common Divisor algorithm. Zero and one are self inverse. + *

      + * i.e. x * MulInv(x) == 1 (modulo BASE) + *

      + */ + private int MulInv( + int x) + { + int t0, t1, q, y; + + if (x < 2) + { + return x; + } + t0 = 1; + t1 = BASE / x; + y = BASE % x; + while (y != 1) + { + q = x / y; + x = x % y; + t0 = (t0 + (t1 * q)) & MASK; + if (x == 1) + { + return t0; + } + q = y / x; + y = y % x; + t1 = (t1 + (t0 * q)) & MASK; + } + return (1 - t1) & MASK; + } + /** + * Return the additive inverse of x. + *

      + * i.e. x + AddInv(x) == 0 + *

      + */ + int AddInv( + int x) + { + return (0 - x) & MASK; + } + + /** + * The function to invert the encryption subkey to the decryption subkey. + * It also involves the multiplicative inverse and the additive inverse functions. + */ + private int[] InvertKey( + int[] inKey) + { + int t1, t2, t3, t4; + int p = 52; /* We work backwards */ + int[] key = new int[52]; + int inOff = 0; + + t1 = MulInv(inKey[inOff++]); + t2 = AddInv(inKey[inOff++]); + t3 = AddInv(inKey[inOff++]); + t4 = MulInv(inKey[inOff++]); + key[--p] = t4; + key[--p] = t3; + key[--p] = t2; + key[--p] = t1; + + for (int round = 1; round < 8; round++) + { + t1 = inKey[inOff++]; + t2 = inKey[inOff++]; + key[--p] = t2; + key[--p] = t1; + + t1 = MulInv(inKey[inOff++]); + t2 = AddInv(inKey[inOff++]); + t3 = AddInv(inKey[inOff++]); + t4 = MulInv(inKey[inOff++]); + key[--p] = t4; + key[--p] = t2; /* NB: Order */ + key[--p] = t3; + key[--p] = t1; + } + t1 = inKey[inOff++]; + t2 = inKey[inOff++]; + key[--p] = t2; + key[--p] = t1; + + t1 = MulInv(inKey[inOff++]); + t2 = AddInv(inKey[inOff++]); + t3 = AddInv(inKey[inOff++]); + t4 = MulInv(inKey[inOff]); + key[--p] = t4; + key[--p] = t3; + key[--p] = t2; + key[--p] = t1; + return key; + } + + private int[] GenerateWorkingKey( + bool forEncryption, + byte[] userKey) + { + if (forEncryption) + { + return ExpandKey(userKey); + } + else + { + return InvertKey(ExpandKey(userKey)); + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/IesEngine.cs b/iTechSharp/srcbc/crypto/engines/IesEngine.cs new file mode 100644 index 0000000..0f9ec9f --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/IesEngine.cs @@ -0,0 +1,236 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * support class for constructing intergrated encryption ciphers + * for doing basic message exchanges on top of key agreement ciphers + */ + public class IesEngine + { + private readonly IBasicAgreement agree; + private readonly IDerivationFunction kdf; + private readonly IMac mac; + private readonly BufferedBlockCipher cipher; + private readonly byte[] macBuf; + + private bool forEncryption; + private ICipherParameters privParam, pubParam; + private IesParameters param; + + /** + * set up for use with stream mode, where the key derivation function + * is used to provide a stream of bytes to xor with the message. + * + * @param agree the key agreement used as the basis for the encryption + * @param kdf the key derivation function used for byte generation + * @param mac the message authentication code generator for the message + */ + public IesEngine( + IBasicAgreement agree, + IDerivationFunction kdf, + IMac mac) + { + this.agree = agree; + this.kdf = kdf; + this.mac = mac; + this.macBuf = new byte[mac.GetMacSize()]; +// this.cipher = null; + } + + /** + * set up for use in conjunction with a block cipher to handle the + * message. + * + * @param agree the key agreement used as the basis for the encryption + * @param kdf the key derivation function used for byte generation + * @param mac the message authentication code generator for the message + * @param cipher the cipher to used for encrypting the message + */ + public IesEngine( + IBasicAgreement agree, + IDerivationFunction kdf, + IMac mac, + BufferedBlockCipher cipher) + { + this.agree = agree; + this.kdf = kdf; + this.mac = mac; + this.macBuf = new byte[mac.GetMacSize()]; + this.cipher = cipher; + } + + /** + * Initialise the encryptor. + * + * @param forEncryption whether or not this is encryption/decryption. + * @param privParam our private key parameters + * @param pubParam the recipient's/sender's public key parameters + * @param param encoding and derivation parameters. + */ + public void Init( + bool forEncryption, + ICipherParameters privParameters, + ICipherParameters pubParameters, + ICipherParameters iesParameters) + { + this.forEncryption = forEncryption; + this.privParam = privParameters; + this.pubParam = pubParameters; + this.param = (IesParameters)iesParameters; + } + + private byte[] DecryptBlock( + byte[] in_enc, + int inOff, + int inLen, + byte[] z) + { + byte[] M = null; + KeyParameter macKey = null; + KdfParameters kParam = new KdfParameters(z, param.GetDerivationV()); + int macKeySize = param.MacKeySize; + + kdf.Init(kParam); + + inLen -= mac.GetMacSize(); + + if (cipher == null) // stream mode + { + byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8)); + + M = new byte[inLen]; + + for (int i = 0; i != inLen; i++) + { + M[i] = (byte)(in_enc[inOff + i] ^ Buffer[i]); + } + + macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8)); + } + else + { + int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize; + byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8)); + + cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8))); + + M = cipher.DoFinal(in_enc, inOff, inLen); + + macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8)); + } + + byte[] macIV = param.GetEncodingV(); + + mac.Init(macKey); + mac.BlockUpdate(in_enc, inOff, inLen); + mac.BlockUpdate(macIV, 0, macIV.Length); + mac.DoFinal(macBuf, 0); + + inOff += inLen; + + for (int t = 0; t < macBuf.Length; t++) + { + if (macBuf[t] != in_enc[inOff + t]) + { + throw (new InvalidCipherTextException("IMac codes failed to equal.")); + } + } + + return M; + } + + private byte[] EncryptBlock( + byte[] input, + int inOff, + int inLen, + byte[] z) + { + byte[] C = null; + KeyParameter macKey = null; + KdfParameters kParam = new KdfParameters(z, param.GetDerivationV()); + int c_text_length = 0; + int macKeySize = param.MacKeySize; + + if (cipher == null) // stream mode + { + byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8)); + + C = new byte[inLen + mac.GetMacSize()]; + c_text_length = inLen; + + for (int i = 0; i != inLen; i++) + { + C[i] = (byte)(input[inOff + i] ^ Buffer[i]); + } + + macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8)); + } + else + { + int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize; + byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8)); + + cipher.Init(true, new KeyParameter(Buffer, 0, (cipherKeySize / 8))); + + c_text_length = cipher.GetOutputSize(inLen); + byte[] tmp = new byte[c_text_length]; + + int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0); + len += cipher.DoFinal(tmp, len); + + C = new byte[len + mac.GetMacSize()]; + c_text_length = len; + + Array.Copy(tmp, 0, C, 0, len); + + macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8)); + } + + byte[] macIV = param.GetEncodingV(); + + mac.Init(macKey); + mac.BlockUpdate(C, 0, c_text_length); + mac.BlockUpdate(macIV, 0, macIV.Length); + // + // return the message and it's MAC + // + mac.DoFinal(C, c_text_length); + return C; + } + + private byte[] GenerateKdfBytes( + KdfParameters kParam, + int length) + { + byte[] buf = new byte[length]; + + kdf.Init(kParam); + + kdf.GenerateBytes(buf, 0, buf.Length); + + return buf; + } + + public byte[] ProcessBlock( + byte[] input, + int inOff, + int inLen) + { + agree.Init(privParam); + + BigInteger z = agree.CalculateAgreement(pubParam); + + // TODO Check that this is right (...Unsigned? Check length?) + byte[] zBytes = z.ToByteArray(); + + return forEncryption + ? EncryptBlock(input, inOff, inLen, zBytes) + : DecryptBlock(input, inOff, inLen, zBytes); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/NaccacheSternEngine.cs b/iTechSharp/srcbc/crypto/engines/NaccacheSternEngine.cs new file mode 100644 index 0000000..06432b0 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/NaccacheSternEngine.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * NaccacheStern Engine. For details on this cipher, please see + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + */ + public class NaccacheSternEngine + : IAsymmetricBlockCipher + { + private bool forEncryption; + + private NaccacheSternKeyParameters key; + + private ArrayList[] lookup = null; + + private bool debug = false; + + public string AlgorithmName + { + get { return "NaccacheStern"; } + } + + /** + * Initializes this algorithm. Must be called before all other Functions. + * + * @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool, + * org.bouncycastle.crypto.CipherParameters) + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + key = (NaccacheSternKeyParameters)parameters; + + // construct lookup table for faster decryption if necessary + if (!this.forEncryption) + { + if (debug) + { + Console.WriteLine("Constructing lookup Array"); + } + NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key; + ArrayList primes = priv.SmallPrimes; + lookup = new ArrayList[primes.Count]; + for (int i = 0; i < primes.Count; i++) + { + BigInteger actualPrime = (BigInteger) primes[i]; + int actualPrimeValue = actualPrime.IntValue; + + lookup[i] = new ArrayList(actualPrimeValue); + lookup[i].Add(BigInteger.One); + + if (debug) + { + Console.WriteLine("Constructing lookup ArrayList for " + actualPrimeValue); + } + + BigInteger accJ = BigInteger.Zero; + + for (int j = 1; j < actualPrimeValue; j++) + { +// BigInteger bigJ = BigInteger.ValueOf(j); +// accJ = priv.PhiN.Multiply(bigJ); + accJ = accJ.Add(priv.PhiN); + BigInteger comp = accJ.Divide(actualPrime); + lookup[i].Add(priv.G.ModPow(comp, priv.Modulus)); + } + } + } + } + + public bool Debug + { + set { this.debug = value; } + } + + /** + * Returns the input block size of this algorithm. + * + * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize() + */ + public int GetInputBlockSize() + { + if (forEncryption) + { + // We can only encrypt values up to lowerSigmaBound + return (key.LowerSigmaBound + 7) / 8 - 1; + } + else + { + // We pad to modulus-size bytes for easier decryption. +// return key.Modulus.ToByteArray().Length; + return key.Modulus.BitLength / 8 + 1; + } + } + + /** + * Returns the output block size of this algorithm. + * + * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize() + */ + public int GetOutputBlockSize() + { + if (forEncryption) + { + // encrypted Data is always padded up to modulus size +// return key.Modulus.ToByteArray().Length; + return key.Modulus.BitLength / 8 + 1; + } + else + { + // decrypted Data has upper limit lowerSigmaBound + return (key.LowerSigmaBound + 7) / 8 - 1; + } + } + + /** + * Process a single Block using the Naccache-Stern algorithm. + * + * @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[], + * int, int) + */ + public byte[] ProcessBlock( + byte[] inBytes, + int inOff, + int length) + { + if (key == null) + throw new InvalidOperationException("NaccacheStern engine not initialised"); + if (length > (GetInputBlockSize() + 1)) + throw new DataLengthException("input too large for Naccache-Stern cipher.\n"); + + if (!forEncryption) + { + // At decryption make sure that we receive padded data blocks + if (length < GetInputBlockSize()) + { + throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n"); + } + } + + // transform input into BigInteger + BigInteger input = new BigInteger(1, inBytes, inOff, length); + + if (debug) + { + Console.WriteLine("input as BigInteger: " + input); + } + + byte[] output; + if (forEncryption) + { + output = Encrypt(input); + } + else + { + ArrayList plain = new ArrayList(); + NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key; + ArrayList primes = priv.SmallPrimes; + // Get Chinese Remainders of CipherText + for (int i = 0; i < primes.Count; i++) + { + BigInteger exp = input.ModPow(priv.PhiN.Divide((BigInteger)primes[i]), priv.Modulus); + ArrayList al = lookup[i]; + if (lookup[i].Count != ((BigInteger)primes[i]).IntValue) + { + if (debug) + { + Console.WriteLine("Prime is " + primes[i] + ", lookup table has size " + al.Count); + } + throw new InvalidCipherTextException("Error in lookup Array for " + + ((BigInteger)primes[i]).IntValue + + ": Size mismatch. Expected ArrayList with length " + + ((BigInteger)primes[i]).IntValue + " but found ArrayList of length " + + lookup[i].Count); + } + int lookedup = al.IndexOf(exp); + + if (lookedup == -1) + { + if (debug) + { + Console.WriteLine("Actual prime is " + primes[i]); + Console.WriteLine("Decrypted value is " + exp); + + Console.WriteLine("LookupList for " + primes[i] + " with size " + lookup[i].Count + + " is: "); + for (int j = 0; j < lookup[i].Count; j++) + { + Console.WriteLine(lookup[i][j]); + } + } + throw new InvalidCipherTextException("Lookup failed"); + } + plain.Add(BigInteger.ValueOf(lookedup)); + } + BigInteger test = chineseRemainder(plain, primes); + + // Should not be used as an oracle, so reencrypt output to see + // if it corresponds to input + + // this breaks probabilisic encryption, so disable it. Anyway, we do + // use the first n primes for key generation, so it is pretty easy + // to guess them. But as stated in the paper, this is not a security + // breach. So we can just work with the correct sigma. + + // if (debug) { + // Console.WriteLine("Decryption is " + test); + // } + // if ((key.G.ModPow(test, key.Modulus)).Equals(input)) { + // output = test.ToByteArray(); + // } else { + // if(debug){ + // Console.WriteLine("Engine seems to be used as an oracle, + // returning null"); + // } + // output = null; + // } + + output = test.ToByteArray(); + } + + return output; + } + + /** + * Encrypts a BigInteger aka Plaintext with the public key. + * + * @param plain + * The BigInteger to encrypt + * @return The byte[] representation of the encrypted BigInteger (i.e. + * crypted.toByteArray()) + */ + public byte[] Encrypt( + BigInteger plain) + { + // Always return modulus size values 0-padded at the beginning + // 0-padding at the beginning is correctly parsed by BigInteger :) +// byte[] output = key.Modulus.ToByteArray(); +// Array.Clear(output, 0, output.Length); + byte[] output = new byte[key.Modulus.BitLength / 8 + 1]; + + byte[] tmp = key.G.ModPow(plain, key.Modulus).ToByteArray(); + Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length); + if (debug) + { + Console.WriteLine("Encrypted value is: " + new BigInteger(output)); + } + return output; + } + + /** + * Adds the contents of two encrypted blocks mod sigma + * + * @param block1 + * the first encrypted block + * @param block2 + * the second encrypted block + * @return encrypt((block1 + block2) mod sigma) + * @throws InvalidCipherTextException + */ + public byte[] AddCryptedBlocks( + byte[] block1, + byte[] block2) + { + // check for correct blocksize + if (forEncryption) + { + if ((block1.Length > GetOutputBlockSize()) + || (block2.Length > GetOutputBlockSize())) + { + throw new InvalidCipherTextException( + "BlockLength too large for simple addition.\n"); + } + } + else + { + if ((block1.Length > GetInputBlockSize()) + || (block2.Length > GetInputBlockSize())) + { + throw new InvalidCipherTextException( + "BlockLength too large for simple addition.\n"); + } + } + + // calculate resulting block + BigInteger m1Crypt = new BigInteger(1, block1); + BigInteger m2Crypt = new BigInteger(1, block2); + BigInteger m1m2Crypt = m1Crypt.Multiply(m2Crypt); + m1m2Crypt = m1m2Crypt.Mod(key.Modulus); + if (debug) + { + Console.WriteLine("c(m1) as BigInteger:....... " + m1Crypt); + Console.WriteLine("c(m2) as BigInteger:....... " + m2Crypt); + Console.WriteLine("c(m1)*c(m2)%n = c(m1+m2)%n: " + m1m2Crypt); + } + + //byte[] output = key.Modulus.ToByteArray(); + //Array.Clear(output, 0, output.Length); + byte[] output = new byte[key.Modulus.BitLength / 8 + 1]; + + byte[] m1m2CryptBytes = m1m2Crypt.ToByteArray(); + Array.Copy(m1m2CryptBytes, 0, output, + output.Length - m1m2CryptBytes.Length, m1m2CryptBytes.Length); + + return output; + } + + /** + * Convenience Method for data exchange with the cipher. + * + * Determines blocksize and splits data to blocksize. + * + * @param data the data to be processed + * @return the data after it went through the NaccacheSternEngine. + * @throws InvalidCipherTextException + */ + public byte[] ProcessData( + byte[] data) + { + if (debug) + { + Console.WriteLine(); + } + if (data.Length > GetInputBlockSize()) + { + int inBlocksize = GetInputBlockSize(); + int outBlocksize = GetOutputBlockSize(); + if (debug) + { + Console.WriteLine("Input blocksize is: " + inBlocksize + " bytes"); + Console.WriteLine("Output blocksize is: " + outBlocksize + " bytes"); + Console.WriteLine("Data has length:.... " + data.Length + " bytes"); + } + int datapos = 0; + int retpos = 0; + byte[] retval = new byte[(data.Length / inBlocksize + 1) * outBlocksize]; + while (datapos < data.Length) + { + byte[] tmp; + if (datapos + inBlocksize < data.Length) + { + tmp = ProcessBlock(data, datapos, inBlocksize); + datapos += inBlocksize; + } + else + { + tmp = ProcessBlock(data, datapos, data.Length - datapos); + datapos += data.Length - datapos; + } + if (debug) + { + Console.WriteLine("new datapos is " + datapos); + } + if (tmp != null) + { + tmp.CopyTo(retval, retpos); + retpos += tmp.Length; + } + else + { + if (debug) + { + Console.WriteLine("cipher returned null"); + } + throw new InvalidCipherTextException("cipher returned null"); + } + } + byte[] ret = new byte[retpos]; + Array.Copy(retval, 0, ret, 0, retpos); + if (debug) + { + Console.WriteLine("returning " + ret.Length + " bytes"); + } + return ret; + } + else + { + if (debug) + { + Console.WriteLine("data size is less then input block size, processing directly"); + } + return ProcessBlock(data, 0, data.Length); + } + } + + /** + * Computes the integer x that is expressed through the given primes and the + * congruences with the chinese remainder theorem (CRT). + * + * @param congruences + * the congruences c_i + * @param primes + * the primes p_i + * @return an integer x for that x % p_i == c_i + */ + private static BigInteger chineseRemainder(ArrayList congruences, ArrayList primes) + { + BigInteger retval = BigInteger.Zero; + BigInteger all = BigInteger.One; + for (int i = 0; i < primes.Count; i++) + { + all = all.Multiply((BigInteger)primes[i]); + } + for (int i = 0; i < primes.Count; i++) + { + BigInteger a = (BigInteger)primes[i]; + BigInteger b = all.Divide(a); + BigInteger b_ = b.ModInverse(a); + BigInteger tmp = b.Multiply(b_); + tmp = tmp.Multiply((BigInteger)congruences[i]); + retval = retval.Add(tmp); + } + + return retval.Mod(all); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/NoekeonEngine.cs b/iTechSharp/srcbc/crypto/engines/NoekeonEngine.cs new file mode 100644 index 0000000..acc4ec4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/NoekeonEngine.cs @@ -0,0 +1,256 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * A Noekeon engine, using direct-key mode. + */ + public class NoekeonEngine + : IBlockCipher + { + private const int GenericSize = 16; // Block and key size, as well as the amount of rounds. + + private static readonly uint[] nullVector = + { + 0x00, 0x00, 0x00, 0x00 // Used in decryption + }; + + private static readonly uint[] roundConstants = + { + 0x80, 0x1b, 0x36, 0x6c, + 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, + 0xc6, 0x97, 0x35, 0x6a, + 0xd4 + }; + + private uint[] state = new uint[4], // a + subKeys = new uint[4], // k + decryptKeys = new uint[4]; + + private bool _initialised, _forEncryption; + + /** + * Create an instance of the Noekeon encryption algorithm + * and set some defaults + */ + public NoekeonEngine() + { + _initialised = false; + } + + public string AlgorithmName + { + get { return "Noekeon"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return GenericSize; + } + + /** + * initialise + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception ArgumentException if the params argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("Invalid parameters passed to Noekeon init - " + parameters.GetType().Name, "parameters"); + + _forEncryption = forEncryption; + _initialised = true; + + KeyParameter p = (KeyParameter) parameters; + + setKey(p.GetKey()); + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (!_initialised) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + if ((inOff + GenericSize) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + GenericSize) > output.Length) + throw new DataLengthException("output buffer too short"); + + return _forEncryption + ? encryptBlock(input, inOff, output, outOff) + : decryptBlock(input, inOff, output, outOff); + } + + public void Reset() + { + // TODO This should do something in case the encryption is aborted + } + + /** + * Re-key the cipher. + * + * @param key the key to be used + */ + private void setKey(byte[] key) + { + subKeys[0] = bytesToIntBig(key, 0); + subKeys[1] = bytesToIntBig(key, 4); + subKeys[2] = bytesToIntBig(key, 8); + subKeys[3] = bytesToIntBig(key, 12); + } + + private int encryptBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + state[0] = bytesToIntBig(input, inOff); + state[1] = bytesToIntBig(input, inOff+4); + state[2] = bytesToIntBig(input, inOff+8); + state[3] = bytesToIntBig(input, inOff+12); + + int i; + for (i = 0; i < GenericSize; i++) + { + state[0] ^= roundConstants[i]; + theta(state, subKeys); + pi1(state); + gamma(state); + pi2(state); + } + + state[0] ^= roundConstants[i]; + theta(state, subKeys); + + intToBytesBig(state[0], output, outOff); + intToBytesBig(state[1], output, outOff+4); + intToBytesBig(state[2], output, outOff+8); + intToBytesBig(state[3], output, outOff+12); + + return GenericSize; + } + + private int decryptBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + state[0] = bytesToIntBig(input, inOff); + state[1] = bytesToIntBig(input, inOff+4); + state[2] = bytesToIntBig(input, inOff+8); + state[3] = bytesToIntBig(input, inOff+12); + + Array.Copy(subKeys, 0, decryptKeys, 0, subKeys.Length); + theta(decryptKeys, nullVector); + + int i; + for (i = GenericSize; i > 0; i--) + { + theta(state, decryptKeys); + state[0] ^= roundConstants[i]; + pi1(state); + gamma(state); + pi2(state); + } + + theta(state, decryptKeys); + state[0] ^= roundConstants[i]; + + intToBytesBig(state[0], output, outOff); + intToBytesBig(state[1], output, outOff+4); + intToBytesBig(state[2], output, outOff+8); + intToBytesBig(state[3], output, outOff+12); + + return GenericSize; + } + + private void gamma(uint[] a) + { + a[1] ^= ~a[3] & ~a[2]; + a[0] ^= a[2] & a[1]; + + uint tmp = a[3]; + a[3] = a[0]; + a[0] = tmp; + a[2] ^= a[0]^a[1]^a[3]; + + a[1] ^= ~a[3] & ~a[2]; + a[0] ^= a[2] & a[1]; + } + + private void theta(uint[] a, uint[] k) + { + uint tmp; + tmp = a[0]^a[2]; + tmp ^= rotl(tmp,8)^rotl(tmp,24); + a[1] ^= tmp; + a[3] ^= tmp; + + for (int i = 0; i < 4; i++) + { + a[i] ^= k[i]; + } + + tmp = a[1]^a[3]; + tmp ^= rotl(tmp,8)^rotl(tmp,24); + a[0] ^= tmp; + a[2] ^= tmp; + } + + private void pi1(uint[] a) + { + a[1] = rotl(a[1], 1); + a[2] = rotl(a[2], 5); + a[3] = rotl(a[3], 2); + } + + private void pi2(uint[] a) + { + a[1] = rotl(a[1], 31); + a[2] = rotl(a[2], 27); + a[3] = rotl(a[3], 30); + } + + // Helpers + + private uint bytesToIntBig(byte[] input, int off) + { + int result = ((input[off++]) << 24) | + ((input[off++] & 0xff) << 16) | + ((input[off++] & 0xff) << 8) | + (input[off ] & 0xff); + return (uint) result; + } + + private void intToBytesBig(uint x, byte[] output, int off) + { + output[off++] = (byte)(x >> 24); + output[off++] = (byte)(x >> 16); + output[off++] = (byte)(x >> 8); + output[off ] = (byte)x; + } + + private uint rotl(uint x, int y) + { + return (x << y) | (x >> (32-y)); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/NullEngine.cs b/iTechSharp/srcbc/crypto/engines/NullEngine.cs new file mode 100644 index 0000000..407b8cc --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/NullEngine.cs @@ -0,0 +1,70 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting. + * Provided for the sake of completeness. + */ + public class NullEngine + : IBlockCipher + { + private bool initialised; + private const int BlockSize = 1; + + public NullEngine() + { + } + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + // we don't mind any parameters that may come in + initialised = true; + } + + public string AlgorithmName + { + get { return "Null"; } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + public int GetBlockSize() + { + return BlockSize; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (!initialised) + throw new InvalidOperationException("Null engine not initialised"); + if ((inOff + BlockSize) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BlockSize) > output.Length) + throw new DataLengthException("output buffer too short"); + + for (int i = 0; i < BlockSize; ++i) + { + output[outOff + i] = input[inOff + i]; + } + + return BlockSize; + } + + public void Reset() + { + // nothing needs to be done + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RC2Engine.cs b/iTechSharp/srcbc/crypto/engines/RC2Engine.cs new file mode 100644 index 0000000..aaf8c71 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RC2Engine.cs @@ -0,0 +1,312 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * an implementation of RC2 as described in RFC 2268 + * "A Description of the RC2(r) Encryption Algorithm" R. Rivest. + */ + public class RC2Engine + : IBlockCipher + { + // + // the values we use for key expansion (based on the digits of PI) + // + private static readonly byte[] piTable = + { + (byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed, + (byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d, + (byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e, + (byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2, + (byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13, + (byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32, + (byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb, + (byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82, + (byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c, + (byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc, + (byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1, + (byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26, + (byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57, + (byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3, + (byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7, + (byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7, + (byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7, + (byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a, + (byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74, + (byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec, + (byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc, + (byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39, + (byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a, + (byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31, + (byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae, + (byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9, + (byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c, + (byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9, + (byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0, + (byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e, + (byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77, + (byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad + }; + + private const int BLOCK_SIZE = 8; + + private int[] workingKey; + private bool encrypting; + + private int[] GenerateWorkingKey( + byte[] key, + int bits) + { + int x; + int[] xKey = new int[128]; + + for (int i = 0; i != key.Length; i++) + { + xKey[i] = key[i] & 0xff; + } + + // Phase 1: Expand input key to 128 bytes + int len = key.Length; + + if (len < 128) + { + int index = 0; + + x = xKey[len - 1]; + + do + { + x = piTable[(x + xKey[index++]) & 255] & 0xff; + xKey[len++] = x; + } + while (len < 128); + } + + // Phase 2 - reduce effective key size to "bits" + len = (bits + 7) >> 3; + x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff; + xKey[128 - len] = x; + + for (int i = 128 - len - 1; i >= 0; i--) + { + x = piTable[x ^ xKey[i + len]] & 0xff; + xKey[i] = x; + } + + // Phase 3 - copy to newKey in little-endian order + int[] newKey = new int[64]; + + for (int i = 0; i != newKey.Length; i++) + { + newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8)); + } + + return newKey; + } + + /** + * initialise a RC2 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.encrypting = forEncryption; + + if (parameters is RC2Parameters) + { + RC2Parameters param = (RC2Parameters) parameters; + + workingKey = GenerateWorkingKey(param.GetKey(), param.EffectiveKeyBits); + } + else if (parameters is KeyParameter) + { + KeyParameter param = (KeyParameter) parameters; + byte[] key = param.GetKey(); + + workingKey = GenerateWorkingKey(key, key.Length * 8); + } + else + { + throw new ArgumentException("invalid parameter passed to RC2 init - " + parameters.GetType().Name); + } + } + + public void Reset() + { + } + + public string AlgorithmName + { + get { return "RC2"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + throw new InvalidOperationException("RC2 engine not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (encrypting) + { + EncryptBlock(input, inOff, output, outOff); + } + else + { + DecryptBlock(input, inOff, output, outOff); + } + + return BLOCK_SIZE; + } + + /** + * return the result rotating the 16 bit number in x left by y + */ + private int RotateWordLeft( + int x, + int y) + { + x &= 0xffff; + return (x << y) | (x >> (16 - y)); + } + + private void EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int x76, x54, x32, x10; + + x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff); + x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff); + x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff); + x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff); + + for (int i = 0; i <= 16; i += 4) + { + x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1); + x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2); + x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3); + x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5); + } + + x10 += workingKey[x76 & 63]; + x32 += workingKey[x10 & 63]; + x54 += workingKey[x32 & 63]; + x76 += workingKey[x54 & 63]; + + for (int i = 20; i <= 40; i += 4) + { + x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1); + x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2); + x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3); + x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5); + } + + x10 += workingKey[x76 & 63]; + x32 += workingKey[x10 & 63]; + x54 += workingKey[x32 & 63]; + x76 += workingKey[x54 & 63]; + + for (int i = 44; i < 64; i += 4) + { + x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1); + x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2); + x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3); + x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5); + } + + outBytes[outOff + 0] = (byte)x10; + outBytes[outOff + 1] = (byte)(x10 >> 8); + outBytes[outOff + 2] = (byte)x32; + outBytes[outOff + 3] = (byte)(x32 >> 8); + outBytes[outOff + 4] = (byte)x54; + outBytes[outOff + 5] = (byte)(x54 >> 8); + outBytes[outOff + 6] = (byte)x76; + outBytes[outOff + 7] = (byte)(x76 >> 8); + } + + private void DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int x76, x54, x32, x10; + + x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff); + x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff); + x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff); + x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff); + + for (int i = 60; i >= 44; i -= 4) + { + x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]); + x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]); + x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]); + x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]); + } + + x76 -= workingKey[x54 & 63]; + x54 -= workingKey[x32 & 63]; + x32 -= workingKey[x10 & 63]; + x10 -= workingKey[x76 & 63]; + + for (int i = 40; i >= 20; i -= 4) + { + x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]); + x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]); + x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]); + x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]); + } + + x76 -= workingKey[x54 & 63]; + x54 -= workingKey[x32 & 63]; + x32 -= workingKey[x10 & 63]; + x10 -= workingKey[x76 & 63]; + + for (int i = 16; i >= 0; i -= 4) + { + x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]); + x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]); + x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]); + x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]); + } + + outBytes[outOff + 0] = (byte)x10; + outBytes[outOff + 1] = (byte)(x10 >> 8); + outBytes[outOff + 2] = (byte)x32; + outBytes[outOff + 3] = (byte)(x32 >> 8); + outBytes[outOff + 4] = (byte)x54; + outBytes[outOff + 5] = (byte)(x54 >> 8); + outBytes[outOff + 6] = (byte)x76; + outBytes[outOff + 7] = (byte)(x76 >> 8); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/RC2WrapEngine.cs b/iTechSharp/srcbc/crypto/engines/RC2WrapEngine.cs new file mode 100644 index 0000000..b89a761 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RC2WrapEngine.cs @@ -0,0 +1,372 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Wrap keys according to RFC 3217 - RC2 mechanism + */ + public class RC2WrapEngine + : IWrapper + { + /** Field engine */ + private CbcBlockCipher engine; + + /** Field param */ + private ICipherParameters parameters; + + /** Field paramPlusIV */ + private ParametersWithIV paramPlusIV; + + /** Field iv */ + private byte[] iv; + + /** Field forWrapping */ + private bool forWrapping; + + private SecureRandom sr; + + /** Field IV2 */ + private static readonly byte[] IV2 = + { + (byte) 0x4a, (byte) 0xdd, (byte) 0xa2, + (byte) 0x2c, (byte) 0x79, (byte) 0xe8, + (byte) 0x21, (byte) 0x05 + }; + + // + // checksum digest + // + IDigest sha1 = new Sha1Digest(); + byte[] digest = new byte[20]; + + /** + * Method init + * + * @param forWrapping + * @param param + */ + public void Init( + bool forWrapping, + ICipherParameters parameters) + { + this.forWrapping = forWrapping; + this.engine = new CbcBlockCipher(new RC2Engine()); + + if (parameters is ParametersWithRandom) + { + ParametersWithRandom pWithR = (ParametersWithRandom)parameters; + sr = pWithR.Random; + parameters = pWithR.Parameters; + } + else + { + sr = new SecureRandom(); + } + + if (parameters is ParametersWithIV) + { + if (!forWrapping) + throw new ArgumentException("You should not supply an IV for unwrapping"); + + this.paramPlusIV = (ParametersWithIV)parameters; + this.iv = this.paramPlusIV.GetIV(); + this.parameters = this.paramPlusIV.Parameters; + + if (this.iv.Length != 8) + throw new ArgumentException("IV is not 8 octets"); + } + else + { + this.parameters = parameters; + + if (this.forWrapping) + { + // Hm, we have no IV but we want to wrap ?!? + // well, then we have to create our own IV. + this.iv = new byte[8]; + sr.NextBytes(iv); + this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv); + } + } + } + + /** + * Method GetAlgorithmName + * + * @return + */ + public string AlgorithmName + { + get { return "RC2"; } + } + + /** + * Method wrap + * + * @param in + * @param inOff + * @param inLen + * @return + */ + public byte[] Wrap( + byte[] input, + int inOff, + int length) + { + if (!forWrapping) + { + throw new InvalidOperationException("Not initialized for wrapping"); + } + + int len = length + 1; + if ((len % 8) != 0) + { + len += 8 - (len % 8); + } + + byte [] keyToBeWrapped = new byte[len]; + + keyToBeWrapped[0] = (byte)length; + Array.Copy(input, inOff, keyToBeWrapped, 1, length); + + byte[] pad = new byte[keyToBeWrapped.Length - length - 1]; + + if (pad.Length > 0) + { + sr.NextBytes(pad); + Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length); + } + + // Compute the CMS Key Checksum, (section 5.6.1), call this CKS. + byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped); + + // Let WKCKS = WK || CKS where || is concatenation. + byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length]; + + Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length); + Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length); + + // Encrypt WKCKS in CBC mode using KEK as the key and IV as the + // initialization vector. Call the results TEMP1. + byte [] TEMP1 = new byte[WKCKS.Length]; + + Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length); + + int noOfBlocks = WKCKS.Length / engine.GetBlockSize(); + int extraBytes = WKCKS.Length % engine.GetBlockSize(); + + if (extraBytes != 0) + { + throw new InvalidOperationException("Not multiple of block length"); + } + + engine.Init(true, paramPlusIV); + + for (int i = 0; i < noOfBlocks; i++) + { + int currentBytePos = i * engine.GetBlockSize(); + + engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos); + } + + // Left TEMP2 = IV || TEMP1. + byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length]; + + Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length); + Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length); + + // Reverse the order of the octets in TEMP2 and call the result TEMP3. + byte[] TEMP3 = new byte[TEMP2.Length]; + + for (int i = 0; i < TEMP2.Length; i++) + { + TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)]; + } + + // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector + // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired + // result. It is 40 octets long if a 168 bit key is being wrapped. + ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2); + + this.engine.Init(true, param2); + + for (int i = 0; i < noOfBlocks + 1; i++) + { + int currentBytePos = i * engine.GetBlockSize(); + + engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos); + } + + return TEMP3; + } + + /** + * Method unwrap + * + * @param in + * @param inOff + * @param inLen + * @return + * @throws InvalidCipherTextException + */ + public byte[] Unwrap( + byte[] input, + int inOff, + int length) + { + if (forWrapping) + { + throw new InvalidOperationException("Not set for unwrapping"); + } + + if (input == null) + { + throw new InvalidCipherTextException("Null pointer as ciphertext"); + } + + if (length % engine.GetBlockSize() != 0) + { + throw new InvalidCipherTextException("Ciphertext not multiple of " + + engine.GetBlockSize()); + } + + /* + // Check if the length of the cipher text is reasonable given the key + // type. It must be 40 bytes for a 168 bit key and either 32, 40, or + // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported + // or inconsistent with the algorithm for which the key is intended, + // return error. + // + // we do not accept 168 bit keys. it has to be 192 bit. + int lengthA = (estimatedKeyLengthInBit / 8) + 16; + int lengthB = estimatedKeyLengthInBit % 8; + + if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) { + throw new XMLSecurityException("empty"); + } + */ + + // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK + // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3. + ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2); + + this.engine.Init(false, param2); + + byte [] TEMP3 = new byte[length]; + + Array.Copy(input, inOff, TEMP3, 0, length); + + for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++) + { + int currentBytePos = i * engine.GetBlockSize(); + + engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos); + } + + // Reverse the order of the octets in TEMP3 and call the result TEMP2. + byte[] TEMP2 = new byte[TEMP3.Length]; + + for (int i = 0; i < TEMP3.Length; i++) + { + TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)]; + } + + // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets. + this.iv = new byte[8]; + + byte[] TEMP1 = new byte[TEMP2.Length - 8]; + + Array.Copy(TEMP2, 0, this.iv, 0, 8); + Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8); + + // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV + // found in the previous step. Call the result WKCKS. + this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv); + + this.engine.Init(false, this.paramPlusIV); + + byte[] LCEKPADICV = new byte[TEMP1.Length]; + + Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length); + + for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++) + { + int currentBytePos = i * engine.GetBlockSize(); + + engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos); + } + + // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are + // those octets before the CKS. + byte[] result = new byte[LCEKPADICV.Length - 8]; + byte[] CKStoBeVerified = new byte[8]; + + Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8); + Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8); + + // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare + // with the CKS extracted in the above step. If they are not equal, return error. + if (!CheckCmsKeyChecksum(result, CKStoBeVerified)) + { + throw new InvalidCipherTextException( + "Checksum inside ciphertext is corrupted"); + } + + if ((result.Length - ((result[0] & 0xff) + 1)) > 7) + { + throw new InvalidCipherTextException( + "too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")"); + } + + // CEK is the wrapped key, now extracted for use in data decryption. + byte[] CEK = new byte[result[0]]; + Array.Copy(result, 1, CEK, 0, CEK.Length); + return CEK; + } + + /** + * Some key wrap algorithms make use of the Key Checksum defined + * in CMS [CMS-Algorithms]. This is used to provide an integrity + * check value for the key being wrapped. The algorithm is + * + * - Compute the 20 octet SHA-1 hash on the key being wrapped. + * - Use the first 8 octets of this hash as the checksum value. + * + * @param key + * @return + * @throws Exception + * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum + */ + private byte[] CalculateCmsKeyChecksum( + byte[] key) + { + byte[] result = new byte[8]; + + sha1.BlockUpdate(key, 0, key.Length); + sha1.DoFinal(digest, 0); + + Array.Copy(digest, 0, result, 0, 8); + + return result; + } + + /** + * @param key + * @param checksum + * @return + * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum + */ + private bool CheckCmsKeyChecksum( + byte[] key, + byte[] checksum) + { + return Arrays.AreEqual(CalculateCmsKeyChecksum(key), checksum); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RC4Engine.cs b/iTechSharp/srcbc/crypto/engines/RC4Engine.cs new file mode 100644 index 0000000..c65468d --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RC4Engine.cs @@ -0,0 +1,147 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + public class RC4Engine + : IStreamCipher + { + private readonly static int STATE_LENGTH = 256; + + /* + * variables to hold the state of the RC4 engine + * during encryption and decryption + */ + + private byte[] engineState; + private int x; + private int y; + private byte[] workingKey; + + /** + * initialise a RC4 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is KeyParameter) + { + /* + * RC4 encryption and decryption is completely + * symmetrical, so the 'forEncryption' is + * irrelevant. + */ + workingKey = ((KeyParameter)parameters).GetKey(); + SetKey(workingKey); + + return; + } + + throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString()); + } + + public string AlgorithmName + { + get { return "RC4"; } + } + + public byte ReturnByte( + byte input) + { + x = (x + 1) & 0xff; + y = (engineState[x] + y) & 0xff; + + // swap + byte tmp = engineState[x]; + engineState[x] = engineState[y]; + engineState[y] = tmp; + + // xor + return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]); + } + + public void ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff + ) + { + if ((inOff + length) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + length) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + for (int i = 0; i < length ; i++) + { + x = (x + 1) & 0xff; + y = (engineState[x] + y) & 0xff; + + // swap + byte tmp = engineState[x]; + engineState[x] = engineState[y]; + engineState[y] = tmp; + + // xor + output[i+outOff] = (byte)(input[i + inOff] + ^ engineState[(engineState[x] + engineState[y]) & 0xff]); + } + } + + public void Reset() + { + SetKey(workingKey); + } + + // Private implementation + + private void SetKey( + byte[] keyBytes) + { + workingKey = keyBytes; + + // System.out.println("the key length is ; "+ workingKey.Length); + + x = 0; + y = 0; + + if (engineState == null) + { + engineState = new byte[STATE_LENGTH]; + } + + // reset the state of the engine + for (int i=0; i < STATE_LENGTH; i++) + { + engineState[i] = (byte)i; + } + + int i1 = 0; + int i2 = 0; + + for (int i=0; i < STATE_LENGTH; i++) + { + i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff; + // do the byte-swap inline + byte tmp = engineState[i]; + engineState[i] = engineState[i2]; + engineState[i2] = tmp; + i1 = (i1+1) % keyBytes.Length; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/RC532Engine.cs b/iTechSharp/srcbc/crypto/engines/RC532Engine.cs new file mode 100644 index 0000000..1661707 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RC532Engine.cs @@ -0,0 +1,294 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * The specification for RC5 came from the RC5 Encryption Algorithm + * publication in RSA CryptoBytes, Spring of 1995. + * http://www.rsasecurity.com/rsalabs/cryptobytes. + *

      + * This implementation has a word size of 32 bits.

      + */ + public class RC532Engine + : IBlockCipher + { + /* + * the number of rounds to perform + */ + private int _noRounds; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private int [] _S; + + /* + * our "magic constants" for 32 32 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static readonly int P32 = unchecked((int) 0xb7e15163); + private static readonly int Q32 = unchecked((int) 0x9e3779b9); + + private bool forEncryption; + + /** + * Create an instance of the RC5 encryption algorithm + * and set some defaults + */ + public RC532Engine() + { + _noRounds = 12; // the default +// _S = null; + } + + public string AlgorithmName + { + get { return "RC5-32"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return 2 * 4; + } + + /** + * initialise a RC5-32 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (typeof(RC5Parameters).IsInstanceOfType(parameters)) + { + RC5Parameters p = (RC5Parameters)parameters; + + _noRounds = p.Rounds; + + SetKey(p.GetKey()); + } + else if (typeof(KeyParameter).IsInstanceOfType(parameters)) + { + KeyParameter p = (KeyParameter)parameters; + + SetKey(p.GetKey()); + } + else + { + throw new ArgumentException("invalid parameter passed to RC532 init - " + parameters.GetType().ToString()); + } + + this.forEncryption = forEncryption; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + return (forEncryption) + ? EncryptBlock(input, inOff, output, outOff) + : DecryptBlock(input, inOff, output, outOff); + } + + public void Reset() + { + } + + /** + * Re-key the cipher. + * + * @param key the key to be used + */ + private void SetKey( + byte[] key) + { + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = 32/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + int[] L = new int[(key.Length + (4 - 1)) / 4]; + + for (int i = 0; i != key.Length; i++) + { + L[i / 4] += (key[i] & 0xff) << (8 * (i % 4)); + } + + // + // Phase 2: + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new int[2*(_noRounds + 1)]; + + _S[0] = P32; + for (int i=1; i < _S.Length; i++) + { + _S[i] = (_S[i-1] + Q32); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.Length > _S.Length) + { + iter = 3 * L.Length; + } + else + { + iter = 3 * _S.Length; + } + + int A = 0, B = 0; + int ii = 0, jj = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[ii] = RotateLeft(_S[ii] + A + B, 3); + B = L[jj] = RotateLeft( L[jj] + A + B, A+B); + ii = (ii+1) % _S.Length; + jj = (jj+1) % L.Length; + } + } + + /** + * Encrypt the given block starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param in in byte buffer containing data to encrypt + * @param inOff offset into src buffer + * @param out out buffer where encrypted data is written + * @param outOff offset into out buffer + */ + private int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int A = BytesToWord(input, inOff) + _S[0]; + int B = BytesToWord(input, inOff + 4) + _S[1]; + + for (int i = 1; i <= _noRounds; i++) + { + A = RotateLeft(A ^ B, B) + _S[2*i]; + B = RotateLeft(B ^ A, A) + _S[2*i+1]; + } + + WordToBytes(A, outBytes, outOff); + WordToBytes(B, outBytes, outOff + 4); + + return 2 * 4; + } + + private int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int A = BytesToWord(input, inOff); + int B = BytesToWord(input, inOff + 4); + + for (int i = _noRounds; i >= 1; i--) + { + B = RotateRight(B - _S[2*i+1], A) ^ A; + A = RotateRight(A - _S[2*i], B) ^ B; + } + + WordToBytes(A - _S[0], outBytes, outOff); + WordToBytes(B - _S[1], outBytes, outOff + 4); + + return 2 * 4; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(32) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * + * @param x word to rotate + * @param y number of bits to rotate % 32 + */ + private int RotateLeft(int x, int y) { + return ((int) ( (uint) (x << (y & (32-1))) | + ((uint) x >> (32 - (y & (32-1)))) ) + ); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(32) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * + * @param x word to rotate + * @param y number of bits to rotate % 32 + */ + private int RotateRight(int x, int y) { + return ((int) ( ((uint) x >> (y & (32-1))) | + (uint) (x << (32 - (y & (32-1)))) ) + ); + } + + private int BytesToWord( + byte[] src, + int srcOff) + { + return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8) + | ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24); + } + + private void WordToBytes( + int word, + byte[] dst, + int dstOff) + { + dst[dstOff] = (byte)word; + dst[dstOff + 1] = (byte)(word >> 8); + dst[dstOff + 2] = (byte)(word >> 16); + dst[dstOff + 3] = (byte)(word >> 24); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/RC564Engine.cs b/iTechSharp/srcbc/crypto/engines/RC564Engine.cs new file mode 100644 index 0000000..5c69d40 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RC564Engine.cs @@ -0,0 +1,295 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * The specification for RC5 came from the RC5 Encryption Algorithm + * publication in RSA CryptoBytes, Spring of 1995. + * http://www.rsasecurity.com/rsalabs/cryptobytes. + *

      + * This implementation is set to work with a 64 bit word size.

      + */ + public class RC564Engine + : IBlockCipher + { + private static readonly int wordSize = 64; + private static readonly int bytesPerWord = wordSize / 8; + + /* + * the number of rounds to perform + */ + private int _noRounds; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private long [] _S; + + /* + * our "magic constants" for wordSize 62 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static readonly long P64 = unchecked( (long) 0xb7e151628aed2a6bL); + private static readonly long Q64 = unchecked( (long) 0x9e3779b97f4a7c15L); + + private bool forEncryption; + + /** + * Create an instance of the RC5 encryption algorithm + * and set some defaults + */ + public RC564Engine() + { + _noRounds = 12; +// _S = null; + } + + public string AlgorithmName + { + get { return "RC5-64"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return 2 * bytesPerWord; + } + + /** + * initialise a RC5-64 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(typeof(RC5Parameters).IsInstanceOfType(parameters))) + { + throw new ArgumentException("invalid parameter passed to RC564 init - " + parameters.GetType().ToString()); + } + + RC5Parameters p = (RC5Parameters)parameters; + + this.forEncryption = forEncryption; + + _noRounds = p.Rounds; + + SetKey(p.GetKey()); + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) + : DecryptBlock(input, inOff, output, outOff); + } + + public void Reset() + { + } + + /** + * Re-key the cipher. + * + * @param key the key to be used + */ + private void SetKey( + byte[] key) + { + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = wordSize/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + long[] L = new long[(key.Length + (bytesPerWord - 1)) / bytesPerWord]; + + for (int i = 0; i != key.Length; i++) + { + L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord)); + } + + // + // Phase 2: + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new long[2*(_noRounds + 1)]; + + _S[0] = P64; + for (int i=1; i < _S.Length; i++) + { + _S[i] = (_S[i-1] + Q64); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.Length > _S.Length) + { + iter = 3 * L.Length; + } + else + { + iter = 3 * _S.Length; + } + + long A = 0, B = 0; + int ii = 0, jj = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[ii] = RotateLeft(_S[ii] + A + B, 3); + B = L[jj] = RotateLeft( L[jj] + A + B, A+B); + ii = (ii+1) % _S.Length; + jj = (jj+1) % L.Length; + } + } + + /** + * Encrypt the given block starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * + * @param in in byte buffer containing data to encrypt + * @param inOff offset into src buffer + * @param out out buffer where encrypted data is written + * @param outOff offset into out buffer + */ + private int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + long A = BytesToWord(input, inOff) + _S[0]; + long B = BytesToWord(input, inOff + bytesPerWord) + _S[1]; + + for (int i = 1; i <= _noRounds; i++) + { + A = RotateLeft(A ^ B, B) + _S[2*i]; + B = RotateLeft(B ^ A, A) + _S[2*i+1]; + } + + WordToBytes(A, outBytes, outOff); + WordToBytes(B, outBytes, outOff + bytesPerWord); + + return 2 * bytesPerWord; + } + + private int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + long A = BytesToWord(input, inOff); + long B = BytesToWord(input, inOff + bytesPerWord); + + for (int i = _noRounds; i >= 1; i--) + { + B = RotateRight(B - _S[2*i+1], A) ^ A; + A = RotateRight(A - _S[2*i], B) ^ B; + } + + WordToBytes(A - _S[0], outBytes, outOff); + WordToBytes(B - _S[1], outBytes, outOff + bytesPerWord); + + return 2 * bytesPerWord; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * + * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private long RotateLeft(long x, long y) { + return ((long) ( (ulong) (x << (int) (y & (wordSize-1))) | + ((ulong) x >> (int) (wordSize - (y & (wordSize-1))))) + ); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * + * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private long RotateRight(long x, long y) { + return ((long) ( ((ulong) x >> (int) (y & (wordSize-1))) | + (ulong) (x << (int) (wordSize - (y & (wordSize-1))))) + ); + } + + private long BytesToWord( + byte[] src, + int srcOff) + { + long word = 0; + + for (int i = bytesPerWord - 1; i >= 0; i--) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void WordToBytes( + long word, + byte[] dst, + int dstOff) + { + for (int i = 0; i < bytesPerWord; i++) + { + dst[i + dstOff] = (byte)word; + word = (long) ((ulong) word >> 8); + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/RC6Engine.cs b/iTechSharp/srcbc/crypto/engines/RC6Engine.cs new file mode 100644 index 0000000..d72cc2f --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RC6Engine.cs @@ -0,0 +1,362 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * An RC6 engine. + */ + public class RC6Engine + : IBlockCipher + { + private static readonly int wordSize = 32; + private static readonly int bytesPerWord = wordSize / 8; + + /* + * the number of rounds to perform + */ + private static readonly int _noRounds = 20; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private int [] _S; + + /* + * our "magic constants" for wordSize 32 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static readonly int P32 = unchecked((int) 0xb7e15163); + private static readonly int Q32 = unchecked((int) 0x9e3779b9); + + private static readonly int LGW = 5; // log2(32) + + private bool forEncryption; + + /** + * Create an instance of the RC6 encryption algorithm + * and set some defaults + */ + public RC6Engine() + { +// _S = null; + } + + public string AlgorithmName + { + get { return "RC6"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return 4 * bytesPerWord; + } + + /** + * initialise a RC5-32 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to RC6 init - " + parameters.GetType().ToString()); + + this.forEncryption = forEncryption; + + KeyParameter p = (KeyParameter)parameters; + SetKey(p.GetKey()); + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + int blockSize = GetBlockSize(); + if (_S == null) + throw new InvalidOperationException("RC6 engine not initialised"); + if ((inOff + blockSize) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + blockSize) > output.Length) + throw new DataLengthException("output buffer too short"); + + return (forEncryption) + ? EncryptBlock(input, inOff, output, outOff) + : DecryptBlock(input, inOff, output, outOff); + } + + public void Reset() + { + } + + /** + * Re-key the cipher. + * + * @param inKey the key to be used + */ + private void SetKey( + byte[] key) + { + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = wordSize/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + // compute number of dwords + int c = (key.Length + (bytesPerWord - 1)) / bytesPerWord; + if (c == 0) + { + c = 1; + } + int[] L = new int[(key.Length + bytesPerWord - 1) / bytesPerWord]; + + // load all key bytes into array of key dwords + for (int i = key.Length - 1; i >= 0; i--) + { + L[i / bytesPerWord] = (L[i / bytesPerWord] << 8) + (key[i] & 0xff); + } + + // + // Phase 2: + // Key schedule is placed in a array of 2+2*ROUNDS+2 = 44 dwords. + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new int[2+2*_noRounds+2]; + + _S[0] = P32; + for (int i=1; i < _S.Length; i++) + { + _S[i] = (_S[i-1] + Q32); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.Length > _S.Length) + { + iter = 3 * L.Length; + } + else + { + iter = 3 * _S.Length; + } + + int A = 0; + int B = 0; + int ii = 0, jj = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[ii] = RotateLeft(_S[ii] + A + B, 3); + B = L[jj] = RotateLeft( L[jj] + A + B, A+B); + ii = (ii+1) % _S.Length; + jj = (jj+1) % L.Length; + } + } + + private int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + // load A,B,C and D registers from in. + int A = BytesToWord(input, inOff); + int B = BytesToWord(input, inOff + bytesPerWord); + int C = BytesToWord(input, inOff + bytesPerWord*2); + int D = BytesToWord(input, inOff + bytesPerWord*3); + + // Do pseudo-round #0: pre-whitening of B and D + B += _S[0]; + D += _S[1]; + + // perform round #1,#2 ... #ROUNDS of encryption + for (int i = 1; i <= _noRounds; i++) + { + int t = 0,u = 0; + + t = B*(2*B+1); + t = RotateLeft(t,5); + + u = D*(2*D+1); + u = RotateLeft(u,5); + + A ^= t; + A = RotateLeft(A,u); + A += _S[2*i]; + + C ^= u; + C = RotateLeft(C,t); + C += _S[2*i+1]; + + int temp = A; + A = B; + B = C; + C = D; + D = temp; + } + // do pseudo-round #(ROUNDS+1) : post-whitening of A and C + A += _S[2*_noRounds+2]; + C += _S[2*_noRounds+3]; + + // store A, B, C and D registers to out + WordToBytes(A, outBytes, outOff); + WordToBytes(B, outBytes, outOff + bytesPerWord); + WordToBytes(C, outBytes, outOff + bytesPerWord*2); + WordToBytes(D, outBytes, outOff + bytesPerWord*3); + + return 4 * bytesPerWord; + } + + private int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + // load A,B,C and D registers from out. + int A = BytesToWord(input, inOff); + int B = BytesToWord(input, inOff + bytesPerWord); + int C = BytesToWord(input, inOff + bytesPerWord*2); + int D = BytesToWord(input, inOff + bytesPerWord*3); + + // Undo pseudo-round #(ROUNDS+1) : post whitening of A and C + C -= _S[2*_noRounds+3]; + A -= _S[2*_noRounds+2]; + + // Undo round #ROUNDS, .., #2,#1 of encryption + for (int i = _noRounds; i >= 1; i--) + { + int t=0,u = 0; + + int temp = D; + D = C; + C = B; + B = A; + A = temp; + + t = B*(2*B+1); + t = RotateLeft(t, LGW); + + u = D*(2*D+1); + u = RotateLeft(u, LGW); + + C -= _S[2*i+1]; + C = RotateRight(C,t); + C ^= u; + + A -= _S[2*i]; + A = RotateRight(A,u); + A ^= t; + + } + // Undo pseudo-round #0: pre-whitening of B and D + D -= _S[1]; + B -= _S[0]; + + WordToBytes(A, outBytes, outOff); + WordToBytes(B, outBytes, outOff + bytesPerWord); + WordToBytes(C, outBytes, outOff + bytesPerWord*2); + WordToBytes(D, outBytes, outOff + bytesPerWord*3); + + return 4 * bytesPerWord; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * + * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private int RotateLeft(int x, int y) + { + return ((int)((uint)(x << (y & (wordSize-1))) + | ((uint) x >> (wordSize - (y & (wordSize-1)))))); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word x is rotated left by y bits. + * Only the lg(wordSize) low-order bits of y + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * + * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private int RotateRight(int x, int y) + { + return ((int)(((uint) x >> (y & (wordSize-1))) + | (uint)(x << (wordSize - (y & (wordSize-1)))))); + } + + private int BytesToWord( + byte[] src, + int srcOff) + { + int word = 0; + + for (int i = bytesPerWord - 1; i >= 0; i--) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void WordToBytes( + int word, + byte[] dst, + int dstOff) + { + for (int i = 0; i < bytesPerWord; i++) + { + dst[i + dstOff] = (byte)word; + word = (int) ((uint) word >> 8); + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/RFC3211WrapEngine.cs b/iTechSharp/srcbc/crypto/engines/RFC3211WrapEngine.cs new file mode 100644 index 0000000..906630a --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RFC3211WrapEngine.cs @@ -0,0 +1,166 @@ +using System; + +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * an implementation of the RFC 3211 Key Wrap + * Specification. + */ + public class Rfc3211WrapEngine + : IWrapper + { + private CbcBlockCipher engine; + private ParametersWithIV param; + private bool forWrapping; + private SecureRandom rand; + + public Rfc3211WrapEngine( + IBlockCipher engine) + { + this.engine = new CbcBlockCipher(engine); + } + + public void Init( + bool forWrapping, + ICipherParameters param) + { + this.forWrapping = forWrapping; + + if (param is ParametersWithRandom) + { + ParametersWithRandom p = (ParametersWithRandom) param; + + this.rand = p.Random; + this.param = (ParametersWithIV) p.Parameters; + } + else + { + if (forWrapping) + { + rand = new SecureRandom(); + } + + this.param = (ParametersWithIV) param; + } + } + + public string AlgorithmName + { + get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; } + } + + public byte[] Wrap( + byte[] inBytes, + int inOff, + int inLen) + { + if (!forWrapping) + { + throw new InvalidOperationException("not set for wrapping"); + } + + engine.Init(true, param); + + int blockSize = engine.GetBlockSize(); + byte[] cekBlock; + + if (inLen + 4 < blockSize * 2) + { + cekBlock = new byte[blockSize * 2]; + } + else + { + cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize]; + } + + cekBlock[0] = (byte)inLen; + cekBlock[1] = (byte)~inBytes[inOff]; + cekBlock[2] = (byte)~inBytes[inOff + 1]; + cekBlock[3] = (byte)~inBytes[inOff + 2]; + + Array.Copy(inBytes, inOff, cekBlock, 4, inLen); + + rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4); + + for (int i = 0; i < cekBlock.Length; i += blockSize) + { + engine.ProcessBlock(cekBlock, i, cekBlock, i); + } + + for (int i = 0; i < cekBlock.Length; i += blockSize) + { + engine.ProcessBlock(cekBlock, i, cekBlock, i); + } + + return cekBlock; + } + + public byte[] Unwrap( + byte[] inBytes, + int inOff, + int inLen) + { + if (forWrapping) + { + throw new InvalidOperationException("not set for unwrapping"); + } + + int blockSize = engine.GetBlockSize(); + + if (inLen < 2 * blockSize) + { + throw new InvalidCipherTextException("input too short"); + } + + byte[] cekBlock = new byte[inLen]; + byte[] iv = new byte[blockSize]; + + Array.Copy(inBytes, inOff, cekBlock, 0, inLen); + Array.Copy(inBytes, inOff, iv, 0, iv.Length); + + engine.Init(false, new ParametersWithIV(param.Parameters, iv)); + + for (int i = blockSize; i < cekBlock.Length; i += blockSize) + { + engine.ProcessBlock(cekBlock, i, cekBlock, i); + } + + Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length); + + engine.Init(false, new ParametersWithIV(param.Parameters, iv)); + + engine.ProcessBlock(cekBlock, 0, cekBlock, 0); + + engine.Init(false, param); + + for (int i = 0; i < cekBlock.Length; i += blockSize) + { + engine.ProcessBlock(cekBlock, i, cekBlock, i); + } + + if ((cekBlock[0] & 0xff) > cekBlock.Length - 4) + { + throw new InvalidCipherTextException("wrapped key corrupted"); + } + + byte[] key = new byte[cekBlock[0] & 0xff]; + + Array.Copy(cekBlock, 4, key, 0, cekBlock[0]); + + for (int i = 0; i != 3; i++) + { + byte check = (byte)~cekBlock[1 + i]; + if (check != key[i]) + { + throw new InvalidCipherTextException("wrapped key fails checksum"); + } + } + + return key; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RFC3394WrapEngine.cs b/iTechSharp/srcbc/crypto/engines/RFC3394WrapEngine.cs new file mode 100644 index 0000000..fc45805 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RFC3394WrapEngine.cs @@ -0,0 +1,181 @@ +using System; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// + /// An implementation of the AES Key Wrapper from the NIST Key Wrap + /// Specification as described in RFC 3394. + ///

      + /// For further details see: http://www.ietf.org/rfc/rfc3394.txt + /// and http://csrc.nist.gov/encryption/kms/key-wrap.pdf. + /// + public class Rfc3394WrapEngine + : IWrapper + { + private readonly IBlockCipher engine; + + private KeyParameter param; + private bool forWrapping; + + private byte[] iv = + { + 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6 + }; + + public Rfc3394WrapEngine( + IBlockCipher engine) + { + this.engine = engine; + } + + public void Init( + bool forWrapping, + ICipherParameters parameters) + { + this.forWrapping = forWrapping; + + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + if (parameters is KeyParameter) + { + this.param = (KeyParameter) parameters; + } + else if (parameters is ParametersWithIV) + { + ParametersWithIV pIV = (ParametersWithIV) parameters; + byte[] iv = pIV.GetIV(); + + if (iv.Length != 8) + throw new ArgumentException("IV length not equal to 8", "parameters"); + + this.iv = iv; + this.param = (KeyParameter) pIV.Parameters; + } + else + { + // TODO Throw an exception for bad parameters? + } + } + + public string AlgorithmName + { + get { return engine.AlgorithmName; } + } + + public byte[] Wrap( + byte[] input, + int inOff, + int inLen) + { + if (!forWrapping) + { + throw new InvalidOperationException("not set for wrapping"); + } + + int n = inLen / 8; + + if ((n * 8) != inLen) + { + throw new DataLengthException("wrap data must be a multiple of 8 bytes"); + } + + byte[] block = new byte[inLen + iv.Length]; + byte[] buf = new byte[8 + iv.Length]; + + Array.Copy(iv, 0, block, 0, iv.Length); + Array.Copy(input, 0, block, iv.Length, inLen); + + engine.Init(true, param); + + for (int j = 0; j != 6; j++) + { + for (int i = 1; i <= n; i++) + { + Array.Copy(block, 0, buf, 0, iv.Length); + Array.Copy(block, 8 * i, buf, iv.Length, 8); + engine.ProcessBlock(buf, 0, buf, 0); + + int t = n * j + i; + for (int k = 1; t != 0; k++) + { + byte v = (byte)t; + + buf[iv.Length - k] ^= v; + t = (int) ((uint)t >> 8); + } + + Array.Copy(buf, 0, block, 0, 8); + Array.Copy(buf, 8, block, 8 * i, 8); + } + } + + return block; + } + + public byte[] Unwrap( + byte[] input, + int inOff, + int inLen) + { + if (forWrapping) + { + throw new InvalidOperationException("not set for unwrapping"); + } + + int n = inLen / 8; + + if ((n * 8) != inLen) + { + throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes"); + } + + byte[] block = new byte[inLen - iv.Length]; + byte[] a = new byte[iv.Length]; + byte[] buf = new byte[8 + iv.Length]; + + Array.Copy(input, 0, a, 0, iv.Length); + Array.Copy(input, iv.Length, block, 0, inLen - iv.Length); + + engine.Init(false, param); + + n = n - 1; + + for (int j = 5; j >= 0; j--) + { + for (int i = n; i >= 1; i--) + { + Array.Copy(a, 0, buf, 0, iv.Length); + Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8); + + int t = n * j + i; + for (int k = 1; t != 0; k++) + { + byte v = (byte)t; + + buf[iv.Length - k] ^= v; + t = (int) ((uint)t >> 8); + } + + engine.ProcessBlock(buf, 0, buf, 0); + Array.Copy(buf, 0, a, 0, 8); + Array.Copy(buf, 8, block, 8 * (i - 1), 8); + } + } + + for (int i = 0; i != iv.Length; i++) + { + if (a[i] != iv[i]) + { + throw new InvalidCipherTextException("checksum failed"); + } + } + + return block; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RSABlindedEngine.cs b/iTechSharp/srcbc/crypto/engines/RSABlindedEngine.cs new file mode 100644 index 0000000..35d315a --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RSABlindedEngine.cs @@ -0,0 +1,139 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * this does your basic RSA algorithm with blinding + */ + public class RsaBlindedEngine + : IAsymmetricBlockCipher + { + private readonly RsaCoreEngine core = new RsaCoreEngine(); + private RsaKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "RSA"; } + } + + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ + public void Init( + bool forEncryption, + ICipherParameters param) + { + core.Init(forEncryption, param); + + if (param is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + key = (RsaKeyParameters)rParam.Parameters; + random = rParam.Random; + } + else + { + key = (RsaKeyParameters)param; + random = new SecureRandom(); + } + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int GetInputBlockSize() + { + return core.GetInputBlockSize(); + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int GetOutputBlockSize() + { + return core.GetOutputBlockSize(); + } + + /** + * Process a single block using the basic RSA algorithm. + * + * @param inBuf the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @exception DataLengthException the input block is too large. + */ + public byte[] ProcessBlock( + byte[] inBuf, + int inOff, + int inLen) + { + if (key == null) + throw new InvalidOperationException("RSA engine not initialised"); + + BigInteger input = core.ConvertInput(inBuf, inOff, inLen); + + BigInteger result; + if (key is RsaPrivateCrtKeyParameters) + { + RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key; + if (k.PublicExponent != null) // can't do blinding without a public exponent + { + BigInteger m = k.Modulus; + BigInteger r = calculateR(m); + + BigInteger blindedInput = r.ModPow(k.PublicExponent, m).Multiply(input).Mod(m); + BigInteger blindedResult = core.ProcessBlock(blindedInput); + + result = blindedResult.Multiply(r.ModInverse(m)).Mod(m); + } + else + { + result = core.ProcessBlock(input); + } + } + else + { + result = core.ProcessBlock(input); + } + + return core.ConvertOutput(result); + } + + /* + * calculate a random mess-with-their-heads value. + */ + private BigInteger calculateR( + BigInteger m) + { + int max = m.BitLength - 1; // must be less than m.BitLength + int min = max / 2; + int length = ((random.NextInt() & 0xff) * ((max - min) / 0xff)) + min; + BigInteger factor = new BigInteger(length, random); + + while (factor.SignValue == 0) + { + factor = new BigInteger(length, random); + } + + return factor; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RSABlindingEngine.cs b/iTechSharp/srcbc/crypto/engines/RSABlindingEngine.cs new file mode 100644 index 0000000..76b57a3 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RSABlindingEngine.cs @@ -0,0 +1,139 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * This does your basic RSA Chaum's blinding and unblinding as outlined in + * "Handbook of Applied Cryptography", page 475. You need to use this if you are + * trying to get another party to generate signatures without them being aware + * of the message they are signing. + */ + public class RsaBlindingEngine + : IAsymmetricBlockCipher + { + private readonly RsaCoreEngine core = new RsaCoreEngine(); + + private RsaKeyParameters key; + private BigInteger blindingFactor; + + private bool forEncryption; + + public string AlgorithmName + { + get { return "RSA"; } + } + + /** + * Initialise the blinding engine. + * + * @param forEncryption true if we are encrypting (blinding), false otherwise. + * @param param the necessary RSA key parameters. + */ + public void Init( + bool forEncryption, + ICipherParameters param) + { + RsaBlindingParameters p; + + if (param is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + p = (RsaBlindingParameters)rParam.Parameters; + } + else + { + p = (RsaBlindingParameters)param; + } + + core.Init(forEncryption, p.PublicKey); + + this.forEncryption = forEncryption; + this.key = p.PublicKey; + this.blindingFactor = p.BlindingFactor; + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int GetInputBlockSize() + { + return core.GetInputBlockSize(); + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int GetOutputBlockSize() + { + return core.GetOutputBlockSize(); + } + + /** + * Process a single block using the RSA blinding algorithm. + * + * @param in the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @throws DataLengthException the input block is too large. + */ + public byte[] ProcessBlock( + byte[] inBuf, + int inOff, + int inLen) + { + BigInteger msg = core.ConvertInput(inBuf, inOff, inLen); + + if (forEncryption) + { + msg = BlindMessage(msg); + } + else + { + msg = UnblindMessage(msg); + } + + return core.ConvertOutput(msg); + } + + /* + * Blind message with the blind factor. + */ + private BigInteger BlindMessage( + BigInteger msg) + { + BigInteger blindMsg = blindingFactor; + blindMsg = msg.Multiply(blindMsg.ModPow(key.Exponent, key.Modulus)); + blindMsg = blindMsg.Mod(key.Modulus); + + return blindMsg; + } + + /* + * Unblind the message blinded with the blind factor. + */ + private BigInteger UnblindMessage( + BigInteger blindedMsg) + { + BigInteger m = key.Modulus; + BigInteger msg = blindedMsg; + BigInteger blindFactorInverse = blindingFactor.ModInverse(m); + msg = msg.Multiply(blindFactorInverse); + msg = msg.Mod(m); + + return msg; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RSACoreEngine.cs b/iTechSharp/srcbc/crypto/engines/RSACoreEngine.cs new file mode 100644 index 0000000..4e64d25 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RSACoreEngine.cs @@ -0,0 +1,156 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * this does your basic RSA algorithm. + */ + class RsaCoreEngine + { + private RsaKeyParameters key; + private bool forEncryption; + private int bitSize; + + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + if (!(parameters is RsaKeyParameters)) + throw new InvalidKeyException("Not an RSA key"); + + this.key = (RsaKeyParameters) parameters; + this.forEncryption = forEncryption; + this.bitSize = key.Modulus.BitLength; + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int GetInputBlockSize() + { + if (forEncryption) + { + return (bitSize - 1) / 8; + } + + return (bitSize + 7) / 8; + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int GetOutputBlockSize() + { + if (forEncryption) + { + return (bitSize + 7) / 8; + } + + return (bitSize - 1) / 8; + } + + public BigInteger ConvertInput( + byte[] inBuf, + int inOff, + int inLen) + { + int maxLength = (bitSize + 7) / 8; + + if (inLen > maxLength) + throw new DataLengthException("input too large for RSA cipher."); + + BigInteger input = new BigInteger(1, inBuf, inOff, inLen); + + if (input.CompareTo(key.Modulus) >= 0) + throw new DataLengthException("input too large for RSA cipher."); + + return input; + } + + public byte[] ConvertOutput( + BigInteger result) + { + byte[] output = result.ToByteArrayUnsigned(); + + if (forEncryption) + { + int outSize = GetOutputBlockSize(); + + // TODO To avoid this, create version of BigInteger.ToByteArray that + // writes to an existing array + if (output.Length < outSize) // have ended up with less bytes than normal, lengthen + { + byte[] tmp = new byte[outSize]; + output.CopyTo(tmp, tmp.Length - output.Length); + output = tmp; + } + } + + return output; + } + + public BigInteger ProcessBlock( + BigInteger input) + { + if (key is RsaPrivateCrtKeyParameters) + { + // + // we have the extra factors, use the Chinese Remainder Theorem - the author + // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for + // advice regarding the expression of this. + // + RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key; + + BigInteger p = crtKey.P;; + BigInteger q = crtKey.Q; + BigInteger dP = crtKey.DP; + BigInteger dQ = crtKey.DQ; + BigInteger qInv = crtKey.QInv; + + BigInteger mP, mQ, h, m; + + // mP = ((input Mod p) ^ dP)) Mod p + mP = (input.Remainder(p)).ModPow(dP, p); + + // mQ = ((input Mod q) ^ dQ)) Mod q + mQ = (input.Remainder(q)).ModPow(dQ, q); + + // h = qInv * (mP - mQ) Mod p + h = mP.Subtract(mQ); + h = h.Multiply(qInv); + h = h.Mod(p); // Mod (in Java) returns the positive residual + + // m = h * q + mQ + m = h.Multiply(q); + m = m.Add(mQ); + + return m; + } + + return input.ModPow(key.Exponent, key.Modulus); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/RijndaelEngine.cs b/iTechSharp/srcbc/crypto/engines/RijndaelEngine.cs new file mode 100644 index 0000000..e8f9752 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RijndaelEngine.cs @@ -0,0 +1,740 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * an implementation of Rijndael, based on the documentation and reference implementation + * by Paulo Barreto, Vincent Rijmen, for v2.0 August '99. + *

      + * Note: this implementation is based on information prior to readonly NIST publication. + *

      + */ + public class RijndaelEngine + : IBlockCipher + { + private static readonly int MAXROUNDS = 14; + + private static readonly int MAXKC = (256/4); + + private static readonly byte[] Logtable = { + (byte)0, (byte)0, (byte)25, (byte)1, (byte)50, (byte)2, (byte)26, (byte)198, + (byte)75, (byte)199, (byte)27, (byte)104, (byte)51, (byte)238, (byte)223, (byte)3, + (byte)100, (byte)4, (byte)224, (byte)14, (byte)52, (byte)141, (byte)129, (byte)239, + (byte)76, (byte)113, (byte)8, (byte)200, (byte)248, (byte)105, (byte)28, (byte)193, + (byte)125, (byte)194, (byte)29, (byte)181, (byte)249, (byte)185, (byte)39, (byte)106, + (byte)77, (byte)228, (byte)166, (byte)114, (byte)154, (byte)201, (byte)9, (byte)120, + (byte)101, (byte)47, (byte)138, (byte)5, (byte)33, (byte)15, (byte)225, (byte)36, + (byte)18, (byte)240, (byte)130, (byte)69, (byte)53, (byte)147, (byte)218, (byte)142, + (byte)150, (byte)143, (byte)219, (byte)189, (byte)54, (byte)208, (byte)206, (byte)148, + (byte)19, (byte)92, (byte)210, (byte)241, (byte)64, (byte)70, (byte)131, (byte)56, + (byte)102, (byte)221, (byte)253, (byte)48, (byte)191, (byte)6, (byte)139, (byte)98, + (byte)179, (byte)37, (byte)226, (byte)152, (byte)34, (byte)136, (byte)145, (byte)16, + (byte)126, (byte)110, (byte)72, (byte)195, (byte)163, (byte)182, (byte)30, (byte)66, + (byte)58, (byte)107, (byte)40, (byte)84, (byte)250, (byte)133, (byte)61, (byte)186, + (byte)43, (byte)121, (byte)10, (byte)21, (byte)155, (byte)159, (byte)94, (byte)202, + (byte)78, (byte)212, (byte)172, (byte)229, (byte)243, (byte)115, (byte)167, (byte)87, + (byte)175, (byte)88, (byte)168, (byte)80, (byte)244, (byte)234, (byte)214, (byte)116, + (byte)79, (byte)174, (byte)233, (byte)213, (byte)231, (byte)230, (byte)173, (byte)232, + (byte)44, (byte)215, (byte)117, (byte)122, (byte)235, (byte)22, (byte)11, (byte)245, + (byte)89, (byte)203, (byte)95, (byte)176, (byte)156, (byte)169, (byte)81, (byte)160, + (byte)127, (byte)12, (byte)246, (byte)111, (byte)23, (byte)196, (byte)73, (byte)236, + (byte)216, (byte)67, (byte)31, (byte)45, (byte)164, (byte)118, (byte)123, (byte)183, + (byte)204, (byte)187, (byte)62, (byte)90, (byte)251, (byte)96, (byte)177, (byte)134, + (byte)59, (byte)82, (byte)161, (byte)108, (byte)170, (byte)85, (byte)41, (byte)157, + (byte)151, (byte)178, (byte)135, (byte)144, (byte)97, (byte)190, (byte)220, (byte)252, + (byte)188, (byte)149, (byte)207, (byte)205, (byte)55, (byte)63, (byte)91, (byte)209, + (byte)83, (byte)57, (byte)132, (byte)60, (byte)65, (byte)162, (byte)109, (byte)71, + (byte)20, (byte)42, (byte)158, (byte)93, (byte)86, (byte)242, (byte)211, (byte)171, + (byte)68, (byte)17, (byte)146, (byte)217, (byte)35, (byte)32, (byte)46, (byte)137, + (byte)180, (byte)124, (byte)184, (byte)38, (byte)119, (byte)153, (byte)227, (byte)165, + (byte)103, (byte)74, (byte)237, (byte)222, (byte)197, (byte)49, (byte)254, (byte)24, + (byte)13, (byte)99, (byte)140, (byte)128, (byte)192, (byte)247, (byte)112, (byte)7 + }; + + private static readonly byte[] Alogtable = { + (byte)0, (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53, + (byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170, + (byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49, + (byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205, + (byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136, + (byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154, + (byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163, + (byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160, + (byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65, + (byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117, + (byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128, + (byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84, + (byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202, + (byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14, + (byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23, + (byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1, + (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53, + (byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170, + (byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49, + (byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205, + (byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136, + (byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154, + (byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163, + (byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160, + (byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65, + (byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117, + (byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128, + (byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84, + (byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202, + (byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14, + (byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23, + (byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1, + }; + + private static readonly byte[] S = { + (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118, + (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192, + (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21, + (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117, + (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132, + (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207, + (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168, + (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210, + (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115, + (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219, + (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121, + (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8, + (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138, + (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158, + (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223, + (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22, + }; + + private static readonly byte[] Si = { + (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251, + (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203, + (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78, + (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37, + (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146, + (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132, + (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6, + (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107, + (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115, + (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110, + (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27, + (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244, + (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95, + (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239, + (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97, + (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125, + }; + + private static readonly int[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; + + static readonly byte[][] shifts0 = new byte [][] + { + new byte [] { 0, 8, 16, 24 }, + new byte [] { 0, 8, 16, 24 }, + new byte [] { 0, 8, 16, 24 }, + new byte [] { 0, 8, 16, 32 }, + new byte [] { 0, 8, 24, 32 } + }; + + static readonly byte[][] shifts1 = + { + new byte [] { 0, 24, 16, 8 }, + new byte [] { 0, 32, 24, 16 }, + new byte [] { 0, 40, 32, 24 }, + new byte [] { 0, 48, 40, 24 }, + new byte [] { 0, 56, 40, 32 } + }; + + /** + * multiply two elements of GF(2^m) + * needed for MixColumn and InvMixColumn + */ + private byte Mul0x2( + int b) + { + if (b != 0) + { + return Alogtable[25 + (Logtable[b] & 0xff)]; + } + else + { + return 0; + } + } + + private byte Mul0x3( + int b) + { + if (b != 0) + { + return Alogtable[1 + (Logtable[b] & 0xff)]; + } + else + { + return 0; + } + } + + private byte Mul0x9( + int b) + { + if (b >= 0) + { + return Alogtable[199 + b]; + } + else + { + return 0; + } + } + + private byte Mul0xb( + int b) + { + if (b >= 0) + { + return Alogtable[104 + b]; + } + else + { + return 0; + } + } + + private byte Mul0xd( + int b) + { + if (b >= 0) + { + return Alogtable[238 + b]; + } + else + { + return 0; + } + } + + private byte Mul0xe( + int b) + { + if (b >= 0) + { + return Alogtable[223 + b]; + } + else + { + return 0; + } + } + + /** + * xor corresponding text input and round key input bytes + */ + private void KeyAddition( + long[] rk) + { + A0 ^= rk[0]; + A1 ^= rk[1]; + A2 ^= rk[2]; + A3 ^= rk[3]; + } + + private long Shift( + long r, + int shift) + { + //return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK; + + ulong temp = (ulong) r >> shift; + + // NB: This corrects for Mono Bug #79087 (fixed in 1.1.17) + if (shift > 31) + { + temp &= 0xFFFFFFFFUL; + } + + return ((long) temp | (r << (BC - shift))) & BC_MASK; + } + + /** + * Row 0 remains unchanged + * The other three rows are shifted a variable amount + */ + private void ShiftRow( + byte[] shiftsSC) + { + A1 = Shift(A1, shiftsSC[1]); + A2 = Shift(A2, shiftsSC[2]); + A3 = Shift(A3, shiftsSC[3]); + } + + private long ApplyS( + long r, + byte[] box) + { + long res = 0; + + for (int j = 0; j < BC; j += 8) + { + res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j; + } + + return res; + } + + /** + * Replace every byte of the input by the byte at that place + * in the nonlinear S-box + */ + private void Substitution( + byte[] box) + { + A0 = ApplyS(A0, box); + A1 = ApplyS(A1, box); + A2 = ApplyS(A2, box); + A3 = ApplyS(A3, box); + } + + /** + * Mix the bytes of every column in a linear way + */ + private void MixColumn() + { + long r0, r1, r2, r3; + + r0 = r1 = r2 = r3 = 0; + + for (int j = 0; j < BC; j += 8) + { + int a0 = (int)((A0 >> j) & 0xff); + int a1 = (int)((A1 >> j) & 0xff); + int a2 = (int)((A2 >> j) & 0xff); + int a3 = (int)((A3 >> j) & 0xff); + + r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; + + r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; + + r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; + + r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Mix the bytes of every column in a linear way + * This is the opposite operation of Mixcolumn + */ + private void InvMixColumn() + { + long r0, r1, r2, r3; + + r0 = r1 = r2 = r3 = 0; + for (int j = 0; j < BC; j += 8) + { + int a0 = (int)((A0 >> j) & 0xff); + int a1 = (int)((A1 >> j) & 0xff); + int a2 = (int)((A2 >> j) & 0xff); + int a3 = (int)((A3 >> j) & 0xff); + + // + // pre-lookup the log table + // + a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1; + a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1; + a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1; + a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1; + + r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j; + + r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j; + + r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j; + + r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j; + } + + A0 = r0; + A1 = r1; + A2 = r2; + A3 = r3; + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + private long[][] GenerateWorkingKey( + byte[] key) + { + int KC; + int t, rconpointer = 0; + int keyBits = key.Length * 8; + byte[,] tk = new byte[4,MAXKC]; + //long[,] W = new long[MAXROUNDS+1,4]; + long[][] W = new long[MAXROUNDS+1][]; + + for (int i = 0; i < MAXROUNDS+1; i++) W[i] = new long[4]; + + switch (keyBits) + { + case 128: + KC = 4; + break; + case 160: + KC = 5; + break; + case 192: + KC = 6; + break; + case 224: + KC = 7; + break; + case 256: + KC = 8; + break; + default : + throw new ArgumentException("Key length not 128/160/192/224/256 bits."); + } + + if (keyBits >= blockBits) + { + ROUNDS = KC + 6; + } + else + { + ROUNDS = (BC / 8) + 6; + } + + // + // copy the key into the processing area + // + int index = 0; + + for (int i = 0; i < key.Length; i++) + { + tk[i % 4,i / 4] = key[index++]; + } + + t = 0; + + // + // copy values into round key array + // + for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++) + { + for (int i = 0; i < 4; i++) + { + W[t / (BC / 8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % BC); + } + } + + // + // while not enough round key material calculated + // calculate new values + // + while (t < (ROUNDS+1)*(BC/8)) + { + for (int i = 0; i < 4; i++) + { + tk[i,0] ^= S[tk[(i+1)%4,KC-1] & 0xff]; + } + tk[0,0] ^= (byte) rcon[rconpointer++]; + + if (KC <= 6) + { + for (int j = 1; j < KC; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i,j] ^= tk[i,j-1]; + } + } + } + else + { + for (int j = 1; j < 4; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i,j] ^= tk[i,j-1]; + } + } + for (int i = 0; i < 4; i++) + { + tk[i,4] ^= S[tk[i,3] & 0xff]; + } + for (int j = 5; j < KC; j++) + { + for (int i = 0; i < 4; i++) + { + tk[i,j] ^= tk[i,j-1]; + } + } + } + + // + // copy values into round key array + // + for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++) + { + for (int i = 0; i < 4; i++) + { + W[t / (BC/8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % (BC)); + } + } + } + return W; + } + + private int BC; + private long BC_MASK; + private int ROUNDS; + private int blockBits; + private long[][] workingKey; + private long A0, A1, A2, A3; + private bool forEncryption; + private byte[] shifts0SC; + private byte[] shifts1SC; + + /** + * default constructor - 128 bit block size. + */ + public RijndaelEngine() : this(128) {} + + /** + * basic constructor - set the cipher up for a given blocksize + * + * @param blocksize the blocksize in bits, must be 128, 192, or 256. + */ + public RijndaelEngine( + int blockBits) + { + switch (blockBits) + { + case 128: + BC = 32; + BC_MASK = 0xffffffffL; + shifts0SC = shifts0[0]; + shifts1SC = shifts1[0]; + break; + case 160: + BC = 40; + BC_MASK = 0xffffffffffL; + shifts0SC = shifts0[1]; + shifts1SC = shifts1[1]; + break; + case 192: + BC = 48; + BC_MASK = 0xffffffffffffL; + shifts0SC = shifts0[2]; + shifts1SC = shifts1[2]; + break; + case 224: + BC = 56; + BC_MASK = 0xffffffffffffffL; + shifts0SC = shifts0[3]; + shifts1SC = shifts1[3]; + break; + case 256: + BC = 64; + BC_MASK = unchecked( (long)0xffffffffffffffffL); + shifts0SC = shifts0[4]; + shifts1SC = shifts1[4]; + break; + default: + throw new ArgumentException("unknown blocksize to Rijndael"); + } + + this.blockBits = blockBits; + } + + /** + * initialise a Rijndael cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (typeof(KeyParameter).IsInstanceOfType(parameters)) + { + workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey()); + this.forEncryption = forEncryption; + return; + } + + throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString()); + } + + public string AlgorithmName + { + get { return "Rijndael"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BC / 2; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + { + throw new InvalidOperationException("Rijndael engine not initialised"); + } + + if ((inOff + (BC / 2)) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + (BC / 2)) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + UnPackBlock(input, inOff); + + if (forEncryption) + { + EncryptBlock(workingKey); + } + else + { + DecryptBlock(workingKey); + } + + PackBlock(output, outOff); + + return BC / 2; + } + + public void Reset() + { + } + + private void UnPackBlock( + byte[] bytes, + int off) + { + int index = off; + + A0 = (long)(bytes[index++] & 0xff); + A1 = (long)(bytes[index++] & 0xff); + A2 = (long)(bytes[index++] & 0xff); + A3 = (long)(bytes[index++] & 0xff); + + for (int j = 8; j != BC; j += 8) + { + A0 |= (long)(bytes[index++] & 0xff) << j; + A1 |= (long)(bytes[index++] & 0xff) << j; + A2 |= (long)(bytes[index++] & 0xff) << j; + A3 |= (long)(bytes[index++] & 0xff) << j; + } + } + + private void PackBlock( + byte[] bytes, + int off) + { + int index = off; + + for (int j = 0; j != BC; j += 8) + { + bytes[index++] = (byte)(A0 >> j); + bytes[index++] = (byte)(A1 >> j); + bytes[index++] = (byte)(A2 >> j); + bytes[index++] = (byte)(A3 >> j); + } + } + + private void EncryptBlock( + long[][] rk) + { + int r; + + // + // begin with a key addition + // + KeyAddition(rk[0]); + + // + // ROUNDS-1 ordinary rounds + // + for (r = 1; r < ROUNDS; r++) + { + Substitution(S); + ShiftRow(shifts0SC); + MixColumn(); + KeyAddition(rk[r]); + } + + // + // Last round is special: there is no MixColumn + // + Substitution(S); + ShiftRow(shifts0SC); + KeyAddition(rk[ROUNDS]); + } + + private void DecryptBlock( + long[][] rk) + { + int r; + + // To decrypt: apply the inverse operations of the encrypt routine, + // in opposite order + // + // (KeyAddition is an involution: it 's equal to its inverse) + // (the inverse of Substitution with table S is Substitution with the inverse table of S) + // (the inverse of Shiftrow is Shiftrow over a suitable distance) + // + + // First the special round: + // without InvMixColumn + // with extra KeyAddition + // + KeyAddition(rk[ROUNDS]); + Substitution(Si); + ShiftRow(shifts1SC); + + // + // ROUNDS-1 ordinary rounds + // + for (r = ROUNDS-1; r > 0; r--) + { + KeyAddition(rk[r]); + InvMixColumn(); + Substitution(Si); + ShiftRow(shifts1SC); + } + + // + // End with the extra key addition + // + KeyAddition(rk[0]); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/RsaEngine.cs b/iTechSharp/srcbc/crypto/engines/RsaEngine.cs new file mode 100644 index 0000000..7e6dfb1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/RsaEngine.cs @@ -0,0 +1,78 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * this does your basic RSA algorithm. + */ + public class RsaEngine + : IAsymmetricBlockCipher + { + private RsaCoreEngine core; + + public string AlgorithmName + { + get { return "RSA"; } + } + + /** + * initialise the RSA engine. + * + * @param forEncryption true if we are encrypting, false otherwise. + * @param param the necessary RSA key parameters. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (core == null) + core = new RsaCoreEngine(); + + core.Init(forEncryption, parameters); + } + + /** + * Return the maximum size for an input block to this engine. + * For RSA this is always one byte less than the key size on + * encryption, and the same length as the key size on decryption. + * + * @return maximum size for an input block. + */ + public int GetInputBlockSize() + { + return core.GetInputBlockSize(); + } + + /** + * Return the maximum size for an output block to this engine. + * For RSA this is always one byte less than the key size on + * decryption, and the same length as the key size on encryption. + * + * @return maximum size for an output block. + */ + public int GetOutputBlockSize() + { + return core.GetOutputBlockSize(); + } + + /** + * Process a single block using the basic RSA algorithm. + * + * @param inBuf the input array. + * @param inOff the offset into the input buffer where the data starts. + * @param inLen the length of the data to be processed. + * @return the result of the RSA process. + * @exception DataLengthException the input block is too large. + */ + public byte[] ProcessBlock( + byte[] inBuf, + int inOff, + int inLen) + { + if (core == null) + throw new InvalidOperationException("RSA engine not initialised"); + + return core.ConvertOutput(core.ProcessBlock(core.ConvertInput(inBuf, inOff, inLen))); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/SEEDEngine.cs b/iTechSharp/srcbc/crypto/engines/SEEDEngine.cs new file mode 100644 index 0000000..efea0f1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/SEEDEngine.cs @@ -0,0 +1,361 @@ +using System; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Implementation of the SEED algorithm as described in RFC 4009 + */ + public class SeedEngine + : IBlockCipher + { + private const int BlockSize = 16; + + private static readonly uint[] SS0 = + { + 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124, + 0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360, + 0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314, + 0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec, + 0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074, + 0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100, + 0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8, + 0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8, + 0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c, + 0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4, + 0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008, + 0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0, + 0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8, + 0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208, + 0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064, + 0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264, + 0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0, + 0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc, + 0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038, + 0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394, + 0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188, + 0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4, + 0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8, + 0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4, + 0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040, + 0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154, + 0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254, + 0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8, + 0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0, + 0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088, + 0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330, + 0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298 + }; + + private static readonly uint[] SS1 = + { + 0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0, + 0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53, + 0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3, + 0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43, + 0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0, + 0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890, + 0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3, + 0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272, + 0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83, + 0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430, + 0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0, + 0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1, + 0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1, + 0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171, + 0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951, + 0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0, + 0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3, + 0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41, + 0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62, + 0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0, + 0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303, + 0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901, + 0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501, + 0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343, + 0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971, + 0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53, + 0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642, + 0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1, + 0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70, + 0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393, + 0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783, + 0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3 + }; + + private static readonly uint[] SS2 = + { + + 0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505, + 0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343, + 0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707, + 0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece, + 0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444, + 0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101, + 0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9, + 0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9, + 0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f, + 0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5, + 0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808, + 0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1, + 0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b, + 0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a, + 0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444, + 0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646, + 0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0, + 0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf, + 0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808, + 0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787, + 0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989, + 0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4, + 0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888, + 0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484, + 0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040, + 0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545, + 0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646, + 0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca, + 0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282, + 0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888, + 0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303, + 0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a + }; + + private static readonly uint[] SS3 = + { + + 0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838, + 0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b, + 0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427, + 0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b, + 0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434, + 0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818, + 0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f, + 0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032, + 0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b, + 0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434, + 0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838, + 0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839, + 0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031, + 0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031, + 0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819, + 0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010, + 0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f, + 0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d, + 0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e, + 0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c, + 0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003, + 0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809, + 0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405, + 0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003, + 0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839, + 0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f, + 0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406, + 0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d, + 0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c, + 0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013, + 0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407, + 0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437 + }; + + private static readonly uint[] KC = + { + 0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc, + 0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf, + 0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1, + 0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b + }; + + private int[] wKey; + private bool forEncryption; + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + wKey = createWorkingKey(((KeyParameter)parameters).GetKey()); + } + + public string AlgorithmName + { + get { return "SEED"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BlockSize; + } + + public int ProcessBlock( + byte[] inBuf, + int inOff, + byte[] outBuf, + int outOff) + { + if (wKey == null) + throw new InvalidOperationException("SEED engine not initialised"); + if (inOff + BlockSize > inBuf.Length) + throw new DataLengthException("input buffer too short"); + if (outOff + BlockSize > outBuf.Length) + throw new DataLengthException("output buffer too short"); + + long l = bytesToLong(inBuf, inOff + 0); + long r = bytesToLong(inBuf, inOff + 8); + + if (forEncryption) + { + for (int i = 0; i < 16; i++) + { + long nl = r; + + r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r); + l = nl; + } + } + else + { + for (int i = 15; i >= 0; i--) + { + long nl = r; + + r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r); + l = nl; + } + } + + longToBytes(outBuf, outOff + 0, r); + longToBytes(outBuf, outOff + 8, l); + + return BlockSize; + } + + public void Reset() + { + } + + private int[] createWorkingKey( + byte[] inKey) + { + int[] key = new int[32]; + long lower = bytesToLong(inKey, 0); + long upper = bytesToLong(inKey, 8); + + int key0 = extractW0(lower); + int key1 = extractW1(lower); + int key2 = extractW0(upper); + int key3 = extractW1(upper); + + for (int i = 0; i < 16; i++) + { + key[2 * i] = G(key0 + key2 - (int)KC[i]); + key[2 * i + 1] = G(key1 - key3 + (int)KC[i]); + + if (i % 2 == 0) + { + lower = rotateRight8(lower); + key0 = extractW0(lower); + key1 = extractW1(lower); + } + else + { + upper = rotateLeft8(upper); + key2 = extractW0(upper); + key3 = extractW1(upper); + } + } + + return key; + } + + private int extractW1( + long lVal) + { + return (int)lVal; + } + + private int extractW0( + long lVal) + { + return (int)(lVal >> 32); + } + + private long rotateLeft8( + long x) + { + return (x << 8) | ((long)((ulong) x >> 56)); + } + + private long rotateRight8( + long x) + { + return ((long)((ulong) x >> 8)) | (x << 56); + } + + private long bytesToLong( + byte[] src, + int srcOff) + { + long word = 0; + + for (int i = 0; i <= 7; i++) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void longToBytes( + byte[] dest, + int destOff, + long value) + { + for (int i = 0; i < 8; i++) + { + dest[i + destOff] = (byte)(value >> ((7 - i) * 8)); + } + } + + private int G( + int x) + { + return (int)(SS0[x & 0xff] ^ SS1[(x >> 8) & 0xff] ^ SS2[(x >> 16) & 0xff] ^ SS3[(x >> 24) & 0xff]); + } + + private long F( + int ki0, + int ki1, + long r) + { + int r0 = (int)(r >> 32); + int r1 = (int)r; + int rd1 = phaseCalc2(r0, ki0, r1, ki1); + int rd0 = rd1 + phaseCalc1(r0, ki0, r1, ki1); + + return ((long)rd0 << 32) | (rd1 & 0xffffffffL); + } + + private int phaseCalc1( + int r0, + int ki0, + int r1, + int ki1) + { + return G(G((r0 ^ ki0) ^ (r1 ^ ki1)) + (r0 ^ ki0)); + } + + private int phaseCalc2( + int r0, + int ki0, + int r1, + int ki1) + { + return G(phaseCalc1(r0, ki0, r1, ki1) + G((r0 ^ ki0) ^ (r1 ^ ki1))); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/SEEDWrapEngine.cs b/iTechSharp/srcbc/crypto/engines/SEEDWrapEngine.cs new file mode 100644 index 0000000..6b71f94 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/SEEDWrapEngine.cs @@ -0,0 +1,16 @@ +namespace Org.BouncyCastle.Crypto.Engines +{ + /// + /// An implementation of the SEED key wrapper based on RFC 4010/RFC 3394. + ///

      + /// For further details see: http://www.ietf.org/rfc/rfc4010.txt. + /// + public class SeedWrapEngine + : Rfc3394WrapEngine + { + public SeedWrapEngine() + : base(new SeedEngine()) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/Salsa20Engine.cs b/iTechSharp/srcbc/crypto/engines/Salsa20Engine.cs new file mode 100644 index 0000000..8abdaed --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/Salsa20Engine.cs @@ -0,0 +1,363 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005 + */ + public class Salsa20Engine + : IStreamCipher + { + /** Constants */ + private const int stateSize = 16; // 16, 32 bit ints = 64 bytes + + private readonly static byte[] + sigma = Encoding.ASCII.GetBytes("expand 32-byte k"), + tau = Encoding.ASCII.GetBytes("expand 16-byte k"); + + /* + * variables to hold the state of the engine + * during encryption and decryption + */ + private int index = 0; + private int[] engineState = new int[stateSize]; // state + private int[] x = new int[stateSize] ; // internal buffer + private byte[] keyStream = new byte[stateSize * 4], // expanded state, 64 bytes + workingKey = null, + workingIV = null; + private bool initialised = false; + + /* + * internal counter + */ + private int cW0, cW1, cW2; + + /** + * initialise a Salsa20 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception ArgumentException if the params argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + /* + * Salsa20 encryption and decryption is completely + * symmetrical, so the 'forEncryption' is + * irrelevant. (Like 90% of stream ciphers) + */ + + ParametersWithIV ivParams = parameters as ParametersWithIV; + + if (ivParams == null) + throw new ArgumentException("Salsa20 Init requires an IV", "parameters"); + + byte[] iv = ivParams.GetIV(); + + if (iv == null || iv.Length != 8) + throw new ArgumentException("Salsa20 requires exactly 8 bytes of IV"); + + KeyParameter key = ivParams.Parameters as KeyParameter; + + if (key == null) + throw new ArgumentException("Salsa20 Init requires a key", "parameters"); + + workingKey = key.GetKey(); + workingIV = iv; + + setKey(workingKey, workingIV); + } + + public string AlgorithmName + { + get { return "Salsa20"; } + } + + public byte ReturnByte( + byte input) + { + if (limitExceeded()) + { + throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV"); + } + + if (index == 0) + { + salsa20WordToByte(engineState, keyStream); + engineState[8]++; + if (engineState[8] == 0) + { + engineState[9]++; + } + } + byte output = (byte)(keyStream[index]^input); + index = (index + 1) & 63; + + return output; + } + + public void ProcessBytes( + byte[] inBytes, + int inOff, + int len, + byte[] outBytes, + int outOff) + { + if (!initialised) + { + throw new InvalidOperationException(AlgorithmName + " not initialised"); + } + + if ((inOff + len) > inBytes.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + len) > outBytes.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (limitExceeded(len)) + { + throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV"); + } + + for (int i = 0; i < len; i++) + { + if (index == 0) + { + salsa20WordToByte(engineState, keyStream); + engineState[8]++; + if (engineState[8] == 0) + { + engineState[9]++; + } + } + outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]); + index = (index + 1) & 63; + } + } + + public void Reset() + { + setKey(workingKey, workingIV); + } + + // Private implementation + + private void setKey(byte[] keyBytes, byte[] ivBytes) + { + workingKey = keyBytes; + workingIV = ivBytes; + + index = 0; + resetCounter(); + int offset = 0; + byte[] constants; + + // Key + engineState[1] = byteToIntLittle(workingKey, 0); + engineState[2] = byteToIntLittle(workingKey, 4); + engineState[3] = byteToIntLittle(workingKey, 8); + engineState[4] = byteToIntLittle(workingKey, 12); + + if (workingKey.Length == 32) + { + constants = sigma; + offset = 16; + } + else + { + constants = tau; + } + + engineState[11] = byteToIntLittle(workingKey, offset); + engineState[12] = byteToIntLittle(workingKey, offset+4); + engineState[13] = byteToIntLittle(workingKey, offset+8); + engineState[14] = byteToIntLittle(workingKey, offset+12); + engineState[0 ] = byteToIntLittle(constants, 0); + engineState[5 ] = byteToIntLittle(constants, 4); + engineState[10] = byteToIntLittle(constants, 8); + engineState[15] = byteToIntLittle(constants, 12); + + // IV + engineState[6] = byteToIntLittle(workingIV, 0); + engineState[7] = byteToIntLittle(workingIV, 4); + engineState[8] = engineState[9] = 0; + + initialised = true; + } + + /** + * Salsa20 function + * + * @param input input data + * + * @return keystream + */ + private void salsa20WordToByte( + int[] input, + byte[] output) + { + Array.Copy(input, 0, x, 0, input.Length); + + for (int i = 0; i < 10; i++) + { + x[ 4] ^= rotl((x[ 0]+x[12]), 7); + x[ 8] ^= rotl((x[ 4]+x[ 0]), 9); + x[12] ^= rotl((x[ 8]+x[ 4]),13); + x[ 0] ^= rotl((x[12]+x[ 8]),18); + x[ 9] ^= rotl((x[ 5]+x[ 1]), 7); + x[13] ^= rotl((x[ 9]+x[ 5]), 9); + x[ 1] ^= rotl((x[13]+x[ 9]),13); + x[ 5] ^= rotl((x[ 1]+x[13]),18); + x[14] ^= rotl((x[10]+x[ 6]), 7); + x[ 2] ^= rotl((x[14]+x[10]), 9); + x[ 6] ^= rotl((x[ 2]+x[14]),13); + x[10] ^= rotl((x[ 6]+x[ 2]),18); + x[ 3] ^= rotl((x[15]+x[11]), 7); + x[ 7] ^= rotl((x[ 3]+x[15]), 9); + x[11] ^= rotl((x[ 7]+x[ 3]),13); + x[15] ^= rotl((x[11]+x[ 7]),18); + x[ 1] ^= rotl((x[ 0]+x[ 3]), 7); + x[ 2] ^= rotl((x[ 1]+x[ 0]), 9); + x[ 3] ^= rotl((x[ 2]+x[ 1]),13); + x[ 0] ^= rotl((x[ 3]+x[ 2]),18); + x[ 6] ^= rotl((x[ 5]+x[ 4]), 7); + x[ 7] ^= rotl((x[ 6]+x[ 5]), 9); + x[ 4] ^= rotl((x[ 7]+x[ 6]),13); + x[ 5] ^= rotl((x[ 4]+x[ 7]),18); + x[11] ^= rotl((x[10]+x[ 9]), 7); + x[ 8] ^= rotl((x[11]+x[10]), 9); + x[ 9] ^= rotl((x[ 8]+x[11]),13); + x[10] ^= rotl((x[ 9]+x[ 8]),18); + x[12] ^= rotl((x[15]+x[14]), 7); + x[13] ^= rotl((x[12]+x[15]), 9); + x[14] ^= rotl((x[13]+x[12]),13); + x[15] ^= rotl((x[14]+x[13]),18); + } + + int offset = 0; + for (int i = 0; i < stateSize; i++) + { + intToByteLittle(x[i] + input[i], output, offset); + offset += 4; + } + + for (int i = stateSize; i < x.Length; i++) + { + intToByteLittle(x[i], output, offset); + offset += 4; + } + } + + /** + * 32 bit word to 4 byte array in little endian order + * + * @param x value to 'unpack' + * + * @return value of x expressed as a byte[] array in little endian order + */ + private byte[] intToByteLittle( + int x, + byte[] bs, + int off) + { + bs[off] = (byte)x; + bs[off + 1] = (byte)(x >> 8); + bs[off + 2] = (byte)(x >> 16); + bs[off + 3] = (byte)(x >> 24); + return bs; + } + + /** + * Rotate left + * + * @param x value to rotate + * @param y amount to rotate x + * + * @return rotated x + */ + private int rotl( + int x, + int y) + { + return (x << y) | ((int)((uint) x >> -y)); + } + + /** + * Pack byte[] array into an int in little endian order + * + * @param x byte array to 'pack' + * @param offset only x[offset]..x[offset+3] will be packed + * + * @return x[offset]..x[offset+3] 'packed' into an int in little-endian order + */ + private int byteToIntLittle( + byte[] x, + int offset) + { + return ((x[offset] & 255)) | + ((x[offset + 1] & 255) << 8) | + ((x[offset + 2] & 255) << 16) | + (x[offset + 3] << 24); + } + + private void resetCounter() + { + cW0 = 0; + cW1 = 0; + cW2 = 0; + } + + private bool limitExceeded() + { + cW0++; + if (cW0 == 0) + { + cW1++; + if (cW1 == 0) + { + cW2++; + return (cW2 & 0x20) != 0; // 2^(32 + 32 + 6) + } + } + + return false; + } + + /* + * this relies on the fact len will always be positive. + */ + private bool limitExceeded( + int len) + { + if (cW0 >= 0) + { + cW0 += len; + } + else + { + cW0 += len; + if (cW0 >= 0) + { + cW1++; + if (cW1 == 0) + { + cW2++; + return (cW2 & 0x20) != 0; // 2^(32 + 32 + 6) + } + } + } + + return false; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/SerpentEngine.cs b/iTechSharp/srcbc/crypto/engines/SerpentEngine.cs new file mode 100644 index 0000000..92b25ac --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/SerpentEngine.cs @@ -0,0 +1,779 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Serpent is a 128-bit 32-round block cipher with variable key lengths, + * including 128, 192 and 256 bit keys conjectured to be at least as + * secure as three-key triple-DES. + *

      + * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a + * candidate algorithm for the NIST AES Quest.> + *

      + *

      + * For full details see the The Serpent home page + *

      + */ + public class SerpentEngine + : IBlockCipher + { + private const int BLOCK_SIZE = 16; + + static readonly int ROUNDS = 32; + static readonly int PHI = unchecked((int)0x9E3779B9); // (Sqrt(5) - 1) * 2**31 + + private bool encrypting; + private int[] wKey; + + private int X0, X1, X2, X3; // registers + + /** + * initialise a Serpent cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to Serpent init - " + parameters.GetType().ToString()); + + this.encrypting = forEncryption; + this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey()); + } + + public string AlgorithmName + { + get { return "Serpent"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (wKey == null) + throw new InvalidOperationException("Serpent not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (encrypting) + { + EncryptBlock(input, inOff, output, outOff); + } + else + { + DecryptBlock(input, inOff, output, outOff); + } + + return BLOCK_SIZE; + } + + public void Reset() + { + } + + /** + * Expand a user-supplied key material into a session key. + * + * @param key The user-key bytes (multiples of 4) to use. + * @exception ArgumentException + */ + private int[] MakeWorkingKey( + byte[] key) + { + // + // pad key to 256 bits + // + int[] kPad = new int[16]; + int off = 0; + int length = 0; + + for (off = key.Length - 4; off > 0; off -= 4) + { + kPad[length++] = BytesToWord(key, off); + } + + if (off == 0) + { + kPad[length++] = BytesToWord(key, 0); + if (length < 8) + { + kPad[length] = 1; + } + } + else + { + throw new ArgumentException("key must be a multiple of 4 bytes"); + } + + // + // expand the padded key up to 33 x 128 bits of key material + // + int amount = (ROUNDS + 1) * 4; + int[] w = new int[amount]; + + // + // compute w0 to w7 from w-8 to w-1 + // + for (int i = 8; i < 16; i++) + { + kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11); + } + + Array.Copy(kPad, 8, w, 0, 8); + + // + // compute w8 to w136 + // + for (int i = 8; i < amount; i++) + { + w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11); + } + + // + // create the working keys by processing w with the Sbox and IP + // + Sb3(w[0], w[1], w[2], w[3]); + w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3; + Sb2(w[4], w[5], w[6], w[7]); + w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3; + Sb1(w[8], w[9], w[10], w[11]); + w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3; + Sb0(w[12], w[13], w[14], w[15]); + w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3; + Sb7(w[16], w[17], w[18], w[19]); + w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3; + Sb6(w[20], w[21], w[22], w[23]); + w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3; + Sb5(w[24], w[25], w[26], w[27]); + w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3; + Sb4(w[28], w[29], w[30], w[31]); + w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3; + Sb3(w[32], w[33], w[34], w[35]); + w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3; + Sb2(w[36], w[37], w[38], w[39]); + w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3; + Sb1(w[40], w[41], w[42], w[43]); + w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3; + Sb0(w[44], w[45], w[46], w[47]); + w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3; + Sb7(w[48], w[49], w[50], w[51]); + w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3; + Sb6(w[52], w[53], w[54], w[55]); + w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3; + Sb5(w[56], w[57], w[58], w[59]); + w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3; + Sb4(w[60], w[61], w[62], w[63]); + w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3; + Sb3(w[64], w[65], w[66], w[67]); + w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3; + Sb2(w[68], w[69], w[70], w[71]); + w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3; + Sb1(w[72], w[73], w[74], w[75]); + w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3; + Sb0(w[76], w[77], w[78], w[79]); + w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3; + Sb7(w[80], w[81], w[82], w[83]); + w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3; + Sb6(w[84], w[85], w[86], w[87]); + w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3; + Sb5(w[88], w[89], w[90], w[91]); + w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3; + Sb4(w[92], w[93], w[94], w[95]); + w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3; + Sb3(w[96], w[97], w[98], w[99]); + w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3; + Sb2(w[100], w[101], w[102], w[103]); + w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3; + Sb1(w[104], w[105], w[106], w[107]); + w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3; + Sb0(w[108], w[109], w[110], w[111]); + w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3; + Sb7(w[112], w[113], w[114], w[115]); + w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3; + Sb6(w[116], w[117], w[118], w[119]); + w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3; + Sb5(w[120], w[121], w[122], w[123]); + w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3; + Sb4(w[124], w[125], w[126], w[127]); + w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3; + Sb3(w[128], w[129], w[130], w[131]); + w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3; + + return w; + } + + private int RotateLeft( + int x, + int bits) + { + return ((x << bits) | (int) ((uint)x >> (32 - bits))); + } + + private int RotateRight( + int x, + int bits) + { + return ( (int)((uint)x >> bits) | (x << (32 - bits))); + } + + private int BytesToWord( + byte[] src, + int srcOff) + { + return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) | + ((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff))); + } + + private void WordToBytes( + int word, + byte[] dst, + int dstOff) + { + dst[dstOff + 3] = (byte)(word); + dst[dstOff + 2] = (byte)((uint)word >> 8); + dst[dstOff + 1] = (byte)((uint)word >> 16); + dst[dstOff] = (byte)((uint)word >> 24); + } + + /** + * Encrypt one block of plaintext. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + */ + private void EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + X3 = BytesToWord(input, inOff); + X2 = BytesToWord(input, inOff + 4); + X1 = BytesToWord(input, inOff + 8); + X0 = BytesToWord(input, inOff + 12); + + Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT(); + Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT(); + Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT(); + Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT(); + Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT(); + Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT(); + Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT(); + Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT(); + Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT(); + Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT(); + Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT(); + Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT(); + Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT(); + Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT(); + Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT(); + Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT(); + Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT(); + Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT(); + Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT(); + Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT(); + Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT(); + Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT(); + Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT(); + Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT(); + Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT(); + Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT(); + Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT(); + Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT(); + Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT(); + Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT(); + Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT(); + Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3); + + WordToBytes(wKey[131] ^ X3, outBytes, outOff); + WordToBytes(wKey[130] ^ X2, outBytes, outOff + 4); + WordToBytes(wKey[129] ^ X1, outBytes, outOff + 8); + WordToBytes(wKey[128] ^ X0, outBytes, outOff + 12); + } + + /** + * Decrypt one block of ciphertext. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + */ + private void DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + X3 = wKey[131] ^ BytesToWord(input, inOff); + X2 = wKey[130] ^ BytesToWord(input, inOff + 4); + X1 = wKey[129] ^ BytesToWord(input, inOff + 8); + X0 = wKey[128] ^ BytesToWord(input, inOff + 12); + + Ib7(X0, X1, X2, X3); + X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127]; + InverseLT(); Ib6(X0, X1, X2, X3); + X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123]; + InverseLT(); Ib5(X0, X1, X2, X3); + X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119]; + InverseLT(); Ib4(X0, X1, X2, X3); + X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115]; + InverseLT(); Ib3(X0, X1, X2, X3); + X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111]; + InverseLT(); Ib2(X0, X1, X2, X3); + X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107]; + InverseLT(); Ib1(X0, X1, X2, X3); + X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103]; + InverseLT(); Ib0(X0, X1, X2, X3); + X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99]; + InverseLT(); Ib7(X0, X1, X2, X3); + X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95]; + InverseLT(); Ib6(X0, X1, X2, X3); + X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91]; + InverseLT(); Ib5(X0, X1, X2, X3); + X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87]; + InverseLT(); Ib4(X0, X1, X2, X3); + X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83]; + InverseLT(); Ib3(X0, X1, X2, X3); + X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79]; + InverseLT(); Ib2(X0, X1, X2, X3); + X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75]; + InverseLT(); Ib1(X0, X1, X2, X3); + X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71]; + InverseLT(); Ib0(X0, X1, X2, X3); + X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67]; + InverseLT(); Ib7(X0, X1, X2, X3); + X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63]; + InverseLT(); Ib6(X0, X1, X2, X3); + X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59]; + InverseLT(); Ib5(X0, X1, X2, X3); + X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55]; + InverseLT(); Ib4(X0, X1, X2, X3); + X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51]; + InverseLT(); Ib3(X0, X1, X2, X3); + X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47]; + InverseLT(); Ib2(X0, X1, X2, X3); + X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43]; + InverseLT(); Ib1(X0, X1, X2, X3); + X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39]; + InverseLT(); Ib0(X0, X1, X2, X3); + X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35]; + InverseLT(); Ib7(X0, X1, X2, X3); + X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31]; + InverseLT(); Ib6(X0, X1, X2, X3); + X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27]; + InverseLT(); Ib5(X0, X1, X2, X3); + X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23]; + InverseLT(); Ib4(X0, X1, X2, X3); + X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19]; + InverseLT(); Ib3(X0, X1, X2, X3); + X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15]; + InverseLT(); Ib2(X0, X1, X2, X3); + X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11]; + InverseLT(); Ib1(X0, X1, X2, X3); + X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7]; + InverseLT(); Ib0(X0, X1, X2, X3); + + WordToBytes(X3 ^ wKey[3], outBytes, outOff); + WordToBytes(X2 ^ wKey[2], outBytes, outOff + 4); + WordToBytes(X1 ^ wKey[1], outBytes, outOff + 8); + WordToBytes(X0 ^ wKey[0], outBytes, outOff + 12); + } + + /* + * The sboxes below are based on the work of Brian Gladman and + * Sam Simpson, whose original notice appears below. + *

      + * For further details see: + * http://fp.gladman.plus.com/cryptography_technology/serpent/ + *

      + */ + + /* Partially optimised Serpent S Box bool functions derived */ + /* using a recursive descent analyser but without a full search */ + /* of all subtrees. This set of S boxes is the result of work */ + /* by Sam Simpson and Brian Gladman using the spare time on a */ + /* cluster of high capacity servers to search for S boxes with */ + /* this customised search engine. There are now an average of */ + /* 15.375 terms per S box. */ + /* */ + /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */ + /* and Sam Simpson (s.simpson@mia.co.uk) */ + /* 17th December 1998 */ + /* */ + /* We hereby give permission for information in this file to be */ + /* used freely subject only to acknowledgement of its origin. */ + + /** + * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms. + */ + private void Sb0(int a, int b, int c, int d) + { + int t1 = a ^ d; + int t3 = c ^ t1; + int t4 = b ^ t3; + X3 = (a & d) ^ t4; + int t7 = a ^ (b & t1); + X2 = t4 ^ (c | t7); + int t12 = X3 & (t3 ^ t7); + X1 = (~t3) ^ t12; + X0 = t12 ^ (~t7); + } + + /** + * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms. + */ + private void Ib0(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ b; + int t4 = d ^ (t1 | t2); + int t5 = c ^ t4; + X2 = t2 ^ t5; + int t8 = t1 ^ (d & t2); + X1 = t4 ^ (X2 & t8); + X3 = (a & t4) ^ (t5 | X1); + X0 = X3 ^ (t5 ^ t8); + } + + /** + * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms. + */ + private void Sb1(int a, int b, int c, int d) + { + int t2 = b ^ (~a); + int t5 = c ^ (a | t2); + X2 = d ^ t5; + int t7 = b ^ (d | t2); + int t8 = t2 ^ X2; + X3 = t8 ^ (t5 & t7); + int t11 = t5 ^ t7; + X1 = X3 ^ t11; + X0 = t5 ^ (t8 & t11); + } + + /** + * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps. + */ + private void Ib1(int a, int b, int c, int d) + { + int t1 = b ^ d; + int t3 = a ^ (b & t1); + int t4 = t1 ^ t3; + X3 = c ^ t4; + int t7 = b ^ (t1 & t3); + int t8 = X3 | t7; + X1 = t3 ^ t8; + int t10 = ~X1; + int t11 = X3 ^ t7; + X0 = t10 ^ t11; + X2 = t4 ^ (t10 | t11); + } + + /** + * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms. + */ + private void Sb2(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = b ^ d; + int t3 = c & t1; + X0 = t2 ^ t3; + int t5 = c ^ t1; + int t6 = c ^ X0; + int t7 = b & t6; + X3 = t5 ^ t7; + X2 = a ^ ((d | t7) & (X0 | t5)); + X1 = (t2 ^ X3) ^ (X2 ^ (d | t1)); + } + + /** + * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps. + */ + private void Ib2(int a, int b, int c, int d) + { + int t1 = b ^ d; + int t2 = ~t1; + int t3 = a ^ c; + int t4 = c ^ t1; + int t5 = b & t4; + X0 = t3 ^ t5; + int t7 = a | t2; + int t8 = d ^ t7; + int t9 = t3 | t8; + X3 = t1 ^ t9; + int t11 = ~t4; + int t12 = X0 | X3; + X1 = t11 ^ t12; + X2 = (d & t11) ^ (t3 ^ t12); + } + + /** + * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms. + */ + private void Sb3(int a, int b, int c, int d) + { + int t1 = a ^ b; + int t2 = a & c; + int t3 = a | d; + int t4 = c ^ d; + int t5 = t1 & t3; + int t6 = t2 | t5; + X2 = t4 ^ t6; + int t8 = b ^ t3; + int t9 = t6 ^ t8; + int t10 = t4 & t9; + X0 = t1 ^ t10; + int t12 = X2 & X0; + X1 = t9 ^ t12; + X3 = (b | d) ^ (t4 ^ t12); + } + + /** + * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms + */ + private void Ib3(int a, int b, int c, int d) + { + int t1 = a | b; + int t2 = b ^ c; + int t3 = b & t2; + int t4 = a ^ t3; + int t5 = c ^ t4; + int t6 = d | t4; + X0 = t2 ^ t6; + int t8 = t2 | t6; + int t9 = d ^ t8; + X2 = t5 ^ t9; + int t11 = t1 ^ t9; + int t12 = X0 & t11; + X3 = t4 ^ t12; + X1 = X3 ^ (X0 ^ t11); + } + + /** + * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms. + */ + private void Sb4(int a, int b, int c, int d) + { + int t1 = a ^ d; + int t2 = d & t1; + int t3 = c ^ t2; + int t4 = b | t3; + X3 = t1 ^ t4; + int t6 = ~b; + int t7 = t1 | t6; + X0 = t3 ^ t7; + int t9 = a & X0; + int t10 = t1 ^ t6; + int t11 = t4 & t10; + X2 = t9 ^ t11; + X1 = (a ^ t3) ^ (t10 & X2); + } + + /** + * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms. + */ + private void Ib4(int a, int b, int c, int d) + { + int t1 = c | d; + int t2 = a & t1; + int t3 = b ^ t2; + int t4 = a & t3; + int t5 = c ^ t4; + X1 = d ^ t5; + int t7 = ~a; + int t8 = t5 & X1; + X3 = t3 ^ t8; + int t10 = X1 | t7; + int t11 = d ^ t10; + X0 = X3 ^ t11; + X2 = (t3 & t11) ^ (X1 ^ t7); + } + + /** + * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms. + */ + private void Sb5(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ b; + int t3 = a ^ d; + int t4 = c ^ t1; + int t5 = t2 | t3; + X0 = t4 ^ t5; + int t7 = d & X0; + int t8 = t2 ^ X0; + X1 = t7 ^ t8; + int t10 = t1 | X0; + int t11 = t2 | t7; + int t12 = t3 ^ t10; + X2 = t11 ^ t12; + X3 = (b ^ t7) ^ (X1 & t12); + } + + /** + * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms. + */ + private void Ib5(int a, int b, int c, int d) + { + int t1 = ~c; + int t2 = b & t1; + int t3 = d ^ t2; + int t4 = a & t3; + int t5 = b ^ t1; + X3 = t4 ^ t5; + int t7 = b | X3; + int t8 = a & t7; + X1 = t3 ^ t8; + int t10 = a | d; + int t11 = t1 ^ t7; + X0 = t10 ^ t11; + X2 = (b & t10) ^ (t4 | (a ^ c)); + } + + /** + * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms. + */ + private void Sb6(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ d; + int t3 = b ^ t2; + int t4 = t1 | t2; + int t5 = c ^ t4; + X1 = b ^ t5; + int t7 = t2 | X1; + int t8 = d ^ t7; + int t9 = t5 & t8; + X2 = t3 ^ t9; + int t11 = t5 ^ t8; + X0 = X2 ^ t11; + X3 = (~t5) ^ (t3 & t11); + } + + /** + * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms. + */ + private void Ib6(int a, int b, int c, int d) + { + int t1 = ~a; + int t2 = a ^ b; + int t3 = c ^ t2; + int t4 = c | t1; + int t5 = d ^ t4; + X1 = t3 ^ t5; + int t7 = t3 & t5; + int t8 = t2 ^ t7; + int t9 = b | t8; + X3 = t5 ^ t9; + int t11 = b | X3; + X0 = t8 ^ t11; + X2 = (d & t1) ^ (t3 ^ t11); + } + + /** + * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms. + */ + private void Sb7(int a, int b, int c, int d) + { + int t1 = b ^ c; + int t2 = c & t1; + int t3 = d ^ t2; + int t4 = a ^ t3; + int t5 = d | t1; + int t6 = t4 & t5; + X1 = b ^ t6; + int t8 = t3 | X1; + int t9 = a & t4; + X3 = t1 ^ t9; + int t11 = t4 ^ t8; + int t12 = X3 & t11; + X2 = t3 ^ t12; + X0 = (~t11) ^ (X3 & X2); + } + + /** + * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms. + */ + private void Ib7(int a, int b, int c, int d) + { + int t3 = c | (a & b); + int t4 = d & (a | b); + X3 = t3 ^ t4; + int t6 = ~d; + int t7 = b ^ t4; + int t9 = t7 | (X3 ^ t6); + X1 = a ^ t9; + X0 = (c ^ t7) ^ (d | X1); + X2 = (t3 ^ X1) ^ (X0 ^ (a & X3)); + } + + /** + * Apply the linear transformation to the register set. + */ + private void LT() + { + int x0 = RotateLeft(X0, 13); + int x2 = RotateLeft(X2, 3); + int x1 = X1 ^ x0 ^ x2 ; + int x3 = X3 ^ x2 ^ x0 << 3; + + X1 = RotateLeft(x1, 1); + X3 = RotateLeft(x3, 7); + X0 = RotateLeft(x0 ^ X1 ^ X3, 5); + X2 = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22); + } + + /** + * Apply the inverse of the linear transformation to the register set. + */ + private void InverseLT() + { + int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7); + int x0 = RotateRight(X0, 5) ^ X1 ^ X3; + int x3 = RotateRight(X3, 7); + int x1 = RotateRight(X1, 1); + X3 = x3 ^ x2 ^ x0 << 3; + X1 = x1 ^ x0 ^ x2; + X2 = RotateRight(x2, 3); + X0 = RotateRight(x0, 13); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/SkipjackEngine.cs b/iTechSharp/srcbc/crypto/engines/SkipjackEngine.cs new file mode 100644 index 0000000..3d2a781 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/SkipjackEngine.cs @@ -0,0 +1,255 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * a class that provides a basic SKIPJACK engine. + */ + public class SkipjackEngine + : IBlockCipher + { + const int BLOCK_SIZE = 8; + + static readonly short [] ftable = + { + 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9, + 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28, + 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53, + 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2, + 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8, + 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90, + 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76, + 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d, + 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18, + 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4, + 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40, + 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5, + 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2, + 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8, + 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac, + 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46 + }; + + private int[] key0, key1, key2, key3; + private bool encrypting; + + /** + * initialise a SKIPJACK cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + parameters.GetType().ToString()); + + byte[] keyBytes = ((KeyParameter)parameters).GetKey(); + + this.encrypting = forEncryption; + this.key0 = new int[32]; + this.key1 = new int[32]; + this.key2 = new int[32]; + this.key3 = new int[32]; + + // + // expand the key to 128 bytes in 4 parts (saving us a modulo, multiply + // and an addition). + // + for (int i = 0; i < 32; i ++) + { + key0[i] = keyBytes[(i * 4) % 10] & 0xff; + key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff; + key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff; + key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff; + } + } + + public string AlgorithmName + { + get { return "SKIPJACK"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (key1 == null) + throw new InvalidOperationException("SKIPJACK engine not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (encrypting) + { + EncryptBlock(input, inOff, output, outOff); + } + else + { + DecryptBlock(input, inOff, output, outOff); + } + + return BLOCK_SIZE; + } + + public void Reset() + { + } + + /** + * The G permutation + */ + private int G( + int k, + int w) + { + int g1, g2, g3, g4, g5, g6; + + g1 = (w >> 8) & 0xff; + g2 = w & 0xff; + + g3 = ftable[g2 ^ key0[k]] ^ g1; + g4 = ftable[g3 ^ key1[k]] ^ g2; + g5 = ftable[g4 ^ key2[k]] ^ g3; + g6 = ftable[g5 ^ key3[k]] ^ g4; + + return ((g5 << 8) + g6); + } + + public int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int w1 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff); + int w2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff); + int w3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff); + int w4 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff); + + int k = 0; + + for (int t = 0; t < 2; t++) + { + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w2; + w2 = G(k, w1); + w1 = w2 ^ tmp ^ (k + 1); + k++; + } + + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w1 ^ w2 ^ (k + 1); + w2 = G(k, w1); + w1 = tmp; + k++; + } + } + + outBytes[outOff + 0] = (byte)((w1 >> 8)); + outBytes[outOff + 1] = (byte)(w1); + outBytes[outOff + 2] = (byte)((w2 >> 8)); + outBytes[outOff + 3] = (byte)(w2); + outBytes[outOff + 4] = (byte)((w3 >> 8)); + outBytes[outOff + 5] = (byte)(w3); + outBytes[outOff + 6] = (byte)((w4 >> 8)); + outBytes[outOff + 7] = (byte)(w4); + + return BLOCK_SIZE; + } + + /** + * the inverse of the G permutation. + */ + private int H( + int k, + int w) + { + int h1, h2, h3, h4, h5, h6; + + h1 = w & 0xff; + h2 = (w >> 8) & 0xff; + + h3 = ftable[h2 ^ key3[k]] ^ h1; + h4 = ftable[h3 ^ key2[k]] ^ h2; + h5 = ftable[h4 ^ key1[k]] ^ h3; + h6 = ftable[h5 ^ key0[k]] ^ h4; + + return ((h6 << 8) + h5); + } + + public int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff); + int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff); + int w4 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff); + int w3 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff); + + int k = 31; + + for (int t = 0; t < 2; t++) + { + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w2; + w2 = H(k, w1); + w1 = w2 ^ tmp ^ (k + 1); + k--; + } + + for(int i = 0; i < 8; i++) + { + int tmp = w4; + w4 = w3; + w3 = w1 ^ w2 ^ (k + 1); + w2 = H(k, w1); + w1 = tmp; + k--; + } + } + + outBytes[outOff + 0] = (byte)((w2 >> 8)); + outBytes[outOff + 1] = (byte)(w2); + outBytes[outOff + 2] = (byte)((w1 >> 8)); + outBytes[outOff + 3] = (byte)(w1); + outBytes[outOff + 4] = (byte)((w4 >> 8)); + outBytes[outOff + 5] = (byte)(w4); + outBytes[outOff + 6] = (byte)((w3 >> 8)); + outBytes[outOff + 7] = (byte)(w3); + + return BLOCK_SIZE; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/TEAEngine.cs b/iTechSharp/srcbc/crypto/engines/TEAEngine.cs new file mode 100644 index 0000000..0fbde59 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/TEAEngine.cs @@ -0,0 +1,191 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * An TEA engine. + */ + public class TeaEngine + : IBlockCipher + { + private const int + rounds = 32, + block_size = 8, + key_size = 16, + delta = unchecked((int) 0x9E3779B9), + d_sum = unchecked((int) 0xC6EF3720); // sum on decrypt + + /* + * the expanded key array of 4 subkeys + */ + private int _a, _b, _c, _d; + private bool _initialised; + private bool _forEncryption; + + /** + * Create an instance of the TEA encryption algorithm + * and set some defaults + */ + public TeaEngine() + { + _initialised = false; + } + + public string AlgorithmName + { + get { return "TEA"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return block_size; + } + + /** + * initialise + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception ArgumentException if the params argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + { + throw new ArgumentException("invalid parameter passed to TEA init - " + + parameters.GetType().FullName); + } + + _forEncryption = forEncryption; + _initialised = true; + + KeyParameter p = (KeyParameter) parameters; + + setKey(p.GetKey()); + } + + public int ProcessBlock( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + if (!_initialised) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + + if ((inOff + block_size) > inBytes.Length) + throw new DataLengthException("input buffer too short"); + + if ((outOff + block_size) > outBytes.Length) + throw new DataLengthException("output buffer too short"); + + return _forEncryption + ? encryptBlock(inBytes, inOff, outBytes, outOff) + : decryptBlock(inBytes, inOff, outBytes, outOff); + } + + public void Reset() + { + } + + /** + * Re-key the cipher. + * + * @param key the key to be used + */ + private void setKey( + byte[] key) + { + _a = bytesToInt(key, 0); + _b = bytesToInt(key, 4); + _c = bytesToInt(key, 8); + _d = bytesToInt(key, 12); + } + + private int encryptBlock( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + // Pack bytes into integers + int v0 = bytesToInt(inBytes, inOff); + int v1 = bytesToInt(inBytes, inOff + 4); + + int sum = 0; + + for (int i = 0; i != rounds; i++) + { + sum += delta; +// v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b); + v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((int)((uint)v1 >> 5) + _b); +// v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d); + v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((int)((uint)v0 >> 5) + _d); + } + + unpackInt(v0, outBytes, outOff); + unpackInt(v1, outBytes, outOff + 4); + + return block_size; + } + + private int decryptBlock( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + // Pack bytes into integers + int v0 = bytesToInt(inBytes, inOff); + int v1 = bytesToInt(inBytes, inOff + 4); + + int sum = d_sum; + + for (int i = 0; i != rounds; i++) + { +// v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >>> 5) + _d); + v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((int)((uint)v0 >> 5) + _d); +// v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >>> 5) + _b); + v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((int)((uint)v1 >> 5) + _b); + sum -= delta; + } + + unpackInt(v0, outBytes, outOff); + unpackInt(v1, outBytes, outOff + 4); + + return block_size; + } + + private int bytesToInt( + byte[] b, + int inOff) + { + return ((b[inOff++]) << 24) + | ((b[inOff++] & 255) << 16) + | ((b[inOff++] & 255) << 8) + | ((b[inOff] & 255)); + } + + private void unpackInt( + int v, + byte[] b, + int outOff) + { + uint uv = (uint) v; + b[outOff++] = (byte)(uv >> 24); + b[outOff++] = (byte)(uv >> 16); + b[outOff++] = (byte)(uv >> 8); + b[outOff ] = (byte)uv; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/TwofishEngine.cs b/iTechSharp/srcbc/crypto/engines/TwofishEngine.cs new file mode 100644 index 0000000..3895ccf --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/TwofishEngine.cs @@ -0,0 +1,673 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * A class that provides Twofish encryption operations. + * + * This Java implementation is based on the Java reference + * implementation provided by Bruce Schneier and developed + * by Raif S. Naffah. + */ + public sealed class TwofishEngine + : IBlockCipher + { + private static readonly byte[,] P = { + { // p0 + (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8, + (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76, + (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78, + (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38, + (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98, + (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C, + (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26, + (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48, + (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30, + (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23, + (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59, + (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82, + (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E, + (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C, + (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE, + (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61, + (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5, + (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B, + (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B, + (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1, + (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45, + (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66, + (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56, + (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7, + (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5, + (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA, + (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF, + (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71, + (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD, + (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8, + (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D, + (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7, + (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED, + (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2, + (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11, + (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90, + (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF, + (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB, + (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B, + (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF, + (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE, + (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B, + (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46, + (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64, + (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F, + (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A, + (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A, + (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A, + (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29, + (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02, + (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17, + (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D, + (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74, + (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72, + (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12, + (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34, + (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68, + (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8, + (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40, + (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4, + (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0, + (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00, + (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42, + (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 }, + { // p1 + (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4, + (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8, + (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B, + (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B, + (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD, + (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1, + (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B, + (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F, + (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B, + (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D, + (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E, + (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5, + (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14, + (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3, + (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54, + (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51, + (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A, + (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96, + (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10, + (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C, + (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7, + (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70, + (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB, + (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8, + (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF, + (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC, + (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF, + (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2, + (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82, + (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9, + (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97, + (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17, + (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D, + (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3, + (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C, + (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E, + (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F, + (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49, + (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21, + (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9, + (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD, + (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01, + (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F, + (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48, + (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E, + (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19, + (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57, + (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64, + (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE, + (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5, + (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44, + (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69, + (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15, + (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E, + (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34, + (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC, + (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B, + (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB, + (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52, + (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9, + (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4, + (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2, + (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56, + (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 } + }; + + /** + * Define the fixed p0/p1 permutations used in keyed S-box lookup. + * By changing the following constant definitions, the S-boxes will + * automatically Get changed in the Twofish engine. + */ + private const int P_00 = 1; + private const int P_01 = 0; + private const int P_02 = 0; + private const int P_03 = P_01 ^ 1; + private const int P_04 = 1; + + private const int P_10 = 0; + private const int P_11 = 0; + private const int P_12 = 1; + private const int P_13 = P_11 ^ 1; + private const int P_14 = 0; + + private const int P_20 = 1; + private const int P_21 = 1; + private const int P_22 = 0; + private const int P_23 = P_21 ^ 1; + private const int P_24 = 0; + + private const int P_30 = 0; + private const int P_31 = 1; + private const int P_32 = 1; + private const int P_33 = P_31 ^ 1; + private const int P_34 = 1; + + /* Primitive polynomial for GF(256) */ + private const int GF256_FDBK = 0x169; + private const int GF256_FDBK_2 = GF256_FDBK / 2; + private const int GF256_FDBK_4 = GF256_FDBK / 4; + + private const int RS_GF_FDBK = 0x14D; // field generator + + //==================================== + // Useful constants + //==================================== + + private const int ROUNDS = 16; + private const int MAX_ROUNDS = 16; // bytes = 128 bits + private const int BLOCK_SIZE = 16; // bytes = 128 bits + private const int MAX_KEY_BITS = 256; + + private const int INPUT_WHITEN=0; + private const int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4 + private const int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8 + + private const int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40 + + private const int SK_STEP = 0x02020202; + private const int SK_BUMP = 0x01010101; + private const int SK_ROTL = 9; + + private bool encrypting; + + private int[] gMDS0 = new int[MAX_KEY_BITS]; + private int[] gMDS1 = new int[MAX_KEY_BITS]; + private int[] gMDS2 = new int[MAX_KEY_BITS]; + private int[] gMDS3 = new int[MAX_KEY_BITS]; + + /** + * gSubKeys[] and gSBox[] are eventually used in the + * encryption and decryption methods. + */ + private int[] gSubKeys; + private int[] gSBox; + + private int k64Cnt; + + private byte[] workingKey; + + public TwofishEngine() + { + // calculate the MDS matrix + int[] m1 = new int[2]; + int[] mX = new int[2]; + int[] mY = new int[2]; + int j; + + for (int i=0; i< MAX_KEY_BITS ; i++) + { + j = P[0,i] & 0xff; + m1[0] = j; + mX[0] = Mx_X(j) & 0xff; + mY[0] = Mx_Y(j) & 0xff; + + j = P[1,i] & 0xff; + m1[1] = j; + mX[1] = Mx_X(j) & 0xff; + mY[1] = Mx_Y(j) & 0xff; + + gMDS0[i] = m1[P_00] | mX[P_00] << 8 | + mY[P_00] << 16 | mY[P_00] << 24; + + gMDS1[i] = mY[P_10] | mY[P_10] << 8 | + mX[P_10] << 16 | m1[P_10] << 24; + + gMDS2[i] = mX[P_20] | mY[P_20] << 8 | + m1[P_20] << 16 | mY[P_20] << 24; + + gMDS3[i] = mX[P_30] | m1[P_30] << 8 | + mY[P_30] << 16 | mX[P_30] << 24; + } + } + + /** + * initialise a Twofish cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param parameters the parameters required to set up the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("invalid parameter passed to Twofish init - " + parameters.GetType().ToString()); + + this.encrypting = forEncryption; + this.workingKey = ((KeyParameter)parameters).GetKey(); + this.k64Cnt = (this.workingKey.Length / 8); // pre-padded ? + SetKey(this.workingKey); + } + + public string AlgorithmName + { + get { return "Twofish"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (workingKey == null) + throw new InvalidOperationException("Twofish not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (encrypting) + { + EncryptBlock(input, inOff, output, outOff); + } + else + { + DecryptBlock(input, inOff, output, outOff); + } + + return BLOCK_SIZE; + } + + public void Reset() + { + if (this.workingKey != null) + { + SetKey(this.workingKey); + } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + //================================== + // Private Implementation + //================================== + + private void SetKey(byte[] key) + { + int[] k32e = new int[MAX_KEY_BITS/64]; // 4 + int[] k32o = new int[MAX_KEY_BITS/64]; // 4 + + int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4 + gSubKeys = new int[TOTAL_SUBKEYS]; + + if (k64Cnt < 1) + { + throw new ArgumentException("Key size less than 64 bits"); + } + + if (k64Cnt > 4) + { + throw new ArgumentException("Key size larger than 256 bits"); + } + + /* + * k64Cnt is the number of 8 byte blocks (64 chunks) + * that are in the input key. The input key is a + * maximum of 32 bytes ( 256 bits ), so the range + * for k64Cnt is 1..4 + */ + for (int i=0,p=0; i> 24); + A += B; + gSubKeys[i*2] = A; + A += B; + gSubKeys[i*2 + 1] = A << SK_ROTL | (int)((uint)A >> (32-SK_ROTL)); + } + + /* + * fully expand the table for speed + */ + int k0 = sBoxKeys[0]; + int k1 = sBoxKeys[1]; + int k2 = sBoxKeys[2]; + int k3 = sBoxKeys[3]; + int b0, b1, b2, b3; + gSBox = new int[4*MAX_KEY_BITS]; + for (int i=0; i>1) | x2 << 31; + x3 = (x3 << 1 | (int) ((uint)x3 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]); + + t0 = Fe32_0(x2); + t1 = Fe32_3(x3); + x0 ^= t0 + t1 + gSubKeys[k++]; + x0 = (int) ((uint)x0 >>1) | x0 << 31; + x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]); + } + + Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex); + Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4); + Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8); + Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 12); + } + + /** + * Decrypt the given input starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * The input will be an exact multiple of our blocksize. + */ + private void DecryptBlock( + byte[] src, + int srcIndex, + byte[] dst, + int dstIndex) + { + int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN]; + int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1]; + int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2]; + int x1 = BytesTo32Bits(src, srcIndex+12) ^ gSubKeys[OUTPUT_WHITEN + 3]; + + int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ; + int t0, t1; + for (int r = 0; r< ROUNDS ; r +=2) + { + t0 = Fe32_0(x2); + t1 = Fe32_3(x3); + x1 ^= t0 + 2*t1 + gSubKeys[k--]; + x0 = (x0 << 1 | (int)((uint) x0 >> 31)) ^ (t0 + t1 + gSubKeys[k--]); + x1 = (int) ((uint)x1 >>1) | x1 << 31; + + t0 = Fe32_0(x0); + t1 = Fe32_3(x1); + x3 ^= t0 + 2*t1 + gSubKeys[k--]; + x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + gSubKeys[k--]); + x3 = (int)((uint)x3 >>1) | x3 << 31; + } + + Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex); + Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4); + Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8); + Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12); + } + + /* + * TODO: This can be optimised and made cleaner by combining + * the functionality in this function and applying it appropriately + * to the creation of the subkeys during key setup. + */ + private int F32(int x, int[] k32) + { + int b0 = M_b0(x); + int b1 = M_b1(x); + int b2 = M_b2(x); + int b3 = M_b3(x); + int k0 = k32[0]; + int k1 = k32[1]; + int k2 = k32[2]; + int k3 = k32[3]; + + int result = 0; + switch (k64Cnt & 3) + { + case 1: + result = gMDS0[(P[P_01,b0] & 0xff) ^ M_b0(k0)] ^ + gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)] ^ + gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)] ^ + gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)]; + break; + case 0: /* 256 bits of key */ + b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3); + b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3); + b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3); + b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3); + goto case 3; + case 3: + b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2); + b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2); + b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2); + b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2); + goto case 2; + case 2: + result = + gMDS0[(P[P_01,(P[P_02,b0]&0xff)^M_b0(k1)]&0xff)^M_b0(k0)] ^ + gMDS1[(P[P_11,(P[P_12,b1]&0xff)^M_b1(k1)]&0xff)^M_b1(k0)] ^ + gMDS2[(P[P_21,(P[P_22,b2]&0xff)^M_b2(k1)]&0xff)^M_b2(k0)] ^ + gMDS3[(P[P_31,(P[P_32,b3]&0xff)^M_b3(k1)]&0xff)^M_b3(k0)]; + break; + } + return result; + } + + /** + * Use (12, 8) Reed-Solomon code over GF(256) to produce + * a key S-box 32-bit entity from 2 key material 32-bit + * entities. + * + * @param k0 first 32-bit entity + * @param k1 second 32-bit entity + * @return Remainder polynomial Generated using RS code + */ + private int RS_MDS_Encode(int k0, int k1) + { + int r = k1; + for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time + { + r = RS_rem(r); + } + r ^= k0; + for (int i=0 ; i < 4 ; i++) + { + r = RS_rem(r); + } + + return r; + } + + /** + * Reed-Solomon code parameters: (12,8) reversible code: + *

      + *

      +        * G(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
      +        * 
      + * where a = primitive root of field generator 0x14D + *

      + */ + private int RS_rem(int x) + { + int b = (int) (((uint)x >> 24) & 0xff); + int g2 = ((b << 1) ^ + ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff; + int g3 = ( (int)((uint)b >> 1) ^ + ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2 ; + return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b); + } + + private int LFSR1(int x) + { + return (x >> 1) ^ + (((x & 0x01) != 0) ? GF256_FDBK_2 : 0); + } + + private int LFSR2(int x) + { + return (x >> 2) ^ + (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^ + (((x & 0x01) != 0) ? GF256_FDBK_4 : 0); + } + + private int Mx_X(int x) + { + return x ^ LFSR2(x); + } // 5B + + private int Mx_Y(int x) + { + return x ^ LFSR1(x) ^ LFSR2(x); + } // EF + + private int M_b0(int x) + { + return x & 0xff; + } + + private int M_b1(int x) + { + return (int)((uint)x >> 8) & 0xff; + } + + private int M_b2(int x) + { + return (int)((uint)x >> 16) & 0xff; + } + + private int M_b3(int x) + { + return (int)((uint)x >> 24) & 0xff; + } + + private int Fe32_0(int x) + { + return gSBox[ 0x000 + 2*(x & 0xff) ] ^ + gSBox[ 0x001 + 2*((int)((uint)x >> 8) & 0xff) ] ^ + gSBox[ 0x200 + 2*((int)((uint)x >> 16) & 0xff) ] ^ + gSBox[ 0x201 + 2*((int)((uint)x >> 24) & 0xff) ]; + } + + private int Fe32_3(int x) + { + return gSBox[ 0x000 + 2*((int)((uint)x >> 24) & 0xff) ] ^ + gSBox[ 0x001 + 2*(x & 0xff) ] ^ + gSBox[ 0x200 + 2*((int)((uint)x >> 8) & 0xff) ] ^ + gSBox[ 0x201 + 2*((int)((uint)x >> 16) & 0xff) ]; + } + + private int BytesTo32Bits(byte[] b, int p) + { + return ((b[p] & 0xff) ) | + ((b[p+1] & 0xff) << 8) | + ((b[p+2] & 0xff) << 16) | + ((b[p+3] & 0xff) << 24); + } + + private void Bits32ToBytes(int inData, byte[] b, int offset) + { + b[offset] = (byte)inData; + b[offset + 1] = (byte)(inData >> 8); + b[offset + 2] = (byte)(inData >> 16); + b[offset + 3] = (byte)(inData >> 24); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/engines/VMPCEngine.cs b/iTechSharp/srcbc/crypto/engines/VMPCEngine.cs new file mode 100644 index 0000000..d467fbb --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/VMPCEngine.cs @@ -0,0 +1,139 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + public class VmpcEngine + : IStreamCipher + { + /* + * variables to hold the state of the VMPC engine during encryption and + * decryption + */ + protected byte n = 0; + protected byte[] P = null; + protected byte s = 0; + + protected byte[] workingIV; + protected byte[] workingKey; + + public virtual string AlgorithmName + { + get { return "VMPC"; } + } + + /** + * initialise a VMPC cipher. + * + * @param forEncryption + * whether or not we are for encryption. + * @param params + * the parameters required to set up the cipher. + * @exception ArgumentException + * if the params argument is inappropriate. + */ + public virtual void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is ParametersWithIV)) + throw new ArgumentException("VMPC Init parameters must include an IV"); + + ParametersWithIV ivParams = (ParametersWithIV) parameters; + KeyParameter key = (KeyParameter) ivParams.Parameters; + + if (!(ivParams.Parameters is KeyParameter)) + throw new ArgumentException("VMPC Init parameters must include a key"); + + this.workingIV = ivParams.GetIV(); + + if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768) + throw new ArgumentException("VMPC requires 1 to 768 bytes of IV"); + + this.workingKey = key.GetKey(); + + InitKey(this.workingKey, this.workingIV); + } + + protected virtual void InitKey( + byte[] keyBytes, + byte[] ivBytes) + { + s = 0; + P = new byte[256]; + for (int i = 0; i < 256; i++) + { + P[i] = (byte) i; + } + + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + n = 0; + } + + public virtual void ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] output, + int outOff) + { + if ((inOff + len) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + len) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + for (int i = 0; i < len; i++) + { + s = P[(s + P[n & 0xff]) & 0xff]; + byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]; + // encryption + byte temp = P[n & 0xff]; + P[n & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + n = (byte) ((n + 1) & 0xff); + + // xor + output[i + outOff] = (byte) (input[i + inOff] ^ z); + } + } + + public virtual void Reset() + { + InitKey(this.workingKey, this.workingIV); + } + + public virtual byte ReturnByte( + byte input) + { + s = P[(s + P[n & 0xff]) & 0xff]; + byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]; + // encryption + byte temp = P[n & 0xff]; + P[n & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + n = (byte) ((n + 1) & 0xff); + + // xor + return (byte) (input ^ z); + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/VMPCKSA3Engine.cs b/iTechSharp/srcbc/crypto/engines/VMPCKSA3Engine.cs new file mode 100644 index 0000000..95b6813 --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/VMPCKSA3Engine.cs @@ -0,0 +1,51 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Engines +{ + public class VmpcKsa3Engine + : VmpcEngine + { + public override string AlgorithmName + { + get { return "VMPC-KSA3"; } + } + + protected override void InitKey( + byte[] keyBytes, + byte[] ivBytes) + { + s = 0; + P = new byte[256]; + for (int i = 0; i < 256; i++) + { + P[i] = (byte) i; + } + + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + + n = 0; + } + } +} diff --git a/iTechSharp/srcbc/crypto/engines/XTEAEngine.cs b/iTechSharp/srcbc/crypto/engines/XTEAEngine.cs new file mode 100644 index 0000000..04318ee --- /dev/null +++ b/iTechSharp/srcbc/crypto/engines/XTEAEngine.cs @@ -0,0 +1,185 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * An XTEA engine. + */ + public class XteaEngine + : IBlockCipher + { + private const int + rounds = 32, + block_size = 8, + key_size = 16, + delta = unchecked((int) 0x9E3779B9), + d_sum = unchecked((int) 0xC6EF3720); // sum on decrypt + + /* + * the expanded key array of 4 subkeys + */ + private int[] _S = new int[4]; + private bool _initialised; + private bool _forEncryption; + + /** + * Create an instance of the TEA encryption algorithm + * and set some defaults + */ + public XteaEngine() + { + _initialised = false; + } + + public string AlgorithmName + { + get { return "XTEA"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return block_size; + } + + /** + * initialise + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception ArgumentException if the params argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + { + throw new ArgumentException("invalid parameter passed to TEA init - " + + parameters.GetType().FullName); + } + + _forEncryption = forEncryption; + _initialised = true; + + KeyParameter p = (KeyParameter) parameters; + + setKey(p.GetKey()); + } + + public int ProcessBlock( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + if (!_initialised) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + + if ((inOff + block_size) > inBytes.Length) + throw new DataLengthException("input buffer too short"); + + if ((outOff + block_size) > outBytes.Length) + throw new DataLengthException("output buffer too short"); + + return _forEncryption + ? encryptBlock(inBytes, inOff, outBytes, outOff) + : decryptBlock(inBytes, inOff, outBytes, outOff); + } + + public void Reset() + { + } + + /** + * Re-key the cipher. + * + * @param key the key to be used + */ + private void setKey( + byte[] key) + { + _S[0] = bytesToInt(key, 0); + _S[1] = bytesToInt(key, 4); + _S[2] = bytesToInt(key, 8); + _S[3] = bytesToInt(key, 12); + } + + private int encryptBlock( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + // Pack bytes into integers + int v0 = bytesToInt(inBytes, inOff); + int v1 = bytesToInt(inBytes, inOff + 4); + + int sum = 0; + + for (int i = 0; i != rounds; i++) + { + v0 += ((v1 << 4 ^ (int)((uint)v1 >> 5)) + v1) ^ (sum + _S[sum & 3]); + sum += delta; + v1 += ((v0 << 4 ^ (int)((uint)v0 >> 5)) + v0) ^ (sum + _S[(int)((uint)sum >> 11) & 3]); + } + + unpackInt(v0, outBytes, outOff); + unpackInt(v1, outBytes, outOff + 4); + + return block_size; + } + + private int decryptBlock( + byte[] inBytes, + int inOff, + byte[] outBytes, + int outOff) + { + // Pack bytes into integers + int v0 = bytesToInt(inBytes, inOff); + int v1 = bytesToInt(inBytes, inOff + 4); + + int sum = d_sum; + + for (int i = 0; i != rounds; i++) + { + v1 -= ((v0 << 4 ^ (int)((uint)v0 >> 5)) + v0) ^ (sum + _S[(int)((uint)sum >> 11) & 3]); + sum -= delta; + v0 -= ((v1 << 4 ^ (int)((uint)v1 >> 5)) + v1) ^ (sum + _S[sum & 3]); + } + + unpackInt(v0, outBytes, outOff); + unpackInt(v1, outBytes, outOff + 4); + + return block_size; + } + + private int bytesToInt(byte[] b, int inOff) + { + return ((b[inOff++]) << 24) | + ((b[inOff++] & 255) << 16) | + ((b[inOff++] & 255) << 8) | + ((b[inOff] & 255)); + } + + private void unpackInt( + int v, + byte[] b, + int outOff) + { + uint uv = (uint) v; + b[outOff++] = (byte)(uv >> 24); + b[outOff++] = (byte)(uv >> 16); + b[outOff++] = (byte)(uv >> 8); + b[outOff ] = (byte)uv; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/BaseKdfBytesGenerator.cs b/iTechSharp/srcbc/crypto/generators/BaseKdfBytesGenerator.cs new file mode 100644 index 0000000..0366401 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/BaseKdfBytesGenerator.cs @@ -0,0 +1,141 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033 + *
      + * This implementation is based on ISO 18033/P1363a. + */ + public class BaseKdfBytesGenerator + : IDerivationFunction + { + private int counterStart; + private IDigest digest; + private byte[] shared; + private byte[] iv; + + /** + * Construct a KDF Parameters generator. + * + * @param counterStart value of counter. + * @param digest the digest to be used as the source of derived keys. + */ + protected BaseKdfBytesGenerator( + int counterStart, + IDigest digest) + { + this.counterStart = counterStart; + this.digest = digest; + } + + public void Init( + IDerivationParameters parameters) + { + if (parameters is KdfParameters) + { + KdfParameters p = (KdfParameters)parameters; + + shared = p.GetSharedSecret(); + iv = p.GetIV(); + } + else if (parameters is Iso18033KdfParameters) + { + Iso18033KdfParameters p = (Iso18033KdfParameters)parameters; + + shared = p.GetSeed(); + iv = null; + } + else + { + throw new ArgumentException("KDF parameters required for KDF Generator"); + } + } + + /** + * return the underlying digest. + */ + public IDigest Digest + { + get + { + return digest; + } + } + + /** + * fill len bytes of the output buffer with bytes generated from + * the derivation function. + * + * @throws ArgumentException if the size of the request will cause an overflow. + * @throws DataLengthException if the out buffer is too small. + */ + public int GenerateBytes( + byte[] output, + int outOff, + int length) + { + if ((output.Length - length) < outOff) + { + throw new DataLengthException("output buffer too small"); + } + + long oBytes = length; + int outLen = digest.GetDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + { + throw new ArgumentException("Output length too large"); + } + + int cThreshold = (int)((oBytes + outLen - 1) / outLen); + + byte[] dig = new byte[digest.GetDigestSize()]; + + int counter = counterStart; + + for (int i = 0; i < cThreshold; i++) + { + digest.BlockUpdate(shared, 0, shared.Length); + + digest.Update((byte)(counter >> 24)); + digest.Update((byte)(counter >> 16)); + digest.Update((byte)(counter >> 8)); + digest.Update((byte)counter); + + if (iv != null) + { + digest.BlockUpdate(iv, 0, iv.Length); + } + + digest.DoFinal(dig, 0); + + if (length > outLen) + { + Array.Copy(dig, 0, output, outOff, outLen); + outOff += outLen; + length -= outLen; + } + else + { + Array.Copy(dig, 0, output, outOff, length); + } + + counter++; + } + + digest.Reset(); + + return (int)oBytes; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs new file mode 100644 index 0000000..a6451ff --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs @@ -0,0 +1,40 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * a basic Diffie-Helman key pair generator. + * + * This Generates keys consistent for use with the basic algorithm for + * Diffie-Helman. + */ + public class DHBasicKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private DHKeyGenerationParameters param; + + public virtual void Init( + KeyGenerationParameters parameters) + { + this.param = (DHKeyGenerationParameters) parameters; + } + + public virtual AsymmetricCipherKeyPair GenerateKeyPair() + { + DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance; + DHParameters dhParams = param.Parameters; + + BigInteger p = dhParams.P; + BigInteger x = helper.CalculatePrivate(p, param.Random, dhParams.L); + BigInteger y = helper.CalculatePublic(p, dhParams.G, x); + + return new AsymmetricCipherKeyPair( + new DHPublicKeyParameters(y, dhParams), + new DHPrivateKeyParameters(x, dhParams)); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/generators/DHKeyGeneratorHelper.cs b/iTechSharp/srcbc/crypto/generators/DHKeyGeneratorHelper.cs new file mode 100644 index 0000000..62c0ee4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DHKeyGeneratorHelper.cs @@ -0,0 +1,78 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + class DHKeyGeneratorHelper + { + private const int MAX_ITERATIONS = 1000; + + internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper(); + + private DHKeyGeneratorHelper() + { + } + + internal BigInteger CalculatePrivate( + BigInteger p, + SecureRandom random, + int limit) + { + // + // calculate the private key + // + BigInteger pSub2 = p.Subtract(BigInteger.Two); + BigInteger x; + + if (limit == 0) + { + x = createInRange(pSub2, random); + } + else + { + do + { + // TODO Check this (should the generated numbers always be odd, + // and length 'limit'?) + x = new BigInteger(limit, 0, random); + } + while (x.SignValue == 0); + } + + return x; + } + + private BigInteger createInRange( + BigInteger max, + SecureRandom random) + { + BigInteger x; + int maxLength = max.BitLength; + int count = 0; + + do + { + x = new BigInteger(maxLength, random); + count++; + } + while ((x.SignValue == 0 || x.CompareTo(max) > 0) && count != MAX_ITERATIONS); + + if (count == MAX_ITERATIONS) // fall back to a faster (restricted) method + { + return new BigInteger(maxLength - 1, random).SetBit(0); + } + + return x; + } + + internal BigInteger CalculatePublic( + BigInteger p, + BigInteger g, + BigInteger x) + { + return g.ModPow(x, p); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/DHKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/DHKeyPairGenerator.cs new file mode 100644 index 0000000..0324e3c --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DHKeyPairGenerator.cs @@ -0,0 +1,40 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * a Diffie-Helman key pair generator. + * + * This Generates keys consistent for use in the MTI/A0 key agreement protocol + * as described in "Handbook of Applied Cryptography", Pages 516-519. + */ + public class DHKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private DHKeyGenerationParameters param; + + public virtual void Init( + KeyGenerationParameters parameters) + { + this.param = (DHKeyGenerationParameters) parameters; + } + + public virtual AsymmetricCipherKeyPair GenerateKeyPair() + { + DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance; + DHParameters dhParams = param.Parameters; + + BigInteger p = dhParams.P; + BigInteger x = helper.CalculatePrivate(p, param.Random, dhParams.L); + BigInteger y = helper.CalculatePublic(p, dhParams.G, x); + + return new AsymmetricCipherKeyPair( + new DHPublicKeyParameters(y, dhParams), + new DHPrivateKeyParameters(x, dhParams)); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/generators/DHParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/DHParametersGenerator.cs new file mode 100644 index 0000000..e752c84 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DHParametersGenerator.cs @@ -0,0 +1,45 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class DHParametersGenerator + { + private int size; + private int certainty; + private SecureRandom random; + + public virtual void Init( + int size, + int certainty, + SecureRandom random) + { + this.size = size; + this.certainty = certainty; + this.random = random; + } + + /** + * which Generates the p and g values from the given parameters, + * returning the DHParameters object. + *

      + * Note: can take a while...

      + */ + public virtual DHParameters GenerateParameters() + { + // + // find a safe prime p where p = 2*q + 1, where p and q are prime. + // + BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random); + + BigInteger p = safePrimes[0]; + BigInteger q = safePrimes[1]; + BigInteger g = DHParametersHelper.SelectGenerator(p, q, random); + + return new DHParameters(p, g, q, BigInteger.Two, null); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/DHParametersHelper.cs b/iTechSharp/srcbc/crypto/generators/DHParametersHelper.cs new file mode 100644 index 0000000..1856e88 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DHParametersHelper.cs @@ -0,0 +1,244 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + internal class DHParametersHelper + { + // The primes b/w 2 and ~2^10 + /* + 3 5 7 11 13 17 19 23 29 + 31 37 41 43 47 53 59 61 67 71 + 73 79 83 89 97 101 103 107 109 113 + 127 131 137 139 149 151 157 163 167 173 + 179 181 191 193 197 199 211 223 227 229 + 233 239 241 251 257 263 269 271 277 281 + 283 293 307 311 313 317 331 337 347 349 + 353 359 367 373 379 383 389 397 401 409 + 419 421 431 433 439 443 449 457 461 463 + 467 479 487 491 499 503 509 521 523 541 + 547 557 563 569 571 577 587 593 599 601 + 607 613 617 619 631 641 643 647 653 659 + 661 673 677 683 691 701 709 719 727 733 + 739 743 751 757 761 769 773 787 797 809 + 811 821 823 827 829 839 853 857 859 863 + 877 881 883 887 907 911 919 929 937 941 + 947 953 967 971 977 983 991 997 + 1009 1013 1019 1021 1031 + */ + + // Each list has a product < 2^31 + private static readonly int[][] primeLists = new int[][] + { + new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 }, + new int[]{ 29, 31, 37, 41, 43 }, + new int[]{ 47, 53, 59, 61, 67 }, + new int[]{ 71, 73, 79, 83 }, + new int[]{ 89, 97, 101, 103 }, + + new int[]{ 107, 109, 113, 127 }, + new int[]{ 131, 137, 139, 149 }, + new int[]{ 151, 157, 163, 167 }, + new int[]{ 173, 179, 181, 191 }, + new int[]{ 193, 197, 199, 211 }, + + new int[]{ 223, 227, 229 }, + new int[]{ 233, 239, 241 }, + new int[]{ 251, 257, 263 }, + new int[]{ 269, 271, 277 }, + new int[]{ 281, 283, 293 }, + + new int[]{ 307, 311, 313 }, + new int[]{ 317, 331, 337 }, + new int[]{ 347, 349, 353 }, + new int[]{ 359, 367, 373 }, + new int[]{ 379, 383, 389 }, + + new int[]{ 397, 401, 409 }, + new int[]{ 419, 421, 431 }, + new int[]{ 433, 439, 443 }, + new int[]{ 449, 457, 461 }, + new int[]{ 463, 467, 479 }, + + new int[]{ 487, 491, 499 }, + new int[]{ 503, 509, 521 }, + new int[]{ 523, 541, 547 }, + new int[]{ 557, 563, 569 }, + new int[]{ 571, 577, 587 }, + + new int[]{ 593, 599, 601 }, + new int[]{ 607, 613, 617 }, + new int[]{ 619, 631, 641 }, + new int[]{ 643, 647, 653 }, + new int[]{ 659, 661, 673 }, + + new int[]{ 677, 683, 691 }, + new int[]{ 701, 709, 719 }, + new int[]{ 727, 733, 739 }, + new int[]{ 743, 751, 757 }, + new int[]{ 761, 769, 773 }, + + new int[]{ 787, 797, 809 }, + new int[]{ 811, 821, 823 }, + new int[]{ 827, 829, 839 }, + new int[]{ 853, 857, 859 }, + new int[]{ 863, 877, 881 }, + + new int[]{ 883, 887, 907 }, + new int[]{ 911, 919, 929 }, + new int[]{ 937, 941, 947 }, + new int[]{ 953, 967, 971 }, + new int[]{ 977, 983, 991 }, + + new int[]{ 997, 1009, 1013 }, + new int[]{ 1019, 1021, 1031 }, + }; + + private static readonly BigInteger Six = BigInteger.ValueOf(6); + + private static readonly int[] primeProducts; + private static readonly BigInteger[] PrimeProducts; + + static DHParametersHelper() + { + primeProducts = new int[primeLists.Length]; + PrimeProducts = new BigInteger[primeLists.Length]; + + for (int i = 0; i < primeLists.Length; ++i) + { + int[] primeList = primeLists[i]; + int product = 1; + for (int j = 0; j < primeList.Length; ++j) + { + product *= primeList[j]; + } + primeProducts[i] = product; + PrimeProducts[i] = BigInteger.ValueOf(product); + } + } + + // Finds a pair of prime BigInteger's {p, q: p = 2q + 1} + internal static BigInteger[] GenerateSafePrimes( + int size, + int certainty, + SecureRandom random) + { + BigInteger p, q; + int qLength = size - 1; + + if (size <= 32) + { + for (;;) + { + q = new BigInteger(qLength, 2, random); + + p = q.ShiftLeft(1).Add(BigInteger.One); + + if (p.IsProbablePrime(certainty) + && (certainty <= 2 || q.IsProbablePrime(certainty))) + break; + } + } + else + { + // Note: Modified from Java version for speed + for (;;) + { + q = new BigInteger(qLength, 0, random); + + retry: + for (int i = 0; i < primeLists.Length; ++i) + { + int test = q.Remainder(PrimeProducts[i]).IntValue; + + if (i == 0) + { + int rem3 = test % 3; + if (rem3 != 2) + { + int diff = 2 * rem3 + 2; + q = q.Add(BigInteger.ValueOf(diff)); + test = (test + diff) % primeProducts[i]; + } + } + + int[] primeList = primeLists[i]; + for (int j = 0; j < primeList.Length; ++j) + { + int prime = primeList[j]; + int qRem = test % prime; + if (qRem == 0 || qRem == (prime >> 1)) + { + q = q.Add(Six); + goto retry; + } + } + } + + + if (q.BitLength != qLength) + continue; + + if (!q.RabinMillerTest(2, random)) + continue; + + p = q.ShiftLeft(1).Add(BigInteger.One); + + if (p.RabinMillerTest(certainty, random) + && (certainty <= 2 || q.RabinMillerTest(certainty - 2, random))) + break; + } + } + + return new BigInteger[] { p, q }; + } + + // Select a high order element of the multiplicative group Zp* + // p and q must be s.t. p = 2*q + 1, where p and q are prime + internal static BigInteger SelectGenerator( + BigInteger p, + BigInteger q, + SecureRandom random) + { + BigInteger pMinusTwo = p.Subtract(BigInteger.Two); + BigInteger g; + + // Handbook of Applied Cryptography 4.86 + do + { + g = CreateInRange(BigInteger.Two, pMinusTwo, random); + } + while (g.ModPow(BigInteger.Two, p).Equals(BigInteger.One) + || g.ModPow(q, p).Equals(BigInteger.One)); + +/* + // RFC 2631 2.1.1 (and see Handbook of Applied Cryptography 4.81) + do + { + BigInteger h = CreateInRange(BigInteger.Two, pMinusTwo, random); + + g = h.ModPow(BigInteger.Two, p); + } + while (g.Equals(BigInteger.One)); +*/ + + return g; + } + + private static BigInteger CreateInRange( + BigInteger min, + BigInteger max, + SecureRandom random) + { + BigInteger x; + do + { + x = new BigInteger(max.BitLength, random); + } + while (x.CompareTo(min) < 0 || x.CompareTo(max) > 0); + return x; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/DesEdeKeyGenerator.cs b/iTechSharp/srcbc/crypto/generators/DesEdeKeyGenerator.cs new file mode 100644 index 0000000..62b71ca --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DesEdeKeyGenerator.cs @@ -0,0 +1,66 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class DesEdeKeyGenerator + : DesKeyGenerator + { + public DesEdeKeyGenerator() + { + } + + internal DesEdeKeyGenerator( + int defaultStrength) + : base(defaultStrength) + { + } + + /** + * initialise the key generator - if strength is set to zero + * the key Generated will be 192 bits in size, otherwise + * strength can be 128 or 192 (or 112 or 168 if you don't count + * parity bits), depending on whether you wish to do 2-key or 3-key + * triple DES. + * + * @param param the parameters to be used for key generation + */ + protected override void engineInit( + KeyGenerationParameters parameters) + { + base.engineInit(parameters); + + if (strength == 0 || strength == (168 / 8)) + { + strength = DesEdeParameters.DesEdeKeyLength; + } + else if (strength == (112 / 8)) + { + strength = 2 * DesEdeParameters.DesKeyLength; + } + else if (strength != DesEdeParameters.DesEdeKeyLength + && strength != (2 * DesEdeParameters.DesKeyLength)) + { + throw new ArgumentException("DESede key must be " + + (DesEdeParameters.DesEdeKeyLength * 8) + " or " + + (2 * 8 * DesEdeParameters.DesKeyLength) + + " bits long."); + } + } + + protected override byte[] engineGenerateKey() + { + byte[] newKey; + + do + { + newKey = random.GenerateSeed(strength); + DesEdeParameters.SetOddParity(newKey); + } + while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length)); + + return newKey; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/DesKeyGenerator.cs b/iTechSharp/srcbc/crypto/generators/DesKeyGenerator.cs new file mode 100644 index 0000000..c412005 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DesKeyGenerator.cs @@ -0,0 +1,34 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class DesKeyGenerator + : CipherKeyGenerator + { + public DesKeyGenerator() + { + } + + internal DesKeyGenerator( + int defaultStrength) + : base(defaultStrength) + { + } + + protected override byte[] engineGenerateKey() + { + byte[] newKey; + + do + { + newKey = random.GenerateSeed(DesParameters.DesKeyLength); + DesParameters.SetOddParity(newKey); + } + while (DesParameters.IsWeakKey(newKey, 0)); + + return newKey; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/DsaKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/DsaKeyPairGenerator.cs new file mode 100644 index 0000000..fee3057 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DsaKeyPairGenerator.cs @@ -0,0 +1,56 @@ +using System; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * a DSA key pair generator. + * + * This Generates DSA keys in line with the method described + * in FIPS 186-2. + */ + public class DsaKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private DsaKeyGenerationParameters param; + + public void Init( + KeyGenerationParameters parameters) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + + // Note: If we start accepting instances of KeyGenerationParameters, + // must apply constraint checking on strength (see DsaParametersGenerator.Init) + + this.param = (DsaKeyGenerationParameters) parameters; + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + DsaParameters dsaParams = param.Parameters; + SecureRandom random = param.Random; + + BigInteger q = dsaParams.Q; + BigInteger x; + + do + { + x = new BigInteger(160, random); + } + while (x.SignValue == 0 || x.CompareTo(q) >= 0); + + // + // calculate the public key. + // + BigInteger y = dsaParams.G.ModPow(x, dsaParams.P); + + return new AsymmetricCipherKeyPair( + new DsaPublicKeyParameters(y, dsaParams), + new DsaPrivateKeyParameters(x, dsaParams)); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/DsaParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/DsaParametersGenerator.cs new file mode 100644 index 0000000..a23b43b --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/DsaParametersGenerator.cs @@ -0,0 +1,184 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generate suitable parameters for DSA, in line with FIPS 186-2. + */ + public class DsaParametersGenerator + { + private int size; + private int certainty; + private SecureRandom random; + + /** + * initialise the key generator. + * + * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments) + * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80). + * @param random random byte source. + */ + public void Init( + int size, + int certainty, + SecureRandom random) + { + if (!IsValidDsaStrength(size)) + throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size"); + + this.size = size; + this.certainty = certainty; + this.random = random; + } + + /** + * add value to b, returning the result in a. The a value is treated + * as a BigInteger of length (a.Length * 8) bits. The result is + * modulo 2^a.Length in case of overflow. + */ + private static void Add( + byte[] a, + byte[] b, + int value) + { + int x = (b[b.Length - 1] & 0xff) + value; + + a[b.Length - 1] = (byte)x; + x = (int) ((uint) x >>8); + + for (int i = b.Length - 2; i >= 0; i--) + { + x += (b[i] & 0xff); + a[i] = (byte)x; + x = (int) ((uint) x >>8); + } + } + + /** + * which Generates the p and g values from the given parameters, + * returning the DsaParameters object. + *

      + * Note: can take a while...

      + */ + public DsaParameters GenerateParameters() + { + byte[] seed = new byte[20]; + byte[] part1 = new byte[20]; + byte[] part2 = new byte[20]; + byte[] u = new byte[20]; + Sha1Digest sha1 = new Sha1Digest(); + int n = (size - 1) / 160; + byte[] w = new byte[size / 8]; + + BigInteger q = null, p = null, g = null; + int counter = 0; + bool primesFound = false; + + while (!primesFound) + { + do + { + random.NextBytes(seed); + + sha1.BlockUpdate(seed, 0, seed.Length); + + sha1.DoFinal(part1, 0); + + Array.Copy(seed, 0, part2, 0, seed.Length); + + Add(part2, seed, 1); + + sha1.BlockUpdate(part2, 0, part2.Length); + + sha1.DoFinal(part2, 0); + + for (int i = 0; i != u.Length; i++) + { + u[i] = (byte)(part1[i] ^ part2[i]); + } + + u[0] |= (byte)0x80; + u[19] |= (byte)0x01; + + q = new BigInteger(1, u); + } + while (!q.IsProbablePrime(certainty)); + + counter = 0; + + int offset = 2; + + while (counter < 4096) + { + for (int k = 0; k < n; k++) + { + Add(part1, seed, offset + k); + sha1.BlockUpdate(part1, 0, part1.Length); + sha1.DoFinal(part1, 0); + Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length); + } + + Add(part1, seed, offset + n); + sha1.BlockUpdate(part1, 0, part1.Length); + sha1.DoFinal(part1, 0); + Array.Copy(part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length); + + w[0] |= (byte)0x80; + + BigInteger x = new BigInteger(1, w); + + BigInteger c = x.Mod(q.ShiftLeft(1)); + + p = x.Subtract(c.Subtract(BigInteger.One)); + + if (p.TestBit(size - 1)) + { + if (p.IsProbablePrime(certainty)) + { + primesFound = true; + break; + } + } + + counter += 1; + offset += n + 1; + } + } + + // + // calculate the generator g + // + BigInteger pMinusOneOverQ = p.Subtract(BigInteger.One).Divide(q); + + for (;;) + { + BigInteger h = new BigInteger(size, random); + if (h.CompareTo(BigInteger.One) <= 0 || h.CompareTo(p.Subtract(BigInteger.One)) >= 0) + { + continue; + } + + g = h.ModPow(pMinusOneOverQ, p); + if (g.CompareTo(BigInteger.One) <= 0) + { + continue; + } + + break; + } + + return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter)); + } + + private static bool IsValidDsaStrength( + int strength) + { + return strength >= 512 && strength <= 1024 && strength % 64 == 0; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/ECKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/ECKeyPairGenerator.cs new file mode 100644 index 0000000..1ecc471 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/ECKeyPairGenerator.cs @@ -0,0 +1,130 @@ +using System; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class ECKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private readonly string algorithm; + + private ECDomainParameters parameters; + private DerObjectIdentifier publicKeyParamSet; + private SecureRandom random; + + public ECKeyPairGenerator() + : this("EC") + { + } + + public ECKeyPairGenerator( + string algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + this.algorithm = VerifyAlgorithmName(algorithm); + } + + public void Init( + KeyGenerationParameters parameters) + { + if (parameters is ECKeyGenerationParameters) + { + ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters; + + if (ecP.PublicKeyParamSet != null) + { + if (algorithm != "ECGOST3410") + throw new ArgumentException("parameters invalid for algorithm: " + algorithm, "parameters"); + + this.publicKeyParamSet = ecP.PublicKeyParamSet; + } + + this.parameters = ecP.DomainParameters; + } + else + { + DerObjectIdentifier oid; + switch (parameters.Strength) + { + case 192: + oid = X9ObjectIdentifiers.Prime192v1; + break; + case 239: + oid = X9ObjectIdentifiers.Prime239v1; + break; + case 256: + oid = X9ObjectIdentifiers.Prime256v1; + break; + default: + throw new InvalidParameterException("unknown key size."); + } + + X9ECParameters ecps = X962NamedCurves.GetByOid(oid); + + this.parameters = new ECDomainParameters( + ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed()); + } + + this.random = parameters.Random; + } + + /** + * Given the domain parameters this routine Generates an EC key + * pair in accordance with X9.62 section 5.2.1 pages 26, 27. + */ + public AsymmetricCipherKeyPair GenerateKeyPair() + { + BigInteger n = parameters.N; + BigInteger d; + + do + { + d = new BigInteger(n.BitLength, random); + } + while (d.SignValue == 0 || (d.CompareTo(n) >= 0)); + + ECPoint q = parameters.G.Multiply(d); + + if (publicKeyParamSet != null) + { + return new AsymmetricCipherKeyPair( + new ECPublicKeyParameters(q, publicKeyParamSet), + new ECPrivateKeyParameters(d, publicKeyParamSet)); + } + + return new AsymmetricCipherKeyPair( + new ECPublicKeyParameters(algorithm, q, parameters), + new ECPrivateKeyParameters(algorithm, d, parameters)); + } + + private string VerifyAlgorithmName( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + + switch (upper) + { + case "EC": + case "ECDSA": + case "ECGOST3410": + case "ECDH": + case "ECDHC": + break; + default: + throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm"); + } + + return upper; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs new file mode 100644 index 0000000..13e8d62 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs @@ -0,0 +1,40 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * a ElGamal key pair generator. + *

      + * This Generates keys consistent for use with ElGamal as described in + * page 164 of "Handbook of Applied Cryptography".

      + */ + public class ElGamalKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private ElGamalKeyGenerationParameters param; + + public void Init( + KeyGenerationParameters parameters) + { + this.param = (ElGamalKeyGenerationParameters) parameters; + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance; + ElGamalParameters elParams = param.Parameters; + + BigInteger p = elParams.P; + BigInteger x = helper.CalculatePrivate(p, param.Random, elParams.L); + BigInteger y = helper.CalculatePublic(p, elParams.G, x); + + return new AsymmetricCipherKeyPair( + new ElGamalPublicKeyParameters(y, elParams), + new ElGamalPrivateKeyParameters(x, elParams)); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/generators/ElGamalParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/ElGamalParametersGenerator.cs new file mode 100644 index 0000000..8443bb0 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/ElGamalParametersGenerator.cs @@ -0,0 +1,46 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + public class ElGamalParametersGenerator + { + private int size; + private int certainty; + private SecureRandom random; + + public void Init( + int size, + int certainty, + SecureRandom random) + { + this.size = size; + this.certainty = certainty; + this.random = random; + } + + /** + * which Generates the p and g values from the given parameters, + * returning the ElGamalParameters object. + *

      + * Note: can take a while... + *

      + */ + public ElGamalParameters GenerateParameters() + { + // + // find a safe prime p where p = 2*q + 1, where p and q are prime. + // + BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random); + + BigInteger p = safePrimes[0]; + BigInteger q = safePrimes[1]; + BigInteger g = DHParametersHelper.SelectGenerator(p, q, random); + + return new ElGamalParameters(p, g); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs new file mode 100644 index 0000000..5878da6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs @@ -0,0 +1,73 @@ +using System; + +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * a GOST3410 key pair generator. + * This generates GOST3410 keys in line with the method described + * in GOST R 34.10-94. + */ + public class Gost3410KeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private Gost3410KeyGenerationParameters param; + + public void Init( + KeyGenerationParameters parameters) + { + if (parameters is Gost3410KeyGenerationParameters) + { + this.param = (Gost3410KeyGenerationParameters) parameters; + } + else + { + Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters( + parameters.Random, + CryptoProObjectIdentifiers.GostR3410x94CryptoProA); + + if (parameters.Strength != kgp.Parameters.P.BitLength - 1) + { + // TODO Should we complain? + } + + this.param = kgp; + } + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + SecureRandom random = param.Random; + Gost3410Parameters gost3410Params = param.Parameters; + + BigInteger q = gost3410Params.Q; + BigInteger x; + do + { + x = new BigInteger(256, random); + } + while (x.SignValue < 1 || x.CompareTo(q) >= 0); + + BigInteger p = gost3410Params.P; + BigInteger a = gost3410Params.A; + + // calculate the public key. + BigInteger y = a.ModPow(x, p); + + if (param.PublicKeyParamSet != null) + { + return new AsymmetricCipherKeyPair( + new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet), + new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet)); + } + + return new AsymmetricCipherKeyPair( + new Gost3410PublicKeyParameters(y, gost3410Params), + new Gost3410PrivateKeyParameters(x, gost3410Params)); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/GOST3410ParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/GOST3410ParametersGenerator.cs new file mode 100644 index 0000000..52a9f5a --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/GOST3410ParametersGenerator.cs @@ -0,0 +1,530 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * generate suitable parameters for GOST3410. + */ + public class Gost3410ParametersGenerator + { + private int size; + private int typeproc; + private SecureRandom init_random; + + /** + * initialise the key generator. + * + * @param size size of the key + * @param typeProcedure type procedure A,B = 1; A',B' - else + * @param random random byte source. + */ + public void Init( + int size, + int typeProcedure, + SecureRandom random) + { + this.size = size; + this.typeproc = typeProcedure; + this.init_random = random; + } + + //Procedure A + private int procedure_A(int x0, int c, BigInteger[] pq, int size) + { + //Verify and perform condition: 065536) + { + x0 = init_random.NextInt()/32768; + } + + while((c<0 || c>65536) || (c/2==0)) + { + c = init_random.NextInt()/32768 + 1; + } + + BigInteger C = BigInteger.ValueOf(c); + BigInteger constA16 = BigInteger.ValueOf(19381); + + //step1 + BigInteger[] y = new BigInteger[1]; // begin length = 1 + y[0] = BigInteger.ValueOf(x0); + + //step 2 + int[] t = new int[1]; // t - orders; begin length = 1 + t[0] = size; + int s = 0; + for (int i=0; t[i]>=17; i++) + { + // extension array t + int[] tmp_t = new int[t.Length + 1]; /////////////// + Array.Copy(t,0,tmp_t,0,t.Length); // extension + t = new int[tmp_t.Length]; // array t + Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); /////////////// + + t[i+1] = t[i]/2; + s = i+1; + } + + //step3 + BigInteger[] p = new BigInteger[s+1]; + p[s] = new BigInteger("8003",16); //set min prime number length 16 bit + + int m = s-1; //step4 + + for (int i=0; i t[m]) + { + goto step6; //step 12 + } + + p[m] = NByLastP.Add(BigInteger.One); + + //step13 + if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0 + && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0) + { + break; + } + + N = N.Add(BigInteger.Two); + } + + if (--m < 0) + { + pq[0] = p[0]; + pq[1] = p[1]; + return y[0].IntValue; //return for procedure B step 2 + } + + break; //step 14 + } + } + return y[0].IntValue; + } + + //Procedure A' + private long procedure_Aa(long x0, long c, BigInteger[] pq, int size) + { + //Verify and perform condition: 04294967296L) + { + x0 = init_random.NextInt()*2; + } + + while((c<0 || c>4294967296L) || (c/2==0)) + { + c = init_random.NextInt()*2+1; + } + + BigInteger C = BigInteger.ValueOf(c); + BigInteger constA32 = BigInteger.ValueOf(97781173); + + //step1 + BigInteger[] y = new BigInteger[1]; // begin length = 1 + y[0] = BigInteger.ValueOf(x0); + + //step 2 + int[] t = new int[1]; // t - orders; begin length = 1 + t[0] = size; + int s = 0; + for (int i=0; t[i]>=33; i++) + { + // extension array t + int[] tmp_t = new int[t.Length + 1]; /////////////// + Array.Copy(t,0,tmp_t,0,t.Length); // extension + t = new int[tmp_t.Length]; // array t + Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); /////////////// + + t[i+1] = t[i]/2; + s = i+1; + } + + //step3 + BigInteger[] p = new BigInteger[s+1]; + p[s] = new BigInteger("8000000B",16); //set min prime number length 32 bit + + int m = s-1; //step4 + + for (int i=0; i t[m]) + { + goto step6; //step 12 + } + + p[m] = NByLastP.Add(BigInteger.One); + + //step13 + if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0 + && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0) + { + break; + } + + N = N.Add(BigInteger.Two); + } + + if (--m < 0) + { + pq[0] = p[0]; + pq[1] = p[1]; + return y[0].LongValue; //return for procedure B' step 2 + } + + break; //step 14 + } + } + return y[0].LongValue; + } + + //Procedure B + private void procedure_B(int x0, int c, BigInteger[] pq) + { + //Verify and perform condition: 065536) + { + x0 = init_random.NextInt()/32768; + } + + while((c<0 || c>65536) || (c/2==0)) + { + c = init_random.NextInt()/32768 + 1; + } + + BigInteger [] qp = new BigInteger[2]; + BigInteger q = null, Q = null, p = null; + BigInteger C = BigInteger.ValueOf(c); + BigInteger constA16 = BigInteger.ValueOf(19381); + + //step1 + x0 = procedure_A(x0, c, qp, 256); + q = qp[0]; + + //step2 + x0 = procedure_A(x0, c, qp, 512); + Q = qp[0]; + + BigInteger[] y = new BigInteger[65]; + y[0] = BigInteger.ValueOf(x0); + + const int tp = 1024; + + BigInteger qQ = q.Multiply(Q); + +step3: + for(;;) + { + //step 3 + for (int j=0; j<64; j++) + { + y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16)); + } + + //step 4 + BigInteger Y = BigInteger.Zero; + + for (int j=0; j<64; j++) + { + Y = Y.Add(y[j].ShiftLeft(16*j)); + } + + y[0] = y[64]; //step 5 + + //step 6 + BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add( + Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024))); + + if (N.TestBit(0)) + { + N = N.Add(BigInteger.One); + } + + //step 7 + + for(;;) + { + //step 11 + BigInteger qQN = qQ.Multiply(N); + + if (qQN.BitLength > tp) + { + goto step3; //step 9 + } + + p = qQN.Add(BigInteger.One); + + //step10 + if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0 + && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0) + { + pq[0] = p; + pq[1] = q; + return; + } + + N = N.Add(BigInteger.Two); + } + } + } + + //Procedure B' + private void procedure_Bb(long x0, long c, BigInteger[] pq) + { + //Verify and perform condition: 04294967296L) + { + x0 = init_random.NextInt()*2; + } + + while((c<0 || c>4294967296L) || (c/2==0)) + { + c = init_random.NextInt()*2+1; + } + + BigInteger [] qp = new BigInteger[2]; + BigInteger q = null, Q = null, p = null; + BigInteger C = BigInteger.ValueOf(c); + BigInteger constA32 = BigInteger.ValueOf(97781173); + + //step1 + x0 = procedure_Aa(x0, c, qp, 256); + q = qp[0]; + + //step2 + x0 = procedure_Aa(x0, c, qp, 512); + Q = qp[0]; + + BigInteger[] y = new BigInteger[33]; + y[0] = BigInteger.ValueOf(x0); + + const int tp = 1024; + + BigInteger qQ = q.Multiply(Q); + +step3: + for(;;) + { + //step 3 + for (int j=0; j<32; j++) + { + y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32)); + } + + //step 4 + BigInteger Y = BigInteger.Zero; + for (int j=0; j<32; j++) + { + Y = Y.Add(y[j].ShiftLeft(32*j)); + } + + y[0] = y[32]; //step 5 + + //step 6 + BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add( + Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024))); + + if (N.TestBit(0)) + { + N = N.Add(BigInteger.One); + } + + //step 7 + + for(;;) + { + //step 11 + BigInteger qQN = qQ.Multiply(N); + + if (qQN.BitLength > tp) + { + goto step3; //step 9 + } + + p = qQN.Add(BigInteger.One); + + //step10 + if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0 + && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0) + { + pq[0] = p; + pq[1] = q; + return; + } + + N = N.Add(BigInteger.Two); + } + } + } + + + /** + * Procedure C + * procedure generates the a value from the given p,q, + * returning the a value. + */ + private BigInteger procedure_C(BigInteger p, BigInteger q) + { + BigInteger pSub1 = p.Subtract(BigInteger.One); + BigInteger pSub1Divq = pSub1.Divide(q); + + for(;;) + { + BigInteger d = new BigInteger(p.BitLength, init_random); + + // 1 < d < p-1 + if (d.CompareTo(BigInteger.One) > 0 && d.CompareTo(pSub1) < 0) + { + BigInteger a = d.ModPow(pSub1Divq, p); + + if (a.CompareTo(BigInteger.One) != 0) + { + return a; + } + } + } + } + + /** + * which generates the p , q and a values from the given parameters, + * returning the Gost3410Parameters object. + */ + public Gost3410Parameters GenerateParameters() + { + BigInteger [] pq = new BigInteger[2]; + BigInteger q = null, p = null, a = null; + + int x0, c; + long x0L, cL; + + if (typeproc==1) + { + x0 = init_random.NextInt(); + c = init_random.NextInt(); + + switch(size) + { + case 512: + procedure_A(x0, c, pq, 512); + break; + case 1024: + procedure_B(x0, c, pq); + break; + default: + throw new ArgumentException("Ooops! key size 512 or 1024 bit."); + } + p = pq[0]; q = pq[1]; + a = procedure_C(p, q); + //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16)); + //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a); + return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0, c)); + } + else + { + x0L = init_random.NextLong(); + cL = init_random.NextLong(); + + switch(size) + { + case 512: + procedure_Aa(x0L, cL, pq, 512); + break; + case 1024: + procedure_Bb(x0L, cL, pq); + break; + default: + throw new InvalidOperationException("Ooops! key size 512 or 1024 bit."); + } + p = pq[0]; q = pq[1]; + a = procedure_C(p, q); + //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16)); + //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a); + return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0L, cL)); + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/Kdf1BytesGenerator.cs b/iTechSharp/srcbc/crypto/generators/Kdf1BytesGenerator.cs new file mode 100644 index 0000000..2b4fb7e --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/Kdf1BytesGenerator.cs @@ -0,0 +1,27 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033 + *
      + * This implementation is based on IEEE P1363/ISO 18033. + */ + public class Kdf1BytesGenerator + : BaseKdfBytesGenerator + { + /** + * Construct a KDF1 byte generator. + * + * @param digest the digest to be used as the source of derived keys. + */ + public Kdf1BytesGenerator( + IDigest digest) + : base(0, digest) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/Kdf2BytesGenerator.cs b/iTechSharp/srcbc/crypto/generators/Kdf2BytesGenerator.cs new file mode 100644 index 0000000..60471a1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/Kdf2BytesGenerator.cs @@ -0,0 +1,28 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033 + *
      + * This implementation is based on IEEE P1363/ISO 18033. + */ + public class Kdf2BytesGenerator + : BaseKdfBytesGenerator + { + /** + * Construct a KDF2 bytes generator. Generates key material + * according to IEEE P1363 or ISO 18033 depending on the initialisation. + * + * @param digest the digest to be used as the source of derived keys. + */ + public Kdf2BytesGenerator( + IDigest digest) + : base(1, digest) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/Mgf1BytesGenerator.cs b/iTechSharp/srcbc/crypto/generators/Mgf1BytesGenerator.cs new file mode 100644 index 0000000..23a3aca --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/Mgf1BytesGenerator.cs @@ -0,0 +1,117 @@ +using System; +//using Org.BouncyCastle.Math; +//using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generator for MGF1 as defined in Pkcs 1v2 + */ + public class Mgf1BytesGenerator : IDerivationFunction + { + private IDigest digest; + private byte[] seed; + private int hLen; + + /** + * @param digest the digest to be used as the source of Generated bytes + */ + public Mgf1BytesGenerator( + IDigest digest) + { + this.digest = digest; + this.hLen = digest.GetDigestSize(); + } + + public void Init( + IDerivationParameters parameters) + { + if (!(typeof(MgfParameters).IsInstanceOfType(parameters))) + { + throw new ArgumentException("MGF parameters required for MGF1Generator"); + } + + MgfParameters p = (MgfParameters)parameters; + + seed = p.GetSeed(); + } + + /** + * return the underlying digest. + */ + public IDigest Digest + { + get + { + return digest; + } + } + + /** + * int to octet string. + */ + private void ItoOSP( + int i, + byte[] sp) + { + sp[0] = (byte)((uint) i >> 24); + sp[1] = (byte)((uint) i >> 16); + sp[2] = (byte)((uint) i >> 8); + sp[3] = (byte)((uint) i >> 0); + } + + /** + * fill len bytes of the output buffer with bytes Generated from + * the derivation function. + * + * @throws DataLengthException if the out buffer is too small. + */ + public int GenerateBytes( + byte[] output, + int outOff, + int length) + { + if ((output.Length - length) < outOff) + { + throw new DataLengthException("output buffer too small"); + } + + byte[] hashBuf = new byte[hLen]; + byte[] C = new byte[4]; + int counter = 0; + + digest.Reset(); + + if (length > hLen) + { + do + { + ItoOSP(counter, C); + + digest.BlockUpdate(seed, 0, seed.Length); + digest.BlockUpdate(C, 0, C.Length); + digest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen); + } + while (++counter < (length / hLen)); + } + + if ((counter * hLen) < length) + { + ItoOSP(counter, C); + + digest.BlockUpdate(seed, 0, seed.Length); + digest.BlockUpdate(C, 0, C.Length); + digest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen)); + } + + return length; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs new file mode 100644 index 0000000..9d58225 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see + * + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + */ + public class NaccacheSternKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private static readonly int[] smallPrimes = + { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, + 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, + 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, + 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, + 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, + 541, 547, 557 + }; + + private NaccacheSternKeyGenerationParameters param; + + /* + * (non-Javadoc) + * + * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters) + */ + public void Init(KeyGenerationParameters parameters) + { + this.param = (NaccacheSternKeyGenerationParameters)parameters; + } + + /* + * (non-Javadoc) + * + * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair() + */ + public AsymmetricCipherKeyPair GenerateKeyPair() + { + int strength = param.Strength; + SecureRandom rand = param.Random; + int certainty = param.Certainty; + bool debug = param.IsDebug; + + if (debug) + { + Console.WriteLine("Fetching first " + param.CountSmallPrimes + " primes."); + } + + ArrayList smallPrimes = findFirstPrimes(param.CountSmallPrimes); + + smallPrimes = permuteList(smallPrimes, rand); + + BigInteger u = BigInteger.One; + BigInteger v = BigInteger.One; + + for (int i = 0; i < smallPrimes.Count / 2; i++) + { + u = u.Multiply((BigInteger)smallPrimes[i]); + } + for (int i = smallPrimes.Count / 2; i < smallPrimes.Count; i++) + { + v = v.Multiply((BigInteger)smallPrimes[i]); + } + + BigInteger sigma = u.Multiply(v); + + // n = (2 a u p_ + 1 ) ( 2 b v q_ + 1) + // -> |n| = strength + // |2| = 1 in bits + // -> |a| * |b| = |n| - |u| - |v| - |p_| - |q_| - |2| -|2| + // remainingStrength = strength - sigma.bitLength() - p_.bitLength() - + // q_.bitLength() - 1 -1 + int remainingStrength = strength - sigma.BitLength - 48; + BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand); + BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand); + + BigInteger p_; + BigInteger q_; + BigInteger p; + BigInteger q; + + long tries = 0; + if (debug) + { + Console.WriteLine("generating p and q"); + } + + BigInteger _2au = a.Multiply(u).ShiftLeft(1); + BigInteger _2bv = b.Multiply(v).ShiftLeft(1); + + for (;;) + { + tries++; + + p_ = generatePrime(24, certainty, rand); + + p = p_.Multiply(_2au).Add(BigInteger.One); + + if (!p.IsProbablePrime(certainty)) + continue; + + for (;;) + { + q_ = generatePrime(24, certainty, rand); + + if (p_.Equals(q_)) + continue; + + q = q_.Multiply(_2bv).Add(BigInteger.One); + + if (q.IsProbablePrime(certainty)) + break; + } + + if (!sigma.Gcd(p_.Multiply(q_)).Equals(BigInteger.One)) + { + Console.WriteLine("sigma.gcd(p_.mult(q_)) != 1!\n p_: " + p_ +"\n q_: "+ q_ ); + continue; + } + + if (p.Multiply(q).BitLength < strength) + { + if (debug) + { + Console.WriteLine("key size too small. Should be " + strength + " but is actually " + + p.Multiply(q).BitLength); + } + continue; + } + break; + } + + if (debug) + { + Console.WriteLine("needed " + tries + " tries to generate p and q."); + } + + BigInteger n = p.Multiply(q); + BigInteger phi_n = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One)); + BigInteger g; + tries = 0; + if (debug) + { + Console.WriteLine("generating g"); + } + for (;;) + { + // TODO After the first loop, just regenerate one randomly-selected gPart each time? + ArrayList gParts = new ArrayList(); + for (int ind = 0; ind != smallPrimes.Count; ind++) + { + BigInteger i = (BigInteger)smallPrimes[ind]; + BigInteger e = phi_n.Divide(i); + + for (;;) + { + tries++; + + g = generatePrime(strength, certainty, rand); + + if (!g.ModPow(e, n).Equals(BigInteger.One)) + { + gParts.Add(g); + break; + } + } + } + g = BigInteger.One; + for (int i = 0; i < smallPrimes.Count; i++) + { + BigInteger gPart = (BigInteger) gParts[i]; + BigInteger smallPrime = (BigInteger) smallPrimes[i]; + g = g.Multiply(gPart.ModPow(sigma.Divide(smallPrime), n)).Mod(n); + } + + // make sure that g is not divisible by p_i or q_i + bool divisible = false; + for (int i = 0; i < smallPrimes.Count; i++) + { + if (g.ModPow(phi_n.Divide((BigInteger)smallPrimes[i]), n).Equals(BigInteger.One)) + { + if (debug) + { + Console.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g); + } + divisible = true; + break; + } + } + + if (divisible) + { + continue; + } + + // make sure that g has order > phi_n/4 + + //if (g.ModPow(phi_n.Divide(BigInteger.ValueOf(4)), n).Equals(BigInteger.One)) + if (g.ModPow(phi_n.ShiftRight(2), n).Equals(BigInteger.One)) + { + if (debug) + { + Console.WriteLine("g has order phi(n)/4\n g:" + g); + } + continue; + } + + if (g.ModPow(phi_n.Divide(p_), n).Equals(BigInteger.One)) + { + if (debug) + { + Console.WriteLine("g has order phi(n)/p'\n g: " + g); + } + continue; + } + if (g.ModPow(phi_n.Divide(q_), n).Equals(BigInteger.One)) + { + if (debug) + { + Console.WriteLine("g has order phi(n)/q'\n g: " + g); + } + continue; + } + if (g.ModPow(phi_n.Divide(a), n).Equals(BigInteger.One)) + { + if (debug) + { + Console.WriteLine("g has order phi(n)/a\n g: " + g); + } + continue; + } + if (g.ModPow(phi_n.Divide(b), n).Equals(BigInteger.One)) + { + if (debug) + { + Console.WriteLine("g has order phi(n)/b\n g: " + g); + } + continue; + } + break; + } + if (debug) + { + Console.WriteLine("needed " + tries + " tries to generate g"); + Console.WriteLine(); + Console.WriteLine("found new NaccacheStern cipher variables:"); + Console.WriteLine("smallPrimes: " + Arrays.ToString(smallPrimes.ToArray())); + Console.WriteLine("sigma:...... " + sigma + " (" + sigma.BitLength + " bits)"); + Console.WriteLine("a:.......... " + a); + Console.WriteLine("b:.......... " + b); + Console.WriteLine("p':......... " + p_); + Console.WriteLine("q':......... " + q_); + Console.WriteLine("p:.......... " + p); + Console.WriteLine("q:.......... " + q); + Console.WriteLine("n:.......... " + n); + Console.WriteLine("phi(n):..... " + phi_n); + Console.WriteLine("g:.......... " + g); + Console.WriteLine(); + } + + return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength), + new NaccacheSternPrivateKeyParameters(g, n, sigma.BitLength, smallPrimes, phi_n)); + } + + private static BigInteger generatePrime( + int bitLength, + int certainty, + SecureRandom rand) + { + return new BigInteger(bitLength, certainty, rand); + } + + /** + * Generates a permuted ArrayList from the original one. The original List + * is not modified + * + * @param arr + * the ArrayList to be permuted + * @param rand + * the source of Randomness for permutation + * @return a new ArrayList with the permuted elements. + */ + private static ArrayList permuteList( + ArrayList arr, + SecureRandom rand) + { + ArrayList retval = new ArrayList(arr.Count); + + foreach (object element in arr) + { + int index = rand.Next(retval.Count + 1); + retval.Insert(index, element); + } + + return retval; + } + + /** + * Finds the first 'count' primes starting with 3 + * + * @param count + * the number of primes to find + * @return a vector containing the found primes as Integer + */ + private static ArrayList findFirstPrimes( + int count) + { + ArrayList primes = new ArrayList(count); + + for (int i = 0; i != count; i++) + { + primes.Add(BigInteger.ValueOf(smallPrimes[i])); + } + + return primes; + } + + } +} diff --git a/iTechSharp/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs new file mode 100644 index 0000000..8da5d3a --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs @@ -0,0 +1,167 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generator for PBE derived keys and ivs as usd by OpenSSL. + *

      + * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an + * iteration count of 1. + *

      + */ + public class OpenSslPbeParametersGenerator + : PbeParametersGenerator + { + private readonly IDigest digest = new MD5Digest(); + + /** + * Construct a OpenSSL Parameters generator. + */ + public OpenSslPbeParametersGenerator() + { + } + + public override void Init( + byte[] password, + byte[] salt, + int iterationCount) + { + // Ignore the provided iterationCount + base.Init(password, salt, 1); + } + + /** + * Initialise - note the iteration count for this algorithm is fixed at 1. + * + * @param password password to use. + * @param salt salt to use. + */ + public virtual void Init( + byte[] password, + byte[] salt) + { + base.Init(password, salt, 1); + } + + /** + * the derived key function, the ith hash of the password and the salt. + */ + private byte[] GenerateDerivedKey( + int bytesNeeded) + { + byte[] buf = new byte[digest.GetDigestSize()]; + byte[] key = new byte[bytesNeeded]; + int offset = 0; + + for (;;) + { + digest.BlockUpdate(mPassword, 0, mPassword.Length); + digest.BlockUpdate(mSalt, 0, mSalt.Length); + + digest.DoFinal(buf, 0); + + int len = (bytesNeeded > buf.Length) ? buf.Length : bytesNeeded; + Array.Copy(buf, 0, key, offset, len); + offset += len; + + // check if we need any more + bytesNeeded -= len; + if (bytesNeeded == 0) + { + break; + } + + // do another round + digest.Reset(); + digest.BlockUpdate(buf, 0, buf.Length); + } + + return key; + } + + /** + * Generate a key parameter derived from the password, salt, and iteration + * count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + * @exception ArgumentException if the key length larger than the base hash size. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize) + { + return GenerateDerivedMacParameters(keySize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize) + { + keySize /= 8; + + byte[] dKey = GenerateDerivedKey(keySize); + + return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + } + + /** + * Generate a key with initialisation vector parameter derived from + * the password, salt, and iteration count we are currently initialised + * with. + * + * @param keySize the size of the key we want (in bits) + * @param ivSize the size of the iv we want (in bits) + * @return a ParametersWithIV object. + * @exception ArgumentException if keySize + ivSize is larger than the base hash size. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize, + int ivSize) + { + keySize = keySize / 8; + ivSize = ivSize / 8; + + byte[] dKey = GenerateDerivedKey(keySize + ivSize); + + return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + byte[] dKey = GenerateDerivedKey(keySize + ivSize); + KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + + return new ParametersWithIV(key, dKey, keySize, ivSize); + } + + /** + * Generate a key parameter for use with a MAC derived from the password, + * salt, and iteration count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + * @exception ArgumentException if the key length larger than the base hash size. + */ + public override ICipherParameters GenerateDerivedMacParameters( + int keySize) + { + keySize = keySize / 8; + + byte[] dKey = GenerateDerivedKey(keySize); + + return new KeyParameter(dKey, 0, keySize); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs new file mode 100644 index 0000000..d2da3f6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs @@ -0,0 +1,245 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generator for Pbe derived keys and ivs as defined by Pkcs 12 V1.0. + *

      + * The document this implementation is based on can be found at + * + * RSA's Pkcs12 Page + *

      + */ + public class Pkcs12ParametersGenerator + : PbeParametersGenerator + { + public const int KeyMaterial = 1; + public const int IVMaterial = 2; + public const int MacMaterial = 3; + + private readonly IDigest digest; + + private readonly int u; + private readonly int v; + + /** + * Construct a Pkcs 12 Parameters generator. + * + * @param digest the digest to be used as the source of derived keys. + * @exception ArgumentException if an unknown digest is passed in. + */ + public Pkcs12ParametersGenerator( + IDigest digest) + { + this.digest = digest; + + u = digest.GetDigestSize(); + v = digest.GetByteLength(); + } + + /** + * add a + b + 1, returning the result in a. The a value is treated + * as a BigInteger of length (b.Length * 8) bits. The result is + * modulo 2^b.Length in case of overflow. + */ + private void Adjust( + byte[] a, + int aOff, + byte[] b) + { + int x = (b[b.Length - 1] & 0xff) + (a[aOff + b.Length - 1] & 0xff) + 1; + + a[aOff + b.Length - 1] = (byte)x; + x = (int) ((uint) x >> 8); + + for (int i = b.Length - 2; i >= 0; i--) + { + x += (b[i] & 0xff) + (a[aOff + i] & 0xff); + a[aOff + i] = (byte)x; + x = (int) ((uint) x >> 8); + } + } + + /** + * generation of a derived key ala Pkcs12 V1.0. + */ + private byte[] GenerateDerivedKey( + int idByte, + int n) + { + byte[] D = new byte[v]; + byte[] dKey = new byte[n]; + + for (int i = 0; i != D.Length; i++) + { + D[i] = (byte)idByte; + } + + byte[] S; + + if ((mSalt != null) && (mSalt.Length != 0)) + { + S = new byte[v * ((mSalt.Length + v - 1) / v)]; + + for (int i = 0; i != S.Length; i++) + { + S[i] = mSalt[i % mSalt.Length]; + } + } + else + { + S = new byte[0]; + } + + byte[] P; + + if ((mPassword != null) && (mPassword.Length != 0)) + { + P = new byte[v * ((mPassword.Length + v - 1) / v)]; + + for (int i = 0; i != P.Length; i++) + { + P[i] = mPassword[i % mPassword.Length]; + } + } + else + { + P = new byte[0]; + } + + byte[] I = new byte[S.Length + P.Length]; + + Array.Copy(S, 0, I, 0, S.Length); + Array.Copy(P, 0, I, S.Length, P.Length); + + byte[] B = new byte[v]; + int c = (n + u - 1) / u; + + for (int i = 1; i <= c; i++) + { + byte[] A = new byte[u]; + + digest.BlockUpdate(D, 0, D.Length); + digest.BlockUpdate(I, 0, I.Length); + digest.DoFinal(A, 0); + for (int j = 1; j != mIterationCount; j++) + { + digest.BlockUpdate(A, 0, A.Length); + digest.DoFinal(A, 0); + } + + for (int j = 0; j != B.Length; j++) + { + B[j] = A[j % A.Length]; + } + + for (int j = 0; j != I.Length / v; j++) + { + Adjust(I, j * v, B); + } + + if (i == c) + { + Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u)); + } + else + { + Array.Copy(A, 0, dKey, (i - 1) * u, A.Length); + } + } + + return dKey; + } + + /** + * Generate a key parameter derived from the password, salt, and iteration + * count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize) + { + keySize /= 8; + + byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize); + + return new KeyParameter(dKey, 0, keySize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize) + { + keySize /= 8; + + byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize); + + return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + } + + /** + * Generate a key with initialisation vector parameter derived from + * the password, salt, and iteration count we are currently initialised + * with. + * + * @param keySize the size of the key we want (in bits) + * @param ivSize the size of the iv we want (in bits) + * @return a ParametersWithIV object. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize); + + byte[] iv = GenerateDerivedKey(IVMaterial, ivSize); + + return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize); + KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + + byte[] iv = GenerateDerivedKey(IVMaterial, ivSize); + + return new ParametersWithIV(key, iv, 0, ivSize); + } + + /** + * Generate a key parameter for use with a MAC derived from the password, + * salt, and iteration count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + */ + public override ICipherParameters GenerateDerivedMacParameters( + int keySize) + { + keySize /= 8; + + byte[] dKey = GenerateDerivedKey(MacMaterial, keySize); + + return new KeyParameter(dKey, 0, keySize); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs new file mode 100644 index 0000000..8586e1c --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs @@ -0,0 +1,162 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 1. + * Note this generator is limited to the size of the hash produced by the + * digest used to drive it. + *

      + * The document this implementation is based on can be found at + * + * RSA's Pkcs5 Page + *

      + */ + public class Pkcs5S1ParametersGenerator + : PbeParametersGenerator + { + private readonly IDigest digest; + + /** + * Construct a Pkcs 5 Scheme 1 Parameters generator. + * + * @param digest the digest to be used as the source of derived keys. + */ + public Pkcs5S1ParametersGenerator( + IDigest digest) + { + this.digest = digest; + } + + /** + * the derived key function, the ith hash of the mPassword and the mSalt. + */ + private byte[] GenerateDerivedKey() + { + byte[] digestBytes = new byte[digest.GetDigestSize()]; + + digest.BlockUpdate(mPassword, 0, mPassword.Length); + digest.BlockUpdate(mSalt, 0, mSalt.Length); + + digest.DoFinal(digestBytes, 0); + for (int i = 1; i < mIterationCount; i++) + { + digest.BlockUpdate(digestBytes, 0, digestBytes.Length); + digest.DoFinal(digestBytes, 0); + } + + return digestBytes; + } + + /** + * Generate a key parameter derived from the mPassword, mSalt, and iteration + * count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + * @exception ArgumentException if the key length larger than the base hash size. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize) + { + return GenerateDerivedMacParameters(keySize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize) + { + keySize /= 8; + + if (keySize > digest.GetDigestSize()) + { + throw new ArgumentException( + "Can't Generate a derived key " + keySize + " bytes long."); + } + + byte[] dKey = GenerateDerivedKey(); + + return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + } + + /** + * Generate a key with initialisation vector parameter derived from + * the mPassword, mSalt, and iteration count we are currently initialised + * with. + * + * @param keySize the size of the key we want (in bits) + * @param ivSize the size of the iv we want (in bits) + * @return a ParametersWithIV object. + * @exception ArgumentException if keySize + ivSize is larger than the base hash size. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + if ((keySize + ivSize) > digest.GetDigestSize()) + { + throw new ArgumentException( + "Can't Generate a derived key " + (keySize + ivSize) + " bytes long."); + } + + byte[] dKey = GenerateDerivedKey(); + + return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + if ((keySize + ivSize) > digest.GetDigestSize()) + { + throw new ArgumentException( + "Can't Generate a derived key " + (keySize + ivSize) + " bytes long."); + } + + byte[] dKey = GenerateDerivedKey(); + KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + + return new ParametersWithIV(key, dKey, keySize, ivSize); + } + + /** + * Generate a key parameter for use with a MAC derived from the mPassword, + * mSalt, and iteration count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + * @exception ArgumentException if the key length larger than the base hash size. + */ + public override ICipherParameters GenerateDerivedMacParameters( + int keySize) + { + keySize /= 8; + + if (keySize > digest.GetDigestSize()) + { + throw new ArgumentException( + "Can't Generate a derived key " + keySize + " bytes long."); + } + + byte[] dKey = GenerateDerivedKey(); + + return new KeyParameter(dKey, 0, keySize); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs b/iTechSharp/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs new file mode 100644 index 0000000..223595d --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs @@ -0,0 +1,175 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 2. + * This generator uses a SHA-1 HMac as the calculation function. + *

      + * The document this implementation is based on can be found at + * + * RSA's Pkcs5 Page

      + */ + public class Pkcs5S2ParametersGenerator + : PbeParametersGenerator + { + private readonly IMac hMac = new HMac(new Sha1Digest()); + + /** + * construct a Pkcs5 Scheme 2 Parameters generator. + */ + public Pkcs5S2ParametersGenerator() + { + } + + private void F( + byte[] P, + byte[] S, + int c, + byte[] iBuf, + byte[] outBytes, + int outOff) + { + byte[] state = new byte[hMac.GetMacSize()]; + ICipherParameters param = new KeyParameter(P); + + hMac.Init(param); + + if (S != null) + { + hMac.BlockUpdate(S, 0, S.Length); + } + + hMac.BlockUpdate(iBuf, 0, iBuf.Length); + + hMac.DoFinal(state, 0); + + Array.Copy(state, 0, outBytes, outOff, state.Length); + + for (int count = 1; count != c; count++) + { + hMac.Init(param); + hMac.BlockUpdate(state, 0, state.Length); + hMac.DoFinal(state, 0); + + for (int j = 0; j != state.Length; j++) + { + outBytes[outOff + j] ^= state[j]; + } + } + } + + private void IntToOctet( + byte[] Buffer, + int i) + { + Buffer[0] = (byte)((uint) i >> 24); + Buffer[1] = (byte)((uint) i >> 16); + Buffer[2] = (byte)((uint) i >> 8); + Buffer[3] = (byte)i; + } + + private byte[] GenerateDerivedKey( + int dkLen) + { + int hLen = hMac.GetMacSize(); + int l = (dkLen + hLen - 1) / hLen; + byte[] iBuf = new byte[4]; + byte[] outBytes = new byte[l * hLen]; + + for (int i = 1; i <= l; i++) + { + IntToOctet(iBuf, i); + + F(mPassword, mSalt, mIterationCount, iBuf, outBytes, (i - 1) * hLen); + } + + return outBytes; + } + + /** + * Generate a key parameter derived from the password, salt, and iteration + * count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize) + { + return GenerateDerivedMacParameters(keySize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize) + { + keySize /= 8; + + byte[] dKey = GenerateDerivedKey(keySize); + + return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + } + + /** + * Generate a key with initialisation vector parameter derived from + * the password, salt, and iteration count we are currently initialised + * with. + * + * @param keySize the size of the key we want (in bits) + * @param ivSize the size of the iv we want (in bits) + * @return a ParametersWithIV object. + */ + [Obsolete("Use version with 'algorithm' parameter")] + public override ICipherParameters GenerateDerivedParameters( + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + byte[] dKey = GenerateDerivedKey(keySize + ivSize); + + return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize); + } + + public override ICipherParameters GenerateDerivedParameters( + string algorithm, + int keySize, + int ivSize) + { + keySize /= 8; + ivSize /= 8; + + byte[] dKey = GenerateDerivedKey(keySize + ivSize); + KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize); + + return new ParametersWithIV(key, dKey, keySize, ivSize); + } + + /** + * Generate a key parameter for use with a MAC derived from the password, + * salt, and iteration count we are currently initialised with. + * + * @param keySize the size of the key we want (in bits) + * @return a KeyParameter object. + */ + public override ICipherParameters GenerateDerivedMacParameters( + int keySize) + { + keySize /= 8; + + byte[] dKey = GenerateDerivedKey(keySize); + + return new KeyParameter(dKey, 0, keySize); + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/RSABlindingFactorGenerator.cs b/iTechSharp/srcbc/crypto/generators/RSABlindingFactorGenerator.cs new file mode 100644 index 0000000..e2f63fa --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/RSABlindingFactorGenerator.cs @@ -0,0 +1,69 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * Generate a random factor suitable for use with RSA blind signatures + * as outlined in Chaum's blinding and unblinding as outlined in + * "Handbook of Applied Cryptography", page 475. + */ + public class RsaBlindingFactorGenerator + { + private RsaKeyParameters key; + private SecureRandom random; + + /** + * Initialise the factor generator + * + * @param param the necessary RSA key parameters. + */ + public void Init( + ICipherParameters param) + { + if (param is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + key = (RsaKeyParameters)rParam.Parameters; + random = rParam.Random; + } + else + { + key = (RsaKeyParameters)param; + random = new SecureRandom(); + } + + if (key.IsPrivate) + throw new ArgumentException("generator requires RSA public key"); + } + + /** + * Generate a suitable blind factor for the public key the generator was initialised with. + * + * @return a random blind factor + */ + public BigInteger GenerateBlindingFactor() + { + if (key == null) + throw new InvalidOperationException("generator not initialised"); + + BigInteger m = key.Modulus; + int length = m.BitLength - 1; // must be less than m.BitLength + BigInteger factor; + BigInteger gcd; + + do + { + factor = new BigInteger(length, random); + gcd = factor.Gcd(m); + } + while (factor.SignValue == 0 || factor.Equals(BigInteger.One) || !gcd.Equals(BigInteger.One)); + + return factor; + } + } +} diff --git a/iTechSharp/srcbc/crypto/generators/RsaKeyPairGenerator.cs b/iTechSharp/srcbc/crypto/generators/RsaKeyPairGenerator.cs new file mode 100644 index 0000000..3074aed --- /dev/null +++ b/iTechSharp/srcbc/crypto/generators/RsaKeyPairGenerator.cs @@ -0,0 +1,139 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * an RSA key pair generator. + */ + public class RsaKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001); + private const int DefaultTests = 12; + + private RsaKeyGenerationParameters param; + + public void Init( + KeyGenerationParameters parameters) + { + if (parameters is RsaKeyGenerationParameters) + { + this.param = (RsaKeyGenerationParameters)parameters; + } + else + { + this.param = new RsaKeyGenerationParameters( + DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests); + } + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + BigInteger p, q, n, d, e, pSub1, qSub1, phi; + + // + // p and q values should have a length of half the strength in bits + // + int strength = param.Strength; + int pbitlength = (strength + 1) / 2; + int qbitlength = (strength - pbitlength); + int mindiffbits = strength / 3; + + e = param.PublicExponent; + + // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes) + // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm") + + // + // Generate p, prime and (p-1) relatively prime to e + // + for (;;) + { + p = new BigInteger(pbitlength, 1, param.Random); + + if (p.Mod(e).Equals(BigInteger.One)) + continue; + + if (!p.IsProbablePrime(param.Certainty)) + continue; + + if (e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One)) + break; + } + + // + // Generate a modulus of the required length + // + for (;;) + { + // Generate q, prime and (q-1) relatively prime to e, + // and not equal to p + // + for (;;) + { + q = new BigInteger(qbitlength, 1, param.Random); + + if (q.Subtract(p).Abs().BitLength < mindiffbits) + continue; + + if (q.Mod(e).Equals(BigInteger.One)) + continue; + + if (!q.IsProbablePrime(param.Certainty)) + continue; + + if (e.Gcd(q.Subtract(BigInteger.One)).Equals(BigInteger.One)) + break; + } + + // + // calculate the modulus + // + n = p.Multiply(q); + + if (n.BitLength == param.Strength) + break; + + // + // if we Get here our primes aren't big enough, make the largest + // of the two p and try again + // + p = p.Max(q); + } + + if (p.CompareTo(q) < 0) + { + phi = p; + p = q; + q = phi; + } + + pSub1 = p.Subtract(BigInteger.One); + qSub1 = q.Subtract(BigInteger.One); + phi = pSub1.Multiply(qSub1); + + // + // calculate the private exponent + // + d = e.ModInverse(phi); + + // + // calculate the CRT factors + // + BigInteger dP, dQ, qInv; + + dP = d.Remainder(pSub1); + dQ = d.Remainder(qSub1); + qInv = q.ModInverse(p); + + return new AsymmetricCipherKeyPair( + new RsaKeyParameters(false, n, e), + new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv)); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/io/CipherStream.cs b/iTechSharp/srcbc/crypto/io/CipherStream.cs new file mode 100644 index 0000000..459aa35 --- /dev/null +++ b/iTechSharp/srcbc/crypto/io/CipherStream.cs @@ -0,0 +1,224 @@ +using System; +using System.Diagnostics; +using System.IO; +using Org.BouncyCastle.Crypto; +namespace Org.BouncyCastle.Crypto.IO +{ + public class CipherStream : Stream + { + internal Stream stream; + internal IBufferedCipher inCipher, outCipher; + private byte[] mInBuf; + private int mInPos; + private bool inStreamEnded; + + public CipherStream( + Stream stream, + IBufferedCipher readCipher, + IBufferedCipher writeCipher) + { + this.stream = stream; + + if (readCipher != null) + { + this.inCipher = readCipher; + mInBuf = null; + } + + if (writeCipher != null) + { + this.outCipher = writeCipher; + } + } + + public IBufferedCipher ReadCipher + { + get { return inCipher; } + } + + public IBufferedCipher WriteCipher + { + get { return outCipher; } + } + + public override int ReadByte() + { + if (inCipher == null) + { + return stream.ReadByte(); + } + + if (mInBuf == null || mInPos >= mInBuf.Length) + { + if (!FillInBuf()) + { + return -1; + } + } + + return mInBuf[mInPos++]; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (inCipher == null) + { + return stream.Read(buffer, offset, count); + } + +// int pos = offset; +// int end = offset + count; +// try +// { +// while (pos < end) +// { +// if (mInPos >= mInBufEnd && !FillInBuf()) break; +// +// int len = System.Math.Min(end - pos, mInBufEnd - mInPos); +// Array.Copy(mInBuf, mInPos, buffer, pos, len); +// mInPos += len; +// pos += len; +// } +// } +// catch (IOException) +// { +// if (pos == offset) throw; +// } +// return pos - offset; + + // TODO Optimise + int i = 0; + while (i < count) + { + int c = ReadByte(); + + if (c < 0) break; + + buffer[offset + i++] = (byte) c; + } + + return i; + } + private bool FillInBuf() + { + if (inStreamEnded) + { + return false; + } + + mInPos = 0; + + do + { + mInBuf = readAndProcessBlock(); + } + while (!inStreamEnded && mInBuf == null); + + return mInBuf != null; + } + private byte[] readAndProcessBlock() + { + int blockSize = inCipher.GetBlockSize(); + int readSize = (blockSize == 0) ? 256 : blockSize; + + byte[] block = new byte[readSize]; + int numRead = 0; + do + { + int count = stream.Read(block, numRead, block.Length - numRead); + if (count < 1) + { + inStreamEnded = true; + break; + } + numRead += count; + } + while (numRead < block.Length); + + Debug.Assert(inStreamEnded || numRead == block.Length); + + byte[] bytes = inStreamEnded + ? inCipher.DoFinal(block, 0, numRead) + : inCipher.ProcessBytes(block); + + if (bytes != null && bytes.Length == 0) + { + bytes = null; + } + + return bytes; + } + public override void Write(byte[] buffer, int offset, int count) + { + Debug.Assert(buffer != null); + Debug.Assert(0 <= offset && offset <= buffer.Length); + Debug.Assert(count >= 0); + + int end = offset + count; + + Debug.Assert(0 <= end && end <= buffer.Length); + + if (outCipher == null) + { + stream.Write(buffer, offset, count); + return; + } + + byte[] data = outCipher.ProcessBytes(buffer, offset, count); + if (data != null) + { + stream.Write(data, 0, data.Length); + } + } + public override void WriteByte( + byte value) + { + if (outCipher == null) + { + stream.WriteByte(value); + return; + } + + byte[] data = outCipher.ProcessByte(value); + if (data != null) + { + stream.Write(data, 0, data.Length); + } + } + public override bool CanRead + { + get { return stream.CanRead && (inCipher != null); } + } + public override bool CanWrite + { + get { return stream.CanWrite && (outCipher != null); } + } + public override bool CanSeek + { + get { return false; } + } + public sealed override long Length { get { throw new NotSupportedException(); } } + public sealed override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + public override void Close() + { + if (outCipher != null) + { + byte[] data = outCipher.DoFinal(); + stream.Write(data, 0, data.Length); + stream.Flush(); + } + stream.Close(); + } + public override void Flush() + { + // Note: outCipher.DoFinal is only called during Close() + stream.Flush(); + } + public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + public sealed override void SetLength(long value) { throw new NotSupportedException(); } + } +} diff --git a/iTechSharp/srcbc/crypto/io/DigestStream.cs b/iTechSharp/srcbc/crypto/io/DigestStream.cs new file mode 100644 index 0000000..04409c4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/io/DigestStream.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; +using Org.BouncyCastle.Crypto; +namespace Org.BouncyCastle.Crypto.IO +{ + public class DigestStream : Stream + { + internal Stream stream; + internal IDigest inDigest; + internal IDigest outDigest; + + public DigestStream( + Stream stream, + IDigest readDigest, + IDigest writeDigest) + { + this.stream = stream; + this.inDigest = readDigest; + this.outDigest = writeDigest; + } + public IDigest ReadDigest() + { + return inDigest; + } + public IDigest WriteDigest() + { + return outDigest; + } + public override int ReadByte() + { + int b = stream.ReadByte(); + if (inDigest != null) + { + if (b >= 0) + { + inDigest.Update((byte)b); + } + } + return b; + } + + public override int Read(byte[] buffer, int offset, int count) + { + int n = stream.Read(buffer, offset, count); + if (inDigest != null) + { + if (n > 0) + { + inDigest.BlockUpdate(buffer, offset, n); + } + } + return n; + } + public override void Write( + byte[] buffer, + int offset, + int count) + { + if (outDigest != null) + { + if (count > 0) + { + outDigest.BlockUpdate(buffer, offset, count); + } + } + stream.Write(buffer, offset, count); + } + public override void WriteByte(byte value) + { + if (outDigest != null) + { + outDigest.Update(value); + } + stream.WriteByte(value); + } + public override bool CanRead + { + get { return stream.CanRead && (inDigest != null); } + } + public override bool CanWrite + { + get { return stream.CanWrite && (outDigest != null); } + } + public override bool CanSeek + { + get { return stream.CanSeek; } + } + public override long Length + { + get { return stream.Length; } + } + public override long Position + { + get { return stream.Position; } + set { stream.Position = value; } + } + public override void Close() + { + stream.Close(); + } + public override void Flush() + { + stream.Flush(); + } + public override long Seek( + long offset, + SeekOrigin origin) + { + return stream.Seek(offset,origin); + } + public override void SetLength(long value) + { + stream.SetLength(value); + } + } +} diff --git a/iTechSharp/srcbc/crypto/io/MacStream.cs b/iTechSharp/srcbc/crypto/io/MacStream.cs new file mode 100644 index 0000000..622e528 --- /dev/null +++ b/iTechSharp/srcbc/crypto/io/MacStream.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; +using Org.BouncyCastle.Crypto; +namespace Org.BouncyCastle.Crypto.IO +{ + public class MacStream : Stream + { + internal Stream stream; + internal IMac inMac; + internal IMac outMac; + + public MacStream( + Stream stream, + IMac readMac, + IMac writeMac) + { + this.stream = stream; + this.inMac = readMac; + this.outMac = writeMac; + } + public IMac ReadMac() + { + return inMac; + } + public IMac WriteMac() + { + return outMac; + } + public override int ReadByte() + { + int b = stream.ReadByte(); + if (inMac != null) + { + if (b >= 0) + { + inMac.Update((byte)b); + } + } + return b; + } + + public override int Read(byte[] buffer, int offset, int count) + { + int n = stream.Read(buffer, offset, count); + if (inMac != null) + { + if (n > 0) + { + inMac.BlockUpdate(buffer, offset, count); + } + } + return n; + } + public override void Write( + byte[] buffer, + int offset, + int count) + { + if (outMac != null) + { + if (count > 0) + { + outMac.BlockUpdate(buffer, offset, count); + } + } + stream.Write(buffer, offset, count); + } + public override void WriteByte(byte value) + { + if (outMac != null) + { + outMac.Update(value); + } + stream.WriteByte(value); + } + public override bool CanRead + { + get { return stream.CanRead && (inMac != null); } + } + public override bool CanWrite + { + get { return stream.CanWrite && (outMac != null); } + } + public override bool CanSeek + { + get { return stream.CanSeek; } + } + public override long Length + { + get { return stream.Length; } + } + public override long Position + { + get { return stream.Position; } + set { stream.Position = value; } + } + public override void Close() + { + stream.Close(); + } + public override void Flush() + { + stream.Flush(); + } + public override long Seek( + long offset, + SeekOrigin origin) + { + return stream.Seek(offset,origin); + } + public override void SetLength(long value) + { + stream.SetLength(value); + } + } +} diff --git a/iTechSharp/srcbc/crypto/macs/CMac.cs b/iTechSharp/srcbc/crypto/macs/CMac.cs new file mode 100644 index 0000000..ea1ce88 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/CMac.cs @@ -0,0 +1,240 @@ +using System; + +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html + *

      + * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC + *

      + * CMAC is a NIST recomendation - see + * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf + *

      + * CMAC/OMAC1 is a blockcipher-based message authentication code designed and + * analyzed by Tetsu Iwata and Kaoru Kurosawa. + *

      + * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message + * Authentication Code). OMAC stands for One-Key CBC MAC. + *

      + * It supports 128- or 64-bits block ciphers, with any key size, and returns + * a MAC with dimension less or equal to the block size of the underlying + * cipher. + *

      + */ + public class CMac + : IMac + { + private const byte CONSTANT_128 = (byte)0x87; + private const byte CONSTANT_64 = (byte)0x1b; + + private byte[] ZEROES; + + private byte[] mac; + + private byte[] buf; + private int bufOff; + private IBlockCipher cipher; + + private int macSize; + + private byte[] L, Lu, Lu2; + + /** + * create a standard MAC based on a CBC block cipher (64 or 128 bit block). + * This will produce an authentication code the length of the block size + * of the cipher. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + */ + public CMac( + IBlockCipher cipher) + : this(cipher, cipher.GetBlockSize() * 8) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + * + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8 and @lt;= 128. + */ + public CMac( + IBlockCipher cipher, + int macSizeInBits) + { + if ((macSizeInBits % 8) != 0) + throw new ArgumentException("MAC size must be multiple of 8"); + + if (macSizeInBits > (cipher.GetBlockSize() * 8)) + { + throw new ArgumentException( + "MAC size must be less or equal to " + + (cipher.GetBlockSize() * 8)); + } + + if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16) + { + throw new ArgumentException( + "Block size must be either 64 or 128 bits"); + } + + this.cipher = new CbcBlockCipher(cipher); + this.macSize = macSizeInBits / 8; + + mac = new byte[cipher.GetBlockSize()]; + + buf = new byte[cipher.GetBlockSize()]; + + ZEROES = new byte[cipher.GetBlockSize()]; + + bufOff = 0; + } + + public string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + private byte[] doubleLu( + byte[] inBytes) + { + int FirstBit = (inBytes[0] & 0xFF) >> 7; + byte[] ret = new byte[inBytes.Length]; + for (int i = 0; i < inBytes.Length - 1; i++) + { + ret[i] = (byte)((inBytes[i] << 1) + ((inBytes[i + 1] & 0xFF) >> 7)); + } + ret[inBytes.Length - 1] = (byte)(inBytes[inBytes.Length - 1] << 1); + if (FirstBit == 1) + { + ret[inBytes.Length - 1] ^= inBytes.Length == 16 ? CONSTANT_128 : CONSTANT_64; + } + return ret; + } + + public void Init( + ICipherParameters parameters) + { + Reset(); + + cipher.Init(true, parameters); + + //initializes the L, Lu, Lu2 numbers + L = new byte[ZEROES.Length]; + cipher.ProcessBlock(ZEROES, 0, L, 0); + Lu = doubleLu(L); + Lu2 = doubleLu(Lu); + + cipher.Init(true, parameters); + } + + public int GetMacSize() + { + return macSize; + } + + public void Update( + byte input) + { + if (bufOff == buf.Length) + { + cipher.ProcessBlock(buf, 0, mac, 0); + bufOff = 0; + } + + buf[bufOff++] = input; + } + + public void BlockUpdate( + byte[] inBytes, + int inOff, + int len) + { + if (len < 0) + throw new ArgumentException("Can't have a negative input length!"); + + int blockSize = cipher.GetBlockSize(); + int gapLen = blockSize - bufOff; + + if (len > gapLen) + { + Array.Copy(inBytes, inOff, buf, bufOff, gapLen); + + cipher.ProcessBlock(buf, 0, mac, 0); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + cipher.ProcessBlock(inBytes, inOff, mac, 0); + + len -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(inBytes, inOff, buf, bufOff, len); + + bufOff += len; + } + + public int DoFinal( + byte[] outBytes, + int outOff) + { + int blockSize = cipher.GetBlockSize(); + + byte[] lu; + if (bufOff == blockSize) + { + lu = Lu; + } + else + { + new ISO7816d4Padding().AddPadding(buf, bufOff); + lu = Lu2; + } + + for (int i = 0; i < mac.Length; i++) + { + buf[i] ^= lu[i]; + } + + cipher.ProcessBlock(buf, 0, mac, 0); + + Array.Copy(mac, 0, outBytes, outOff, macSize); + + Reset(); + + return macSize; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + /* + * clean the buffer. + */ + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + /* + * Reset the underlying cipher. + */ + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/macs/CbcBlockCipherMac.cs b/iTechSharp/srcbc/crypto/macs/CbcBlockCipherMac.cs new file mode 100644 index 0000000..11ed834 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/CbcBlockCipherMac.cs @@ -0,0 +1,213 @@ +using System; + +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * standard CBC Block Cipher MAC - if no padding is specified the default of + * pad of zeroes is used. + */ + public class CbcBlockCipherMac + : IMac + { + private byte[] mac; + private byte[] Buffer; + private int bufOff; + private IBlockCipher cipher; + private IBlockCipherPadding padding; + private int macSize; + + /** + * create a standard MAC based on a CBC block cipher. This will produce an + * authentication code half the length of the block size of the cipher. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + */ + public CbcBlockCipherMac( + IBlockCipher cipher) + : this(cipher, (cipher.GetBlockSize() * 8) / 2, null) + { + } + + /** + * create a standard MAC based on a CBC block cipher. This will produce an + * authentication code half the length of the block size of the cipher. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param padding the padding to be used to complete the last block. + */ + public CbcBlockCipherMac( + IBlockCipher cipher, + IBlockCipherPadding padding) + : this(cipher, (cipher.GetBlockSize() * 8) / 2, padding) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. This class uses CBC mode as the basis for the + * MAC generation. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + *

      + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. + */ + public CbcBlockCipherMac( + IBlockCipher cipher, + int macSizeInBits) + : this(cipher, macSizeInBits, null) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. This class uses CBC mode as the basis for the + * MAC generation. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + *

      + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. + * @param padding the padding to be used to complete the last block. + */ + public CbcBlockCipherMac( + IBlockCipher cipher, + int macSizeInBits, + IBlockCipherPadding padding) + { + if ((macSizeInBits % 8) != 0) + throw new ArgumentException("MAC size must be multiple of 8"); + + this.cipher = new CbcBlockCipher(cipher); + this.padding = padding; + this.macSize = macSizeInBits / 8; + + mac = new byte[cipher.GetBlockSize()]; + + Buffer = new byte[cipher.GetBlockSize()]; + bufOff = 0; + } + + public string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + public void Init( + ICipherParameters parameters) + { + Reset(); + + cipher.Init(true, parameters); + } + + public int GetMacSize() + { + return macSize; + } + + public void Update( + byte input) + { + if (bufOff == Buffer.Length) + { + cipher.ProcessBlock(Buffer, 0, mac, 0); + bufOff = 0; + } + + Buffer[bufOff++] = input; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + if (len < 0) + throw new ArgumentException("Can't have a negative input length!"); + + int blockSize = cipher.GetBlockSize(); + int resultLen = 0; + int gapLen = blockSize - bufOff; + + if (len > gapLen) + { + Array.Copy(input, inOff, Buffer, bufOff, gapLen); + + resultLen += cipher.ProcessBlock(Buffer, 0, mac, 0); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + resultLen += cipher.ProcessBlock(input, inOff, mac, 0); + + len -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(input, inOff, Buffer, bufOff, len); + + bufOff += len; + } + + public int DoFinal( + byte[] output, + int outOff) + { + int blockSize = cipher.GetBlockSize(); + + if (padding == null) + { + // pad with zeroes + while (bufOff < blockSize) + { + Buffer[bufOff++] = 0; + } + } + else + { + if (bufOff == blockSize) + { + cipher.ProcessBlock(Buffer, 0, mac, 0); + bufOff = 0; + } + + padding.AddPadding(Buffer, bufOff); + } + + cipher.ProcessBlock(Buffer, 0, mac, 0); + + Array.Copy(mac, 0, output, outOff, macSize); + + Reset(); + + return macSize; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + // Clear the buffer. + Array.Clear(Buffer, 0, Buffer.Length); + bufOff = 0; + + // Reset the underlying cipher. + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/macs/CfbBlockCipherMac.cs b/iTechSharp/srcbc/crypto/macs/CfbBlockCipherMac.cs new file mode 100644 index 0000000..364cf84 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/CfbBlockCipherMac.cs @@ -0,0 +1,368 @@ +using System; + +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher. + */ + class MacCFBBlockCipher + : IBlockCipher + { + private byte[] IV; + private byte[] cfbV; + private byte[] cfbOutV; + + private readonly int blockSize; + private readonly IBlockCipher cipher; + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of the + * feedback mode. + * @param blockSize the block size in bits (note: a multiple of 8) + */ + public MacCFBBlockCipher( + IBlockCipher cipher, + int bitBlockSize) + { + this.cipher = cipher; + this.blockSize = bitBlockSize / 8; + + this.IV = new byte[cipher.GetBlockSize()]; + this.cfbV = new byte[cipher.GetBlockSize()]; + this.cfbOutV = new byte[cipher.GetBlockSize()]; + } + + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * An IV which is too short is handled in FIPS compliant fashion. + * + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV)parameters; + byte[] iv = ivParam.GetIV(); + + if (iv.Length < IV.Length) + { + Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length); + } + else + { + Array.Copy(iv, 0, IV, 0, IV.Length); + } + + parameters = ivParam.Parameters; + } + + Reset(); + + cipher.Init(true, parameters); + } + + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/CFB" + * and the block size in bits. + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + /** + * return the block size we are operating at. + * + * @return the block size we are operating at (in bytes). + */ + public int GetBlockSize() + { + return blockSize; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + throw new DataLengthException("input buffer too short"); + + if ((outOff + blockSize) > outBytes.Length) + throw new DataLengthException("output buffer too short"); + + cipher.ProcessBlock(cfbV, 0, cfbOutV, 0); + + // + // XOR the cfbV with the plaintext producing the cipher text + // + for (int i = 0; i < blockSize; i++) + { + outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]); + } + + // + // change over the input block. + // + Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize); + Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize); + + return blockSize; + } + + /** + * reset the chaining vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + IV.CopyTo(cfbV, 0); + + cipher.Reset(); + } + + public void GetMacBlock( + byte[] mac) + { + cipher.ProcessBlock(cfbV, 0, mac, 0); + } + } + + public class CfbBlockCipherMac + : IMac + { + private byte[] mac; + private byte[] Buffer; + private int bufOff; + private MacCFBBlockCipher cipher; + private IBlockCipherPadding padding; + private int macSize; + + /** + * create a standard MAC based on a CFB block cipher. This will produce an + * authentication code half the length of the block size of the cipher, with + * the CFB mode set to 8 bits. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + */ + public CfbBlockCipherMac( + IBlockCipher cipher) + : this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, null) + { + } + + /** + * create a standard MAC based on a CFB block cipher. This will produce an + * authentication code half the length of the block size of the cipher, with + * the CFB mode set to 8 bits. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param padding the padding to be used. + */ + public CfbBlockCipherMac( + IBlockCipher cipher, + IBlockCipherPadding padding) + : this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, padding) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. This class uses CFB mode as the basis for the + * MAC generation. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + *

      + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param cfbBitSize the size of an output block produced by the CFB mode. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. + */ + public CfbBlockCipherMac( + IBlockCipher cipher, + int cfbBitSize, + int macSizeInBits) + : this(cipher, cfbBitSize, macSizeInBits, null) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. This class uses CFB mode as the basis for the + * MAC generation. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + *

      + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param cfbBitSize the size of an output block produced by the CFB mode. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. + * @param padding a padding to be used. + */ + public CfbBlockCipherMac( + IBlockCipher cipher, + int cfbBitSize, + int macSizeInBits, + IBlockCipherPadding padding) + { + if ((macSizeInBits % 8) != 0) + throw new ArgumentException("MAC size must be multiple of 8"); + + mac = new byte[cipher.GetBlockSize()]; + + this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize); + this.padding = padding; + this.macSize = macSizeInBits / 8; + + Buffer = new byte[this.cipher.GetBlockSize()]; + bufOff = 0; + } + + public string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + public void Init( + ICipherParameters parameters) + { + Reset(); + + cipher.Init(true, parameters); + } + + public int GetMacSize() + { + return macSize; + } + + public void Update( + byte input) + { + if (bufOff == Buffer.Length) + { + cipher.ProcessBlock(Buffer, 0, mac, 0); + bufOff = 0; + } + + Buffer[bufOff++] = input; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + if (len < 0) + throw new ArgumentException("Can't have a negative input length!"); + + int blockSize = cipher.GetBlockSize(); + int resultLen = 0; + int gapLen = blockSize - bufOff; + + if (len > gapLen) + { + Array.Copy(input, inOff, Buffer, bufOff, gapLen); + + resultLen += cipher.ProcessBlock(Buffer, 0, mac, 0); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + resultLen += cipher.ProcessBlock(input, inOff, mac, 0); + + len -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(input, inOff, Buffer, bufOff, len); + + bufOff += len; + } + + public int DoFinal( + byte[] output, + int outOff) + { + int blockSize = cipher.GetBlockSize(); + + // pad with zeroes + if (this.padding == null) + { + while (bufOff < blockSize) + { + Buffer[bufOff++] = 0; + } + } + else + { + padding.AddPadding(Buffer, bufOff); + } + + cipher.ProcessBlock(Buffer, 0, mac, 0); + + cipher.GetMacBlock(mac); + + Array.Copy(mac, 0, output, outOff, macSize); + + Reset(); + + return macSize; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + // Clear the buffer. + Array.Clear(Buffer, 0, Buffer.Length); + bufOff = 0; + + // Reset the underlying cipher. + cipher.Reset(); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/macs/GOST28147Mac.cs b/iTechSharp/srcbc/crypto/macs/GOST28147Mac.cs new file mode 100644 index 0000000..9a8f1b7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/GOST28147Mac.cs @@ -0,0 +1,296 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * implementation of GOST 28147-89 MAC + */ + public class Gost28147Mac : IMac + { + private const int blockSize = 8; + private const int macSize = 4; + private int bufOff; + private byte[] buf; + private byte[] mac; + private bool firstStep = true; + private int[] workingKey; + + // + // This is default S-box - E_A. + private byte[] S = + { + 0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5, + 0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1, + 0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9, + 0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6, + 0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6, + 0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6, + 0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE, + 0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4 + }; + + public Gost28147Mac() + { + mac = new byte[blockSize]; + buf = new byte[blockSize]; + bufOff = 0; + } + + private static int[] generateWorkingKey( + byte[] userKey) + { + if (userKey.Length != 32) + throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!"); + + int[] key = new int[8]; + for(int i=0; i!=8; i++) + { + key[i] = bytesToint(userKey,i*4); + } + + return key; + } + + public void Init( + ICipherParameters parameters) + { + Reset(); + buf = new byte[blockSize]; + if (parameters is ParametersWithSBox) + { + ParametersWithSBox param = (ParametersWithSBox)parameters; + + // + // Set the S-Box + // + param.GetSBox().CopyTo(this.S, 0); + + // + // set key if there is one + // + if (param.Parameters != null) + { + workingKey = generateWorkingKey(((KeyParameter)param.Parameters).GetKey()); + } + } + else if (parameters is KeyParameter) + { + workingKey = generateWorkingKey(((KeyParameter)parameters).GetKey()); + } + else + { + throw new ArgumentException("invalid parameter passed to Gost28147 init - " + + parameters.GetType().Name); + } + } + + public string AlgorithmName + { + get { return "Gost28147Mac"; } + } + + public int GetMacSize() + { + return macSize; + } + + private int gost28147_mainStep(int n1, int key) + { + int cm = (key + n1); // CM1 + + // S-box replacing + + int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4); + om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4); + om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4); + om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4); + om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4); + om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4); + om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4); + om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4); + +// return om << 11 | om >>> (32-11); // 11-leftshift + int omLeft = om << 11; + int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation + + return omLeft | omRight; + } + + private void gost28147MacFunc( + int[] workingKey, + byte[] input, + int inOff, + byte[] output, + int outOff) + { + int N1, N2, tmp; //tmp -> for saving N1 + N1 = bytesToint(input, inOff); + N2 = bytesToint(input, inOff + 4); + + for (int k = 0; k < 2; k++) // 1-16 steps + { + for (int j = 0; j < 8; j++) + { + tmp = N1; + N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2 + N2 = tmp; + } + } + + intTobytes(N1, output, outOff); + intTobytes(N2, output, outOff + 4); + } + + //array of bytes to type int + private static int bytesToint( + byte[] input, + int inOff) + { + return (int)((input[inOff + 3] << 24) & 0xff000000) + ((input[inOff + 2] << 16) & 0xff0000) + + ((input[inOff + 1] << 8) & 0xff00) + (input[inOff] & 0xff); + } + + //int to array of bytes + private static void intTobytes( + int num, + byte[] output, + int outOff) + { + output[outOff + 3] = (byte)(num >> 24); + output[outOff + 2] = (byte)(num >> 16); + output[outOff + 1] = (byte)(num >> 8); + output[outOff] = (byte)num; + } + + private static byte[] CM5func( + byte[] buf, + int bufOff, + byte[] mac) + { + byte[] sum = new byte[buf.Length - bufOff]; + + Array.Copy(buf, bufOff, sum, 0, mac.Length); + + for (int i = 0; i != mac.Length; i++) + { + sum[i] = (byte)(sum[i] ^ mac[i]); + } + + return sum; + } + + public void Update( + byte input) + { + if (bufOff == buf.Length) + { + byte[] sumbuf = new byte[buf.Length]; + Array.Copy(buf, 0, sumbuf, 0, mac.Length); + + if (firstStep) + { + firstStep = false; + } + else + { + sumbuf = CM5func(buf, 0, mac); + } + + gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + bufOff = 0; + } + + buf[bufOff++] = input; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + if (len < 0) + throw new ArgumentException("Can't have a negative input length!"); + + int gapLen = blockSize - bufOff; + + if (len > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + + byte[] sumbuf = new byte[buf.Length]; + Array.Copy(buf, 0, sumbuf, 0, mac.Length); + + if (firstStep) + { + firstStep = false; + } + else + { + sumbuf = CM5func(buf, 0, mac); + } + + gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + sumbuf = CM5func(input, inOff, mac); + gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + + len -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(input, inOff, buf, bufOff, len); + + bufOff += len; + } + + public int DoFinal( + byte[] output, + int outOff) + { + //padding with zero + while (bufOff < blockSize) + { + buf[bufOff++] = 0; + } + + byte[] sumbuf = new byte[buf.Length]; + Array.Copy(buf, 0, sumbuf, 0, mac.Length); + + if (firstStep) + { + firstStep = false; + } + else + { + sumbuf = CM5func(buf, 0, mac); + } + + gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + + Array.Copy(mac, (mac.Length/2)-macSize, output, outOff, macSize); + + Reset(); + + return macSize; + } + + public void Reset() + { + // Clear the buffer. + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + firstStep = true; + } + } +} diff --git a/iTechSharp/srcbc/crypto/macs/HMac.cs b/iTechSharp/srcbc/crypto/macs/HMac.cs new file mode 100644 index 0000000..e1a5628 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/HMac.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * HMAC implementation based on RFC2104 + * + * H(K XOR opad, H(K XOR ipad, text)) + */ + public class HMac : IMac + { + private const byte IPAD = (byte)0x36; + private const byte OPAD = (byte)0x5C; + + private readonly IDigest digest; + private readonly int digestSize; + private readonly int blockLength; + + private byte[] inputPad; + private byte[] outputPad; + + public HMac( + IDigest digest) + { + this.digest = digest; + digestSize = digest.GetDigestSize(); + + blockLength = digest.GetByteLength(); + + inputPad = new byte[blockLength]; + outputPad = new byte[blockLength]; + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "/HMAC"; } + } + + public IDigest GetUnderlyingDigest() + { + return digest; + } + + public void Init( + ICipherParameters parameters) + { + digest.Reset(); + + byte[] key = ((KeyParameter)parameters).GetKey(); + + if (key.Length > blockLength) + { + digest.BlockUpdate(key, 0, key.Length); + digest.DoFinal(inputPad, 0); + for (int i = digestSize; i < inputPad.Length; i++) + { + inputPad[i] = 0; + } + } + else + { + Array.Copy(key, 0, inputPad, 0, key.Length); + for (int i = key.Length; i < inputPad.Length; i++) + { + inputPad[i] = 0; + } + } + + outputPad = new byte[inputPad.Length]; + Array.Copy(inputPad, 0, outputPad, 0, inputPad.Length); + + for (int i = 0; i < inputPad.Length; i++) + { + inputPad[i] ^= IPAD; + } + + for (int i = 0; i < outputPad.Length; i++) + { + outputPad[i] ^= OPAD; + } + + digest.BlockUpdate(inputPad, 0, inputPad.Length); + } + + public int GetMacSize() + { + return digestSize; + } + + public void Update( + byte input) + { + digest.Update(input); + } + + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + digest.BlockUpdate(input, inOff, len); + } + + public int DoFinal( + byte[] output, + int outOff) + { + byte[] tmp = new byte[digestSize]; + digest.DoFinal(tmp, 0); + + digest.BlockUpdate(outputPad, 0, outputPad.Length); + digest.BlockUpdate(tmp, 0, tmp.Length); + + int len = digest.DoFinal(output, outOff); + + Reset(); + + return len; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + /* + * reset the underlying digest. + */ + digest.Reset(); + + /* + * reinitialize the digest. + */ + digest.BlockUpdate(inputPad, 0, inputPad.Length); + } + } +} diff --git a/iTechSharp/srcbc/crypto/macs/ISO9797Alg3Mac.cs b/iTechSharp/srcbc/crypto/macs/ISO9797Alg3Mac.cs new file mode 100644 index 0000000..40e67b5 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/ISO9797Alg3Mac.cs @@ -0,0 +1,259 @@ +using System; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Macs +{ + /** + * DES based CBC Block Cipher MAC according to ISO9797, algorithm 3 (ANSI X9.19 Retail MAC) + * + * This could as well be derived from CBCBlockCipherMac, but then the property mac in the base + * class must be changed to protected + */ + public class ISO9797Alg3Mac : IMac + { + private byte[] mac; + private byte[] buf; + private int bufOff; + private IBlockCipher cipher; + private IBlockCipherPadding padding; + private int macSize; + private KeyParameter lastKey2; + private KeyParameter lastKey3; + + /** + * create a Retail-MAC based on a CBC block cipher. This will produce an + * authentication code of the length of the block size of the cipher. + * + * @param cipher the cipher to be used as the basis of the MAC generation. This must + * be DESEngine. + */ + public ISO9797Alg3Mac( + IBlockCipher cipher) + : this(cipher, cipher.GetBlockSize() * 8, null) + { + } + + /** + * create a Retail-MAC based on a CBC block cipher. This will produce an + * authentication code of the length of the block size of the cipher. + * + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param padding the padding to be used to complete the last block. + */ + public ISO9797Alg3Mac( + IBlockCipher cipher, + IBlockCipherPadding padding) + : this(cipher, cipher.GetBlockSize() * 8, padding) + { + } + + /** + * create a Retail-MAC based on a block cipher with the size of the + * MAC been given in bits. This class uses single DES CBC mode as the basis for the + * MAC generation. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + *

      + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. + */ + public ISO9797Alg3Mac( + IBlockCipher cipher, + int macSizeInBits) + : this(cipher, macSizeInBits, null) + { + } + + /** + * create a standard MAC based on a block cipher with the size of the + * MAC been given in bits. This class uses single DES CBC mode as the basis for the + * MAC generation. The final block is decrypted and then encrypted using the + * middle and right part of the key. + *

      + * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81), + * or 16 bits if being used as a data authenticator (FIPS Publication 113), + * and in general should be less than the size of the block cipher as it reduces + * the chance of an exhaustive attack (see Handbook of Applied Cryptography). + *

      + * @param cipher the cipher to be used as the basis of the MAC generation. + * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8. + * @param padding the padding to be used to complete the last block. + */ + public ISO9797Alg3Mac( + IBlockCipher cipher, + int macSizeInBits, + IBlockCipherPadding padding) + { + if ((macSizeInBits % 8) != 0) + throw new ArgumentException("MAC size must be multiple of 8"); + + if (!(cipher is DesEngine)) + throw new ArgumentException("cipher must be instance of DesEngine"); + + this.cipher = new CbcBlockCipher(cipher); + this.padding = padding; + this.macSize = macSizeInBits / 8; + + mac = new byte[cipher.GetBlockSize()]; + buf = new byte[cipher.GetBlockSize()]; + bufOff = 0; + } + + public string AlgorithmName + { + get { return "ISO9797Alg3"; } + } + + public void Init( + ICipherParameters parameters) + { + Reset(); + + if (!(parameters is KeyParameter)) + throw new ArgumentException("parameters must be an instance of KeyParameter"); + + // KeyParameter must contain a double or triple length DES key, + // however the underlying cipher is a single DES. The middle and + // right key are used only in the final step. + + KeyParameter kp = (KeyParameter)parameters; + KeyParameter key1; + byte[] keyvalue = kp.GetKey(); + + if (keyvalue.Length == 16) + { // Double length DES key + key1 = new KeyParameter(keyvalue, 0, 8); + this.lastKey2 = new KeyParameter(keyvalue, 8, 8); + this.lastKey3 = key1; + } + else if (keyvalue.Length == 24) + { // Triple length DES key + key1 = new KeyParameter(keyvalue, 0, 8); + this.lastKey2 = new KeyParameter(keyvalue, 8, 8); + this.lastKey3 = new KeyParameter(keyvalue, 16, 8); + } + else + { + throw new ArgumentException("Key must be either 112 or 168 bit long"); + } + + cipher.Init(true, key1); + } + + public int GetMacSize() + { + return macSize; + } + + public void Update( + byte input) + { + if (bufOff == buf.Length) + { + cipher.ProcessBlock(buf, 0, mac, 0); + bufOff = 0; + } + + buf[bufOff++] = input; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + if (len < 0) + throw new ArgumentException("Can't have a negative input length!"); + + int blockSize = cipher.GetBlockSize(); + int resultLen = 0; + int gapLen = blockSize - bufOff; + + if (len > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + + resultLen += cipher.ProcessBlock(buf, 0, mac, 0); + + bufOff = 0; + len -= gapLen; + inOff += gapLen; + + while (len > blockSize) + { + resultLen += cipher.ProcessBlock(input, inOff, mac, 0); + + len -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(input, inOff, buf, bufOff, len); + + bufOff += len; + } + + public int DoFinal( + byte[] output, + int outOff) + { + int blockSize = cipher.GetBlockSize(); + + if (padding == null) + { + // pad with zeroes + while (bufOff < blockSize) + { + buf[bufOff++] = 0; + } + } + else + { + if (bufOff == blockSize) + { + cipher.ProcessBlock(buf, 0, mac, 0); + bufOff = 0; + } + + padding.AddPadding(buf, bufOff); + } + + cipher.ProcessBlock(buf, 0, mac, 0); + + // Added to code from base class + DesEngine deseng = new DesEngine(); + + deseng.Init(false, this.lastKey2); + deseng.ProcessBlock(mac, 0, mac, 0); + + deseng.Init(true, this.lastKey3); + deseng.ProcessBlock(mac, 0, mac, 0); + // **** + + Array.Copy(mac, 0, output, outOff, macSize); + + Reset(); + + return macSize; + } + + /** + * Reset the mac generator. + */ + public void Reset() + { + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + // reset the underlying cipher. + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/macs/VMPCMac.cs b/iTechSharp/srcbc/crypto/macs/VMPCMac.cs new file mode 100644 index 0000000..8991635 --- /dev/null +++ b/iTechSharp/srcbc/crypto/macs/VMPCMac.cs @@ -0,0 +1,173 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Macs +{ + public class VmpcMac + : IMac + { + private byte g; + + private byte n = 0; + private byte[] P = null; + private byte s = 0; + + private byte[] T; + private byte[] workingIV; + + private byte[] workingKey; + + private byte x1, x2, x3, x4; + + public virtual int DoFinal(byte[] output, int outOff) + { + // Execute the Post-Processing Phase + for (int r = 1; r < 25; r++) + { + s = P[(s + P[n & 0xff]) & 0xff]; + + x4 = P[(x4 + x3 + r) & 0xff]; + x3 = P[(x3 + x2 + r) & 0xff]; + x2 = P[(x2 + x1 + r) & 0xff]; + x1 = P[(x1 + s + r) & 0xff]; + T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1); + T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2); + T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3); + T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4); + g = (byte) ((g + 4) & 0x1f); + + byte temp = P[n & 0xff]; + P[n & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + n = (byte) ((n + 1) & 0xff); + } + + // Input T to the IV-phase of the VMPC KSA + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + + // Store 20 new outputs of the VMPC Stream Cipher input table M + byte[] M = new byte[20]; + for (int i = 0; i < 20; i++) + { + s = P[(s + P[i & 0xff]) & 0xff]; + M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]; + + byte temp = P[i & 0xff]; + P[i & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + + Array.Copy(M, 0, output, outOff, M.Length); + Reset(); + + return M.Length; + } + + public virtual string AlgorithmName + { + get { return "VMPC-MAC"; } + } + + public virtual int GetMacSize() + { + return 20; + } + + public virtual void Init(ICipherParameters parameters) + { + if (!(parameters is ParametersWithIV)) + throw new ArgumentException("VMPC-MAC Init parameters must include an IV", "parameters"); + + ParametersWithIV ivParams = (ParametersWithIV) parameters; + KeyParameter key = (KeyParameter) ivParams.Parameters; + + if (!(ivParams.Parameters is KeyParameter)) + throw new ArgumentException("VMPC-MAC Init parameters must include a key", "parameters"); + + this.workingIV = ivParams.GetIV(); + + if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768) + throw new ArgumentException("VMPC-MAC requires 1 to 768 bytes of IV", "parameters"); + + this.workingKey = key.GetKey(); + + Reset(); + + } + + private void initKey(byte[] keyBytes, byte[] ivBytes) + { + s = 0; + P = new byte[256]; + for (int i = 0; i < 256; i++) + { + P[i] = (byte) i; + } + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + for (int m = 0; m < 768; m++) + { + s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff]; + byte temp = P[m & 0xff]; + P[m & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + } + n = 0; + } + + public virtual void Reset() + { + initKey(this.workingKey, this.workingIV); + g = x1 = x2 = x3 = x4 = n = 0; + T = new byte[32]; + for (int i = 0; i < 32; i++) + { + T[i] = 0; + } + } + + public virtual void Update(byte input) + { + s = P[(s + P[n & 0xff]) & 0xff]; + byte c = (byte) (input ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]); + + x4 = P[(x4 + x3) & 0xff]; + x3 = P[(x3 + x2) & 0xff]; + x2 = P[(x2 + x1) & 0xff]; + x1 = P[(x1 + s + c) & 0xff]; + T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1); + T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2); + T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3); + T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4); + g = (byte) ((g + 4) & 0x1f); + + byte temp = P[n & 0xff]; + P[n & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + n = (byte) ((n + 1) & 0xff); + } + + public virtual void BlockUpdate(byte[] input, int inOff, int len) + { + if ((inOff + len) > input.Length) + throw new DataLengthException("input buffer too short"); + + for (int i = 0; i < len; i++) + { + Update(input[i]); + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/CbcBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/CbcBlockCipher.cs new file mode 100644 index 0000000..c183025 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/CbcBlockCipher.cs @@ -0,0 +1,230 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher. + */ + public class CbcBlockCipher + : IBlockCipher + { + private byte[] IV, cbcV, cbcNextV; + private int blockSize; + private IBlockCipher cipher; + private bool encrypting; + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of chaining. + */ + public CbcBlockCipher( + IBlockCipher cipher) + { + this.cipher = cipher; + this.blockSize = cipher.GetBlockSize(); + + this.IV = new byte[blockSize]; + this.cbcV = new byte[blockSize]; + this.cbcNextV = new byte[blockSize]; + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.encrypting = forEncryption; + + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV)parameters; + byte[] iv = ivParam.GetIV(); + + if (iv.Length != blockSize) + { + throw new ArgumentException("initialisation vector must be the same length as block size"); + } + + Array.Copy(iv, 0, IV, 0, iv.Length); + + parameters = ivParam.Parameters; + } + + Reset(); + + cipher.Init(encrypting, parameters); + } + + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/CBC". + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/CBC"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + /** + * return the block size of the underlying cipher. + * + * @return the block size of the underlying cipher. + */ + public int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + return (encrypting) + ? EncryptBlock(input, inOff, output, outOff) + : DecryptBlock(input, inOff, output, outOff); + } + + /** + * reset the chaining vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + Array.Copy(IV, 0, cbcV, 0, IV.Length); + + cipher.Reset(); + } + + /** + * Do the appropriate chaining step for CBC mode encryption. + * + * @param in the array containing the data to be encrypted. + * @param inOff offset into the in array the data starts at. + * @param out the array the encrypted data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + private int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + /* + * XOR the cbcV and the input, + * then encrypt the cbcV + */ + for (int i = 0; i < blockSize; i++) + { + cbcV[i] ^= input[inOff + i]; + } + + int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff); + + /* + * copy ciphertext to cbcV + */ + Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length); + + return length; + } + + /** + * Do the appropriate chaining step for CBC mode decryption. + * + * @param in the array containing the data to be decrypted. + * @param inOff offset into the in array the data starts at. + * @param out the array the decrypted data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + private int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + Array.Copy(input, inOff, cbcNextV, 0, blockSize); + + int length = cipher.ProcessBlock(input, inOff, outBytes, outOff); + + /* + * XOR the cbcV and the output + */ + for (int i = 0; i < blockSize; i++) + { + outBytes[outOff + i] ^= cbcV[i]; + } + + /* + * swap the back up buffer into next position + */ + byte[] tmp; + + tmp = cbcV; + cbcV = cbcNextV; + cbcNextV = tmp; + + return length; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/modes/CcmBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/CcmBlockCipher.cs new file mode 100644 index 0000000..21b049f --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/CcmBlockCipher.cs @@ -0,0 +1,345 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in + * NIST Special Publication 800-38C. + *

      + * Note: this mode is a packet mode - it needs all the data up front. + *

      + */ + public class CcmBlockCipher + : IAeadBlockCipher + { + private static readonly int BlockSize = 16; + + private readonly IBlockCipher cipher; + private readonly byte[] macBlock; + private bool forEncryption; + private byte[] nonce; + private byte[] associatedText; + private int macSize; + private ICipherParameters keyParam; + private readonly MemoryStream data = new MemoryStream(); + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used. + */ + public CcmBlockCipher( + IBlockCipher cipher) + { + this.cipher = cipher; + this.macBlock = new byte[BlockSize]; + + if (cipher.GetBlockSize() != BlockSize) + throw new ArgumentException("cipher required with a block size of " + BlockSize + "."); + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public virtual IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + + public virtual void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + if (parameters is AeadParameters) + { + AeadParameters param = (AeadParameters) parameters; + + nonce = param.GetNonce(); + associatedText = param.GetAssociatedText(); + macSize = param.MacSize / 8; + keyParam = param.Key; + } + else if (parameters is ParametersWithIV) + { + ParametersWithIV param = (ParametersWithIV) parameters; + + nonce = param.GetIV(); + associatedText = null; + macSize = macBlock.Length / 2; + keyParam = param.Parameters; + } + else + { + throw new ArgumentException("invalid parameters passed to CCM"); + } + } + + public virtual string AlgorithmName + { + get { return cipher.AlgorithmName + "/CCM"; } + } + + public virtual int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + public virtual int ProcessByte( + byte input, + byte[] outBytes, + int outOff) + { + data.WriteByte(input); + + return 0; + } + + public virtual int ProcessBytes( + byte[] inBytes, + int inOff, + int inLen, + byte[] outBytes, + int outOff) + { + data.Write(inBytes, inOff, inLen); + + return 0; + } + + public virtual int DoFinal( + byte[] outBytes, + int outOff) + { + byte[] text = data.ToArray(); + byte[] enc = ProcessPacket(text, 0, text.Length); + + Array.Copy(enc, 0, outBytes, outOff, enc.Length); + + Reset(); + + return enc.Length; + } + + public virtual void Reset() + { + cipher.Reset(); + data.SetLength(0); + } + + /** + * Returns a byte array containing the mac calculated as part of the + * last encrypt or decrypt operation. + * + * @return the last mac calculated. + */ + public virtual byte[] GetMac() + { + byte[] mac = new byte[macSize]; + + Array.Copy(macBlock, 0, mac, 0, mac.Length); + + return mac; + } + + public virtual int GetUpdateOutputSize( + int len) + { + return 0; + } + + public int GetOutputSize( + int len) + { + if (forEncryption) + { + return (int) data.Length + len + macSize; + } + + return (int) data.Length + len - macSize; + } + + public byte[] ProcessPacket( + byte[] input, + int inOff, + int inLen) + { + if (keyParam == null) + throw new InvalidOperationException("CCM cipher unitialized."); + + IBlockCipher ctrCipher = new SicBlockCipher(cipher); + byte[] iv = new byte[BlockSize]; + byte[] output; + + iv[0] = (byte)(((15 - nonce.Length) - 1) & 0x7); + + Array.Copy(nonce, 0, iv, 1, nonce.Length); + + ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv)); + + if (forEncryption) + { + int index = inOff; + int outOff = 0; + + output = new byte[inLen + macSize]; + + calculateMac(input, inOff, inLen, macBlock); + + ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0); // S0 + + while (index < inLen - BlockSize) // S1... + { + ctrCipher.ProcessBlock(input, index, output, outOff); + outOff += BlockSize; + index += BlockSize; + } + + byte[] block = new byte[BlockSize]; + + Array.Copy(input, index, block, 0, inLen - index); + + ctrCipher.ProcessBlock(block, 0, block, 0); + + Array.Copy(block, 0, output, outOff, inLen - index); + + outOff += inLen - index; + + Array.Copy(macBlock, 0, output, outOff, output.Length - outOff); + } + else + { + int index = inOff; + int outOff = 0; + + output = new byte[inLen - macSize]; + + Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize); + + ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0); + + for (int i = macSize; i != macBlock.Length; i++) + { + macBlock[i] = 0; + } + + while (outOff < output.Length - BlockSize) + { + ctrCipher.ProcessBlock(input, index, output, outOff); + outOff += BlockSize; + index += BlockSize; + } + + byte[] block = new byte[BlockSize]; + + Array.Copy(input, index, block, 0, output.Length - outOff); + + ctrCipher.ProcessBlock(block, 0, block, 0); + + Array.Copy(block, 0, output, outOff, output.Length - outOff); + + byte[] calculatedMacBlock = new byte[BlockSize]; + + calculateMac(output, 0, output.Length, calculatedMacBlock); + + if (!Arrays.AreEqual(macBlock, calculatedMacBlock)) + throw new InvalidCipherTextException("mac check in CCM failed"); + } + + return output; + } + + private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock) + { + IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8); + + cMac.Init(keyParam); + + // + // build b0 + // + byte[] b0 = new byte[16]; + + if (hasAssociatedText()) + { + b0[0] |= 0x40; + } + + b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3); + + b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7); + + Array.Copy(nonce, 0, b0, 1, nonce.Length); + + int q = dataLen; + int count = 1; + while (q > 0) + { + b0[b0.Length - count] = (byte)(q & 0xff); + q >>= 8; + count++; + } + + cMac.BlockUpdate(b0, 0, b0.Length); + + // + // process associated text + // + if (hasAssociatedText()) + { + int extra; + + if (associatedText.Length < ((1 << 16) - (1 << 8))) + { + cMac.Update((byte)(associatedText.Length >> 8)); + cMac.Update((byte)associatedText.Length); + + extra = 2; + } + else // can't go any higher than 2^32 + { + cMac.Update((byte)0xff); + cMac.Update((byte)0xfe); + cMac.Update((byte)(associatedText.Length >> 24)); + cMac.Update((byte)(associatedText.Length >> 16)); + cMac.Update((byte)(associatedText.Length >> 8)); + cMac.Update((byte)associatedText.Length); + + extra = 6; + } + + cMac.BlockUpdate(associatedText, 0, associatedText.Length); + + extra = (extra + associatedText.Length) % 16; + if (extra != 0) + { + for (int i = 0; i != 16 - extra; i++) + { + cMac.Update((byte)0x00); + } + } + } + + // + // add the text + // + cMac.BlockUpdate(data, dataOff, dataLen); + + return cMac.DoFinal(macBlock, 0); + } + + private bool hasAssociatedText() + { + return associatedText != null && associatedText.Length != 0; + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/CfbBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/CfbBlockCipher.cs new file mode 100644 index 0000000..5340bc7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/CfbBlockCipher.cs @@ -0,0 +1,218 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher. + */ + public class CfbBlockCipher + : IBlockCipher + { + private byte[] IV; + private byte[] cfbV; + private byte[] cfbOutV; + private bool encrypting; + + private readonly int blockSize; + private readonly IBlockCipher cipher; + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of the + * feedback mode. + * @param blockSize the block size in bits (note: a multiple of 8) + */ + public CfbBlockCipher( + IBlockCipher cipher, + int bitBlockSize) + { + this.cipher = cipher; + this.blockSize = bitBlockSize / 8; + this.IV = new byte[cipher.GetBlockSize()]; + this.cfbV = new byte[cipher.GetBlockSize()]; + this.cfbOutV = new byte[cipher.GetBlockSize()]; + } + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * An IV which is too short is handled in FIPS compliant fashion. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.encrypting = forEncryption; + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV) parameters; + byte[] iv = ivParam.GetIV(); + int diff = IV.Length - iv.Length; + Array.Copy(iv, 0, IV, diff, iv.Length); + Array.Clear(IV, 0, diff); + + parameters = ivParam.Parameters; + } + Reset(); + cipher.Init(true, parameters); + } + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/CFB" + * and the block size in bits. + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + /** + * return the block size we are operating at. + * + * @return the block size we are operating at (in bytes). + */ + public int GetBlockSize() + { + return blockSize; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + return (encrypting) + ? EncryptBlock(input, inOff, output, outOff) + : DecryptBlock(input, inOff, output, outOff); + } + + /** + * Do the appropriate processing for CFB mode encryption. + * + * @param in the array containing the data to be encrypted. + * @param inOff offset into the in array the data starts at. + * @param out the array the encrypted data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + if ((outOff + blockSize) > outBytes.Length) + { + throw new DataLengthException("output buffer too short"); + } + cipher.ProcessBlock(cfbV, 0, cfbOutV, 0); + // + // XOR the cfbV with the plaintext producing the cipher text + // + for (int i = 0; i < blockSize; i++) + { + outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]); + } + // + // change over the input block. + // + Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize); + Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize); + return blockSize; + } + /** + * Do the appropriate processing for CFB mode decryption. + * + * @param in the array containing the data to be decrypted. + * @param inOff offset into the in array the data starts at. + * @param out the array the encrypted data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + if ((outOff + blockSize) > outBytes.Length) + { + throw new DataLengthException("output buffer too short"); + } + cipher.ProcessBlock(cfbV, 0, cfbOutV, 0); + // + // change over the input block. + // + Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize); + Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize); + // + // XOR the cfbV with the plaintext producing the plain text + // + for (int i = 0; i < blockSize; i++) + { + outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]); + } + return blockSize; + } + /** + * reset the chaining vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + Array.Copy(IV, 0, cfbV, 0, IV.Length); + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/CtsBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/CtsBlockCipher.cs new file mode 100644 index 0000000..a32b496 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/CtsBlockCipher.cs @@ -0,0 +1,253 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to + * be used to produce cipher text which is the same outLength as the plain text. + */ + public class CtsBlockCipher + : BufferedBlockCipher + { + private readonly int blockSize; + + /** + * Create a buffered block cipher that uses Cipher Text Stealing + * + * @param cipher the underlying block cipher this buffering object wraps. + */ + public CtsBlockCipher( + IBlockCipher cipher) + { + // TODO Should this test for acceptable ones instead? + if (cipher is OfbBlockCipher || cipher is CfbBlockCipher) + throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers"); + + this.cipher = cipher; + + blockSize = cipher.GetBlockSize(); + + buf = new byte[blockSize * 2]; + bufOff = 0; + } + + /** + * return the size of the output buffer required for an update of 'length' bytes. + * + * @param length the outLength of the input. + * @return the space required to accommodate a call to update + * with length bytes of input. + */ + public override int GetUpdateOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + + if (leftOver == 0) + { + return total - buf.Length; + } + + return total - leftOver; + } + + /** + * return the size of the output buffer required for an update plus a + * doFinal with an input of length bytes. + * + * @param length the outLength of the input. + * @return the space required to accommodate a call to update and doFinal + * with length bytes of input. + */ + public override int GetOutputSize( + int length) + { + return length + bufOff; + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + int resultLen = 0; + + if (bufOff == buf.Length) + { + resultLen = cipher.ProcessBlock(buf, 0, output, outOff); + Debug.Assert(resultLen == blockSize); + + Array.Copy(buf, blockSize, buf, 0, blockSize); + bufOff = blockSize; + } + + buf[bufOff++] = input; + + return resultLen; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param length the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (length < 0) + { + throw new ArgumentException("Can't have a negative input outLength!"); + } + + int blockSize = GetBlockSize(); + int outLength = GetUpdateOutputSize(length); + + if (outLength > 0) + { + if ((outOff + outLength) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.Length - bufOff; + + if (length > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + + resultLen += cipher.ProcessBlock(buf, 0, output, outOff); + Array.Copy(buf, blockSize, buf, 0, blockSize); + + bufOff = blockSize; + + length -= gapLen; + inOff += gapLen; + + while (length > blockSize) + { + Array.Copy(input, inOff, buf, bufOff, blockSize); + resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); + Array.Copy(buf, blockSize, buf, 0, blockSize); + + length -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(input, inOff, buf, bufOff, length); + + bufOff += length; + + return resultLen; + } + + /** + * Process the last block in the buffer. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output. + * @exception InvalidOperationException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if cipher text decrypts wrongly (in + * case the exception will never Get thrown). + */ + public override int DoFinal( + byte[] output, + int outOff) + { + if (bufOff + outOff > output.Length) + { + throw new DataLengthException("output buffer too small in doFinal"); + } + + int blockSize = cipher.GetBlockSize(); + int length = bufOff - blockSize; + byte[] block = new byte[blockSize]; + + if (forEncryption) + { + cipher.ProcessBlock(buf, 0, block, 0); + + if (bufOff < blockSize) + { + throw new DataLengthException("need at least one block of input for CTS"); + } + + for (int i = bufOff; i != buf.Length; i++) + { + buf[i] = block[i - blockSize]; + } + + for (int i = blockSize; i != bufOff; i++) + { + buf[i] ^= block[i - blockSize]; + } + + IBlockCipher c = (cipher is CbcBlockCipher) + ? ((CbcBlockCipher)cipher).GetUnderlyingCipher() + : cipher; + + c.ProcessBlock(buf, blockSize, output, outOff); + + Array.Copy(block, 0, output, outOff + blockSize, length); + } + else + { + byte[] lastBlock = new byte[blockSize]; + + IBlockCipher c = (cipher is CbcBlockCipher) + ? ((CbcBlockCipher)cipher).GetUnderlyingCipher() + : cipher; + + c.ProcessBlock(buf, 0, block, 0); + + for (int i = blockSize; i != bufOff; i++) + { + lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]); + } + + Array.Copy(buf, blockSize, block, 0, length); + + cipher.ProcessBlock(block, 0, output, outOff); + Array.Copy(lastBlock, 0, output, outOff + blockSize, length); + } + + int offset = bufOff; + + Reset(); + + return offset; + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/EAXBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/EAXBlockCipher.cs new file mode 100644 index 0000000..b3016d7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/EAXBlockCipher.cs @@ -0,0 +1,302 @@ +using System; + +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and + * Efficiency - by M. Bellare, P. Rogaway, D. Wagner. + * + * http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf + * + * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block + * cipher to encrypt and authenticate data. It's on-line (the length of a + * message isn't needed to begin processing it), has good performances, it's + * simple and provably secure (provided the underlying block cipher is secure). + * + * Of course, this implementations is NOT thread-safe. + */ + public class EaxBlockCipher + : IAeadBlockCipher + { + private enum Tag : byte { N, H, C }; + + private SicBlockCipher cipher; + + private bool forEncryption; + + private int blockSize; + + private IMac mac; + + private byte[] nonceMac; + private byte[] associatedTextMac; + private byte[] macBlock; + + private int macSize; + private byte[] bufBlock; + private int bufOff; + + /** + * Constructor that accepts an instance of a block cipher engine. + * + * @param cipher the engine to use + */ + public EaxBlockCipher( + IBlockCipher cipher) + { + blockSize = cipher.GetBlockSize(); + mac = new CMac(cipher); + macBlock = new byte[blockSize]; + bufBlock = new byte[blockSize * 2]; + associatedTextMac = new byte[mac.GetMacSize()]; + nonceMac = new byte[mac.GetMacSize()]; + this.cipher = new SicBlockCipher(cipher); + } + + public virtual string AlgorithmName + { + get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; } + } + + public virtual int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + public virtual void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + byte[] nonce, associatedText; + ICipherParameters keyParam; + + if (parameters is AeadParameters) + { + AeadParameters param = (AeadParameters) parameters; + + nonce = param.GetNonce(); + associatedText = param.GetAssociatedText(); + macSize = param.MacSize / 8; + keyParam = param.Key; + } + else if (parameters is ParametersWithIV) + { + ParametersWithIV param = (ParametersWithIV) parameters; + + nonce = param.GetIV(); + associatedText = new byte[0]; + macSize = mac.GetMacSize() / 2; + keyParam = param.Parameters; + } + else + { + throw new ArgumentException("invalid parameters passed to EAX"); + } + + byte[] tag = new byte[blockSize]; + + mac.Init(keyParam); + tag[blockSize - 1] = (byte) Tag.H; + mac.BlockUpdate(tag, 0, blockSize); + mac.BlockUpdate(associatedText, 0, associatedText.Length); + mac.DoFinal(associatedTextMac, 0); + + tag[blockSize - 1] = (byte) Tag.N; + mac.BlockUpdate(tag, 0, blockSize); + mac.BlockUpdate(nonce, 0, nonce.Length); + mac.DoFinal(nonceMac, 0); + + tag[blockSize - 1] = (byte) Tag.C; + mac.BlockUpdate(tag, 0, blockSize); + + cipher.Init(true, new ParametersWithIV(keyParam, nonceMac)); + } + + private void calculateMac() + { + byte[] outC = new byte[blockSize]; + mac.DoFinal(outC, 0); + + for (int i = 0; i < macBlock.Length; i++) + { + macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]); + } + } + + public virtual void Reset() + { + Reset(true); + } + + private void Reset( + bool clearMac) + { + cipher.Reset(); + mac.Reset(); + + bufOff = 0; + Array.Clear(bufBlock, 0, bufBlock.Length); + + if (clearMac) + { + Array.Clear(macBlock, 0, macBlock.Length); + } + + byte[] tag = new byte[blockSize]; + tag[blockSize - 1] = (byte) Tag.C; + mac.BlockUpdate(tag, 0, blockSize); + } + + public virtual int ProcessByte( + byte input, + byte[] outBytes, + int outOff) + { + return process(input, outBytes, outOff); + } + + public virtual int ProcessBytes( + byte[] inBytes, + int inOff, + int len, + byte[] outBytes, + int outOff) + { + int resultLen = 0; + + for (int i = 0; i != len; i++) + { + resultLen += process(inBytes[inOff + i], outBytes, outOff + resultLen); + } + + return resultLen; + } + + public virtual int DoFinal( + byte[] outBytes, + int outOff) + { + int extra = bufOff; + byte[] tmp = new byte[bufBlock.Length]; + + bufOff = 0; + + if (forEncryption) + { + cipher.ProcessBlock(bufBlock, 0, tmp, 0); + cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize); + + Array.Copy(tmp, 0, outBytes, outOff, extra); + + mac.BlockUpdate(tmp, 0, extra); + + calculateMac(); + + Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize); + + Reset(false); + + return extra + macSize; + } + else + { + if (extra > macSize) + { + mac.BlockUpdate(bufBlock, 0, extra - macSize); + + cipher.ProcessBlock(bufBlock, 0, tmp, 0); + cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize); + + Array.Copy(tmp, 0, outBytes, outOff, extra - macSize); + } + + calculateMac(); + + if (!verifyMac(bufBlock, extra - macSize)) + throw new InvalidCipherTextException("mac check in EAX failed"); + + Reset(false); + + return extra - macSize; + } + } + + public virtual byte[] GetMac() + { + byte[] mac = new byte[macSize]; + + Array.Copy(macBlock, 0, mac, 0, macSize); + + return mac; + } + + public virtual int GetUpdateOutputSize( + int len) + { + return ((len + bufOff) / blockSize) * blockSize; + } + + public virtual int GetOutputSize( + int len) + { + if (forEncryption) + { + return len + bufOff + macSize; + } + + return len + bufOff - macSize; + } + + private int process( + byte b, + byte[] outBytes, + int outOff) + { + bufBlock[bufOff++] = b; + + if (bufOff == bufBlock.Length) + { + int size; + + if (forEncryption) + { + size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff); + + mac.BlockUpdate(outBytes, outOff, blockSize); + } + else + { + mac.BlockUpdate(bufBlock, 0, blockSize); + + size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff); + } + + bufOff = blockSize; + Array.Copy(bufBlock, blockSize, bufBlock, 0, blockSize); + + return size; + } + + return 0; + } + + private bool verifyMac(byte[] mac, int off) + { + for (int i = 0; i < macSize; i++) + { + if (macBlock[i] != mac[off + i]) + { + return false; + } + } + + return true; + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/GCMBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/GCMBlockCipher.cs new file mode 100644 index 0000000..98c0543 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/GCMBlockCipher.cs @@ -0,0 +1,447 @@ +using System; + +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /// + /// Implements the Galois/Counter mode (GCM) detailed in + /// NIST Special Publication 800-38D. + /// + public class GcmBlockCipher + : IAeadBlockCipher + { + private const int BlockSize = 16; + private static readonly byte[] Zeroes = new byte[BlockSize]; + private static readonly BigInteger R = new BigInteger("11100001", 2).ShiftLeft(120); + + private readonly IBlockCipher cipher; + + // These fields are set by Init and not modified by processing + private bool forEncryption; + private int macSize; + private byte[] nonce; + private byte[] A; + private KeyParameter keyParam; + // private int tagLength; + private BigInteger H; + private BigInteger initS; + private byte[] J0; + + // These fields are modified during processing + private byte[] bufBlock; + private byte[] macBlock; + private BigInteger S; + private byte[] counter; + private int bufOff; + private long totalLength; + + // Debug variables + // private int nCount, xCount, yCount; + + public GcmBlockCipher( + IBlockCipher c) + { + if (c.GetBlockSize() != BlockSize) + throw new ArgumentException("cipher required with a block size of " + BlockSize + "."); + + this.cipher = c; + } + + public virtual string AlgorithmName + { + get { return cipher.AlgorithmName + "/GCM"; } + } + + public virtual int GetBlockSize() + { + return BlockSize; + } + + public virtual void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + this.macSize = 16; // TODO Make configurable? + this.macBlock = null; + + // TODO If macSize limitation is removed, be very careful about bufBlock + int bufLength = forEncryption ? BlockSize : (BlockSize + macSize); + this.bufBlock = new byte[bufLength]; + + if (parameters is AeadParameters) + { + AeadParameters param = (AeadParameters)parameters; + + nonce = param.GetNonce(); + A = param.GetAssociatedText(); + // macSize = param.getMacSize() / 8; + if (param.MacSize != 128) + { + // TODO Make configurable? + throw new ArgumentException("only 128-bit MAC supported currently"); + } + keyParam = param.Key; + } + else if (parameters is ParametersWithIV) + { + ParametersWithIV param = (ParametersWithIV)parameters; + + nonce = param.GetIV(); + A = null; + keyParam = (KeyParameter)param.Parameters; + } + else + { + throw new ArgumentException("invalid parameters passed to GCM"); + } + + if (nonce == null || nonce.Length < 1) + { + throw new ArgumentException("IV must be at least 1 byte"); + } + + if (A == null) + { + // Avoid lots of null checks + A = new byte[0]; + } + + // Cipher always used input forward mode + cipher.Init(true, keyParam); + + // TODO This should be configurable by Init parameters + // (but must be 16 if nonce length not 12) (BlockSize?) + // this.tagLength = 16; + + byte[] h = new byte[BlockSize]; + cipher.ProcessBlock(Zeroes, 0, h, 0); + //trace("H: " + new string(Hex.encode(h))); + this.H = new BigInteger(1, h); + this.initS = gHASH(A, false); + + if (nonce.Length == 12) + { + this.J0 = new byte[16]; + Array.Copy(nonce, 0, J0, 0, nonce.Length); + this.J0[15] = 0x01; + } + else + { + BigInteger N = gHASH(nonce, true); + BigInteger X = BigInteger.ValueOf(nonce.Length * 8); + //trace("len({})||len(IV): " + dumpBigInt(X)); + + N = multiply(N.Xor(X), H); + //trace("GHASH(H,{},IV): " + dumpBigInt(N)); + this.J0 = asBlock(N); + } + + this.S = initS; + this.counter = Arrays.Clone(J0); + //trace("Y" + yCount + ": " + new string(Hex.encode(counter))); + this.bufOff = 0; + this.totalLength = 0; + } + + public virtual byte[] GetMac() + { + return Arrays.Clone(macBlock); + } + + public virtual int GetOutputSize( + int len) + { + if (forEncryption) + { + return len + bufOff + macSize; + } + + return len + bufOff - macSize; + } + + public virtual int GetUpdateOutputSize( + int len) + { + return ((len + bufOff) / BlockSize) * BlockSize; + } + + public virtual int ProcessByte( + byte input, + byte[] output, + int outOff) + { + return Process(input, output, outOff); + } + + public virtual int ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] output, + int outOff) + { + int resultLen = 0; + + for (int i = 0; i != len; i++) + { + resultLen += Process(input[inOff + i], output, outOff + resultLen); + } + + return resultLen; + } + + private int Process( + byte input, + byte[] output, + int outOff) + { + bufBlock[bufOff++] = input; + + if (bufOff == bufBlock.Length) + { + gCTRBlock(bufBlock, BlockSize, output, outOff); + if (!forEncryption) + { + Array.Copy(bufBlock, BlockSize, bufBlock, 0, BlockSize); + } + // bufOff = 0; + bufOff = bufBlock.Length - BlockSize; + // return bufBlock.Length; + return BlockSize; + } + + return 0; + } + + public int DoFinal(byte[] output, int outOff) + { + int extra = bufOff; + if (!forEncryption) + { + if (extra < macSize) + throw new InvalidCipherTextException("data too short"); + + extra -= macSize; + } + + if (extra > 0) + { + byte[] tmp = new byte[BlockSize]; + Array.Copy(bufBlock, 0, tmp, 0, extra); + gCTRBlock(tmp, extra, output, outOff); + } + + // Final gHASH + BigInteger X = BigInteger.ValueOf(A.Length * 8).ShiftLeft(64).Add( + BigInteger.ValueOf(totalLength * 8)); + //trace("len(A)||len(C): " + dumpBigInt(X)); + + S = multiply(S.Xor(X), H); + //trace("GHASH(H,A,C): " + dumpBigInt(S)); + + // T = MSBt(GCTRk(J0,S)) + byte[] tBytes = new byte[BlockSize]; + cipher.ProcessBlock(J0, 0, tBytes, 0); + //trace("E(K,Y0): " + new string(Hex.encode(tmp))); + BigInteger T = S.Xor(new BigInteger(1, tBytes)); + + // TODO Fix this if tagLength becomes configurable + byte[] tag = asBlock(T); + //trace("T: " + new string(Hex.encode(tag))); + + int resultLen = extra; + + if (forEncryption) + { + this.macBlock = tag; + Array.Copy(tag, 0, output, outOff + bufOff, tag.Length); + resultLen += tag.Length; + } + else + { + this.macBlock = new byte[macSize]; + Array.Copy(bufBlock, extra, macBlock, 0, macSize); + if (!Arrays.AreEqual(tag, this.macBlock)) + throw new InvalidCipherTextException("mac check input GCM failed"); + } + + Reset(false); + + return resultLen; + } + + public virtual void Reset() + { + Reset(true); + } + + private void Reset( + bool clearMac) + { + // Debug + // nCount = xCount = yCount = 0; + + S = initS; + counter = Arrays.Clone(J0); + bufOff = 0; + totalLength = 0; + + if (bufBlock != null) + { + Array.Clear(bufBlock, 0, bufBlock.Length); + } + + if (clearMac) + { + macBlock = null; + } + + cipher.Reset(); + } + + private void gCTRBlock(byte[] buf, int bufCount, byte[] output, int outOff) + { + inc(counter); + //trace("Y" + ++yCount + ": " + new string(Hex.encode(counter))); + + byte[] tmp = new byte[BlockSize]; + cipher.ProcessBlock(counter, 0, tmp, 0); + //trace("E(K,Y" + yCount + "): " + new string(Hex.encode(tmp))); + + if (forEncryption) + { + Array.Copy(Zeroes, bufCount, tmp, bufCount, BlockSize - bufCount); + + for (int i = bufCount - 1; i >= 0; --i) + { + tmp[i] ^= buf[i]; + output[outOff + i] = tmp[i]; + } + + gHASHBlock(tmp); + } + else + { + for (int i = bufCount - 1; i >= 0; --i) + { + tmp[i] ^= buf[i]; + output[outOff + i] = tmp[i]; + } + + gHASHBlock(buf); + } + + totalLength += bufCount; + } + + private BigInteger gHASH(byte[] b, bool nonce) + { + //trace("" + b.Length); + BigInteger Y = BigInteger.Zero; + + for (int pos = 0; pos < b.Length; pos += 16) + { + byte[] x = new byte[16]; + int num = System.Math.Min(b.Length - pos, 16); + Array.Copy(b, pos, x, 0, num); + BigInteger X = new BigInteger(1, x); + Y = multiply(Y.Xor(X), H); + // if (nonce) + // { + // trace("N" + ++nCount + ": " + dumpBigInt(Y)); + // } + // else + // { + // trace("X" + ++xCount + ": " + dumpBigInt(Y) + " (gHASH)"); + // } + } + + return Y; + } + + private void gHASHBlock(byte[] block) + { + if (block.Length > BlockSize) + { + byte[] tmp = new byte[BlockSize]; + Array.Copy(block, 0, tmp, 0, BlockSize); + block = tmp; + } + + BigInteger X = new BigInteger(1, block); + S = multiply(S.Xor(X), H); + //trace("X" + ++xCount + ": " + dumpBigInt(S) + " (gHASHBlock)"); + } + + private static void inc(byte[] block) + { + // assert block.Length == 16; + + for (int i = 15; i >= 12; --i) + { + byte b = (byte)((block[i] + 1) & 0xff); + block[i] = b; + + if (b != 0) + { + break; + } + } + } + + private BigInteger multiply( + BigInteger X, + BigInteger Y) + { + BigInteger Z = BigInteger.Zero; + BigInteger V = X; + + for (int i = 0; i < 128; ++i) + { + if (Y.TestBit(127 - i)) + { + Z = Z.Xor(V); + } + + bool lsb = V.TestBit(0); + V = V.ShiftRight(1); + if (lsb) + { + V = V.Xor(R); + } + } + + return Z; + } + + private byte[] asBlock( + BigInteger bi) + { + byte[] b = BigIntegers.AsUnsignedByteArray(bi); + if (b.Length < 16) + { + byte[] tmp = new byte[16]; + Array.Copy(b, 0, tmp, tmp.Length - b.Length, b.Length); + b = tmp; + } + return b; + } + + // private string dumpBigInt(BigInteger bi) + // { + // byte[] b = asBlock(bi); + // + // return new string(Hex.encode(b)); + // } + // + // private void trace(string msg) + // { + // System.err.println(msg); + // } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/crypto/modes/GOFBBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/GOFBBlockCipher.cs new file mode 100644 index 0000000..7db8431 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/GOFBBlockCipher.cs @@ -0,0 +1,223 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * implements the GOST 28147 OFB counter mode (GCTR). + */ + public class GOfbBlockCipher + : IBlockCipher + { + private byte[] IV; + private byte[] ofbV; + private byte[] ofbOutV; + + private readonly int blockSize; + private readonly IBlockCipher cipher; + + bool firstStep = true; + int N3; + int N4; + const int C1 = 16843012; //00000001000000010000000100000100 + const int C2 = 16843009; //00000001000000010000000100000001 + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of the + * counter mode (must have a 64 bit block size). + */ + public GOfbBlockCipher( + IBlockCipher cipher) + { + this.cipher = cipher; + this.blockSize = cipher.GetBlockSize(); + + if (blockSize != 8) + { + throw new ArgumentException("GCTR only for 64 bit block ciphers"); + } + + this.IV = new byte[cipher.GetBlockSize()]; + this.ofbV = new byte[cipher.GetBlockSize()]; + this.ofbOutV = new byte[cipher.GetBlockSize()]; + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * An IV which is too short is handled in FIPS compliant fashion. + * + * @param encrypting if true the cipher is initialised for + * encryption, if false for decryption. + * @param parameters the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is inappropriate. + */ + public void Init( + bool forEncryption, //ignored by this CTR mode + ICipherParameters parameters) + { + firstStep = true; + N3 = 0; + N4 = 0; + + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV)parameters; + byte[] iv = ivParam.GetIV(); + + if (iv.Length < IV.Length) + { + // prepend the supplied IV with zeros (per FIPS PUB 81) + Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length); + for (int i = 0; i < IV.Length - iv.Length; i++) + { + IV[i] = 0; + } + } + else + { + Array.Copy(iv, 0, IV, 0, IV.Length); + } + + parameters = ivParam.Parameters; + } + + Reset(); + + cipher.Init(true, parameters); + } + + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/GCTR" + * and the block size in bits + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/GCTR"; } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + /** + * return the block size we are operating at (in bytes). + * + * @return the block size we are operating at (in bytes). + */ + public int GetBlockSize() + { + return blockSize; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + blockSize) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (firstStep) + { + firstStep = false; + cipher.ProcessBlock(ofbV, 0, ofbOutV, 0); + N3 = bytesToint(ofbOutV, 0); + N4 = bytesToint(ofbOutV, 4); + } + N3 += C2; + N4 += C1; + intTobytes(N3, ofbV, 0); + intTobytes(N4, ofbV, 4); + + cipher.ProcessBlock(ofbV, 0, ofbOutV, 0); + + // + // XOR the ofbV with the plaintext producing the cipher text (and + // the next input block). + // + for (int i = 0; i < blockSize; i++) + { + output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]); + } + + // + // change over the input block. + // + Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize); + Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize); + + return blockSize; + } + + /** + * reset the feedback vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + Array.Copy(IV, 0, ofbV, 0, IV.Length); + + cipher.Reset(); + } + + //array of bytes to type int + private int bytesToint( + byte[] inBytes, + int inOff) + { + return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) + + ((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff); + } + + //int to array of bytes + private void intTobytes( + int num, + byte[] outBytes, + int outOff) + { + outBytes[outOff + 3] = (byte)(num >> 24); + outBytes[outOff + 2] = (byte)(num >> 16); + outBytes[outOff + 1] = (byte)(num >> 8); + outBytes[outOff] = (byte)num; + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/IAeadBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/IAeadBlockCipher.cs new file mode 100644 index 0000000..ca7dab4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/IAeadBlockCipher.cs @@ -0,0 +1,90 @@ +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /// + /// A block cipher mode that includes authenticated encryption with a streaming mode + /// and optional associated data. + /// + public interface IAeadBlockCipher + { + /// The name of the algorithm this cipher implements. + string AlgorithmName { get; } + + /// Initialise the cipher. + /// Parameter can either be an AeadParameters or a ParametersWithIV object. + /// Initialise for encryption if true, for decryption if false. + /// The key or other data required by the cipher. + void Init(bool forEncryption, ICipherParameters parameters); + + /// The block size for this cipher, in bytes. + int GetBlockSize(); + + /** + * Encrypt/decrypt a single byte. + * + * @param input the byte to be processed. + * @param outBytes the output buffer the processed byte goes into. + * @param outOff the offset into the output byte array the processed data starts at. + * @return the number of bytes written to out. + * @exception DataLengthException if the output buffer is too small. + */ + int ProcessByte(byte input, byte[] outBytes, int outOff); + + /** + * Process a block of bytes from in putting the result into out. + * + * @param inBytes the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + * @param outBytes the output buffer the processed bytes go into. + * @param outOff the offset into the output byte array the processed data starts at. + * @return the number of bytes written to out. + * @exception DataLengthException if the output buffer is too small. + */ + int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff); + + /** + * Finish the operation either appending or verifying the MAC at the end of the data. + * + * @param outBytes space for any resulting output data. + * @param outOff offset into out to start copying the data at. + * @return number of bytes written into out. + * @throws InvalidOperationException if the cipher is in an inappropriate state. + * @throws InvalidCipherTextException if the MAC fails to match. + */ + int DoFinal(byte[] outBytes, int outOff); + + /** + * Return the value of the MAC associated with the last stream processed. + * + * @return MAC for plaintext data. + */ + byte[] GetMac(); + + /** + * Return the size of the output buffer required for a ProcessBytes + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to ProcessBytes + * with len bytes of input. + */ + int GetUpdateOutputSize(int len); + + /** + * Return the size of the output buffer required for a ProcessBytes plus a + * DoFinal with an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to ProcessBytes and DoFinal + * with len bytes of input. + */ + int GetOutputSize(int len); + + /// + /// Reset the cipher to the same state as it was after the last init (if there was one). + /// + void Reset(); + } +} diff --git a/iTechSharp/srcbc/crypto/modes/OfbBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/OfbBlockCipher.cs new file mode 100644 index 0000000..9408a74 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/OfbBlockCipher.cs @@ -0,0 +1,178 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * implements a Output-FeedBack (OFB) mode on top of a simple cipher. + */ + public class OfbBlockCipher + : IBlockCipher + { + private byte[] IV; + private byte[] ofbV; + private byte[] ofbOutV; + + private readonly int blockSize; + private readonly IBlockCipher cipher; + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of the + * feedback mode. + * @param blockSize the block size in bits (note: a multiple of 8) + */ + public OfbBlockCipher( + IBlockCipher cipher, + int blockSize) + { + this.cipher = cipher; + this.blockSize = blockSize / 8; + + this.IV = new byte[cipher.GetBlockSize()]; + this.ofbV = new byte[cipher.GetBlockSize()]; + this.ofbOutV = new byte[cipher.GetBlockSize()]; + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * An IV which is too short is handled in FIPS compliant fashion. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, //ignored by this OFB mode + ICipherParameters parameters) + { + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV)parameters; + byte[] iv = ivParam.GetIV(); + + if (iv.Length < IV.Length) + { + // prepend the supplied IV with zeros (per FIPS PUB 81) + Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length); + for (int i = 0; i < IV.Length - iv.Length; i++) + { + IV[i] = 0; + } + } + else + { + Array.Copy(iv, 0, IV, 0, IV.Length); + } + + parameters = ivParam.Parameters; + } + + Reset(); + + cipher.Init(true, parameters); + } + + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/OFB" + * and the block size in bits + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + /** + * return the block size we are operating at (in bytes). + * + * @return the block size we are operating at (in bytes). + */ + public int GetBlockSize() + { + return blockSize; + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + blockSize) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + + cipher.ProcessBlock(ofbV, 0, ofbOutV, 0); + + // + // XOR the ofbV with the plaintext producing the cipher text (and + // the next input block). + // + for (int i = 0; i < blockSize; i++) + { + output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]); + } + + // + // change over the input block. + // + Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize); + Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize); + + return blockSize; + } + + /** + * reset the feedback vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + Array.Copy(IV, 0, ofbV, 0, IV.Length); + + cipher.Reset(); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs new file mode 100644 index 0000000..01a55fc --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs @@ -0,0 +1,344 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode + * on top of a simple cipher. This class assumes the IV has been prepended + * to the data stream already, and just accomodates the reset after + * (blockSize + 2) bytes have been read. + *

      + * For further info see RFC 2440. + *

      + */ + public class OpenPgpCfbBlockCipher + : IBlockCipher + { + private byte[] IV; + private byte[] FR; + private byte[] FRE; + private byte[] tmp; + + private readonly IBlockCipher cipher; + private readonly int blockSize; + + private int count; + private bool forEncryption; + + /** + * Basic constructor. + * + * @param cipher the block cipher to be used as the basis of the + * feedback mode. + */ + public OpenPgpCfbBlockCipher( + IBlockCipher cipher) + { + this.cipher = cipher; + + this.blockSize = cipher.GetBlockSize(); + this.IV = new byte[blockSize]; + this.FR = new byte[blockSize]; + this.FRE = new byte[blockSize]; + this.tmp = new byte[blockSize]; + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + + /** + * return the algorithm name and mode. + * + * @return the name of the underlying algorithm followed by "/PGPCFB" + * and the block size in bits. + */ + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/OpenPGPCFB"; } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + /** + * return the block size we are operating at. + * + * @return the block size we are operating at (in bytes). + */ + public int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + /** + * Process one block of input from the array in and write it to + * the out array. + * + * @param in the array containing the input data. + * @param inOff offset into the in array the data starts at. + * @param out the array the output data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff); + } + + /** + * reset the chaining vector back to the IV and reset the underlying + * cipher. + */ + public void Reset() + { + count = 0; + + Array.Copy(IV, 0, FR, 0, FR.Length); + + cipher.Reset(); + } + + /** + * Initialise the cipher and, possibly, the initialisation vector (IV). + * If an IV isn't passed as part of the parameter, the IV will be all zeros. + * An IV which is too short is handled in FIPS compliant fashion. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param parameters the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV)parameters; + byte[] iv = ivParam.GetIV(); + + if (iv.Length < IV.Length) + { + // prepend the supplied IV with zeros (per FIPS PUB 81) + Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length); + for (int i = 0; i < IV.Length - iv.Length; i++) + { + IV[i] = 0; + } + } + else + { + Array.Copy(iv, 0, IV, 0, IV.Length); + } + + parameters = ivParam.Parameters; + } + + Reset(); + + cipher.Init(true, parameters); + } + + /** + * Encrypt one byte of data according to CFB mode. + * @param data the byte to encrypt + * @param blockOff offset in the current block + * @returns the encrypted byte + */ + private byte EncryptByte(byte data, int blockOff) + { + return (byte)(FRE[blockOff] ^ data); + } + + /** + * Do the appropriate processing for CFB IV mode encryption. + * + * @param in the array containing the data to be encrypted. + * @param inOff offset into the in array the data starts at. + * @param out the array the encrypted data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + private int EncryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + blockSize) > outBytes.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (count > blockSize) + { + FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2); + FR[blockSize - 1] = outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1); + + cipher.ProcessBlock(FR, 0, FRE, 0); + + for (int n = 2; n < blockSize; n++) + { + outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2); + } + + Array.Copy(outBytes, outOff + 2, FR, 0, blockSize - 2); + } + else if (count == 0) + { + cipher.ProcessBlock(FR, 0, FRE, 0); + + for (int n = 0; n < blockSize; n++) + { + outBytes[outOff + n] = EncryptByte(input[inOff + n], n); + } + + Array.Copy(outBytes, outOff, FR, 0, blockSize); + + count += blockSize; + } + else if (count == blockSize) + { + cipher.ProcessBlock(FR, 0, FRE, 0); + + outBytes[outOff] = EncryptByte(input[inOff], 0); + outBytes[outOff + 1] = EncryptByte(input[inOff + 1], 1); + + // + // do reset + // + Array.Copy(FR, 2, FR, 0, blockSize - 2); + Array.Copy(outBytes, outOff, FR, blockSize - 2, 2); + + cipher.ProcessBlock(FR, 0, FRE, 0); + + for (int n = 2; n < blockSize; n++) + { + outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2); + } + + Array.Copy(outBytes, outOff + 2, FR, 0, blockSize - 2); + + count += blockSize; + } + + return blockSize; + } + + /** + * Do the appropriate processing for CFB IV mode decryption. + * + * @param in the array containing the data to be decrypted. + * @param inOff offset into the in array the data starts at. + * @param out the array the encrypted data will be copied into. + * @param outOff the offset into the out array the output will start at. + * @exception DataLengthException if there isn't enough data in in, or + * space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + * @return the number of bytes processed and produced. + */ + private int DecryptBlock( + byte[] input, + int inOff, + byte[] outBytes, + int outOff) + { + if ((inOff + blockSize) > input.Length) + { + throw new DataLengthException("input buffer too short"); + } + + if ((outOff + blockSize) > outBytes.Length) + { + throw new DataLengthException("output buffer too short"); + } + + if (count > blockSize) + { + // copy in buffer so that this mode works if in and out are the same + Array.Copy(input, inOff, tmp, 0, blockSize); + + outBytes[outOff] = EncryptByte(tmp[0], blockSize - 2); + outBytes[outOff + 1] = EncryptByte(tmp[1], blockSize - 1); + + Array.Copy(tmp, 0, FR, blockSize - 2, 2); + + cipher.ProcessBlock(FR, 0, FRE, 0); + + for (int n = 2; n < blockSize; n++) + { + outBytes[outOff + n] = EncryptByte(tmp[n], n - 2); + } + + Array.Copy(tmp, 2, FR, 0, blockSize - 2); + } + else if (count == 0) + { + cipher.ProcessBlock(FR, 0, FRE, 0); + + for (int n = 0; n < blockSize; n++) + { + FR[n] = input[inOff + n]; + outBytes[n] = EncryptByte(input[inOff + n], n); + } + + count += blockSize; + } + else if (count == blockSize) + { + Array.Copy(input, inOff, tmp, 0, blockSize); + + cipher.ProcessBlock(FR, 0, FRE, 0); + + outBytes[outOff] = EncryptByte(tmp[0], 0); + outBytes[outOff + 1] = EncryptByte(tmp[1], 1); + + Array.Copy(FR, 2, FR, 0, blockSize - 2); + + FR[blockSize - 2] = tmp[0]; + FR[blockSize - 1] = tmp[1]; + + cipher.ProcessBlock(FR, 0, FRE, 0); + + for (int n = 2; n < blockSize; n++) + { + FR[n - 2] = input[inOff + n]; + outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2); + } + + count += blockSize; + } + + return blockSize; + } + } +} diff --git a/iTechSharp/srcbc/crypto/modes/SicBlockCipher.cs b/iTechSharp/srcbc/crypto/modes/SicBlockCipher.cs new file mode 100644 index 0000000..fe7fb10 --- /dev/null +++ b/iTechSharp/srcbc/crypto/modes/SicBlockCipher.cs @@ -0,0 +1,106 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Modes +{ + /** + * Implements the Segmented Integer Counter (SIC) mode on top of a simple + * block cipher. + */ + public class SicBlockCipher + : IBlockCipher + { + private readonly IBlockCipher cipher; + private readonly int blockSize; + private readonly byte[] IV; + private readonly byte[] counter; + private readonly byte[] counterOut; + + /** + * Basic constructor. + * + * @param c the block cipher to be used. + */ + public SicBlockCipher(IBlockCipher cipher) + { + this.cipher = cipher; + this.blockSize = cipher.GetBlockSize(); + this.IV = new byte[blockSize]; + this.counter = new byte[blockSize]; + this.counterOut = new byte[blockSize]; + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public IBlockCipher GetUnderlyingCipher() + { + return cipher; + } + + public void Init( + bool forEncryption, //ignored by this CTR mode + ICipherParameters parameters) + { + if (parameters is ParametersWithIV) + { + ParametersWithIV ivParam = (ParametersWithIV) parameters; + byte[] iv = ivParam.GetIV(); + Array.Copy(iv, 0, IV, 0, IV.Length); + + Reset(); + cipher.Init(true, ivParam.Parameters); + } + } + + public string AlgorithmName + { + get { return cipher.AlgorithmName + "/SIC"; } + } + + public bool IsPartialBlockOkay + { + get { return true; } + } + + public int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + cipher.ProcessBlock(counter, 0, counterOut, 0); + + // + // XOR the counterOut with the plaintext producing the cipher text + // + for (int i = 0; i < counterOut.Length; i++) + { + output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]); + } + + // Increment the counter + int j = counter.Length; + while (--j >= 0 && ++counter[j] == 0) + { + } + + return counter.Length; + } + + public void Reset() + { + Array.Copy(IV, 0, counter, 0, counter.Length); + cipher.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/paddings/BlockCipherPadding.cs b/iTechSharp/srcbc/crypto/paddings/BlockCipherPadding.cs new file mode 100644 index 0000000..33a5f9f --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/BlockCipherPadding.cs @@ -0,0 +1,43 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + + +namespace Org.BouncyCastle.Crypto.Paddings +{ + /** + * Block cipher padders are expected to conform to this interface + */ + public interface IBlockCipherPadding + { + /** + * Initialise the padder. + * + * @param param parameters, if any required. + */ + void Init(SecureRandom random); + //throws ArgumentException; + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + string PaddingName { get; } + + /** + * add the pad bytes to the passed in block, returning the + * number of bytes added. + */ + int AddPadding(byte[] input, int inOff); + + /** + * return the number of pad bytes present in the block. + * @exception InvalidCipherTextException if the padding is badly formed + * or invalid. + */ + int PadCount(byte[] input); + //throws InvalidCipherTextException; + } + +} diff --git a/iTechSharp/srcbc/crypto/paddings/ISO10126d2Padding.cs b/iTechSharp/srcbc/crypto/paddings/ISO10126d2Padding.cs new file mode 100644 index 0000000..e132a62 --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/ISO10126d2Padding.cs @@ -0,0 +1,76 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + + +namespace Org.BouncyCastle.Crypto.Paddings +{ + + /** + * A padder that adds ISO10126-2 padding to a block. + */ + public class ISO10126d2Padding: IBlockCipherPadding + { + private SecureRandom random; + + /** + * Initialise the padder. + * + * @param random a SecureRandom if available. + */ + public void Init( + SecureRandom random) + //throws ArgumentException + { + this.random = (random != null) ? random : new SecureRandom(); + } + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + public string PaddingName + { + get { return "ISO10126-2"; } + } + + /** + * add the pad bytes to the passed in block, returning the + * number of bytes added. + */ + public int AddPadding( + byte[] input, + int inOff) + { + byte code = (byte)(input.Length - inOff); + + while (inOff < (input.Length - 1)) + { + input[inOff] = (byte)random.NextInt(); + inOff++; + } + + input[inOff] = code; + + return code; + } + + /** + * return the number of pad bytes present in the block. + */ + public int PadCount(byte[] input) + //throws InvalidCipherTextException + { + int count = input[input.Length - 1] & 0xff; + + if (count > input.Length) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + + return count; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/paddings/ISO7816d4Padding.cs b/iTechSharp/srcbc/crypto/paddings/ISO7816d4Padding.cs new file mode 100644 index 0000000..016b25a --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/ISO7816d4Padding.cs @@ -0,0 +1,79 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Paddings +{ + /** + * A padder that adds the padding according to the scheme referenced in + * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00 + */ + public class ISO7816d4Padding + : IBlockCipherPadding + { + /** + * Initialise the padder. + * + * @param random - a SecureRandom if available. + */ + public void Init( + SecureRandom random) + { + // nothing to do. + } + + /** + * Return the name of the algorithm the padder implements. + * + * @return the name of the algorithm the padder implements. + */ + public string PaddingName + { + get { return "ISO7816-4"; } + } + + /** + * add the pad bytes to the passed in block, returning the + * number of bytes added. + */ + public int AddPadding( + byte[] input, + int inOff) + { + int added = (input.Length - inOff); + + input[inOff]= (byte) 0x80; + inOff ++; + + while (inOff < input.Length) + { + input[inOff] = (byte) 0; + inOff++; + } + + return added; + } + + /** + * return the number of pad bytes present in the block. + */ + public int PadCount( + byte[] input) + { + int count = input.Length - 1; + + while (count > 0 && input[count] == 0) + { + count--; + } + + if (input[count] != (byte)0x80) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + + return input.Length - count; + } + } +} diff --git a/iTechSharp/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs b/iTechSharp/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs new file mode 100644 index 0000000..dd5cba8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs @@ -0,0 +1,287 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Paddings +{ + /** + * A wrapper class that allows block ciphers to be used to process data in + * a piecemeal fashion with padding. The PaddedBufferedBlockCipher + * outputs a block only when the buffer is full and more data is being added, + * or on a doFinal (unless the current block in the buffer is a pad block). + * The default padding mechanism used is the one outlined in Pkcs5/Pkcs7. + */ + public class PaddedBufferedBlockCipher + : BufferedBlockCipher + { + private readonly IBlockCipherPadding padding; + + /** + * Create a buffered block cipher with the desired padding. + * + * @param cipher the underlying block cipher this buffering object wraps. + * @param padding the padding type. + */ + public PaddedBufferedBlockCipher( + IBlockCipher cipher, + IBlockCipherPadding padding) + { + this.cipher = cipher; + this.padding = padding; + + buf = new byte[cipher.GetBlockSize()]; + bufOff = 0; + } + + /** + * Create a buffered block cipher Pkcs7 padding + * + * @param cipher the underlying block cipher this buffering object wraps. + */ + public PaddedBufferedBlockCipher(IBlockCipher cipher) + : this(cipher, new Pkcs7Padding()) { } + + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + SecureRandom initRandom = null; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom p = (ParametersWithRandom)parameters; + initRandom = p.Random; + parameters = p.Parameters; + } + + Reset(); + padding.Init(initRandom); + cipher.Init(forEncryption, parameters); + } + + /** + * return the minimum size of the output buffer required for an update + * plus a doFinal with an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with len bytes of input. + */ + public override int GetOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + + if (leftOver == 0) + { + if (forEncryption) + { + return total + buf.Length; + } + + return total; + } + + return total - leftOver + buf.Length; + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public override int GetUpdateOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + + if (leftOver == 0) + { + return total - buf.Length; + } + + return total - leftOver; + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + int resultLen = 0; + + if (bufOff == buf.Length) + { + resultLen = cipher.ProcessBlock(buf, 0, output, outOff); + bufOff = 0; + } + + buf[bufOff++] = input; + + return resultLen; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param len the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (length < 0) + { + throw new ArgumentException("Can't have a negative input length!"); + } + + int blockSize = GetBlockSize(); + int outLength = GetUpdateOutputSize(length); + + if (outLength > 0) + { + if ((outOff + outLength) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.Length - bufOff; + + if (length > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + + resultLen += cipher.ProcessBlock(buf, 0, output, outOff); + + bufOff = 0; + length -= gapLen; + inOff += gapLen; + + while (length > buf.Length) + { + resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen); + + length -= blockSize; + inOff += blockSize; + } + } + + Array.Copy(input, inOff, buf, bufOff, length); + + bufOff += length; + + return resultLen; + } + + /** + * Process the last block in the buffer. If the buffer is currently + * full and padding needs to be added a call to doFinal will produce + * 2 * GetBlockSize() bytes. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output or we are decrypting and the input is not block size aligned. + * @exception InvalidOperationException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if padding is expected and not found. + */ + public override int DoFinal( + byte[] output, + int outOff) + { + int blockSize = cipher.GetBlockSize(); + int resultLen = 0; + + if (forEncryption) + { + if (bufOff == blockSize) + { + if ((outOff + 2 * blockSize) > output.Length) + { + Reset(); + + throw new DataLengthException("output buffer too short"); + } + + resultLen = cipher.ProcessBlock(buf, 0, output, outOff); + bufOff = 0; + } + + padding.AddPadding(buf, bufOff); + + resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); + + Reset(); + } + else + { + if (bufOff == blockSize) + { + resultLen = cipher.ProcessBlock(buf, 0, buf, 0); + bufOff = 0; + } + else + { + Reset(); + + throw new DataLengthException("last block incomplete in decryption"); + } + + try + { + resultLen -= padding.PadCount(buf); + + Array.Copy(buf, 0, output, outOff, resultLen); + } + finally + { + Reset(); + } + } + + return resultLen; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/paddings/Pkcs7Padding.cs b/iTechSharp/srcbc/crypto/paddings/Pkcs7Padding.cs new file mode 100644 index 0000000..e873940 --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/Pkcs7Padding.cs @@ -0,0 +1,77 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + + +namespace Org.BouncyCastle.Crypto.Paddings +{ + /** + * A padder that adds Pkcs7/Pkcs5 padding to a block. + */ + public class Pkcs7Padding: IBlockCipherPadding + { + /** + * Initialise the padder. + * + * @param random - a SecureRandom if available. + */ + public void Init(SecureRandom random) + { + // nothing to do. + } + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + public string PaddingName + { + get { return "PKCS7"; } + } + + /** + * add the pad bytes to the passed in block, returning the + * number of bytes added. + */ + public int AddPadding( + byte[] input, + int inOff) + { + byte code = (byte)(input.Length - inOff); + + while (inOff < input.Length) + { + input[inOff] = code; + inOff++; + } + + return code; + } + + /** + * return the number of pad bytes present in the block. + */ + public int PadCount( + byte[] input) + { + int count = (int) input[input.Length - 1]; + + if (count < 1 || count > input.Length) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + + for (int i = 1; i <= count; i++) + { + if (input[input.Length - i] != count) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + } + + return count; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/paddings/TbcPadding.cs b/iTechSharp/srcbc/crypto/paddings/TbcPadding.cs new file mode 100644 index 0000000..74b64e8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/TbcPadding.cs @@ -0,0 +1,79 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Paddings +{ + + /// A padder that adds Trailing-Bit-Compliment padding to a block. + ///

      + /// This padding pads the block out compliment of the last bit + /// of the plain text. + ///

      + ///
      + public class TbcPadding + : IBlockCipherPadding + { + /// Return the name of the algorithm the cipher implements. + /// the name of the algorithm the cipher implements. + /// + public string PaddingName + { + get { return "TBC"; } + } + + /// Initialise the padder. + /// - a SecureRandom if available. + /// + public virtual void Init(SecureRandom random) + { + // nothing to do. + } + + /// add the pad bytes to the passed in block, returning the + /// number of bytes added. + ///

      + /// Note: this assumes that the last block of plain text is always + /// passed to it inside in. i.e. if inOff is zero, indicating the + /// entire block is to be overwritten with padding the value of in + /// should be the same as the last block of plain text. + ///

      + ///
      + public virtual int AddPadding(byte[] input, int inOff) + { + int count = input.Length - inOff; + byte code; + + if (inOff > 0) + { + code = (byte)((input[inOff - 1] & 0x01) == 0?0xff:0x00); + } + else + { + code = (byte)((input[input.Length - 1] & 0x01) == 0?0xff:0x00); + } + + while (inOff < input.Length) + { + input[inOff] = code; + inOff++; + } + + return count; + } + + /// return the number of pad bytes present in the block. + public virtual int PadCount(byte[] input) + { + byte code = input[input.Length - 1]; + + int index = input.Length - 1; + while (index > 0 && input[index - 1] == code) + { + index--; + } + + return input.Length - index; + } + } +} diff --git a/iTechSharp/srcbc/crypto/paddings/X923Padding.cs b/iTechSharp/srcbc/crypto/paddings/X923Padding.cs new file mode 100644 index 0000000..cc1b52b --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/X923Padding.cs @@ -0,0 +1,82 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Paddings +{ + /** + * A padder that adds X9.23 padding to a block - if a SecureRandom is + * passed in random padding is assumed, otherwise padding with zeros is used. + */ + public class X923Padding + : IBlockCipherPadding + { + private SecureRandom random; + + /** + * Initialise the padder. + * + * @param random a SecureRandom if one is available. + */ + public void Init( + SecureRandom random) + { + this.random = random; + } + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + public string PaddingName + { + get { return "X9.23"; } + } + + /** + * add the pad bytes to the passed in block, returning the + * number of bytes added. + */ + public int AddPadding( + byte[] input, + int inOff) + { + byte code = (byte)(input.Length - inOff); + + while (inOff < input.Length - 1) + { + if (random == null) + { + input[inOff] = 0; + } + else + { + input[inOff] = (byte)random.NextInt(); + } + inOff++; + } + + input[inOff] = code; + + return code; + } + + /** + * return the number of pad bytes present in the block. + */ + public int PadCount( + byte[] input) + { + int count = input[input.Length - 1] & 0xff; + + if (count > input.Length) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + + return count; + } + } +} diff --git a/iTechSharp/srcbc/crypto/paddings/ZeroBytePadding.cs b/iTechSharp/srcbc/crypto/paddings/ZeroBytePadding.cs new file mode 100644 index 0000000..0d55ca4 --- /dev/null +++ b/iTechSharp/srcbc/crypto/paddings/ZeroBytePadding.cs @@ -0,0 +1,68 @@ +using System; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Paddings +{ + + /// A padder that adds Null byte padding to a block. + public class ZeroBytePadding : IBlockCipherPadding + { + /// Return the name of the algorithm the cipher implements. + /// + /// + /// the name of the algorithm the cipher implements. + /// + public string PaddingName + { + get { return "ZeroBytePadding"; } + } + + /// Initialise the padder. + /// + /// + /// - a SecureRandom if available. + /// + public void Init(SecureRandom random) + { + // nothing to do. + } + + /// add the pad bytes to the passed in block, returning the + /// number of bytes added. + /// + public int AddPadding( + byte[] input, + int inOff) + { + int added = (input.Length - inOff); + + while (inOff < input.Length) + { + input[inOff] = (byte) 0; + inOff++; + } + + return added; + } + + /// return the number of pad bytes present in the block. + public int PadCount( + byte[] input) + { + int count = input.Length; + + while (count > 0) + { + if (input[count - 1] != 0) + { + break; + } + + count--; + } + + return input.Length - count; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/AEADParameters.cs b/iTechSharp/srcbc/crypto/parameters/AEADParameters.cs new file mode 100644 index 0000000..06b2f5c --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/AEADParameters.cs @@ -0,0 +1,53 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class AeadParameters + : ICipherParameters + { + private readonly byte[] associatedText; + private readonly byte[] nonce; + private readonly KeyParameter key; + private readonly int macSize; + + /** + * Base constructor. + * + * @param key key to be used by underlying cipher + * @param macSize macSize in bits + * @param nonce nonce to be used + * @param associatedText associated text, if any + */ + public AeadParameters( + KeyParameter key, + int macSize, + byte[] nonce, + byte[] associatedText) + { + this.key = key; + this.nonce = nonce; + this.macSize = macSize; + this.associatedText = associatedText; + } + + public virtual KeyParameter Key + { + get { return key; } + } + + public virtual int MacSize + { + get { return macSize; } + } + + public virtual byte[] GetAssociatedText() + { + return associatedText; + } + + public virtual byte[] GetNonce() + { + return nonce; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/CcmParameters.cs b/iTechSharp/srcbc/crypto/parameters/CcmParameters.cs new file mode 100644 index 0000000..8dc981e --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/CcmParameters.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class CcmParameters + : AeadParameters + { + /** + * Base constructor. + * + * @param key key to be used by underlying cipher + * @param macSize macSize in bits + * @param nonce nonce to be used + * @param associatedText associated text, if any + */ + public CcmParameters( + KeyParameter key, + int macSize, + byte[] nonce, + byte[] associatedText) + : base(key, macSize, nonce, associatedText) + { + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DHKeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/DHKeyGenerationParameters.cs new file mode 100644 index 0000000..93ae231 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DHKeyGenerationParameters.cs @@ -0,0 +1,25 @@ +using System; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DHKeyGenerationParameters + : KeyGenerationParameters + { + private readonly DHParameters parameters; + + public DHKeyGenerationParameters( + SecureRandom random, + DHParameters parameters) + : base(random, parameters.P.BitLength) + { + this.parameters = parameters; + } + + public DHParameters Parameters + { + get { return parameters; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DHKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/DHKeyParameters.cs new file mode 100644 index 0000000..3fc82d6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DHKeyParameters.cs @@ -0,0 +1,59 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DHKeyParameters + : AsymmetricKeyParameter + { + private readonly DHParameters parameters; + + protected DHKeyParameters( + bool isPrivate, + DHParameters parameters) + : base(isPrivate) + { + // TODO Should we allow parameters to be null? + this.parameters = parameters; + } + + public DHParameters Parameters + { + get { return parameters; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DHKeyParameters other = obj as DHKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DHKeyParameters other) + { + return Platform.Equals(parameters, other.parameters) + && base.Equals(other); + } + + public override int GetHashCode() + { + int hc = base.GetHashCode(); + + if (parameters != null) + { + hc ^= parameters.GetHashCode(); + } + + return hc; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DHParameters.cs b/iTechSharp/srcbc/crypto/parameters/DHParameters.cs new file mode 100644 index 0000000..f0dc686 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DHParameters.cs @@ -0,0 +1,178 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DHParameters + : ICipherParameters + { + private const int DefaultMinimumLength = 160; + + private readonly BigInteger p, g, q, j; + private readonly int m, l; + private readonly DHValidationParameters validation; + + private static int GetDefaultM( + BigInteger p, + int l) + { + int effectiveL = l != 0 ? l : p.BitLength - 1; + + return System.Math.Min(DefaultMinimumLength, effectiveL); + +// return DefaultMinimumLength; + } + + public DHParameters( + BigInteger p, + BigInteger g) + : this(p, g, null, GetDefaultM(p, 0), 0, null, null) + { + } + + public DHParameters( + BigInteger p, + BigInteger g, + BigInteger q) + : this(p, g, q, GetDefaultM(p, 0), 0, null, null) + { + } + + public DHParameters( + BigInteger p, + BigInteger g, + BigInteger q, + int l) + : this(p, g, q, GetDefaultM(p, l), l, null, null) + { + } + + public DHParameters( + BigInteger p, + BigInteger g, + BigInteger q, + int m, + int l) + : this(p, g, q, m, l, null, null) + { + } + + public DHParameters( + BigInteger p, + BigInteger g, + BigInteger q, + BigInteger j, + DHValidationParameters validation) + : this(p, g, q, GetDefaultM(p, 0), 0, j, validation) + { + } + + public DHParameters( + BigInteger p, + BigInteger g, + BigInteger q, + int m, + int l, + BigInteger j, + DHValidationParameters validation) + { + if (p == null) + throw new ArgumentNullException("p"); + if (g == null) + throw new ArgumentNullException("g"); + if (!p.TestBit(0)) + throw new ArgumentException("field must be an odd prime", "p"); + if (g.CompareTo(BigInteger.Two) < 0 + || g.CompareTo(p.Subtract(BigInteger.Two)) > 0) + throw new ArgumentException("generator must in the range [2, p - 2]", "g"); + if (m >= p.BitLength) + throw new ArgumentException("m value must be < bitlength of p", "m"); + if (l != 0 && l < m) + throw new ArgumentException("l value must be >= m, or zero", "l"); + if (j != null && j.CompareTo(BigInteger.Two) < 0) + throw new ArgumentException("subgroup factor must be >= 2", "j"); + + this.p = p; + this.g = g; + this.q = q; + this.m = m; + this.l = l; + this.j = j; + this.validation = validation; + } + + public BigInteger P + { + get { return p; } + } + + public BigInteger G + { + get { return g; } + } + + public BigInteger Q + { + get { return q; } + } + + public BigInteger J + { + get { return j; } + } + + /// The minimum bitlength of the private value. + public int M + { + get { return m; } + } + + /// The bitlength of the private value. + /// If zero, bitLength(p) - 1 will be used. + public int L + { + get { return l; } + } + + public DHValidationParameters ValidationParameters + { + get { return validation; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DHParameters other = obj as DHParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DHParameters other) + { + return p.Equals(other.p) + && g.Equals(other.g) + && Platform.Equals(q, other.q); + } + + public override int GetHashCode() + { + int hc = p.GetHashCode() ^ g.GetHashCode(); + + if (q != null) + { + hc ^= q.GetHashCode(); + } + + return hc; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DHPrivateKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/DHPrivateKeyParameters.cs new file mode 100644 index 0000000..1f7e336 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DHPrivateKeyParameters.cs @@ -0,0 +1,50 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DHPrivateKeyParameters + : DHKeyParameters + { + private readonly BigInteger x; + + public DHPrivateKeyParameters( + BigInteger x, + DHParameters parameters) + : base(true, parameters) + { + this.x = x; + } + + public BigInteger X + { + get { return x; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DHPrivateKeyParameters other = obj as DHPrivateKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DHPrivateKeyParameters other) + { + return x.Equals(other.x) && base.Equals(other); + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DHPublicKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/DHPublicKeyParameters.cs new file mode 100644 index 0000000..18b5c19 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DHPublicKeyParameters.cs @@ -0,0 +1,53 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DHPublicKeyParameters + : DHKeyParameters + { + private readonly BigInteger y; + + public DHPublicKeyParameters( + BigInteger y, + DHParameters parameters) + : base(false, parameters) + { + if (y == null) + throw new ArgumentNullException("y"); + + this.y = y; + } + + public BigInteger Y + { + get { return y; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DHPublicKeyParameters other = obj as DHPublicKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DHPublicKeyParameters other) + { + return y.Equals(other.y) && base.Equals(other); + } + + public override int GetHashCode() + { + return y.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DHValidationParameters.cs b/iTechSharp/srcbc/crypto/parameters/DHValidationParameters.cs new file mode 100644 index 0000000..50c0739 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DHValidationParameters.cs @@ -0,0 +1,59 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DHValidationParameters + { + private readonly byte[] seed; + private readonly int counter; + + public DHValidationParameters( + byte[] seed, + int counter) + { + if (seed == null) + throw new ArgumentNullException("seed"); + + this.seed = (byte[]) seed.Clone(); + this.counter = counter; + } + + public byte[] GetSeed() + { + return (byte[]) seed.Clone(); + } + + public int Counter + { + get { return counter; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DHValidationParameters other = obj as DHValidationParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DHValidationParameters other) + { + return counter == other.counter + && Arrays.AreEqual(this.seed, other.seed); + } + + public override int GetHashCode() + { + return counter.GetHashCode() ^ Arrays.GetHashCode(seed); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DesEdeParameters.cs b/iTechSharp/srcbc/crypto/parameters/DesEdeParameters.cs new file mode 100644 index 0000000..420aaec --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DesEdeParameters.cs @@ -0,0 +1,95 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DesEdeParameters + : DesParameters + { + /* + * DES-EDE Key length in bytes. + */ + public const int DesEdeKeyLength = 24; + + private static byte[] FixKey( + byte[] key, + int keyOff, + int keyLen) + { + byte[] tmp = new byte[24]; + + switch (keyLen) + { + case 16: + Array.Copy(key, keyOff, tmp, 0, 16); + Array.Copy(key, keyOff, tmp, 16, 8); + break; + case 24: + Array.Copy(key, keyOff, tmp, 0, 24); + break; + default: + throw new ArgumentException("Bad length for DESede key: " + keyLen, "keyLen"); + } + + if (IsWeakKey(tmp)) + throw new ArgumentException("attempt to create weak DESede key"); + + return tmp; + } + + public DesEdeParameters( + byte[] key) + : base(FixKey(key, 0, key.Length)) + { + } + + public DesEdeParameters( + byte[] key, + int keyOff, + int keyLen) + : base(FixKey(key, keyOff, keyLen)) + { + } + + /** + * return true if the passed in key is a DES-EDE weak key. + * + * @param key bytes making up the key + * @param offset offset into the byte array the key starts at + * @param length number of bytes making up the key + */ + public static bool IsWeakKey( + byte[] key, + int offset, + int length) + { + for (int i = offset; i < length; i += DesKeyLength) + { + if (DesParameters.IsWeakKey(key, i)) + { + return true; + } + } + + return false; + } + + /** + * return true if the passed in key is a DES-EDE weak key. + * + * @param key bytes making up the key + * @param offset offset into the byte array the key starts at + */ + public static new bool IsWeakKey( + byte[] key, + int offset) + { + return IsWeakKey(key, offset, key.Length - offset); + } + + public static new bool IsWeakKey( + byte[] key) + { + return IsWeakKey(key, 0, key.Length); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DesParameters.cs b/iTechSharp/srcbc/crypto/parameters/DesParameters.cs new file mode 100644 index 0000000..ee37cd8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DesParameters.cs @@ -0,0 +1,130 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DesParameters + : KeyParameter + { + public DesParameters( + byte[] key) + : base(key) + { + if (IsWeakKey(key)) + throw new ArgumentException("attempt to create weak DES key"); + } + + public DesParameters( + byte[] key, + int keyOff, + int keyLen) + : base(key, keyOff, keyLen) + { + if (IsWeakKey(key, keyOff)) + throw new ArgumentException("attempt to create weak DES key"); + } + + /* + * DES Key Length in bytes. + */ + public const int DesKeyLength = 8; + + /* + * Table of weak and semi-weak keys taken from Schneier pp281 + */ + private const int N_DES_WEAK_KEYS = 16; + + private static readonly byte[] DES_weak_keys = + { + /* weak keys */ + (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, + (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e, + (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1, + (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, + + /* semi-weak keys */ + (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, + (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1, + (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1, + (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe, + (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e, + (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe, + (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, + (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e, + (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01, + (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e, + (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01, + (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1 + }; + + /** + * DES has 16 weak keys. This method will check + * if the given DES key material is weak or semi-weak. + * Key material that is too short is regarded as weak. + *

      + * See "Applied + * Cryptography" by Bruce Schneier for more information. + *

      + * @return true if the given DES key material is weak or semi-weak, + * false otherwise. + */ + public static bool IsWeakKey( + byte[] key, + int offset) + { + if (key.Length - offset < DesKeyLength) + throw new ArgumentException("key material too short."); + + //nextkey: + for (int i = 0; i < N_DES_WEAK_KEYS; i++) + { + bool unmatch = false; + for (int j = 0; j < DesKeyLength; j++) + { + if (key[j + offset] != DES_weak_keys[i * DesKeyLength + j]) + { + //continue nextkey; + unmatch = true; + break; + } + } + + if (!unmatch) + { + return true; + } + } + + return false; + } + + public static bool IsWeakKey( + byte[] key) + { + return IsWeakKey(key, 0); + } + + /** + * DES Keys use the LSB as the odd parity bit. This can + * be used to check for corrupt keys. + * + * @param bytes the byte array to set the parity on. + */ + public static void SetOddParity( + byte[] bytes) + { + for (int i = 0; i < bytes.Length; i++) + { + int b = bytes[i]; + bytes[i] = (byte)((b & 0xfe) | + ((((b >> 1) ^ + (b >> 2) ^ + (b >> 3) ^ + (b >> 4) ^ + (b >> 5) ^ + (b >> 6) ^ + (b >> 7)) ^ 0x01) & 0x01)); + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs new file mode 100644 index 0000000..86d6f5b --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs @@ -0,0 +1,26 @@ +using System; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DsaKeyGenerationParameters + : KeyGenerationParameters + { + private readonly DsaParameters parameters; + + public DsaKeyGenerationParameters( + SecureRandom random, + DsaParameters parameters) + : base(random, parameters.P.BitLength - 1) + { + this.parameters = parameters; + } + + public DsaParameters Parameters + { + get { return parameters; } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/DsaKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/DsaKeyParameters.cs new file mode 100644 index 0000000..a51cbfb --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DsaKeyParameters.cs @@ -0,0 +1,59 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DsaKeyParameters + : AsymmetricKeyParameter + { + private readonly DsaParameters parameters; + + public DsaKeyParameters( + bool isPrivate, + DsaParameters parameters) + : base(isPrivate) + { + // Note: parameters may be null + this.parameters = parameters; + } + + public DsaParameters Parameters + { + get { return parameters; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DsaKeyParameters other = obj as DsaKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DsaKeyParameters other) + { + return Platform.Equals(parameters, other.parameters) + && base.Equals(other); + } + + public override int GetHashCode() + { + int hc = base.GetHashCode(); + + if (parameters != null) + { + hc ^= parameters.GetHashCode(); + } + + return hc; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DsaParameters.cs b/iTechSharp/srcbc/crypto/parameters/DsaParameters.cs new file mode 100644 index 0000000..50d080e --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DsaParameters.cs @@ -0,0 +1,85 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DsaParameters + : ICipherParameters + { + private readonly BigInteger p, q , g; + private readonly DsaValidationParameters validation; + + public DsaParameters( + BigInteger p, + BigInteger q, + BigInteger g) + : this(p, q, g, null) + { + } + + public DsaParameters( + BigInteger p, + BigInteger q, + BigInteger g, + DsaValidationParameters parameters) + { + if (p == null) + throw new ArgumentNullException("p"); + if (q == null) + throw new ArgumentNullException("q"); + if (g == null) + throw new ArgumentNullException("g"); + + this.p = p; + this.q = q; + this.g = g; + this.validation = parameters; + } + + public BigInteger P + { + get { return p; } + } + + public BigInteger Q + { + get { return q; } + } + + public BigInteger G + { + get { return g; } + } + + public DsaValidationParameters ValidationParameters + { + get { return validation; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DsaParameters other = obj as DsaParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DsaParameters other) + { + return p.Equals(other.p) && q.Equals(other.q) && g.Equals(other.g); + } + + public override int GetHashCode() + { + return p.GetHashCode() ^ q.GetHashCode() ^ g.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs new file mode 100644 index 0000000..2abdd0e --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs @@ -0,0 +1,53 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DsaPrivateKeyParameters + : DsaKeyParameters + { + private readonly BigInteger x; + + public DsaPrivateKeyParameters( + BigInteger x, + DsaParameters parameters) + : base(true, parameters) + { + if (x == null) + throw new ArgumentNullException("x"); + + this.x = x; + } + + public BigInteger X + { + get { return x; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DsaPrivateKeyParameters other = obj as DsaPrivateKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DsaPrivateKeyParameters other) + { + return x.Equals(other.x) && base.Equals(other); + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DsaPublicKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/DsaPublicKeyParameters.cs new file mode 100644 index 0000000..f11f858 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DsaPublicKeyParameters.cs @@ -0,0 +1,52 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DsaPublicKeyParameters + : DsaKeyParameters + { + private readonly BigInteger y; + + public DsaPublicKeyParameters( + BigInteger y, + DsaParameters parameters) + : base(false, parameters) + { + if (y == null) + throw new ArgumentNullException("y"); + + this.y = y; + } + + public BigInteger Y + { + get { return y; } + } + + public override bool Equals(object obj) + { + if (obj == this) + return true; + + DsaPublicKeyParameters other = obj as DsaPublicKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DsaPublicKeyParameters other) + { + return y.Equals(other.y) && base.Equals(other); + } + + public override int GetHashCode() + { + return y.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/DsaValidationParameters.cs b/iTechSharp/srcbc/crypto/parameters/DsaValidationParameters.cs new file mode 100644 index 0000000..b9cdc4a --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/DsaValidationParameters.cs @@ -0,0 +1,59 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class DsaValidationParameters + { + private readonly byte[] seed; + private readonly int counter; + + public DsaValidationParameters( + byte[] seed, + int counter) + { + if (seed == null) + throw new ArgumentNullException("seed"); + + this.seed = (byte[]) seed.Clone(); + this.counter = counter; + } + + public byte[] GetSeed() + { + return (byte[]) seed.Clone(); + } + + public int Counter + { + get { return counter; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + DsaValidationParameters other = obj as DsaValidationParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + DsaValidationParameters other) + { + return counter == other.counter + && Arrays.AreEqual(seed, other.seed); + } + + public override int GetHashCode() + { + return counter.GetHashCode() ^ Arrays.GetHashCode(seed); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ECDomainParameters.cs b/iTechSharp/srcbc/crypto/parameters/ECDomainParameters.cs new file mode 100644 index 0000000..c6a3e4e --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ECDomainParameters.cs @@ -0,0 +1,116 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ECDomainParameters + { + internal ECCurve curve; + internal byte[] seed; + internal ECPoint g; + internal BigInteger n; + internal BigInteger h; + + public ECDomainParameters( + ECCurve curve, + ECPoint g, + BigInteger n) + : this(curve, g, n, BigInteger.One) + { + } + + public ECDomainParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h) + : this(curve, g, n, h, null) + { + } + + public ECDomainParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + { + if (curve == null) + throw new ArgumentNullException("curve"); + if (g == null) + throw new ArgumentNullException("g"); + if (n == null) + throw new ArgumentNullException("n"); + if (h == null) + throw new ArgumentNullException("h"); + + this.curve = curve; + this.g = g; + this.n = n; + this.h = h; + this.seed = Arrays.Clone(seed); + } + + public ECCurve Curve + { + get { return curve; } + } + + public ECPoint G + { + get { return g; } + } + + public BigInteger N + { + get { return n; } + } + + public BigInteger H + { + get { return h; } + } + + public byte[] GetSeed() + { + return Arrays.Clone(seed); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECDomainParameters other = obj as ECDomainParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECDomainParameters other) + { + return curve.Equals(other.curve) + && g.Equals(other.g) + && n.Equals(other.n) + && h.Equals(other.h) + && Arrays.AreEqual(seed, other.seed); + } + + public override int GetHashCode() + { + return curve.GetHashCode() + ^ g.GetHashCode() + ^ n.GetHashCode() + ^ h.GetHashCode() + ^ Arrays.GetHashCode(seed); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/ECKeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/ECKeyGenerationParameters.cs new file mode 100644 index 0000000..4bed302 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ECKeyGenerationParameters.cs @@ -0,0 +1,55 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ECKeyGenerationParameters + : KeyGenerationParameters + { + private readonly ECDomainParameters domainParams; + private readonly DerObjectIdentifier publicKeyParamSet; + + public ECKeyGenerationParameters( + ECDomainParameters domainParameters, + SecureRandom random) + : base(random, domainParameters.N.BitLength) + { + this.domainParams = domainParameters; + } + + public ECKeyGenerationParameters( + DerObjectIdentifier publicKeyParamSet, + SecureRandom random) + : this(LookupParameters(publicKeyParamSet), random) + { + this.publicKeyParamSet = publicKeyParamSet; + } + + public ECDomainParameters DomainParameters + { + get { return domainParams; } + } + + public DerObjectIdentifier PublicKeyParamSet + { + get { return publicKeyParamSet; } + } + + private static ECDomainParameters LookupParameters( + DerObjectIdentifier publicKeyParamSet) + { + if (publicKeyParamSet == null) + throw new ArgumentNullException("publicKeyParamSet"); + + ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet); + + if (p == null) + throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet"); + + return p; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ECKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/ECKeyParameters.cs new file mode 100644 index 0000000..6c848c1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ECKeyParameters.cs @@ -0,0 +1,121 @@ +using System; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public abstract class ECKeyParameters + : AsymmetricKeyParameter + { + private readonly string algorithm; + private readonly ECDomainParameters parameters; + private readonly DerObjectIdentifier publicKeyParamSet; + + protected ECKeyParameters( + string algorithm, + bool isPrivate, + ECDomainParameters parameters) + : base(isPrivate) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + if (parameters == null) + throw new ArgumentNullException("parameters"); + + this.algorithm = VerifyAlgorithmName(algorithm); + this.parameters = parameters; + } + + protected ECKeyParameters( + string algorithm, + bool isPrivate, + DerObjectIdentifier publicKeyParamSet) + : base(isPrivate) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + if (publicKeyParamSet == null) + throw new ArgumentNullException("publicKeyParamSet"); + + this.algorithm = VerifyAlgorithmName(algorithm); + this.parameters = LookupParameters(publicKeyParamSet); + this.publicKeyParamSet = publicKeyParamSet; + } + + public string AlgorithmName + { + get { return algorithm; } + } + + public ECDomainParameters Parameters + { + get { return parameters; } + } + + public DerObjectIdentifier PublicKeyParamSet + { + get { return publicKeyParamSet; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECDomainParameters other = obj as ECDomainParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECKeyParameters other) + { + return parameters.Equals(other.parameters) && base.Equals(other); + } + + public override int GetHashCode() + { + return parameters.GetHashCode() ^ base.GetHashCode(); + } + + private string VerifyAlgorithmName( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + + switch (upper) + { + case "EC": + case "ECDSA": + case "ECGOST3410": + case "ECDH": + case "ECDHC": + break; + default: + throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm"); + } + + return upper; + } + + private static ECDomainParameters LookupParameters( + DerObjectIdentifier publicKeyParamSet) + { + if (publicKeyParamSet == null) + throw new ArgumentNullException("publicKeyParamSet"); + + ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet); + + if (p == null) + throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet"); + + return p; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ECPrivateKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/ECPrivateKeyParameters.cs new file mode 100644 index 0000000..f003fb6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ECPrivateKeyParameters.cs @@ -0,0 +1,74 @@ +using System; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ECPrivateKeyParameters + : ECKeyParameters + { + private readonly BigInteger d; + + public ECPrivateKeyParameters( + BigInteger d, + ECDomainParameters parameters) + : this("EC", d, parameters) + { + } + + public ECPrivateKeyParameters( + BigInteger d, + DerObjectIdentifier publicKeyParamSet) + : base("ECGOST3410", true, publicKeyParamSet) + { + if (d == null) + throw new ArgumentNullException("d"); + + this.d = d; + } + + public ECPrivateKeyParameters( + string algorithm, + BigInteger d, + ECDomainParameters parameters) + : base(algorithm, true, parameters) + { + if (d == null) + throw new ArgumentNullException("d"); + + this.d = d; + } + + public BigInteger D + { + get { return d; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECPrivateKeyParameters other = obj as ECPrivateKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECPrivateKeyParameters other) + { + return d.Equals(other.d) && base.Equals(other); + } + + public override int GetHashCode() + { + return d.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ECPublicKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/ECPublicKeyParameters.cs new file mode 100644 index 0000000..39919c1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ECPublicKeyParameters.cs @@ -0,0 +1,73 @@ +using System; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ECPublicKeyParameters + : ECKeyParameters + { + private readonly ECPoint q; + + public ECPublicKeyParameters( + ECPoint q, + ECDomainParameters parameters) + : this("EC", q, parameters) + { + } + + public ECPublicKeyParameters( + ECPoint q, + DerObjectIdentifier publicKeyParamSet) + : base("ECGOST3410", false, publicKeyParamSet) + { + if (q == null) + throw new ArgumentNullException("q"); + + this.q = q; + } + + public ECPublicKeyParameters( + string algorithm, + ECPoint q, + ECDomainParameters parameters) + : base(algorithm, false, parameters) + { + if (q == null) + throw new ArgumentNullException("q"); + + this.q = q; + } + + public ECPoint Q + { + get { return q; } + } + + public override bool Equals(object obj) + { + if (obj == this) + return true; + + ECPublicKeyParameters other = obj as ECPublicKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECPublicKeyParameters other) + { + return q.Equals(other.q) && base.Equals(other); + } + + public override int GetHashCode() + { + return q.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs new file mode 100644 index 0000000..3454362 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs @@ -0,0 +1,25 @@ +using System; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ElGamalKeyGenerationParameters + : KeyGenerationParameters + { + private readonly ElGamalParameters parameters; + + public ElGamalKeyGenerationParameters( + SecureRandom random, + ElGamalParameters parameters) + : base(random, parameters.P.BitLength) + { + this.parameters = parameters; + } + + public ElGamalParameters Parameters + { + get { return parameters; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ElGamalKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/ElGamalKeyParameters.cs new file mode 100644 index 0000000..8b6e279 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ElGamalKeyParameters.cs @@ -0,0 +1,59 @@ +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ElGamalKeyParameters + : AsymmetricKeyParameter + { + private readonly ElGamalParameters parameters; + + protected ElGamalKeyParameters( + bool isPrivate, + ElGamalParameters parameters) + : base(isPrivate) + { + // TODO Should we allow 'parameters' to be null? + this.parameters = parameters; + } + + public ElGamalParameters Parameters + { + get { return parameters; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ElGamalKeyParameters other = obj as ElGamalKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ElGamalKeyParameters other) + { + return Platform.Equals(parameters, other.parameters) + && base.Equals(other); + } + + public override int GetHashCode() + { + int hc = base.GetHashCode(); + + if (parameters != null) + { + hc ^= parameters.GetHashCode(); + } + + return hc; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ElGamalParameters.cs b/iTechSharp/srcbc/crypto/parameters/ElGamalParameters.cs new file mode 100644 index 0000000..ab6d3e7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ElGamalParameters.cs @@ -0,0 +1,81 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ElGamalParameters + : ICipherParameters + { + private readonly BigInteger p, g; + private readonly int l; + + public ElGamalParameters( + BigInteger p, + BigInteger g) + : this(p, g, 0) + { + } + + public ElGamalParameters( + BigInteger p, + BigInteger g, + int l) + { + if (p == null) + throw new ArgumentNullException("p"); + if (g == null) + throw new ArgumentNullException("g"); + + this.p = p; + this.g = g; + this.l = l; + } + + public BigInteger P + { + get { return p; } + } + + /** + * return the generator - g + */ + public BigInteger G + { + get { return g; } + } + + /** + * return private value limit - l + */ + public int L + { + get { return l; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ElGamalParameters other = obj as ElGamalParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ElGamalParameters other) + { + return p.Equals(other.p) && g.Equals(other.g) && l == other.l; + } + + public override int GetHashCode() + { + return p.GetHashCode() ^ g.GetHashCode() ^ l; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs new file mode 100644 index 0000000..6363f2b --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs @@ -0,0 +1,53 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ElGamalPrivateKeyParameters + : ElGamalKeyParameters + { + private readonly BigInteger x; + + public ElGamalPrivateKeyParameters( + BigInteger x, + ElGamalParameters parameters) + : base(true, parameters) + { + if (x == null) + throw new ArgumentNullException("x"); + + this.x = x; + } + + public BigInteger X + { + get { return x; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ElGamalPrivateKeyParameters other = obj as ElGamalPrivateKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ElGamalPrivateKeyParameters other) + { + return other.x.Equals(x) && base.Equals(other); + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs new file mode 100644 index 0000000..25ac625 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs @@ -0,0 +1,53 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ElGamalPublicKeyParameters + : ElGamalKeyParameters + { + private readonly BigInteger y; + + public ElGamalPublicKeyParameters( + BigInteger y, + ElGamalParameters parameters) + : base(false, parameters) + { + if (y == null) + throw new ArgumentNullException("y"); + + this.y = y; + } + + public BigInteger Y + { + get { return y; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ElGamalPublicKeyParameters other = obj as ElGamalPublicKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ElGamalPublicKeyParameters other) + { + return y.Equals(other.y) && base.Equals(other); + } + + public override int GetHashCode() + { + return y.GetHashCode() ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs new file mode 100644 index 0000000..b06a5d8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs @@ -0,0 +1,55 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class Gost3410KeyGenerationParameters + : KeyGenerationParameters + { + private readonly Gost3410Parameters parameters; + private readonly DerObjectIdentifier publicKeyParamSet; + + public Gost3410KeyGenerationParameters( + SecureRandom random, + Gost3410Parameters parameters) + : base(random, parameters.P.BitLength - 1) + { + this.parameters = parameters; + } + + public Gost3410KeyGenerationParameters( + SecureRandom random, + DerObjectIdentifier publicKeyParamSet) + : this(random, LookupParameters(publicKeyParamSet)) + { + this.publicKeyParamSet = publicKeyParamSet; + } + + public Gost3410Parameters Parameters + { + get { return parameters; } + } + + public DerObjectIdentifier PublicKeyParamSet + { + get { return publicKeyParamSet; } + } + + private static Gost3410Parameters LookupParameters( + DerObjectIdentifier publicKeyParamSet) + { + if (publicKeyParamSet == null) + throw new ArgumentNullException("publicKeyParamSet"); + + Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet); + + if (p == null) + throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet"); + + return new Gost3410Parameters(p.P, p.Q, p.A); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/GOST3410KeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/GOST3410KeyParameters.cs new file mode 100644 index 0000000..f771c4d --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/GOST3410KeyParameters.cs @@ -0,0 +1,58 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public abstract class Gost3410KeyParameters + : AsymmetricKeyParameter + { + private readonly Gost3410Parameters parameters; + private readonly DerObjectIdentifier publicKeyParamSet; + + protected Gost3410KeyParameters( + bool isPrivate, + Gost3410Parameters parameters) + : base(isPrivate) + { + this.parameters = parameters; + } + + protected Gost3410KeyParameters( + bool isPrivate, + DerObjectIdentifier publicKeyParamSet) + : base(isPrivate) + { + this.parameters = LookupParameters(publicKeyParamSet); + this.publicKeyParamSet = publicKeyParamSet; + } + + public Gost3410Parameters Parameters + { + get { return parameters; } + } + + public DerObjectIdentifier PublicKeyParamSet + { + get { return publicKeyParamSet; } + } + + // TODO Implement Equals/GetHashCode + + private static Gost3410Parameters LookupParameters( + DerObjectIdentifier publicKeyParamSet) + { + if (publicKeyParamSet == null) + throw new ArgumentNullException("publicKeyParamSet"); + + Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet); + + if (p == null) + throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet"); + + return new Gost3410Parameters(p.P, p.Q, p.A); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/GOST3410Parameters.cs b/iTechSharp/srcbc/crypto/parameters/GOST3410Parameters.cs new file mode 100644 index 0000000..2ec167e --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/GOST3410Parameters.cs @@ -0,0 +1,86 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class Gost3410Parameters + : ICipherParameters + { + private readonly BigInteger p, q, a; + private readonly Gost3410ValidationParameters validation; + + public Gost3410Parameters( + BigInteger p, + BigInteger q, + BigInteger a) + : this(p, q, a, null) + { + } + + public Gost3410Parameters( + BigInteger p, + BigInteger q, + BigInteger a, + Gost3410ValidationParameters validation) + { + if (p == null) + throw new ArgumentNullException("p"); + if (q == null) + throw new ArgumentNullException("q"); + if (a == null) + throw new ArgumentNullException("a"); + + this.p = p; + this.q = q; + this.a = a; + this.validation = validation; + } + + public BigInteger P + { + get { return p; } + } + + public BigInteger Q + { + get { return q; } + } + + public BigInteger A + { + get { return a; } + } + + public Gost3410ValidationParameters ValidationParameters + { + get { return validation; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + Gost3410Parameters other = obj as Gost3410Parameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + Gost3410Parameters other) + { + return p.Equals(other.p) && q.Equals(other.q) && a.Equals(other.a); + } + + public override int GetHashCode() + { + return p.GetHashCode() ^ q.GetHashCode() ^ a.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs new file mode 100644 index 0000000..e3a613d --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs @@ -0,0 +1,41 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class Gost3410PrivateKeyParameters + : Gost3410KeyParameters + { + private readonly BigInteger x; + + public Gost3410PrivateKeyParameters( + BigInteger x, + Gost3410Parameters parameters) + : base(true, parameters) + { + if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0) + throw new ArgumentException("Invalid x for GOST3410 private key", "x"); + + this.x = x; + } + + public Gost3410PrivateKeyParameters( + BigInteger x, + DerObjectIdentifier publicKeyParamSet) + : base(true, publicKeyParamSet) + { + if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0) + throw new ArgumentException("Invalid x for GOST3410 private key", "x"); + + this.x = x; + } + + public BigInteger X + { + get { return x; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs new file mode 100644 index 0000000..96b7e91 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs @@ -0,0 +1,40 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class Gost3410PublicKeyParameters + : Gost3410KeyParameters + { + private readonly BigInteger y; + + public Gost3410PublicKeyParameters( + BigInteger y, + Gost3410Parameters parameters) + : base(false, parameters) + { + if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0) + throw new ArgumentException("Invalid y for GOST3410 public key", "y"); + + this.y = y; + } + + public Gost3410PublicKeyParameters( + BigInteger y, + DerObjectIdentifier publicKeyParamSet) + : base(false, publicKeyParamSet) + { + if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0) + throw new ArgumentException("Invalid y for GOST3410 public key", "y"); + + this.y = y; + } + + public BigInteger Y + { + get { return y; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/GOST3410ValidationParameters.cs b/iTechSharp/srcbc/crypto/parameters/GOST3410ValidationParameters.cs new file mode 100644 index 0000000..21e5af8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/GOST3410ValidationParameters.cs @@ -0,0 +1,51 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class Gost3410ValidationParameters + { + private int x0; + private int c; + private long x0L; + private long cL; + + public Gost3410ValidationParameters( + int x0, + int c) + { + this.x0 = x0; + this.c = c; + } + + public Gost3410ValidationParameters( + long x0L, + long cL) + { + this.x0L = x0L; + this.cL = cL; + } + + public int C { get { return c; } } + public int X0 { get { return x0; } } + public long CL { get { return cL; } } + public long X0L { get { return x0L; } } + + public override bool Equals( + object obj) + { + Gost3410ValidationParameters other = obj as Gost3410ValidationParameters; + + return other != null + && other.c == this.c + && other.x0 == this.x0 + && other.cL == this.cL + && other.x0L == this.x0L; + } + + public override int GetHashCode() + { + return c.GetHashCode() ^ x0.GetHashCode() ^ cL.GetHashCode() ^ x0L.GetHashCode(); + } + + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ISO18033KDFParameters.cs b/iTechSharp/srcbc/crypto/parameters/ISO18033KDFParameters.cs new file mode 100644 index 0000000..2d8fff8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ISO18033KDFParameters.cs @@ -0,0 +1,25 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * parameters for Key derivation functions for ISO-18033 + */ + public class Iso18033KdfParameters + : IDerivationParameters + { + byte[] seed; + + public Iso18033KdfParameters( + byte[] seed) + { + this.seed = seed; + } + + public byte[] GetSeed() + { + return seed; + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/IesParameters.cs b/iTechSharp/srcbc/crypto/parameters/IesParameters.cs new file mode 100644 index 0000000..d306b2c --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/IesParameters.cs @@ -0,0 +1,49 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * parameters for using an integrated cipher in stream mode. + */ + public class IesParameters : ICipherParameters + { + private byte[] derivation; + private byte[] encoding; + private int macKeySize; + + /** + * @param derivation the derivation parameter for the KDF function. + * @param encoding the encoding parameter for the KDF function. + * @param macKeySize the size of the MAC key (in bits). + */ + public IesParameters( + byte[] derivation, + byte[] encoding, + int macKeySize) + { + this.derivation = derivation; + this.encoding = encoding; + this.macKeySize = macKeySize; + } + + public byte[] GetDerivationV() + { + return derivation; + } + + public byte[] GetEncodingV() + { + return encoding; + } + + public int MacKeySize + { + get + { + return macKeySize; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/IesWithCipherParameters.cs b/iTechSharp/srcbc/crypto/parameters/IesWithCipherParameters.cs new file mode 100644 index 0000000..70ef55d --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/IesWithCipherParameters.cs @@ -0,0 +1,33 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class IesWithCipherParameters : IesParameters + { + private int cipherKeySize; + + /** + * @param derivation the derivation parameter for the KDF function. + * @param encoding the encoding parameter for the KDF function. + * @param macKeySize the size of the MAC key (in bits). + * @param cipherKeySize the size of the associated Cipher key (in bits). + */ + public IesWithCipherParameters( + byte[] derivation, + byte[] encoding, + int macKeySize, + int cipherKeySize) : base(derivation, encoding, macKeySize) + { + this.cipherKeySize = cipherKeySize; + } + + public int CipherKeySize + { + get + { + return cipherKeySize; + } + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/KdfParameters.cs b/iTechSharp/srcbc/crypto/parameters/KdfParameters.cs new file mode 100644 index 0000000..bc5c905 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/KdfParameters.cs @@ -0,0 +1,33 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * parameters for Key derivation functions for IEEE P1363a + */ + public class KdfParameters : IDerivationParameters + { + byte[] iv; + byte[] shared; + + public KdfParameters( + byte[] shared, + byte[] iv) + { + this.shared = shared; + this.iv = iv; + } + + public byte[] GetSharedSecret() + { + return shared; + } + + public byte[] GetIV() + { + return iv; + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/KeyParameter.cs b/iTechSharp/srcbc/crypto/parameters/KeyParameter.cs new file mode 100644 index 0000000..33dff96 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/KeyParameter.cs @@ -0,0 +1,43 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class KeyParameter + : ICipherParameters + { + private readonly byte[] key; + + public KeyParameter( + byte[] key) + { + if (key == null) + throw new ArgumentNullException("key"); + + this.key = (byte[]) key.Clone(); + } + + public KeyParameter( + byte[] key, + int keyOff, + int keyLen) + { + if (key == null) + throw new ArgumentNullException("key"); + if (keyOff < 0 || keyOff > key.Length) + throw new ArgumentOutOfRangeException("keyOff"); + if (keyLen < 0 || (keyOff + keyLen) > key.Length) + throw new ArgumentOutOfRangeException("keyLen"); + + this.key = new byte[keyLen]; + Array.Copy(key, keyOff, this.key, 0, keyLen); + } + + public byte[] GetKey() + { + return (byte[]) key.Clone(); + } + } + +} diff --git a/iTechSharp/srcbc/crypto/parameters/MgfParameters.cs b/iTechSharp/srcbc/crypto/parameters/MgfParameters.cs new file mode 100644 index 0000000..11983b8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/MgfParameters.cs @@ -0,0 +1,31 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /// Parameters for mask derivation functions. + public class MgfParameters + : IDerivationParameters + { + private readonly byte[] seed; + + public MgfParameters( + byte[] seed) + : this(seed, 0, seed.Length) + { + } + + public MgfParameters( + byte[] seed, + int off, + int len) + { + this.seed = new byte[len]; + Array.Copy(seed, off, this.seed, 0, len); + } + + public byte[] GetSeed() + { + return (byte[]) seed.Clone(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs new file mode 100644 index 0000000..5b40525 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs @@ -0,0 +1,101 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * Parameters for NaccacheStern public private key generation. For details on + * this cipher, please see + * + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + */ + public class NaccacheSternKeyGenerationParameters : KeyGenerationParameters + { + // private BigInteger publicExponent; + private readonly int certainty; + private readonly int countSmallPrimes; + private bool debug; + + /** + * Parameters for generating a NaccacheStern KeyPair. + * + * @param random + * The source of randomness + * @param strength + * The desired strength of the Key in Bits + * @param certainty + * the probability that the generated primes are not really prime + * as integer: 2^(-certainty) is then the probability + * @param countSmallPrimes + * How many small key factors are desired + */ + public NaccacheSternKeyGenerationParameters( + SecureRandom random, + int strength, + int certainty, + int countSmallPrimes) + : this(random, strength, certainty, countSmallPrimes, false) + { + } + + /** + * Parameters for a NaccacheStern KeyPair. + * + * @param random + * The source of randomness + * @param strength + * The desired strength of the Key in Bits + * @param certainty + * the probability that the generated primes are not really prime + * as integer: 2^(-certainty) is then the probability + * @param cntSmallPrimes + * How many small key factors are desired + * @param debug + * Turn debugging on or off (reveals secret information, use with + * caution) + */ + public NaccacheSternKeyGenerationParameters(SecureRandom random, + int strength, + int certainty, + int countSmallPrimes, + bool debug) + : base(random, strength) + { + if (countSmallPrimes % 2 == 1) + { + throw new ArgumentException("countSmallPrimes must be a multiple of 2"); + } + if (countSmallPrimes < 30) + { + throw new ArgumentException("countSmallPrimes must be >= 30 for security reasons"); + } + this.certainty = certainty; + this.countSmallPrimes = countSmallPrimes; + this.debug = debug; + } + + /** + * @return Returns the certainty. + */ + public int Certainty + { + get { return certainty; } + } + + /** + * @return Returns the countSmallPrimes. + */ + public int CountSmallPrimes + { + get { return countSmallPrimes; } + } + + public bool IsDebug + { + get { return debug; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs new file mode 100644 index 0000000..8be7ad8 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs @@ -0,0 +1,44 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * Public key parameters for NaccacheStern cipher. For details on this cipher, + * please see + * + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + */ + public class NaccacheSternKeyParameters : AsymmetricKeyParameter + { + private readonly BigInteger g, n; + private readonly int lowerSigmaBound; + + /** + * @param privateKey + */ + public NaccacheSternKeyParameters(bool privateKey, BigInteger g, BigInteger n, int lowerSigmaBound) + : base(privateKey) + { + this.g = g; + this.n = n; + this.lowerSigmaBound = lowerSigmaBound; + } + + /** + * @return Returns the g. + */ + public BigInteger G { get { return g; } } + + /** + * @return Returns the lowerSigmaBound. + */ + public int LowerSigmaBound { get { return lowerSigmaBound; } } + + /** + * @return Returns the n. + */ + public BigInteger Modulus { get { return n; } } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs new file mode 100644 index 0000000..bcaa318 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * Private key parameters for NaccacheStern cipher. For details on this cipher, + * please see + * + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + */ + public class NaccacheSternPrivateKeyParameters : NaccacheSternKeyParameters + { + private readonly BigInteger phiN; + private readonly ArrayList smallPrimes; + + /** + * Constructs a NaccacheSternPrivateKey + * + * @param g + * the public enryption parameter g + * @param n + * the public modulus n = p*q + * @param lowerSigmaBound + * the public lower sigma bound up to which data can be encrypted + * @param smallPrimes + * the small primes, of which sigma is constructed in the right + * order + * @param phi_n + * the private modulus phi(n) = (p-1)(q-1) + */ + public NaccacheSternPrivateKeyParameters( + BigInteger g, + BigInteger n, + int lowerSigmaBound, + ArrayList smallPrimes, + BigInteger phiN) + : base(true, g, n, lowerSigmaBound) + { + this.smallPrimes = smallPrimes; + this.phiN = phiN; + } + + public BigInteger PhiN + { + get { return phiN; } + } + + public ArrayList SmallPrimes + { + get { return smallPrimes; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ParametersWithIV.cs b/iTechSharp/srcbc/crypto/parameters/ParametersWithIV.cs new file mode 100644 index 0000000..e00abce --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ParametersWithIV.cs @@ -0,0 +1,44 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ParametersWithIV + : ICipherParameters + { + private readonly ICipherParameters parameters; + private readonly byte[] iv; + + public ParametersWithIV( + ICipherParameters parameters, + byte[] iv) + : this(parameters, iv, 0, iv.Length) + { + } + + public ParametersWithIV( + ICipherParameters parameters, + byte[] iv, + int ivOff, + int ivLen) + { + if (parameters == null) + throw new ArgumentNullException("parameters"); + if (iv == null) + throw new ArgumentNullException("iv"); + + this.parameters = parameters; + this.iv = new byte[ivLen]; + Array.Copy(iv, ivOff, this.iv, 0, ivLen); + } + + public byte[] GetIV() + { + return (byte[]) iv.Clone(); + } + + public ICipherParameters Parameters + { + get { return parameters; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ParametersWithRandom.cs b/iTechSharp/srcbc/crypto/parameters/ParametersWithRandom.cs new file mode 100644 index 0000000..a05e774 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ParametersWithRandom.cs @@ -0,0 +1,48 @@ +using System; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ParametersWithRandom + : ICipherParameters + { + private readonly ICipherParameters parameters; + private readonly SecureRandom random; + + public ParametersWithRandom( + ICipherParameters parameters, + SecureRandom random) + { + if (parameters == null) + throw new ArgumentNullException("random"); + if (random == null) + throw new ArgumentNullException("random"); + + this.parameters = parameters; + this.random = random; + } + + public ParametersWithRandom( + ICipherParameters parameters) + : this(parameters, new SecureRandom()) + { + } + + [Obsolete("Use Random property instead")] + public SecureRandom GetRandom() + { + return Random; + } + + public SecureRandom Random + { + get { return random; } + } + + public ICipherParameters Parameters + { + get { return parameters; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ParametersWithSBox.cs b/iTechSharp/srcbc/crypto/parameters/ParametersWithSBox.cs new file mode 100644 index 0000000..6473796 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ParametersWithSBox.cs @@ -0,0 +1,24 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class ParametersWithSBox : ICipherParameters + { + private ICipherParameters parameters; + private byte[] sBox; + + public ParametersWithSBox( + ICipherParameters parameters, + byte[] sBox) + { + this.parameters = parameters; + this.sBox = sBox; + } + + public byte[] GetSBox() { return sBox; } + + public ICipherParameters Parameters { get { return parameters; } } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/ParametersWithSalt.cs b/iTechSharp/srcbc/crypto/parameters/ParametersWithSalt.cs new file mode 100644 index 0000000..7f4cd6c --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/ParametersWithSalt.cs @@ -0,0 +1,39 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + + /// Cipher parameters with a fixed salt value associated with them. + public class ParametersWithSalt : ICipherParameters + { + private byte[] salt; + private ICipherParameters parameters; + + public ParametersWithSalt(ICipherParameters parameters, byte[] salt):this(parameters, salt, 0, salt.Length) + { + } + + public ParametersWithSalt(ICipherParameters parameters, byte[] salt, int saltOff, int saltLen) + { + this.salt = new byte[saltLen]; + this.parameters = parameters; + + Array.Copy(salt, saltOff, this.salt, 0, saltLen); + } + + public byte[] GetSalt() + { + return salt; + } + + public ICipherParameters Parameters + { + get + { + return parameters; + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/RC2Parameters.cs b/iTechSharp/srcbc/crypto/parameters/RC2Parameters.cs new file mode 100644 index 0000000..7a6d5bb --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/RC2Parameters.cs @@ -0,0 +1,47 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class RC2Parameters + : KeyParameter + { + private readonly int bits; + + public RC2Parameters( + byte[] key) + : this(key, (key.Length > 128) ? 1024 : (key.Length * 8)) + { + } + + public RC2Parameters( + byte[] key, + int keyOff, + int keyLen) + : this(key, keyOff, keyLen, (keyLen > 128) ? 1024 : (keyLen * 8)) + { + } + + public RC2Parameters( + byte[] key, + int bits) + : base(key) + { + this.bits = bits; + } + + public RC2Parameters( + byte[] key, + int keyOff, + int keyLen, + int bits) + : base(key, keyOff, keyLen) + { + this.bits = bits; + } + + public int EffectiveKeyBits + { + get { return bits; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/RC5Parameters.cs b/iTechSharp/srcbc/crypto/parameters/RC5Parameters.cs new file mode 100644 index 0000000..88a59e1 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/RC5Parameters.cs @@ -0,0 +1,27 @@ +using System; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class RC5Parameters + : KeyParameter + { + private readonly int rounds; + + public RC5Parameters( + byte[] key, + int rounds) + : base(key) + { + if (key.Length > 255) + throw new ArgumentException("RC5 key length can be no greater than 255"); + + this.rounds = rounds; + } + + public int Rounds + { + get { return rounds; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/RSABlindingParameters.cs b/iTechSharp/srcbc/crypto/parameters/RSABlindingParameters.cs new file mode 100644 index 0000000..49c7bcc --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/RSABlindingParameters.cs @@ -0,0 +1,34 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class RsaBlindingParameters + : ICipherParameters + { + private readonly RsaKeyParameters publicKey; + private readonly BigInteger blindingFactor; + + public RsaBlindingParameters( + RsaKeyParameters publicKey, + BigInteger blindingFactor) + { + if (publicKey.IsPrivate) + throw new ArgumentException("RSA parameters should be for a public key"); + + this.publicKey = publicKey; + this.blindingFactor = blindingFactor; + } + + public RsaKeyParameters PublicKey + { + get { return publicKey; } + } + + public BigInteger BlindingFactor + { + get { return blindingFactor; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs b/iTechSharp/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs new file mode 100644 index 0000000..619ab65 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs @@ -0,0 +1,55 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class RsaKeyGenerationParameters + : KeyGenerationParameters + { + private readonly BigInteger publicExponent; + private readonly int certainty; + + public RsaKeyGenerationParameters( + BigInteger publicExponent, + SecureRandom random, + int strength, + int certainty) + : base(random, strength) + { + this.publicExponent = publicExponent; + this.certainty = certainty; + } + + public BigInteger PublicExponent + { + get { return publicExponent; } + } + + public int Certainty + { + get { return certainty; } + } + + public override bool Equals( + object obj) + { + RsaKeyGenerationParameters other = obj as RsaKeyGenerationParameters; + + if (other == null) + { + return false; + } + + return certainty == other.certainty + && publicExponent.Equals(other.publicExponent); + } + + public override int GetHashCode() + { + return certainty.GetHashCode() ^ publicExponent.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/RsaKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/RsaKeyParameters.cs new file mode 100644 index 0000000..d19a46c --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/RsaKeyParameters.cs @@ -0,0 +1,54 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class RsaKeyParameters + : AsymmetricKeyParameter + { + private readonly BigInteger modulus; + private readonly BigInteger exponent; + + public RsaKeyParameters( + bool isPrivate, + BigInteger modulus, + BigInteger exponent) + : base(isPrivate) + { + this.modulus = modulus; + this.exponent = exponent; + } + + public BigInteger Modulus + { + get { return modulus; } + } + + public BigInteger Exponent + { + get { return exponent; } + } + + public override bool Equals( + object obj) + { + RsaKeyParameters kp = obj as RsaKeyParameters; + + if (kp == null) + { + return false; + } + + return kp.IsPrivate == this.IsPrivate + && kp.Modulus.Equals(this.modulus) + && kp.Exponent.Equals(this.exponent); + } + + public override int GetHashCode() + { + return modulus.GetHashCode() ^ exponent.GetHashCode() ^ IsPrivate.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs b/iTechSharp/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs new file mode 100644 index 0000000..0f1f399 --- /dev/null +++ b/iTechSharp/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs @@ -0,0 +1,89 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + public class RsaPrivateCrtKeyParameters + : RsaKeyParameters + { + private readonly BigInteger e, p, q, dP, dQ, qInv; + + public RsaPrivateCrtKeyParameters( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger p, + BigInteger q, + BigInteger dP, + BigInteger dQ, + BigInteger qInv) + : base(true, modulus, privateExponent) + { + this.e = publicExponent; + this.p = p; + this.q = q; + this.dP = dP; + this.dQ = dQ; + this.qInv = qInv; + } + + public BigInteger PublicExponent + { + get { return e; } + } + + public BigInteger P + { + get { return p; } + } + + public BigInteger Q + { + get { return q; } + } + + public BigInteger DP + { + get { return dP; } + } + + public BigInteger DQ + { + get { return dQ; } + } + + public BigInteger QInv + { + get { return qInv; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + RsaPrivateCrtKeyParameters kp = obj as RsaPrivateCrtKeyParameters; + + if (kp == null) + return false; + + return kp.DP.Equals(dP) + && kp.DQ.Equals(dQ) + && kp.Exponent.Equals(this.Exponent) + && kp.Modulus.Equals(this.Modulus) + && kp.P.Equals(p) + && kp.Q.Equals(q) + && kp.PublicExponent.Equals(e) + && kp.QInv.Equals(qInv); + } + + public override int GetHashCode() + { + return DP.GetHashCode() ^ DQ.GetHashCode() ^ Exponent.GetHashCode() ^ Modulus.GetHashCode() + ^ P.GetHashCode() ^ Q.GetHashCode() ^ PublicExponent.GetHashCode() ^ QInv.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/prng/CryptoApiRandomGenerator.cs b/iTechSharp/srcbc/crypto/prng/CryptoApiRandomGenerator.cs new file mode 100644 index 0000000..815fd0b --- /dev/null +++ b/iTechSharp/srcbc/crypto/prng/CryptoApiRandomGenerator.cs @@ -0,0 +1,61 @@ +#if !NETCF_1_0 + +using System; +using System.Security.Cryptography; + +namespace Org.BouncyCastle.Crypto.Prng +{ + /// + /// Uses Microsoft's RNGCryptoServiceProvider + /// + public class CryptoApiRandomGenerator + : IRandomGenerator + { + private readonly RNGCryptoServiceProvider rndProv; + + public CryptoApiRandomGenerator() + { + rndProv = new RNGCryptoServiceProvider(); + } + + #region IRandomGenerator Members + + public virtual void AddSeedMaterial(byte[] seed) + { + // We don't care about the seed + } + + public virtual void AddSeedMaterial(long seed) + { + // We don't care about the seed + } + + public virtual void NextBytes(byte[] bytes) + { + rndProv.GetBytes(bytes); + } + + public virtual void NextBytes(byte[] bytes, int start, int len) + { + if (start < 0) + throw new ArgumentException("Start offset cannot be negative", "start"); + if (bytes.Length < (start + len)) + throw new ArgumentException("Byte array too small for requested offset and length"); + + if (bytes.Length == len && start == 0) + { + NextBytes(bytes); + } + else + { + byte[] tmpBuf = new byte[len]; + rndProv.GetBytes(tmpBuf); + Array.Copy(tmpBuf, 0, bytes, start, len); + } + } + + #endregion + } +} + +#endif diff --git a/iTechSharp/srcbc/crypto/prng/DigestRandomGenerator.cs b/iTechSharp/srcbc/crypto/prng/DigestRandomGenerator.cs new file mode 100644 index 0000000..8417a44 --- /dev/null +++ b/iTechSharp/srcbc/crypto/prng/DigestRandomGenerator.cs @@ -0,0 +1,107 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; + +namespace Org.BouncyCastle.Crypto.Prng +{ + /** + * Random generation based on the digest with counter. Calling addSeedMaterial will + * always increase the entropy of the hash. + *

      + * Internal access to the digest is syncrhonized so a single one of these can be shared. + *

      + */ + public class DigestRandomGenerator + : IRandomGenerator + { + private long counter; + private IDigest digest; + private byte[] state; + + public DigestRandomGenerator( + IDigest digest) + { + this.digest = digest; + this.state = new byte[digest.GetDigestSize()]; + this.counter = 1; + } + + public void AddSeedMaterial( + byte[] inSeed) + { + lock (this) + { + DigestUpdate(inSeed); + } + } + + public void AddSeedMaterial( + long rSeed) + { + lock (this) + { + for (int i = 0; i != 8; i++) + { + DigestUpdate((byte)rSeed); +// rSeed >>>= 8; + rSeed >>= 8; + } + } + } + + public void NextBytes( + byte[] bytes) + { + NextBytes(bytes, 0, bytes.Length); + } + + public void NextBytes( + byte[] bytes, + int start, + int len) + { + lock (this) + { + int stateOff = 0; + + DigestDoFinal(state); + + int end = start + len; + for (int i = start; i < end; ++i) + { + if (stateOff == state.Length) + { + DigestUpdate(counter++); + DigestUpdate(state); + DigestDoFinal(state); + stateOff = 0; + } + bytes[i] = state[stateOff++]; + } + + DigestUpdate(counter++); + DigestUpdate(state); + } + } + + private void DigestUpdate(long seed) + { + for (int i = 0; i != 8; i++) + { + digest.Update((byte)seed); +// seed >>>= 8; + seed >>= 8; + } + } + + private void DigestUpdate(byte[] inSeed) + { + digest.BlockUpdate(inSeed, 0, inSeed.Length); + } + + private void DigestDoFinal(byte[] result) + { + digest.DoFinal(result, 0); + } + } +} diff --git a/iTechSharp/srcbc/crypto/prng/IRandomGenerator.cs b/iTechSharp/srcbc/crypto/prng/IRandomGenerator.cs new file mode 100644 index 0000000..8dbe406 --- /dev/null +++ b/iTechSharp/srcbc/crypto/prng/IRandomGenerator.cs @@ -0,0 +1,26 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Prng +{ + /// Generic interface for objects generating random bytes. + public interface IRandomGenerator + { + /// Add more seed material to the generator. + /// A byte array to be mixed into the generator's state. + void AddSeedMaterial(byte[] seed); + + /// Add more seed material to the generator. + /// A long value to be mixed into the generator's state. + void AddSeedMaterial(long seed); + + /// Fill byte array with random values. + /// Array to be filled. + void NextBytes(byte[] bytes); + + /// Fill byte array with random values. + /// Array to receive bytes. + /// Index to start filling at. + /// Length of segment to fill. + void NextBytes(byte[] bytes, int start, int len); + } +} diff --git a/iTechSharp/srcbc/crypto/prng/ReversedWindowGenerator.cs b/iTechSharp/srcbc/crypto/prng/ReversedWindowGenerator.cs new file mode 100644 index 0000000..dd28c52 --- /dev/null +++ b/iTechSharp/srcbc/crypto/prng/ReversedWindowGenerator.cs @@ -0,0 +1,98 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Prng +{ + /// + /// Takes bytes generated by an underling RandomGenerator and reverses the order in + /// each small window (of configurable size). + ///

      + /// Access to internals is synchronized so a single one of these can be shared. + ///

      + ///
      + public class ReversedWindowGenerator + : IRandomGenerator + { + private readonly IRandomGenerator generator; + + private byte[] window; + private int windowCount; + + public ReversedWindowGenerator( + IRandomGenerator generator, + int windowSize) + { + if (generator == null) + throw new ArgumentNullException("generator"); + if (windowSize < 2) + throw new ArgumentException("Window size must be at least 2", "windowSize"); + + this.generator = generator; + this.window = new byte[windowSize]; + } + + /// Add more seed material to the generator. + /// A byte array to be mixed into the generator's state. + public virtual void AddSeedMaterial( + byte[] seed) + { + lock (this) + { + windowCount = 0; + generator.AddSeedMaterial(seed); + } + } + + /// Add more seed material to the generator. + /// A long value to be mixed into the generator's state. + public virtual void AddSeedMaterial( + long seed) + { + lock (this) + { + windowCount = 0; + generator.AddSeedMaterial(seed); + } + } + + /// Fill byte array with random values. + /// Array to be filled. + public virtual void NextBytes( + byte[] bytes) + { + doNextBytes(bytes, 0, bytes.Length); + } + + /// Fill byte array with random values. + /// Array to receive bytes. + /// Index to start filling at. + /// Length of segment to fill. + public virtual void NextBytes( + byte[] bytes, + int start, + int len) + { + doNextBytes(bytes, start, len); + } + + private void doNextBytes( + byte[] bytes, + int start, + int len) + { + lock (this) + { + int done = 0; + while (done < len) + { + if (windowCount < 1) + { + generator.NextBytes(window, 0, window.Length); + windowCount = window.Length; + } + + bytes[start + done++] = window[--windowCount]; + } + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/prng/ThreadedSeedGenerator.cs b/iTechSharp/srcbc/crypto/prng/ThreadedSeedGenerator.cs new file mode 100644 index 0000000..86e8a43 --- /dev/null +++ b/iTechSharp/srcbc/crypto/prng/ThreadedSeedGenerator.cs @@ -0,0 +1,97 @@ +using System; +using System.Threading; + +namespace Org.BouncyCastle.Crypto.Prng +{ + /** + * A thread based seed generator - one source of randomness. + *

      + * Based on an idea from Marcus Lippert. + *

      + */ + public class ThreadedSeedGenerator + { + private class SeedGenerator + { +#if NETCF_1_0 + // No volatile keyword, but all fields implicitly volatile anyway + private int counter = 0; + private bool stop = false; +#else + private volatile int counter = 0; + private volatile bool stop = false; +#endif + + private void Run(object ignored) + { + while (!this.stop) + { + this.counter++; + } + } + + public byte[] GenerateSeed( + int numBytes, + bool fast) + { + this.counter = 0; + this.stop = false; + + byte[] result = new byte[numBytes]; + int last = 0; + int end = fast ? numBytes : numBytes * 8; + + ThreadPool.QueueUserWorkItem(new WaitCallback(Run)); + + for (int i = 0; i < end; i++) + { + while (this.counter == last) + { + try + { + Thread.Sleep(1); + } + catch (Exception) + { + // ignore + } + } + + last = this.counter; + + if (fast) + { + result[i] = (byte) last; + } + else + { + int bytepos = i / 8; + result[bytepos] = (byte) ((result[bytepos] << 1) | (last & 1)); + } + } + + this.stop = true; + + return result; + } + } + + /** + * Generate seed bytes. Set fast to false for best quality. + *

      + * If fast is set to true, the code should be round about 8 times faster when + * generating a long sequence of random bytes. 20 bytes of random values using + * the fast mode take less than half a second on a Nokia e70. If fast is set to false, + * it takes round about 2500 ms. + *

      + * @param numBytes the number of bytes to generate + * @param fast true if fast mode should be used + */ + public byte[] GenerateSeed( + int numBytes, + bool fast) + { + return new SeedGenerator().GenerateSeed(numBytes, fast); + } + } +} diff --git a/iTechSharp/srcbc/crypto/prng/VMPCRandomGenerator.cs b/iTechSharp/srcbc/crypto/prng/VMPCRandomGenerator.cs new file mode 100644 index 0000000..2ab0799 --- /dev/null +++ b/iTechSharp/srcbc/crypto/prng/VMPCRandomGenerator.cs @@ -0,0 +1,115 @@ +namespace Org.BouncyCastle.Crypto.Prng +{ + public class VmpcRandomGenerator + : IRandomGenerator + { + private byte n = 0; + + /// + /// Permutation generated by code: + /// + /// // First 1850 fractional digit of Pi number. + /// byte[] key = new BigInteger("14159265358979323846...5068006422512520511").ToByteArray(); + /// s = 0; + /// P = new byte[256]; + /// for (int i = 0; i < 256; i++) + /// { + /// P[i] = (byte) i; + /// } + /// for (int m = 0; m < 768; m++) + /// { + /// s = P[(s + P[m & 0xff] + key[m % key.length]) & 0xff]; + /// byte temp = P[m & 0xff]; + /// P[m & 0xff] = P[s & 0xff]; + /// P[s & 0xff] = temp; + /// } + /// + private byte[] P = + { + (byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f, (byte) 0xb5, (byte) 0xaa, (byte) 0xd4, + (byte) 0x0d, (byte) 0x81, (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0, (byte) 0xa1, + (byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56, (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10, + (byte) 0xc4, (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80, (byte) 0x12, (byte) 0xb8, + (byte) 0x69, (byte) 0xda, (byte) 0x2f, (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36, + (byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0, (byte) 0xdd, (byte) 0x05, (byte) 0x43, + (byte) 0x90, (byte) 0xad, (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b, (byte) 0x4c, + (byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50, (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4, + (byte) 0xf3, (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9, (byte) 0x83, (byte) 0x97, + (byte) 0x46, (byte) 0xb1, (byte) 0x99, (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d, + (byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0, (byte) 0x8a, (byte) 0x22, (byte) 0x38, + (byte) 0xf8, (byte) 0x68, (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7, (byte) 0xbc, + (byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5, (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86, + (byte) 0xa6, (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e, (byte) 0xd7, (byte) 0x40, + (byte) 0xb3, (byte) 0xcf, (byte) 0x7e, (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c, + (byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58, (byte) 0x11, (byte) 0x27, (byte) 0xf4, + (byte) 0x59, (byte) 0xd0, (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac, (byte) 0xff, + (byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79, (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76, + (byte) 0x42, (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a, (byte) 0x30, (byte) 0x28, + (byte) 0x0f, (byte) 0x73, (byte) 0x01, (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9, + (byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41, (byte) 0x6d, (byte) 0xb4, (byte) 0xc3, + (byte) 0x9e, (byte) 0xbf, (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60, (byte) 0x47, + (byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a, (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37, + (byte) 0x4b, (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6, (byte) 0x39, (byte) 0x8b, + (byte) 0xb7, (byte) 0x0c, (byte) 0x20, (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74, + (byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2, (byte) 0x87, (byte) 0xf5, (byte) 0xeb, + (byte) 0x70, (byte) 0xe3, (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44, (byte) 0x4a, + (byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b, (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9, + (byte) 0x8c, (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e, (byte) 0x9d, (byte) 0xdc, + (byte) 0x67, (byte) 0x48, (byte) 0xba, (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c, + (byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea, (byte) 0xbe, (byte) 0xca, (byte) 0x72, + (byte) 0x4f, (byte) 0x52, (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b, (byte) 0x3b, + (byte) 0x54 + }; + + /// Value generated in the same way as P. + private byte s = (byte) 0xbe; + + public VmpcRandomGenerator() + { + } + + public virtual void AddSeedMaterial(byte[] seed) + { + for (int m = 0; m < seed.Length; m++) + { + s = P[(s + P[n & 0xff] + seed[m]) & 0xff]; + byte temp = P[n & 0xff]; + P[n & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + n = (byte) ((n + 1) & 0xff); + } + } + + public virtual void AddSeedMaterial(long seed) + { + byte[] s = new byte[4]; + s[3] = (byte) (seed & 0x000000ff); + s[2] = (byte) ((seed & 0x0000ff00) >> 8); + s[1] = (byte) ((seed & 0x00ff0000) >> 16); + s[0] = (byte) ((seed & 0xff000000) >> 24); + AddSeedMaterial(s); + } + + public virtual void NextBytes(byte[] bytes) + { + NextBytes(bytes, 0, bytes.Length); + } + + public virtual void NextBytes(byte[] bytes, int start, int len) + { + lock (P) + { + int end = start + len; + for (int i = start; i != end; i++) + { + s = P[(s + P[n & 0xff]) & 0xff]; + bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]; + byte temp = P[n & 0xff]; + P[n & 0xff] = P[s & 0xff]; + P[s & 0xff] = temp; + n = (byte) ((n + 1) & 0xff); + } + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/DsaDigestSigner.cs b/iTechSharp/srcbc/crypto/signers/DsaDigestSigner.cs new file mode 100644 index 0000000..12e786b --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/DsaDigestSigner.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + public class DsaDigestSigner + : ISigner + { + private readonly IDigest digest; + private readonly IDsa dsaSigner; + private bool forSigning; + + public DsaDigestSigner( + IDsa signer, + IDigest digest) + { + this.digest = digest; + this.dsaSigner = signer; + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + this.forSigning = forSigning; + + AsymmetricKeyParameter k; + + if (parameters is ParametersWithRandom) + { + k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters; + } + else + { + k = (AsymmetricKeyParameter)parameters; + } + + if (forSigning && !k.IsPrivate) + { + throw new InvalidKeyException("Signing Requires Private Key."); + } + + if (!forSigning && k.IsPrivate) + { + throw new InvalidKeyException("Verification Requires Public Key."); + } + + Reset(); + + dsaSigner.Init(forSigning, parameters); + } + + /** + * update the internal digest with the byte b + */ + public void Update( + byte input) + { + digest.Update(input); + } + + /** + * update the internal digest with the byte array in + */ + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + digest.BlockUpdate(input, inOff, length); + } + + /** + * Generate a signature for the message we've been loaded with using + * the key we were initialised with. + */ + public byte[] GenerateSignature() + { + if (!forSigning) + throw new InvalidOperationException("DSADigestSigner not initialised for signature generation."); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + try + { + BigInteger[] sig = dsaSigner.GenerateSignature(hash); + + return DerEncode(sig[0], sig[1]); + } + catch (Exception e) + { + throw new SignatureException(e.Message, e); + } + } + + /// true if the internal state represents the signature described in the passed in array. + public bool VerifySignature( + byte[] signature) + { + if (forSigning) + throw new InvalidOperationException("DSADigestSigner not initialised for verification"); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + BigInteger[] sig; + try + { + sig = DerDecode(signature); + } + catch (Exception e) + { + throw new SignatureException("error decoding signature bytes.", e); + } + + return dsaSigner.VerifySignature(hash, sig[0], sig[1]); + } + + /// Reset the internal state + public void Reset() + { + digest.Reset(); + } + + private byte[] DerEncode( + BigInteger r, + BigInteger s) + { + return new DerSequence(new DerInteger(r), new DerInteger(s)).GetDerEncoded(); + } + + private BigInteger[] DerDecode( + byte[] encoding) + { + Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding); + + return new BigInteger[] + { + ((DerInteger) s[0]).Value, + ((DerInteger) s[1]).Value + }; + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/DsaSigner.cs b/iTechSharp/srcbc/crypto/signers/DsaSigner.cs new file mode 100644 index 0000000..419b197 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/DsaSigner.cs @@ -0,0 +1,136 @@ +using System; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * The Digital Signature Algorithm - as described in "Handbook of Applied + * Cryptography", pages 452 - 453. + */ + public class DsaSigner + : IDsa + { + private DsaKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "DSA"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is DsaPrivateKeyParameters)) + throw new InvalidKeyException("DSA private key required for signing"); + + this.key = (DsaPrivateKeyParameters) parameters; + } + else + { + if (!(parameters is DsaPublicKeyParameters)) + throw new InvalidKeyException("DSA public key required for verification"); + + this.key = (DsaPublicKeyParameters) parameters; + } + } + + /** + * Generate a signature for the given message using the key we were + * initialised with. For conventional DSA the message should be a SHA-1 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + DsaParameters parameters = key.Parameters; + BigInteger q = parameters.Q; + BigInteger m = calculateE(q, message); + BigInteger k; + + do + { + k = new BigInteger(q.BitLength, random); + } + while (k.CompareTo(q) >= 0); + + BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q); + + k = k.ModInverse(q).Multiply( + m.Add(((DsaPrivateKeyParameters)key).X.Multiply(r))); + + BigInteger s = k.Mod(q); + + return new BigInteger[]{ r, s }; + } + + /** + * return true if the value r and s represent a DSA signature for + * the passed in message for standard DSA the message should be a + * SHA-1 hash of the real message to be verified. + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + DsaParameters parameters = key.Parameters; + BigInteger q = parameters.Q; + BigInteger m = calculateE(q, message); + + if (r.SignValue <= 0 || q.CompareTo(r) <= 0) + { + return false; + } + + if (s.SignValue <= 0 || q.CompareTo(s) <= 0) + { + return false; + } + + BigInteger w = s.ModInverse(q); + + BigInteger u1 = m.Multiply(w).Mod(q); + BigInteger u2 = r.Multiply(w).Mod(q); + + BigInteger p = parameters.P; + u1 = parameters.G.ModPow(u1, p); + u2 = ((DsaPublicKeyParameters)key).Y.ModPow(u2, p); + + BigInteger v = u1.Multiply(u2).Mod(p).Mod(q); + + return v.Equals(r); + } + + private BigInteger calculateE( + BigInteger n, + byte[] message) + { + int length = System.Math.Min(message.Length, n.BitLength / 8); + + return new BigInteger(1, message, 0, length); + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/ECDsaSigner.cs b/iTechSharp/srcbc/crypto/signers/ECDsaSigner.cs new file mode 100644 index 0000000..a116caf --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/ECDsaSigner.cs @@ -0,0 +1,150 @@ +using System; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * EC-DSA as described in X9.62 + */ + public class ECDsaSigner + : IDsa + { + private ECKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "ECDSA"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom) parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is ECPrivateKeyParameters)) + throw new InvalidKeyException("EC private key required for signing"); + + this.key = (ECPrivateKeyParameters) parameters; + } + else + { + if (!(parameters is ECPublicKeyParameters)) + throw new InvalidKeyException("EC public key required for verification"); + + this.key = (ECPublicKeyParameters) parameters; + } + } + + // 5.3 pg 28 + /** + * Generate a signature for the given message using the key we were + * initialised with. For conventional DSA the message should be a SHA-1 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + BigInteger n = key.Parameters.N; + BigInteger e = calculateE(n, message); + + BigInteger r = null; + BigInteger s = null; + + // 5.3.2 + do // Generate s + { + BigInteger k = null; + + do // Generate r + { + do + { + k = new BigInteger(n.BitLength, random); + } + while (k.SignValue == 0); + + ECPoint p = key.Parameters.G.Multiply(k); + + // 5.3.3 + BigInteger x = p.X.ToBigInteger(); + + r = x.Mod(n); + } + while (r.SignValue == 0); + + BigInteger d = ((ECPrivateKeyParameters)key).D; + + s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n); + } + while (s.SignValue == 0); + + return new BigInteger[]{ r, s }; + } + + // 5.4 pg 29 + /** + * return true if the value r and s represent a DSA signature for + * the passed in message (for standard DSA the message should be + * a SHA-1 hash of the real message to be verified). + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + BigInteger n = key.Parameters.N; + + // r and s should both in the range [1,n-1] + if (r.SignValue < 1 || s.SignValue < 1 + || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0) + { + return false; + } + + BigInteger e = calculateE(n, message); + BigInteger c = s.ModInverse(n); + + BigInteger u1 = e.Multiply(c).Mod(n); + BigInteger u2 = r.Multiply(c).Mod(n); + + ECPoint G = key.Parameters.G; + ECPoint Q = ((ECPublicKeyParameters) key).Q; + + ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2); + + BigInteger v = point.X.ToBigInteger().Mod(n); + + return v.Equals(r); + } + + private BigInteger calculateE( + BigInteger n, + byte[] message) + { + int length = System.Math.Min(message.Length, n.BitLength / 8); + + return new BigInteger(1, message, 0, length); + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/ECGOST3410Signer.cs b/iTechSharp/srcbc/crypto/signers/ECGOST3410Signer.cs new file mode 100644 index 0000000..d68b83f --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/ECGOST3410Signer.cs @@ -0,0 +1,154 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * GOST R 34.10-2001 Signature Algorithm + */ + public class ECGost3410Signer + : IDsa + { + private ECKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "ECGOST3410"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is ECPrivateKeyParameters)) + throw new InvalidKeyException("EC private key required for signing"); + + this.key = (ECPrivateKeyParameters) parameters; + } + else + { + if (!(parameters is ECPublicKeyParameters)) + throw new InvalidKeyException("EC public key required for verification"); + + this.key = (ECPublicKeyParameters)parameters; + } + } + + /** + * generate a signature for the given message using the key we were + * initialised with. For conventional GOST3410 the message should be a GOST3411 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + byte[] mRev = new byte[message.Length]; // conversion is little-endian + for (int i = 0; i != mRev.Length; i++) + { + mRev[i] = message[mRev.Length - 1 - i]; + } + + BigInteger e = new BigInteger(1, mRev); + BigInteger n = key.Parameters.N; + + BigInteger r = null; + BigInteger s = null; + + do // generate s + { + BigInteger k = null; + + do // generate r + { + do + { + k = new BigInteger(n.BitLength, random); + } + while (k.SignValue == 0); + + ECPoint p = key.Parameters.G.Multiply(k); + + BigInteger x = p.X.ToBigInteger(); + + r = x.Mod(n); + } + while (r.SignValue == 0); + + BigInteger d = ((ECPrivateKeyParameters)key).D; + + s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n); + } + while (s.SignValue == 0); + + return new BigInteger[]{ r, s }; + } + + /** + * return true if the value r and s represent a GOST3410 signature for + * the passed in message (for standard GOST3410 the message should be + * a GOST3411 hash of the real message to be verified). + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + byte[] mRev = new byte[message.Length]; // conversion is little-endian + for (int i = 0; i != mRev.Length; i++) + { + mRev[i] = message[mRev.Length - 1 - i]; + } + + BigInteger e = new BigInteger(1, mRev); + BigInteger n = key.Parameters.N; + + // r in the range [1,n-1] + if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0) + { + return false; + } + + // s in the range [1,n-1] + if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0) + { + return false; + } + + BigInteger v = e.ModInverse(n); + + BigInteger z1 = s.Multiply(v).Mod(n); + BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n); + + ECPoint G = key.Parameters.G; // P + ECPoint Q = ((ECPublicKeyParameters)key).Q; + + ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2); + + BigInteger R = point.X.ToBigInteger().Mod(n); + + return R.Equals(r); + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/ECNRSigner.cs b/iTechSharp/srcbc/crypto/signers/ECNRSigner.cs new file mode 100644 index 0000000..63865d7 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/ECNRSigner.cs @@ -0,0 +1,186 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * EC-NR as described in IEEE 1363-2000 + */ + public class ECNRSigner + : IDsa + { + private bool forSigning; + private ECKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "ECNR"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + this.forSigning = forSigning; + + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom) parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is ECPrivateKeyParameters)) + throw new InvalidKeyException("EC private key required for signing"); + + this.key = (ECPrivateKeyParameters) parameters; + } + else + { + if (!(parameters is ECPublicKeyParameters)) + throw new InvalidKeyException("EC public key required for verification"); + + this.key = (ECPublicKeyParameters) parameters; + } + } + + // Section 7.2.5 ECSP-NR, pg 34 + /** + * generate a signature for the given message using the key we were + * initialised with. Generally, the order of the curve should be at + * least as long as the hash of the message of interest, and with + * ECNR it *must* be at least as long. + * + * @param digest the digest to be signed. + * @exception DataLengthException if the digest is longer than the key allows + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + if (!this.forSigning) + { + // not properly initilaized... deal with it + throw new InvalidOperationException("not initialised for signing"); + } + + BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N; + int nBitLength = n.BitLength; + + BigInteger e = new BigInteger(1, message); + int eBitLength = e.BitLength; + + ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)key; + + if (eBitLength > nBitLength) + { + throw new DataLengthException("input too large for ECNR key."); + } + + BigInteger r = null; + BigInteger s = null; + + AsymmetricCipherKeyPair tempPair; + do // generate r + { + // generate another, but very temporary, key pair using + // the same EC parameters + ECKeyPairGenerator keyGen = new ECKeyPairGenerator(); + + keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random)); + + tempPair = keyGen.GenerateKeyPair(); + + // BigInteger Vx = tempPair.getPublic().getW().getAffineX(); + ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key + BigInteger Vx = V.Q.X.ToBigInteger(); // get the point's x coordinate + + r = Vx.Add(e).Mod(n); + } + while (r.SignValue == 0); + + // generate s + BigInteger x = privKey.D; // private key value + BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value + s = u.Subtract(r.Multiply(x)).Mod(n); + + return new BigInteger[]{ r, s }; + } + + // Section 7.2.6 ECVP-NR, pg 35 + /** + * return true if the value r and s represent a signature for the + * message passed in. Generally, the order of the curve should be at + * least as long as the hash of the message of interest, and with + * ECNR, it *must* be at least as long. But just in case the signer + * applied mod(n) to the longer digest, this implementation will + * apply mod(n) during verification. + * + * @param digest the digest to be verified. + * @param r the r value of the signature. + * @param s the s value of the signature. + * @exception DataLengthException if the digest is longer than the key allows + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + if (this.forSigning) + { + // not properly initilaized... deal with it + throw new InvalidOperationException("not initialised for verifying"); + } + + ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key; + BigInteger n = pubKey.Parameters.N; + int nBitLength = n.BitLength; + + BigInteger e = new BigInteger(1, message); + int eBitLength = e.BitLength; + + if (eBitLength > nBitLength) + { + throw new DataLengthException("input too large for ECNR key."); + } + + // r in the range [1,n-1] + if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0) + { + return false; + } + + // TODO So why is this different from the spec? + // s in the range [0,n-1] NB: ECNR spec says 0 + if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0) + { + return false; + } + + // compute P = sG + rW + + ECPoint G = pubKey.Parameters.G; + ECPoint W = pubKey.Q; + // calculate P using Bouncy math + ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r); + + BigInteger x = P.X.ToBigInteger(); + BigInteger t = r.Subtract(x).Mod(n); + + return t.Equals(e); + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/GOST3410DigestSigner.cs b/iTechSharp/srcbc/crypto/signers/GOST3410DigestSigner.cs new file mode 100644 index 0000000..58aefa3 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/GOST3410DigestSigner.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + public class Gost3410DigestSigner + : ISigner + { + private readonly IDigest digest; + private readonly IDsa dsaSigner; + private bool forSigning; + + public Gost3410DigestSigner( + IDsa signer, + IDigest digest) + { + this.dsaSigner = signer; + this.digest = digest; + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + this.forSigning = forSigning; + + AsymmetricKeyParameter k; + if (parameters is ParametersWithRandom) + { + k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters; + } + else + { + k = (AsymmetricKeyParameter)parameters; + } + + if (forSigning && !k.IsPrivate) + { + throw new InvalidKeyException("Signing Requires Private Key."); + } + + if (!forSigning && k.IsPrivate) + { + throw new InvalidKeyException("Verification Requires Public Key."); + } + + Reset(); + + dsaSigner.Init(forSigning, parameters); + } + + /** + * update the internal digest with the byte b + */ + public void Update( + byte input) + { + digest.Update(input); + } + + /** + * update the internal digest with the byte array in + */ + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + digest.BlockUpdate(input, inOff, length); + } + + /** + * Generate a signature for the message we've been loaded with using + * the key we were initialised with. + */ + public byte[] GenerateSignature() + { + if (!forSigning) + throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation."); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + try + { + BigInteger[] sig = dsaSigner.GenerateSignature(hash); + byte[] sigBytes = new byte[64]; + + // TODO Add methods to allow writing BigInteger to existing byte array? + byte[] r = sig[0].ToByteArrayUnsigned(); + byte[] s = sig[1].ToByteArrayUnsigned(); + s.CopyTo(sigBytes, 32 - s.Length); + r.CopyTo(sigBytes, 64 - r.Length); + return sigBytes; + } + catch (Exception e) + { + throw new SignatureException(e.Message, e); + } + } + + /// true if the internal state represents the signature described in the passed in array. + public bool VerifySignature( + byte[] signature) + { + if (forSigning) + throw new InvalidOperationException("DSADigestSigner not initialised for verification"); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + BigInteger R, S; + try + { + R = new BigInteger(1, signature, 32, 32); + S = new BigInteger(1, signature, 0, 32); + } + catch (Exception e) + { + throw new SignatureException("error decoding signature bytes.", e); + } + + return dsaSigner.VerifySignature(hash, R, S); + } + + /// Reset the internal state + public void Reset() + { + digest.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/GOST3410Signer.cs b/iTechSharp/srcbc/crypto/signers/GOST3410Signer.cs new file mode 100644 index 0000000..375eeb5 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/GOST3410Signer.cs @@ -0,0 +1,132 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * Gost R 34.10-94 Signature Algorithm + */ + public class Gost3410Signer + : IDsa + { + private Gost3410KeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "GOST3410"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is Gost3410PrivateKeyParameters)) + throw new InvalidKeyException("GOST3410 private key required for signing"); + + this.key = (Gost3410PrivateKeyParameters) parameters; + } + else + { + if (!(parameters is Gost3410PublicKeyParameters)) + throw new InvalidKeyException("GOST3410 public key required for signing"); + + this.key = (Gost3410PublicKeyParameters) parameters; + } + } + + /** + * generate a signature for the given message using the key we were + * initialised with. For conventional Gost3410 the message should be a Gost3411 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + byte[] mRev = new byte[message.Length]; // conversion is little-endian + for (int i = 0; i != mRev.Length; i++) + { + mRev[i] = message[mRev.Length - 1 - i]; + } + + BigInteger m = new BigInteger(1, mRev); + Gost3410Parameters parameters = key.Parameters; + BigInteger k; + + do + { + k = new BigInteger(parameters.Q.BitLength, random); + } + while (k.CompareTo(parameters.Q) >= 0); + + BigInteger r = parameters.A.ModPow(k, parameters.P).Mod(parameters.Q); + + BigInteger s = k.Multiply(m). + Add(((Gost3410PrivateKeyParameters)key).X.Multiply(r)). + Mod(parameters.Q); + + return new BigInteger[]{ r, s }; + } + + /** + * return true if the value r and s represent a Gost3410 signature for + * the passed in message for standard Gost3410 the message should be a + * Gost3411 hash of the real message to be verified. + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + byte[] mRev = new byte[message.Length]; // conversion is little-endian + for (int i = 0; i != mRev.Length; i++) + { + mRev[i] = message[mRev.Length - 1 - i]; + } + + BigInteger m = new BigInteger(1, mRev); + Gost3410Parameters parameters = key.Parameters; + + if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0) + { + return false; + } + + if (s.SignValue < 0 || parameters.Q.CompareTo(s) <= 0) + { + return false; + } + + BigInteger v = m.ModPow(parameters.Q.Subtract(BigInteger.Two), parameters.Q); + + BigInteger z1 = s.Multiply(v).Mod(parameters.Q); + BigInteger z2 = (parameters.Q.Subtract(r)).Multiply(v).Mod(parameters.Q); + + z1 = parameters.A.ModPow(z1, parameters.P); + z2 = ((Gost3410PublicKeyParameters)key).Y.ModPow(z2, parameters.P); + + BigInteger u = z1.Multiply(z2).Mod(parameters.P).Mod(parameters.Q); + + return u.Equals(r); + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/Iso9796d2PssSigner.cs b/iTechSharp/srcbc/crypto/signers/Iso9796d2PssSigner.cs new file mode 100644 index 0000000..07d7696 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/Iso9796d2PssSigner.cs @@ -0,0 +1,561 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /// ISO9796-2 - mechanism using a hash function with recovery (scheme 2 and 3). + ///

      + /// Note: the usual length for the salt is the length of the hash + /// function used in bytes.

      + ///
      + public class Iso9796d2PssSigner + : ISignerWithRecovery + { + /// + /// Return a reference to the recoveredMessage message. + /// + /// The full/partial recoveredMessage message. + /// + public byte[] GetRecoveredMessage() + { + return recoveredMessage; + } + + public const int TrailerImplicit = 0xBC; + public const int TrailerRipeMD160 = 0x31CC; + public const int TrailerRipeMD128 = 0x32CC; + public const int TrailerSha1 = 0x33CC; + + private IDigest digest; + private IAsymmetricBlockCipher cipher; + + private SecureRandom random; + private byte[] standardSalt; + + private int hLen; + private int trailer; + private int keyBits; + private byte[] block; + private byte[] mBuf; + private int messageLength; + private readonly int saltLength; + private bool fullMessage; + private byte[] recoveredMessage; + + /// + /// Generate a signer for the with either implicit or explicit trailers + /// for ISO9796-2, scheme 2 or 3. + /// + /// base cipher to use for signature creation/verification + /// digest to use. + /// length of salt in bytes. + /// whether or not the trailer is implicit or gives the hash. + public Iso9796d2PssSigner( + IAsymmetricBlockCipher cipher, + IDigest digest, + int saltLength, + bool isImplicit) + { + this.cipher = cipher; + this.digest = digest; + this.hLen = digest.GetDigestSize(); + this.saltLength = saltLength; + + if (isImplicit) + { + trailer = TrailerImplicit; + } + else + { + if (digest is Sha1Digest) + { + trailer = TrailerSha1; + } + else if (digest is RipeMD160Digest) + { + trailer = TrailerRipeMD160; + } + else if (digest is RipeMD128Digest) + { + trailer = TrailerRipeMD128; + } + else + { + throw new ArgumentException("no valid trailer for digest"); + } + } + } + + /// Constructor for a signer with an explicit digest trailer. + /// + /// + /// cipher to use. + /// + /// digest to sign with. + /// + /// length of salt in bytes. + /// + public Iso9796d2PssSigner( + IAsymmetricBlockCipher cipher, + IDigest digest, + int saltLength) + : this(cipher, digest, saltLength, false) + { + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; } + } + + /// Initialise the signer. + /// true if for signing, false if for verification. + /// parameters for signature generation/verification. If the + /// parameters are for generation they should be a ParametersWithRandom, + /// a ParametersWithSalt, or just an RsaKeyParameters object. If RsaKeyParameters + /// are passed in a SecureRandom will be created. + /// + /// if wrong parameter type or a fixed + /// salt is passed in which is the wrong length. + /// + public virtual void Init( + bool forSigning, + ICipherParameters parameters) + { + RsaKeyParameters kParam; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom p = (ParametersWithRandom) parameters; + + kParam = (RsaKeyParameters) p.Parameters; + + if (forSigning) + { + random = p.Random; + } + } + else if (parameters is ParametersWithSalt) + { + if (!forSigning) + throw new ArgumentException("ParametersWithSalt only valid for signing", "parameters"); + + ParametersWithSalt p = (ParametersWithSalt) parameters; + + kParam = (RsaKeyParameters) p.Parameters; + standardSalt = p.GetSalt(); + + if (standardSalt.Length != saltLength) + throw new ArgumentException("Fixed salt is of wrong length"); + } + else + { + kParam = (RsaKeyParameters) parameters; + + if (forSigning) + { + random = new SecureRandom(); + } + } + + cipher.Init(forSigning, kParam); + + keyBits = kParam.Modulus.BitLength; + + block = new byte[(keyBits + 7) / 8]; + + if (trailer == TrailerImplicit) + { + mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1]; + } + else + { + mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 2]; + } + + Reset(); + } + + /// compare two byte arrays. + private bool IsSameAs(byte[] a, byte[] b) + { + if (messageLength != b.Length) + { + return false; + } + + for (int i = 0; i != b.Length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + /// clear possible sensitive data + private void ClearBlock( + byte[] block) + { + Array.Clear(block, 0, block.Length); + } + + /// update the internal digest with the byte b + public virtual void Update( + byte input) + { + if (messageLength < mBuf.Length) + { + mBuf[messageLength++] = input; + } + else + { + digest.Update(input); + } + } + + /// update the internal digest with the byte array in + public virtual void BlockUpdate( + byte[] input, + int inOff, + int length) + { + while (length > 0 && messageLength < mBuf.Length) + { + this.Update(input[inOff]); + inOff++; + length--; + } + + if (length > 0) + { + digest.BlockUpdate(input, inOff, length); + } + } + + /// reset the internal state + public virtual void Reset() + { + digest.Reset(); + messageLength = 0; + if (mBuf != null) + { + ClearBlock(mBuf); + } + if (recoveredMessage != null) + { + ClearBlock(recoveredMessage); + recoveredMessage = null; + } + fullMessage = false; + } + + /// Generate a signature for the loaded message using the key we were + /// initialised with. + /// + public byte[] GenerateSignature() + { + int digSize = digest.GetDigestSize(); + byte[] m2Hash = new byte[digSize]; + digest.DoFinal(m2Hash, 0); + + byte[] C = new byte[8]; + LtoOSP(messageLength * 8, C); + + digest.BlockUpdate(C, 0, C.Length); + digest.BlockUpdate(mBuf, 0, messageLength); + digest.BlockUpdate(m2Hash, 0, m2Hash.Length); + + byte[] salt; + if (standardSalt != null) + { + salt = standardSalt; + } + else + { + salt = new byte[saltLength]; + random.NextBytes(salt); + } + + digest.BlockUpdate(salt, 0, salt.Length); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + int tLength = 2; + if (trailer == TrailerImplicit) + { + tLength = 1; + } + + int off = block.Length - messageLength - salt.Length - hLen - tLength - 1; + + block[off] = (byte) (0x01); + + Array.Copy(mBuf, 0, block, off + 1, messageLength); + Array.Copy(salt, 0, block, off + 1 + messageLength, salt.Length); + + byte[] dbMask = MaskGeneratorFunction1(hash, 0, hash.Length, block.Length - hLen - tLength); + for (int i = 0; i != dbMask.Length; i++) + { + block[i] ^= dbMask[i]; + } + + Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen); + + if (trailer == TrailerImplicit) + { + block[block.Length - 1] = (byte)TrailerImplicit; + } + else + { + block[block.Length - 2] = (byte) ((uint)trailer >> 8); + block[block.Length - 1] = (byte) trailer; + } + + block[0] &= (byte) (0x7f); + + byte[] b = cipher.ProcessBlock(block, 0, block.Length); + + ClearBlock(mBuf); + ClearBlock(block); + messageLength = 0; + + return b; + } + + /// return true if the signature represents a ISO9796-2 signature + /// for the passed in message. + /// + public virtual bool VerifySignature( + byte[] signature) + { + byte[] block = cipher.ProcessBlock(signature, 0, signature.Length); + + // + // adjust block size for leading zeroes if necessary + // + int expectedSize = (keyBits + 7) / 8; + if (block.Length < expectedSize) + { + byte[] tmp = new byte[expectedSize]; + block.CopyTo(tmp, tmp.Length - block.Length); + ClearBlock(block); + block = tmp; + } + + int tLength; + + if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0) + { + tLength = 1; + } + else + { + int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF); + + switch (sigTrail) + { + case TrailerRipeMD160: + if (!(digest is RipeMD160Digest)) + { + throw new ArgumentException("signer should be initialised with RipeMD160"); + } + break; + case TrailerSha1: + if (!(digest is Sha1Digest)) + { + throw new ArgumentException("signer should be initialised with SHA1"); + } + break; + case TrailerRipeMD128: + if (!(digest is RipeMD128Digest)) + { + throw new ArgumentException("signer should be initialised with RipeMD128"); + } + break; + default: + throw new ArgumentException("unrecognised hash in signature"); + } + + tLength = 2; + } + + // + // calculate H(m2) + // + byte[] m2Hash = new byte[hLen]; + digest.DoFinal(m2Hash, 0); + + // + // remove the mask + // + byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - tLength, hLen, block.Length - hLen - tLength); + for (int i = 0; i != dbMask.Length; i++) + { + block[i] ^= dbMask[i]; + } + + block[0] &= 0x7f; + + // + // find out how much padding we've got + // + int mStart = 0; + while (mStart < block.Length) + { + if (block[mStart++] == 0x01) + break; + } + + if (mStart >= block.Length) + { + ClearBlock(block); + return false; + } + + fullMessage = (mStart > 1); + + // TODO Should we check if a standardSalt was set and, if so, use its length instead? + recoveredMessage = new byte[dbMask.Length - mStart - saltLength]; + + Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length); + + // + // check the hashes + // + byte[] C = new byte[8]; + LtoOSP(recoveredMessage.Length * 8, C); + + digest.BlockUpdate(C, 0, C.Length); + + if (recoveredMessage.Length != 0) + { + digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length); + } + + digest.BlockUpdate(m2Hash, 0, m2Hash.Length); + + // Update for the salt + digest.BlockUpdate(block, mStart + recoveredMessage.Length, saltLength); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + int off = block.Length - tLength - hash.Length; + + for (int i = 0; i != hash.Length; i++) + { + if (hash[i] != block[off + i]) + { + ClearBlock(block); + ClearBlock(hash); + ClearBlock(recoveredMessage); + fullMessage = false; + + return false; + } + } + + ClearBlock(block); + ClearBlock(hash); + + // + // if they've input a message check what we've recovered against + // what was input. + // + if (messageLength != 0) + { + if (!IsSameAs(mBuf, recoveredMessage)) + { + ClearBlock(mBuf); + return false; + } + + messageLength = 0; + } + + ClearBlock(mBuf); + return true; + } + + /// + /// Return true if the full message was recoveredMessage. + /// + /// true on full message recovery, false otherwise, or if not sure. + /// + public virtual bool HasFullMessage() + { + return fullMessage; + } + + /// int to octet string. + /// int to octet string. + private void ItoOSP( + int i, + byte[] sp) + { + sp[0] = (byte)((uint)i >> 24); + sp[1] = (byte)((uint)i >> 16); + sp[2] = (byte)((uint)i >> 8); + sp[3] = (byte)((uint)i >> 0); + } + + /// long to octet string. + private void LtoOSP(long l, byte[] sp) + { + sp[0] = (byte)((ulong)l >> 56); + sp[1] = (byte)((ulong)l >> 48); + sp[2] = (byte)((ulong)l >> 40); + sp[3] = (byte)((ulong)l >> 32); + sp[4] = (byte)((ulong)l >> 24); + sp[5] = (byte)((ulong)l >> 16); + sp[6] = (byte)((ulong)l >> 8); + sp[7] = (byte)((ulong)l >> 0); + } + + /// mask generator function, as described in Pkcs1v2. + private byte[] MaskGeneratorFunction1( + byte[] Z, + int zOff, + int zLen, + int length) + { + byte[] mask = new byte[length]; + byte[] hashBuf = new byte[hLen]; + byte[] C = new byte[4]; + int counter = 0; + + digest.Reset(); + + do + { + ItoOSP(counter, C); + + digest.BlockUpdate(Z, zOff, zLen); + digest.BlockUpdate(C, 0, C.Length); + digest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * hLen, hLen); + } + while (++counter < (length / hLen)); + + if ((counter * hLen) < length) + { + ItoOSP(counter, C); + + digest.BlockUpdate(Z, zOff, zLen); + digest.BlockUpdate(C, 0, C.Length); + digest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen)); + } + + return mask; + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/Iso9796d2Signer.cs b/iTechSharp/srcbc/crypto/signers/Iso9796d2Signer.cs new file mode 100644 index 0000000..62d5d62 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/Iso9796d2Signer.cs @@ -0,0 +1,451 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Signers +{ + + /// ISO9796-2 - mechanism using a hash function with recovery (scheme 1) + public class Iso9796d2Signer : ISignerWithRecovery + { + /// + /// Return a reference to the recoveredMessage message. + /// + /// The full/partial recoveredMessage message. + /// + public byte[] GetRecoveredMessage() + { + return recoveredMessage; + } + + public const int TrailerImplicit = 0xBC; + public const int TrailerRipeMD160 = 0x31CC; + public const int TrailerRipeMD128 = 0x32CC; + public const int TrailerSha1 = 0x33CC; + + private IDigest digest; + private IAsymmetricBlockCipher cipher; + + private int trailer; + private int keyBits; + private byte[] block; + private byte[] mBuf; + private int messageLength; + private bool fullMessage; + private byte[] recoveredMessage; + + /// + /// Generate a signer for the with either implicit or explicit trailers + /// for ISO9796-2. + /// + /// base cipher to use for signature creation/verification + /// digest to use. + /// whether or not the trailer is implicit or gives the hash. + public Iso9796d2Signer( + IAsymmetricBlockCipher cipher, + IDigest digest, + bool isImplicit) + { + this.cipher = cipher; + this.digest = digest; + + if (isImplicit) + { + trailer = TrailerImplicit; + } + else + { + if (digest is Sha1Digest) + { + trailer = TrailerSha1; + } + else if (digest is RipeMD160Digest) + { + trailer = TrailerRipeMD160; + } + else if (digest is RipeMD128Digest) + { + trailer = TrailerRipeMD128; + } + else + { + throw new System.ArgumentException("no valid trailer for digest"); + } + } + } + + /// Constructor for a signer with an explicit digest trailer. + /// + /// + /// cipher to use. + /// + /// digest to sign with. + /// + public Iso9796d2Signer(IAsymmetricBlockCipher cipher, IDigest digest):this(cipher, digest, false) + { + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; } + } + + public virtual void Init(bool forSigning, ICipherParameters parameters) + { + RsaKeyParameters kParam = (RsaKeyParameters) parameters; + + cipher.Init(forSigning, kParam); + + keyBits = kParam.Modulus.BitLength; + + block = new byte[(keyBits + 7) / 8]; + if (trailer == TrailerImplicit) + { + mBuf = new byte[block.Length - digest.GetDigestSize() - 2]; + } + else + { + mBuf = new byte[block.Length - digest.GetDigestSize() - 3]; + } + + Reset(); + } + + /// compare two byte arrays. + private bool IsSameAs(byte[] a, byte[] b) + { + if (messageLength > mBuf.Length) + { + if (mBuf.Length > b.Length) + { + return false; + } + + for (int i = 0; i != mBuf.Length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + } + else + { + if (messageLength != b.Length) + { + return false; + } + + for (int i = 0; i != b.Length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + } + + return true; + } + + /// clear possible sensitive data + private void ClearBlock( + byte[] block) + { + Array.Clear(block, 0, block.Length); + } + + /// update the internal digest with the byte b + public void Update( + byte input) + { + digest.Update(input); + + if (messageLength < mBuf.Length) + { + mBuf[messageLength] = input; + } + + messageLength++; + } + + /// update the internal digest with the byte array in + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + digest.BlockUpdate(input, inOff, length); + + if (messageLength < mBuf.Length) + { + for (int i = 0; i < length && (i + messageLength) < mBuf.Length; i++) + { + mBuf[messageLength + i] = input[inOff + i]; + } + } + + messageLength += length; + } + + /// reset the internal state + public virtual void Reset() + { + digest.Reset(); + messageLength = 0; + ClearBlock(mBuf); + + if (recoveredMessage != null) + { + ClearBlock(recoveredMessage); + } + + recoveredMessage = null; + fullMessage = false; + } + + /// Generate a signature for the loaded message using the key we were + /// initialised with. + /// + public virtual byte[] GenerateSignature() + { + int digSize = digest.GetDigestSize(); + + int t = 0; + int delta = 0; + + if (trailer == TrailerImplicit) + { + t = 8; + delta = block.Length - digSize - 1; + digest.DoFinal(block, delta); + block[block.Length - 1] = (byte) TrailerImplicit; + } + else + { + t = 16; + delta = block.Length - digSize - 2; + digest.DoFinal(block, delta); + block[block.Length - 2] = (byte) ((uint)trailer >> 8); + block[block.Length - 1] = (byte) trailer; + } + + byte header = 0; + int x = (digSize + messageLength) * 8 + t + 4 - keyBits; + + if (x > 0) + { + int mR = messageLength - ((x + 7) / 8); + header = (byte) (0x60); + + delta -= mR; + + Array.Copy(mBuf, 0, block, delta, mR); + } + else + { + header = (byte) (0x40); + delta -= messageLength; + + Array.Copy(mBuf, 0, block, delta, messageLength); + } + + if ((delta - 1) > 0) + { + for (int i = delta - 1; i != 0; i--) + { + block[i] = (byte) 0xbb; + } + block[delta - 1] ^= (byte) 0x01; + block[0] = (byte) 0x0b; + block[0] |= header; + } + else + { + block[0] = (byte) 0x0a; + block[0] |= header; + } + + byte[] b = cipher.ProcessBlock(block, 0, block.Length); + + ClearBlock(mBuf); + ClearBlock(block); + + return b; + } + + /// return true if the signature represents a ISO9796-2 signature + /// for the passed in message. + /// + public virtual bool VerifySignature(byte[] signature) + { + byte[] block = cipher.ProcessBlock(signature, 0, signature.Length); + + if (((block[0] & 0xC0) ^ 0x40) != 0) + { + ClearBlock(mBuf); + ClearBlock(block); + + return false; + } + + if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0) + { + ClearBlock(mBuf); + ClearBlock(block); + + return false; + } + + int delta = 0; + + if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0) + { + delta = 1; + } + else + { + int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF); + + switch (sigTrail) + { + case TrailerRipeMD160: + if (!(digest is RipeMD160Digest)) + { + throw new ArgumentException("signer should be initialised with RipeMD160"); + } + break; + case TrailerSha1: + if (!(digest is Sha1Digest)) + { + throw new ArgumentException("signer should be initialised with SHA1"); + } + break; + case TrailerRipeMD128: + if (!(digest is RipeMD128Digest)) + { + throw new ArgumentException("signer should be initialised with RipeMD128"); + } + break; + default: + throw new ArgumentException("unrecognised hash in signature"); + } + + delta = 2; + } + + // + // find out how much padding we've got + // + int mStart = 0; + for (; mStart != block.Length; mStart++) + { + if (((block[mStart] & 0x0f) ^ 0x0a) == 0) + { + break; + } + } + + mStart++; + + // + // check the hashes + // + byte[] hash = new byte[digest.GetDigestSize()]; + + int off = block.Length - delta - hash.Length; + + // + // there must be at least one byte of message string + // + if ((off - mStart) <= 0) + { + ClearBlock(mBuf); + ClearBlock(block); + + return false; + } + + // + // if we contain the whole message as well, check the hash of that. + // + if ((block[0] & 0x20) == 0) + { + fullMessage = true; + + digest.Reset(); + digest.BlockUpdate(block, mStart, off - mStart); + digest.DoFinal(hash, 0); + + for (int i = 0; i != hash.Length; i++) + { + block[off + i] ^= hash[i]; + if (block[off + i] != 0) + { + ClearBlock(mBuf); + ClearBlock(block); + + return false; + } + } + + recoveredMessage = new byte[off - mStart]; + Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length); + } + else + { + fullMessage = false; + + digest.DoFinal(hash, 0); + + for (int i = 0; i != hash.Length; i++) + { + block[off + i] ^= hash[i]; + if (block[off + i] != 0) + { + ClearBlock(mBuf); + ClearBlock(block); + + return false; + } + } + + recoveredMessage = new byte[off - mStart]; + Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length); + } + + // + // if they've input a message check what we've recovered against + // what was input. + // + if (messageLength != 0) + { + if (!IsSameAs(mBuf, recoveredMessage)) + { + ClearBlock(mBuf); + ClearBlock(block); + ClearBlock(recoveredMessage); + + return false; + } + } + + ClearBlock(mBuf); + ClearBlock(block); + + return true; + } + + /// + /// Return true if the full message was recoveredMessage. + /// + /// true on full message recovery, false otherwise. + /// + public virtual bool HasFullMessage() + { + return fullMessage; + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/PssSigner.cs b/iTechSharp/srcbc/crypto/signers/PssSigner.cs new file mode 100644 index 0000000..30c2ad5 --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/PssSigner.cs @@ -0,0 +1,299 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /// RSA-PSS as described in Pkcs# 1 v 2.1. + ///

      + /// Note: the usual value for the salt length is the number of + /// bytes in the hash function.

      + ///
      + public class PssSigner + : ISigner + { + public const byte TrailerImplicit = (byte)0xBC; + + private readonly IDigest digest; + private readonly IAsymmetricBlockCipher cipher; + + private SecureRandom random; + + private int hLen; + private int sLen; + private int emBits; + private byte[] salt; + private byte[] mDash; + private byte[] block; + private byte trailer; + + public PssSigner( + IAsymmetricBlockCipher cipher, + IDigest digest) + : this(cipher, digest, digest.GetDigestSize()) + { + } + + /// Basic constructor + /// the asymmetric cipher to use. + /// the digest to use. + /// the length of the salt to use (in bytes). + public PssSigner( + IAsymmetricBlockCipher cipher, + IDigest digest, + int saltLen) + : this(cipher, digest, saltLen, TrailerImplicit) + { + } + + public PssSigner( + IAsymmetricBlockCipher cipher, + IDigest digest, + int saltLen, + byte trailer) + { + this.cipher = cipher; + this.digest = digest; + this.hLen = digest.GetDigestSize(); + this.sLen = saltLen; + this.salt = new byte[saltLen]; + this.mDash = new byte[8 + saltLen + hLen]; + this.trailer = trailer; + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "withRSAandMGF1"; } + } + + public virtual void Init( + bool forSigning, + ICipherParameters parameters) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom p = (ParametersWithRandom) parameters; + + parameters = p.Parameters; + random = p.Random; + } + else + { + if (forSigning) + { + random = new SecureRandom(); + } + } + + cipher.Init(forSigning, parameters); + + RsaKeyParameters kParam; + if (parameters is RsaBlindingParameters) + { + kParam = ((RsaBlindingParameters) parameters).PublicKey; + } + else + { + kParam = (RsaKeyParameters) parameters; + } + + emBits = kParam.Modulus.BitLength - 1; + + block = new byte[(emBits + 7) / 8]; + } + + /// clear possible sensitive data + private void ClearBlock( + byte[] block) + { + Array.Clear(block, 0, block.Length); + } + + /// update the internal digest with the byte b + public virtual void Update( + byte input) + { + digest.Update(input); + } + + /// update the internal digest with the byte array in + public virtual void BlockUpdate( + byte[] input, + int inOff, + int length) + { + digest.BlockUpdate(input, inOff, length); + } + + /// reset the internal state + public virtual void Reset() + { + digest.Reset(); + } + + /// Generate a signature for the message we've been loaded with using + /// the key we were initialised with. + /// + public virtual byte[] GenerateSignature() + { + if (emBits < (8 * hLen + 8 * sLen + 9)) + { + throw new DataLengthException("encoding error"); + } + + digest.DoFinal(mDash, mDash.Length - hLen - sLen); + + if (sLen != 0) + { + random.NextBytes(salt); + salt.CopyTo(mDash, mDash.Length - sLen); + } + + byte[] h = new byte[hLen]; + + digest.BlockUpdate(mDash, 0, mDash.Length); + + digest.DoFinal(h, 0); + + block[block.Length - sLen - 1 - hLen - 1] = (byte) (0x01); + salt.CopyTo(block, block.Length - sLen - hLen - 1); + + byte[] dbMask = MaskGeneratorFunction1(h, 0, h.Length, block.Length - hLen - 1); + for (int i = 0; i != dbMask.Length; i++) + { + block[i] ^= dbMask[i]; + } + + block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits))); + + h.CopyTo(block, block.Length - hLen - 1); + + block[block.Length - 1] = trailer; + + byte[] b = cipher.ProcessBlock(block, 0, block.Length); + + ClearBlock(block); + + return b; + } + + /// return true if the internal state represents the signature described + /// in the passed in array. + /// + public virtual bool VerifySignature( + byte[] signature) + { + if (emBits < (8 * hLen + 8 * sLen + 9)) + { + return false; + } + + digest.DoFinal(mDash, mDash.Length - hLen - sLen); + + byte[] b = cipher.ProcessBlock(signature, 0, signature.Length); + b.CopyTo(block, block.Length - b.Length); + + if (block[block.Length - 1] != trailer) + { + ClearBlock(block); + return false; + } + + byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1); + + for (int i = 0; i != dbMask.Length; i++) + { + block[i] ^= dbMask[i]; + } + + block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits))); + + for (int i = 0; i != block.Length - hLen - sLen - 2; i++) + { + if (block[i] != 0) + { + ClearBlock(block); + return false; + } + } + + if (block[block.Length - hLen - sLen - 2] != 0x01) + { + ClearBlock(block); + return false; + } + + Array.Copy(block, block.Length - sLen - hLen - 1, mDash, mDash.Length - sLen, sLen); + + digest.BlockUpdate(mDash, 0, mDash.Length); + digest.DoFinal(mDash, mDash.Length - hLen); + + for (int i = block.Length - hLen - 1, j = mDash.Length - hLen; j != mDash.Length; i++, j++) + { + if ((block[i] ^ mDash[j]) != 0) + { + ClearBlock(mDash); + ClearBlock(block); + return false; + } + } + + ClearBlock(mDash); + ClearBlock(block); + + return true; + } + + /// int to octet string. + private void ItoOSP( + int i, + byte[] sp) + { + sp[0] = (byte)((uint) i >> 24); + sp[1] = (byte)((uint) i >> 16); + sp[2] = (byte)((uint) i >> 8); + sp[3] = (byte)((uint) i >> 0); + } + + /// mask generator function, as described in Pkcs1v2. + private byte[] MaskGeneratorFunction1( + byte[] Z, + int zOff, + int zLen, + int length) + { + byte[] mask = new byte[length]; + byte[] hashBuf = new byte[hLen]; + byte[] C = new byte[4]; + int counter = 0; + + digest.Reset(); + + while (counter < (length / hLen)) + { + ItoOSP(counter, C); + + digest.BlockUpdate(Z, zOff, zLen); + digest.BlockUpdate(C, 0, C.Length); + digest.DoFinal(hashBuf, 0); + + hashBuf.CopyTo(mask, counter * hLen); + ++counter; + } + + if ((counter * hLen) < length) + { + ItoOSP(counter, C); + + digest.BlockUpdate(Z, zOff, zLen); + digest.BlockUpdate(C, 0, C.Length); + digest.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen)); + } + + return mask; + } + } +} diff --git a/iTechSharp/srcbc/crypto/signers/RsaDigestSigner.cs b/iTechSharp/srcbc/crypto/signers/RsaDigestSigner.cs new file mode 100644 index 0000000..bdfb5fc --- /dev/null +++ b/iTechSharp/srcbc/crypto/signers/RsaDigestSigner.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Encodings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Signers +{ + public class RsaDigestSigner + : ISigner + { + private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine()); + private readonly AlgorithmIdentifier algId; + private readonly IDigest digest; + private bool forSigning; + + private static readonly Hashtable oidMap = new Hashtable(); + + /// + /// Load oid table. + /// + static RsaDigestSigner() + { + oidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128; + oidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160; + oidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256; + + oidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1; + oidMap["SHA-224"] = NistObjectIdentifiers.IdSha224; + oidMap["SHA-256"] = NistObjectIdentifiers.IdSha256; + oidMap["SHA-384"] = NistObjectIdentifiers.IdSha384; + oidMap["SHA-512"] = NistObjectIdentifiers.IdSha512; + + oidMap["MD2"] = PkcsObjectIdentifiers.MD2; + oidMap["MD4"] = PkcsObjectIdentifiers.MD4; + oidMap["MD5"] = PkcsObjectIdentifiers.MD5; + } + + public RsaDigestSigner( + IDigest digest) + { + this.digest = digest; + + algId = new AlgorithmIdentifier( (DerObjectIdentifier)oidMap[digest.AlgorithmName] , DerNull.Instance); + } + + public string AlgorithmName + { + get { return digest.AlgorithmName + "withRSA"; } + } + + /** + * Initialise the signer for signing or verification. + * + * @param forSigning true if for signing, false otherwise + * @param param necessary parameters. + */ + public void Init( + bool forSigning, + ICipherParameters parameters) + { + this.forSigning = forSigning; + AsymmetricKeyParameter k; + + if (parameters is ParametersWithRandom) + { + k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters; + } + else + { + k = (AsymmetricKeyParameter)parameters; + } + + if (forSigning && !k.IsPrivate) + throw new InvalidKeyException("Signing requires private key."); + + if (!forSigning && k.IsPrivate) + throw new InvalidKeyException("Verification requires public key."); + + Reset(); + + rsaEngine.Init(forSigning, parameters); + } + + /** + * update the internal digest with the byte b + */ + public void Update( + byte input) + { + digest.Update(input); + } + + /** + * update the internal digest with the byte array in + */ + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + digest.BlockUpdate(input, inOff, length); + } + + /** + * Generate a signature for the message we've been loaded with using + * the key we were initialised with. + */ + public byte[] GenerateSignature() + { + if (!forSigning) + throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation."); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + byte[] data = DerEncode(hash); + return rsaEngine.ProcessBlock(data, 0, data.Length); + } + + /** + * return true if the internal state represents the signature described + * in the passed in array. + */ + public bool VerifySignature( + byte[] signature) + { + if (forSigning) + throw new InvalidOperationException("RsaDigestSigner not initialised for verification"); + + byte[] hash = new byte[digest.GetDigestSize()]; + digest.DoFinal(hash, 0); + + byte[] sig; + byte[] expected; + + try + { + sig = rsaEngine.ProcessBlock(signature, 0, signature.Length); + expected = DerEncode(hash); + } + catch (Exception) + { + return false; + } + + if (sig.Length == expected.Length) + { + for (int i = 0; i < sig.Length; i++) + { + if (sig[i] != expected[i]) + { + return false; + } + } + } + else if (sig.Length == expected.Length - 2) // NULL left out + { + int sigOffset = sig.Length - hash.Length - 2; + int expectedOffset = expected.Length - hash.Length - 2; + + expected[1] -= 2; // adjust lengths + expected[3] -= 2; + + for (int i = 0; i < hash.Length; i++) + { + if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash + { + return false; + } + } + + for (int i = 0; i < sigOffset; i++) + { + if (sig[i] != expected[i]) // check header less NULL + { + return false; + } + } + } + else + { + return false; + } + + return true; + } + + public void Reset() + { + digest.Reset(); + } + + private byte[] DerEncode( + byte[] hash) + { + DigestInfo dInfo = new DigestInfo(algId, hash); + + return dInfo.GetDerEncoded(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/AlwaysValidVerifyer.cs b/iTechSharp/srcbc/crypto/tls/AlwaysValidVerifyer.cs new file mode 100644 index 0000000..616ad97 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/AlwaysValidVerifyer.cs @@ -0,0 +1,23 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// + /// A certificate verifyer, that will always return true. + ///
      +	/// DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
      +	/// 
      + ///
      + public class AlwaysValidVerifyer + : ICertificateVerifyer + { + /// Return true. + public bool IsValid( + X509CertificateStructure[] certs) + { + return true; + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/ByteQueue.cs b/iTechSharp/srcbc/crypto/tls/ByteQueue.cs new file mode 100644 index 0000000..58f592b --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/ByteQueue.cs @@ -0,0 +1,125 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// + /// A queue for bytes. + ///

      + /// This file could be more optimized. + ///

      + ///
      + public class ByteQueue + { + /// The smallest number which can be written as 2^x which is bigger than i. + public static int NextTwoPow( + int i) + { + /* + * This code is based of a lot of code I found on the Internet + * which mostly referenced a book called "Hacking delight". + * + */ + i |= (i >> 1); + i |= (i >> 2); + i |= (i >> 4); + i |= (i >> 8); + i |= (i >> 16); + return i + 1; + } + + /** + * The initial size for our buffer. + */ + private const int InitBufSize = 1024; + + /** + * The buffer where we store our data. + */ + private byte[] databuf = new byte[ByteQueue.InitBufSize]; + + /** + * How many bytes at the beginning of the buffer are skipped. + */ + private int skipped = 0; + + /** + * How many bytes in the buffer are valid data. + */ + private int available = 0; + + /// Read data from the buffer. + /// The buffer where the read data will be copied to. + /// How many bytes to skip at the beginning of buf. + /// How many bytes to read at all. + /// How many bytes from our data to skip. + public void Read( + byte[] buf, + int offset, + int len, + int skip) + { + if ((available - skip) < len) + { + throw new TlsException("Not enough data to read"); + } + if ((buf.Length - offset) < len) + { + throw new TlsException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes"); + } + Array.Copy(databuf, skipped + skip, buf, offset, len); + } + + /// Add some data to our buffer. + /// A byte-array to read data from. + /// How many bytes to skip at the beginning of the array. + /// How many bytes to read from the array. + public void AddData( + byte[] data, + int offset, + int len) + { + if ((skipped + available + len) > databuf.Length) + { + byte[] tmp = new byte[ByteQueue.NextTwoPow(data.Length)]; + Array.Copy(databuf, skipped, tmp, 0, available); + skipped = 0; + databuf = tmp; + } + Array.Copy(data, offset, databuf, skipped + available, len); + available += len; + } + + /// Remove some bytes from our data from the beginning. + /// How many bytes to remove. + public void RemoveData( + int i) + { + if (i > available) + { + throw new TlsException("Cannot remove " + i + " bytes, only got " + available); + } + + /* + * Skip the data. + */ + available -= i; + skipped += i; + + /* + * If more than half of our data is skipped, we will move the data + * in the buffer. + */ + if (skipped > (databuf.Length / 2)) + { + Array.Copy(databuf, skipped, databuf, 0, available); + skipped = 0; + } + } + + /// The number of bytes which are available in this buffer. + public int Available + { + get { return available; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/Certificate.cs b/iTechSharp/srcbc/crypto/tls/Certificate.cs new file mode 100644 index 0000000..f4fc94e --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/Certificate.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * A representation for a certificate chain as used by an tls server. + */ + public class Certificate + { + /** + * The certificates. + */ + internal X509CertificateStructure[] certs; + + /** + * Parse the ServerCertificate message. + * + * @param is The stream where to parse from. + * @return A Certificate object with the certs, the server has sended. + * @throws IOException If something goes wrong during parsing. + */ + internal static Certificate Parse( + Stream inStr) + { + X509CertificateStructure[] certs; + int left = TlsUtilities.ReadUint24(inStr); + ArrayList tmp = new ArrayList(); + while (left > 0) + { + int size = TlsUtilities.ReadUint24(inStr); + left -= 3 + size; + byte[] buf = new byte[size]; + TlsUtilities.ReadFully(buf, inStr); + MemoryStream bis = new MemoryStream(buf, false); + Asn1InputStream ais = new Asn1InputStream(bis); + Asn1Object o = ais.ReadObject(); + tmp.Add(X509CertificateStructure.GetInstance(o)); +// if (bis.available() > 0) + if (bis.Position < bis.Length) + { + throw new ArgumentException("Sorry, there is garbage data left after the certificate"); + } + } +// certs = new X509CertificateStructure[tmp.size()]; +// for (int i = 0; i < tmp.size(); i++) +// { +// certs[i] = (X509CertificateStructure)tmp.elementAt(i); +// } + certs = (X509CertificateStructure[]) tmp.ToArray(typeof(X509CertificateStructure)); + return new Certificate(certs); + } + + /** + * Private constructure from an cert array. + * + * @param certs The certs the chain should contain. + */ + private Certificate( + X509CertificateStructure[] certs) + { + this.certs = certs; + } + + /// An array which contains the certs, this chain contains. + public X509CertificateStructure[] GetCerts() + { +// X509CertificateStructure[] result = new X509CertificateStructure[certs.Length]; +// Array.Copy(certs, 0, result, 0, certs.Length); +// return result; + return (X509CertificateStructure[]) certs.Clone(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/CombinedHash.cs b/iTechSharp/srcbc/crypto/tls/CombinedHash.cs new file mode 100644 index 0000000..f460291 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/CombinedHash.cs @@ -0,0 +1,70 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// A combined hash, which implements md5(m) || sha1(m). + public class CombinedHash + : IDigest + { + private IDigest md5 = new MD5Digest(); + private IDigest sha1 = new Sha1Digest(); + + /// + public string AlgorithmName + { + get + { + return md5.AlgorithmName + " and " + sha1.AlgorithmName + " for TLS 1.0"; + } + } + + /// + public int GetByteLength() + { + return System.Math.Max(md5.GetByteLength(), sha1.GetByteLength()); + } + + /// + public int GetDigestSize() + { + return md5.GetDigestSize() + sha1.GetDigestSize(); + } + + /// + public void Update( + byte input) + { + md5.Update(input); + sha1.Update(input); + } + + /// + public void BlockUpdate( + byte[] input, + int inOff, + int len) + { + md5.BlockUpdate(input, inOff, len); + sha1.BlockUpdate(input, inOff, len); + } + + /// + public int DoFinal( + byte[] output, + int outOff) + { + int i1 = md5.DoFinal(output, outOff); + int i2 = sha1.DoFinal(output, outOff + i1); + return i1 + i2; + } + + /// + public void Reset() + { + md5.Reset(); + sha1.Reset(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/ICertificateVerifyer.cs b/iTechSharp/srcbc/crypto/tls/ICertificateVerifyer.cs new file mode 100644 index 0000000..b53b9c9 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/ICertificateVerifyer.cs @@ -0,0 +1,17 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// + /// This should be implemented by any class which can find out, if a given + /// certificate chain is beeing accepted by an client. + /// + public interface ICertificateVerifyer + { + /// The certs, which are part of the chain. + /// True, if the chain is accepted, false otherwise + bool IsValid(X509CertificateStructure[] certs); + } +} diff --git a/iTechSharp/srcbc/crypto/tls/RecordStream.cs b/iTechSharp/srcbc/crypto/tls/RecordStream.cs new file mode 100644 index 0000000..3383a36 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/RecordStream.cs @@ -0,0 +1,107 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// An implementation of the TLS 1.0 record layer. + public class RecordStream + { + private TlsProtocolHandler handler; + private Stream inStr; + private Stream outStr; + internal CombinedHash hash1; + internal CombinedHash hash2; + internal TlsCipherSuite readSuite = null; + internal TlsCipherSuite writeSuite = null; + + internal RecordStream( + TlsProtocolHandler handler, + Stream inStr, + Stream outStr) + { + this.handler = handler; + this.inStr = inStr; + this.outStr = outStr; + hash1 = new CombinedHash(); + hash2 = new CombinedHash(); + this.readSuite = new TlsNullCipherSuite(); + this.writeSuite = this.readSuite; + } + + public void ReadData() + { + short type = TlsUtilities.ReadUint8(inStr); + TlsUtilities.CheckVersion(inStr, handler); + int size = TlsUtilities.ReadUint16(inStr); + byte[] buf = DecodeAndVerify(type, inStr, size); + handler.ProcessData(type, buf, 0, buf.Length); + + } + + internal byte[] DecodeAndVerify( + short type, + Stream inStr, + int len) + { + byte[] buf = new byte[len]; + TlsUtilities.ReadFully(buf, inStr); + byte[] result = readSuite.DecodeCiphertext(type, buf, 0, buf.Length, handler); + return result; + } + + internal void WriteMessage( + short type, + byte[] message, + int offset, + int len) + { + if (type == 22) + { + hash1.BlockUpdate(message, offset, len); + hash2.BlockUpdate(message, offset, len); + } + byte[] ciphertext = writeSuite.EncodePlaintext(type, message, offset, len); + byte[] writeMessage = new byte[ciphertext.Length + 5]; + TlsUtilities.WriteUint8(type, writeMessage, 0); + TlsUtilities.WriteUint8((short)3, writeMessage, 1); + TlsUtilities.WriteUint8((short)1, writeMessage, 2); + TlsUtilities.WriteUint16(ciphertext.Length, writeMessage, 3); + Array.Copy(ciphertext, 0, writeMessage, 5, ciphertext.Length); + outStr.Write(writeMessage, 0, writeMessage.Length); + outStr.Flush(); + } + + internal void Close() + { + IOException e = null; + try + { + inStr.Close(); + } + catch (IOException ex) + { + e = ex; + } + + try + { + // NB: This is harmless if outStr == inStr + outStr.Close(); + } + catch (IOException ex) + { + e = ex; + } + + if (e != null) + { + throw e; + } + } + + internal void Flush() + { + outStr.Flush(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs b/iTechSharp/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs new file mode 100644 index 0000000..1bc1ace --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs @@ -0,0 +1,196 @@ +using System; +using System.Text; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// A generic TLS 1.0 block cipher suite. This can be used for AES or 3DES for example. + public class TlsBlockCipherCipherSuite + : TlsCipherSuite + { + private IBlockCipher encryptCipher; + + private IBlockCipher decryptCipher; + + private IDigest writeDigest; + + private IDigest readDigest; + + private int cipherKeySize; + + private short keyExchange; + + private TlsMac writeMac; + + private TlsMac readMac; + + internal TlsBlockCipherCipherSuite( + IBlockCipher encrypt, + IBlockCipher decrypt, + IDigest writeDigest, + IDigest readDigest, + int cipherKeySize, + short keyExchange) + { + this.encryptCipher = encrypt; + this.decryptCipher = decrypt; + this.writeDigest = writeDigest; + this.readDigest = readDigest; + this.cipherKeySize = cipherKeySize; + this.keyExchange = keyExchange; + } + + internal override void Init(byte[] ms, byte[] cr, byte[] sr) + { + int prfSize = (2 * cipherKeySize) + (2 * writeDigest.GetDigestSize()) + + (2 * encryptCipher.GetBlockSize()); + byte[] key_block = new byte[prfSize]; + byte[] random = new byte[cr.Length + sr.Length]; + Array.Copy(cr, 0, random, sr.Length, cr.Length); + Array.Copy(sr, 0, random, 0, sr.Length); + TlsUtilities.PRF(ms, TlsUtilities.ToByteArray("key expansion"), random, key_block); + + int offset = 0; + + // Init MACs + writeMac = new TlsMac(writeDigest, key_block, offset, writeDigest + .GetDigestSize()); + offset += writeDigest.GetDigestSize(); + readMac = new TlsMac(readDigest, key_block, offset, readDigest + .GetDigestSize()); + offset += readDigest.GetDigestSize(); + + // Init Ciphers + this.initCipher(true, encryptCipher, key_block, cipherKeySize, offset, + offset + (cipherKeySize * 2)); + offset += cipherKeySize; + this.initCipher(false, decryptCipher, key_block, cipherKeySize, offset, + offset + cipherKeySize + decryptCipher.GetBlockSize()); + } + + private void initCipher(bool forEncryption, IBlockCipher cipher, + byte[] key_block, int key_size, int key_offset, int iv_offset) + { + KeyParameter key_parameter = new KeyParameter(key_block, key_offset, + key_size); + ParametersWithIV parameters_with_iv = new ParametersWithIV( + key_parameter, key_block, iv_offset, cipher.GetBlockSize()); + cipher.Init(forEncryption, parameters_with_iv); + } + + internal override byte[] EncodePlaintext( + short type, + byte[] plaintext, + int offset, + int len) + { + int blocksize = encryptCipher.GetBlockSize(); + int paddingsize = blocksize + - ((len + writeMac.Size + 1) % blocksize); + int totalsize = len + writeMac.Size + paddingsize + 1; + byte[] outbuf = new byte[totalsize]; + Array.Copy(plaintext, offset, outbuf, 0, len); + byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len); + Array.Copy(mac, 0, outbuf, len, mac.Length); + int paddoffset = len + mac.Length; + for (int i = 0; i <= paddingsize; i++) + { + outbuf[i + paddoffset] = (byte)paddingsize; + } + for (int i = 0; i < totalsize; i += blocksize) + { + encryptCipher.ProcessBlock(outbuf, i, outbuf, i); + } + return outbuf; + } + + internal override byte[] DecodeCiphertext( + short type, + byte[] ciphertext, + int offset, + int len, + TlsProtocolHandler handler) + { + int blocksize = decryptCipher.GetBlockSize(); + bool decrypterror = false; + + /* + * Decrypt all the ciphertext using the blockcipher + */ + for (int i = 0; i < len; i += blocksize) + { + decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i + + offset); + } + + /* + * Check if padding is correct + */ + int paddingsize = ciphertext[offset + len - 1]; + if (offset + len - 1 - paddingsize < 0) + { + /* + * This would lead to an negativ array index, so this padding + * must be incorrect! + */ + decrypterror = true; + paddingsize = 0; + } + else + { + /* + * Now, check all the padding-bytes. + */ + for (int i = 0; i <= paddingsize; i++) + { + if (ciphertext[offset + len - 1 - i] != paddingsize) + { + /* Wrong padding */ + decrypterror = true; + } + } + } + + /* + * We now don't care if padding verification has failed or not, + * we will calculate the mac to give an attacker no kind of timing + * profile he can use to find out if mac verification failed or + * padding verification failed. + */ + int plaintextlength = len - readMac.Size - paddingsize - 1; + byte[] calculatedMac = readMac.CalculateMac(type, ciphertext, offset, + plaintextlength); + + /* + * Check all bytes in the mac. + */ + for (int i = 0; i < calculatedMac.Length; i++) + { + if (ciphertext[offset + plaintextlength + i] != calculatedMac[i]) + { + decrypterror = true; + } + } + + /* + * Now, it is save to fail. + */ + if (decrypterror) + { + handler.FailWithError(TlsProtocolHandler.AL_fatal, + TlsProtocolHandler.AP_bad_record_mac); + } + byte[] plaintext = new byte[plaintextlength]; + Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength); + return plaintext; + + } + + internal override short KeyExchangeAlgorithm + { + get { return this.keyExchange; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsCipherSuite.cs b/iTechSharp/srcbc/crypto/tls/TlsCipherSuite.cs new file mode 100644 index 0000000..f8414f0 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsCipherSuite.cs @@ -0,0 +1,26 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// A generic class for ciphersuites in TLS 1.0. + public abstract class TlsCipherSuite + { + internal const short KE_RSA = 1; + internal const short KE_RSA_EXPORT = 2; + internal const short KE_DHE_DSS = 3; + internal const short KE_DHE_DSS_EXPORT = 4; + internal const short KE_DHE_RSA = 5; + internal const short KE_DHE_RSA_EXPORT = 6; + internal const short KE_DH_DSS = 7; + internal const short KE_DH_RSA = 8; + internal const short KE_DH_anon = 9; + + internal abstract void Init(byte[] ms, byte[] cr, byte[] sr); + + internal abstract byte[] EncodePlaintext(short type, byte[] plaintext, int offset, int len); + + internal abstract byte[] DecodeCiphertext(short type, byte[] plaintext, int offset, int len, TlsProtocolHandler handler); + + internal abstract short KeyExchangeAlgorithm { get; } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsCipherSuiteManager.cs b/iTechSharp/srcbc/crypto/tls/TlsCipherSuiteManager.cs new file mode 100644 index 0000000..81b2c79 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsCipherSuiteManager.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// + /// A manager for ciphersuite. This class does manage all ciphersuites + /// which are used by MicroTLS. + /// + public class TlsCipherSuiteManager + { + private const int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000a; + private const int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016; + private const int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002f; + private const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033; + private const int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035; + private const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039; + + internal static void WriteCipherSuites( + Stream outStr) + { + TlsUtilities.WriteUint16(2 * 6, outStr); + + TlsUtilities.WriteUint16(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, outStr); + TlsUtilities.WriteUint16(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, outStr); + TlsUtilities.WriteUint16(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, outStr); + + TlsUtilities.WriteUint16(TLS_RSA_WITH_AES_256_CBC_SHA, outStr); + TlsUtilities.WriteUint16(TLS_RSA_WITH_AES_128_CBC_SHA, outStr); + TlsUtilities.WriteUint16(TLS_RSA_WITH_3DES_EDE_CBC_SHA, outStr); + + } + + internal static TlsCipherSuite GetCipherSuite( + int number, + TlsProtocolHandler handler) + { + switch (number) + { + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new DesEdeEngine()), new CbcBlockCipher(new DesEdeEngine()), new Sha1Digest(), new Sha1Digest(), 24, TlsCipherSuite.KE_RSA); + + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new DesEdeEngine()), new CbcBlockCipher(new DesEdeEngine()), new Sha1Digest(), new Sha1Digest(), 24, TlsCipherSuite.KE_DHE_RSA); + + case TLS_RSA_WITH_AES_128_CBC_SHA: + return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 16, TlsCipherSuite.KE_RSA); + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 16, TlsCipherSuite.KE_DHE_RSA); + + case TLS_RSA_WITH_AES_256_CBC_SHA: + return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 32, TlsCipherSuite.KE_RSA); + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return new TlsBlockCipherCipherSuite(new CbcBlockCipher(new AesFastEngine()), new CbcBlockCipher(new AesFastEngine()), new Sha1Digest(), new Sha1Digest(), 32, TlsCipherSuite.KE_DHE_RSA); + + default: + handler.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_handshake_failure); + + /* + * Unreachable Code, failWithError will always throw an exception! + */ + return null; + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsException.cs b/iTechSharp/srcbc/crypto/tls/TlsException.cs new file mode 100644 index 0000000..fa3e732 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + public class TlsException : Exception + { + public TlsException() : base() { } + public TlsException(string message) : base(message) { } + public TlsException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsInputStream.cs b/iTechSharp/srcbc/crypto/tls/TlsInputStream.cs new file mode 100644 index 0000000..f5533c9 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsInputStream.cs @@ -0,0 +1,42 @@ +using System; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// An input Stream for a TLS 1.0 connection. + // TODO Fix name and make internal once TlsProtocolHandler.TlsInputStream is removed + public class TlsInputStream + : BaseInputStream + { + private readonly TlsProtocolHandler handler; + + internal TlsInputStream( + TlsProtocolHandler handler) + { + this.handler = handler; + } + + public override int Read( + byte[] buf, + int offset, + int len) + { + return this.handler.ReadApplicationData(buf, offset, len); + } + + public override int ReadByte() + { + byte[] buf = new byte[1]; + if (this.Read(buf, 0, 1) <= 0) + return -1; + return buf[0]; + } + + public override void Close() + { + handler.Close(); + base.Close(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsMac.cs b/iTechSharp/srcbc/crypto/tls/TlsMac.cs new file mode 100644 index 0000000..cd32ac6 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsMac.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// + /// A generic TLS MAC implementation, which can be used with any kind of + /// IDigest to act as an HMAC. + /// + public class TlsMac + { + private long seqNo; + private HMac mac; + + /** + * Generate a new instance of an TlsMac. + * + * @param digest The digest to use. + * @param key_block A byte-array where the key for this mac is located. + * @param offset The number of bytes to skip, before the key starts in the buffer. + * @param len The length of the key. + */ + internal TlsMac( + IDigest digest, + byte[] key_block, + int offset, + int len) + { + this.mac = new HMac(digest); + KeyParameter param = new KeyParameter(key_block, offset, len); + this.mac.Init(param); + this.seqNo = 0; + } + + /** + * @return The Keysize of the mac. + */ + internal int Size + { + get { return mac.GetMacSize(); } + } + + /** + * Calculate the mac for some given data. + *

      + * TlsMac will keep track of the sequence number internally. + * + * @param type The message type of the message. + * @param message A byte-buffer containing the message. + * @param offset The number of bytes to skip, before the message starts. + * @param len The length of the message. + * @return A new byte-buffer containing the mac value. + */ + internal byte[] CalculateMac( + short type, + byte[] message, + int offset, + int len) + { + try + { + MemoryStream bosMac = new MemoryStream(13 + len); + TlsUtilities.WriteUint64(seqNo++, bosMac); + TlsUtilities.WriteUint8(type, bosMac); + TlsUtilities.WriteVersion(bosMac); + TlsUtilities.WriteUint16(len, bosMac); + bosMac.Write(message, offset, len); + byte[] macData = bosMac.ToArray(); + mac.BlockUpdate(macData, 0, macData.Length); + byte[] result = new byte[mac.GetMacSize()]; + mac.DoFinal(result, 0); + mac.Reset(); + return result; + } + catch (IOException) + { + // This should never happen + throw new InvalidOperationException("Internal error during mac calculation"); + } + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsNullCipherSuite.cs b/iTechSharp/srcbc/crypto/tls/TlsNullCipherSuite.cs new file mode 100644 index 0000000..e14d062 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsNullCipherSuite.cs @@ -0,0 +1,45 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// A NULL CipherSuite in java, this should only be used during handshake. + public class TlsNullCipherSuite + : TlsCipherSuite + { + internal override void Init( + byte[] ms, + byte[] cr, + byte[] sr) + { + throw new TlsException("Sorry, init of TLS_NULL_WITH_NULL_NULL is forbidden"); + } + + internal override byte[] EncodePlaintext( + short type, + byte[] plaintext, + int offset, + int len) + { + byte[] result = new byte[len]; + Array.Copy(plaintext, offset, result, 0, len); + return result; + } + + internal override byte[] DecodeCiphertext( + short type, + byte[] plaintext, + int offset, + int len, + TlsProtocolHandler handler) + { + byte[] result = new byte[len]; + Array.Copy(plaintext, offset, result, 0, len); + return result; + } + + internal override short KeyExchangeAlgorithm + { + get { return 0; } + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsOutputStream.cs b/iTechSharp/srcbc/crypto/tls/TlsOutputStream.cs new file mode 100644 index 0000000..5f3a625 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsOutputStream.cs @@ -0,0 +1,50 @@ +using System; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// An output Stream for a TLS 1.0 connection. + // TODO Fix name and make internal once TlsProtocolHandler.TlsOuputStream is removed + public class TlsOuputStream + : BaseOutputStream + { + private readonly TlsProtocolHandler handler; + + internal TlsOuputStream( + TlsProtocolHandler handler) + { + this.handler = handler; + } + + public override void Write( + byte[] buf, + int offset, + int len) + { + this.handler.WriteData(buf, offset, len); + } + + [Obsolete("Use version that takes a 'byte' argument")] + public void WriteByte(int arg0) + { + this.Write((byte)arg0); + } + + public override void WriteByte(byte b) + { + this.Write(b); + } + + public override void Close() + { + handler.Close(); + base.Close(); + } + + public override void Flush() + { + handler.Flush(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/crypto/tls/TlsProtocolHandler.cs b/iTechSharp/srcbc/crypto/tls/TlsProtocolHandler.cs new file mode 100644 index 0000000..a8b13f9 --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsProtocolHandler.cs @@ -0,0 +1,1152 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Encodings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Prng; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// An implementation of all high level protocols in TLS 1.0. + public class TlsProtocolHandler + { + private const short RL_CHANGE_CIPHER_SPEC = 20; + private const short RL_ALERT = 21; + private const short RL_HANDSHAKE = 22; + private const short RL_APPLICATION_DATA = 23; + + /* + hello_request(0), client_hello(1), server_hello(2), + certificate(11), server_key_exchange (12), + certificate_request(13), server_hello_done(14), + certificate_verify(15), client_key_exchange(16), + finished(20), (255) + */ + + private const short HP_HELLO_REQUEST = 0; + private const short HP_CLIENT_HELLO = 1; + private const short HP_SERVER_HELLO = 2; + private const short HP_CERTIFICATE = 11; + private const short HP_SERVER_KEY_EXCHANGE = 12; + private const short HP_CERTIFICATE_REQUEST = 13; + private const short HP_SERVER_HELLO_DONE = 14; + private const short HP_CERTIFICATE_VERIFY = 15; + private const short HP_CLIENT_KEY_EXCHANGE = 16; + private const short HP_FINISHED = 20; + + /* + * Our Connection states + */ + + private const short CS_CLIENT_HELLO_SEND = 1; + private const short CS_SERVER_HELLO_RECEIVED = 2; + private const short CS_SERVER_CERTIFICATE_RECEIVED = 3; + private const short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4; + private const short CS_CERTIFICATE_REQUEST_RECEIVED = 5; + private const short CS_SERVER_HELLO_DONE_RECEIVED = 6; + private const short CS_CLIENT_KEY_EXCHANGE_SEND = 7; + private const short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 8; + private const short CS_CLIENT_FINISHED_SEND = 9; + private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 10; + private const short CS_DONE = 11; + + internal const short AP_close_notify = 0; + internal const short AP_unexpected_message = 10; + internal const short AP_bad_record_mac = 20; + internal const short AP_decryption_failed = 21; + internal const short AP_record_overflow = 22; + internal const short AP_decompression_failure = 30; + internal const short AP_handshake_failure = 40; + internal const short AP_bad_certificate = 42; + internal const short AP_unsupported_certificate = 43; + internal const short AP_certificate_revoked = 44; + internal const short AP_certificate_expired = 45; + internal const short AP_certificate_unknown = 46; + internal const short AP_illegal_parameter = 47; + internal const short AP_unknown_ca = 48; + internal const short AP_access_denied = 49; + internal const short AP_decode_error = 50; + internal const short AP_decrypt_error = 51; + internal const short AP_export_restriction = 60; + internal const short AP_protocol_version = 70; + internal const short AP_insufficient_security = 71; + internal const short AP_internal_error = 80; + internal const short AP_user_canceled = 90; + internal const short AP_no_renegotiation = 100; + + internal const short AL_warning = 1; + internal const short AL_fatal = 2; + + private static readonly byte[] emptybuf = new byte[0]; + + private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack"; + + /* + * Queues for data from some protocols. + */ + + private ByteQueue applicationDataQueue = new ByteQueue(); + private ByteQueue changeCipherSpecQueue = new ByteQueue(); + private ByteQueue alertQueue = new ByteQueue(); + private ByteQueue handshakeQueue = new ByteQueue(); + + /* + * The Record Stream we use + */ + private RecordStream rs; + + private SecureRandom random; + + /* + * The public rsa-key of the server. + */ + private RsaKeyParameters serverRsaKey = null; + + private TlsInputStream tlsInputStream = null; + private TlsOuputStream tlsOutputStream = null; + + private bool closed = false; + private bool failedWithError = false; + private bool appDataReady = false; + + private byte[] clientRandom; + private byte[] serverRandom; + private byte[] ms; + + private TlsCipherSuite choosenCipherSuite = null; + + private BigInteger Yc; + private byte[] pms; + + private ICertificateVerifyer verifyer = null; + + /* + * Both streams can be the same object + */ + public TlsProtocolHandler( + Stream inStr, + Stream outStr) + { + /* + * We use a threaded seed generator to generate a good random + * seed. If the user has a better random seed, he should use + * the constructor with a SecureRandom. + * + * Hopefully, 20 bytes in fast mode are good enough. + */ + byte[] seed = new ThreadedSeedGenerator().GenerateSeed(20, true); + + this.random = new SecureRandom(seed); + this.rs = new RecordStream(this, inStr, outStr); + } + + public TlsProtocolHandler( + Stream inStr, + Stream outStr, + SecureRandom sr) + { + this.random = sr; + this.rs = new RecordStream(this, inStr, outStr); + } + + private short connection_state; + + internal void ProcessData( + short protocol, + byte[] buf, + int offset, + int len) + { + /* + * Have a look at the protocol type, and add it to the correct queue. + */ + switch (protocol) + { + case RL_CHANGE_CIPHER_SPEC: + changeCipherSpecQueue.AddData(buf, offset, len); + processChangeCipherSpec(); + break; + case RL_ALERT: + alertQueue.AddData(buf, offset, len); + processAlert(); + break; + case RL_HANDSHAKE: + handshakeQueue.AddData(buf, offset, len); + processHandshake(); + break; + case RL_APPLICATION_DATA: + if (!appDataReady) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + applicationDataQueue.AddData(buf, offset, len); + processApplicationData(); + break; + default: + /* + * Uh, we don't know this protocol. + * + * RFC2246 defines on page 13, that we should ignore this. + */ + break; + } + } + + private void processHandshake() + { + bool read; + do + { + read = false; + + /* + * We need the first 4 bytes, they contain type and length of + * the message. + */ + if (handshakeQueue.Available >= 4) + { + byte[] beginning = new byte[4]; + handshakeQueue.Read(beginning, 0, 4, 0); + MemoryStream bis = new MemoryStream(beginning, false); + short type = TlsUtilities.ReadUint8(bis); + int len = TlsUtilities.ReadUint24(bis); + + /* + * Check if we have enough bytes in the buffer to read + * the full message. + */ + if (handshakeQueue.Available >= (len + 4)) + { + /* + * Read the message. + */ + byte[] buf = new byte[len]; + handshakeQueue.Read(buf, 0, len, 4); + handshakeQueue.RemoveData(len + 4); + + /* + * If it is not a finished message, update our hashes + * we prepare for the finish message. + */ + if (type != HP_FINISHED) + { + rs.hash1.BlockUpdate(beginning, 0, 4); + rs.hash2.BlockUpdate(beginning, 0, 4); + rs.hash1.BlockUpdate(buf, 0, len); + rs.hash2.BlockUpdate(buf, 0, len); + } + + /* + * Now, parse the message. + */ + MemoryStream inStr = new MemoryStream(buf, false); + + /* + * Check the type. + */ + switch (type) + { + case HP_CERTIFICATE: + switch (connection_state) + { + case CS_SERVER_HELLO_RECEIVED: + /* + * Parse the certificates. + */ + Certificate cert = Certificate.Parse(inStr); + AssertEmpty(inStr); + + /* + * Verify them. + */ + if (!this.verifyer.IsValid(cert.GetCerts())) + { + this.FailWithError(AL_fatal, AP_user_canceled); + } + + /* + * We only support RSA certificates. Lets hope + * this is one. + */ + RsaPublicKeyStructure rsaKey = null; + try + { + rsaKey = RsaPublicKeyStructure.GetInstance( + cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey()); + } + catch (Exception) + { + /* + * Sorry, we have to fail ;-( + */ + this.FailWithError(AL_fatal, AP_unsupported_certificate); + } + + /* + * Parse the servers public RSA key. + */ + this.serverRsaKey = new RsaKeyParameters( + false, + rsaKey.Modulus, + rsaKey.PublicExponent); + + connection_state = CS_SERVER_CERTIFICATE_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_FINISHED: + switch (connection_state) + { + case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED: + /* + * Read the checksum from the finished message, + * it has always 12 bytes. + */ + byte[] receivedChecksum = new byte[12]; + TlsUtilities.ReadFully(receivedChecksum, inStr); + AssertEmpty(inStr); + + /* + * Calculate our own checksum. + */ + byte[] checksum = new byte[12]; + byte[] md5andsha1 = new byte[16 + 20]; + rs.hash2.DoFinal(md5andsha1, 0); + TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum); + + /* + * Compare both checksums. + */ + for (int i = 0; i < receivedChecksum.Length; i++) + { + if (receivedChecksum[i] != checksum[i]) + { + /* + * Wrong checksum in the finished message. + */ + this.FailWithError(AL_fatal, AP_handshake_failure); + } + } + + connection_state = CS_DONE; + + /* + * We are now ready to receive application data. + */ + this.appDataReady = true; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_SERVER_HELLO: + switch (connection_state) + { + case CS_CLIENT_HELLO_SEND: + /* + * Read the server hello message + */ + TlsUtilities.CheckVersion(inStr, this); + + /* + * Read the server random + */ + this.serverRandom = new byte[32]; + TlsUtilities.ReadFully(this.serverRandom, inStr); + + /* + * Currently, we don't support session ids + */ + short sessionIdLength = TlsUtilities.ReadUint8(inStr); + byte[] sessionId = new byte[sessionIdLength]; + TlsUtilities.ReadFully(sessionId, inStr); + + /* + * Find out which ciphersuite the server has + * chosen. If we don't support this ciphersuite, + * the TlsCipherSuiteManager will throw an + * exception. + */ + this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite( + TlsUtilities.ReadUint16(inStr), this); + + /* + * We support only the null compression which + * means no compression. + */ + short compressionMethod = TlsUtilities.ReadUint8(inStr); + if (compressionMethod != 0) + { + this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter); + } + AssertEmpty(inStr); + + connection_state = CS_SERVER_HELLO_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_SERVER_HELLO_DONE: + switch (connection_state) + { + case CS_SERVER_CERTIFICATE_RECEIVED: + case CS_SERVER_KEY_EXCHANGE_RECEIVED: + case CS_CERTIFICATE_REQUEST_RECEIVED: + + // NB: Original code used case label fall-through + if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) + { + /* + * There was no server key exchange message, check + * that we are doing RSA key exchange. + */ + if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + } + + AssertEmpty(inStr); + bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED); + connection_state = CS_SERVER_HELLO_DONE_RECEIVED; + + if (isCertReq) + { + sendClientCertificate(); + } + + /* + * Send the client key exchange message, depending + * on the key exchange we are using in our + * ciphersuite. + */ + short ke = this.choosenCipherSuite.KeyExchangeAlgorithm; + + switch (ke) + { + case TlsCipherSuite.KE_RSA: + /* + * We are doing RSA key exchange. We will + * choose a pre master secret and send it + * rsa encrypted to the server. + * + * Prepare pre master secret. + */ + pms = new byte[48]; + pms[0] = 3; + pms[1] = 1; + random.NextBytes(pms, 2, 46); + + /* + * Encode the pms and send it to the server. + * + * Prepare an Pkcs1Encoding with good random + * padding. + */ + RsaBlindedEngine rsa = new RsaBlindedEngine(); + Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); + encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random)); + byte[] encrypted = null; + try + { + encrypted = encoding.ProcessBlock(pms, 0, pms.Length); + } + catch (InvalidCipherTextException) + { + /* + * This should never happen, only during decryption. + */ + this.FailWithError(AL_fatal, AP_internal_error); + } + + /* + * Send the encrypted pms. + */ + MemoryStream bos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos); + TlsUtilities.WriteUint24(encrypted.Length + 2, bos); + TlsUtilities.WriteUint16(encrypted.Length, bos); + bos.Write(encrypted, 0, encrypted.Length); + byte[] message = bos.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); + break; + case TlsCipherSuite.KE_DHE_RSA: + /* + * Send the Client Key Exchange message for + * DHE key exchange. + */ + byte[] YcByte = this.Yc.ToByteArray(); + MemoryStream DHbos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos); + TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos); + TlsUtilities.WriteUint16(YcByte.Length, DHbos); + DHbos.Write(YcByte, 0, YcByte.Length); + byte[] DHmessage = DHbos.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length); + + break; + default: + /* + * Problem during handshake, we don't know + * how to handle this key exchange method. + */ + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + + } + + connection_state = CS_CLIENT_KEY_EXCHANGE_SEND; + + /* + * Now, we send change cipher state + */ + byte[] cmessage = new byte[1]; + cmessage[0] = 1; + rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length); + + connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND; + + /* + * Calculate the ms + */ + this.ms = new byte[48]; + byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length]; + Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length); + Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length); + TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms); + + /* + * Initialize our cipher suite + */ + rs.writeSuite = this.choosenCipherSuite; + rs.writeSuite.Init(this.ms, clientRandom, serverRandom); + + /* + * Send our finished message. + */ + byte[] checksum = new byte[12]; + byte[] md5andsha1 = new byte[16 + 20]; + rs.hash1.DoFinal(md5andsha1, 0); + TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum); + + MemoryStream bos2 = new MemoryStream(); + TlsUtilities.WriteUint8(HP_FINISHED, bos2); + TlsUtilities.WriteUint24(12, bos2); + bos2.Write(checksum, 0, checksum.Length); + byte[] message2 = bos2.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length); + + this.connection_state = CS_CLIENT_FINISHED_SEND; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_handshake_failure); + break; + } + break; + case HP_SERVER_KEY_EXCHANGE: + switch (connection_state) + { + case CS_SERVER_CERTIFICATE_RECEIVED: + /* + * Check that we are doing DHE key exchange + */ + if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + + /* + * Parse the Structure + */ + int pLength = TlsUtilities.ReadUint16(inStr); + byte[] pByte = new byte[pLength]; + TlsUtilities.ReadFully(pByte, inStr); + + int gLength = TlsUtilities.ReadUint16(inStr); + byte[] gByte = new byte[gLength]; + TlsUtilities.ReadFully(gByte, inStr); + + int YsLength = TlsUtilities.ReadUint16(inStr); + byte[] YsByte = new byte[YsLength]; + TlsUtilities.ReadFully(YsByte, inStr); + + int sigLength = TlsUtilities.ReadUint16(inStr); + byte[] sigByte = new byte[sigLength]; + TlsUtilities.ReadFully(sigByte, inStr); + + AssertEmpty(inStr); + + /* + * Verify the Signature. + * + * First, calculate the hash. + */ + CombinedHash sigDigest = new CombinedHash(); + MemoryStream signedData = new MemoryStream(); + TlsUtilities.WriteUint16(pLength, signedData); + signedData.Write(pByte, 0, pByte.Length); + TlsUtilities.WriteUint16(gLength, signedData); + signedData.Write(gByte, 0, gByte.Length); + TlsUtilities.WriteUint16(YsLength, signedData); + signedData.Write(YsByte, 0, YsByte.Length); + byte[] signed = signedData.ToArray(); + + sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length); + sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length); + sigDigest.BlockUpdate(signed, 0, signed.Length); + byte[] hash = new byte[sigDigest.GetDigestSize()]; + sigDigest.DoFinal(hash, 0); + + /* + * Now, do the RSA operation + */ + RsaBlindedEngine rsa = new RsaBlindedEngine(); + Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); + encoding.Init(false, this.serverRsaKey); + + /* + * The data which was signed + */ + byte[] sigHash = null; + + try + { + sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length); + } + catch (InvalidCipherTextException) + { + this.FailWithError(AL_fatal, AP_bad_certificate); + } + + /* + * Check if the data which was signed is equal to + * the hash we calculated. + */ + if (sigHash.Length != hash.Length) + { + this.FailWithError(AL_fatal, AP_bad_certificate); + } + + for (int i = 0; i < sigHash.Length; i++) + { + if (sigHash[i] != hash[i]) + { + this.FailWithError(AL_fatal, AP_bad_certificate); + } + } + + /* + * OK, Signature was correct. + * + * Do the DH calculation. + */ + BigInteger p = new BigInteger(1, pByte); + BigInteger g = new BigInteger(1, gByte); + BigInteger Ys = new BigInteger(1, YsByte); + BigInteger x = new BigInteger(p.BitLength - 1, this.random); + Yc = g.ModPow(x, p); + this.pms = Ys.ModPow(x, p).ToByteArrayUnsigned(); + + this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_CERTIFICATE_REQUEST: + switch (connection_state) + { + case CS_SERVER_CERTIFICATE_RECEIVED: + case CS_SERVER_KEY_EXCHANGE_RECEIVED: + + // NB: Original code used case label fall-through + if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) + { + /* + * There was no server key exchange message, check + * that we are doing RSA key exchange. + */ + if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + } + + int typesLength = TlsUtilities.ReadUint8(inStr); + byte[] types = new byte[typesLength]; + TlsUtilities.ReadFully(types, inStr); + + int authsLength = TlsUtilities.ReadUint16(inStr); + byte[] auths = new byte[authsLength]; + TlsUtilities.ReadFully(auths, inStr); + + AssertEmpty(inStr); + + this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_HELLO_REQUEST: + case HP_CLIENT_KEY_EXCHANGE: + case HP_CERTIFICATE_VERIFY: + case HP_CLIENT_HELLO: + default: + // We do not support this! + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + + } + + } + } + } + while (read); + + } + + private void processApplicationData() + { + /* + * There is nothing we need to do here. + * + * This function could be used for callbacks when application + * data arrives in the future. + */ + } + + private void processAlert() + { + while (alertQueue.Available >= 2) + { + /* + * An alert is always 2 bytes. Read the alert. + */ + byte[] tmp = new byte[2]; + alertQueue.Read(tmp, 0, 2, 0); + alertQueue.RemoveData(2); + short level = tmp[0]; + short description = tmp[1]; + if (level == AL_fatal) + { + /* + * This is a fatal error. + */ + this.failedWithError = true; + this.closed = true; + /* + * Now try to Close the stream, ignore errors. + */ + try + { + rs.Close(); + } + catch (Exception) + { + } + throw new IOException(TLS_ERROR_MESSAGE); + } + else + { + /* + * This is just a warning. + */ + if (description == AP_close_notify) + { + /* + * Close notify + */ + this.FailWithError(AL_warning, AP_close_notify); + } + /* + * If it is just a warning, we continue. + */ + } + } + + } + + /** + * This method is called, when a change cipher spec message is received. + * + * @throws IOException If the message has an invalid content or the + * handshake is not in the correct state. + */ + private void processChangeCipherSpec() + { + while (changeCipherSpecQueue.Available > 0) + { + /* + * A change cipher spec message is only one byte with the value 1. + */ + byte[] b = new byte[1]; + changeCipherSpecQueue.Read(b, 0, 1, 0); + changeCipherSpecQueue.RemoveData(1); + if (b[0] != 1) + { + /* + * This should never happen. + */ + this.FailWithError(AL_fatal, AP_unexpected_message); + + } + else + { + /* + * Check if we are in the correct connection state. + */ + if (this.connection_state == CS_CLIENT_FINISHED_SEND) + { + rs.readSuite = rs.writeSuite; + this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED; + } + else + { + /* + * We are not in the correct connection state. + */ + this.FailWithError(AL_fatal, AP_handshake_failure); + } + + } + } + } + + private void sendClientCertificate() + { + /* + * just write back the "no client certificate" message + * see also gnutls, auth_cert.c:643 (0B 00 00 03 00 00 00) + */ + MemoryStream bos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CERTIFICATE, bos); + TlsUtilities.WriteUint24(3, bos); + TlsUtilities.WriteUint24(0, bos); + byte[] message = bos.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); + } + + ///

      Connects to the remote system. + /// Will be used when a certificate is received to verify + /// that this certificate is accepted by the client. + /// If handshake was not successful + public virtual void Connect( + ICertificateVerifyer verifyer) + { + this.verifyer = verifyer; + + /* + * Send Client hello + * + * First, generate some random data. + */ + this.clientRandom = new byte[32]; + + /* + * TLS 1.0 requires a unix-timestamp in the first 4 bytes + */ + int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L); + this.clientRandom[0] = (byte)(t >> 24); + this.clientRandom[1] = (byte)(t >> 16); + this.clientRandom[2] = (byte)(t >> 8); + this.clientRandom[3] = (byte)t; + + random.NextBytes(this.clientRandom, 4, 28); + + + MemoryStream outStr = new MemoryStream(); + TlsUtilities.WriteVersion(outStr); + outStr.Write(this.clientRandom, 0, this.clientRandom.Length); + + /* + * Length of Session id + */ + TlsUtilities.WriteUint8((short)0, outStr); + + /* + * Cipher suites + */ + TlsCipherSuiteManager.WriteCipherSuites(outStr); + + /* + * Compression methods, just the null method. + */ + byte[] compressionMethods = new byte[]{0x00}; + TlsUtilities.WriteUint8((short)compressionMethods.Length, outStr); + outStr.Write(compressionMethods,0, compressionMethods.Length); + + + MemoryStream bos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos); + TlsUtilities.WriteUint24((int) outStr.Length, bos); + byte[] outBytes = outStr.ToArray(); + bos.Write(outBytes, 0, outBytes.Length); + byte[] message = bos.ToArray(); + rs.WriteMessage(RL_HANDSHAKE, message, 0, message.Length); + connection_state = CS_CLIENT_HELLO_SEND; + + /* + * We will now read data, until we have completed the handshake. + */ + while (connection_state != CS_DONE) + { + rs.ReadData(); + } + + this.tlsInputStream = new TlsInputStream(this); + this.tlsOutputStream = new TlsOuputStream(this); + } + + /** + * Read data from the network. The method will return immed, if there is + * still some data left in the buffer, or block untill some application + * data has been read from the network. + * + * @param buf The buffer where the data will be copied to. + * @param offset The position where the data will be placed in the buffer. + * @param len The maximum number of bytes to read. + * @return The number of bytes read. + * @throws IOException If something goes wrong during reading data. + */ + internal int ReadApplicationData(byte[] buf, int offset, int len) + { + while (applicationDataQueue.Available == 0) + { + /* + * We need to read some data. + */ + if (this.failedWithError) + { + /* + * Something went terribly wrong, we should throw an IOException + */ + throw new IOException(TLS_ERROR_MESSAGE); + } + if (this.closed) + { + /* + * Connection has been closed, there is no more data to read. + */ + return 0; + } + + try + { + rs.ReadData(); + } + catch (IOException e) + { + if (!this.closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + catch (Exception e) + { + if (!this.closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + } + len = System.Math.Min(len, applicationDataQueue.Available); + applicationDataQueue.Read(buf, offset, len, 0); + applicationDataQueue.RemoveData(len); + return len; + } + + /** + * Send some application data to the remote system. + *

      + * The method will handle fragmentation internally. + * + * @param buf The buffer with the data. + * @param offset The position in the buffer where the data is placed. + * @param len The length of the data. + * @throws IOException If something goes wrong during sending. + */ + internal void WriteData(byte[] buf, int offset, int len) + { + if (this.failedWithError) + { + throw new IOException(TLS_ERROR_MESSAGE); + } + if (this.closed) + { + throw new IOException("Sorry, connection has been closed, you cannot write more data"); + } + + /* + * Protect against known IV attack! + * + * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT + * YOU ARE DOING HERE. + */ + rs.WriteMessage(RL_APPLICATION_DATA, emptybuf, 0, 0); + + do + { + /* + * We are only allowed to write fragments up to 2^14 bytes. + */ + int toWrite = System.Math.Min(len, 1 << 14); + + try + { + rs.WriteMessage(RL_APPLICATION_DATA, buf, offset, toWrite); + } + catch (IOException e) + { + if (!closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + catch (Exception e) + { + if (!closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + + + offset += toWrite; + len -= toWrite; + } + while (len > 0); + + } + + [Obsolete("Use 'OutputStream' property instead")] + public TlsOuputStream TlsOuputStream + { + get { return this.tlsOutputStream; } + } + + ///

      A Stream which can be used to send data. + public virtual Stream OutputStream + { + get { return this.tlsOutputStream; } + } + + [Obsolete("Use 'InputStream' property instead")] + public TlsInputStream TlsInputStream + { + get { return this.tlsInputStream; } + } + + /// A Stream which can be used to read data. + public virtual Stream InputStream + { + get { return this.tlsInputStream; } + } + + /** + * Terminate this connection whith an alert. + *

      + * Can be used for normal closure too. + * + * @param alertLevel The level of the alert, an be AL_fatal or AL_warning. + * @param alertDescription The exact alert message. + * @throws IOException If alert was fatal. + */ + internal void FailWithError( + short alertLevel, + short alertDescription) + { + /* + * Check if the connection is still open. + */ + if (!closed) + { + /* + * Prepare the message + */ + byte[] error = new byte[2]; + error[0] = (byte)alertLevel; + error[1] = (byte)alertDescription; + this.closed = true; + + if (alertLevel == AL_fatal) + { + /* + * This is a fatal message. + */ + this.failedWithError = true; + } + rs.WriteMessage(RL_ALERT, error, 0, 2); + rs.Close(); + if (alertLevel == AL_fatal) + { + throw new IOException(TLS_ERROR_MESSAGE); + } + + } + else + { + throw new IOException(TLS_ERROR_MESSAGE); + } + } + + ///

      Closes this connection + /// If something goes wrong during closing. + public virtual void Close() + { + if (!closed) + { + this.FailWithError((short)1, (short)0); + } + } + + /** + * Make sure the Stream is now empty. Fail otherwise. + * + * @param is The Stream to check. + * @throws IOException If is is not empty. + */ + internal void AssertEmpty( + MemoryStream inStr) + { +// if (inStr.available() > 0) + if (inStr.Position < inStr.Length) + { + this.FailWithError(AL_fatal, AP_decode_error); + } + } + + internal void Flush() + { + rs.Flush(); + } + } +} diff --git a/iTechSharp/srcbc/crypto/tls/TlsUtilities.cs b/iTechSharp/srcbc/crypto/tls/TlsUtilities.cs new file mode 100644 index 0000000..8fad3dd --- /dev/null +++ b/iTechSharp/srcbc/crypto/tls/TlsUtilities.cs @@ -0,0 +1,223 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// Some helper fuctions for MicroTLS. + public class TlsUtilities + { + internal static byte[] ToByteArray(string str) + { + return Strings.ToByteArray(str); + } + + internal static void WriteUint8(short i, Stream os) + { + os.WriteByte((byte)i); + } + + internal static void WriteUint8(short i, byte[] buf, int offset) + { + buf[offset] = (byte)i; + } + + internal static void WriteUint16(int i, Stream os) + { + os.WriteByte((byte)(i >> 8)); + os.WriteByte((byte)i); + } + + internal static void WriteUint16(int i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >> 8); + buf[offset + 1] = (byte)i; + } + + internal static void WriteUint24(int i, Stream os) + { + os.WriteByte((byte)(i >> 16)); + os.WriteByte((byte)(i >> 8)); + os.WriteByte((byte)i); + } + + internal static void WriteUint24(int i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >> 16); + buf[offset + 1] = (byte)(i >> 8); + buf[offset + 2] = (byte)(i); + } + + internal static void WriteUint32(long i, Stream os) + { + os.WriteByte((byte)(i >> 24)); + os.WriteByte((byte)(i >> 16)); + os.WriteByte((byte)(i >> 8)); + os.WriteByte((byte)i); + } + + internal static void WriteUint32(long i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >> 24); + buf[offset + 1] = (byte)(i >> 16); + buf[offset + 2] = (byte)(i >> 8); + buf[offset + 3] = (byte)(i); + } + + internal static void WriteUint64(long i, Stream os) + { + os.WriteByte((byte)(i >> 56)); + os.WriteByte((byte)(i >> 48)); + os.WriteByte((byte)(i >> 40)); + os.WriteByte((byte)(i >> 32)); + os.WriteByte((byte)(i >> 24)); + os.WriteByte((byte)(i >> 16)); + os.WriteByte((byte)(i >> 8)); + os.WriteByte((byte)i); + } + + internal static void WriteUint64(long i, byte[] buf, int offset) + { + buf[offset] = (byte)(i >> 56); + buf[offset + 1] = (byte)(i >> 48); + buf[offset + 2] = (byte)(i >> 40); + buf[offset + 3] = (byte)(i >> 32); + buf[offset + 4] = (byte)(i >> 24); + buf[offset + 5] = (byte)(i >> 16); + buf[offset + 6] = (byte)(i >> 8); + buf[offset + 7] = (byte)(i); + } + + internal static short ReadUint8(Stream inStr) + { + int i = inStr.ReadByte(); + if (i < 0) + { + throw new EndOfStreamException(); + } + return (short)i; + } + + internal static int ReadUint16(Stream inStr) + { + int i1 = inStr.ReadByte(); + int i2 = inStr.ReadByte(); + if ((i1 | i2) < 0) + { + throw new EndOfStreamException(); + } + return i1 << 8 | i2; + } + + internal static int ReadUint24(Stream inStr) + { + int i1 = inStr.ReadByte(); + int i2 = inStr.ReadByte(); + int i3 = inStr.ReadByte(); + if ((i1 | i2 | i3) < 0) + { + throw new EndOfStreamException(); + } + return (i1 << 16) | (i2 << 8) | i3; + } + + internal static long ReadUint32(Stream inStr) + { + int i1 = inStr.ReadByte(); + int i2 = inStr.ReadByte(); + int i3 = inStr.ReadByte(); + int i4 = inStr.ReadByte(); + if ((i1 | i2 | i3 | i4) < 0) + { + throw new EndOfStreamException(); + } + // TODO Examine this +// return (((long)i1) << 24) | (((long)i2) << 16) | (((long)i3) << 8) | ((long)i4); + return ((long)i1 << 24) | ((long)i2 << 16) | ((long)i3 << 8) | (uint)i4; + } + + internal static void ReadFully(byte[] buf, Stream inStr) + { + if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length) + throw new EndOfStreamException(); + } + + internal static void CheckVersion(byte[] readVersion, TlsProtocolHandler handler) + { + if ((readVersion[0] != 3) || (readVersion[1] != 1)) + { + handler.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_protocol_version); + } + } + + internal static void CheckVersion(Stream inStr, TlsProtocolHandler handler) + { + int i1 = inStr.ReadByte(); + int i2 = inStr.ReadByte(); + if ((i1 != 3) || (i2 != 1)) + { + handler.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_protocol_version); + } + } + + internal static void WriteVersion(Stream os) + { + os.WriteByte(3); + os.WriteByte(1); + } + + private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output) + { + HMac mac = new HMac(digest); + KeyParameter param = new KeyParameter(secret); + byte[] a = seed; + int size = digest.GetDigestSize(); + int iterations = (output.Length + size - 1) / size; + byte[] buf = new byte[mac.GetMacSize()]; + byte[] buf2 = new byte[mac.GetMacSize()]; + for (int i = 0; i < iterations; i++) + { + mac.Init(param); + mac.BlockUpdate(a, 0, a.Length); + mac.DoFinal(buf, 0); + a = buf; + mac.Init(param); + mac.BlockUpdate(a, 0, a.Length); + mac.BlockUpdate(seed, 0, seed.Length); + mac.DoFinal(buf2, 0); + Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i))); + } + } + + internal static void PRF( + byte[] secret, + byte[] label, + byte[] seed, + byte[] buf) + { + int s_half = (secret.Length + 1) / 2; + byte[] s1 = new byte[s_half]; + byte[] s2 = new byte[s_half]; + Array.Copy(secret, 0, s1, 0, s_half); + Array.Copy(secret, secret.Length - s_half, s2, 0, s_half); + + byte[] ls = new byte[label.Length + seed.Length]; + Array.Copy(label, 0, ls, 0, label.Length); + Array.Copy(seed, 0, ls, label.Length, seed.Length); + + byte[] prf = new byte[buf.Length]; + hmac_hash(new MD5Digest(), s1, ls, prf); + hmac_hash(new Sha1Digest(), s2, ls, buf); + for (int i = 0; i < buf.Length; i++) + { + buf[i] ^= prf[i]; + } + } + } +} diff --git a/iTechSharp/srcbc/math/BigInteger.cs b/iTechSharp/srcbc/math/BigInteger.cs new file mode 100644 index 0000000..d1fb5f2 --- /dev/null +++ b/iTechSharp/srcbc/math/BigInteger.cs @@ -0,0 +1,3152 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +namespace Org.BouncyCastle.Math +{ +#if !NETCF_1_0 + [Serializable] +#endif + public class BigInteger + { + // The primes b/w 2 and ~2^10 + /* + 3 5 7 11 13 17 19 23 29 + 31 37 41 43 47 53 59 61 67 71 + 73 79 83 89 97 101 103 107 109 113 + 127 131 137 139 149 151 157 163 167 173 + 179 181 191 193 197 199 211 223 227 229 + 233 239 241 251 257 263 269 271 277 281 + 283 293 307 311 313 317 331 337 347 349 + 353 359 367 373 379 383 389 397 401 409 + 419 421 431 433 439 443 449 457 461 463 + 467 479 487 491 499 503 509 521 523 541 + 547 557 563 569 571 577 587 593 599 601 + 607 613 617 619 631 641 643 647 653 659 + 661 673 677 683 691 701 709 719 727 733 + 739 743 751 757 761 769 773 787 797 809 + 811 821 823 827 829 839 853 857 859 863 + 877 881 883 887 907 911 919 929 937 941 + 947 953 967 971 977 983 991 997 + 1009 1013 1019 1021 1031 + */ + + // Each list has a product < 2^31 + private static readonly int[][] primeLists = new int[][] + { + new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 }, + new int[]{ 29, 31, 37, 41, 43 }, + new int[]{ 47, 53, 59, 61, 67 }, + new int[]{ 71, 73, 79, 83 }, + new int[]{ 89, 97, 101, 103 }, + + new int[]{ 107, 109, 113, 127 }, + new int[]{ 131, 137, 139, 149 }, + new int[]{ 151, 157, 163, 167 }, + new int[]{ 173, 179, 181, 191 }, + new int[]{ 193, 197, 199, 211 }, + + new int[]{ 223, 227, 229 }, + new int[]{ 233, 239, 241 }, + new int[]{ 251, 257, 263 }, + new int[]{ 269, 271, 277 }, + new int[]{ 281, 283, 293 }, + + new int[]{ 307, 311, 313 }, + new int[]{ 317, 331, 337 }, + new int[]{ 347, 349, 353 }, + new int[]{ 359, 367, 373 }, + new int[]{ 379, 383, 389 }, + + new int[]{ 397, 401, 409 }, + new int[]{ 419, 421, 431 }, + new int[]{ 433, 439, 443 }, + new int[]{ 449, 457, 461 }, + new int[]{ 463, 467, 479 }, + + new int[]{ 487, 491, 499 }, + new int[]{ 503, 509, 521 }, + new int[]{ 523, 541, 547 }, + new int[]{ 557, 563, 569 }, + new int[]{ 571, 577, 587 }, + + new int[]{ 593, 599, 601 }, + new int[]{ 607, 613, 617 }, + new int[]{ 619, 631, 641 }, + new int[]{ 643, 647, 653 }, + new int[]{ 659, 661, 673 }, + + new int[]{ 677, 683, 691 }, + new int[]{ 701, 709, 719 }, + new int[]{ 727, 733, 739 }, + new int[]{ 743, 751, 757 }, + new int[]{ 761, 769, 773 }, + + new int[]{ 787, 797, 809 }, + new int[]{ 811, 821, 823 }, + new int[]{ 827, 829, 839 }, + new int[]{ 853, 857, 859 }, + new int[]{ 863, 877, 881 }, + + new int[]{ 883, 887, 907 }, + new int[]{ 911, 919, 929 }, + new int[]{ 937, 941, 947 }, + new int[]{ 953, 967, 971 }, + new int[]{ 977, 983, 991 }, + + new int[]{ 997, 1009, 1013 }, + new int[]{ 1019, 1021, 1031 }, + }; + + private static readonly int[] primeProducts; + + private const long IMASK = 0xffffffffL; + private static readonly ulong UIMASK = (ulong)IMASK; + + private static readonly int[] ZeroMagnitude = new int[0]; + private static readonly byte[] ZeroEncoding = new byte[0]; + + public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false); + public static readonly BigInteger One = createUValueOf(1); + public static readonly BigInteger Two = createUValueOf(2); + public static readonly BigInteger Three = createUValueOf(3); + public static readonly BigInteger Ten = createUValueOf(10); + + private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time + private static readonly BigInteger radix2 = ValueOf(2); + private static readonly BigInteger radix2E = radix2.Pow(chunk2); + + private static readonly int chunk10 = 19; + private static readonly BigInteger radix10 = ValueOf(10); + private static readonly BigInteger radix10E = radix10.Pow(chunk10); + + private static readonly int chunk16 = 16; + private static readonly BigInteger radix16 = ValueOf(16); + private static readonly BigInteger radix16E = radix16.Pow(chunk16); + + private static readonly Random RandomSource = new Random(); + + private const int BitsPerByte = 8; + private const int BitsPerInt = 32; + private const int BytesPerInt = 4; + + static BigInteger() + { + primeProducts = new int[primeLists.Length]; + + for (int i = 0; i < primeLists.Length; ++i) + { + int[] primeList = primeLists[i]; + int product = 1; + for (int j = 0; j < primeList.Length; ++j) + { + product *= primeList[j]; + } + primeProducts[i] = product; + } + } + + private int sign; // -1 means -ve; +1 means +ve; 0 means 0; + private int[] magnitude; // array of ints with [0] being the most significant + private int nBits = -1; // cache BitCount() value + private int nBitLength = -1; // cache calcBitLength() value + private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.) + + private static int GetByteLength( + int nBits) + { + return (nBits + BitsPerByte - 1) / BitsPerByte; + } + + private BigInteger() + { + } + + private BigInteger( + int signum, + int[] mag, + bool checkMag) + { + if (checkMag) + { + int i = 0; + while (i < mag.Length && mag[i] == 0) + { + ++i; + } + + if (i == mag.Length) + { +// this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else + { + this.sign = signum; + + if (i == 0) + { + this.magnitude = mag; + } + else + { + // strip leading 0 words + this.magnitude = new int[mag.Length - i]; + Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length); + } + } + } + else + { + this.sign = signum; + this.magnitude = mag; + } + } + + public BigInteger( + string value) + : this(value, 10) + { + } + + public BigInteger( + string str, + int radix) + { + if (str.Length == 0) + throw new FormatException("Zero length BigInteger"); + + NumberStyles style; + int chunk; + BigInteger r; + BigInteger rE; + + switch (radix) + { + case 2: + // Is there anyway to restrict to binary digits? + style = NumberStyles.Integer; + chunk = chunk2; + r = radix2; + rE = radix2E; + break; + case 10: + // This style seems to handle spaces and minus sign already (our processing redundant?) + style = NumberStyles.Integer; + chunk = chunk10; + r = radix10; + rE = radix10E; + break; + case 16: + // TODO Should this be HexNumber? + style = NumberStyles.AllowHexSpecifier; + chunk = chunk16; + r = radix16; + rE = radix16E; + break; + default: + throw new FormatException("Only bases 2, 10, or 16 allowed"); + } + + + int index = 0; + sign = 1; + + if (str[0] == '-') + { + if (str.Length == 1) + throw new FormatException("Zero length BigInteger"); + + sign = -1; + index = 1; + } + + // strip leading zeros from the string str + while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0) + { + index++; + } + + if (index >= str.Length) + { + // zero value - we're done + sign = 0; + magnitude = ZeroMagnitude; + return; + } + + ////// + // could we work out the max number of ints required to store + // str.Length digits in the given base, then allocate that + // storage in one hit?, then Generate the magnitude in one hit too? + ////// + + BigInteger b = Zero; + + + int next = index + chunk; + + if (next <= str.Length) + { + do + { + string s = str.Substring(index, chunk); + ulong i = ulong.Parse(s, style); + BigInteger bi = createUValueOf(i); + + switch (radix) + { + case 2: + // TODO Need this because we are parsing in radix 10 above + if (i > 1) + throw new FormatException("Bad character in radix 2 string: " + s); + + // TODO Parse 64 bits at a time + b = b.ShiftLeft(1); + break; + case 16: + b = b.ShiftLeft(64); + break; + default: + b = b.Multiply(rE); + break; + } + + b = b.Add(bi); + + index = next; + next += chunk; + } + while (next <= str.Length); + } + + if (index < str.Length) + { + string s = str.Substring(index); + ulong i = ulong.Parse(s, style); + BigInteger bi = createUValueOf(i); + + if (b.sign > 0) + { + if (radix == 2) + { + // NB: Can't reach here since we are parsing one char at a time + Debug.Assert(false); + + // TODO Parse all bits at once +// b = b.ShiftLeft(s.Length); + } + else if (radix == 16) + { + b = b.ShiftLeft(s.Length << 2); + } + else + { + b = b.Multiply(r.Pow(s.Length)); + } + + b = b.Add(bi); + } + else + { + b = bi; + } + } + + // Note: This is the previous (slower) algorithm + // while (index < value.Length) + // { + // char c = value[index]; + // string s = c.ToString(); + // int i = Int32.Parse(s, style); + // + // b = b.Multiply(r).Add(ValueOf(i)); + // index++; + // } + + magnitude = b.magnitude; + } + + public BigInteger( + byte[] bytes) + : this(bytes, 0, bytes.Length) + { + } + + public BigInteger( + byte[] bytes, + int offset, + int length) + { + if (length == 0) + throw new FormatException("Zero length BigInteger"); + + // TODO Move this processing into MakeMagnitude (provide sign argument) + if ((sbyte)bytes[offset] < 0) + { + this.sign = -1; + + int end = offset + length; + + int iBval; + // strip leading sign bytes + for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++) + { + } + + if (iBval >= end) + { + this.magnitude = One.magnitude; + } + else + { + int numBytes = end - iBval; + byte[] inverse = new byte[numBytes]; + + int index = 0; + while (index < numBytes) + { + inverse[index++] = (byte)~bytes[iBval++]; + } + + Debug.Assert(iBval == end); + + while (inverse[--index] == byte.MaxValue) + { + inverse[index] = byte.MinValue; + } + + inverse[index]++; + + this.magnitude = MakeMagnitude(inverse, 0, inverse.Length); + } + } + else + { + // strip leading zero bytes and return magnitude bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length > 0 ? 1 : 0; + } + } + + private static int[] MakeMagnitude( + byte[] bytes, + int offset, + int length) + { + int end = offset + length; + + // strip leading zeros + int firstSignificant; + for (firstSignificant = offset; firstSignificant < end + && bytes[firstSignificant] == 0; firstSignificant++) + { + } + + if (firstSignificant >= end) + { + return ZeroMagnitude; + } + + int nInts = (end - firstSignificant + 3) / BytesPerInt; + int bCount = (end - firstSignificant) % BytesPerInt; + if (bCount == 0) + { + bCount = BytesPerInt; + } + + if (nInts < 1) + { + return ZeroMagnitude; + } + + int[] mag = new int[nInts]; + + int v = 0; + int magnitudeIndex = 0; + for (int i = firstSignificant; i < end; ++i) + { + v <<= 8; + v |= bytes[i] & 0xff; + bCount--; + if (bCount <= 0) + { + mag[magnitudeIndex] = v; + magnitudeIndex++; + bCount = BytesPerInt; + v = 0; + } + } + + if (magnitudeIndex < mag.Length) + { + mag[magnitudeIndex] = v; + } + + return mag; + } + + public BigInteger( + int sign, + byte[] bytes) + : this(sign, bytes, 0, bytes.Length) + { + } + + public BigInteger( + int sign, + byte[] bytes, + int offset, + int length) + { + if (sign < -1 || sign > 1) + throw new FormatException("Invalid sign value"); + + if (sign == 0) + { + //this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else + { + // copy bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length < 1 ? 0 : sign; + } + } + + public BigInteger( + int sizeInBits, + Random random) + { + if (sizeInBits < 0) + throw new ArgumentException("sizeInBits must be non-negative"); + + this.nBits = -1; + this.nBitLength = -1; + + if (sizeInBits == 0) + { +// this.sign = 0; + this.magnitude = ZeroMagnitude; + return; + } + + int nBytes = GetByteLength(sizeInBits); + byte[] b = new byte[nBytes]; + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits]; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.sign = this.magnitude.Length < 1 ? 0 : 1; + } + + private static readonly byte[] rndMask = { 255, 127, 63, 31, 15, 7, 3, 1 }; + + public BigInteger( + int bitLength, + int certainty, + Random random) + { + if (bitLength < 2) + throw new ArithmeticException("bitLength < 2"); + + this.sign = 1; + this.nBitLength = bitLength; + + if (bitLength == 2) + { + this.magnitude = random.Next(2) == 0 + ? Two.magnitude + : Three.magnitude; + return; + } + + int nBytes = GetByteLength(bitLength); + byte[] b = new byte[nBytes]; + + int xBits = BitsPerByte * nBytes - bitLength; + byte mask = rndMask[xBits]; + + for (;;) + { + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= mask; + + // ensure the leading bit is 1 (to meet the strength requirement) + b[0] |= (byte)(1 << (7 - xBits)); + + // ensure the trailing bit is 1 (i.e. must be odd) + b[nBytes - 1] |= 1; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.nBits = -1; + this.mQuote = -1L; + + if (certainty < 1) + break; + + if (CheckProbablePrime(certainty, random)) + break; + + if (bitLength > 32) + { + for (int rep = 0; rep < 10000; ++rep) + { + int n = 33 + random.Next(bitLength - 2); + this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31)); + this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1); + this.mQuote = -1L; + + if (CheckProbablePrime(certainty, random)) + return; + } + } + } + } + + public BigInteger Abs() + { + return sign >= 0 ? this : Negate(); + } + + /** + * return a = a + b - b preserved. + */ + private static int[] AddMagnitudes( + int[] a, + int[] b) + { + int tI = a.Length - 1; + int vI = b.Length - 1; + long m = 0; + + while (vI >= 0) + { + m += ((long)(uint)a[tI] + (long)(uint)b[vI--]); + a[tI--] = (int)m; + m = (long)((ulong)m >> 32); + } + + if (m != 0) + { + while (tI >= 0 && ++a[tI--] == 0) + { + } + } + + return a; + } + + public BigInteger Add( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (this.sign != value.sign) + { + if (value.sign == 0) + return this; + + if (value.sign < 0) + return Subtract(value.Negate()); + + return value.Subtract(Negate()); + } + + return AddToMagnitude(value.magnitude); + } + + private BigInteger AddToMagnitude( + int[] magToAdd) + { + int[] big, small; + if (this.magnitude.Length < magToAdd.Length) + { + big = magToAdd; + small = this.magnitude; + } + else + { + big = this.magnitude; + small = magToAdd; + } + + // Conservatively avoid over-allocation when no overflow possible + uint limit = uint.MaxValue; + if (big.Length == small.Length) + limit -= (uint) small[0]; + + bool possibleOverflow = (uint) big[0] >= limit; + + int[] bigCopy; + if (possibleOverflow) + { + bigCopy = new int[big.Length + 1]; + big.CopyTo(bigCopy, 1); + } + else + { + bigCopy = (int[]) big.Clone(); + } + + bigCopy = AddMagnitudes(bigCopy, small); + + return new BigInteger(this.sign, bigCopy, possibleOverflow); + } + + public BigInteger And( + BigInteger value) + { + if (this.sign == 0 || value.sign == 0) + { + return Zero; + } + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 && value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord & bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger AndNot( + BigInteger val) + { + return And(val.Not()); + } + + public int BitCount + { + get + { + if (nBits == -1) + { + if (sign < 0) + { + // TODO Optimise this case + nBits = Not().BitCount; + } + else + { + int sum = 0; + for (int i = 0; i < magnitude.Length; i++) + { + sum += bitCounts[(byte) magnitude[i]]; + sum += bitCounts[(byte)(magnitude[i] >> 8)]; + sum += bitCounts[(byte)(magnitude[i] >> 16)]; + sum += bitCounts[(byte)(magnitude[i] >> 24)]; + } + nBits = sum; + } + } + + return nBits; + } + } + + private readonly static byte[] bitCounts = + { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, + 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, + 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, + 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, + 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, + 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, + 6, 6, 7, 6, 7, 7, 8 + }; + + private int calcBitLength( + int indx, + int[] mag) + { + for (;;) + { + if (indx >= mag.Length) + return 0; + + if (mag[indx] != 0) + break; + + ++indx; + } + + // bit length for everything after the first int + int bitLength = 32 * ((mag.Length - indx) - 1); + + // and determine bitlength of first int + int firstMag = mag[indx]; + bitLength += BitLen(firstMag); + + // Check for negative powers of two + if (sign < 0 && ((firstMag & -firstMag) == firstMag)) + { + do + { + if (++indx >= mag.Length) + { + --bitLength; + break; + } + } + while (mag[indx] == 0); + } + + return bitLength; + } + + public int BitLength + { + get + { + if (nBitLength == -1) + { + nBitLength = sign == 0 + ? 0 + : calcBitLength(0, magnitude); + } + + return nBitLength; + } + } + + // + // BitLen(value) is the number of bits in value. + // + private static int BitLen( + int w) + { + // Binary search - decision tree (5 tests, rarely 6) + return (w < 1 << 15 ? (w < 1 << 7 + ? (w < 1 << 3 ? (w < 1 << 1 + ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) + : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 + ? (w < 1 << 4 ? 4 : 5) + : (w < 1 << 6 ? 6 : 7))) + : (w < 1 << 11 + ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) + : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 + ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) + : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 + ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) + : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); + } + +// private readonly static byte[] bitLengths = +// { +// 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, +// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, +// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +// 8, 8, 8, 8, 8, 8, 8, 8 +// }; + + private bool QuickPow2Check() + { + return sign > 0 && nBits == 1; + } + + public int CompareTo( + object obj) + { + return CompareTo((BigInteger)obj); + } + + /** + * unsigned comparison on two arrays - note the arrays may + * start with leading zeros. + */ + private static int CompareTo( + int xIndx, + int[] x, + int yIndx, + int[] y) + { + while (xIndx != x.Length && x[xIndx] == 0) + { + xIndx++; + } + + while (yIndx != y.Length && y[yIndx] == 0) + { + yIndx++; + } + + return CompareNoLeadingZeroes(xIndx, x, yIndx, y); + } + + private static int CompareNoLeadingZeroes( + int xIndx, + int[] x, + int yIndx, + int[] y) + { + int diff = (x.Length - y.Length) - (xIndx - yIndx); + + if (diff != 0) + { + return diff < 0 ? -1 : 1; + } + + // lengths of magnitudes the same, test the magnitude values + + while (xIndx < x.Length) + { + uint v1 = (uint)x[xIndx++]; + uint v2 = (uint)y[yIndx++]; + + if (v1 != v2) + return v1 < v2 ? -1 : 1; + } + + return 0; + } + + public int CompareTo( + BigInteger value) + { + return sign < value.sign ? -1 + : sign > value.sign ? 1 + : sign == 0 ? 0 + : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude); + } + + /** + * return z = x / y - done in place (z value preserved, x contains the + * remainder) + */ + private int[] Divide( + int[] x, + int[] y) + { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) + { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) + { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + int[] count; + + if (xyCmp > 0) + { + int yBitLength = calcBitLength(yStart, y); + int xBitLength = calcBitLength(xStart, x); + int shift = xBitLength - yBitLength; + + int[] iCount; + int iCountStart = 0; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) + { +// iCount = ShiftLeft(One.magnitude, shift); + iCount = new int[(shift >> 5) + 1]; + iCount[0] = 1 << (shift % 32); + + c = ShiftLeft(y, shift); + cBitLength += shift; + } + else + { + iCount = new int[] { 1 }; + + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + count = new int[iCount.Length]; + + for (;;) + { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) + { + Subtract(xStart, x, cStart, c); + AddMagnitudes(count, iCount); + + while (x[xStart] == 0) + { + if (++xStart == x.Length) + return count; + } + + //xBitLength = calcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) + { + if (xBitLength < yBitLength) + return count; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) + { + uint firstC = (uint) c[cStart] >> 1; + uint firstX = (uint) x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) + { + c = ShiftRightOneInPlace(cStart, c); + --cBitLength; + iCount = ShiftRightOneInPlace(iCountStart, iCount); + } + else + { + c = ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + iCount = ShiftRightInPlace(iCountStart, iCount, shift); + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) + { + ++cStart; + } + + while (iCount[iCountStart] == 0) + { + ++iCountStart; + } + } + } + else + { + count = new int[1]; + } + + if (xyCmp == 0) + { + AddMagnitudes(count, One.magnitude); + Array.Clear(x, xStart, x.Length - xStart); + } + + return count; + } + + public BigInteger Divide( + BigInteger val) + { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1); + return val.sign == this.sign ? result : result.Negate(); + } + + int[] mag = (int[]) this.magnitude.Clone(); + + return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true); + } + + public BigInteger[] DivideAndRemainder( + BigInteger val) + { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + BigInteger[] biggies = new BigInteger[2]; + + if (sign == 0) + { + biggies[0] = Zero; + biggies[1] = Zero; + } + else if (val.QuickPow2Check()) // val is power of two + { + int e = val.Abs().BitLength - 1; + BigInteger quotient = this.Abs().ShiftRight(e); + int[] remainder = this.LastNBits(e); + + biggies[0] = val.sign == this.sign ? quotient : quotient.Negate(); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + else + { + int[] remainder = (int[]) this.magnitude.Clone(); + int[] quotient = Divide(remainder, val.magnitude); + + biggies[0] = new BigInteger(this.sign * val.sign, quotient, true); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + + return biggies; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + BigInteger biggie = obj as BigInteger; + if (biggie == null) + return false; + + if (biggie.sign != sign || biggie.magnitude.Length != magnitude.Length) + return false; + + for (int i = 0; i < magnitude.Length; i++) + { + if (biggie.magnitude[i] != magnitude[i]) + { + return false; + } + } + + return true; + } + + public BigInteger Gcd( + BigInteger value) + { + if (value.sign == 0) + return Abs(); + + if (sign == 0) + return value.Abs(); + + BigInteger r; + BigInteger u = this; + BigInteger v = value; + + while (v.sign != 0) + { + r = u.Mod(v); + u = v; + v = r; + } + + return u; + } + + public override int GetHashCode() + { + int hc = magnitude.Length; + if (magnitude.Length > 0) + { + hc ^= magnitude[0]; + + if (magnitude.Length > 1) + { + hc ^= magnitude[magnitude.Length - 1]; + } + } + + return sign < 0 ? ~hc : hc; + } + + // TODO Make public? + private BigInteger Inc() + { + if (this.sign == 0) + return One; + + if (this.sign < 0) + return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true); + + return AddToMagnitude(One.magnitude); + } + + public int IntValue + { + get + { + return sign == 0 ? 0 + : sign > 0 ? magnitude[magnitude.Length - 1] + : -magnitude[magnitude.Length - 1]; + } + } + + /** + * return whether or not a BigInteger is probably prime with a + * probability of 1 - (1/2)**certainty. + *

      From Knuth Vol 2, pg 395.

      + */ + public bool IsProbablePrime( + int certainty) + { + if (certainty <= 0) + return true; + + BigInteger n = Abs(); + + if (!n.TestBit(0)) + return n.Equals(Two); + + if (n.Equals(One)) + return false; + + return n.CheckProbablePrime(certainty, RandomSource); + } + + private bool CheckProbablePrime( + int certainty, + Random random) + { + Debug.Assert(certainty > 0); + Debug.Assert(CompareTo(Two) > 0); + Debug.Assert(TestBit(0)); + + + // Try to reduce the penalty for really small numbers + int numLists = System.Math.Min(BitLength - 1, primeLists.Length); + + for (int i = 0; i < numLists; ++i) + { + int test = Remainder(primeProducts[i]); + + int[] primeList = primeLists[i]; + for (int j = 0; j < primeList.Length; ++j) + { + int prime = primeList[j]; + int qRem = test % prime; + if (qRem == 0) + { + // We may find small numbers in the list + return BitLength < 16 && IntValue == prime; + } + } + } + + + // TODO Special case for < 10^16 (RabinMiller fixed list) +// if (BitLength < 30) +// { +// RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient +// } + + + // TODO Is it worth trying to create a hybrid of these two? + return RabinMillerTest(certainty, random); +// return SolovayStrassenTest(certainty, random); + +// bool rbTest = RabinMillerTest(certainty, random); +// bool ssTest = SolovayStrassenTest(certainty, random); +// +// Debug.Assert(rbTest == ssTest); +// +// return rbTest; + } + + internal bool RabinMillerTest( + int certainty, + Random random) + { + Debug.Assert(certainty > 0); + Debug.Assert(BitLength > 2); + Debug.Assert(TestBit(0)); + + // let n = 1 + d . 2^s + BigInteger n = this; + BigInteger nMinusOne = n.Subtract(One); + int s = nMinusOne.GetLowestSetBit(); + BigInteger r = nMinusOne.ShiftRight(s); + + Debug.Assert(s >= 1); + + do + { + // TODO Make a method for random BigIntegers in range 0 < x < n) + // - Method can be optimized by only replacing examined bits at each trial + BigInteger a; + do + { + a = new BigInteger(n.BitLength, random); + } + while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0); + + BigInteger y = a.ModPow(r, n); + + if (!y.Equals(One)) + { + int j = 0; + while (!y.Equals(nMinusOne)) + { + if (++j == s) + return false; + + y = y.ModPow(Two, n); + + if (y.Equals(One)) + return false; + } + } + + certainty -= 2; // composites pass for only 1/4 possible 'a' + } + while (certainty > 0); + + return true; + } + +// private bool SolovayStrassenTest( +// int certainty, +// Random random) +// { +// Debug.Assert(certainty > 0); +// Debug.Assert(CompareTo(Two) > 0); +// Debug.Assert(TestBit(0)); +// +// BigInteger n = this; +// BigInteger nMinusOne = n.Subtract(One); +// BigInteger e = nMinusOne.ShiftRight(1); +// +// do +// { +// BigInteger a; +// do +// { +// a = new BigInteger(nBitLength, random); +// } +// // NB: Spec says 0 < x < n, but 1 is trivial +// while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0); +// +// +// // TODO Check this is redundant given the way Jacobi() works? +//// if (!a.Gcd(n).Equals(One)) +//// return false; +// +// int x = Jacobi(a, n); +// +// if (x == 0) +// return false; +// +// BigInteger check = a.ModPow(e, n); +// +// if (x == 1 && !check.Equals(One)) +// return false; +// +// if (x == -1 && !check.Equals(nMinusOne)) +// return false; +// +// --certainty; +// } +// while (certainty > 0); +// +// return true; +// } +// +// private static int Jacobi( +// BigInteger a, +// BigInteger b) +// { +// Debug.Assert(a.sign >= 0); +// Debug.Assert(b.sign > 0); +// Debug.Assert(b.TestBit(0)); +// Debug.Assert(a.CompareTo(b) < 0); +// +// int totalS = 1; +// for (;;) +// { +// if (a.sign == 0) +// return 0; +// +// if (a.Equals(One)) +// break; +// +// int e = a.GetLowestSetBit(); +// +// int bLsw = b.magnitude[b.magnitude.Length - 1]; +// if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5)) +// totalS = -totalS; +// +// // TODO Confirm this is faster than later a1.Equals(One) test +// if (a.BitLength == e + 1) +// break; +// BigInteger a1 = a.ShiftRight(e); +//// if (a1.Equals(One)) +//// break; +// +// int a1Lsw = a1.magnitude[a1.magnitude.Length - 1]; +// if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3) +// totalS = -totalS; +// +//// a = b.Mod(a1); +// a = b.Remainder(a1); +// b = a1; +// } +// return totalS; +// } + + public long LongValue + { + get + { + if (sign == 0) + return 0; + + long v; + if (magnitude.Length > 1) + { + v = ((long)magnitude[magnitude.Length - 2] << 32) + | (magnitude[magnitude.Length - 1] & IMASK); + } + else + { + v = (magnitude[magnitude.Length - 1] & IMASK); + } + + return sign < 0 ? -v : v; + } + } + + public BigInteger Max( + BigInteger value) + { + return CompareTo(value) > 0 ? this : value; + } + + public BigInteger Min( + BigInteger value) + { + return CompareTo(value) < 0 ? this : value; + } + + public BigInteger Mod( + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + BigInteger biggie = Remainder(m); + + return (biggie.sign >= 0 ? biggie : biggie.Add(m)); + } + + public BigInteger ModInverse( + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + // TODO Too slow at the moment +// // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel +// if (m.TestBit(0)) +// { +// //The Almost Inverse Algorithm +// int k = 0; +// BigInteger B = One, C = Zero, F = this, G = m, tmp; +// +// for (;;) +// { +// // While F is even, do F=F/u, C=C*u, k=k+1. +// int zeroes = F.GetLowestSetBit(); +// if (zeroes > 0) +// { +// F = F.ShiftRight(zeroes); +// C = C.ShiftLeft(zeroes); +// k += zeroes; +// } +// +// // If F = 1, then return B,k. +// if (F.Equals(One)) +// { +// BigInteger half = m.Add(One).ShiftRight(1); +// BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m); +// return B.Multiply(halfK).Mod(m); +// } +// +// if (F.CompareTo(G) < 0) +// { +// tmp = G; G = F; F = tmp; +// tmp = B; B = C; C = tmp; +// } +// +// F = F.Add(G); +// B = B.Add(C); +// } +// } + + BigInteger x = new BigInteger(); + BigInteger gcd = ExtEuclid(this.Mod(m), m, x, null); + + if (!gcd.Equals(One)) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x.sign < 0) + { + x.sign = 1; + //x = m.Subtract(x); + x.magnitude = doSubBigLil(m.magnitude, x.magnitude); + } + + return x; + } + + /** + * Calculate the numbers u1, u2, and u3 such that: + * + * u1 * a + u2 * b = u3 + * + * where u3 is the greatest common divider of a and b. + * a and b using the extended Euclid algorithm (refer p. 323 + * of The Art of Computer Programming vol 2, 2nd ed). + * This also seems to have the side effect of calculating + * some form of multiplicative inverse. + * + * @param a First number to calculate gcd for + * @param b Second number to calculate gcd for + * @param u1Out the return object for the u1 value + * @param u2Out the return object for the u2 value + * @return The greatest common divisor of a and b + */ + private static BigInteger ExtEuclid( + BigInteger a, + BigInteger b, + BigInteger u1Out, + BigInteger u2Out) + { + BigInteger u1 = One; + BigInteger u3 = a; + BigInteger v1 = Zero; + BigInteger v3 = b; + + while (v3.sign > 0) + { + BigInteger[] q = u3.DivideAndRemainder(v3); + + BigInteger tmp = v1.Multiply(q[0]); + BigInteger tn = u1.Subtract(tmp); + u1 = v1; + v1 = tn; + + u3 = v3; + v3 = q[1]; + } + + if (u1Out != null) + { + u1Out.sign = u1.sign; + u1Out.magnitude = u1.magnitude; + } + + if (u2Out != null) + { + BigInteger tmp = u1.Multiply(a); + tmp = u3.Subtract(tmp); + BigInteger res = tmp.Divide(b); + u2Out.sign = res.sign; + u2Out.magnitude = res.magnitude; + } + + return u3; + } + + private static void ZeroOut( + int[] x) + { + Array.Clear(x, 0, x.Length); + } + + public BigInteger ModPow( + BigInteger exponent, + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + if (m.Equals(One)) + return Zero; + + if (exponent.sign == 0) + return One; + + if (sign == 0) + return Zero; + + int[] zVal = null; + int[] yAccum = null; + int[] yVal; + + // Montgomery exponentiation is only possible if the modulus is odd, + // but AFAIK, this is always the case for crypto algo's + bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1); + long mQ = 0; + if (useMonty) + { + mQ = m.GetMQuote(); + + // tmp = this * R mod m + BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m); + zVal = tmp.magnitude; + + useMonty = (zVal.Length <= m.magnitude.Length); + + if (useMonty) + { + yAccum = new int[m.magnitude.Length + 1]; + if (zVal.Length < m.magnitude.Length) + { + int[] longZ = new int[m.magnitude.Length]; + zVal.CopyTo(longZ, longZ.Length - zVal.Length); + zVal = longZ; + } + } + } + + if (!useMonty) + { + if (magnitude.Length <= m.magnitude.Length) + { + //zAccum = new int[m.magnitude.Length * 2]; + zVal = new int[m.magnitude.Length]; + magnitude.CopyTo(zVal, zVal.Length - magnitude.Length); + } + else + { + // + // in normal practice we'll never see this... + // + BigInteger tmp = Remainder(m); + + //zAccum = new int[m.magnitude.Length * 2]; + zVal = new int[m.magnitude.Length]; + tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length); + } + + yAccum = new int[m.magnitude.Length * 2]; + } + + yVal = new int[m.magnitude.Length]; + + // + // from LSW to MSW + // + for (int i = 0; i < exponent.magnitude.Length; i++) + { + int v = exponent.magnitude[i]; + int bits = 0; + + if (i == 0) + { + while (v > 0) + { + v <<= 1; + bits++; + } + + // + // first time in initialise y + // + zVal.CopyTo(yVal, 0); + + v <<= 1; + bits++; + } + + while (v != 0) + { + if (useMonty) + { + // Montgomery square algo doesn't exist, and a normal + // square followed by a Montgomery reduction proved to + // be almost as heavy as a Montgomery mulitply. + MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); + } + else + { + Square(yAccum, yVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); + ZeroOut(yAccum); + } + bits++; + + if (v < 0) + { + if (useMonty) + { + MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); + } + else + { + Multiply(yAccum, yVal, zVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, + yVal.Length); + ZeroOut(yAccum); + } + } + + v <<= 1; + } + + while (bits < 32) + { + if (useMonty) + { + MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); + } + else + { + Square(yAccum, yVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); + ZeroOut(yAccum); + } + bits++; + } + } + + if (useMonty) + { + // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m + ZeroOut(zVal); + zVal[zVal.Length - 1] = 1; + MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); + } + + BigInteger result = new BigInteger(1, yVal, true); + + return exponent.sign > 0 + ? result + : result.ModInverse(m); + } + + /** + * return w with w = x * x - w is assumed to have enough space. + */ + private static int[] Square( + int[] w, + int[] x) + { + // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit +// if (w.Length != 2 * x.Length) +// throw new ArgumentException("no I don't think so..."); + + ulong u1, u2, c; + + int wBase = w.Length - 1; + + for (int i = x.Length - 1; i != 0; i--) + { + ulong v = (ulong)(uint) x[i]; + + u1 = v * v; + u2 = u1 >> 32; + u1 = (uint) u1; + + u1 += (ulong)(uint) w[wBase]; + + w[wBase] = (int)(uint) u1; + c = u2 + (u1 >> 32); + + for (int j = i - 1; j >= 0; j--) + { + --wBase; + u1 = v * (ulong)(uint) x[j]; + u2 = u1 >> 31; // multiply by 2! + u1 = (uint)(u1 << 1); // multiply by 2! + u1 += c + (ulong)(uint) w[wBase]; + + w[wBase] = (int)(uint) u1; + c = u2 + (u1 >> 32); + } + + c += (ulong)(uint) w[--wBase]; + w[wBase] = (int)(uint) c; + + if (--wBase >= 0) + { + w[wBase] = (int)(uint)(c >> 32); + } + else + { + Debug.Assert((uint)(c >> 32) == 0); + } + wBase += i; + } + + u1 = (ulong)(uint) x[0]; + u1 = u1 * u1; + u2 = u1 >> 32; + u1 = u1 & IMASK; + + u1 += (ulong)(uint) w[wBase]; + + w[wBase] = (int)(uint) u1; + if (--wBase >= 0) + { + w[wBase] = (int)(uint)(u2 + (u1 >> 32) + (ulong)(uint) w[wBase]); + } + else + { + Debug.Assert((uint)(u2 + (u1 >> 32)) == 0); + } + + return w; + } + + /** + * return x with x = y * z - x is assumed to have enough space. + */ + private static int[] Multiply( + int[] x, + int[] y, + int[] z) + { + int i = z.Length; + + if (i < 1) + return x; + + int xBase = x.Length - y.Length; + + for (;;) + { + long a = z[--i] & IMASK; + long val = 0; + + for (int j = y.Length - 1; j >= 0; j--) + { + val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK); + + x[xBase + j] = (int)val; + + val = (long)((ulong)val >> 32); + } + + --xBase; + + if (i < 1) + { + if (xBase >= 0) + { + x[xBase] = (int)val; + } + else + { + Debug.Assert(val == 0); + } + break; + } + + x[xBase] = (int)val; + } + + return x; + } + + private static long FastExtEuclid( + long a, + long b, + long[] uOut) + { + long u1 = 1; + long u3 = a; + long v1 = 0; + long v3 = b; + + while (v3 > 0) + { + long q, tn; + + q = u3 / v3; + + tn = u1 - (v1 * q); + u1 = v1; + v1 = tn; + + tn = u3 - (v3 * q); + u3 = v3; + v3 = tn; + } + + uOut[0] = u1; + uOut[1] = (u3 - (u1 * a)) / b; + + return u3; + } + + private static long FastModInverse( + long v, + long m) + { + if (m < 1) + throw new ArithmeticException("Modulus must be positive"); + + long[] x = new long[2]; + long gcd = FastExtEuclid(v, m, x); + + if (gcd != 1) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x[0] < 0) + { + x[0] += m; + } + + return x[0]; + } + +// private static BigInteger MQuoteB = One.ShiftLeft(32); +// private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One); + + /** + * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size) + */ + private long GetMQuote() + { + Debug.Assert(this.sign > 0); + + if (mQuote != -1) + { + return mQuote; // already calculated + } + + if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0) + { + return -1; // not for even numbers + } + + long v = (((~this.magnitude[this.magnitude.Length - 1]) | 1) & 0xffffffffL); + mQuote = FastModInverse(v, 0x100000000L); + + return mQuote; + } + + /** + * Montgomery multiplication: a = x * y * R^(-1) mod m + *
      + * Based algorithm 14.36 of Handbook of Applied Cryptography. + *
      + *
    • m, x, y should have length n
    • + *
    • a should have length (n + 1)
    • + *
    • b = 2^32, R = b^n
    • + *
      + * The result is put in x + *
      + * NOTE: the indices of x, y, m, a different in HAC and in Java + */ + private static void MultiplyMonty( + int[] a, + int[] x, + int[] y, + int[] m, + long mQuote) + // mQuote = -m^(-1) mod b + { + if (m.Length == 1) + { + x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], (ulong)mQuote); + return; + } + + int n = m.Length; + int nMinus1 = n - 1; + long y_0 = y[nMinus1] & IMASK; + + // 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} ) + Array.Clear(a, 0, n + 1); + + // 2. for i from 0 to (n - 1) do the following: + for (int i = n; i > 0; i--) + { + long x_i = x[i - 1] & IMASK; + + // 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b + long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK; + + // 2.2 a = (a + x_i * y + u * m) / b + long prod1 = x_i * y_0; + long prod2 = u * (m[nMinus1] & IMASK); + long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK); + long carry = (long)((ulong)prod1 >> 32) + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); + for (int j = nMinus1; j > 0; j--) + { + prod1 = x_i * (y[j - 1] & IMASK); + prod2 = u * (m[j - 1] & IMASK); + tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK); + carry = (long)((ulong)carry >> 32) + (long)((ulong)prod1 >> 32) + + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); + a[j + 1] = (int)tmp; // division by b + } + carry += (a[0] & IMASK); + a[1] = (int)carry; + a[0] = (int)((ulong)carry >> 32); // OJO!!!!! + } + + // 3. if x >= m the x = x - m + if (CompareTo(0, a, 0, m) >= 0) + { + Subtract(0, a, 0, m); + } + + // put the result in x + Array.Copy(a, 1, x, 0, n); + } + + private static uint MultiplyMontyNIsOne( + uint x, + uint y, + uint m, + ulong mQuote) + { + ulong um = m; + ulong prod1 = (ulong)x * (ulong)y; + ulong u = (prod1 * mQuote) & UIMASK; + ulong prod2 = u * um; + ulong tmp = (prod1 & UIMASK) + (prod2 & UIMASK); + ulong carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32); + + if (carry > um) + { + carry -= um; + } + + return (uint)(carry & UIMASK); + } + + public BigInteger Multiply( + BigInteger val) + { + if (sign == 0 || val.sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1); + return val.sign > 0 ? result : result.Negate(); + } + + if (this.QuickPow2Check()) // this is power of two + { + BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1); + return this.sign > 0 ? result : result.Negate(); + } + + int maxBitLength = this.BitLength + val.BitLength; + int resLength = (maxBitLength + BitsPerInt - 1) / BitsPerInt; + + int[] res = new int[resLength]; + + if (val == this) + { + Square(res, this.magnitude); + } + else + { + Multiply(res, this.magnitude, val.magnitude); + } + + return new BigInteger(sign * val.sign, res, true); + } + + public BigInteger Negate() + { + if (sign == 0) + return this; + + return new BigInteger(-sign, magnitude, false); + } + + public BigInteger NextProbablePrime() + { + if (sign < 0) + throw new ArithmeticException("Cannot be called on value < 0"); + + if (CompareTo(Two) < 0) + return Two; + + BigInteger n = Inc().SetBit(0); + + while (!n.CheckProbablePrime(100, RandomSource)) + { + n = n.Add(Two); + } + + return n; + } + + public BigInteger Not() + { + return Inc().Negate(); + } + + public BigInteger Pow(int exp) + { + if (exp < 0) + { + throw new ArithmeticException("Negative exponent"); + } + + if (exp == 0) + { + return One; + } + + if (sign == 0 || Equals(One)) + { + return this; + } + + BigInteger y = One; + BigInteger z = this; + + for (;;) + { + if ((exp & 0x1) == 1) + { + y = y.Multiply(z); + } + exp >>= 1; + if (exp == 0) break; + z = z.Multiply(z); + } + + return y; + } + + public static BigInteger ProbablePrime( + int bitLength, + Random random) + { + return new BigInteger(bitLength, 100, random); + } + + private int Remainder( + int m) + { + Debug.Assert(m > 0); + + long acc = 0; + for (int pos = 0; pos < magnitude.Length; ++pos) + { + long posVal = (uint) magnitude[pos]; + acc = (acc << 32 | posVal) % m; + } + + return (int) acc; + } + + /** + * return x = x % y - done in place (y value preserved) + */ + private int[] Remainder( + int[] x, + int[] y) + { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) + { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) + { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp > 0) + { + int yBitLength = calcBitLength(yStart, y); + int xBitLength = calcBitLength(xStart, x); + int shift = xBitLength - yBitLength; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) + { + c = ShiftLeft(y, shift); + cBitLength += shift; + Debug.Assert(c[0] != 0); + } + else + { + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + for (;;) + { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) + { + Subtract(xStart, x, cStart, c); + + while (x[xStart] == 0) + { + if (++xStart == x.Length) + return x; + } + + //xBitLength = calcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) + { + if (xBitLength < yBitLength) + return x; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) + { + uint firstC = (uint) c[cStart] >> 1; + uint firstX = (uint) x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) + { + c = ShiftRightOneInPlace(cStart, c); + --cBitLength; + } + else + { + c = ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) + { + ++cStart; + } + } + } + + if (xyCmp == 0) + { + Array.Clear(x, xStart, x.Length - xStart); + } + + return x; + } + + public BigInteger Remainder( + BigInteger n) + { + if (n.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (this.sign == 0) + return Zero; + + // For small values, use fast remainder method + if (n.magnitude.Length == 1) + { + int val = n.magnitude[0]; + + if (val > 0) + { + if (val == 1) + return Zero; + + // TODO Make this func work on uint, and handle val == 1? + int rem = Remainder(val); + + return rem == 0 + ? Zero + : new BigInteger(sign, new int[]{ rem }, false); + } + } + + if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0) + return this; + + int[] result; + if (n.QuickPow2Check()) // n is power of two + { + // TODO Move before small values branch above? + result = LastNBits(n.Abs().BitLength - 1); + } + else + { + result = (int[]) this.magnitude.Clone(); + result = Remainder(result, n.magnitude); + } + + return new BigInteger(sign, result, true); + } + + private int[] LastNBits( + int n) + { + if (n < 1) + return ZeroMagnitude; + + int numWords = (n + BitsPerInt - 1) / BitsPerInt; + numWords = System.Math.Min(numWords, this.magnitude.Length); + int[] result = new int[numWords]; + + Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords); + + int hiBits = n % 32; + if (hiBits != 0) + { + result[0] &= ~(-1 << hiBits); + } + + return result; + } + + /** + * do a left shift - this returns a new array. + */ + private static int[] ShiftLeft( + int[] mag, + int n) + { + int nInts = (int)((uint)n >> 5); + int nBits = n & 0x1f; + int magLen = mag.Length; + int[] newMag; + + if (nBits == 0) + { + newMag = new int[magLen + nInts]; + mag.CopyTo(newMag, 0); + } + else + { + int i = 0; + int nBits2 = 32 - nBits; + int highBits = (int)((uint)mag[0] >> nBits2); + + if (highBits != 0) + { + newMag = new int[magLen + nInts + 1]; + newMag[i++] = highBits; + } + else + { + newMag = new int[magLen + nInts]; + } + + int m = mag[0]; + for (int j = 0; j < magLen - 1; j++) + { + int next = mag[j + 1]; + + newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2); + m = next; + } + + newMag[i] = mag[magLen - 1] << nBits; + } + + return newMag; + } + + public BigInteger ShiftLeft( + int n) + { + if (sign == 0 || magnitude.Length == 0) + return Zero; + + if (n == 0) + return this; + + if (n < 0) + return ShiftRight(-n); + + BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true); + + if (this.nBits != -1) + { + result.nBits = sign > 0 + ? this.nBits + : this.nBits + n; + } + + if (this.nBitLength != -1) + { + result.nBitLength = this.nBitLength + n; + } + + return result; + } + + /** + * do a right shift - this does it in place. + */ + private static int[] ShiftRightInPlace( + int start, + int[] mag, + int n) + { + int nInts = (int)((uint)n >> 5) + start; + int nBits = n & 0x1f; + int magEnd = mag.Length - 1; + + if (nInts != start) + { + int delta = (nInts - start); + + for (int i = magEnd; i >= nInts; i--) + { + mag[i] = mag[i - delta]; + } + for (int i = nInts - 1; i >= start; i--) + { + mag[i] = 0; + } + } + + if (nBits != 0) + { + int nBits2 = 32 - nBits; + int m = mag[magEnd]; + + for (int i = magEnd; i > nInts; --i) + { + int next = mag[i - 1]; + + mag[i] = (int)((uint)m >> nBits) | (next << nBits2); + m = next; + } + + mag[nInts] = (int)((uint)mag[nInts] >> nBits); + } + + return mag; + } + + /** + * do a right shift by one - this does it in place. + */ + private static int[] ShiftRightOneInPlace( + int start, + int[] mag) + { + int i = mag.Length; + int m = mag[i - 1]; + + while (--i > start) + { + int next = mag[i - 1]; + mag[i] = ((int)((uint)m >> 1)) | (next << 31); + m = next; + } + + mag[start] = (int)((uint)mag[start] >> 1); + + return mag; + } + + public BigInteger ShiftRight( + int n) + { + if (n == 0) + return this; + + if (n < 0) + return ShiftLeft(-n); + + if (n >= BitLength) + return (this.sign < 0 ? One.Negate() : Zero); + +// int[] res = (int[]) this.magnitude.Clone(); +// +// res = ShiftRightInPlace(0, res, n); +// +// return new BigInteger(this.sign, res, true); + + int resultLength = (BitLength - n + 31) >> 5; + int[] res = new int[resultLength]; + + int numInts = n >> 5; + int numBits = n & 31; + + if (numBits == 0) + { + Array.Copy(this.magnitude, 0, res, 0, res.Length); + } + else + { + int numBits2 = 32 - numBits; + + int magPos = this.magnitude.Length - 1 - numInts; + for (int i = resultLength - 1; i >= 0; --i) + { + res[i] = (int)((uint) this.magnitude[magPos--] >> numBits); + + if (magPos >= 0) + { + res[i] |= this.magnitude[magPos] << numBits2; + } + } + } + + Debug.Assert(res[0] != 0); + + return new BigInteger(this.sign, res, false); + } + + public int SignValue + { + get { return sign; } + } + + /** + * returns x = x - y - we assume x is >= y + */ + private static int[] Subtract( + int xStart, + int[] x, + int yStart, + int[] y) + { + Debug.Assert(yStart < y.Length); + Debug.Assert(x.Length - xStart >= y.Length - yStart); + + int iT = x.Length; + int iV = y.Length; + long m; + int borrow = 0; + + do + { + m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow; + x[iT] = (int) m; + +// borrow = (m < 0) ? -1 : 0; + borrow = (int)(m >> 63); + } + while (iV > yStart); + + if (borrow != 0) + { + while (--x[--iT] == -1) + { + } + } + + return x; + } + + public BigInteger Subtract( + BigInteger n) + { + if (n.sign == 0) + return this; + + if (this.sign == 0) + return n.Negate(); + + if (this.sign != n.sign) + return Add(n.Negate()); + + int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); + if (compare == 0) + return Zero; + + BigInteger bigun, lilun; + if (compare < 0) + { + bigun = n; + lilun = this; + } + else + { + bigun = this; + lilun = n; + } + + return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); + } + + private static int[] doSubBigLil( + int[] bigMag, + int[] lilMag) + { + int[] res = (int[]) bigMag.Clone(); + + return Subtract(0, res, 0, lilMag); + } + + public byte[] ToByteArray() + { + return ToByteArray(false); + } + + public byte[] ToByteArrayUnsigned() + { + return ToByteArray(true); + } + + private byte[] ToByteArray( + bool unsigned) + { + if (sign == 0) + return unsigned ? ZeroEncoding : new byte[1]; + + int nBits = (unsigned && sign > 0) + ? BitLength + : BitLength + 1; + + int nBytes = GetByteLength(nBits); + byte[] bytes = new byte[nBytes]; + + int magIndex = magnitude.Length; + int bytesIndex = bytes.Length; + + if (sign > 0) + { + while (magIndex > 1) + { + uint mag = (uint) magnitude[--magIndex]; + bytes[--bytesIndex] = (byte) mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint) magnitude[0]; + while (lastMag > byte.MaxValue) + { + bytes[--bytesIndex] = (byte) lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte) lastMag; + } + else // sign < 0 + { + bool carry = true; + + while (magIndex > 1) + { + uint mag = ~((uint) magnitude[--magIndex]); + + if (carry) + { + carry = (++mag == uint.MinValue); + } + + bytes[--bytesIndex] = (byte) mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint) magnitude[0]; + + if (carry) + { + // Never wraps because magnitude[0] != 0 + --lastMag; + } + + while (lastMag > byte.MaxValue) + { + bytes[--bytesIndex] = (byte) ~lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte) ~lastMag; + + if (bytesIndex > 0) + { + bytes[--bytesIndex] = byte.MaxValue; + } + } + + return bytes; + } + + public override string ToString() + { + return ToString(10); + } + + public string ToString( + int radix) + { + // TODO Make this method work for other radices (ideally 2 <= radix <= 16) + + switch (radix) + { + case 2: + case 10: + case 16: + break; + default: + throw new FormatException("Only bases 2, 10, 16 are allowed"); + } + + // NB: Can only happen to internally managed instances + if (magnitude == null) + return "null"; + + if (sign == 0) + return "0"; + + Debug.Assert(magnitude.Length > 0); + + StringBuilder sb = new StringBuilder(); + + if (radix == 16) + { + sb.Append(magnitude[0].ToString("x")); + + for (int i = 1; i < magnitude.Length; i++) + { + sb.Append(magnitude[i].ToString("x8")); + } + } + else if (radix == 2) + { + sb.Append('1'); + + for (int i = BitLength - 2; i >= 0; --i) + { + sb.Append(TestBit(i) ? '1' : '0'); + } + } + else + { + // This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works + Stack S = new Stack(); + BigInteger bs = ValueOf(radix); + + // The sign is handled separatly. + // Notice however that for this to work, radix 16 _MUST_ be a special case, + // unless we want to enter a recursion well. In their infinite wisdom, why did not + // the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter? + // (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.) +// BigInteger u = new BigInteger(Abs().ToString(16), 16); + BigInteger u = this.Abs(); + BigInteger b; + + while (u.sign != 0) + { + b = u.Mod(bs); + if (b.sign == 0) + { + S.Push("0"); + } + else + { + // see how to interact with different bases + S.Push(b.magnitude[0].ToString("d")); + } + u = u.Divide(bs); + } + + // Then pop the stack + while (S.Count != 0) + { + sb.Append((string) S.Pop()); + } + } + + string s = sb.ToString(); + + Debug.Assert(s.Length > 0); + + // Strip leading zeros. (We know this number is not all zeroes though) + if (s[0] == '0') + { + int nonZeroPos = 0; + while (s[++nonZeroPos] == '0') {} + + s = s.Substring(nonZeroPos); + } + + if (sign == -1) + { + s = "-" + s; + } + + return s; + } + + private static BigInteger createUValueOf( + ulong value) + { + int msw = (int)(value >> 32); + int lsw = (int)value; + + if (msw != 0) + return new BigInteger(1, new int[] { msw, lsw }, false); + + if (lsw != 0) + { + BigInteger n = new BigInteger(1, new int[] { lsw }, false); + // Check for a power of two + if ((lsw & -lsw) == lsw) + { + n.nBits = 1; + } + return n; + } + + return Zero; + } + + private static BigInteger createValueOf( + long value) + { + if (value < 0) + { + if (value == long.MinValue) + return createValueOf(~value).Not(); + + return createValueOf(-value).Negate(); + } + + return createUValueOf((ulong)value); + +// // store value into a byte array +// byte[] b = new byte[8]; +// for (int i = 0; i < 8; i++) +// { +// b[7 - i] = (byte)value; +// value >>= 8; +// } +// +// return new BigInteger(b); + } + + public static BigInteger ValueOf( + long value) + { + switch (value) + { + case 0: + return Zero; + case 1: + return One; + case 2: + return Two; + case 3: + return Three; + case 10: + return Ten; + } + + return createValueOf(value); + } + + public int GetLowestSetBit() + { + if (this.sign == 0) + return -1; + + int w = magnitude.Length; + + while (--w > 0) + { + if (magnitude[w] != 0) + break; + } + + int word = (int) magnitude[w]; + Debug.Assert(word != 0); + + int b = (word & 0x0000FFFF) == 0 + ? (word & 0x00FF0000) == 0 + ? 7 + : 15 + : (word & 0x000000FF) == 0 + ? 23 + : 31; + + while (b > 0) + { + if ((word << b) == int.MinValue) + break; + + b--; + } + + return ((magnitude.Length - w) * 32 - (b + 1)); + } + + public bool TestBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit position must not be negative"); + + if (sign < 0) + return !Not().TestBit(n); + + int wordNum = n / 32; + if (wordNum >= magnitude.Length) + return false; + + int word = magnitude[magnitude.Length - 1 - wordNum]; + return ((word >> (n % 32)) & 1) > 0; + } + + public BigInteger Or( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 || value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord | bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger Xor( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + // TODO Can just replace with sign != value.sign? + bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0); + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord ^ bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger SetBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (TestBit(n)) + return this; + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Or(One.ShiftLeft(n)); + } + + public BigInteger ClearBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (!TestBit(n)) + return this; + + // TODO Handle negative values + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return AndNot(One.ShiftLeft(n)); + } + + public BigInteger FlipBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Xor(One.ShiftLeft(n)); + } + + private BigInteger FlipExistingBit( + int n) + { + Debug.Assert(sign > 0); + Debug.Assert(n >= 0); + Debug.Assert(n < BitLength - 1); + + int[] mag = (int[]) this.magnitude.Clone(); + mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit + //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32)); + return new BigInteger(this.sign, mag, false); + } + } +} diff --git a/iTechSharp/srcbc/math/ec/ECAlgorithms.cs b/iTechSharp/srcbc/math/ec/ECAlgorithms.cs new file mode 100644 index 0000000..08108b9 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/ECAlgorithms.cs @@ -0,0 +1,94 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Math.EC +{ + public class ECAlgorithms + { + public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, + ECPoint Q, BigInteger b) + { + ECCurve c = P.Curve; + if (!c.Equals(Q.Curve)) + throw new ArgumentException("P and Q must be on same curve"); + + // TODO Put back in once WTNAF F2m point multiplication is enabled +// // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick +// if (c is F2mCurve) +// { +// F2mCurve f2mCurve = (F2mCurve) c; +// if (f2mCurve.IsKoblitz) +// { +// return P.Multiply(a).Add(Q.Multiply(b)); +// } +// } + + return ImplShamirsTrick(P, a, Q, b); + } + + /* + * "Shamir's Trick", originally due to E. G. Straus + * (Addition chains of vectors. American Mathematical Monthly, + * 71(7):806–808, Aug./Sept. 1964) + * + * Input: The points P, Q, scalar k = (km?, ... , k1, k0) + * and scalar l = (lm?, ... , l1, l0). + * Output: R = k * P + l * Q. + * 1: Z <- P + Q + * 2: R <- O + * 3: for i from m-1 down to 0 do + * 4: R <- R + R {point doubling} + * 5: if (ki = 1) and (li = 0) then R <- R + P end if + * 6: if (ki = 0) and (li = 1) then R <- R + Q end if + * 7: if (ki = 1) and (li = 1) then R <- R + Z end if + * 8: end for + * 9: return R + */ + public static ECPoint ShamirsTrick( + ECPoint P, + BigInteger k, + ECPoint Q, + BigInteger l) + { + if (!P.Curve.Equals(Q.Curve)) + throw new ArgumentException("P and Q must be on same curve"); + + return ImplShamirsTrick(P, k, Q, l); + } + + private static ECPoint ImplShamirsTrick(ECPoint P, BigInteger k, + ECPoint Q, BigInteger l) + { + int m = System.Math.Max(k.BitLength, l.BitLength); + ECPoint Z = P.Add(Q); + ECPoint R = P.Curve.Infinity; + + for (int i = m - 1; i >= 0; --i) + { + R = R.Twice(); + + if (k.TestBit(i)) + { + if (l.TestBit(i)) + { + R = R.Add(Z); + } + else + { + R = R.Add(P); + } + } + else + { + if (l.TestBit(i)) + { + R = R.Add(Q); + } + } + } + + return R; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/ECCurve.cs b/iTechSharp/srcbc/math/ec/ECCurve.cs new file mode 100644 index 0000000..4dd5e74 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/ECCurve.cs @@ -0,0 +1,661 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Math.EC.Abc; + +namespace Org.BouncyCastle.Math.EC +{ + /// Base class for an elliptic curve. + public abstract class ECCurve + { + internal ECFieldElement a, b; + + public abstract int FieldSize { get; } + public abstract ECFieldElement FromBigInteger(BigInteger x); + public abstract ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression); + public abstract ECPoint DecodePoint(byte[] encoded); + public abstract ECPoint Infinity { get; } + + public ECFieldElement A + { + get { return a; } + } + + public ECFieldElement B + { + get { return b; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECCurve other = obj as ECCurve; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECCurve other) + { + return a.Equals(other.a) && b.Equals(other.b); + } + + public override int GetHashCode() + { + return a.GetHashCode() ^ b.GetHashCode(); + } + } + + public abstract class ECCurveBase : ECCurve + { + protected internal ECCurveBase() + { + } + + protected internal abstract ECPoint DecompressPoint(int yTilde, BigInteger X1); + + /** + * Decode a point on this curve from its ASN.1 encoding. The different + * encodings are taken account of, including point compression for + * Fp (X9.62 s 4.2.1 pg 17). + * @return The decoded point. + */ + public override ECPoint DecodePoint( + byte[] encoded) + { + ECPoint p = null; + int expectedLength = (FieldSize + 7) / 8; + + switch (encoded[0]) + { + case 0x00: // infinity + { + if (encoded.Length != 1) + throw new ArgumentException("Incorrect length for infinity encoding", "encoded"); + + p = Infinity; + break; + } + + case 0x02: // compressed + case 0x03: // compressed + { + if (encoded.Length != (expectedLength + 1)) + throw new ArgumentException("Incorrect length for compressed encoding", "encoded"); + + int yTilde = encoded[0] & 1; + BigInteger X1 = new BigInteger(1, encoded, 1, encoded.Length - 1); + + p = DecompressPoint(yTilde, X1); + break; + } + + case 0x04: // uncompressed + case 0x06: // hybrid + case 0x07: // hybrid + { + if (encoded.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for uncompressed/hybrid encoding", "encoded"); + + BigInteger X1 = new BigInteger(1, encoded, 1, expectedLength); + BigInteger Y1 = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); + + p = CreatePoint(X1, Y1, false); + break; + } + + default: + throw new FormatException("Invalid point encoding " + encoded[0]); + } + + return p; + } + } + + /** + * Elliptic curve over Fp + */ + public class FpCurve : ECCurveBase + { + private readonly BigInteger q; + private readonly FpPoint infinity; + + public FpCurve(BigInteger q, BigInteger a, BigInteger b) + { + this.q = q; + this.a = FromBigInteger(a); + this.b = FromBigInteger(b); + this.infinity = new FpPoint(this, null, null); + } + + public BigInteger Q + { + get { return q; } + } + + public override ECPoint Infinity + { + get { return infinity; } + } + + public override int FieldSize + { + get { return q.BitLength; } + } + + public override ECFieldElement FromBigInteger(BigInteger x) + { + return new FpFieldElement(this.q, x); + } + + public override ECPoint CreatePoint( + BigInteger X1, + BigInteger Y1, + bool withCompression) + { + // TODO Validation of X1, Y1? + return new FpPoint( + this, + FromBigInteger(X1), + FromBigInteger(Y1), + withCompression); + } + + protected internal override ECPoint DecompressPoint( + int yTilde, + BigInteger X1) + { + ECFieldElement x = FromBigInteger(X1); + ECFieldElement alpha = x.Multiply(x.Square().Add(a)).Add(b); + ECFieldElement beta = alpha.Sqrt(); + + // + // if we can't find a sqrt we haven't got a point on the + // curve - run! + // + if (beta == null) + throw new ArithmeticException("Invalid point compression"); + + BigInteger betaValue = beta.ToBigInteger(); + int bit0 = betaValue.TestBit(0) ? 1 : 0; + + if (bit0 != yTilde) + { + // Use the other root + beta = FromBigInteger(q.Subtract(betaValue)); + } + + return new FpPoint(this, x, beta, true); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + FpCurve other = obj as FpCurve; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + FpCurve other) + { + return base.Equals(other) && q.Equals(other.q); + } + + public override int GetHashCode() + { + return base.GetHashCode() ^ q.GetHashCode(); + } + } + + /** + * Elliptic curves over F2m. The Weierstrass equation is given by + * y2 + xy = x3 + ax2 + b. + */ + public class F2mCurve : ECCurveBase + { + /** + * The exponent m of F2m. + */ + private readonly int m; + + /** + * TPB: The integer k where xm + + * xk + 1 represents the reduction polynomial + * f(z).
      + * PPB: The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + private readonly int k1; + + /** + * TPB: Always set to 0
      + * PPB: The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + private readonly int k2; + + /** + * TPB: Always set to 0
      + * PPB: The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + private readonly int k3; + + /** + * The order of the base point of the curve. + */ + private readonly BigInteger n; + + /** + * The cofactor of the curve. + */ + private readonly BigInteger h; + + /** + * The point at infinity on this curve. + */ + private readonly F2mPoint infinity; + + /** + * The parameter μ of the elliptic curve if this is + * a Koblitz curve. + */ + private sbyte mu = 0; + + /** + * The auxiliary values s0 and + * s1 used for partial modular reduction for + * Koblitz curves. + */ + private BigInteger[] si = null; + + /** + * Constructor for Trinomial Polynomial Basis (TPB). + * @param m The exponent m of + * F2m. + * @param k The integer k where xm + + * xk + 1 represents the reduction + * polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + */ + public F2mCurve( + int m, + int k, + BigInteger a, + BigInteger b) + : this(m, k, 0, 0, a, b, null, null) + { + } + + /** + * Constructor for Trinomial Polynomial Basis (TPB). + * @param m The exponent m of + * F2m. + * @param k The integer k where xm + + * xk + 1 represents the reduction + * polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param n The order of the main subgroup of the elliptic curve. + * @param h The cofactor of the elliptic curve, i.e. + * #Ea(F2m) = h * n. + */ + public F2mCurve( + int m, + int k, + BigInteger a, + BigInteger b, + BigInteger n, + BigInteger h) + : this(m, k, 0, 0, a, b, n, h) + { + } + + /** + * Constructor for Pentanomial Polynomial Basis (PPB). + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + */ + public F2mCurve( + int m, + int k1, + int k2, + int k3, + BigInteger a, + BigInteger b) + : this(m, k1, k2, k3, a, b, null, null) + { + } + + /** + * Constructor for Pentanomial Polynomial Basis (PPB). + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param n The order of the main subgroup of the elliptic curve. + * @param h The cofactor of the elliptic curve, i.e. + * #Ea(F2m) = h * n. + */ + public F2mCurve( + int m, + int k1, + int k2, + int k3, + BigInteger a, + BigInteger b, + BigInteger n, + BigInteger h) + { + this.m = m; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + this.n = n; + this.h = h; + this.infinity = new F2mPoint(this, null, null); + + if (k1 == 0) + throw new ArgumentException("k1 must be > 0"); + + if (k2 == 0) + { + if (k3 != 0) + throw new ArgumentException("k3 must be 0 if k2 == 0"); + } + else + { + if (k2 <= k1) + throw new ArgumentException("k2 must be > k1"); + + if (k3 <= k2) + throw new ArgumentException("k3 must be > k2"); + } + + this.a = FromBigInteger(a); + this.b = FromBigInteger(b); + } + + public override ECPoint Infinity + { + get { return infinity; } + } + + public override int FieldSize + { + get { return m; } + } + + public override ECFieldElement FromBigInteger(BigInteger x) + { + return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x); + } + + /** + * Returns true if this is a Koblitz curve (ABC curve). + * @return true if this is a Koblitz curve (ABC curve), false otherwise + */ + public bool IsKoblitz + { + get + { + return n != null && h != null + && (a.ToBigInteger().Equals(BigInteger.Zero) + || a.ToBigInteger().Equals(BigInteger.One)) + && b.ToBigInteger().Equals(BigInteger.One); + } + } + + /** + * Returns the parameter μ of the elliptic curve. + * @return μ of the elliptic curve. + * @throws ArgumentException if the given ECCurve is not a + * Koblitz curve. + */ + internal sbyte GetMu() + { + if (mu == 0) + { + lock (this) + { + if (mu == 0) + { + mu = Tnaf.GetMu(this); + } + } + } + + return mu; + } + + /** + * @return the auxiliary values s0 and + * s1 used for partial modular reduction for + * Koblitz curves. + */ + internal BigInteger[] GetSi() + { + if (si == null) + { + lock (this) + { + if (si == null) + { + si = Tnaf.GetSi(this); + } + } + } + return si; + } + + public override ECPoint CreatePoint( + BigInteger X1, + BigInteger Y1, + bool withCompression) + { + // TODO Validation of X1, Y1? + return new F2mPoint( + this, + FromBigInteger(X1), + FromBigInteger(Y1), + withCompression); + } + + protected internal override ECPoint DecompressPoint( + int yTilde, + BigInteger X1) + { + ECFieldElement xp = FromBigInteger(X1); + ECFieldElement yp = null; + if (xp.ToBigInteger().SignValue == 0) + { + yp = (F2mFieldElement)b; + for (int i = 0; i < m - 1; i++) + { + yp = yp.Square(); + } + } + else + { + ECFieldElement beta = xp.Add(a).Add( + b.Multiply(xp.Square().Invert())); + ECFieldElement z = solveQuadradicEquation(beta); + + if (z == null) + throw new ArithmeticException("Invalid point compression"); + + int zBit = z.ToBigInteger().TestBit(0) ? 1 : 0; + if (zBit != yTilde) + { + z = z.Add(FromBigInteger(BigInteger.One)); + } + + yp = xp.Multiply(z); + } + + return new F2mPoint(this, xp, yp, true); + } + + /** + * Solves a quadratic equation z2 + z = beta(X9.62 + * D.1.6) The other solution is z + 1. + * + * @param beta + * The value to solve the qradratic equation for. + * @return the solution for z2 + z = beta or + * null if no solution exists. + */ + private ECFieldElement solveQuadradicEquation(ECFieldElement beta) + { + if (beta.ToBigInteger().SignValue == 0) + { + return FromBigInteger(BigInteger.Zero); + } + + ECFieldElement z = null; + ECFieldElement gamma = FromBigInteger(BigInteger.Zero); + + while (gamma.ToBigInteger().SignValue == 0) + { + ECFieldElement t = FromBigInteger(new BigInteger(m, new Random())); + z = FromBigInteger(BigInteger.Zero); + + ECFieldElement w = beta; + for (int i = 1; i <= m - 1; i++) + { + ECFieldElement w2 = w.Square(); + z = z.Square().Add(w2.Multiply(t)); + w = w2.Add(beta); + } + if (w.ToBigInteger().SignValue != 0) + { + return null; + } + gamma = z.Square().Add(z); + } + return z; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + F2mCurve other = obj as F2mCurve; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + F2mCurve other) + { + return m == other.m + && k1 == other.k1 + && k2 == other.k2 + && k3 == other.k3 + && base.Equals(other); + } + + public override int GetHashCode() + { + return base.GetHashCode() ^ m ^ k1 ^ k2 ^ k3; + } + + public int M + { + get { return m; } + } + + /** + * Return true if curve uses a Trinomial basis. + * + * @return true if curve Trinomial, false otherwise. + */ + public bool IsTrinomial() + { + return k2 == 0 && k3 == 0; + } + + public int K1 + { + get { return k1; } + } + + public int K2 + { + get { return k2; } + } + + public int K3 + { + get { return k3; } + } + + public BigInteger N + { + get { return n; } + } + + public BigInteger H + { + get { return h; } + } + } +} diff --git a/iTechSharp/srcbc/math/ec/ECFieldElement.cs b/iTechSharp/srcbc/math/ec/ECFieldElement.cs new file mode 100644 index 0000000..63a0d2f --- /dev/null +++ b/iTechSharp/srcbc/math/ec/ECFieldElement.cs @@ -0,0 +1,1253 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Math.EC +{ + public abstract class ECFieldElement + { + public abstract BigInteger ToBigInteger(); + public abstract string FieldName { get; } + public abstract int FieldSize { get; } + public abstract ECFieldElement Add(ECFieldElement b); + public abstract ECFieldElement Subtract(ECFieldElement b); + public abstract ECFieldElement Multiply(ECFieldElement b); + public abstract ECFieldElement Divide(ECFieldElement b); + public abstract ECFieldElement Negate(); + public abstract ECFieldElement Square(); + public abstract ECFieldElement Invert(); + public abstract ECFieldElement Sqrt(); + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECFieldElement other = obj as ECFieldElement; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECFieldElement other) + { + return ToBigInteger().Equals(other.ToBigInteger()); + } + + public override int GetHashCode() + { + return ToBigInteger().GetHashCode(); + } + + public override string ToString() + { + return this.ToBigInteger().ToString(2); + } + } + + public class FpFieldElement + : ECFieldElement + { + private readonly BigInteger q, x; + + public FpFieldElement( + BigInteger q, + BigInteger x) + { + if (x.CompareTo(q) >= 0) + throw new ArgumentException("x value too large in field element"); + + this.q = q; + this.x = x; + } + + public override BigInteger ToBigInteger() + { + return x; + } + + /** + * return the field name for this field. + * + * @return the string "Fp". + */ + public override string FieldName + { + get { return "Fp"; } + } + + public override int FieldSize + { + get { return q.BitLength; } + } + + public BigInteger Q + { + get { return q; } + } + + public override ECFieldElement Add( + ECFieldElement b) + { + return new FpFieldElement(q, x.Add(b.ToBigInteger()).Mod(q)); + } + + public override ECFieldElement Subtract( + ECFieldElement b) + { + return new FpFieldElement(q, x.Subtract(b.ToBigInteger()).Mod(q)); + } + + public override ECFieldElement Multiply( + ECFieldElement b) + { + return new FpFieldElement(q, x.Multiply(b.ToBigInteger()).Mod(q)); + } + + public override ECFieldElement Divide( + ECFieldElement b) + { + return new FpFieldElement(q, x.Multiply(b.ToBigInteger().ModInverse(q)).Mod(q)); + } + + public override ECFieldElement Negate() + { + return new FpFieldElement(q, x.Negate().Mod(q)); + } + + public override ECFieldElement Square() + { + return new FpFieldElement(q, x.Multiply(x).Mod(q)); + } + + public override ECFieldElement Invert() + { + return new FpFieldElement(q, x.ModInverse(q)); + } + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation + * returns the right value - if none exists it returns null. + */ + public override ECFieldElement Sqrt() + { + if (!q.TestBit(0)) + throw Platform.CreateNotImplementedException("even value of q"); + + // p mod 4 == 3 + if (q.TestBit(1)) + { + // TODO Can this be optimised (inline the Square?) + // z = g^(u+1) + p, p = 4u + 3 + ECFieldElement z = new FpFieldElement(q, x.ModPow(q.ShiftRight(2).Add(BigInteger.One), q)); + + return z.Square().Equals(this) ? z : null; + } + + // p mod 4 == 1 + BigInteger qMinusOne = q.Subtract(BigInteger.One); + + BigInteger legendreExponent = qMinusOne.ShiftRight(1); + if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One))) + return null; + + BigInteger u = qMinusOne.ShiftRight(2); + BigInteger k = u.ShiftLeft(1).Add(BigInteger.One); + + BigInteger Q = this.x; + BigInteger fourQ = Q.ShiftLeft(2).Mod(q); + + BigInteger U, V; + do + { + Random rand = new Random(); + BigInteger P; + do + { + P = new BigInteger(q.BitLength, rand); + } + while (P.CompareTo(q) >= 0 + || !(P.Multiply(P).Subtract(fourQ).ModPow(legendreExponent, q).Equals(qMinusOne))); + + BigInteger[] result = fastLucasSequence(q, P, Q, k); + U = result[0]; + V = result[1]; + + if (V.Multiply(V).Mod(q).Equals(fourQ)) + { + // Integer division by 2, mod q + if (V.TestBit(0)) + { + V = V.Add(q); + } + + V = V.ShiftRight(1); + + Debug.Assert(V.Multiply(V).Mod(q).Equals(x)); + + return new FpFieldElement(q, V); + } + } + while (U.Equals(BigInteger.One) || U.Equals(qMinusOne)); + + return null; + + +// BigInteger qMinusOne = q.Subtract(BigInteger.One); +// +// BigInteger legendreExponent = qMinusOne.ShiftRight(1); +// if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One))) +// return null; +// +// Random rand = new Random(); +// BigInteger fourX = x.ShiftLeft(2); +// +// BigInteger r; +// do +// { +// r = new BigInteger(q.BitLength, rand); +// } +// while (r.CompareTo(q) >= 0 +// || !(r.Multiply(r).Subtract(fourX).ModPow(legendreExponent, q).Equals(qMinusOne))); +// +// BigInteger n1 = qMinusOne.ShiftRight(2); +// BigInteger n2 = n1.Add(BigInteger.One); +// +// BigInteger wOne = WOne(r, x, q); +// BigInteger wSum = W(n1, wOne, q).Add(W(n2, wOne, q)).Mod(q); +// BigInteger twoR = r.ShiftLeft(1); +// +// BigInteger root = twoR.ModPow(q.Subtract(BigInteger.Two), q) +// .Multiply(x).Mod(q) +// .Multiply(wSum).Mod(q); +// +// return new FpFieldElement(q, root); + } + +// private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p) +// { +// if (n.Equals(BigInteger.One)) +// return wOne; +// +// bool isEven = !n.TestBit(0); +// n = n.ShiftRight(1); +// if (isEven) +// { +// BigInteger w = W(n, wOne, p); +// return w.Multiply(w).Subtract(BigInteger.Two).Mod(p); +// } +// BigInteger w1 = W(n.Add(BigInteger.One), wOne, p); +// BigInteger w2 = W(n, wOne, p); +// return w1.Multiply(w2).Subtract(wOne).Mod(p); +// } +// +// private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p) +// { +// return r.Multiply(r).Multiply(x.ModPow(q.Subtract(BigInteger.Two), q)).Subtract(BigInteger.Two).Mod(p); +// } + + private static BigInteger[] fastLucasSequence( + BigInteger p, + BigInteger P, + BigInteger Q, + BigInteger k) + { + // TODO Research and apply "common-multiplicand multiplication here" + + int n = k.BitLength; + int s = k.GetLowestSetBit(); + + Debug.Assert(k.TestBit(s)); + + BigInteger Uh = BigInteger.One; + BigInteger Vl = BigInteger.Two; + BigInteger Vh = P; + BigInteger Ql = BigInteger.One; + BigInteger Qh = BigInteger.One; + + for (int j = n - 1; j >= s + 1; --j) + { + Ql = Ql.Multiply(Qh).Mod(p); + + if (k.TestBit(j)) + { + Qh = Ql.Multiply(Q).Mod(p); + Uh = Uh.Multiply(Vh).Mod(p); + Vl = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p); + Vh = Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)).Mod(p); + } + else + { + Qh = Ql; + Uh = Uh.Multiply(Vl).Subtract(Ql).Mod(p); + Vh = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p); + Vl = Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)).Mod(p); + } + } + + Ql = Ql.Multiply(Qh).Mod(p); + Qh = Ql.Multiply(Q).Mod(p); + Uh = Uh.Multiply(Vl).Subtract(Ql).Mod(p); + Vl = Vh.Multiply(Vl).Subtract(P.Multiply(Ql)).Mod(p); + Ql = Ql.Multiply(Qh).Mod(p); + + for (int j = 1; j <= s; ++j) + { + Uh = Uh.Multiply(Vl).Mod(p); + Vl = Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)).Mod(p); + Ql = Ql.Multiply(Ql).Mod(p); + } + + return new BigInteger[]{ Uh, Vl }; + } + +// private static BigInteger[] verifyLucasSequence( +// BigInteger p, +// BigInteger P, +// BigInteger Q, +// BigInteger k) +// { +// BigInteger[] actual = fastLucasSequence(p, P, Q, k); +// BigInteger[] plus1 = fastLucasSequence(p, P, Q, k.Add(BigInteger.One)); +// BigInteger[] plus2 = fastLucasSequence(p, P, Q, k.Add(BigInteger.Two)); +// +// BigInteger[] check = stepLucasSequence(p, P, Q, actual, plus1); +// +// Debug.Assert(check[0].Equals(plus2[0])); +// Debug.Assert(check[1].Equals(plus2[1])); +// +// return actual; +// } +// +// private static BigInteger[] stepLucasSequence( +// BigInteger p, +// BigInteger P, +// BigInteger Q, +// BigInteger[] backTwo, +// BigInteger[] backOne) +// { +// return new BigInteger[] +// { +// P.Multiply(backOne[0]).Subtract(Q.Multiply(backTwo[0])).Mod(p), +// P.Multiply(backOne[1]).Subtract(Q.Multiply(backTwo[1])).Mod(p) +// }; +// } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + FpFieldElement other = obj as FpFieldElement; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + FpFieldElement other) + { + return q.Equals(other.q) && base.Equals(other); + } + + public override int GetHashCode() + { + return q.GetHashCode() ^ base.GetHashCode(); + } + } + +// /** +// * Class representing the Elements of the finite field +// * F2m in polynomial basis (PB) +// * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial +// * basis representations are supported. Gaussian normal basis (GNB) +// * representation is not supported. +// */ +// public class F2mFieldElement +// : ECFieldElement +// { +// /** +// * Indicates gaussian normal basis representation (GNB). Number chosen +// * according to X9.62. GNB is not implemented at present. +// */ +// public const int Gnb = 1; +// +// /** +// * Indicates trinomial basis representation (Tpb). Number chosen +// * according to X9.62. +// */ +// public const int Tpb = 2; +// +// /** +// * Indicates pentanomial basis representation (Ppb). Number chosen +// * according to X9.62. +// */ +// public const int Ppb = 3; +// +// /** +// * Tpb or Ppb. +// */ +// private int representation; +// +// /** +// * The exponent m of F2m. +// */ +// private int m; +// +// /** +// * Tpb: The integer k where xm + +// * xk + 1 represents the reduction polynomial +// * f(z).
      +// * Ppb: The integer k1 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z).
      +// */ +// private int k1; +// +// /** +// * Tpb: Always set to 0
      +// * Ppb: The integer k2 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z).
      +// */ +// private int k2; +// +// /** +// * Tpb: Always set to 0
      +// * Ppb: The integer k3 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z).
      +// */ +// private int k3; +// +// /** +// * Constructor for Ppb. +// * @param m The exponent m of +// * F2m. +// * @param k1 The integer k1 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z). +// * @param k2 The integer k2 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z). +// * @param k3 The integer k3 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z). +// * @param x The BigInteger representing the value of the field element. +// */ +// public F2mFieldElement( +// int m, +// int k1, +// int k2, +// int k3, +// BigInteger x) +// : base(x) +// { +// if ((k2 == 0) && (k3 == 0)) +// { +// this.representation = Tpb; +// } +// else +// { +// if (k2 >= k3) +// throw new ArgumentException("k2 must be smaller than k3"); +// if (k2 <= 0) +// throw new ArgumentException("k2 must be larger than 0"); +// +// this.representation = Ppb; +// } +// +// if (x.SignValue < 0) +// throw new ArgumentException("x value cannot be negative"); +// +// this.m = m; +// this.k1 = k1; +// this.k2 = k2; +// this.k3 = k3; +// } +// +// /** +// * Constructor for Tpb. +// * @param m The exponent m of +// * F2m. +// * @param k The integer k where xm + +// * xk + 1 represents the reduction +// * polynomial f(z). +// * @param x The BigInteger representing the value of the field element. +// */ +// public F2mFieldElement( +// int m, +// int k, +// BigInteger x) +// : this(m, k, 0, 0, x) +// { +// // Set k1 to k, and set k2 and k3 to 0 +// } +// +// public override string FieldName +// { +// get { return "F2m"; } +// } +// +// /** +// * Checks, if the ECFieldElements a and b +// * are elements of the same field F2m +// * (having the same representation). +// * @param a field element. +// * @param b field element to be compared. +// * @throws ArgumentException if a and b +// * are not elements of the same field +// * F2m (having the same +// * representation). +// */ +// public static void CheckFieldElements( +// ECFieldElement a, +// ECFieldElement b) +// { +// if (!(a is F2mFieldElement) || !(b is F2mFieldElement)) +// { +// throw new ArgumentException("Field elements are not " +// + "both instances of F2mFieldElement"); +// } +// +// if ((a.x.SignValue < 0) || (b.x.SignValue < 0)) +// { +// throw new ArgumentException( +// "x value may not be negative"); +// } +// +// F2mFieldElement aF2m = (F2mFieldElement)a; +// F2mFieldElement bF2m = (F2mFieldElement)b; +// +// if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1) +// || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3)) +// { +// throw new ArgumentException("Field elements are not " +// + "elements of the same field F2m"); +// } +// +// if (aF2m.representation != bF2m.representation) +// { +// // Should never occur +// throw new ArgumentException( +// "One of the field " +// + "elements are not elements has incorrect representation"); +// } +// } +// +// /** +// * Computes z * a(z) mod f(z), where f(z) is +// * the reduction polynomial of this. +// * @param a The polynomial a(z) to be multiplied by +// * z mod f(z). +// * @return z * a(z) mod f(z) +// */ +// private BigInteger multZModF( +// BigInteger a) +// { +// // Left-shift of a(z) +// BigInteger az = a.ShiftLeft(1); +// if (az.TestBit(this.m)) +// { +// // If the coefficient of z^m in a(z) Equals 1, reduction +// // modulo f(z) is performed: Add f(z) to to a(z): +// // Step 1: Unset mth coeffient of a(z) +// az = az.ClearBit(this.m); +// +// // Step 2: Add r(z) to a(z), where r(z) is defined as +// // f(z) = z^m + r(z), and k1, k2, k3 are the positions of +// // the non-zero coefficients in r(z) +// az = az.FlipBit(0); +// az = az.FlipBit(this.k1); +// if (this.representation == Ppb) +// { +// az = az.FlipBit(this.k2); +// az = az.FlipBit(this.k3); +// } +// } +// return az; +// } +// +// public override ECFieldElement Add( +// ECFieldElement b) +// { +// // No check performed here for performance reasons. Instead the +// // elements involved are checked in ECPoint.F2m +// // checkFieldElements(this, b); +// if (b.x.SignValue == 0) +// return this; +// +// return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, this.x.Xor(b.x)); +// } +// +// public override ECFieldElement Subtract( +// ECFieldElement b) +// { +// // Addition and subtraction are the same in F2m +// return Add(b); +// } +// +// public override ECFieldElement Multiply( +// ECFieldElement b) +// { +// // Left-to-right shift-and-add field multiplication in F2m +// // Input: Binary polynomials a(z) and b(z) of degree at most m-1 +// // Output: c(z) = a(z) * b(z) mod f(z) +// +// // No check performed here for performance reasons. Instead the +// // elements involved are checked in ECPoint.F2m +// // checkFieldElements(this, b); +// BigInteger az = this.x; +// BigInteger bz = b.x; +// BigInteger cz; +// +// // Compute c(z) = a(z) * b(z) mod f(z) +// if (az.TestBit(0)) +// { +// cz = bz; +// } +// else +// { +// cz = BigInteger.Zero; +// } +// +// for (int i = 1; i < this.m; i++) +// { +// // b(z) := z * b(z) mod f(z) +// bz = multZModF(bz); +// +// if (az.TestBit(i)) +// { +// // If the coefficient of x^i in a(z) Equals 1, b(z) is added +// // to c(z) +// cz = cz.Xor(bz); +// } +// } +// return new F2mFieldElement(m, this.k1, this.k2, this.k3, cz); +// } +// +// +// public override ECFieldElement Divide( +// ECFieldElement b) +// { +// // There may be more efficient implementations +// ECFieldElement bInv = b.Invert(); +// return Multiply(bInv); +// } +// +// public override ECFieldElement Negate() +// { +// // -x == x holds for all x in F2m +// return this; +// } +// +// public override ECFieldElement Square() +// { +// // Naive implementation, can probably be speeded up using modular +// // reduction +// return Multiply(this); +// } +// +// public override ECFieldElement Invert() +// { +// // Inversion in F2m using the extended Euclidean algorithm +// // Input: A nonzero polynomial a(z) of degree at most m-1 +// // Output: a(z)^(-1) mod f(z) +// +// // u(z) := a(z) +// BigInteger uz = this.x; +// if (uz.SignValue <= 0) +// { +// throw new ArithmeticException("x is zero or negative, " + +// "inversion is impossible"); +// } +// +// // v(z) := f(z) +// BigInteger vz = BigInteger.One.ShiftLeft(m); +// vz = vz.SetBit(0); +// vz = vz.SetBit(this.k1); +// if (this.representation == Ppb) +// { +// vz = vz.SetBit(this.k2); +// vz = vz.SetBit(this.k3); +// } +// +// // g1(z) := 1, g2(z) := 0 +// BigInteger g1z = BigInteger.One; +// BigInteger g2z = BigInteger.Zero; +// +// // while u != 1 +// while (uz.SignValue != 0) +// { +// // j := deg(u(z)) - deg(v(z)) +// int j = uz.BitLength - vz.BitLength; +// +// // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j +// if (j < 0) +// { +// BigInteger uzCopy = uz; +// uz = vz; +// vz = uzCopy; +// +// BigInteger g1zCopy = g1z; +// g1z = g2z; +// g2z = g1zCopy; +// +// j = -j; +// } +// +// // u(z) := u(z) + z^j * v(z) +// // Note, that no reduction modulo f(z) is required, because +// // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) +// // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) +// // = deg(u(z)) +// uz = uz.Xor(vz.ShiftLeft(j)); +// +// // g1(z) := g1(z) + z^j * g2(z) +// g1z = g1z.Xor(g2z.ShiftLeft(j)); +// // if (g1z.BitLength() > this.m) { +// // throw new ArithmeticException( +// // "deg(g1z) >= m, g1z = " + g1z.ToString(2)); +// // } +// } +// return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, g2z); +// } +// +// public override ECFieldElement Sqrt() +// { +// throw new ArithmeticException("Not implemented"); +// } +// +// /** +// * @return the representation of the field +// * F2m, either of +// * {@link F2mFieldElement.Tpb} (trinomial +// * basis representation) or +// * {@link F2mFieldElement.Ppb} (pentanomial +// * basis representation). +// */ +// public int Representation +// { +// get { return this.representation; } +// } +// +// /** +// * @return the degree m of the reduction polynomial +// * f(z). +// */ +// public int M +// { +// get { return this.m; } +// } +// +// /** +// * @return Tpb: The integer k where xm + +// * xk + 1 represents the reduction polynomial +// * f(z).
      +// * Ppb: The integer k1 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z).
      +// */ +// public int K1 +// { +// get { return this.k1; } +// } +// +// /** +// * @return Tpb: Always returns 0
      +// * Ppb: The integer k2 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z).
      +// */ +// public int K2 +// { +// get { return this.k2; } +// } +// +// /** +// * @return Tpb: Always set to 0
      +// * Ppb: The integer k3 where xm + +// * xk3 + xk2 + xk1 + 1 +// * represents the reduction polynomial f(z).
      +// */ +// public int K3 +// { +// get { return this.k3; } +// } +// +// public override bool Equals( +// object obj) +// { +// if (obj == this) +// return true; +// +// F2mFieldElement other = obj as F2mFieldElement; +// +// if (other == null) +// return false; +// +// return Equals(other); +// } +// +// protected bool Equals( +// F2mFieldElement other) +// { +// return m == other.m +// && k1 == other.k1 +// && k2 == other.k2 +// && k3 == other.k3 +// && representation == other.representation +// && base.Equals(other); +// } +// +// public override int GetHashCode() +// { +// return base.GetHashCode() ^ m ^ k1 ^ k2 ^ k3; +// } +// } + + /** + * Class representing the Elements of the finite field + * F2m in polynomial basis (PB) + * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial + * basis representations are supported. Gaussian normal basis (GNB) + * representation is not supported. + */ + public class F2mFieldElement + : ECFieldElement + { + /** + * Indicates gaussian normal basis representation (GNB). Number chosen + * according to X9.62. GNB is not implemented at present. + */ + public const int Gnb = 1; + + /** + * Indicates trinomial basis representation (Tpb). Number chosen + * according to X9.62. + */ + public const int Tpb = 2; + + /** + * Indicates pentanomial basis representation (Ppb). Number chosen + * according to X9.62. + */ + public const int Ppb = 3; + + /** + * Tpb or Ppb. + */ + private int representation; + + /** + * The exponent m of F2m. + */ + private int m; + + /** + * Tpb: The integer k where xm + + * xk + 1 represents the reduction polynomial + * f(z).
      + * Ppb: The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + private int k1; + + /** + * Tpb: Always set to 0
      + * Ppb: The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + private int k2; + + /** + * Tpb: Always set to 0
      + * Ppb: The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + private int k3; + + /** + * The IntArray holding the bits. + */ + private IntArray x; + + /** + * The number of ints required to hold m bits. + */ + private readonly int t; + + /** + * Constructor for Ppb. + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param x The BigInteger representing the value of the field element. + */ + public F2mFieldElement( + int m, + int k1, + int k2, + int k3, + BigInteger x) + { + // t = m / 32 rounded up to the next integer + this.t = (m + 31) >> 5; + this.x = new IntArray(x, t); + + if ((k2 == 0) && (k3 == 0)) + { + this.representation = Tpb; + } + else + { + if (k2 >= k3) + throw new ArgumentException("k2 must be smaller than k3"); + if (k2 <= 0) + throw new ArgumentException("k2 must be larger than 0"); + + this.representation = Ppb; + } + + if (x.SignValue < 0) + throw new ArgumentException("x value cannot be negative"); + + this.m = m; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + } + + /** + * Constructor for Tpb. + * @param m The exponent m of + * F2m. + * @param k The integer k where xm + + * xk + 1 represents the reduction + * polynomial f(z). + * @param x The BigInteger representing the value of the field element. + */ + public F2mFieldElement( + int m, + int k, + BigInteger x) + : this(m, k, 0, 0, x) + { + // Set k1 to k, and set k2 and k3 to 0 + } + + private F2mFieldElement(int m, int k1, int k2, int k3, IntArray x) + { + t = (m + 31) >> 5; + this.x = x; + this.m = m; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + + if ((k2 == 0) && (k3 == 0)) + { + this.representation = Tpb; + } + else + { + this.representation = Ppb; + } + } + + public override BigInteger ToBigInteger() + { + return x.ToBigInteger(); + } + + public override string FieldName + { + get { return "F2m"; } + } + + public override int FieldSize + { + get { return m; } + } + + /** + * Checks, if the ECFieldElements a and b + * are elements of the same field F2m + * (having the same representation). + * @param a field element. + * @param b field element to be compared. + * @throws ArgumentException if a and b + * are not elements of the same field + * F2m (having the same + * representation). + */ + public static void CheckFieldElements( + ECFieldElement a, + ECFieldElement b) + { + if (!(a is F2mFieldElement) || !(b is F2mFieldElement)) + { + throw new ArgumentException("Field elements are not " + + "both instances of F2mFieldElement"); + } + + F2mFieldElement aF2m = (F2mFieldElement)a; + F2mFieldElement bF2m = (F2mFieldElement)b; + + if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1) + || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3)) + { + throw new ArgumentException("Field elements are not " + + "elements of the same field F2m"); + } + + if (aF2m.representation != bF2m.representation) + { + // Should never occur + throw new ArgumentException( + "One of the field " + + "elements are not elements has incorrect representation"); + } + } + + public override ECFieldElement Add( + ECFieldElement b) + { + // No check performed here for performance reasons. Instead the + // elements involved are checked in ECPoint.F2m + // checkFieldElements(this, b); + IntArray iarrClone = (IntArray) this.x.Clone(); + F2mFieldElement bF2m = (F2mFieldElement) b; + iarrClone.AddShifted(bF2m.x, 0); + return new F2mFieldElement(m, k1, k2, k3, iarrClone); + } + + public override ECFieldElement Subtract( + ECFieldElement b) + { + // Addition and subtraction are the same in F2m + return Add(b); + } + + public override ECFieldElement Multiply( + ECFieldElement b) + { + // Right-to-left comb multiplication in the IntArray + // Input: Binary polynomials a(z) and b(z) of degree at most m-1 + // Output: c(z) = a(z) * b(z) mod f(z) + + // No check performed here for performance reasons. Instead the + // elements involved are checked in ECPoint.F2m + // checkFieldElements(this, b); + F2mFieldElement bF2m = (F2mFieldElement) b; + IntArray mult = x.Multiply(bF2m.x, m); + mult.Reduce(m, new int[]{k1, k2, k3}); + return new F2mFieldElement(m, k1, k2, k3, mult); + } + + public override ECFieldElement Divide( + ECFieldElement b) + { + // There may be more efficient implementations + ECFieldElement bInv = b.Invert(); + return Multiply(bInv); + } + + public override ECFieldElement Negate() + { + // -x == x holds for all x in F2m + return this; + } + + public override ECFieldElement Square() + { + IntArray squared = x.Square(m); + squared.Reduce(m, new int[]{k1, k2, k3}); + return new F2mFieldElement(m, k1, k2, k3, squared); + } + + public override ECFieldElement Invert() + { + // Inversion in F2m using the extended Euclidean algorithm + // Input: A nonzero polynomial a(z) of degree at most m-1 + // Output: a(z)^(-1) mod f(z) + + // u(z) := a(z) + IntArray uz = (IntArray)this.x.Clone(); + + // v(z) := f(z) + IntArray vz = new IntArray(t); + vz.SetBit(m); + vz.SetBit(0); + vz.SetBit(this.k1); + if (this.representation == Ppb) + { + vz.SetBit(this.k2); + vz.SetBit(this.k3); + } + + // g1(z) := 1, g2(z) := 0 + IntArray g1z = new IntArray(t); + g1z.SetBit(0); + IntArray g2z = new IntArray(t); + + // while u != 0 + while (uz.GetUsedLength() > 0) +// while (uz.bitLength() > 1) + { + // j := deg(u(z)) - deg(v(z)) + int j = uz.BitLength - vz.BitLength; + + // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j + if (j < 0) + { + IntArray uzCopy = uz; + uz = vz; + vz = uzCopy; + + IntArray g1zCopy = g1z; + g1z = g2z; + g2z = g1zCopy; + + j = -j; + } + + // u(z) := u(z) + z^j * v(z) + // Note, that no reduction modulo f(z) is required, because + // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) + // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) + // = deg(u(z)) + // uz = uz.xor(vz.ShiftLeft(j)); + // jInt = n / 32 + int jInt = j >> 5; + // jInt = n % 32 + int jBit = j & 0x1F; + IntArray vzShift = vz.ShiftLeft(jBit); + uz.AddShifted(vzShift, jInt); + + // g1(z) := g1(z) + z^j * g2(z) +// g1z = g1z.xor(g2z.ShiftLeft(j)); + IntArray g2zShift = g2z.ShiftLeft(jBit); + g1z.AddShifted(g2zShift, jInt); + } + return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, g2z); + } + + public override ECFieldElement Sqrt() + { + throw new ArithmeticException("Not implemented"); + } + + /** + * @return the representation of the field + * F2m, either of + * {@link F2mFieldElement.Tpb} (trinomial + * basis representation) or + * {@link F2mFieldElement.Ppb} (pentanomial + * basis representation). + */ + public int Representation + { + get { return this.representation; } + } + + /** + * @return the degree m of the reduction polynomial + * f(z). + */ + public int M + { + get { return this.m; } + } + + /** + * @return Tpb: The integer k where xm + + * xk + 1 represents the reduction polynomial + * f(z).
      + * Ppb: The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + public int K1 + { + get { return this.k1; } + } + + /** + * @return Tpb: Always returns 0
      + * Ppb: The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + public int K2 + { + get { return this.k2; } + } + + /** + * @return Tpb: Always set to 0
      + * Ppb: The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
      + */ + public int K3 + { + get { return this.k3; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + F2mFieldElement other = obj as F2mFieldElement; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + F2mFieldElement other) + { + return m == other.m + && k1 == other.k1 + && k2 == other.k2 + && k3 == other.k3 + && representation == other.representation + && base.Equals(other); + } + + public override int GetHashCode() + { + return m.GetHashCode() + ^ k1.GetHashCode() + ^ k2.GetHashCode() + ^ k3.GetHashCode() + ^ representation.GetHashCode() + ^ base.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/math/ec/ECPoint.cs b/iTechSharp/srcbc/math/ec/ECPoint.cs new file mode 100644 index 0000000..7a91ada --- /dev/null +++ b/iTechSharp/srcbc/math/ec/ECPoint.cs @@ -0,0 +1,566 @@ +using System; +using System.Collections; +using System.Diagnostics; + +using Org.BouncyCastle.Asn1.X9; + +using Org.BouncyCastle.Math.EC.Multiplier; + +namespace Org.BouncyCastle.Math.EC +{ + /** + * base class for points on elliptic curves. + */ + public abstract class ECPoint + { + internal readonly ECCurve curve; + internal readonly ECFieldElement x, y; + internal readonly bool withCompression; + internal ECMultiplier multiplier = null; + internal PreCompInfo preCompInfo = null; + + protected internal ECPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y, + bool withCompression) + { + if (curve == null) + throw new ArgumentNullException("curve"); + + this.curve = curve; + this.x = x; + this.y = y; + this.withCompression = withCompression; + } + + public ECCurve Curve + { + get { return curve; } + } + + public ECFieldElement X + { + get { return x; } + } + + public ECFieldElement Y + { + get { return y; } + } + + public bool IsInfinity + { + get { return x == null && y == null; } + } + + public bool IsCompressed + { + get { return withCompression; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECPoint o = obj as ECPoint; + + if (o == null) + return false; + + if (this.IsInfinity) + return o.IsInfinity; + + return x.Equals(o.x) && y.Equals(o.y); + } + + public override int GetHashCode() + { + if (this.IsInfinity) + return 0; + + return x.GetHashCode() ^ y.GetHashCode(); + } + +// /** +// * Mainly for testing. Explicitly set the ECMultiplier. +// * @param multiplier The ECMultiplier to be used to multiply +// * this ECPoint. +// */ +// internal void SetECMultiplier( +// ECMultiplier multiplier) +// { +// this.multiplier = multiplier; +// } + + /** + * Sets the PreCompInfo. Used by ECMultipliers + * to save the precomputation for this ECPoint to store the + * precomputation result for use by subsequent multiplication. + * @param preCompInfo The values precomputed by the + * ECMultiplier. + */ + internal void SetPreCompInfo( + PreCompInfo preCompInfo) + { + this.preCompInfo = preCompInfo; + } + + public abstract byte[] GetEncoded(); + + public abstract ECPoint Add(ECPoint b); + public abstract ECPoint Subtract(ECPoint b); + public abstract ECPoint Negate(); + public abstract ECPoint Twice(); + public abstract ECPoint Multiply(BigInteger b); + + /** + * Sets the appropriate ECMultiplier, unless already set. + */ + internal virtual void AssertECMultiplier() + { + if (this.multiplier == null) + { + lock (this) + { + if (this.multiplier == null) + { + this.multiplier = new FpNafMultiplier(); + } + } + } + } + } + + public abstract class ECPointBase + : ECPoint + { + protected internal ECPointBase( + ECCurve curve, + ECFieldElement x, + ECFieldElement y, + bool withCompression) + : base(curve, x, y, withCompression) + { + } + + protected internal abstract bool YTilde { get; } + + /** + * return the field element encoded with point compression. (S 4.3.6) + */ + public override byte[] GetEncoded() + { + if (this.IsInfinity) + return new byte[1]; + + // Note: some of the tests rely on calculating byte length from the field element + // (since the test cases use mismatching fields for curve/elements) + int byteLength = X9IntegerConverter.GetByteLength(x); + byte[] X = X9IntegerConverter.IntegerToBytes(this.X.ToBigInteger(), byteLength); + byte[] PO; + + if (withCompression) + { + PO = new byte[1 + X.Length]; + + PO[0] = (byte)(YTilde ? 0x03 : 0x02); + } + else + { + byte[] Y = X9IntegerConverter.IntegerToBytes(this.Y.ToBigInteger(), byteLength); + PO = new byte[1 + X.Length + Y.Length]; + + PO[0] = 0x04; + + Y.CopyTo(PO, 1 + X.Length); + } + + X.CopyTo(PO, 1); + + return PO; + } + + /** + * Multiplies this ECPoint by the given number. + * @param k The multiplicator. + * @return k * this. + */ + public override ECPoint Multiply( + BigInteger k) + { + if (this.IsInfinity) + return this; + + if (k.SignValue == 0) + return this.curve.Infinity; + + AssertECMultiplier(); + return this.multiplier.Multiply(this, k, preCompInfo); + } + } + + /** + * Elliptic curve points over Fp + */ + public class FpPoint + : ECPointBase + { + /** + * Create a point which encodes with point compression. + * + * @param curve the curve to use + * @param x affine x co-ordinate + * @param y affine y co-ordinate + */ + public FpPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y) + : this(curve, x, y, false) + { + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve the curve to use + * @param x affine x co-ordinate + * @param y affine y co-ordinate + * @param withCompression if true encode with point compression + */ + public FpPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y, + bool withCompression) + : base(curve, x, y, withCompression) + { + if ((x != null && y == null) || (x == null && y != null)) + throw new ArgumentException("Exactly one of the field elements is null"); + } + + protected internal override bool YTilde + { + get + { + return this.Y.ToBigInteger().TestBit(0); + } + } + + // B.3 pg 62 + public override ECPoint Add( + ECPoint b) + { + if (this.IsInfinity) + return b; + + if (b.IsInfinity) + return this; + + // Check if b = this or b = -this + if (this.x.Equals(b.x)) + { + if (this.y.Equals(b.y)) + { + // this = b, i.e. this must be doubled + return this.Twice(); + } + + Debug.Assert(this.y.Equals(b.y.Negate())); + + // this = -b, i.e. the result is the point at infinity + return this.curve.Infinity; + } + + ECFieldElement gamma = b.y.Subtract(this.y).Divide(b.x.Subtract(this.x)); + + ECFieldElement x3 = gamma.Square().Subtract(this.x).Subtract(b.x); + ECFieldElement y3 = gamma.Multiply(this.x.Subtract(x3)).Subtract(this.y); + + return new FpPoint(curve, x3, y3); + } + + // B.3 pg 62 + public override ECPoint Twice() + { + // Twice identity element (point at infinity) is identity + if (this.IsInfinity) + return this; + + // if y1 == 0, then (x1, y1) == (x1, -y1) + // and hence this = -this and thus 2(x1, y1) == infinity + if (this.y.ToBigInteger().SignValue == 0) + return this.curve.Infinity; + + ECFieldElement TWO = this.curve.FromBigInteger(BigInteger.Two); + ECFieldElement THREE = this.curve.FromBigInteger(BigInteger.Three); + ECFieldElement gamma = this.x.Square().Multiply(THREE).Add(curve.a).Divide(y.Multiply(TWO)); + + ECFieldElement x3 = gamma.Square().Subtract(this.x.Multiply(TWO)); + ECFieldElement y3 = gamma.Multiply(this.x.Subtract(x3)).Subtract(this.y); + + return new FpPoint(curve, x3, y3, this.withCompression); + } + + // D.3.2 pg 102 (see Note:) + public override ECPoint Subtract( + ECPoint b) + { + if (b.IsInfinity) + return this; + + // Add -b + return Add(b.Negate()); + } + + public override ECPoint Negate() + { + return new FpPoint(this.curve, this.x, this.y.Negate(), this.withCompression); + } + + // TODO Uncomment this to enable WNAF Fp point multiplication +// /** +// * Sets the default ECMultiplier, unless already set. +// */ +// internal override void AssertECMultiplier() +// { +// if (this.multiplier == null) +// { +// lock (this) +// { +// if (this.multiplier == null) +// { +// this.multiplier = new WNafMultiplier(); +// } +// } +// } +// } + } + + /** + * Elliptic curve points over F2m + */ + public class F2mPoint + : ECPointBase + { + /** + * @param curve base curve + * @param x x point + * @param y y point + */ + public F2mPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y) + : this(curve, x, y, false) + { + } + + /** + * @param curve base curve + * @param x x point + * @param y y point + * @param withCompression true if encode with point compression. + */ + public F2mPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y, + bool withCompression) + : base(curve, x, y, withCompression) + { + if ((x != null && y == null) || (x == null && y != null)) + { + throw new ArgumentException("Exactly one of the field elements is null"); + } + + if (x != null) + { + // Check if x and y are elements of the same field + F2mFieldElement.CheckFieldElements(this.x, this.y); + + // Check if x and a are elements of the same field + F2mFieldElement.CheckFieldElements(this.x, this.curve.A); + } + } + + /** + * Constructor for point at infinity + */ + [Obsolete("Use ECCurve.Infinity property")] + public F2mPoint( + ECCurve curve) + : this(curve, null, null) + { + } + + protected internal override bool YTilde + { + get + { + // X9.62 4.2.2 and 4.3.6: + // if x = 0 then ypTilde := 0, else ypTilde is the rightmost + // bit of y * x^(-1) + return this.X.ToBigInteger().SignValue != 0 + && this.Y.Multiply(this.X.Invert()).ToBigInteger().TestBit(0); + } + } + + /** + * Check, if two ECPoints can be added or subtracted. + * @param a The first ECPoint to check. + * @param b The second ECPoint to check. + * @throws IllegalArgumentException if a and b + * cannot be added. + */ + private static void CheckPoints( + ECPoint a, + ECPoint b) + { + // Check, if points are on the same curve + if (!a.curve.Equals(b.curve)) + throw new ArgumentException("Only points on the same curve can be added or subtracted"); + +// F2mFieldElement.CheckFieldElements(a.x, b.x); + } + + /* (non-Javadoc) + * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint) + */ + public override ECPoint Add(ECPoint b) + { + CheckPoints(this, b); + return AddSimple((F2mPoint) b); + } + + /** + * Adds another ECPoints.F2m to this without + * checking if both points are on the same curve. Used by multiplication + * algorithms, because there all points are a multiple of the same point + * and hence the checks can be omitted. + * @param b The other ECPoints.F2m to add to + * this. + * @return this + b + */ + internal F2mPoint AddSimple(F2mPoint b) + { + if (this.IsInfinity) + return b; + + if (b.IsInfinity) + return this; + + F2mFieldElement x2 = (F2mFieldElement) b.X; + F2mFieldElement y2 = (F2mFieldElement) b.Y; + + // Check if b == this or b == -this + if (this.x.Equals(x2)) + { + // this == b, i.e. this must be doubled + if (this.y.Equals(y2)) + return (F2mPoint) this.Twice(); + + // this = -other, i.e. the result is the point at infinity + return (F2mPoint) this.curve.Infinity; + } + + ECFieldElement xSum = this.x.Add(x2); + + F2mFieldElement lambda + = (F2mFieldElement)(this.y.Add(y2)).Divide(xSum); + + F2mFieldElement x3 + = (F2mFieldElement)lambda.Square().Add(lambda).Add(xSum).Add(this.curve.A); + + F2mFieldElement y3 + = (F2mFieldElement)lambda.Multiply(this.x.Add(x3)).Add(x3).Add(this.y); + + return new F2mPoint(curve, x3, y3, withCompression); + } + + /* (non-Javadoc) + * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint) + */ + public override ECPoint Subtract( + ECPoint b) + { + CheckPoints(this, b); + return SubtractSimple((F2mPoint) b); + } + + /** + * Subtracts another ECPoints.F2m from this + * without checking if both points are on the same curve. Used by + * multiplication algorithms, because there all points are a multiple + * of the same point and hence the checks can be omitted. + * @param b The other ECPoints.F2m to subtract from + * this. + * @return this - b + */ + internal F2mPoint SubtractSimple( + F2mPoint b) + { + if (b.IsInfinity) + return this; + + // Add -b + return AddSimple((F2mPoint) b.Negate()); + } + + /* (non-Javadoc) + * @see Org.BouncyCastle.Math.EC.ECPoint#twice() + */ + public override ECPoint Twice() + { + // Twice identity element (point at infinity) is identity + if (this.IsInfinity) + return this; + + // if x1 == 0, then (x1, y1) == (x1, x1 + y1) + // and hence this = -this and thus 2(x1, y1) == infinity + if (this.x.ToBigInteger().SignValue == 0) + return this.curve.Infinity; + + F2mFieldElement lambda = (F2mFieldElement) this.x.Add(this.y.Divide(this.x)); + F2mFieldElement x2 = (F2mFieldElement)lambda.Square().Add(lambda).Add(this.curve.A); + ECFieldElement ONE = this.curve.FromBigInteger(BigInteger.One); + F2mFieldElement y2 = (F2mFieldElement)this.x.Square().Add( + x2.Multiply(lambda.Add(ONE))); + + return new F2mPoint(this.curve, x2, y2, withCompression); + } + + public override ECPoint Negate() + { + return new F2mPoint(curve, this.x, this.x.Add(this.y), withCompression); + } + + // TODO Uncomment this to enable WNAF/WTNAF F2m point multiplication +// /** +// * Sets the appropriate ECMultiplier, unless already set. +// */ +// internal override void AssertECMultiplier() +// { +// if (this.multiplier == null) +// { +// lock (this) +// { +// if (this.multiplier == null) +// { +// if (((F2mCurve) this.curve).IsKoblitz) +// { +// this.multiplier = new WTauNafMultiplier(); +// } +// else +// { +// this.multiplier = new WNafMultiplier(); +// } +// } +// } +// } +// } + } +} diff --git a/iTechSharp/srcbc/math/ec/IntArray.cs b/iTechSharp/srcbc/math/ec/IntArray.cs new file mode 100644 index 0000000..b6b5828 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/IntArray.cs @@ -0,0 +1,486 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Math.EC +{ + internal class IntArray + : ICloneable + { + // TODO make m fixed for the IntArray, and hence compute T once and for all + + // TODO Use uint's internally? + private int[] m_ints; + + public IntArray(int intLen) + { + m_ints = new int[intLen]; + } + + private IntArray(int[] ints) + { + m_ints = ints; + } + + public IntArray(BigInteger bigInt) + : this(bigInt, 0) + { + } + + public IntArray(BigInteger bigInt, int minIntLen) + { + if (bigInt.SignValue == -1) + throw new ArgumentException("Only positive Integers allowed", "bigint"); + + if (bigInt.SignValue == 0) + { + m_ints = new int[] { 0 }; + return; + } + + byte[] barr = bigInt.ToByteArrayUnsigned(); + int barrLen = barr.Length; + + int intLen = (barrLen + 3) / 4; + m_ints = new int[System.Math.Max(intLen, minIntLen)]; + + int rem = barrLen % 4; + int barrI = 0; + + if (0 < rem) + { + int temp = (int) barr[barrI++]; + while (barrI < rem) + { + temp = temp << 8 | (int) barr[barrI++]; + } + m_ints[--intLen] = temp; + } + + while (intLen > 0) + { + int temp = (int) barr[barrI++]; + for (int i = 1; i < 4; i++) + { + temp = temp << 8 | (int) barr[barrI++]; + } + m_ints[--intLen] = temp; + } + } + + public int GetUsedLength() + { + int highestIntPos = m_ints.Length; + + if (highestIntPos < 1) + return 0; + + // Check if first element will act as sentinel + if (m_ints[0] != 0) + { + while (m_ints[--highestIntPos] == 0) + { + } + return highestIntPos + 1; + } + + do + { + if (m_ints[--highestIntPos] != 0) + { + return highestIntPos + 1; + } + } + while (highestIntPos > 0); + + return 0; + } + + public int BitLength + { + get + { + // JDK 1.5: see Integer.numberOfLeadingZeros() + int intLen = GetUsedLength(); + if (intLen == 0) + return 0; + + int last = intLen - 1; + uint highest = (uint) m_ints[last]; + int bits = (last << 5) + 1; + + // A couple of binary search steps + if (highest > 0x0000ffff) + { + if (highest > 0x00ffffff) + { + bits += 24; + highest >>= 24; + } + else + { + bits += 16; + highest >>= 16; + } + } + else if (highest > 0x000000ff) + { + bits += 8; + highest >>= 8; + } + + while (highest > 1) + { + ++bits; + highest >>= 1; + } + + return bits; + } + } + + private int[] resizedInts(int newLen) + { + int[] newInts = new int[newLen]; + int oldLen = m_ints.Length; + int copyLen = oldLen < newLen ? oldLen : newLen; + Array.Copy(m_ints, 0, newInts, 0, copyLen); + return newInts; + } + + public BigInteger ToBigInteger() + { + int usedLen = GetUsedLength(); + if (usedLen == 0) + { + return BigInteger.Zero; + } + + int highestInt = m_ints[usedLen - 1]; + byte[] temp = new byte[4]; + int barrI = 0; + bool trailingZeroBytesDone = false; + for (int j = 3; j >= 0; j--) + { + byte thisByte = (byte)((int)((uint) highestInt >> (8 * j))); + if (trailingZeroBytesDone || (thisByte != 0)) + { + trailingZeroBytesDone = true; + temp[barrI++] = thisByte; + } + } + + int barrLen = 4 * (usedLen - 1) + barrI; + byte[] barr = new byte[barrLen]; + for (int j = 0; j < barrI; j++) + { + barr[j] = temp[j]; + } + // Highest value int is done now + + for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) + { + for (int j = 3; j >= 0; j--) + { + barr[barrI++] = (byte)((int)((uint)m_ints[iarrJ] >> (8 * j))); + } + } + return new BigInteger(1, barr); + } + + public void ShiftLeft() + { + int usedLen = GetUsedLength(); + if (usedLen == 0) + { + return; + } + if (m_ints[usedLen - 1] < 0) + { + // highest bit of highest used byte is set, so shifting left will + // make the IntArray one byte longer + usedLen++; + if (usedLen > m_ints.Length) + { + // make the m_ints one byte longer, because we need one more + // byte which is not available in m_ints + m_ints = resizedInts(m_ints.Length + 1); + } + } + + bool carry = false; + for (int i = 0; i < usedLen; i++) + { + // nextCarry is true if highest bit is set + bool nextCarry = m_ints[i] < 0; + m_ints[i] <<= 1; + if (carry) + { + // set lowest bit + m_ints[i] |= 1; + } + carry = nextCarry; + } + } + + public IntArray ShiftLeft(int n) + { + int usedLen = GetUsedLength(); + if (usedLen == 0) + { + return this; + } + + if (n == 0) + { + return this; + } + + if (n > 31) + { + throw new ArgumentException("shiftLeft() for max 31 bits " + + ", " + n + "bit shift is not possible", "n"); + } + + int[] newInts = new int[usedLen + 1]; + + int nm32 = 32 - n; + newInts[0] = m_ints[0] << n; + for (int i = 1; i < usedLen; i++) + { + newInts[i] = (m_ints[i] << n) | (int)((uint)m_ints[i - 1] >> nm32); + } + newInts[usedLen] = (int)((uint)m_ints[usedLen - 1] >> nm32); + + return new IntArray(newInts); + } + + public void AddShifted(IntArray other, int shift) + { + int usedLenOther = other.GetUsedLength(); + int newMinUsedLen = usedLenOther + shift; + if (newMinUsedLen > m_ints.Length) + { + m_ints = resizedInts(newMinUsedLen); + //Console.WriteLine("Resize required"); + } + + for (int i = 0; i < usedLenOther; i++) + { + m_ints[i + shift] ^= other.m_ints[i]; + } + } + + public int Length + { + get { return m_ints.Length; } + } + + public bool TestBit(int n) + { + // theInt = n / 32 + int theInt = n >> 5; + // theBit = n % 32 + int theBit = n & 0x1F; + int tester = 1 << theBit; + return ((m_ints[theInt] & tester) != 0); + } + + public void FlipBit(int n) + { + // theInt = n / 32 + int theInt = n >> 5; + // theBit = n % 32 + int theBit = n & 0x1F; + int flipper = 1 << theBit; + m_ints[theInt] ^= flipper; + } + + public void SetBit(int n) + { + // theInt = n / 32 + int theInt = n >> 5; + // theBit = n % 32 + int theBit = n & 0x1F; + int setter = 1 << theBit; + m_ints[theInt] |= setter; + } + + public IntArray Multiply(IntArray other, int m) + { + // Lenght of c is 2m bits rounded up to the next int (32 bit) + int t = (m + 31) >> 5; + if (m_ints.Length < t) + { + m_ints = resizedInts(t); + } + + IntArray b = new IntArray(other.resizedInts(other.Length + 1)); + IntArray c = new IntArray((m + m + 31) >> 5); + // IntArray c = new IntArray(t + t); + int testBit = 1; + for (int k = 0; k < 32; k++) + { + for (int j = 0; j < t; j++) + { + if ((m_ints[j] & testBit) != 0) + { + // The kth bit of m_ints[j] is set + c.AddShifted(b, j); + } + } + testBit <<= 1; + b.ShiftLeft(); + } + return c; + } + + // public IntArray multiplyLeftToRight(IntArray other, int m) { + // // Lenght of c is 2m bits rounded up to the next int (32 bit) + // int t = (m + 31) / 32; + // if (m_ints.Length < t) { + // m_ints = resizedInts(t); + // } + // + // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1)); + // IntArray c = new IntArray((m + m + 31) / 32); + // // IntArray c = new IntArray(t + t); + // int testBit = 1 << 31; + // for (int k = 31; k >= 0; k--) { + // for (int j = 0; j < t; j++) { + // if ((m_ints[j] & testBit) != 0) { + // // The kth bit of m_ints[j] is set + // c.addShifted(b, j); + // } + // } + // testBit >>>= 1; + // if (k > 0) { + // c.shiftLeft(); + // } + // } + // return c; + // } + + // TODO note, redPol.Length must be 3 for TPB and 5 for PPB + public void Reduce(int m, int[] redPol) + { + for (int i = m + m - 2; i >= m; i--) + { + if (TestBit(i)) + { + int bit = i - m; + FlipBit(bit); + FlipBit(i); + int l = redPol.Length; + while (--l >= 0) + { + FlipBit(redPol[l] + bit); + } + } + } + m_ints = resizedInts((m + 31) >> 5); + } + + public IntArray Square(int m) + { + // TODO make the table static readonly + int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40, + 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 }; + + int t = (m + 31) >> 5; + if (m_ints.Length < t) + { + m_ints = resizedInts(t); + } + + IntArray c = new IntArray(t + t); + + // TODO twice the same code, put in separate private method + for (int i = 0; i < t; i++) + { + int v0 = 0; + for (int j = 0; j < 4; j++) + { + v0 = (int)((uint) v0 >> 8); + int u = (int)((uint)m_ints[i] >> (j * 4)) & 0xF; + int w = table[u] << 24; + v0 |= w; + } + c.m_ints[i + i] = v0; + + v0 = 0; + int upper = (int)((uint) m_ints[i] >> 16); + for (int j = 0; j < 4; j++) + { + v0 = (int)((uint) v0 >> 8); + int u = (int)((uint)upper >> (j * 4)) & 0xF; + int w = table[u] << 24; + v0 |= w; + } + c.m_ints[i + i + 1] = v0; + } + return c; + } + + public override bool Equals(object o) + { + if (!(o is IntArray)) + { + return false; + } + IntArray other = (IntArray) o; + int usedLen = GetUsedLength(); + if (other.GetUsedLength() != usedLen) + { + return false; + } + for (int i = 0; i < usedLen; i++) + { + if (m_ints[i] != other.m_ints[i]) + { + return false; + } + } + return true; + } + + public override int GetHashCode() + { + int i = GetUsedLength(); + int hc = i; + while (--i >= 0) + { + hc *= 17; + hc ^= m_ints[i]; + } + return hc; + } + + public object Clone() + { + return new IntArray((int[]) m_ints.Clone()); + } + + public override string ToString() + { + int usedLen = GetUsedLength(); + if (usedLen == 0) + { + return "0"; + } + + StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[usedLen - 1], 2)); + for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) + { + string hexString = Convert.ToString(m_ints[iarrJ], 2); + + // Add leading zeroes, except for highest significant int + for (int i = hexString.Length; i < 8; i++) + { + hexString = "0" + hexString; + } + sb.Append(hexString); + } + return sb.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/math/ec/abc/SimpleBigDecimal.cs b/iTechSharp/srcbc/math/ec/abc/SimpleBigDecimal.cs new file mode 100644 index 0000000..d5664db --- /dev/null +++ b/iTechSharp/srcbc/math/ec/abc/SimpleBigDecimal.cs @@ -0,0 +1,241 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Math.EC.Abc +{ + /** + * Class representing a simple version of a big decimal. A + * SimpleBigDecimal is basically a + * {@link java.math.BigInteger BigInteger} with a few digits on the right of + * the decimal point. The number of (binary) digits on the right of the decimal + * point is called the scale of the SimpleBigDecimal. + * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted + * automatically, but must be set manually. All SimpleBigDecimals + * taking part in the same arithmetic operation must have equal scale. The + * result of a multiplication of two SimpleBigDecimals returns a + * SimpleBigDecimal with double scale. + */ + internal class SimpleBigDecimal + // : Number + { + // private static final long serialVersionUID = 1L; + + private readonly BigInteger bigInt; + private readonly int scale; + + /** + * Returns a SimpleBigDecimal representing the same numerical + * value as value. + * @param value The value of the SimpleBigDecimal to be + * created. + * @param scale The scale of the SimpleBigDecimal to be + * created. + * @return The such created SimpleBigDecimal. + */ + public static SimpleBigDecimal GetInstance(BigInteger val, int scale) + { + return new SimpleBigDecimal(val.ShiftLeft(scale), scale); + } + + /** + * Constructor for SimpleBigDecimal. The value of the + * constructed SimpleBigDecimal Equals bigInt / + * 2scale. + * @param bigInt The bigInt value parameter. + * @param scale The scale of the constructed SimpleBigDecimal. + */ + public SimpleBigDecimal(BigInteger bigInt, int scale) + { + if (scale < 0) + throw new ArgumentException("scale may not be negative"); + + this.bigInt = bigInt; + this.scale = scale; + } + + private SimpleBigDecimal(SimpleBigDecimal limBigDec) + { + bigInt = limBigDec.bigInt; + scale = limBigDec.scale; + } + + private void CheckScale(SimpleBigDecimal b) + { + if (scale != b.scale) + throw new ArgumentException("Only SimpleBigDecimal of same scale allowed in arithmetic operations"); + } + + public SimpleBigDecimal AdjustScale(int newScale) + { + if (newScale < 0) + throw new ArgumentException("scale may not be negative"); + + if (newScale == scale) + return this; + + return new SimpleBigDecimal(bigInt.ShiftLeft(newScale - scale), newScale); + } + + public SimpleBigDecimal Add(SimpleBigDecimal b) + { + CheckScale(b); + return new SimpleBigDecimal(bigInt.Add(b.bigInt), scale); + } + + public SimpleBigDecimal Add(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Add(b.ShiftLeft(scale)), scale); + } + + public SimpleBigDecimal Negate() + { + return new SimpleBigDecimal(bigInt.Negate(), scale); + } + + public SimpleBigDecimal Subtract(SimpleBigDecimal b) + { + return Add(b.Negate()); + } + + public SimpleBigDecimal Subtract(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Subtract(b.ShiftLeft(scale)), scale); + } + + public SimpleBigDecimal Multiply(SimpleBigDecimal b) + { + CheckScale(b); + return new SimpleBigDecimal(bigInt.Multiply(b.bigInt), scale + scale); + } + + public SimpleBigDecimal Multiply(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Multiply(b), scale); + } + + public SimpleBigDecimal Divide(SimpleBigDecimal b) + { + CheckScale(b); + BigInteger dividend = bigInt.ShiftLeft(scale); + return new SimpleBigDecimal(dividend.Divide(b.bigInt), scale); + } + + public SimpleBigDecimal Divide(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Divide(b), scale); + } + + public SimpleBigDecimal ShiftLeft(int n) + { + return new SimpleBigDecimal(bigInt.ShiftLeft(n), scale); + } + + public int CompareTo(SimpleBigDecimal val) + { + CheckScale(val); + return bigInt.CompareTo(val.bigInt); + } + + public int CompareTo(BigInteger val) + { + return bigInt.CompareTo(val.ShiftLeft(scale)); + } + + public BigInteger Floor() + { + return bigInt.ShiftRight(scale); + } + + public BigInteger Round() + { + SimpleBigDecimal oneHalf = new SimpleBigDecimal(BigInteger.One, 1); + return Add(oneHalf.AdjustScale(scale)).Floor(); + } + + public int IntValue + { + get { return Floor().IntValue; } + } + + public long LongValue + { + get { return Floor().LongValue; } + } + +// public double doubleValue() +// { +// return new Double(ToString()).doubleValue(); +// } +// +// public float floatValue() +// { +// return new Float(ToString()).floatValue(); +// } + + public int Scale + { + get { return scale; } + } + + public override string ToString() + { + if (scale == 0) + return bigInt.ToString(); + + BigInteger floorBigInt = Floor(); + + BigInteger fract = bigInt.Subtract(floorBigInt.ShiftLeft(scale)); + if (bigInt.SignValue < 0) + { + fract = BigInteger.One.ShiftLeft(scale).Subtract(fract); + } + + if ((floorBigInt.SignValue == -1) && (!(fract.Equals(BigInteger.Zero)))) + { + floorBigInt = floorBigInt.Add(BigInteger.One); + } + string leftOfPoint = floorBigInt.ToString(); + + char[] fractCharArr = new char[scale]; + string fractStr = fract.ToString(2); + int fractLen = fractStr.Length; + int zeroes = scale - fractLen; + for (int i = 0; i < zeroes; i++) + { + fractCharArr[i] = '0'; + } + for (int j = 0; j < fractLen; j++) + { + fractCharArr[zeroes + j] = fractStr[j]; + } + string rightOfPoint = new string(fractCharArr); + + StringBuilder sb = new StringBuilder(leftOfPoint); + sb.Append("."); + sb.Append(rightOfPoint); + + return sb.ToString(); + } + + public override bool Equals( + object obj) + { + if (this == obj) + return true; + + SimpleBigDecimal other = obj as SimpleBigDecimal; + + if (other == null) + return false; + + return bigInt.Equals(other.bigInt) + && scale == other.scale; + } + + public override int GetHashCode() + { + return bigInt.GetHashCode() ^ scale; + } + + } +} diff --git a/iTechSharp/srcbc/math/ec/abc/Tnaf.cs b/iTechSharp/srcbc/math/ec/abc/Tnaf.cs new file mode 100644 index 0000000..225fc30 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/abc/Tnaf.cs @@ -0,0 +1,834 @@ +using System; + +namespace Org.BouncyCastle.Math.EC.Abc +{ + /** + * Class holding methods for point multiplication based on the window + * τ-adic nonadjacent form (WTNAF). The algorithms are based on the + * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves" + * by Jerome A. Solinas. The paper first appeared in the Proceedings of + * Crypto 1997. + */ + internal class Tnaf + { + private static readonly BigInteger MinusOne = BigInteger.One.Negate(); + private static readonly BigInteger MinusTwo = BigInteger.Two.Negate(); + private static readonly BigInteger MinusThree = BigInteger.Three.Negate(); + private static readonly BigInteger Four = BigInteger.ValueOf(4); + + /** + * The window width of WTNAF. The standard value of 4 is slightly less + * than optimal for running time, but keeps space requirements for + * precomputation low. For typical curves, a value of 5 or 6 results in + * a better running time. When changing this value, the + * αu's must be computed differently, see + * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson, + * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004, + * p. 121-122 + */ + public const sbyte Width = 4; + + /** + * 24 + */ + public const sbyte Pow2Width = 16; + + /** + * The αu's for a=0 as an array + * of ZTauElements. + */ + public static readonly ZTauElement[] Alpha0 = + { + null, + new ZTauElement(BigInteger.One, BigInteger.Zero), null, + new ZTauElement(MinusThree, MinusOne), null, + new ZTauElement(MinusOne, MinusOne), null, + new ZTauElement(BigInteger.One, MinusOne), null + }; + + /** + * The αu's for a=0 as an array + * of TNAFs. + */ + public static readonly sbyte[][] Alpha0Tnaf = + { + null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1} + }; + + /** + * The αu's for a=1 as an array + * of ZTauElements. + */ + public static readonly ZTauElement[] Alpha1 = + { + null, + new ZTauElement(BigInteger.One, BigInteger.Zero), null, + new ZTauElement(MinusThree, BigInteger.One), null, + new ZTauElement(MinusOne, BigInteger.One), null, + new ZTauElement(BigInteger.One, BigInteger.One), null + }; + + /** + * The αu's for a=1 as an array + * of TNAFs. + */ + public static readonly sbyte[][] Alpha1Tnaf = + { + null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1} + }; + + /** + * Computes the norm of an element λ of + * Z[τ]. + * @param mu The parameter μ of the elliptic curve. + * @param lambda The element λ of + * Z[τ]. + * @return The norm of λ. + */ + public static BigInteger Norm(sbyte mu, ZTauElement lambda) + { + BigInteger norm; + + // s1 = u^2 + BigInteger s1 = lambda.u.Multiply(lambda.u); + + // s2 = u * v + BigInteger s2 = lambda.u.Multiply(lambda.v); + + // s3 = 2 * v^2 + BigInteger s3 = lambda.v.Multiply(lambda.v).ShiftLeft(1); + + if (mu == 1) + { + norm = s1.Add(s2).Add(s3); + } + else if (mu == -1) + { + norm = s1.Subtract(s2).Add(s3); + } + else + { + throw new ArgumentException("mu must be 1 or -1"); + } + + return norm; + } + + /** + * Computes the norm of an element λ of + * R[τ], where λ = u + vτ + * and u and u are real numbers (elements of + * R). + * @param mu The parameter μ of the elliptic curve. + * @param u The real part of the element λ of + * R[τ]. + * @param v The τ-adic part of the element + * λ of R[τ]. + * @return The norm of λ. + */ + public static SimpleBigDecimal Norm(sbyte mu, SimpleBigDecimal u, SimpleBigDecimal v) + { + SimpleBigDecimal norm; + + // s1 = u^2 + SimpleBigDecimal s1 = u.Multiply(u); + + // s2 = u * v + SimpleBigDecimal s2 = u.Multiply(v); + + // s3 = 2 * v^2 + SimpleBigDecimal s3 = v.Multiply(v).ShiftLeft(1); + + if (mu == 1) + { + norm = s1.Add(s2).Add(s3); + } + else if (mu == -1) + { + norm = s1.Subtract(s2).Add(s3); + } + else + { + throw new ArgumentException("mu must be 1 or -1"); + } + + return norm; + } + + /** + * Rounds an element λ of R[τ] + * to an element of Z[τ], such that their difference + * has minimal norm. λ is given as + * λ = λ0 + λ1τ. + * @param lambda0 The component λ0. + * @param lambda1 The component λ1. + * @param mu The parameter μ of the elliptic curve. Must + * equal 1 or -1. + * @return The rounded element of Z[τ]. + * @throws ArgumentException if lambda0 and + * lambda1 do not have same scale. + */ + public static ZTauElement Round(SimpleBigDecimal lambda0, + SimpleBigDecimal lambda1, sbyte mu) + { + int scale = lambda0.Scale; + if (lambda1.Scale != scale) + throw new ArgumentException("lambda0 and lambda1 do not have same scale"); + + if (!((mu == 1) || (mu == -1))) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger f0 = lambda0.Round(); + BigInteger f1 = lambda1.Round(); + + SimpleBigDecimal eta0 = lambda0.Subtract(f0); + SimpleBigDecimal eta1 = lambda1.Subtract(f1); + + // eta = 2*eta0 + mu*eta1 + SimpleBigDecimal eta = eta0.Add(eta0); + if (mu == 1) + { + eta = eta.Add(eta1); + } + else + { + // mu == -1 + eta = eta.Subtract(eta1); + } + + // check1 = eta0 - 3*mu*eta1 + // check2 = eta0 + 4*mu*eta1 + SimpleBigDecimal threeEta1 = eta1.Add(eta1).Add(eta1); + SimpleBigDecimal fourEta1 = threeEta1.Add(eta1); + SimpleBigDecimal check1; + SimpleBigDecimal check2; + if (mu == 1) + { + check1 = eta0.Subtract(threeEta1); + check2 = eta0.Add(fourEta1); + } + else + { + // mu == -1 + check1 = eta0.Add(threeEta1); + check2 = eta0.Subtract(fourEta1); + } + + sbyte h0 = 0; + sbyte h1 = 0; + + // if eta >= 1 + if (eta.CompareTo(BigInteger.One) >= 0) + { + if (check1.CompareTo(MinusOne) < 0) + { + h1 = mu; + } + else + { + h0 = 1; + } + } + else + { + // eta < 1 + if (check2.CompareTo(BigInteger.Two) >= 0) + { + h1 = mu; + } + } + + // if eta < -1 + if (eta.CompareTo(MinusOne) < 0) + { + if (check1.CompareTo(BigInteger.One) >= 0) + { + h1 = (sbyte)-mu; + } + else + { + h0 = -1; + } + } + else + { + // eta >= -1 + if (check2.CompareTo(MinusTwo) < 0) + { + h1 = (sbyte)-mu; + } + } + + BigInteger q0 = f0.Add(BigInteger.ValueOf(h0)); + BigInteger q1 = f1.Add(BigInteger.ValueOf(h1)); + return new ZTauElement(q0, q1); + } + + /** + * Approximate division by n. For an integer + * k, the value λ = s k / n is + * computed to c bits of accuracy. + * @param k The parameter k. + * @param s The curve parameter s0 or + * s1. + * @param vm The Lucas Sequence element Vm. + * @param a The parameter a of the elliptic curve. + * @param m The bit length of the finite field + * Fm. + * @param c The number of bits of accuracy, i.e. the scale of the returned + * SimpleBigDecimal. + * @return The value λ = s k / n computed to + * c bits of accuracy. + */ + public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k, + BigInteger s, BigInteger vm, sbyte a, int m, int c) + { + int _k = (m + 5)/2 + c; + BigInteger ns = k.ShiftRight(m - _k - 2 + a); + + BigInteger gs = s.Multiply(ns); + + BigInteger hs = gs.ShiftRight(m); + + BigInteger js = vm.Multiply(hs); + + BigInteger gsPlusJs = gs.Add(js); + BigInteger ls = gsPlusJs.ShiftRight(_k-c); + if (gsPlusJs.TestBit(_k-c-1)) + { + // round up + ls = ls.Add(BigInteger.One); + } + + return new SimpleBigDecimal(ls, c); + } + + /** + * Computes the τ-adic NAF (non-adjacent form) of an + * element λ of Z[τ]. + * @param mu The parameter μ of the elliptic curve. + * @param lambda The element λ of + * Z[τ]. + * @return The τ-adic NAF of λ. + */ + public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda) + { + if (!((mu == 1) || (mu == -1))) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger norm = Norm(mu, lambda); + + // Ceiling of log2 of the norm + int log2Norm = norm.BitLength; + + // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52 + int maxLength = log2Norm > 30 ? log2Norm + 4 : 34; + + // The array holding the TNAF + sbyte[] u = new sbyte[maxLength]; + int i = 0; + + // The actual length of the TNAF + int length = 0; + + BigInteger r0 = lambda.u; + BigInteger r1 = lambda.v; + + while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero)))) + { + // If r0 is odd + if (r0.TestBit(0)) + { + u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue; + + // r0 = r0 - u[i] + if (u[i] == 1) + { + r0 = r0.ClearBit(0); + } + else + { + // u[i] == -1 + r0 = r0.Add(BigInteger.One); + } + length = i; + } + else + { + u[i] = 0; + } + + BigInteger t = r0; + BigInteger s = r0.ShiftRight(1); + if (mu == 1) + { + r0 = r1.Add(s); + } + else + { + // mu == -1 + r0 = r1.Subtract(s); + } + + r1 = t.ShiftRight(1).Negate(); + i++; + } + + length++; + + // Reduce the TNAF array to its actual length + sbyte[] tnaf = new sbyte[length]; + Array.Copy(u, 0, tnaf, 0, length); + return tnaf; + } + + /** + * Applies the operation τ() to an + * F2mPoint. + * @param p The F2mPoint to which τ() is applied. + * @return τ(p) + */ + public static F2mPoint Tau(F2mPoint p) + { + if (p.IsInfinity) + return p; + + ECFieldElement x = p.X; + ECFieldElement y = p.Y; + + return new F2mPoint(p.Curve, x.Square(), y.Square(), p.IsCompressed); + } + + /** + * Returns the parameter μ of the elliptic curve. + * @param curve The elliptic curve from which to obtain μ. + * The curve must be a Koblitz curve, i.e. a Equals + * 0 or 1 and b Equals + * 1. + * @return μ of the elliptic curve. + * @throws ArgumentException if the given ECCurve is not a Koblitz + * curve. + */ + public static sbyte GetMu(F2mCurve curve) + { + BigInteger a = curve.A.ToBigInteger(); + + sbyte mu; + if (a.SignValue == 0) + { + mu = -1; + } + else if (a.Equals(BigInteger.One)) + { + mu = 1; + } + else + { + throw new ArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible"); + } + return mu; + } + + /** + * Calculates the Lucas Sequence elements Uk-1 and + * Uk or Vk-1 and + * Vk. + * @param mu The parameter μ of the elliptic curve. + * @param k The index of the second element of the Lucas Sequence to be + * returned. + * @param doV If set to true, computes Vk-1 and + * Vk, otherwise Uk-1 and + * Uk. + * @return An array with 2 elements, containing Uk-1 + * and Uk or Vk-1 + * and Vk. + */ + public static BigInteger[] GetLucas(sbyte mu, int k, bool doV) + { + if (!(mu == 1 || mu == -1)) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger u0; + BigInteger u1; + BigInteger u2; + + if (doV) + { + u0 = BigInteger.Two; + u1 = BigInteger.ValueOf(mu); + } + else + { + u0 = BigInteger.Zero; + u1 = BigInteger.One; + } + + for (int i = 1; i < k; i++) + { + // u2 = mu*u1 - 2*u0; + BigInteger s = null; + if (mu == 1) + { + s = u1; + } + else + { + // mu == -1 + s = u1.Negate(); + } + + u2 = s.Subtract(u0.ShiftLeft(1)); + u0 = u1; + u1 = u2; + // System.out.println(i + ": " + u2); + // System.out.println(); + } + + BigInteger[] retVal = {u0, u1}; + return retVal; + } + + /** + * Computes the auxiliary value tw. If the width is + * 4, then for mu = 1, tw = 6 and for + * mu = -1, tw = 10 + * @param mu The parameter μ of the elliptic curve. + * @param w The window width of the WTNAF. + * @return the auxiliary value tw + */ + public static BigInteger GetTw(sbyte mu, int w) + { + if (w == 4) + { + if (mu == 1) + { + return BigInteger.ValueOf(6); + } + else + { + // mu == -1 + return BigInteger.ValueOf(10); + } + } + else + { + // For w <> 4, the values must be computed + BigInteger[] us = GetLucas(mu, w, false); + BigInteger twoToW = BigInteger.Zero.SetBit(w); + BigInteger u1invert = us[1].ModInverse(twoToW); + BigInteger tw; + tw = BigInteger.Two.Multiply(us[0]).Multiply(u1invert).Mod(twoToW); + //System.out.println("mu = " + mu); + //System.out.println("tw = " + tw); + return tw; + } + } + + /** + * Computes the auxiliary values s0 and + * s1 used for partial modular reduction. + * @param curve The elliptic curve for which to compute + * s0 and s1. + * @throws ArgumentException if curve is not a + * Koblitz curve (Anomalous Binary Curve, ABC). + */ + public static BigInteger[] GetSi(F2mCurve curve) + { + if (!curve.IsKoblitz) + throw new ArgumentException("si is defined for Koblitz curves only"); + + int m = curve.M; + int a = curve.A.ToBigInteger().IntValue; + sbyte mu = curve.GetMu(); + int h = curve.H.IntValue; + int index = m + 3 - a; + BigInteger[] ui = GetLucas(mu, index, false); + + BigInteger dividend0; + BigInteger dividend1; + if (mu == 1) + { + dividend0 = BigInteger.One.Subtract(ui[1]); + dividend1 = BigInteger.One.Subtract(ui[0]); + } + else if (mu == -1) + { + dividend0 = BigInteger.One.Add(ui[1]); + dividend1 = BigInteger.One.Add(ui[0]); + } + else + { + throw new ArgumentException("mu must be 1 or -1"); + } + + BigInteger[] si = new BigInteger[2]; + + if (h == 2) + { + si[0] = dividend0.ShiftRight(1); + si[1] = dividend1.ShiftRight(1).Negate(); + } + else if (h == 4) + { + si[0] = dividend0.ShiftRight(2); + si[1] = dividend1.ShiftRight(2).Negate(); + } + else + { + throw new ArgumentException("h (Cofactor) must be 2 or 4"); + } + + return si; + } + + /** + * Partial modular reduction modulo + * m - 1)/(τ - 1). + * @param k The integer to be reduced. + * @param m The bitlength of the underlying finite field. + * @param a The parameter a of the elliptic curve. + * @param s The auxiliary values s0 and + * s1. + * @param mu The parameter μ of the elliptic curve. + * @param c The precision (number of bits of accuracy) of the partial + * modular reduction. + * @return ρ := k partmod (τm - 1)/(τ - 1) + */ + public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a, + BigInteger[] s, sbyte mu, sbyte c) + { + // d0 = s[0] + mu*s[1]; mu is either 1 or -1 + BigInteger d0; + if (mu == 1) + { + d0 = s[0].Add(s[1]); + } + else + { + d0 = s[0].Subtract(s[1]); + } + + BigInteger[] v = GetLucas(mu, m, true); + BigInteger vm = v[1]; + + SimpleBigDecimal lambda0 = ApproximateDivisionByN( + k, s[0], vm, a, m, c); + + SimpleBigDecimal lambda1 = ApproximateDivisionByN( + k, s[1], vm, a, m, c); + + ZTauElement q = Round(lambda0, lambda1, mu); + + // r0 = n - d0*q0 - 2*s1*q1 + BigInteger r0 = k.Subtract(d0.Multiply(q.u)).Subtract( + BigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v)); + + // r1 = s1*q0 - s0*q1 + BigInteger r1 = s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v)); + + return new ZTauElement(r0, r1); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint} + * by a BigInteger using the reduced τ-adic + * NAF (RTNAF) method. + * @param p The F2mPoint to Multiply. + * @param k The BigInteger by which to Multiply p. + * @return k * p + */ + public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k) + { + F2mCurve curve = (F2mCurve) p.Curve; + int m = curve.M; + sbyte a = (sbyte) curve.A.ToBigInteger().IntValue; + sbyte mu = curve.GetMu(); + BigInteger[] s = curve.GetSi(); + ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10); + + return MultiplyTnaf(p, rho); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint} + * by an element λ of Z[τ] + * using the τ-adic NAF (TNAF) method. + * @param p The F2mPoint to Multiply. + * @param lambda The element λ of + * Z[τ]. + * @return λ * p + */ + public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda) + { + F2mCurve curve = (F2mCurve)p.Curve; + sbyte mu = curve.GetMu(); + sbyte[] u = TauAdicNaf(mu, lambda); + + F2mPoint q = MultiplyFromTnaf(p, u); + + return q; + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint} + * by an element λ of Z[τ] + * using the τ-adic NAF (TNAF) method, given the TNAF + * of λ. + * @param p The F2mPoint to Multiply. + * @param u The the TNAF of λ.. + * @return λ * p + */ + public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u) + { + F2mCurve curve = (F2mCurve)p.Curve; + F2mPoint q = (F2mPoint) curve.Infinity; + for (int i = u.Length - 1; i >= 0; i--) + { + q = Tau(q); + if (u[i] == 1) + { + q = (F2mPoint)q.AddSimple(p); + } + else if (u[i] == -1) + { + q = (F2mPoint)q.SubtractSimple(p); + } + } + return q; + } + + /** + * Computes the [τ]-adic window NAF of an element + * λ of Z[τ]. + * @param mu The parameter μ of the elliptic curve. + * @param lambda The element λ of + * Z[τ] of which to compute the + * [τ]-adic NAF. + * @param width The window width of the resulting WNAF. + * @param pow2w 2width. + * @param tw The auxiliary value tw. + * @param alpha The αu's for the window width. + * @return The [τ]-adic window NAF of + * λ. + */ + public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda, + sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha) + { + if (!((mu == 1) || (mu == -1))) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger norm = Norm(mu, lambda); + + // Ceiling of log2 of the norm + int log2Norm = norm.BitLength; + + // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52 + int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width; + + // The array holding the TNAF + sbyte[] u = new sbyte[maxLength]; + + // 2^(width - 1) + BigInteger pow2wMin1 = pow2w.ShiftRight(1); + + // Split lambda into two BigIntegers to simplify calculations + BigInteger r0 = lambda.u; + BigInteger r1 = lambda.v; + int i = 0; + + // while lambda <> (0, 0) + while (!((r0.Equals(BigInteger.Zero))&&(r1.Equals(BigInteger.Zero)))) + { + // if r0 is odd + if (r0.TestBit(0)) + { + // uUnMod = r0 + r1*tw Mod 2^width + BigInteger uUnMod + = r0.Add(r1.Multiply(tw)).Mod(pow2w); + + sbyte uLocal; + // if uUnMod >= 2^(width - 1) + if (uUnMod.CompareTo(pow2wMin1) >= 0) + { + uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue; + } + else + { + uLocal = (sbyte) uUnMod.IntValue; + } + // uLocal is now in [-2^(width-1), 2^(width-1)-1] + + u[i] = uLocal; + bool s = true; + if (uLocal < 0) + { + s = false; + uLocal = (sbyte)-uLocal; + } + // uLocal is now >= 0 + + if (s) + { + r0 = r0.Subtract(alpha[uLocal].u); + r1 = r1.Subtract(alpha[uLocal].v); + } + else + { + r0 = r0.Add(alpha[uLocal].u); + r1 = r1.Add(alpha[uLocal].v); + } + } + else + { + u[i] = 0; + } + + BigInteger t = r0; + + if (mu == 1) + { + r0 = r1.Add(r0.ShiftRight(1)); + } + else + { + // mu == -1 + r0 = r1.Subtract(r0.ShiftRight(1)); + } + r1 = t.ShiftRight(1).Negate(); + i++; + } + return u; + } + + /** + * Does the precomputation for WTNAF multiplication. + * @param p The ECPoint for which to do the precomputation. + * @param a The parameter a of the elliptic curve. + * @return The precomputation array for p. + */ + public static F2mPoint[] GetPreComp(F2mPoint p, sbyte a) + { + F2mPoint[] pu; + pu = new F2mPoint[16]; + pu[1] = p; + sbyte[][] alphaTnaf; + if (a == 0) + { + alphaTnaf = Tnaf.Alpha0Tnaf; + } + else + { + // a == 1 + alphaTnaf = Tnaf.Alpha1Tnaf; + } + + int precompLen = alphaTnaf.Length; + for (int i = 3; i < precompLen; i = i + 2) + { + pu[i] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]); + } + + return pu; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/abc/ZTauElement.cs b/iTechSharp/srcbc/math/ec/abc/ZTauElement.cs new file mode 100644 index 0000000..4fcbf1b --- /dev/null +++ b/iTechSharp/srcbc/math/ec/abc/ZTauElement.cs @@ -0,0 +1,36 @@ +namespace Org.BouncyCastle.Math.EC.Abc +{ + /** + * Class representing an element of Z[τ]. Let + * λ be an element of Z[τ]. Then + * λ is given as λ = u + vτ. The + * components u and v may be used directly, there + * are no accessor methods. + * Immutable class. + */ + internal class ZTauElement + { + /** + * The "real" part of λ. + */ + public readonly BigInteger u; + + /** + * The "τ-adic" part of λ. + */ + public readonly BigInteger v; + + /** + * Constructor for an element λ of + * Z[τ]. + * @param u The "real" part of λ. + * @param v The "τ-adic" part of + * λ. + */ + public ZTauElement(BigInteger u, BigInteger v) + { + this.u = u; + this.v = v; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/ECMultiplier.cs b/iTechSharp/srcbc/math/ec/multiplier/ECMultiplier.cs new file mode 100644 index 0000000..c6d768e --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/ECMultiplier.cs @@ -0,0 +1,18 @@ +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Interface for classes encapsulating a point multiplication algorithm + * for ECPoints. + */ + internal interface ECMultiplier + { + /** + * Multiplies the ECPoint p by k, i.e. + * p is added k times to itself. + * @param p The ECPoint to be multiplied. + * @param k The factor by which p i multiplied. + * @return p multiplied by k. + */ + ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo); + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/FpNafMultiplier.cs b/iTechSharp/srcbc/math/ec/multiplier/FpNafMultiplier.cs new file mode 100644 index 0000000..f5a9850 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/FpNafMultiplier.cs @@ -0,0 +1,39 @@ +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm. + */ + internal class FpNafMultiplier + : ECMultiplier + { + /** + * D.3.2 pg 101 + * @see org.bouncycastle.math.ec.multiplier.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger) + */ + public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo) + { + // TODO Probably should try to add this + // BigInteger e = k.Mod(n); // n == order of p + BigInteger e = k; + BigInteger h = e.Multiply(BigInteger.Three); + + ECPoint neg = p.Negate(); + ECPoint R = p; + + for (int i = h.BitLength - 2; i > 0; --i) + { + R = R.Twice(); + + bool hBit = h.TestBit(i); + bool eBit = e.TestBit(i); + + if (hBit != eBit) + { + R = R.Add(hBit ? p : neg); + } + } + + return R; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/PreCompInfo.cs b/iTechSharp/srcbc/math/ec/multiplier/PreCompInfo.cs new file mode 100644 index 0000000..d379508 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/PreCompInfo.cs @@ -0,0 +1,11 @@ +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Interface for classes storing precomputation data for multiplication + * algorithms. Used as a Memento (see GOF patterns) for + * WNafMultiplier. + */ + internal interface PreCompInfo + { + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/ReferenceMultiplier.cs b/iTechSharp/srcbc/math/ec/multiplier/ReferenceMultiplier.cs new file mode 100644 index 0000000..cdccffc --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/ReferenceMultiplier.cs @@ -0,0 +1,30 @@ +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + internal class ReferenceMultiplier + : ECMultiplier + { + /** + * Simple shift-and-add multiplication. Serves as reference implementation + * to verify (possibly faster) implementations in + * {@link org.bouncycastle.math.ec.ECPoint ECPoint}. + * + * @param p The point to multiply. + * @param k The factor by which to multiply. + * @return The result of the point multiplication k * p. + */ + public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo) + { + ECPoint q = p.Curve.Infinity; + int t = k.BitLength; + for (int i = 0; i < t; i++) + { + if (k.TestBit(i)) + { + q = q.Add(p); + } + p = p.Twice(); + } + return q; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/WNafMultiplier.cs b/iTechSharp/srcbc/math/ec/multiplier/WNafMultiplier.cs new file mode 100644 index 0000000..b5cf34b --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/WNafMultiplier.cs @@ -0,0 +1,241 @@ +using System; + +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class implementing the WNAF (Window Non-Adjacent Form) multiplication + * algorithm. + */ + internal class WNafMultiplier + : ECMultiplier + { + /** + * Computes the Window NAF (non-adjacent Form) of an integer. + * @param width The width w of the Window NAF. The width is + * defined as the minimal number w, such that for any + * w consecutive digits in the resulting representation, at + * most one is non-zero. + * @param k The integer of which the Window NAF is computed. + * @return The Window NAF of the given width, such that the following holds: + * k = −i=0l-1 ki2i + * , where the ki denote the elements of the + * returned sbyte[]. + */ + public sbyte[] WindowNaf(sbyte width, BigInteger k) + { + // The window NAF is at most 1 element longer than the binary + // representation of the integer k. sbyte can be used instead of short or + // int unless the window width is larger than 8. For larger width use + // short or int. However, a width of more than 8 is not efficient for + // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than + // 1000 Bits are currently not used in practice. + sbyte[] wnaf = new sbyte[k.BitLength + 1]; + + // 2^width as short and BigInteger + short pow2wB = (short)(1 << width); + BigInteger pow2wBI = BigInteger.ValueOf(pow2wB); + + int i = 0; + + // The actual length of the WNAF + int length = 0; + + // while k >= 1 + while (k.SignValue > 0) + { + // if k is odd + if (k.TestBit(0)) + { + // k Mod 2^width + BigInteger remainder = k.Mod(pow2wBI); + + // if remainder > 2^(width - 1) - 1 + if (remainder.TestBit(width - 1)) + { + wnaf[i] = (sbyte)(remainder.IntValue - pow2wB); + } + else + { + wnaf[i] = (sbyte)remainder.IntValue; + } + // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1] + + k = k.Subtract(BigInteger.ValueOf(wnaf[i])); + length = i; + } + else + { + wnaf[i] = 0; + } + + // k = k/2 + k = k.ShiftRight(1); + i++; + } + + length++; + + // Reduce the WNAF array to its actual length + sbyte[] wnafShort = new sbyte[length]; + Array.Copy(wnaf, 0, wnafShort, 0, length); + return wnafShort; + } + + /** + * Multiplies this by an integer k using the + * Window NAF method. + * @param k The integer by which this is multiplied. + * @return A new ECPoint which equals this + * multiplied by k. + */ + public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo) + { + WNafPreCompInfo wnafPreCompInfo; + + if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo)) + { + wnafPreCompInfo = (WNafPreCompInfo)preCompInfo; + } + else + { + // Ignore empty PreCompInfo or PreCompInfo of incorrect type + wnafPreCompInfo = new WNafPreCompInfo(); + } + + // floor(log2(k)) + int m = k.BitLength; + + // width of the Window NAF + sbyte width; + + // Required length of precomputation array + int reqPreCompLen; + + // Determine optimal width and corresponding length of precomputation + // array based on literature values + if (m < 13) + { + width = 2; + reqPreCompLen = 1; + } + else + { + if (m < 41) + { + width = 3; + reqPreCompLen = 2; + } + else + { + if (m < 121) + { + width = 4; + reqPreCompLen = 4; + } + else + { + if (m < 337) + { + width = 5; + reqPreCompLen = 8; + } + else + { + if (m < 897) + { + width = 6; + reqPreCompLen = 16; + } + else + { + if (m < 2305) + { + width = 7; + reqPreCompLen = 32; + } + else + { + width = 8; + reqPreCompLen = 127; + } + } + } + } + } + } + + // The length of the precomputation array + int preCompLen = 1; + + ECPoint[] preComp = wnafPreCompInfo.GetPreComp(); + ECPoint twiceP = wnafPreCompInfo.GetTwiceP(); + + // Check if the precomputed ECPoints already exist + if (preComp == null) + { + // Precomputation must be performed from scratch, create an empty + // precomputation array of desired length + preComp = new ECPoint[]{ p }; + } + else + { + // Take the already precomputed ECPoints to start with + preCompLen = preComp.Length; + } + + if (twiceP == null) + { + // Compute twice(p) + twiceP = p.Twice(); + } + + if (preCompLen < reqPreCompLen) + { + // Precomputation array must be made bigger, copy existing preComp + // array into the larger new preComp array + ECPoint[] oldPreComp = preComp; + preComp = new ECPoint[reqPreCompLen]; + Array.Copy(oldPreComp, 0, preComp, 0, preCompLen); + + for (int i = preCompLen; i < reqPreCompLen; i++) + { + // Compute the new ECPoints for the precomputation array. + // The values 1, 3, 5, ..., 2^(width-1)-1 times p are + // computed + preComp[i] = twiceP.Add(preComp[i - 1]); + } + } + + // Compute the Window NAF of the desired width + sbyte[] wnaf = WindowNaf(width, k); + int l = wnaf.Length; + + // Apply the Window NAF to p using the precomputed ECPoint values. + ECPoint q = p.Curve.Infinity; + for (int i = l - 1; i >= 0; i--) + { + q = q.Twice(); + + if (wnaf[i] != 0) + { + if (wnaf[i] > 0) + { + q = q.Add(preComp[(wnaf[i] - 1)/2]); + } + else + { + // wnaf[i] < 0 + q = q.Subtract(preComp[(-wnaf[i] - 1)/2]); + } + } + } + + // Set PreCompInfo in ECPoint, such that it is available for next + // multiplication. + wnafPreCompInfo.SetPreComp(preComp); + wnafPreCompInfo.SetTwiceP(twiceP); + p.SetPreCompInfo(wnafPreCompInfo); + return q; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/WNafPreCompInfo.cs b/iTechSharp/srcbc/math/ec/multiplier/WNafPreCompInfo.cs new file mode 100644 index 0000000..d9305da --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/WNafPreCompInfo.cs @@ -0,0 +1,46 @@ +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class holding precomputation data for the WNAF (Window Non-Adjacent Form) + * algorithm. + */ + internal class WNafPreCompInfo + : PreCompInfo + { + /** + * Array holding the precomputed ECPoints used for the Window + * NAF multiplication in + * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply() + * WNafMultiplier.multiply()}. + */ + private ECPoint[] preComp = null; + + /** + * Holds an ECPoint representing twice(this). Used for the + * Window NAF multiplication in + * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply() + * WNafMultiplier.multiply()}. + */ + private ECPoint twiceP = null; + + internal ECPoint[] GetPreComp() + { + return preComp; + } + + internal void SetPreComp(ECPoint[] preComp) + { + this.preComp = preComp; + } + + internal ECPoint GetTwiceP() + { + return twiceP; + } + + internal void SetTwiceP(ECPoint twiceThis) + { + this.twiceP = twiceThis; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/WTauNafMultiplier.cs b/iTechSharp/srcbc/math/ec/multiplier/WTauNafMultiplier.cs new file mode 100644 index 0000000..f1a6057 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/WTauNafMultiplier.cs @@ -0,0 +1,120 @@ +using System; + +using Org.BouncyCastle.Math.EC.Abc; + +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class implementing the WTNAF (Window + * τ-adic Non-Adjacent Form) algorithm. + */ + internal class WTauNafMultiplier + : ECMultiplier + { + /** + * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint} + * by k using the reduced τ-adic NAF (RTNAF) + * method. + * @param p The F2mPoint to multiply. + * @param k The integer by which to multiply k. + * @return p multiplied by k. + */ + public ECPoint Multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo) + { + if (!(point is F2mPoint)) + throw new ArgumentException("Only F2mPoint can be used in WTauNafMultiplier"); + + F2mPoint p = (F2mPoint)point; + + F2mCurve curve = (F2mCurve) p.Curve; + int m = curve.M; + sbyte a = (sbyte) curve.A.ToBigInteger().IntValue; + sbyte mu = curve.GetMu(); + BigInteger[] s = curve.GetSi(); + + ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10); + + return MultiplyWTnaf(p, rho, preCompInfo, a, mu); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint} + * by an element λ of Z[τ] using + * the τ-adic NAF (TNAF) method. + * @param p The F2mPoint to multiply. + * @param lambda The element λ of + * Z[τ] of which to compute the + * [τ]-adic NAF. + * @return p multiplied by λ. + */ + private F2mPoint MultiplyWTnaf(F2mPoint p, ZTauElement lambda, + PreCompInfo preCompInfo, sbyte a, sbyte mu) + { + ZTauElement[] alpha; + if (a == 0) + { + alpha = Tnaf.Alpha0; + } + else + { + // a == 1 + alpha = Tnaf.Alpha1; + } + + BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width); + + sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width, + BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha); + + return MultiplyFromWTnaf(p, u, preCompInfo); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint} + * by an element λ of Z[τ] + * using the window τ-adic NAF (TNAF) method, given the + * WTNAF of λ. + * @param p The F2mPoint to multiply. + * @param u The the WTNAF of λ.. + * @return λ * p + */ + private static F2mPoint MultiplyFromWTnaf(F2mPoint p, sbyte[] u, + PreCompInfo preCompInfo) + { + F2mCurve curve = (F2mCurve)p.Curve; + sbyte a = (sbyte) curve.A.ToBigInteger().IntValue; + + F2mPoint[] pu; + if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo)) + { + pu = Tnaf.GetPreComp(p, a); + p.SetPreCompInfo(new WTauNafPreCompInfo(pu)); + } + else + { + pu = ((WTauNafPreCompInfo)preCompInfo).GetPreComp(); + } + + // q = infinity + F2mPoint q = (F2mPoint) p.Curve.Infinity; + for (int i = u.Length - 1; i >= 0; i--) + { + q = Tnaf.Tau(q); + if (u[i] != 0) + { + if (u[i] > 0) + { + q = q.AddSimple(pu[u[i]]); + } + else + { + // u[i] < 0 + q = q.SubtractSimple(pu[-u[i]]); + } + } + } + + return q; + } + } +} diff --git a/iTechSharp/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs b/iTechSharp/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs new file mode 100644 index 0000000..cede4a0 --- /dev/null +++ b/iTechSharp/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs @@ -0,0 +1,41 @@ +namespace Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class holding precomputation data for the WTNAF (Window + * τ-adic Non-Adjacent Form) algorithm. + */ + internal class WTauNafPreCompInfo + : PreCompInfo + { + /** + * Array holding the precomputed F2mPoints used for the + * WTNAF multiplication in + * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() + * WTauNafMultiplier.multiply()}. + */ + private readonly F2mPoint[] preComp; + + /** + * Constructor for WTauNafPreCompInfo + * @param preComp Array holding the precomputed F2mPoints + * used for the WTNAF multiplication in + * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() + * WTauNafMultiplier.multiply()}. + */ + internal WTauNafPreCompInfo(F2mPoint[] preComp) + { + this.preComp = preComp; + } + + /** + * @return the array holding the precomputed F2mPoints + * used for the WTNAF multiplication in + * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() + * WTauNafMultiplier.multiply()}. + */ + internal F2mPoint[] GetPreComp() + { + return preComp; + } + } +} diff --git a/iTechSharp/srcbc/ocsp/BasicOCSPResp.cs b/iTechSharp/srcbc/ocsp/BasicOCSPResp.cs new file mode 100644 index 0000000..ffe45e2 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/BasicOCSPResp.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Ocsp +{ + /// + /// + /// BasicOcspResponse ::= SEQUENCE { + /// tbsResponseData ResponseData, + /// signatureAlgorithm AlgorithmIdentifier, + /// signature BIT STRING, + /// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL + /// } + /// + /// + public class BasicOcspResp + : X509ExtensionBase + { + private readonly BasicOcspResponse resp; + private readonly ResponseData data; +// private readonly X509Certificate[] chain; + + public BasicOcspResp( + BasicOcspResponse resp) + { + this.resp = resp; + this.data = resp.TbsResponseData; + } + + /// The DER encoding of the tbsResponseData field. + /// In the event of an encoding error. + public byte[] GetTbsResponseData() + { + try + { + return data.GetDerEncoded(); + } + catch (IOException e) + { + throw new OcspException("problem encoding tbsResponseData", e); + } + } + + public int Version + { + get { return data.Version.Value.IntValue + 1; } + } + + public RespID ResponderId + { + get { return new RespID(data.ResponderID); } + } + + public DateTime ProducedAt + { + get { return data.ProducedAt.ToDateTime(); } + } + + public SingleResp[] Responses + { + get + { + Asn1Sequence s = data.Responses; + SingleResp[] rs = new SingleResp[s.Count]; + + for (int i = 0; i != rs.Length; i++) + { + rs[i] = new SingleResp(SingleResponse.GetInstance(s[i])); + } + + return rs; + } + } + + public X509Extensions ResponseExtensions + { + get { return data.ResponseExtensions; } + } + + protected override X509Extensions GetX509Extensions() + { + return ResponseExtensions; + } + + public string SignatureAlgName + { + get { return OcspUtilities.GetAlgorithmName(resp.SignatureAlgorithm.ObjectID); } + } + + public string SignatureAlgOid + { + get { return resp.SignatureAlgorithm.ObjectID.Id; } + } + + [Obsolete("RespData class is no longer required as all functionality is available on this class")] + public RespData GetResponseData() + { + return new RespData(data); + } + + public byte[] GetSignature() + { + return resp.Signature.GetBytes(); + } + + private ArrayList GetCertList() + { + // load the certificates and revocation lists if we have any + + ArrayList certs = new ArrayList(); + Asn1Sequence s = resp.Certs; + + if (s != null) + { + foreach (Asn1Encodable ae in s) + { + try + { + certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded())); + } + catch (IOException ex) + { + throw new OcspException("can't re-encode certificate!", ex); + } + catch (CertificateException ex) + { + throw new OcspException("can't re-encode certificate!", ex); + } + } + } + + return certs; + } + + public X509Certificate[] GetCerts() + { + ArrayList certs = GetCertList(); + + return (X509Certificate[]) certs.ToArray(typeof(X509Certificate)); + } + + /// The certificates, if any, associated with the response. + /// In the event of an encoding error. + public IX509Store GetCertificates( + string type) + { + try + { + return X509StoreFactory.Create( + "Certificate/" + type, + new X509CollectionStoreParameters(this.GetCertList())); + } + catch (Exception e) + { + throw new OcspException("can't setup the CertStore", e); + } + } + + /// + /// Verify the signature against the tbsResponseData object we contain. + /// + public bool Verify( + AsymmetricKeyParameter publicKey) + { + try + { + ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgName); + signature.Init(false, publicKey); + byte[] bs = data.GetDerEncoded(); + signature.BlockUpdate(bs, 0, bs.Length); + + return signature.VerifySignature(this.GetSignature()); + } + catch (Exception e) + { + throw new OcspException("exception processing sig: " + e, e); + } + } + + /// The ASN.1 encoded representation of this object. + public byte[] GetEncoded() + { + return resp.GetEncoded(); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + BasicOcspResp other = obj as BasicOcspResp; + + if (other == null) + return false; + + return resp.Equals(other.resp); + } + + public override int GetHashCode() + { + return resp.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/ocsp/BasicOCSPRespGenerator.cs b/iTechSharp/srcbc/ocsp/BasicOCSPRespGenerator.cs new file mode 100644 index 0000000..5200689 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/BasicOCSPRespGenerator.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + /** + * Generator for basic OCSP response objects. + */ + public class BasicOcspRespGenerator + { + private readonly IList list = new ArrayList(); + + private X509Extensions responseExtensions; + private RespID responderID; + + private class ResponseObject + { + internal CertificateID certId; + internal CertStatus certStatus; + internal DerGeneralizedTime thisUpdate; + internal DerGeneralizedTime nextUpdate; + internal X509Extensions extensions; + + public ResponseObject( + CertificateID certId, + CertificateStatus certStatus, + DateTime thisUpdate, + X509Extensions extensions) + : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), null, extensions) + { + } + + public ResponseObject( + CertificateID certId, + CertificateStatus certStatus, + DateTime thisUpdate, + DateTime nextUpdate, + X509Extensions extensions) + : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), new DerGeneralizedTime(nextUpdate), extensions) + { + } + + private ResponseObject( + CertificateID certId, + CertificateStatus certStatus, + DerGeneralizedTime thisUpdate, + DerGeneralizedTime nextUpdate, + X509Extensions extensions) + { + this.certId = certId; + + if (certStatus == null) + { + this.certStatus = new CertStatus(); + } + else if (certStatus is UnknownStatus) + { + this.certStatus = new CertStatus(2, DerNull.Instance); + } + else + { + RevokedStatus rs = (RevokedStatus) certStatus; + CrlReason revocationReason = rs.HasRevocationReason + ? new CrlReason(rs.RevocationReason) + : null; + + this.certStatus = new CertStatus( + new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason)); + } + + this.thisUpdate = thisUpdate; + this.nextUpdate = nextUpdate; + + this.extensions = extensions; + } + + public SingleResponse ToResponse() + { + return new SingleResponse(certId.ToAsn1Object(), certStatus, thisUpdate, nextUpdate, extensions); + } + } + + /** + * basic constructor + */ + public BasicOcspRespGenerator( + RespID responderID) + { + this.responderID = responderID; + } + + /** + * construct with the responderID to be the SHA-1 keyHash of the passed in public key. + */ + public BasicOcspRespGenerator( + AsymmetricKeyParameter publicKey) + { + this.responderID = new RespID(publicKey); + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param certStatus status of the certificate - null if okay + */ + public void AddResponse( + CertificateID certID, + CertificateStatus certStatus) + { + list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null)); + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public void AddResponse( + CertificateID certID, + CertificateStatus certStatus, + X509Extensions singleExtensions) + { + list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, singleExtensions)); + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public void AddResponse( + CertificateID certID, + CertificateStatus certStatus, + DateTime nextUpdate, + X509Extensions singleExtensions) + { + list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, nextUpdate, singleExtensions)); + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param thisUpdate date this response was valid on + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public void AddResponse( + CertificateID certID, + CertificateStatus certStatus, + DateTime thisUpdate, + DateTime nextUpdate, + X509Extensions singleExtensions) + { + list.Add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions)); + } + + /** + * Set the extensions for the response. + * + * @param responseExtensions the extension object to carry. + */ + public void SetResponseExtensions( + X509Extensions responseExtensions) + { + this.responseExtensions = responseExtensions; + } + + private BasicOcspResp GenerateResponse( + string signatureName, + AsymmetricKeyParameter privateKey, + X509Certificate[] chain, + DateTime producedAt, + SecureRandom random) + { + DerObjectIdentifier signingAlgorithm; + try + { + signingAlgorithm = OcspUtilities.GetAlgorithmOid(signatureName); + } + catch (Exception e) + { + throw new ArgumentException("unknown signing algorithm specified", e); + } + + Asn1EncodableVector responses = new Asn1EncodableVector(); + + foreach (ResponseObject respObj in list) + { + try + { + responses.Add(respObj.ToResponse()); + } + catch (Exception e) + { + throw new OcspException("exception creating Request", e); + } + } + + ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new DerGeneralizedTime(producedAt), new DerSequence(responses), responseExtensions); + + ISigner sig = null; + + try + { + sig = SignerUtilities.GetSigner(signatureName); + + if (random != null) + { + sig.Init(true, new ParametersWithRandom(privateKey, random)); + } + else + { + sig.Init(true, privateKey); + } + } + catch (Exception e) + { + throw new OcspException("exception creating signature: " + e, e); + } + + DerBitString bitSig = null; + + try + { + byte[] encoded = tbsResp.GetDerEncoded(); + sig.BlockUpdate(encoded, 0, encoded.Length); + + bitSig = new DerBitString(sig.GenerateSignature()); + } + catch (Exception e) + { + throw new OcspException("exception processing TBSRequest: " + e, e); + } + + AlgorithmIdentifier sigAlgId = OcspUtilities.GetSigAlgID(signingAlgorithm); + + if (chain != null && chain.Length > 0) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + try + { + for (int i = 0; i != chain.Length; i++) + { + v.Add( + X509CertificateStructure.GetInstance( + Asn1Object.FromByteArray(chain[i].GetEncoded()))); + } + } + catch (IOException e) + { + throw new OcspException("error processing certs", e); + } + catch (CertificateEncodingException e) + { + throw new OcspException("error encoding certs", e); + } + + return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, new DerSequence(v))); + } + else + { + return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, null)); + } + } + + public BasicOcspResp Generate( + string signingAlgorithm, + AsymmetricKeyParameter privateKey, + X509Certificate[] chain, + DateTime thisUpdate) + { + return Generate(signingAlgorithm, privateKey, chain, thisUpdate, null); + } + + public BasicOcspResp Generate( + string signingAlgorithm, + AsymmetricKeyParameter privateKey, + X509Certificate[] chain, + DateTime producedAt, + SecureRandom random) + { + if (signingAlgorithm == null) + { + throw new ArgumentException("no signing algorithm specified"); + } + + return GenerateResponse(signingAlgorithm, privateKey, chain, producedAt, random); + } + + /** + * Return an IEnumerable of the signature names supported by the generator. + * + * @return an IEnumerable containing recognised names. + */ + public IEnumerable SignatureAlgNames + { + get { return OcspUtilities.AlgNames; } + } + } +} diff --git a/iTechSharp/srcbc/ocsp/CertificateID.cs b/iTechSharp/srcbc/ocsp/CertificateID.cs new file mode 100644 index 0000000..df4a00a --- /dev/null +++ b/iTechSharp/srcbc/ocsp/CertificateID.cs @@ -0,0 +1,118 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + public class CertificateID + { + public const string HashSha1 = "1.3.14.3.2.26"; + + private readonly CertID id; + + public CertificateID( + CertID id) + { + this.id = id; + } + + /** + * create from an issuer certificate and the serial number of the + * certificate it signed. + * @exception OcspException if any problems occur creating the id fields. + */ + public CertificateID( + string hashAlgorithm, + X509Certificate issuerCert, + BigInteger number) + { + try + { + IDigest digest = DigestUtilities.GetDigest(hashAlgorithm); + AlgorithmIdentifier hashAlg = new AlgorithmIdentifier( + new DerObjectIdentifier(hashAlgorithm), DerNull.Instance); + + X509Name issuerName = PrincipalUtilities.GetSubjectX509Principal(issuerCert); + + byte[] encodedIssuerName = issuerName.GetEncoded(); + digest.BlockUpdate(encodedIssuerName, 0, encodedIssuerName.Length); + + byte[] hash = DigestUtilities.DoFinal(digest); + + Asn1OctetString issuerNameHash = new DerOctetString(hash); + AsymmetricKeyParameter issuerKey = issuerCert.GetPublicKey(); + + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKey); + + byte[] encodedPublicKey = info.PublicKeyData.GetBytes(); + digest.BlockUpdate(encodedPublicKey, 0, encodedPublicKey.Length); + + hash = DigestUtilities.DoFinal(digest); + + Asn1OctetString issuerKeyHash = new DerOctetString(hash); + + DerInteger serialNumber = new DerInteger(number); + + this.id = new CertID(hashAlg, issuerNameHash, issuerKeyHash, serialNumber); + } + catch (Exception e) + { + throw new OcspException("problem creating ID: " + e, e); + } + } + + public string HashAlgOid + { + get { return id.HashAlgorithm.ObjectID.Id; } + } + + public byte[] GetIssuerNameHash() + { + return id.IssuerNameHash.GetOctets(); + } + + public byte[] GetIssuerKeyHash() + { + return id.IssuerKeyHash.GetOctets(); + } + + /** + * return the serial number for the certificate associated + * with this request. + */ + public BigInteger SerialNumber + { + get { return id.SerialNumber.Value; } + } + + public CertID ToAsn1Object() + { + return id; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + CertificateID other = obj as CertificateID; + + if (other == null) + return false; + + return id.ToAsn1Object().Equals(other.id.ToAsn1Object()); + } + + public override int GetHashCode() + { + return id.ToAsn1Object().GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/ocsp/CertificateStatus.cs b/iTechSharp/srcbc/ocsp/CertificateStatus.cs new file mode 100644 index 0000000..edfcc25 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/CertificateStatus.cs @@ -0,0 +1,9 @@ +using System; + +namespace Org.BouncyCastle.Ocsp +{ + public abstract class CertificateStatus + { + public static readonly CertificateStatus Good = null; + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPException.cs b/iTechSharp/srcbc/ocsp/OCSPException.cs new file mode 100644 index 0000000..44eed9f --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Ocsp +{ + public class OcspException + : Exception + { + public OcspException() + { + } + + public OcspException( + string message) + : base(message) + { + } + + public OcspException( + string message, + Exception e) + : base(message, e) + { + } + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPReq.cs b/iTechSharp/srcbc/ocsp/OCSPReq.cs new file mode 100644 index 0000000..b69d442 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPReq.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Ocsp +{ + /** + *
      +	 * OcspRequest     ::=     SEQUENCE {
      +	 *       tbsRequest                  TBSRequest,
      +	 *       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
      +	 *
      +	 *   TBSRequest      ::=     SEQUENCE {
      +	 *       version             [0]     EXPLICIT Version DEFAULT v1,
      +	 *       requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
      +	 *       requestList                 SEQUENCE OF Request,
      +	 *       requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
      +	 *
      +	 *   Signature       ::=     SEQUENCE {
      +	 *       signatureAlgorithm      AlgorithmIdentifier,
      +	 *       signature               BIT STRING,
      +	 *       certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
      +	 *
      +	 *   Version         ::=             INTEGER  {  v1(0) }
      +	 *
      +	 *   Request         ::=     SEQUENCE {
      +	 *       reqCert                     CertID,
      +	 *       singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
      +	 *
      +	 *   CertID          ::=     SEQUENCE {
      +	 *       hashAlgorithm       AlgorithmIdentifier,
      +	 *       issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
      +	 *       issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
      +	 *       serialNumber        CertificateSerialNumber }
      +	 * 
      + */ + public class OcspReq + : X509ExtensionBase + { + private OcspRequest req; + + public OcspReq( + OcspRequest req) + { + this.req = req; + } + + public OcspReq( + byte[] req) + : this(new Asn1InputStream(req)) + { + } + + public OcspReq( + Stream inStr) + : this(new Asn1InputStream(inStr)) + { + } + + private OcspReq( + Asn1InputStream aIn) + { + try + { + this.req = OcspRequest.GetInstance(aIn.ReadObject()); + } + catch (ArgumentException e) + { + throw new IOException("malformed request: " + e.Message); + } + catch (InvalidCastException e) + { + throw new IOException("malformed request: " + e.Message); + } + } + + /** + * Return the DER encoding of the tbsRequest field. + * @return DER encoding of tbsRequest + * @throws OcspException in the event of an encoding error. + */ + public byte[] GetTbsRequest() + { + try + { + return req.TbsRequest.GetEncoded(); + } + catch (IOException e) + { + throw new OcspException("problem encoding tbsRequest", e); + } + } + + public int Version + { + get { return req.TbsRequest.Version.Value.IntValue + 1; } + } + + public GeneralName RequestorName + { + get { return GeneralName.GetInstance(req.TbsRequest.RequestorName); } + } + + public Req[] GetRequestList() + { + Asn1Sequence seq = req.TbsRequest.RequestList; + Req[] requests = new Req[seq.Count]; + + for (int i = 0; i != requests.Length; i++) + { + requests[i] = new Req(Request.GetInstance(seq[i])); + } + + return requests; + } + + public X509Extensions RequestExtensions + { + get { return X509Extensions.GetInstance(req.TbsRequest.RequestExtensions); } + } + + protected override X509Extensions GetX509Extensions() + { + return RequestExtensions; + } + + /** + * return the object identifier representing the signature algorithm + */ + public string SignatureAlgOid + { + get + { + if (!this.IsSigned) + return null; + + return req.OptionalSignature.SignatureAlgorithm.ObjectID.Id; + } + } + + public byte[] GetSignature() + { + if (!this.IsSigned) + return null; + + return req.OptionalSignature.SignatureValue.GetBytes(); + } + + private ArrayList GetCertList() + { + // load the certificates if we have any + + ArrayList certs = new ArrayList(); + Asn1Sequence s = req.OptionalSignature.Certs; + + if (s != null) + { + foreach (Asn1Encodable ae in s) + { + try + { + certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded())); + } + catch (Exception e) + { + throw new OcspException("can't re-encode certificate!", e); + } + } + } + + return certs; + } + + public X509Certificate[] GetCerts() + { + if (!this.IsSigned) + return null; + + ArrayList certs = this.GetCertList(); + + return (X509Certificate[]) certs.ToArray(typeof(X509Certificate)); + } + + /** + * If the request is signed return a possibly empty CertStore containing the certificates in the + * request. If the request is not signed the method returns null. + * + * @return null if not signed, a CertStore otherwise + * @throws OcspException + */ + public IX509Store GetCertificates( + string type) + { + if (!this.IsSigned) + return null; + + try + { + return X509StoreFactory.Create( + "Certificate/" + type, + new X509CollectionStoreParameters(this.GetCertList())); + } + catch (Exception e) + { + throw new OcspException("can't setup the CertStore", e); + } + } + + /** + * Return whether or not this request is signed. + * + * @return true if signed false otherwise. + */ + public bool IsSigned + { + get { return req.OptionalSignature != null; } + } + + /** + * Verify the signature against the TBSRequest object we contain. + */ + public bool Verify( + AsymmetricKeyParameter publicKey) + { + if (!this.IsSigned) + throw new OcspException("attempt to Verify signature on unsigned object"); + + try + { + ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgOid); + + signature.Init(false, publicKey); + + byte[] encoded = req.TbsRequest.GetEncoded(); + + signature.BlockUpdate(encoded, 0, encoded.Length); + + return signature.VerifySignature(this.GetSignature()); + } + catch (Exception e) + { + throw new OcspException("exception processing sig: " + e, e); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return req.GetEncoded(); + } + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPReqGenerator.cs b/iTechSharp/srcbc/ocsp/OCSPReqGenerator.cs new file mode 100644 index 0000000..5f3c0d5 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPReqGenerator.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + public class OcspReqGenerator + { + private IList list = new ArrayList(); + private GeneralName requestorName = null; + private X509Extensions requestExtensions = null; + + private class RequestObject + { + internal CertificateID certId; + internal X509Extensions extensions; + + public RequestObject( + CertificateID certId, + X509Extensions extensions) + { + this.certId = certId; + this.extensions = extensions; + } + + public Request ToRequest() + { + return new Request(certId.ToAsn1Object(), extensions); + } + } + + /** + * Add a request for the given CertificateID. + * + * @param certId certificate ID of interest + */ + public void AddRequest( + CertificateID certId) + { + list.Add(new RequestObject(certId, null)); + } + + /** + * Add a request with extensions + * + * @param certId certificate ID of interest + * @param singleRequestExtensions the extensions to attach to the request + */ + public void AddRequest( + CertificateID certId, + X509Extensions singleRequestExtensions) + { + list.Add(new RequestObject(certId, singleRequestExtensions)); + } + + /** + * Set the requestor name to the passed in X509Principal + * + * @param requestorName a X509Principal representing the requestor name. + */ + public void SetRequestorName( + X509Name requestorName) + { + try + { + this.requestorName = new GeneralName(GeneralName.DirectoryName, requestorName); + } + catch (Exception e) + { + throw new ArgumentException("cannot encode principal", e); + } + } + + public void SetRequestorName( + GeneralName requestorName) + { + this.requestorName = requestorName; + } + + public void SetRequestExtensions( + X509Extensions requestExtensions) + { + this.requestExtensions = requestExtensions; + } + + private OcspReq GenerateRequest( + DerObjectIdentifier signingAlgorithm, + AsymmetricKeyParameter privateKey, + X509Certificate[] chain, + SecureRandom random) + { + Asn1EncodableVector requests = new Asn1EncodableVector(); + + foreach (RequestObject reqObj in list) + { + try + { + requests.Add(reqObj.ToRequest()); + } + catch (Exception e) + { + throw new OcspException("exception creating Request", e); + } + } + + TbsRequest tbsReq = new TbsRequest(requestorName, new DerSequence(requests), requestExtensions); + + ISigner sig = null; + Signature signature = null; + + if (signingAlgorithm != null) + { + if (requestorName == null) + { + throw new OcspException("requestorName must be specified if request is signed."); + } + + try + { + sig = SignerUtilities.GetSigner(signingAlgorithm.Id); + if (random != null) + { + sig.Init(true, new ParametersWithRandom(privateKey, random)); + } + else + { + sig.Init(true, privateKey); + } + } + catch (Exception e) + { + throw new OcspException("exception creating signature: " + e, e); + } + + DerBitString bitSig = null; + + try + { + byte[] encoded = tbsReq.GetEncoded(); + sig.BlockUpdate(encoded, 0, encoded.Length); + + bitSig = new DerBitString(sig.GenerateSignature()); + } + catch (Exception e) + { + throw new OcspException("exception processing TBSRequest: " + e, e); + } + + AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DerNull.Instance); + + if (chain != null && chain.Length > 0) + { + Asn1EncodableVector v = new Asn1EncodableVector(); + try + { + for (int i = 0; i != chain.Length; i++) + { + v.Add( + X509CertificateStructure.GetInstance( + Asn1Object.FromByteArray(chain[i].GetEncoded()))); + } + } + catch (IOException e) + { + throw new OcspException("error processing certs", e); + } + catch (CertificateEncodingException e) + { + throw new OcspException("error encoding certs", e); + } + + signature = new Signature(sigAlgId, bitSig, new DerSequence(v)); + } + else + { + signature = new Signature(sigAlgId, bitSig); + } + } + + return new OcspReq(new OcspRequest(tbsReq, signature)); + } + + /** + * Generate an unsigned request + * + * @return the OcspReq + * @throws OcspException + */ + public OcspReq Generate() + { + return GenerateRequest(null, null, null, null); + } + + public OcspReq Generate( + string signingAlgorithm, + AsymmetricKeyParameter privateKey, + X509Certificate[] chain) + { + return Generate(signingAlgorithm, privateKey, chain, null); + } + + public OcspReq Generate( + string signingAlgorithm, + AsymmetricKeyParameter privateKey, + X509Certificate[] chain, + SecureRandom random) + { + if (signingAlgorithm == null) + throw new ArgumentException("no signing algorithm specified"); + + try + { + DerObjectIdentifier oid = OcspUtilities.GetAlgorithmOid(signingAlgorithm); + + return GenerateRequest(oid, privateKey, chain, random); + } + catch (ArgumentException) + { + throw new ArgumentException("unknown signing algorithm specified: " + signingAlgorithm); + } + } + + /** + * Return an IEnumerable of the signature names supported by the generator. + * + * @return an IEnumerable containing recognised names. + */ + public IEnumerable SignatureAlgNames + { + get { return OcspUtilities.AlgNames; } + } + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPResp.cs b/iTechSharp/srcbc/ocsp/OCSPResp.cs new file mode 100644 index 0000000..dc99c6a --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPResp.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; + +namespace Org.BouncyCastle.Ocsp +{ + public class OcspResp + { + private OcspResponse resp; + + public OcspResp( + OcspResponse resp) + { + this.resp = resp; + } + + public OcspResp( + byte[] resp) + : this(new Asn1InputStream(resp)) + { + } + + public OcspResp( + Stream inStr) + : this(new Asn1InputStream(inStr)) + { + } + + private OcspResp( + Asn1InputStream aIn) + { + try + { + this.resp = OcspResponse.GetInstance(aIn.ReadObject()); + } + catch (Exception e) + { + throw new IOException("malformed response: " + e.Message, e); + } + } + + public int Status + { + get { return this.resp.ResponseStatus.Value.IntValue; } + } + + public object GetResponseObject() + { + ResponseBytes rb = this.resp.ResponseBytes; + + if (rb == null) + return null; + + if (rb.ResponseType.Equals(OcspObjectIdentifiers.PkixOcspBasic)) + { + try + { + return new BasicOcspResp( + BasicOcspResponse.GetInstance( + Asn1Object.FromByteArray(rb.Response.GetOctets()))); + } + catch (Exception e) + { + throw new OcspException("problem decoding object: " + e, e); + } + } + + return rb.Response; + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return resp.GetEncoded(); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + OcspResp other = obj as OcspResp; + + if (other == null) + return false; + + return resp.Equals(other.resp); + } + + public override int GetHashCode() + { + return resp.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPRespGenerator.cs b/iTechSharp/srcbc/ocsp/OCSPRespGenerator.cs new file mode 100644 index 0000000..e0eb9ae --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPRespGenerator.cs @@ -0,0 +1,54 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; + +namespace Org.BouncyCastle.Ocsp +{ + /** + * base generator for an OCSP response - at the moment this only supports the + * generation of responses containing BasicOCSP responses. + */ + public class OCSPRespGenerator + { + public const int Successful = 0; // Response has valid confirmations + public const int MalformedRequest = 1; // Illegal confirmation request + public const int InternalError = 2; // Internal error in issuer + public const int TryLater = 3; // Try again later + // (4) is not used + public const int SigRequired = 5; // Must sign the request + public const int Unauthorized = 6; // Request unauthorized + + public OcspResp Generate( + int status, + object response) + { + if (response == null) + { + return new OcspResp(new OcspResponse(new OcspResponseStatus(status),null)); + } + if (response is BasicOcspResp) + { + BasicOcspResp r = (BasicOcspResp)response; + Asn1OctetString octs; + + try + { + octs = new DerOctetString(r.GetEncoded()); + } + catch (Exception e) + { + throw new OcspException("can't encode object.", e); + } + + ResponseBytes rb = new ResponseBytes( + OcspObjectIdentifiers.PkixOcspBasic, octs); + + return new OcspResp(new OcspResponse( + new OcspResponseStatus(status), rb)); + } + + throw new OcspException("unknown response object"); + } + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPRespStatus.cs b/iTechSharp/srcbc/ocsp/OCSPRespStatus.cs new file mode 100644 index 0000000..9c00c70 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPRespStatus.cs @@ -0,0 +1,22 @@ +using System; + +namespace Org.BouncyCastle.Ocsp +{ + [Obsolete("Use version with correct spelling 'OcspRespStatus'")] + public abstract class OcscpRespStatus : OcspRespStatus + { + } + + public abstract class OcspRespStatus + { + /** + * note 4 is not used. + */ + public const int Successful = 0; // --Response has valid confirmations + public const int MalformedRequest = 1; // --Illegal confirmation request + public const int InternalError = 2; // --Internal error in issuer + public const int TryLater = 3; // --Try again later + public const int SigRequired = 5; // --Must sign the request + public const int Unauthorized = 6; // --Request unauthorized + } +} diff --git a/iTechSharp/srcbc/ocsp/OCSPUtil.cs b/iTechSharp/srcbc/ocsp/OCSPUtil.cs new file mode 100644 index 0000000..390ba0f --- /dev/null +++ b/iTechSharp/srcbc/ocsp/OCSPUtil.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Ocsp +{ + class OcspUtilities + { + private static readonly Hashtable algorithms = new Hashtable(); + private static readonly Hashtable oids = new Hashtable(); + private static readonly ISet noParams = new HashSet(); + + static OcspUtilities() + { + algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption); + algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption); + algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption); + algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption); + algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption); + algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption); + algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160); + algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160); + algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128); + algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128); + algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256); + algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256); + algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1); + algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1); + algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224); + algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256); + algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224); + algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256); + algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384); + algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512); + algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + + oids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2WITHRSA"); + oids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA"); + oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, "RIPEMD160WITHRSA"); + oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, "RIPEMD128WITHRSA"); + oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, "RIPEMD256WITHRSA"); + oids.Add(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1WITHDSA"); + oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA"); + oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA"); + oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410"); + + // + // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. + // The parameters field SHALL be NULL for RSA based signature algorithms. + // + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512); + noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1); + noParams.Add(NistObjectIdentifiers.DsaWithSha224); + noParams.Add(NistObjectIdentifiers.DsaWithSha256); + } + + internal static DerObjectIdentifier GetAlgorithmOid( + string algorithmName) + { + algorithmName = algorithmName.ToUpper(CultureInfo.InvariantCulture); + + if (algorithms.ContainsKey(algorithmName)) + { + return (DerObjectIdentifier)algorithms[algorithmName]; + } + + return new DerObjectIdentifier(algorithmName); + } + + + internal static string GetAlgorithmName( + DerObjectIdentifier oid) + { + if (oids.ContainsKey(oid)) + { + return (string)oids[oid]; + } + + return oid.Id; + } + + internal static AlgorithmIdentifier GetSigAlgID( + DerObjectIdentifier sigOid) + { + if (noParams.Contains(sigOid)) + { + return new AlgorithmIdentifier(sigOid); + } + + return new AlgorithmIdentifier(sigOid, DerNull.Instance); + } + + internal static IEnumerable AlgNames + { + get { return new EnumerableProxy(algorithms.Keys); } + } + } +} diff --git a/iTechSharp/srcbc/ocsp/Req.cs b/iTechSharp/srcbc/ocsp/Req.cs new file mode 100644 index 0000000..68fd9f1 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/Req.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + public class Req + : X509ExtensionBase + { + private Request req; + + public Req( + Request req) + { + this.req = req; + } + + public CertificateID GetCertID() + { + return new CertificateID(req.ReqCert); + } + + public X509Extensions SingleRequestExtensions + { + get { return req.SingleRequestExtensions; } + } + + protected override X509Extensions GetX509Extensions() + { + return SingleRequestExtensions; + } + } +} diff --git a/iTechSharp/srcbc/ocsp/RespData.cs b/iTechSharp/srcbc/ocsp/RespData.cs new file mode 100644 index 0000000..105726c --- /dev/null +++ b/iTechSharp/srcbc/ocsp/RespData.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + public class RespData + : X509ExtensionBase + { + internal readonly ResponseData data; + + public RespData( + ResponseData data) + { + this.data = data; + } + + public int Version + { + get { return data.Version.Value.IntValue + 1; } + } + + public RespID GetResponderId() + { + return new RespID(data.ResponderID); + } + + public DateTime ProducedAt + { + get { return data.ProducedAt.ToDateTime(); } + } + + public SingleResp[] GetResponses() + { + Asn1Sequence s = data.Responses; + SingleResp[] rs = new SingleResp[s.Count]; + + for (int i = 0; i != rs.Length; i++) + { + rs[i] = new SingleResp(SingleResponse.GetInstance(s[i])); + } + + return rs; + } + + public X509Extensions ResponseExtensions + { + get { return data.ResponseExtensions; } + } + + protected override X509Extensions GetX509Extensions() + { + return ResponseExtensions; + } + } +} diff --git a/iTechSharp/srcbc/ocsp/RespID.cs b/iTechSharp/srcbc/ocsp/RespID.cs new file mode 100644 index 0000000..302811d --- /dev/null +++ b/iTechSharp/srcbc/ocsp/RespID.cs @@ -0,0 +1,86 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + /** + * Carrier for a ResponderID. + */ + public class RespID + { + internal readonly ResponderID id; + + public RespID( + ResponderID id) + { + this.id = id; + } + + public RespID( + X509Name name) + { + try + { + this.id = new ResponderID(name); + } + catch (Exception e) + { + throw new ArgumentException("can't decode name.", e); + } + } + + public RespID( + AsymmetricKeyParameter publicKey) + { + try + { + IDigest digest = DigestUtilities.GetDigest("SHA1"); + + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); + + byte[] encoded = info.PublicKeyData.GetBytes(); + digest.BlockUpdate(encoded, 0, encoded.Length); + + byte[] hash = DigestUtilities.DoFinal(digest); + + Asn1OctetString keyHash = new DerOctetString(hash); + + this.id = new ResponderID(keyHash); + } + catch (Exception e) + { + throw new OcspException("problem creating ID: " + e, e); + } + } + + public ResponderID ToAsn1Object() + { + return id; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + RespID other = obj as RespID; + + if (other == null) + return false; + + return id.Equals(other.id); + } + + public override int GetHashCode() + { + return id.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/ocsp/RevokedStatus.cs b/iTechSharp/srcbc/ocsp/RevokedStatus.cs new file mode 100644 index 0000000..6e5ad1b --- /dev/null +++ b/iTechSharp/srcbc/ocsp/RevokedStatus.cs @@ -0,0 +1,58 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Ocsp +{ + /** + * wrapper for the RevokedInfo object + */ + public class RevokedStatus + : CertificateStatus + { + internal readonly RevokedInfo info; + + public RevokedStatus( + RevokedInfo info) + { + this.info = info; + } + + public RevokedStatus( + DateTime revocationDate, + int reason) + { + this.info = new RevokedInfo(new DerGeneralizedTime(revocationDate), new CrlReason(reason)); + } + + public DateTime RevocationTime + { + get { return info.RevocationTime.ToDateTime(); } + } + + public bool HasRevocationReason + { + get { return (info.RevocationReason != null); } + } + + /** + * return the revocation reason. Note: this field is optional, test for it + * with hasRevocationReason() first. + * @exception InvalidOperationException if a reason is asked for and none is avaliable + */ + public int RevocationReason + { + get + { + if (info.RevocationReason == null) + { + throw new InvalidOperationException("attempt to get a reason where none is available"); + } + + return info.RevocationReason.Value.IntValue; + } + } + } +} diff --git a/iTechSharp/srcbc/ocsp/SingleResp.cs b/iTechSharp/srcbc/ocsp/SingleResp.cs new file mode 100644 index 0000000..b8979c5 --- /dev/null +++ b/iTechSharp/srcbc/ocsp/SingleResp.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ocsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Ocsp +{ + public class SingleResp + : X509ExtensionBase + { + internal readonly SingleResponse resp; + + public SingleResp( + SingleResponse resp) + { + this.resp = resp; + } + + public CertificateID GetCertID() + { + return new CertificateID(resp.CertId); + } + + /** + * Return the status object for the response - null indicates good. + * + * @return the status object for the response, null if it is good. + */ + public object GetCertStatus() + { + CertStatus s = resp.CertStatus; + + if (s.TagNo == 0) + { + return null; // good + } + + if (s.TagNo == 1) + { + return new RevokedStatus(RevokedInfo.GetInstance(s.Status)); + } + + return new UnknownStatus(); + } + + public DateTime ThisUpdate + { + get { return resp.ThisUpdate.ToDateTime(); } + } + + /** + * return the NextUpdate value - note: this is an optional field so may + * be returned as null. + * + * @return nextUpdate, or null if not present. + */ + public DateTimeObject NextUpdate + { + get + { + return resp.NextUpdate == null + ? null + : new DateTimeObject(resp.NextUpdate.ToDateTime()); + } + } + + public X509Extensions SingleExtensions + { + get { return resp.SingleExtensions; } + } + + protected override X509Extensions GetX509Extensions() + { + return SingleExtensions; + } + } +} diff --git a/iTechSharp/srcbc/ocsp/UnknownStatus.cs b/iTechSharp/srcbc/ocsp/UnknownStatus.cs new file mode 100644 index 0000000..c0f7a3a --- /dev/null +++ b/iTechSharp/srcbc/ocsp/UnknownStatus.cs @@ -0,0 +1,15 @@ +using System; + +namespace Org.BouncyCastle.Ocsp +{ + /** + * wrapper for the UnknownInfo object + */ + public class UnknownStatus + : CertificateStatus + { + public UnknownStatus() + { + } + } +} diff --git a/iTechSharp/srcbc/openpgp/IStreamGenerator.cs b/iTechSharp/srcbc/openpgp/IStreamGenerator.cs new file mode 100644 index 0000000..379213a --- /dev/null +++ b/iTechSharp/srcbc/openpgp/IStreamGenerator.cs @@ -0,0 +1,7 @@ +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public interface IStreamGenerator + { + void Close(); + } +} diff --git a/iTechSharp/srcbc/openpgp/PGPKeyRing.cs b/iTechSharp/srcbc/openpgp/PGPKeyRing.cs new file mode 100644 index 0000000..63708f7 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PGPKeyRing.cs @@ -0,0 +1,77 @@ +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public abstract class PgpKeyRing + : PgpObject + { + internal PgpKeyRing() + { + } + + internal static TrustPacket ReadOptionalTrustPacket( + BcpgInputStream bcpgInput) + { + return (bcpgInput.NextPacketTag() == PacketTag.Trust) + ? (TrustPacket) bcpgInput.ReadPacket() + : null; + } + + internal static ArrayList ReadSignaturesAndTrust( + BcpgInputStream bcpgInput) + { + try + { + ArrayList sigList = new ArrayList(); + + while (bcpgInput.NextPacketTag() == PacketTag.Signature) + { + SignaturePacket signaturePacket = (SignaturePacket) bcpgInput.ReadPacket(); + TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput); + + sigList.Add(new PgpSignature(signaturePacket, trustPacket)); + } + + return sigList; + } + catch (PgpException e) + { + throw new IOException("can't create signature object: " + e.Message, e); + } + } + + internal static void ReadUserIDs( + BcpgInputStream bcpgInput, + out ArrayList ids, + out ArrayList idTrusts, + out ArrayList idSigs) + { + ids = new ArrayList(); + idTrusts = new ArrayList(); + idSigs = new ArrayList(); + + while (bcpgInput.NextPacketTag() == PacketTag.UserId + || bcpgInput.NextPacketTag() == PacketTag.UserAttribute) + { + Packet obj = bcpgInput.ReadPacket(); + if (obj is UserIdPacket) + { + UserIdPacket id = (UserIdPacket)obj; + ids.Add(id.GetId()); + } + else + { + UserAttributePacket user = (UserAttributePacket) obj; + ids.Add(new PgpUserAttributeSubpacketVector(user.GetSubpackets())); + } + + idTrusts.Add( + ReadOptionalTrustPacket(bcpgInput)); + + idSigs.Add( + ReadSignaturesAndTrust(bcpgInput)); + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PGPObject.cs b/iTechSharp/srcbc/openpgp/PGPObject.cs new file mode 100644 index 0000000..d38276c --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PGPObject.cs @@ -0,0 +1,9 @@ +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public abstract class PgpObject + { + internal PgpObject() + { + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs b/iTechSharp/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs new file mode 100644 index 0000000..3116dc6 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Bcpg.Attr; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public class PgpUserAttributeSubpacketVectorGenerator + { + private ArrayList list = new ArrayList(); + + public virtual void SetImageAttribute( + ImageAttrib.Format imageType, + byte[] imageData) + { + if (imageData == null) + throw new ArgumentException("attempt to set null image", "imageData"); + + list.Add(new ImageAttrib(imageType, imageData)); + } + + public virtual PgpUserAttributeSubpacketVector Generate() + { + return new PgpUserAttributeSubpacketVector( + (UserAttributeSubpacket[]) list.ToArray(typeof(UserAttributeSubpacket))); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpCompressedData.cs b/iTechSharp/srcbc/openpgp/PgpCompressedData.cs new file mode 100644 index 0000000..18c8fb4 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpCompressedData.cs @@ -0,0 +1,50 @@ +using System.IO; + +using Org.BouncyCastle.Apache.Bzip2; +using Org.BouncyCastle.Utilities.Zlib; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Compressed data objects + public class PgpCompressedData + : PgpObject + { + private readonly CompressedDataPacket data; + + public PgpCompressedData( + BcpgInputStream bcpgInput) + { + data = (CompressedDataPacket) bcpgInput.ReadPacket(); + } + + /// The algorithm used for compression + public CompressionAlgorithmTag Algorithm + { + get { return data.Algorithm; } + } + + /// Get the raw input stream contained in the object. + public Stream GetInputStream() + { + return data.GetInputStream(); + } + + /// Return an uncompressed input stream which allows reading of the compressed data. + public Stream GetDataStream() + { + switch (Algorithm) + { + case CompressionAlgorithmTag.Uncompressed: + return GetInputStream(); + case CompressionAlgorithmTag.Zip: + return new ZInflaterInputStream(GetInputStream(), true); + case CompressionAlgorithmTag.ZLib: + return new ZInflaterInputStream(GetInputStream()); + case CompressionAlgorithmTag.BZip2: + return new CBZip2InputStream(GetInputStream()); + default: + throw new PgpException("can't recognise compression algorithm: " + Algorithm); + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpCompressedDataGenerator.cs b/iTechSharp/srcbc/openpgp/PgpCompressedDataGenerator.cs new file mode 100644 index 0000000..5c57bc6 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpCompressedDataGenerator.cs @@ -0,0 +1,177 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Apache.Bzip2; +using Org.BouncyCastle.Utilities.Zlib; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Class for producing compressed data packets. + public class PgpCompressedDataGenerator + : IStreamGenerator + { + private readonly CompressionAlgorithmTag algorithm; + private readonly int compression; + + private Stream dOut; + private BcpgOutputStream pkOut; + + public PgpCompressedDataGenerator( + CompressionAlgorithmTag algorithm) + : this(algorithm, JZlib.Z_DEFAULT_COMPRESSION) + { + } + + public PgpCompressedDataGenerator( + CompressionAlgorithmTag algorithm, + int compression) + { + switch (algorithm) + { + case CompressionAlgorithmTag.Uncompressed: + case CompressionAlgorithmTag.Zip: + case CompressionAlgorithmTag.ZLib: + case CompressionAlgorithmTag.BZip2: + break; + default: + throw new ArgumentException("unknown compression algorithm", "algorithm"); + } + + if (compression != JZlib.Z_DEFAULT_COMPRESSION) + { + if ((compression < JZlib.Z_NO_COMPRESSION) || (compression > JZlib.Z_BEST_COMPRESSION)) + { + throw new ArgumentException("unknown compression level: " + compression); + } + } + + this.algorithm = algorithm; + this.compression = compression; + } + + /// + ///

      + /// Return an output stream which will save the data being written to + /// the compressed object. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///
      + /// Stream to be used for output. + /// A Stream for output of the compressed data. + /// + /// + /// + public Stream Open( + Stream outStr) + { + if (dOut != null) + throw new InvalidOperationException("generator already in open state"); + if (outStr == null) + throw new ArgumentNullException("outStr"); + + this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData); + + doOpen(); + + return new WrappedGeneratorStream(this, dOut); + } + + /// + ///

      + /// Return an output stream which will compress the data as it is written to it. + /// The stream will be written out in chunks according to the size of the passed in buffer. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///

      + /// Note: if the buffer is not a power of 2 in length only the largest power of 2 + /// bytes worth of the buffer will be used. + ///

      + ///

      + /// Note: using this may break compatibility with RFC 1991 compliant tools. + /// Only recent OpenPGP implementations are capable of accepting these streams. + ///

      + ///
      + /// Stream to be used for output. + /// The buffer to use. + /// A Stream for output of the compressed data. + /// + /// + /// + /// + public Stream Open( + Stream outStr, + byte[] buffer) + { + if (dOut != null) + throw new InvalidOperationException("generator already in open state"); + if (outStr == null) + throw new ArgumentNullException("outStr"); + if (buffer == null) + throw new ArgumentNullException("buffer"); + + this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData, buffer); + + doOpen(); + + return new WrappedGeneratorStream(this, dOut); + } + + private void doOpen() + { + pkOut.WriteByte((byte) algorithm); + + switch (algorithm) + { + case CompressionAlgorithmTag.Uncompressed: + dOut = pkOut; + break; + case CompressionAlgorithmTag.Zip: + dOut = new ZDeflaterOutputStream(pkOut, compression, true); + break; + case CompressionAlgorithmTag.ZLib: + dOut = new ZDeflaterOutputStream(pkOut, compression, false); + break; + case CompressionAlgorithmTag.BZip2: + dOut = new CBZip2OutputStream(pkOut); + break; + default: + // Constructor should guard against this possibility + throw new InvalidOperationException(); + } + } + + /// Close the compressed object.summary> + public void Close() + { + if (dOut != null) + { + switch (algorithm) + { + case CompressionAlgorithmTag.BZip2: + ((CBZip2OutputStream) dOut).Finish(); + break; + case CompressionAlgorithmTag.Zip: + case CompressionAlgorithmTag.ZLib: + ((ZDeflaterOutputStream) dOut).Finish(); + break; + } + + dOut.Flush(); + + pkOut.Finish(); + pkOut.Flush(); + + dOut = null; + pkOut = null; + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpDataValidationException.cs b/iTechSharp/srcbc/openpgp/PgpDataValidationException.cs new file mode 100644 index 0000000..74674da --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpDataValidationException.cs @@ -0,0 +1,15 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Thrown if the IV at the start of a data stream indicates the wrong key is being used. + /// + public class PgpDataValidationException + : PgpException + { + public PgpDataValidationException() : base() {} + public PgpDataValidationException(string message) : base(message) {} + public PgpDataValidationException(string message, Exception exception) : base(message, exception) {} + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpEncryptedData.cs b/iTechSharp/srcbc/openpgp/PgpEncryptedData.cs new file mode 100644 index 0000000..67b5fea --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpEncryptedData.cs @@ -0,0 +1,151 @@ +using System; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public abstract class PgpEncryptedData + { + internal class TruncatedStream + : BaseInputStream + { + private const int LookAheadSize = 22; + private const int LookAheadBufSize = 512; + private const int LookAheadBufLimit = LookAheadBufSize - LookAheadSize; + + private readonly Stream inStr; + private readonly byte[] lookAhead = new byte[LookAheadBufSize]; + private int bufStart, bufEnd; + + internal TruncatedStream( + Stream inStr) + { + int numRead = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length); + + if (numRead < LookAheadSize) + throw new EndOfStreamException(); + + this.inStr = inStr; + this.bufStart = 0; + this.bufEnd = numRead - LookAheadSize; + } + + private int FillBuffer() + { + if (bufEnd < LookAheadBufLimit) + return 0; + + Debug.Assert(bufStart == LookAheadBufLimit); + Debug.Assert(bufEnd == LookAheadBufLimit); + + Array.Copy(lookAhead, LookAheadBufLimit, lookAhead, 0, LookAheadSize); + bufEnd = Streams.ReadFully(inStr, lookAhead, LookAheadSize, LookAheadBufLimit); + bufStart = 0; + return bufEnd; + } + + public override int ReadByte() + { + if (bufStart < bufEnd) + return lookAhead[bufStart++]; + + if (FillBuffer() < 1) + return -1; + + return lookAhead[bufStart++]; + } + + public override int Read(byte[] buf, int off, int len) + { + int avail = bufEnd - bufStart; + + int pos = off; + while (len > avail) + { + Array.Copy(lookAhead, bufStart, buf, pos, avail); + + bufStart += avail; + pos += avail; + len -= avail; + + if ((avail = FillBuffer()) < 1) + return pos - off; + } + + Array.Copy(lookAhead, bufStart, buf, pos, len); + bufStart += len; + + return pos + len - off;; + } + + internal byte[] GetLookAhead() + { + byte[] temp = new byte[LookAheadSize]; + Array.Copy(lookAhead, bufStart, temp, 0, LookAheadSize); + return temp; + } + } + + internal InputStreamPacket encData; + internal Stream encStream; + internal TruncatedStream truncStream; + + internal PgpEncryptedData( + InputStreamPacket encData) + { + this.encData = encData; + } + + /// Return the raw input stream for the data stream. + public virtual Stream GetInputStream() + { + return encData.GetInputStream(); + } + + /// Return true if the message is integrity protected. + /// True, if there is a modification detection code namespace associated + /// with this stream. + public bool IsIntegrityProtected() + { + return encData is SymmetricEncIntegrityPacket; + } + + /// Note: This can only be called after the message has been read. + /// True, if the message verifies, false otherwise + public bool Verify() + { + if (!IsIntegrityProtected()) + throw new PgpException("data not integrity protected."); + + DigestStream dIn = (DigestStream) encStream; + + // + // make sure we are at the end. + // + while (encStream.ReadByte() >= 0) + { + // do nothing + } + + // + // process the MDC packet + // + byte[] lookAhead = truncStream.GetLookAhead(); + + IDigest hash = dIn.ReadDigest(); + hash.BlockUpdate(lookAhead, 0, 2); + byte[] digest = DigestUtilities.DoFinal(hash); + + byte[] streamDigest = new byte[digest.Length]; + Array.Copy(lookAhead, 2, streamDigest, 0, streamDigest.Length); + + return Arrays.AreEqual(digest, streamDigest); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpEncryptedDataGenerator.cs b/iTechSharp/srcbc/openpgp/PgpEncryptedDataGenerator.cs new file mode 100644 index 0000000..7d9ea78 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpEncryptedDataGenerator.cs @@ -0,0 +1,495 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Generator for encrypted objects. + public class PgpEncryptedDataGenerator + : IStreamGenerator + { + private BcpgOutputStream pOut; + private CipherStream cOut; + private IBufferedCipher c; + private bool withIntegrityPacket; + private bool oldFormat; + private DigestStream digestOut; + + private abstract class EncMethod + : ContainedPacket + { + protected byte[] sessionInfo; + protected SymmetricKeyAlgorithmTag encAlgorithm; + protected KeyParameter key; + + public abstract void AddSessionInfo(byte[] si, SecureRandom random); + } + + private class PbeMethod + : EncMethod + { + private S2k s2k; + + internal PbeMethod( + SymmetricKeyAlgorithmTag encAlgorithm, + S2k s2k, + KeyParameter key) + { + this.encAlgorithm = encAlgorithm; + this.s2k = s2k; + this.key = key; + } + + public KeyParameter GetKey() + { + return key; + } + + public override void AddSessionInfo( + byte[] si, + SecureRandom random) + { + string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); + IBufferedCipher c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); + + byte[] iv = new byte[c.GetBlockSize()]; + c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random)); + + this.sessionInfo = c.DoFinal(si, 0, si.Length - 2); + } + + public override void Encode(BcpgOutputStream pOut) + { + SymmetricKeyEncSessionPacket pk = new SymmetricKeyEncSessionPacket( + encAlgorithm, s2k, sessionInfo); + + pOut.WritePacket(pk); + } + } + + private class PubMethod + : EncMethod + { + internal PgpPublicKey pubKey; + internal BigInteger[] data; + + internal PubMethod( + PgpPublicKey pubKey) + { + this.pubKey = pubKey; + } + + public override void AddSessionInfo( + byte[] si, + SecureRandom random) + { + IBufferedCipher c; + + switch (pubKey.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding"); + break; + case PublicKeyAlgorithmTag.Dsa: + throw new PgpException("Can't use DSA for encryption."); + case PublicKeyAlgorithmTag.ECDsa: + throw new PgpException("Can't use ECDSA for encryption."); + default: + throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm); + } + + AsymmetricKeyParameter akp = pubKey.GetKey(); + + c.Init(true, new ParametersWithRandom(akp, random)); + + byte[] encKey = c.DoFinal(si); + + switch (pubKey.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + data = new BigInteger[]{ new BigInteger(1, encKey) }; + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + int halfLength = encKey.Length / 2; + data = new BigInteger[] + { + new BigInteger(1, encKey, 0, halfLength), + new BigInteger(1, encKey, halfLength, halfLength) + }; + break; + default: + throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm); + } + } + + public override void Encode(BcpgOutputStream pOut) + { + PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket( + pubKey.KeyId, pubKey.Algorithm, data); + + pOut.WritePacket(pk); + } + } + + private readonly ArrayList methods = new ArrayList(); + private readonly SymmetricKeyAlgorithmTag defAlgorithm; + private readonly SecureRandom rand; + + public PgpEncryptedDataGenerator( + SymmetricKeyAlgorithmTag encAlgorithm) + { + this.defAlgorithm = encAlgorithm; + this.rand = new SecureRandom(); + } + + public PgpEncryptedDataGenerator( + SymmetricKeyAlgorithmTag encAlgorithm, + bool withIntegrityPacket) + { + this.defAlgorithm = encAlgorithm; + this.withIntegrityPacket = withIntegrityPacket; + this.rand = new SecureRandom(); + } + + /// Existing SecureRandom constructor. + /// The symmetric algorithm to use. + /// Source of randomness. + public PgpEncryptedDataGenerator( + SymmetricKeyAlgorithmTag encAlgorithm, + SecureRandom rand) + { + this.defAlgorithm = encAlgorithm; + this.rand = rand; + } + + /// Creates a cipher stream which will have an integrity packet associated with it. + public PgpEncryptedDataGenerator( + SymmetricKeyAlgorithmTag encAlgorithm, + bool withIntegrityPacket, + SecureRandom rand) + { + this.defAlgorithm = encAlgorithm; + this.rand = rand; + this.withIntegrityPacket = withIntegrityPacket; + } + + /// Base constructor. + /// The symmetric algorithm to use. + /// Source of randomness. + /// PGP 2.6.x compatibility required. + public PgpEncryptedDataGenerator( + SymmetricKeyAlgorithmTag encAlgorithm, + SecureRandom rand, + bool oldFormat) + { + this.defAlgorithm = encAlgorithm; + this.rand = rand; + this.oldFormat = oldFormat; + } + + /// Add a PBE encryption method to the encrypted object. + public void AddMethod( + char[] passPhrase) + { + byte[] iv = new byte[8]; + rand.NextBytes(iv); + + S2k s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60); + + methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.MakeKeyFromPassPhrase(defAlgorithm, s2k, passPhrase))); + } + + /// Add a public key encrypted session key to the encrypted object. + public void AddMethod( + PgpPublicKey key) + { + if (!key.IsEncryptionKey) + { + throw new ArgumentException("passed in key not an encryption key!"); + } + + methods.Add(new PubMethod(key)); + } + + private void AddCheckSum( + byte[] sessionInfo) + { + Debug.Assert(sessionInfo != null); + Debug.Assert(sessionInfo.Length >= 3); + + int check = 0; + + for (int i = 1; i < sessionInfo.Length - 2; i++) + { + check += sessionInfo[i]; + } + + sessionInfo[sessionInfo.Length - 2] = (byte)(check >> 8); + sessionInfo[sessionInfo.Length - 1] = (byte)(check); + } + + private byte[] CreateSessionInfo( + SymmetricKeyAlgorithmTag algorithm, + KeyParameter key) + { + byte[] keyBytes = key.GetKey(); + byte[] sessionInfo = new byte[keyBytes.Length + 3]; + sessionInfo[0] = (byte) algorithm; + keyBytes.CopyTo(sessionInfo, 1); + AddCheckSum(sessionInfo); + return sessionInfo; + } + + /// + ///

      + /// If buffer is non null stream assumed to be partial, otherwise the length will be used + /// to output a fixed length packet. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///
      + private Stream Open( + Stream outStr, + long length, + byte[] buffer) + { + if (cOut != null) + throw new InvalidOperationException("generator already in open state"); + if (methods.Count == 0) + throw new InvalidOperationException("No encryption methods specified"); + if (outStr == null) + throw new ArgumentNullException("outStr"); + + pOut = new BcpgOutputStream(outStr); + + KeyParameter key; + + if (methods.Count == 1) + { + if (methods[0] is PbeMethod) + { + PbeMethod m = (PbeMethod)methods[0]; + + key = m.GetKey(); + } + else + { + key = PgpUtilities.MakeRandomKey(defAlgorithm, rand); + + byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key); + PubMethod m = (PubMethod)methods[0]; + + try + { + m.AddSessionInfo(sessionInfo, rand); + } + catch (Exception e) + { + throw new PgpException("exception encrypting session key", e); + } + } + + pOut.WritePacket((ContainedPacket)methods[0]); + } + else // multiple methods + { + key = PgpUtilities.MakeRandomKey(defAlgorithm, rand); + byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key); + + for (int i = 0; i != methods.Count; i++) + { + EncMethod m = (EncMethod)methods[i]; + + try + { + m.AddSessionInfo(sessionInfo, rand); + } + catch (Exception e) + { + throw new PgpException("exception encrypting session key", e); + } + + pOut.WritePacket(m); + } + } + + string cName = PgpUtilities.GetSymmetricCipherName(defAlgorithm); + if (cName == null) + { + throw new PgpException("null cipher specified"); + } + + try + { + if (withIntegrityPacket) + { + cName += "/CFB/NoPadding"; + } + else + { + cName += "/OpenPGPCFB/NoPadding"; + } + + c = CipherUtilities.GetCipher(cName); + + // TODO Confirm the IV should be all zero bytes (not inLineIv - see below) + byte[] iv = new byte[c.GetBlockSize()]; + c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), rand)); + + if (buffer == null) + { + // + // we have to Add block size + 2 for the Generated IV and + 1 + 22 if integrity protected + // + if (withIntegrityPacket) + { + pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22); + pOut.WriteByte(1); // version number + } + else + { + pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat); + } + } + else + { + if (withIntegrityPacket) + { + pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer); + pOut.WriteByte(1); // version number + } + else + { + pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer); + } + } + + int blockSize = c.GetBlockSize(); + byte[] inLineIv = new byte[blockSize + 2]; + rand.NextBytes(inLineIv, 0, blockSize); + Array.Copy(inLineIv, inLineIv.Length - 4, inLineIv, inLineIv.Length - 2, 2); + + Stream myOut = cOut = new CipherStream(pOut, null, c); + + if (withIntegrityPacket) + { + string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); + IDigest digest = DigestUtilities.GetDigest(digestName); + myOut = digestOut = new DigestStream(myOut, null, digest); + } + + myOut.Write(inLineIv, 0, inLineIv.Length); + + return new WrappedGeneratorStream(this, myOut); + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + } + + /// + ///

      + /// Return an output stream which will encrypt the data as it is written to it. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///
      + public Stream Open( + Stream outStr, + long length) + { + return Open(outStr, length, null); + } + + /// + ///

      + /// Return an output stream which will encrypt the data as it is written to it. + /// The stream will be written out in chunks according to the size of the passed in buffer. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///

      + /// Note: if the buffer is not a power of 2 in length only the largest power of 2 + /// bytes worth of the buffer will be used. + ///

      + ///
      + public Stream Open( + Stream outStr, + byte[] buffer) + { + return Open(outStr, 0, buffer); + } + + /// + ///

      + /// Close off the encrypted object - this is equivalent to calling Close() on the stream + /// returned by the Open() method. + ///

      + ///

      + /// Note: This does not close the underlying output stream, only the stream on top of + /// it created by the Open() method. + ///

      + ///
      + public void Close() + { + if (cOut != null) + { + // TODO Should this all be under the try/catch block? + if (digestOut != null) + { + // + // hand code a mod detection packet + // + BcpgOutputStream bOut = new BcpgOutputStream( + digestOut, PacketTag.ModificationDetectionCode, 20); + + bOut.Flush(); + digestOut.Flush(); + + // TODO + byte[] dig = DigestUtilities.DoFinal(digestOut.WriteDigest()); + cOut.Write(dig, 0, dig.Length); + } + + cOut.Flush(); + + try + { + pOut.Write(c.DoFinal()); + pOut.Finish(); + } + catch (Exception e) + { + throw new IOException(e.Message, e); + } + + cOut = null; + pOut = null; + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpEncryptedDataList.cs b/iTechSharp/srcbc/openpgp/PgpEncryptedDataList.cs new file mode 100644 index 0000000..8578813 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpEncryptedDataList.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A holder for a list of PGP encryption method packets. + public class PgpEncryptedDataList + : PgpObject + { + private ArrayList list = new ArrayList(); + private InputStreamPacket data; + + public PgpEncryptedDataList( + BcpgInputStream bcpgInput) + { + while (bcpgInput.NextPacketTag() == PacketTag.PublicKeyEncryptedSession + || bcpgInput.NextPacketTag() == PacketTag.SymmetricKeyEncryptedSessionKey) + { + list.Add(bcpgInput.ReadPacket()); + } + + data = (InputStreamPacket)bcpgInput.ReadPacket(); + + for (int i = 0; i != list.Count; i++) + { + if (list[i] is SymmetricKeyEncSessionPacket) + { + list[i] = new PgpPbeEncryptedData((SymmetricKeyEncSessionPacket) list[i], data); + } + else + { + list[i] = new PgpPublicKeyEncryptedData((PublicKeyEncSessionPacket) list[i], data); + } + } + } + + public PgpEncryptedData this[int index] + { + get { return (PgpEncryptedData) list[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public object Get(int index) + { + return this[index]; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return list.Count; } + } + + public int Count + { + get { return list.Count; } + } + + public bool IsEmpty + { + get { return list.Count == 0; } + } + + public IEnumerable GetEncryptedDataObjects() + { + return new EnumerableProxy(list); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpException.cs b/iTechSharp/srcbc/openpgp/PgpException.cs new file mode 100644 index 0000000..3048116 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpException.cs @@ -0,0 +1,19 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Generic exception class for PGP encoding/decoding problems. + public class PgpException + : Exception + { + public PgpException() : base() {} + public PgpException(string message) : base(message) {} + public PgpException(string message, Exception exception) : base(message, exception) {} + + [Obsolete("Use InnerException property")] + public Exception UnderlyingException + { + get { return InnerException; } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpExperimental.cs b/iTechSharp/srcbc/openpgp/PgpExperimental.cs new file mode 100644 index 0000000..8518335 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpExperimental.cs @@ -0,0 +1,16 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public class PgpExperimental + : PgpObject + { + private readonly ExperimentalPacket p; + + public PgpExperimental( + BcpgInputStream bcpgIn) + { + p = (ExperimentalPacket) bcpgIn.ReadPacket(); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpKeyFlags.cs b/iTechSharp/srcbc/openpgp/PgpKeyFlags.cs new file mode 100644 index 0000000..ea18006 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpKeyFlags.cs @@ -0,0 +1,13 @@ +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Key flag values for the KeyFlags subpacket. + public abstract class PgpKeyFlags + { + public const int CanCertify = 0x01; // This key may be used to certify other keys. + public const int CanSign = 0x02; // This key may be used to sign data. + public const int CanEncryptCommunications = 0x04; // This key may be used to encrypt communications. + public const int CanEncryptStorage = 0x08; // This key may be used to encrypt storage. + public const int MaybeSplit = 0x10; // The private component of this key may have been split by a secret-sharing mechanism. + public const int MaybeShared = 0x80; // The private component of this key may be in the possession of more than one person. + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpKeyPair.cs b/iTechSharp/srcbc/openpgp/PgpKeyPair.cs new file mode 100644 index 0000000..6efb03a --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpKeyPair.cs @@ -0,0 +1,67 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// General class to handle JCA key pairs and convert them into OpenPGP ones. + ///

      + /// A word for the unwary, the KeyId for an OpenPGP public key is calculated from + /// a hash that includes the time of creation, if you pass a different date to the + /// constructor below with the same public private key pair the KeyIs will not be the + /// same as for previous generations of the key, so ideally you only want to do + /// this once. + ///

      + ///
      + public class PgpKeyPair + { + private readonly PgpPublicKey pub; + private readonly PgpPrivateKey priv; + + public PgpKeyPair( + PublicKeyAlgorithmTag algorithm, + AsymmetricCipherKeyPair keyPair, + DateTime time) + : this(algorithm, keyPair.Public, keyPair.Private, time) + { + } + + public PgpKeyPair( + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + AsymmetricKeyParameter privKey, + DateTime time) + { + this.pub = new PgpPublicKey(algorithm, pubKey, time); + this.priv = new PgpPrivateKey(privKey, pub.KeyId); + } + + /// Create a key pair from a PgpPrivateKey and a PgpPublicKey. + /// The public key. + /// The private key. + public PgpKeyPair( + PgpPublicKey pub, + PgpPrivateKey priv) + { + this.pub = pub; + this.priv = priv; + } + + /// The keyId associated with this key pair. + public long KeyId + { + get { return pub.KeyId; } + } + + public PgpPublicKey PublicKey + { + get { return pub; } + } + + public PgpPrivateKey PrivateKey + { + get { return priv; } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpKeyRingGenerator.cs b/iTechSharp/srcbc/openpgp/PgpKeyRingGenerator.cs new file mode 100644 index 0000000..1bbb3e9 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpKeyRingGenerator.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Generator for a PGP master and subkey ring. + /// This class will generate both the secret and public key rings + /// + public class PgpKeyRingGenerator + { + private ArrayList keys = new ArrayList(); + private string id; + private SymmetricKeyAlgorithmTag encAlgorithm; + private int certificationLevel; + private char[] passPhrase; + private bool useSha1; + private PgpKeyPair masterKey; + private PgpSignatureSubpacketVector hashedPacketVector; + private PgpSignatureSubpacketVector unhashedPacketVector; + private SecureRandom rand; + + /// + /// Create a new key ring generator using old style checksumming. It is recommended to use + /// SHA1 checksumming where possible. + /// + /// The certification level for keys on this ring. + /// The master key pair. + /// The id to be associated with the ring. + /// The algorithm to be used to protect secret keys. + /// The passPhrase to be used to protect secret keys. + /// Packets to be included in the certification hash. + /// Packets to be attached unhashed to the certification. + /// input secured random. + public PgpKeyRingGenerator( + int certificationLevel, + PgpKeyPair masterKey, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand) + { + } + + /// + /// Create a new key ring generator. + /// + /// The certification level for keys on this ring. + /// The master key pair. + /// The id to be associated with the ring. + /// The algorithm to be used to protect secret keys. + /// The passPhrase to be used to protect secret keys. + /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum. + /// Packets to be included in the certification hash. + /// Packets to be attached unhashed to the certification. + /// input secured random. + public PgpKeyRingGenerator( + int certificationLevel, + PgpKeyPair masterKey, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + { + this.certificationLevel = certificationLevel; + this.masterKey = masterKey; + this.id = id; + this.encAlgorithm = encAlgorithm; + this.passPhrase = passPhrase; + this.useSha1 = useSha1; + this.hashedPacketVector = hashedPackets; + this.unhashedPacketVector = unhashedPackets; + this.rand = rand; + + keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); + } + + /// Add a subkey to the key ring to be generated with default certification. + public void AddSubKey( + PgpKeyPair keyPair) + { + AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector); + } + + /// + /// Add a subkey with specific hashed and unhashed packets associated with it and + /// default certification. + /// + /// Public/private key pair. + /// Hashed packet values to be included in certification. + /// Unhashed packets values to be included in certification. + /// + public void AddSubKey( + PgpKeyPair keyPair, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets) + { + try + { + PgpSignatureGenerator sGen = new PgpSignatureGenerator( + masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1); + + // + // Generate the certification + // + sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + ArrayList subSigs = new ArrayList(); + + subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey)); + + keys.Add(new PgpSecretKey(keyPair, null, subSigs, encAlgorithm, passPhrase, useSha1, rand)); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("exception adding subkey: ", e); + } + } + + /// Return the secret key ring. + public PgpSecretKeyRing GenerateSecretKeyRing() + { + return new PgpSecretKeyRing(keys); + } + + /// Return the public key ring that corresponds to the secret key ring. + public PgpPublicKeyRing GeneratePublicKeyRing() + { + ArrayList pubKeys = new ArrayList(); + + IEnumerator enumerator = keys.GetEnumerator(); + enumerator.MoveNext(); + + PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current; + pubKeys.Add(pgpSecretKey.PublicKey); + + while (enumerator.MoveNext()) + { + pgpSecretKey = (PgpSecretKey) enumerator.Current; + + PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey); + k.publicPk = new PublicSubkeyPacket( + k.Algorithm, k.CreationTime, k.publicPk.Key); + + pubKeys.Add(k); + } + + return new PgpPublicKeyRing(pubKeys); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpKeyValidationException.cs b/iTechSharp/srcbc/openpgp/PgpKeyValidationException.cs new file mode 100644 index 0000000..da07f40 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpKeyValidationException.cs @@ -0,0 +1,15 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Thrown if the key checksum is invalid. + /// + public class PgpKeyValidationException + : PgpException + { + public PgpKeyValidationException() : base() {} + public PgpKeyValidationException(string message) : base(message) {} + public PgpKeyValidationException(string message, Exception exception) : base(message, exception) {} + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpLiteralData.cs b/iTechSharp/srcbc/openpgp/PgpLiteralData.cs new file mode 100644 index 0000000..d48818a --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpLiteralData.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Class for processing literal data objects. + public class PgpLiteralData + : PgpObject + { + public const char Binary = 'b'; + public const char Text = 't'; + + /// The special name indicating a "for your eyes only" packet. + public const string Console = "_CONSOLE"; + + private LiteralDataPacket data; + + public PgpLiteralData( + BcpgInputStream bcpgInput) + { + data = (LiteralDataPacket) bcpgInput.ReadPacket(); + } + + /// The format of the data stream - Binary or Text + public int Format + { + get { return data.Format; } + } + + /// The file name that's associated with the data stream. + public string FileName + { + get { return data.FileName; } + } + + /// The modification time for the file. + public DateTime ModificationTime + { + get { return DateTimeUtilities.UnixMsToDateTime(data.ModificationTime); } + } + + /// The raw input stream for the data stream. + public Stream GetInputStream() + { + return data.GetInputStream(); + } + + /// The input stream representing the data stream. + public Stream GetDataStream() + { + return GetInputStream(); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpLiteralDataGenerator.cs b/iTechSharp/srcbc/openpgp/PgpLiteralDataGenerator.cs new file mode 100644 index 0000000..11b0515 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpLiteralDataGenerator.cs @@ -0,0 +1,177 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Class for producing literal data packets. + public class PgpLiteralDataGenerator + : IStreamGenerator + { + public const char Binary = PgpLiteralData.Binary; + public const char Text = PgpLiteralData.Text; + + /// The special name indicating a "for your eyes only" packet. + public const string Console = PgpLiteralData.Console; + + private BcpgOutputStream pkOut; + private bool oldFormat; + + public PgpLiteralDataGenerator() + { + } + + /// + /// Generates literal data objects in the old format. + /// This is important if you need compatibility with PGP 2.6.x. + /// + /// If true, uses old format. + public PgpLiteralDataGenerator( + bool oldFormat) + { + this.oldFormat = oldFormat; + } + + private void WriteHeader( + BcpgOutputStream outStr, + char format, + string name, + long modificationTime) + { + byte[] asciiName = Strings.ToByteArray(name); + + outStr.Write( + (byte) format, + (byte) asciiName.Length); + + outStr.Write(asciiName); + + long modDate = modificationTime / 1000L; + + outStr.Write( + (byte)(modDate >> 24), + (byte)(modDate >> 16), + (byte)(modDate >> 8), + (byte)modDate); + } + + /// + ///

      + /// Open a literal data packet, returning a stream to store the data inside the packet. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///
      + /// The stream we want the packet in. + /// The format we are using. + /// The name of the 'file'. + /// The length of the data we will write. + /// The time of last modification we want stored. + public Stream Open( + Stream outStr, + char format, + string name, + long length, + DateTime modificationTime) + { + if (pkOut != null) + throw new InvalidOperationException("generator already in open state"); + if (outStr == null) + throw new ArgumentNullException("outStr"); + + // Do this first, since it might throw an exception + long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime); + + pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, + length + 2 + name.Length + 4, oldFormat); + + WriteHeader(pkOut, format, name, unixMs); + + return new WrappedGeneratorStream(this, pkOut); + } + + /// + ///

      + /// Open a literal data packet, returning a stream to store the data inside the packet, + /// as an indefinite length stream. The stream is written out as a series of partial + /// packets with a chunk size determined by the size of the passed in buffer. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///

      + /// Note: if the buffer is not a power of 2 in length only the largest power of 2 + /// bytes worth of the buffer will be used.

      + ///
      + /// The stream we want the packet in. + /// The format we are using. + /// The name of the 'file'. + /// The time of last modification we want stored. + /// The buffer to use for collecting data to put into chunks. + public Stream Open( + Stream outStr, + char format, + string name, + DateTime modificationTime, + byte[] buffer) + { + if (pkOut != null) + throw new InvalidOperationException("generator already in open state"); + if (outStr == null) + throw new ArgumentNullException("outStr"); + + // Do this first, since it might throw an exception + long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime); + + pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer); + + WriteHeader(pkOut, format, name, unixMs); + + return new WrappedGeneratorStream(this, pkOut); + } + + /// + ///

      + /// Open a literal data packet for the passed in FileInfo object, returning + /// an output stream for saving the file contents. + ///

      + ///

      + /// The stream created can be closed off by either calling Close() + /// on the stream or Close() on the generator. Closing the returned + /// stream does not close off the Stream parameter outStr. + ///

      + ///
      + /// The stream we want the packet in. + /// The format we are using. + /// The FileInfo object containg the packet details. + public Stream Open( + Stream outStr, + char format, + FileInfo file) + { + return Open(outStr, format, file.Name, file.Length, file.LastWriteTime); + } + + /// + /// Close the literal data packet - this is equivalent to calling Close() + /// on the stream returned by the Open() method. + /// + public void Close() + { + if (pkOut != null) + { + pkOut.Finish(); + pkOut.Flush(); + pkOut = null; + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpMarker.cs b/iTechSharp/srcbc/openpgp/PgpMarker.cs new file mode 100644 index 0000000..733e4e9 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpMarker.cs @@ -0,0 +1,18 @@ +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// A PGP marker packet - in general these should be ignored other than where + /// the idea is to preserve the original input stream. + /// + public class PgpMarker + : PgpObject + { + private readonly MarkerPacket p; + + public PgpMarker( + BcpgInputStream bcpgIn) + { + p = (MarkerPacket) bcpgIn.ReadPacket(); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpObjectFactory.cs b/iTechSharp/srcbc/openpgp/PgpObjectFactory.cs new file mode 100644 index 0000000..d24a4a9 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpObjectFactory.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections; +using System.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// General class for reading a PGP object stream. + ///

      + /// Note: if this class finds a PgpPublicKey or a PgpSecretKey it + /// will create a PgpPublicKeyRing, or a PgpSecretKeyRing for each + /// key found. If all you are trying to do is read a key ring file use + /// either PgpPublicKeyRingBundle or PgpSecretKeyRingBundle.

      + ///
      + public class PgpObjectFactory + { + private readonly BcpgInputStream bcpgIn; + + public PgpObjectFactory( + Stream inputStream) + { + this.bcpgIn = BcpgInputStream.Wrap(inputStream); + } + + public PgpObjectFactory( + byte[] bytes) + : this(new MemoryStream(bytes, false)) + { + } + + /// Return the next object in the stream, or null if the end is reached. + /// On a parse error + public PgpObject NextPgpObject() + { + PacketTag tag = bcpgIn.NextPacketTag(); + + if ((int) tag == -1) return null; + + switch (tag) + { + case PacketTag.Signature: + { + ArrayList l = new ArrayList(); + + while (bcpgIn.NextPacketTag() == PacketTag.Signature) + { + try + { + l.Add(new PgpSignature(bcpgIn)); + } + catch (PgpException e) + { + throw new IOException("can't create signature object: " + e); + } + } + + return new PgpSignatureList( + (PgpSignature[]) l.ToArray(typeof(PgpSignature))); + } + case PacketTag.SecretKey: + try + { + return new PgpSecretKeyRing(bcpgIn); + } + catch (PgpException e) + { + throw new IOException("can't create secret key object: " + e); + } + case PacketTag.PublicKey: + return new PgpPublicKeyRing(bcpgIn); + case PacketTag.CompressedData: + return new PgpCompressedData(bcpgIn); + case PacketTag.LiteralData: + return new PgpLiteralData(bcpgIn); + case PacketTag.PublicKeyEncryptedSession: + case PacketTag.SymmetricKeyEncryptedSessionKey: + return new PgpEncryptedDataList(bcpgIn); + case PacketTag.OnePassSignature: + { + ArrayList l = new ArrayList(); + + while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature) + { + try + { + l.Add(new PgpOnePassSignature(bcpgIn)); + } + catch (PgpException e) + { + throw new IOException("can't create one pass signature object: " + e); + } + } + + return new PgpOnePassSignatureList( + (PgpOnePassSignature[]) l.ToArray(typeof(PgpOnePassSignature))); + } + case PacketTag.Marker: + return new PgpMarker(bcpgIn); + case PacketTag.Experimental1: + case PacketTag.Experimental2: + case PacketTag.Experimental3: + case PacketTag.Experimental4: + return new PgpExperimental(bcpgIn); + } + + throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag()); + } + + [Obsolete("Use NextPgpObject() instead")] + public object NextObject() + { + return NextPgpObject(); + } + + /// + /// Return all available objects in a list. + /// + /// An IList containing all objects from this factory, in order. + public IList AllPgpObjects() + { + ArrayList result = new ArrayList(); + PgpObject pgpObject; + while ((pgpObject = NextPgpObject()) != null) + { + result.Add(pgpObject); + } + return result; + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpOnePassSignature.cs b/iTechSharp/srcbc/openpgp/PgpOnePassSignature.cs new file mode 100644 index 0000000..d82025c --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpOnePassSignature.cs @@ -0,0 +1,179 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A one pass signature object. + public class PgpOnePassSignature + { + private OnePassSignaturePacket sigPack; + private int signatureType; + private ISigner sig; + private byte lastb; + + internal PgpOnePassSignature( + BcpgInputStream bcpgInput) + : this((OnePassSignaturePacket) bcpgInput.ReadPacket()) + { + } + + internal PgpOnePassSignature( + OnePassSignaturePacket sigPack) + { + this.sigPack = sigPack; + this.signatureType = sigPack.SignatureType; + + try + { + this.sig = SignerUtilities.GetSigner( + PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm)); + } + catch (Exception e) + { + throw new PgpException("can't set up signature object.", e); + } + } + + /// Initialise the signature object for verification. + public void InitVerify( + PgpPublicKey pubKey) + { + lastb = 0; + + try + { + sig.Init(false, pubKey.GetKey()); + } + catch (InvalidKeyException e) + { + throw new PgpException("invalid key.", e); + } + } + + public void Update( + byte b) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + doCanonicalUpdateByte(b); + } + else + { + sig.Update(b); + } + } + + private void doCanonicalUpdateByte( + byte b) + { + if (b == '\r') + { + doUpdateCRLF(); + } + else if (b == '\n') + { + if (lastb != '\r') + { + doUpdateCRLF(); + } + } + else + { + sig.Update(b); + } + + lastb = b; + } + + private void doUpdateCRLF() + { + sig.Update((byte)'\r'); + sig.Update((byte)'\n'); + } + + public void Update( + byte[] bytes) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + for (int i = 0; i != bytes.Length; i++) + { + doCanonicalUpdateByte(bytes[i]); + } + } + else + { + sig.BlockUpdate(bytes, 0, bytes.Length); + } + } + + public void Update( + byte[] bytes, + int off, + int length) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + int finish = off + length; + + for (int i = off; i != finish; i++) + { + doCanonicalUpdateByte(bytes[i]); + } + } + else + { + sig.BlockUpdate(bytes, off, length); + } + } + + /// Verify the calculated signature against the passed in PgpSignature. + public bool Verify( + PgpSignature pgpSig) + { + byte[] trailer = pgpSig.GetSignatureTrailer(); + + sig.BlockUpdate(trailer, 0, trailer.Length); + + return sig.VerifySignature(pgpSig.GetSignature()); + } + + public long KeyId + { + get { return sigPack.KeyId; } + } + + public int SignatureType + { + get { return sigPack.SignatureType; } + } + + public HashAlgorithmTag HashAlgorithm + { + get { return sigPack.HashAlgorithm; } + } + + public PublicKeyAlgorithmTag KeyAlgorithm + { + get { return sigPack.KeyAlgorithm; } + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream.Wrap(outStr).WritePacket(sigPack); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpOnePassSignatureList.cs b/iTechSharp/srcbc/openpgp/PgpOnePassSignatureList.cs new file mode 100644 index 0000000..37c4288 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpOnePassSignatureList.cs @@ -0,0 +1,51 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Holder for a list of PgpOnePassSignature objects. + public class PgpOnePassSignatureList + : PgpObject + { + private readonly PgpOnePassSignature[] sigs; + + public PgpOnePassSignatureList( + PgpOnePassSignature[] sigs) + { + this.sigs = (PgpOnePassSignature[]) sigs.Clone(); + } + + public PgpOnePassSignatureList( + PgpOnePassSignature sig) + { + this.sigs = new PgpOnePassSignature[]{ sig }; + } + + public PgpOnePassSignature this[int index] + { + get { return sigs[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public PgpOnePassSignature Get( + int index) + { + return this[index]; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return sigs.Length; } + } + + public int Count + { + get { return sigs.Length; } + } + + public bool IsEmpty + { + get { return (sigs.Length == 0); } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs b/iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs new file mode 100644 index 0000000..c5fe894 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs @@ -0,0 +1,135 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A password based encryption object. + public class PgpPbeEncryptedData + : PgpEncryptedData + { + private readonly SymmetricKeyEncSessionPacket keyData; + + internal PgpPbeEncryptedData( + SymmetricKeyEncSessionPacket keyData, + InputStreamPacket encData) + : base(encData) + { + this.keyData = keyData; + } + + /// Return the raw input stream for the data stream. + public override Stream GetInputStream() + { + return encData.GetInputStream(); + } + + /// Return the decrypted input stream, using the passed in passphrase. + public Stream GetDataStream( + char[] passPhrase) + { + try + { + SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm; + + KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase( + keyAlgorithm, keyData.S2k, passPhrase); + + + byte[] secKeyData = keyData.GetSecKeyData(); + if (secKeyData != null && secKeyData.Length > 0) + { + IBufferedCipher keyCipher = CipherUtilities.GetCipher( + PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding"); + + keyCipher.Init(false, + new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()])); + + byte[] keyBytes = keyCipher.DoFinal(secKeyData); + + keyAlgorithm = (SymmetricKeyAlgorithmTag) keyBytes[0]; + + key = ParameterUtilities.CreateKeyParameter( + PgpUtilities.GetSymmetricCipherName(keyAlgorithm), + keyBytes, 1, keyBytes.Length - 1); + } + + + IBufferedCipher c = CreateStreamCipher(keyAlgorithm); + + byte[] iv = new byte[c.GetBlockSize()]; + + c.Init(false, new ParametersWithIV(key, iv)); + + encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c, null)); + + if (encData is SymmetricEncIntegrityPacket) + { + truncStream = new TruncatedStream(encStream); + + string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); + IDigest digest = DigestUtilities.GetDigest(digestName); + + encStream = new DigestStream(truncStream, digest, null); + } + + if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length) + throw new EndOfStreamException("unexpected end of stream."); + + int v1 = encStream.ReadByte(); + int v2 = encStream.ReadByte(); + + if (v1 < 0 || v2 < 0) + throw new EndOfStreamException("unexpected end of stream."); + + + // Note: the oracle attack on the "quick check" bytes is not deemed + // a security risk for PBE (see PgpPublicKeyEncryptedData) + + bool repeatCheckPassed = + iv[iv.Length - 2] == (byte)v1 + && iv[iv.Length - 1] == (byte)v2; + + // Note: some versions of PGP appear to produce 0 for the extra + // bytes rather than repeating the two previous bytes + bool zeroesCheckPassed = + v1 == 0 + && v2 == 0; + + if (!repeatCheckPassed && !zeroesCheckPassed) + { + throw new PgpDataValidationException("quick check failed."); + } + + + return encStream; + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + } + + private IBufferedCipher CreateStreamCipher( + SymmetricKeyAlgorithmTag keyAlgorithm) + { + string mode = (encData is SymmetricEncIntegrityPacket) + ? "CFB" + : "OpenPGPCFB"; + + string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + + "/" + mode + "/NoPadding"; + + return CipherUtilities.GetCipher(cName); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpPrivateKey.cs b/iTechSharp/srcbc/openpgp/PgpPrivateKey.cs new file mode 100644 index 0000000..154c87c --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpPrivateKey.cs @@ -0,0 +1,42 @@ +using System; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// General class to contain a private key for use with other OpenPGP objects. + public class PgpPrivateKey + { + private readonly long keyId; + private readonly AsymmetricKeyParameter privateKey; + + /// + /// Create a PgpPrivateKey from a regular private key and the ID of its + /// associated public key. + /// + /// Private key to use. + /// ID of the corresponding public key. + public PgpPrivateKey( + AsymmetricKeyParameter privateKey, + long keyId) + { + if (!privateKey.IsPrivate) + throw new ArgumentException("Expected a private key", "privateKey"); + + this.privateKey = privateKey; + this.keyId = keyId; + } + + /// The keyId associated with the contained private key. + public long KeyId + { + get { return keyId; } + } + + /// The contained private key. + public AsymmetricKeyParameter Key + { + get { return privateKey; } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpPublicKey.cs b/iTechSharp/srcbc/openpgp/PgpPublicKey.cs new file mode 100644 index 0000000..9a95f01 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpPublicKey.cs @@ -0,0 +1,835 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// General class to handle a PGP public key object. + public class PgpPublicKey + { + private static readonly int[] MasterKeyCertificationTypes = new int[] + { + PgpSignature.PositiveCertification, + PgpSignature.CasualCertification, + PgpSignature.NoCertification, + PgpSignature.DefaultCertification + }; + + private long keyId; + private byte[] fingerprint; + private int keyStrength; + + internal PublicKeyPacket publicPk; + private TrustPacket trustPk; + private ArrayList keySigs = new ArrayList(); + private ArrayList ids = new ArrayList(); + private ArrayList idTrusts = new ArrayList(); + private ArrayList idSigs = new ArrayList(); + private ArrayList subSigs; + + private void Init() + { + IBcpgKey key = publicPk.Key; + + if (publicPk.Version <= 3) + { + RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key; + + this.keyId = rK.Modulus.LongValue; + + try + { + IDigest digest = DigestUtilities.GetDigest("MD5"); + + byte[] bytes = rK.Modulus.ToByteArrayUnsigned(); + digest.BlockUpdate(bytes, 0, bytes.Length); + + bytes = rK.PublicExponent.ToByteArrayUnsigned(); + digest.BlockUpdate(bytes, 0, bytes.Length); + + this.fingerprint = DigestUtilities.DoFinal(digest); + } + //catch (NoSuchAlgorithmException) + catch (Exception) + { + throw new IOException("can't find MD5"); + } + + this.keyStrength = rK.Modulus.BitLength; + } + else + { + byte[] kBytes = publicPk.GetEncodedContents(); + + try + { + IDigest digest = DigestUtilities.GetDigest("SHA1"); + + digest.Update(0x99); + digest.Update((byte)(kBytes.Length >> 8)); + digest.Update((byte)kBytes.Length); + digest.BlockUpdate(kBytes, 0, kBytes.Length); + this.fingerprint = DigestUtilities.DoFinal(digest); + } + //catch (NoSuchAlgorithmException) + catch (Exception) + { + throw new IOException("can't find SHA1"); + } + + this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56) + | ((ulong)fingerprint[fingerprint.Length - 7] << 48) + | ((ulong)fingerprint[fingerprint.Length - 6] << 40) + | ((ulong)fingerprint[fingerprint.Length - 5] << 32) + | ((ulong)fingerprint[fingerprint.Length - 4] << 24) + | ((ulong)fingerprint[fingerprint.Length - 3] << 16) + | ((ulong)fingerprint[fingerprint.Length - 2] << 8) + | (ulong)fingerprint[fingerprint.Length - 1]); + + if (key is RsaPublicBcpgKey) + { + this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength; + } + else if (key is DsaPublicBcpgKey) + { + this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength; + } + else if (key is ElGamalPublicBcpgKey) + { + this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength; + } + } + } + + /// + /// Create a PgpPublicKey from the passed in lightweight one. + /// + /// + /// Note: the time passed in affects the value of the key's keyId, so you probably only want + /// to do this once for a lightweight key, or make sure you keep track of the time you used. + /// + /// Asymmetric algorithm type representing the public key. + /// Actual public key to associate. + /// Date of creation. + /// If pubKey is not public. + /// On key creation problem. + public PgpPublicKey( + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + DateTime time) + { + if (pubKey.IsPrivate) + throw new ArgumentException("Expected a public key", "pubKey"); + + IBcpgKey bcpgKey; + if (pubKey is RsaKeyParameters) + { + RsaKeyParameters rK = (RsaKeyParameters) pubKey; + + bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent); + } + else if (pubKey is DsaPublicKeyParameters) + { + DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey; + DsaParameters dP = dK.Parameters; + + bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y); + } + else if (pubKey is ElGamalPublicKeyParameters) + { + ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey; + ElGamalParameters eS = eK.Parameters; + + bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y); + } + else + { + throw new PgpException("unknown key class"); + } + + this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey); + this.ids = new ArrayList(); + this.idSigs = new ArrayList(); + + try + { + Init(); + } + catch (IOException e) + { + throw new PgpException("exception calculating keyId", e); + } + } + + /// Constructor for a sub-key. + internal PgpPublicKey( + PublicKeyPacket publicPk, + TrustPacket trustPk, + ArrayList sigs) + { + this.publicPk = publicPk; + this.trustPk = trustPk; + this.subSigs = sigs; + + Init(); + } + + internal PgpPublicKey( + PgpPublicKey key, + TrustPacket trust, + ArrayList subSigs) + { + this.publicPk = key.publicPk; + this.trustPk = trust; + this.subSigs = subSigs; + + this.fingerprint = key.fingerprint; + this.keyId = key.keyId; + this.keyStrength = key.keyStrength; + } + + /// Copy constructor. + /// The public key to copy. + internal PgpPublicKey( + PgpPublicKey pubKey) + { + this.publicPk = pubKey.publicPk; + + this.keySigs = new ArrayList(pubKey.keySigs); + this.ids = new ArrayList(pubKey.ids); + this.idTrusts = new ArrayList(pubKey.idTrusts); + this.idSigs = new ArrayList(pubKey.idSigs.Count); + for (int i = 0; i != pubKey.idSigs.Count; i++) + { + this.idSigs.Add(new ArrayList((ArrayList)pubKey.idSigs[i])); + } + + if (pubKey.subSigs != null) + { + this.subSigs = new ArrayList(pubKey.subSigs.Count); + for (int i = 0; i != pubKey.subSigs.Count; i++) + { + this.subSigs.Add(pubKey.subSigs[i]); + } + } + + this.fingerprint = pubKey.fingerprint; + this.keyId = pubKey.keyId; + this.keyStrength = pubKey.keyStrength; + } + + internal PgpPublicKey( + PublicKeyPacket publicPk, + TrustPacket trustPk, + ArrayList keySigs, + ArrayList ids, + ArrayList idTrusts, + ArrayList idSigs) + { + this.publicPk = publicPk; + this.trustPk = trustPk; + this.keySigs = keySigs; + this.ids = ids; + this.idTrusts = idTrusts; + this.idSigs = idSigs; + + Init(); + } + + internal PgpPublicKey( + PublicKeyPacket publicPk, + ArrayList ids, + ArrayList idSigs) + { + this.publicPk = publicPk; + this.ids = ids; + this.idSigs = idSigs; + Init(); + } + + /// The version of this key. + public int Version + { + get { return publicPk.Version; } + } + + /// The creation time of this key. + public DateTime CreationTime + { + get { return publicPk.GetTime(); } + } + + /// The number of valid days from creation time - zero means no expiry. + public int ValidDays + { + get + { + if (publicPk.Version > 3) + { + return (int)(GetValidSeconds() / (24 * 60 * 60)); + } + + return publicPk.ValidDays; + } + } + + /// Return the trust data associated with the public key, if present. + /// A byte array with trust data, null otherwise. + public byte[] GetTrustData() + { + if (trustPk == null) + { + return null; + } + + return trustPk.GetLevelAndTrustAmount(); + } + + /// The number of valid seconds from creation time - zero means no expiry. + public long GetValidSeconds() + { + if (publicPk.Version > 3) + { + if (IsMasterKey) + { + for (int i = 0; i != MasterKeyCertificationTypes.Length; i++) + { + long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]); + + if (seconds >= 0) + { + return seconds; + } + } + } + else + { + long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding); + + if (seconds >= 0) + { + return seconds; + } + } + + return 0; + } + + return (long) publicPk.ValidDays * 24 * 60 * 60; + } + + private long GetExpirationTimeFromSig( + bool selfSigned, + int signatureType) + { + foreach (PgpSignature sig in GetSignaturesOfType(signatureType)) + { + if (!selfSigned || sig.KeyId == KeyId) + { + PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets(); + + if (hashed != null) + { + return hashed.GetKeyExpirationTime(); + } + + return 0; + } + } + + return -1; + } + + /// The keyId associated with the public key. + public long KeyId + { + get { return keyId; } + } + + /// The fingerprint of the key + public byte[] GetFingerprint() + { + return (byte[]) fingerprint.Clone(); + } + + + /// True, if this key is marked as suitable for encryption + /// True, if this key is marked as suitable for using for encryption. + public bool IsEncryptionKey + { + get + { + switch (publicPk.Algorithm) + { + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + return true; + default: + return false; + } + } + } + + /// True, if this is a master key. + public bool IsMasterKey + { + get { return subSigs == null; } + } + + /// The algorithm code associated with the public key. + public PublicKeyAlgorithmTag Algorithm + { + get { return publicPk.Algorithm; } + } + + /// The strength of the key in bits. + public int BitStrength + { + get { return keyStrength; } + } + + /// The public key contained in the object. + /// A lightweight public key. + /// If the key algorithm is not recognised. + public AsymmetricKeyParameter GetKey() + { + try + { + switch (publicPk.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key; + return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent); + case PublicKeyAlgorithmTag.Dsa: + DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key; + return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G)); + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key; + return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G)); + default: + throw new PgpException("unknown public key algorithm encountered"); + } + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("exception constructing public key", e); + } + } + + /// Allows enumeration of any user IDs associated with the key. + /// An IEnumerable of string objects. + public IEnumerable GetUserIds() + { + ArrayList temp = new ArrayList(); + + foreach (object o in ids) + { + if (o is string) + { + temp.Add(o); + } + } + + return new EnumerableProxy(temp); + } + + /// Allows enumeration of any user attribute vectors associated with the key. + /// An IEnumerable of PgpUserAttributeSubpacketVector objects. + public IEnumerable GetUserAttributes() + { + ArrayList temp = new ArrayList(); + + foreach (object o in ids) + { + if (o is PgpUserAttributeSubpacketVector) + { + temp.Add(o); + } + } + + return new EnumerableProxy(temp); + } + + /// Allows enumeration of any signatures associated with the passed in id. + /// The ID to be matched. + /// An IEnumerable of PgpSignature objects. + public IEnumerable GetSignaturesForId( + string id) + { + if (id == null) + throw new ArgumentNullException("id"); + + for (int i = 0; i != ids.Count; i++) + { + if (id.Equals(ids[i])) + { + return new EnumerableProxy((ArrayList) idSigs[i]); + } + } + + return null; + } + + /// Allows enumeration of signatures associated with the passed in user attributes. + /// The vector of user attributes to be matched. + /// An IEnumerable of PgpSignature objects. + public IEnumerable GetSignaturesForUserAttribute( + PgpUserAttributeSubpacketVector userAttributes) + { + for (int i = 0; i != ids.Count; i++) + { + if (userAttributes.Equals(ids[i])) + { + return new EnumerableProxy((ArrayList) idSigs[i]); + } + } + + return null; + } + + /// Allows enumeration of signatures of the passed in type that are on this key. + /// The type of the signature to be returned. + /// An IEnumerable of PgpSignature objects. + public IEnumerable GetSignaturesOfType( + int signatureType) + { + ArrayList temp = new ArrayList(); + + foreach (PgpSignature sig in GetSignatures()) + { + if (sig.SignatureType == signatureType) + { + temp.Add(sig); + } + } + + return new EnumerableProxy(temp); + } + + /// Allows enumeration of all signatures/certifications associated with this key. + /// An IEnumerable with all signatures/certifications. + public IEnumerable GetSignatures() + { + ArrayList sigs; + if (subSigs != null) + { + sigs = subSigs; + } + else + { + sigs = new ArrayList(keySigs); + + foreach (ICollection extraSigs in idSigs) + { + sigs.AddRange(extraSigs); + } + } + + return new EnumerableProxy(sigs); + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + Encode(bOut); + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); + + bcpgOut.WritePacket(publicPk); + if (trustPk != null) + { + bcpgOut.WritePacket(trustPk); + } + + if (subSigs == null) // not a sub-key + { + foreach (PgpSignature keySig in keySigs) + { + keySig.Encode(bcpgOut); + } + + for (int i = 0; i != ids.Count; i++) + { + if (ids[i] is string) + { + string id = (string) ids[i]; + + bcpgOut.WritePacket(new UserIdPacket(id)); + } + else + { + PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i]; + bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray())); + } + + if (idTrusts[i] != null) + { + bcpgOut.WritePacket((ContainedPacket)idTrusts[i]); + } + + foreach (PgpSignature sig in (ArrayList) idSigs[i]) + { + sig.Encode(bcpgOut); + } + } + } + else + { + foreach (PgpSignature subSig in subSigs) + { + subSig.Encode(bcpgOut); + } + } + } + + /// Check whether this (sub)key has a revocation signature on it. + /// True, if this (sub)key has been revoked. + public bool IsRevoked() + { + int ns = 0; + bool revoked = false; + if (IsMasterKey) // Master key + { + while (!revoked && (ns < keySigs.Count)) + { + if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation) + { + revoked = true; + } + } + } + else // Sub-key + { + while (!revoked && (ns < subSigs.Count)) + { + if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation) + { + revoked = true; + } + } + } + return revoked; + } + + /// Add a certification for an id to the given public key. + /// The key the certification is to be added to. + /// The ID the certification is associated with. + /// The new certification. + /// The re-certified key. + public static PgpPublicKey AddCertification( + PgpPublicKey key, + string id, + PgpSignature certification) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + ArrayList sigList = null; + + for (int i = 0; i != returnKey.ids.Count; i++) + { + if (id.Equals(returnKey.ids[i])) + { + sigList = (ArrayList) returnKey.idSigs[i]; + } + } + + if (sigList != null) + { + sigList.Add(certification); + } + else + { + sigList = new ArrayList(); + + sigList.Add(certification); + returnKey.ids.Add(id); + returnKey.idTrusts.Add(null); + returnKey.idSigs.Add(sigList); + } + + return returnKey; + } + + /// Add a certification for the given UserAttributeSubpackets to the given public key. + /// The key the certification is to be added to. + /// The attributes the certification is associated with. + /// The new certification. + /// The re-certified key. + public static PgpPublicKey AddCertification( + PgpPublicKey key, + PgpUserAttributeSubpacketVector userAttributes, + PgpSignature certification) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + IList sigList = null; + + for (int i = 0; i != returnKey.ids.Count; i++) + { + if (userAttributes.Equals(returnKey.ids[i])) + { + sigList = (IList) returnKey.idSigs[i]; + } + } + + if (sigList != null) + { + sigList.Add(certification); + } + else + { + sigList = new ArrayList(); + sigList.Add(certification); + returnKey.ids.Add(userAttributes); + returnKey.idTrusts.Add(null); + returnKey.idSigs.Add(sigList); + } + + return returnKey; + } + + /// + /// Remove any certifications associated with a user attribute subpacket on a key. + /// + /// The key the certifications are to be removed from. + /// The attributes to be removed. + /// + /// The re-certified key, or null if the user attribute subpacket was not found on the key. + /// + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + PgpUserAttributeSubpacketVector userAttributes) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + bool found = false; + + for (int i = 0; i < returnKey.ids.Count; i++) + { + if (userAttributes.Equals(returnKey.ids[i])) + { + found = true; + returnKey.ids.RemoveAt(i); + returnKey.idTrusts.RemoveAt(i); + returnKey.idSigs.RemoveAt(i); + } + } + + if (!found) + { + return null; + } + + return returnKey; + } + + /// Remove any certifications associated with a given ID on a key. + /// The key the certifications are to be removed from. + /// The ID that is to be removed. + /// The re-certified key, or null if the ID was not found on the key. + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + string id) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + bool found = false; + + for (int i = 0; i < returnKey.ids.Count; i++) + { + if (id.Equals(returnKey.ids[i])) + { + found = true; + returnKey.ids.RemoveAt(i); + returnKey.idTrusts.RemoveAt(i); + returnKey.idSigs.RemoveAt(i); + } + } + + return found ? returnKey : null; + } + + /// Remove any certifications associated with a given ID on a key. + /// The key the certifications are to be removed from. + /// The ID that the certfication is to be removed from. + /// The certfication to be removed. + /// The re-certified key, or null if the certification was not found. + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + string id, + PgpSignature certification) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + bool found = false; + + for (int i = 0; i < returnKey.ids.Count; i++) + { + if (id.Equals(returnKey.ids[i])) + { + ArrayList certs = (ArrayList) returnKey.idSigs[i]; + found = certs.Contains(certification); + + if (found) + { + certs.Remove(certification); + } + } + } + + return found ? returnKey : null; + } + + /// Add a revocation or some other key certification to a key. + /// The key the revocation is to be added to. + /// The key signature to be added. + /// The new changed public key object. + public static PgpPublicKey AddCertification( + PgpPublicKey key, + PgpSignature certification) + { + if (key.IsMasterKey) + { + if (certification.SignatureType == PgpSignature.SubkeyRevocation) + { + throw new ArgumentException("signature type incorrect for master key revocation."); + } + } + else + { + if (certification.SignatureType == PgpSignature.KeyRevocation) + { + throw new ArgumentException("signature type incorrect for sub-key revocation."); + } + } + + PgpPublicKey returnKey = new PgpPublicKey(key); + + if (returnKey.subSigs != null) + { + returnKey.subSigs.Add(certification); + } + else + { + returnKey.keySigs.Add(certification); + } + + return returnKey; + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpPublicKeyEncryptedData.cs b/iTechSharp/srcbc/openpgp/PgpPublicKeyEncryptedData.cs new file mode 100644 index 0000000..c4fd729 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpPublicKeyEncryptedData.cs @@ -0,0 +1,233 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A public key encrypted data object. + public class PgpPublicKeyEncryptedData + : PgpEncryptedData + { + private PublicKeyEncSessionPacket keyData; + + internal PgpPublicKeyEncryptedData( + PublicKeyEncSessionPacket keyData, + InputStreamPacket encData) + : base(encData) + { + this.keyData = keyData; + } + + private static IBufferedCipher GetKeyCipher( + PublicKeyAlgorithmTag algorithm) + { + try + { + switch (algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + return CipherUtilities.GetCipher("RSA//PKCS1Padding"); + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding"); + default: + throw new PgpException("unknown asymmetric algorithm: " + algorithm); + } + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + } + + private bool ConfirmCheckSum( + byte[] sessionInfo) + { + int check = 0; + + for (int i = 1; i != sessionInfo.Length - 2; i++) + { + check += sessionInfo[i] & 0xff; + } + + return (sessionInfo[sessionInfo.Length - 2] == (byte)(check >> 8)) + && (sessionInfo[sessionInfo.Length - 1] == (byte)(check)); + } + + /// The key ID for the key used to encrypt the data. + public long KeyId + { + get { return keyData.KeyId; } + } + + /// Return the decrypted data stream for the packet. + public Stream GetDataStream( + PgpPrivateKey privKey) + { + IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm); + + try + { + c1.Init(false, privKey.Key); + } + catch (InvalidKeyException e) + { + throw new PgpException("error setting asymmetric cipher", e); + } + + BigInteger[] keyD = keyData.GetEncSessionKey(); + + if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt + || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral) + { + c1.ProcessBytes(keyD[0].ToByteArrayUnsigned()); + } + else + { + ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key; + int size = (k.Parameters.P.BitLength + 7) / 8; + + byte[] bi = keyD[0].ToByteArray(); + + int diff = bi.Length - size; + if (diff >= 0) + { + c1.ProcessBytes(bi, diff, size); + } + else + { + byte[] zeros = new byte[-diff]; + c1.ProcessBytes(zeros); + c1.ProcessBytes(bi); + } + + bi = keyD[1].ToByteArray(); + + diff = bi.Length - size; + if (diff >= 0) + { + c1.ProcessBytes(bi, diff, size); + } + else + { + byte[] zeros = new byte[-diff]; + c1.ProcessBytes(zeros); + c1.ProcessBytes(bi); + } + } + + byte[] plain; + try + { + plain = c1.DoFinal(); + } + catch (Exception e) + { + throw new PgpException("exception decrypting secret key", e); + } + + if (!ConfirmCheckSum(plain)) + throw new PgpKeyValidationException("key checksum failed"); + + IBufferedCipher c2; + string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]); + string cName = cipherName; + + try + { + if (encData is SymmetricEncIntegrityPacket) + { + cName += "/CFB/NoPadding"; + } + else + { + cName += "/OpenPGPCFB/NoPadding"; + } + + c2 = CipherUtilities.GetCipher(cName); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("exception creating cipher", e); + } + + if (c2 == null) + return encData.GetInputStream(); + + try + { + KeyParameter key = ParameterUtilities.CreateKeyParameter( + cipherName, plain, 1, plain.Length - 3); + + byte[] iv = new byte[c2.GetBlockSize()]; + + c2.Init(false, new ParametersWithIV(key, iv)); + + encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null)); + + if (encData is SymmetricEncIntegrityPacket) + { + truncStream = new TruncatedStream(encStream); + + string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1); + IDigest digest = DigestUtilities.GetDigest(digestName); + + encStream = new DigestStream(truncStream, digest, null); + } + + if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length) + throw new EndOfStreamException("unexpected end of stream."); + + int v1 = encStream.ReadByte(); + int v2 = encStream.ReadByte(); + + if (v1 < 0 || v2 < 0) + throw new EndOfStreamException("unexpected end of stream."); + + // Note: the oracle attack on the "quick check" bytes is deemed + // a security risk for typical public key encryption usages, + // therefore we do not perform the check. + +// bool repeatCheckPassed = +// iv[iv.Length - 2] == (byte)v1 +// && iv[iv.Length - 1] == (byte)v2; +// +// // Note: some versions of PGP appear to produce 0 for the extra +// // bytes rather than repeating the two previous bytes +// bool zeroesCheckPassed = +// v1 == 0 +// && v2 == 0; +// +// if (!repeatCheckPassed && !zeroesCheckPassed) +// { +// throw new PgpDataValidationException("quick check failed."); +// } + + return encStream; + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception starting decryption", e); + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs b/iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs new file mode 100644 index 0000000..33f45fb --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Class to hold a single master public key and its subkeys. + ///

      + /// Often PGP keyring files consist of multiple master keys, if you are trying to process + /// or construct one of these you should use the PgpPublicKeyRingBundle class. + ///

      + ///
      + public class PgpPublicKeyRing + : PgpKeyRing + { + private readonly ArrayList keys; + + public PgpPublicKeyRing( + byte[] encoding) + : this(new MemoryStream(encoding, false)) + { + } + + internal PgpPublicKeyRing( + ArrayList pubKeys) + { + this.keys = pubKeys; + } + + public PgpPublicKeyRing( + Stream inputStream) + { + this.keys = new ArrayList(); + + BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream); + + PacketTag initialTag = bcpgInput.NextPacketTag(); + if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey) + { + throw new IOException("public key ring doesn't start with public key tag: " + + "tag 0x" + ((int)initialTag).ToString("X")); + } + + PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();; + TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput); + + // direct signatures and revocations + ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput); + + ArrayList ids, idTrusts, idSigs; + ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); + + keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs)); + + + // Read subkeys + while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey) + { + PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket(); + TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput); + + // PGP 8 actually leaves out the signature. + ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); + + keys.Add(new PgpPublicKey(pk, kTrust, sigList)); + } + } + + /// Return the first public key in the ring. + public PgpPublicKey GetPublicKey() + { + return (PgpPublicKey) keys[0]; + } + + /// Return the public key referred to by the passed in key ID if it is present. + public PgpPublicKey GetPublicKey( + long keyId) + { + foreach (PgpPublicKey k in keys) + { + if (keyId == k.KeyId) + { + return k; + } + } + + return null; + } + + /// Allows enumeration of all the public keys. + /// An IEnumerable of PgpPublicKey objects. + public IEnumerable GetPublicKeys() + { + return new EnumerableProxy(keys); + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + foreach (PgpPublicKey k in keys) + { + k.Encode(outStr); + } + } + + /// + /// Returns a new key ring with the public key passed in either added or + /// replacing an existing one. + /// + /// The public key ring to be modified. + /// The public key to be inserted. + /// A new PgpPublicKeyRing + public static PgpPublicKeyRing InsertPublicKey( + PgpPublicKeyRing pubRing, + PgpPublicKey pubKey) + { + ArrayList keys = new ArrayList(pubRing.keys); + bool found = false; + bool masterFound = false; + + for (int i = 0; i != keys.Count; i++) + { + PgpPublicKey key = (PgpPublicKey) keys[i]; + + if (key.KeyId == pubKey.KeyId) + { + found = true; + keys[i] = pubKey; + } + if (key.IsMasterKey) + { + masterFound = true; + } + } + + if (!found) + { + if (pubKey.IsMasterKey && masterFound) + throw new ArgumentException("cannot add a master key to a ring that already has one"); + + keys.Add(pubKey); + } + + return new PgpPublicKeyRing(keys); + } + + /// Returns a new key ring with the public key passed in removed from the key ring. + /// The public key ring to be modified. + /// The public key to be removed. + /// A new PgpPublicKeyRing, or null if pubKey is not found. + public static PgpPublicKeyRing RemovePublicKey( + PgpPublicKeyRing pubRing, + PgpPublicKey pubKey) + { + ArrayList keys = new ArrayList(pubRing.keys); + bool found = false; + + for (int i = 0; i < keys.Count; i++) + { + PgpPublicKey key = (PgpPublicKey) keys[i]; + + if (key.KeyId == pubKey.KeyId) + { + found = true; + keys.RemoveAt(i); + } + } + + return found ? new PgpPublicKeyRing(keys) : null; + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpPublicKeyRingBundle.cs b/iTechSharp/srcbc/openpgp/PgpPublicKeyRingBundle.cs new file mode 100644 index 0000000..4d79022 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpPublicKeyRingBundle.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Often a PGP key ring file is made up of a succession of master/sub-key key rings. + /// If you want to read an entire public key file in one hit this is the class for you. + /// + public class PgpPublicKeyRingBundle + { + private readonly IDictionary pubRings; + private readonly ArrayList order; + + private PgpPublicKeyRingBundle( + IDictionary pubRings, + ArrayList order) + { + this.pubRings = pubRings; + this.order = order; + } + + public PgpPublicKeyRingBundle( + byte[] encoding) + : this(new MemoryStream(encoding, false)) + { + } + + /// Build a PgpPubliKeyRingBundle from the passed in input stream. + /// Input stream containing data. + /// If a problem parsing the stream occurs. + /// If an object is encountered which isn't a PgpPublicKeyRing. + public PgpPublicKeyRingBundle( + Stream inputStream) + : this(new PgpObjectFactory(inputStream).AllPgpObjects()) + { + } + + public PgpPublicKeyRingBundle( + IEnumerable e) + { + this.pubRings = new Hashtable(); + this.order = new ArrayList(); + + foreach (object obj in e) + { + PgpPublicKeyRing pgpPub = obj as PgpPublicKeyRing; + + if (pgpPub == null) + { + throw new PgpException(obj.GetType().FullName + " found where PgpPublicKeyRing expected"); + } + + long key = pgpPub.GetPublicKey().KeyId; + pubRings.Add(key, pgpPub); + order.Add(key); + } + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return order.Count; } + } + + /// Return the number of rings in this collection. + public int Count + { + get { return order.Count; } + } + + /// Allow enumeration of the public key rings making up this collection. + public IEnumerable GetKeyRings() + { + return new EnumerableProxy(pubRings.Values); + } + + /// Allow enumeration of the key rings associated with the passed in userId. + /// The user ID to be matched. + /// An IEnumerable of key rings which matched (possibly none). + public IEnumerable GetKeyRings( + string userId) + { + return GetKeyRings(userId, false, false); + } + + /// Allow enumeration of the key rings associated with the passed in userId. + /// The user ID to be matched. + /// If true, userId need only be a substring of an actual ID string to match. + /// An IEnumerable of key rings which matched (possibly none). + public IEnumerable GetKeyRings( + string userId, + bool matchPartial) + { + return GetKeyRings(userId, matchPartial, false); + } + + /// Allow enumeration of the key rings associated with the passed in userId. + /// The user ID to be matched. + /// If true, userId need only be a substring of an actual ID string to match. + /// If true, case is ignored in user ID comparisons. + /// An IEnumerable of key rings which matched (possibly none). + public IEnumerable GetKeyRings( + string userId, + bool matchPartial, + bool ignoreCase) + { + IList rings = new ArrayList(); + + if (ignoreCase) + { + userId = userId.ToLower(CultureInfo.InvariantCulture); + } + + foreach (PgpPublicKeyRing pubRing in GetKeyRings()) + { + foreach (string nextUserID in pubRing.GetPublicKey().GetUserIds()) + { + string next = nextUserID; + if (ignoreCase) + { + next = next.ToLower(CultureInfo.InvariantCulture); + } + + if (matchPartial) + { + if (next.IndexOf(userId) > -1) + { + rings.Add(pubRing); + } + } + else + { + if (next.Equals(userId)) + { + rings.Add(pubRing); + } + } + } + } + + return new EnumerableProxy(rings); + } + + /// Return the PGP public key associated with the given key id. + /// The ID of the public key to return. + public PgpPublicKey GetPublicKey( + long keyId) + { + foreach (PgpPublicKeyRing pubRing in GetKeyRings()) + { + PgpPublicKey pub = pubRing.GetPublicKey(keyId); + + if (pub != null) + { + return pub; + } + } + + return null; + } + + /// Return the public key ring which contains the key referred to by keyId + /// The ID of the public key + public PgpPublicKeyRing GetPublicKeyRing( + long keyId) + { + if (pubRings.Contains(keyId)) + { + return (PgpPublicKeyRing)pubRings[keyId]; + } + + foreach (PgpPublicKeyRing pubRing in GetKeyRings()) + { + PgpPublicKey pub = pubRing.GetPublicKey(keyId); + + if (pub != null) + { + return pubRing; + } + } + + return null; + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); + + foreach (long key in order) + { + PgpPublicKeyRing sec = (PgpPublicKeyRing) pubRings[key]; + + sec.Encode(bcpgOut); + } + } + + /// + /// Return a new bundle containing the contents of the passed in bundle and + /// the passed in public key ring. + /// + /// The PgpPublicKeyRingBundle the key ring is to be added to. + /// The key ring to be added. + /// A new PgpPublicKeyRingBundle merging the current one with the passed in key ring. + /// If the keyId for the passed in key ring is already present. + public static PgpPublicKeyRingBundle AddPublicKeyRing( + PgpPublicKeyRingBundle bundle, + PgpPublicKeyRing publicKeyRing) + { + long key = publicKeyRing.GetPublicKey().KeyId; + + if (bundle.pubRings.Contains(key)) + { + throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring."); + } + + IDictionary newPubRings = new Hashtable(bundle.pubRings); + ArrayList newOrder = new ArrayList(bundle.order); + + newPubRings[key] = publicKeyRing; + + newOrder.Add(key); + + return new PgpPublicKeyRingBundle(newPubRings, newOrder); + } + + /// + /// Return a new bundle containing the contents of the passed in bundle with + /// the passed in public key ring removed. + /// + /// The PgpPublicKeyRingBundle the key ring is to be removed from. + /// The key ring to be removed. + /// A new PgpPublicKeyRingBundle not containing the passed in key ring. + /// If the keyId for the passed in key ring is not present. + public static PgpPublicKeyRingBundle RemovePublicKeyRing( + PgpPublicKeyRingBundle bundle, + PgpPublicKeyRing publicKeyRing) + { + long key = publicKeyRing.GetPublicKey().KeyId; + + if (!bundle.pubRings.Contains(key)) + { + throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring."); + } + + IDictionary newPubRings = new Hashtable(bundle.pubRings); + ArrayList newOrder = new ArrayList(bundle.order); + + newPubRings.Remove(key); + newOrder.Remove(key); + + return new PgpPublicKeyRingBundle(newPubRings, newOrder); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSecretKey.cs b/iTechSharp/srcbc/openpgp/PgpSecretKey.cs new file mode 100644 index 0000000..9857b06 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSecretKey.cs @@ -0,0 +1,707 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// General class to handle a PGP secret key object. + public class PgpSecretKey + { + private SecretKeyPacket secret; + private TrustPacket trust; + private ArrayList keySigs; + private ArrayList ids; + private ArrayList idTrusts; + private ArrayList idSigs; + private PgpPublicKey pub; + private ArrayList subSigs; + + /// Copy constructor - master key. + private PgpSecretKey( + SecretKeyPacket secret, + TrustPacket trust, + ArrayList keySigs, + ArrayList ids, + ArrayList idTrusts, + ArrayList idSigs, + PgpPublicKey pub) + { + this.secret = secret; + this.trust = trust; + this.keySigs = keySigs; + this.ids = ids; + this.idTrusts = idTrusts; + this.idSigs = idSigs; + this.pub = pub; + } + + /// Copy constructor - subkey. + private PgpSecretKey( + SecretKeyPacket secret, + TrustPacket trust, + ArrayList subSigs, + PgpPublicKey pub) + { + this.secret = secret; + this.trust = trust; + this.subSigs = subSigs; + this.pub = pub; + } + + internal PgpSecretKey( + SecretKeyPacket secret, + TrustPacket trust, + ArrayList keySigs, + ArrayList ids, + ArrayList idTrusts, + ArrayList idSigs) + { + this.secret = secret; + this.trust = trust; + this.keySigs = keySigs; + this.ids = ids; + this.idTrusts = idTrusts; + this.idSigs = idSigs; + this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs); + } + + internal PgpSecretKey( + SecretKeyPacket secret, + TrustPacket trust, + ArrayList subSigs) + { + this.secret = secret; + this.trust = trust; + this.subSigs = subSigs; + this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, subSigs); + } + + /// Create a subkey + internal PgpSecretKey( + PgpKeyPair keyPair, + TrustPacket trust, + ArrayList subSigs, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSHA1, + SecureRandom rand) + : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand) + { + this.secret = new SecretSubkeyPacket( + secret.PublicKeyPacket, + secret.EncAlgorithm, + secret.S2kUsage, + secret.S2k, + secret.GetIV(), + secret.GetSecretKeyData()); + + this.trust = trust; + this.subSigs = subSigs; + this.pub = new PgpPublicKey(keyPair.PublicKey, trust, subSigs); + } + + internal PgpSecretKey( + PgpKeyPair keyPair, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSHA1, + SecureRandom rand) + { + PublicKeyPacket pubPk = keyPair.PublicKey.publicPk; + + BcpgObject secKey; + switch (keyPair.PublicKey.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaSign: + case PublicKeyAlgorithmTag.RsaGeneral: + RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) keyPair.PrivateKey.Key; + secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q); + break; + case PublicKeyAlgorithmTag.Dsa: + DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) keyPair.PrivateKey.Key; + secKey = new DsaSecretBcpgKey(dsK.X); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) keyPair.PrivateKey.Key; + secKey = new ElGamalSecretBcpgKey(esK.X); + break; + default: + throw new PgpException("unknown key class"); + } + + try + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WriteObject(secKey); + + byte[] keyData = bOut.ToArray(); + byte[] checksumBytes = Checksum(useSHA1, keyData, keyData.Length); + + pOut.Write(checksumBytes); + + byte[] bOutData = bOut.ToArray(); + + if (encAlgorithm == SymmetricKeyAlgorithmTag.Null) + { + this.secret = new SecretKeyPacket(pubPk, encAlgorithm, null, null, bOutData); + } + else + { + S2k s2k; + byte[] iv; + byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv); + + int usage = useSHA1 + ? SecretKeyPacket.UsageSha1 + : SecretKeyPacket.UsageChecksum; + + this.secret = new SecretKeyPacket(pubPk, encAlgorithm, usage, s2k, iv, encData); + } + + this.trust = null; + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception encrypting key", e); + } + + this.keySigs = new ArrayList(); + } + + public PgpSecretKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand) + { + } + + public PgpSecretKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSHA1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand) + { + try + { + this.trust = null; + this.ids = new ArrayList(); + ids.Add(id); + + this.idTrusts = new ArrayList(); + idTrusts.Add(null); + + this.idSigs = new ArrayList(); + + PgpSignatureGenerator sGen = new PgpSignatureGenerator( + keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1); + + // + // Generate the certification + // + sGen.InitSign(certificationLevel, keyPair.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey); + this.pub = PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification); + + ArrayList sigList = new ArrayList(); + sigList.Add(certification); + idSigs.Add(sigList); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception encrypting key", e); + } + } + + public PgpSecretKey( + int certificationLevel, + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + AsymmetricKeyParameter privKey, + DateTime time, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, + new PgpKeyPair(algorithm, pubKey, privKey, time), + id, encAlgorithm, passPhrase, hashedPackets, unhashedPackets, rand) + { + } + + public PgpSecretKey( + int certificationLevel, + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + AsymmetricKeyParameter privKey, + DateTime time, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSHA1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSHA1, hashedPackets, unhashedPackets, rand) + { + } + + /// True, if this key is marked as suitable for signature generation. + public bool IsSigningKey + { + get + { + switch (pub.Algorithm) + { + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + case PublicKeyAlgorithmTag.Dsa: + case PublicKeyAlgorithmTag.ECDsa: + case PublicKeyAlgorithmTag.ElGamalGeneral: + return true; + default: + return false; + } + } + } + + /// True, if this is a master key. + public bool IsMasterKey + { + get { return subSigs == null; } + } + + /// The algorithm the key is encrypted with. + public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm + { + get { return secret.EncAlgorithm; } + } + + /// The key ID of the public key associated with this key. + public long KeyId + { + get { return pub.KeyId; } + } + + /// The public key associated with this key. + public PgpPublicKey PublicKey + { + get { return pub; } + } + + /// Allows enumeration of any user IDs associated with the key. + /// An IEnumerable of string objects. + public IEnumerable UserIds + { + get { return pub.GetUserIds(); } + } + + /// Allows enumeration of any user attribute vectors associated with the key. + /// An IEnumerable of string objects. + public IEnumerable UserAttributes + { + get { return pub.GetUserAttributes(); } + } + + private byte[] ExtractKeyData( + char[] passPhrase) + { + SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm; + byte[] encData = secret.GetSecretKeyData(); + + if (alg == SymmetricKeyAlgorithmTag.Null) + return encData; + + byte[] data; + IBufferedCipher c = null; + try + { + string cName = PgpUtilities.GetSymmetricCipherName(alg); + c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + + // TODO Factor this block out as 'encryptData' + try + { + KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase); + byte[] iv = secret.GetIV(); + + if (secret.PublicKeyPacket.Version == 4) + { + c.Init(false, new ParametersWithIV(key, iv)); + + data = c.DoFinal(encData); + + bool useSHA1 = secret.S2kUsage == SecretKeyPacket.UsageSha1; + byte[] check = Checksum(useSHA1, data, (useSHA1) ? data.Length - 20 : data.Length - 2); + + for (int i = 0; i != check.Length; i++) + { + if (check[i] != data[data.Length - check.Length + i]) + { + throw new PgpException("Checksum mismatch at " + i + " of " + check.Length); + } + } + } + else // version 2 or 3, RSA only. + { + data = new byte[encData.Length]; + + // + // read in the four numbers + // + int pos = 0; + + for (int i = 0; i != 4; i++) + { + c.Init(false, new ParametersWithIV(key, iv)); + + int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; + + data[pos] = encData[pos]; + data[pos + 1] = encData[pos + 1]; + pos += 2; + + c.DoFinal(encData, pos, encLen, data, pos); + pos += encLen; + + if (i != 3) + { + Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length); + } + } + + // + // verify Checksum + // + int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); + int calcCs = 0; + for (int j=0; j < data.Length-2; j++) + { + calcCs += data[j] & 0xff; + } + + calcCs &= 0xffff; + if (calcCs != cs) + { + throw new PgpException("Checksum mismatch: passphrase wrong, expected " + + cs.ToString("X") + + " found " + calcCs.ToString("X")); + } + } + + return data; + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception decrypting key", e); + } + } + + /// Extract a PgpPrivateKey from this secret key's encrypted contents. + public PgpPrivateKey ExtractPrivateKey( + char[] passPhrase) + { + byte[] secKeyData = secret.GetSecretKeyData(); + if (secKeyData == null || secKeyData.Length < 1) + return null; + + PublicKeyPacket pubPk = secret.PublicKeyPacket; + try + { + byte[] data = ExtractKeyData(passPhrase); + BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false)); + AsymmetricKeyParameter privateKey; + switch (pubPk.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key; + RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn); + RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters( + rsaPriv.Modulus, + rsaPub.PublicExponent, + rsaPriv.PrivateExponent, + rsaPriv.PrimeP, + rsaPriv.PrimeQ, + rsaPriv.PrimeExponentP, + rsaPriv.PrimeExponentQ, + rsaPriv.CrtCoefficient); + privateKey = rsaPrivSpec; + break; + case PublicKeyAlgorithmTag.Dsa: + DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key; + DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn); + DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G); + privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key; + ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn); + ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G); + privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams); + break; + default: + throw new PgpException("unknown public key algorithm encountered"); + } + + return new PgpPrivateKey(privateKey, KeyId); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception constructing key", e); + } + } + + private static byte[] Checksum( + bool useSHA1, + byte[] bytes, + int length) + { + if (useSHA1) + { + try + { + IDigest dig = DigestUtilities.GetDigest("SHA1"); + dig.BlockUpdate(bytes, 0, length); + return DigestUtilities.DoFinal(dig); + } + //catch (NoSuchAlgorithmException e) + catch (Exception e) + { + throw new PgpException("Can't find SHA-1", e); + } + } + else + { + int Checksum = 0; + for (int i = 0; i != length; i++) + { + Checksum += bytes[i]; + } + + return new byte[] { (byte)(Checksum >> 8), (byte)Checksum }; + } + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + Encode(bOut); + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); + + bcpgOut.WritePacket(secret); + if (trust != null) + { + bcpgOut.WritePacket(trust); + } + + if (subSigs == null) // is not a sub key + { + foreach (PgpSignature keySig in keySigs) + { + keySig.Encode(bcpgOut); + } + + for (int i = 0; i != ids.Count; i++) + { + if (ids[i] is string) + { + string id = (string) ids[i]; + + bcpgOut.WritePacket(new UserIdPacket(id)); + } + else + { + PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i]; + bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray())); + } + + if (idTrusts[i] != null) + { + bcpgOut.WritePacket((ContainedPacket)idTrusts[i]); + } + + foreach (PgpSignature sig in (ArrayList) idSigs[i]) + { + sig.Encode(bcpgOut); + } + } + } + else + { + foreach (PgpSignature subSig in subSigs) + { + subSig.Encode(bcpgOut); + } + } + + // TODO Check that this is right/necessary + //bcpgOut.Finish(); + } + + /// + /// Return a copy of the passed in secret key, encrypted using a new password + /// and the passed in algorithm. + /// + /// The PgpSecretKey to be copied. + /// The current password for the key. + /// The new password for the key. + /// The algorithm to be used for the encryption. + /// Source of randomness. + public static PgpSecretKey CopyWithNewPassword( + PgpSecretKey key, + char[] oldPassPhrase, + char[] newPassPhrase, + SymmetricKeyAlgorithmTag newEncAlgorithm, + SecureRandom rand) + { + byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); + int s2kUsage = key.secret.S2kUsage; + byte[] iv = null; + S2k s2k = null; + byte[] keyData; + + if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) + { + s2kUsage = SecretKeyPacket.UsageNone; + if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum + { + keyData = new byte[rawKeyData.Length - 18]; + + Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); + + byte[] check = Checksum(false, keyData, keyData.Length - 2); + + keyData[keyData.Length - 2] = check[0]; + keyData[keyData.Length - 1] = check[1]; + } + else + { + keyData = rawKeyData; + } + } + else + { + try + { + keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception encrypting key", e); + } + } + + SecretKeyPacket secret; + if (key.secret is SecretSubkeyPacket) + { + secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, + newEncAlgorithm, s2kUsage, s2k, iv, keyData); + } + else + { + secret = new SecretKeyPacket(key.secret.PublicKeyPacket, + newEncAlgorithm, s2kUsage, s2k, iv, keyData); + } + + if (key.subSigs == null) + { + return new PgpSecretKey(secret, key.trust, key.keySigs, key.ids, + key.idTrusts, key.idSigs, key.pub); + } + + return new PgpSecretKey(secret, key.trust, key.subSigs, key.pub); + } + + private static byte[] EncryptKeyData( + byte[] rawKeyData, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + SecureRandom random, + out S2k s2k, + out byte[] iv) + { + IBufferedCipher c; + try + { + string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); + c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + + byte[] s2kIV = new byte[8]; + random.NextBytes(s2kIV); + s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60); + + KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase); + + iv = new byte[c.GetBlockSize()]; + random.NextBytes(iv); + + c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random)); + + return c.DoFinal(rawKeyData); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs b/iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs new file mode 100644 index 0000000..232f4c3 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Class to hold a single master secret key and its subkeys. + ///

      + /// Often PGP keyring files consist of multiple master keys, if you are trying to process + /// or construct one of these you should use the PgpSecretKeyRingBundle class. + ///

      + ///
      + public class PgpSecretKeyRing + : PgpKeyRing + { + private readonly ArrayList keys; + + internal PgpSecretKeyRing( + ArrayList keys) + { + this.keys = keys; + } + + public PgpSecretKeyRing( + byte[] encoding) + : this(new MemoryStream(encoding)) + { + } + + public PgpSecretKeyRing( + Stream inputStream) + { + this.keys = new ArrayList(); + + BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream); + + PacketTag initialTag = bcpgInput.NextPacketTag(); + if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey) + { + throw new IOException("secret key ring doesn't start with secret key tag: " + + "tag 0x" + ((int)initialTag).ToString("X")); + } + + SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket(); + + // + // ignore GPG comment packets if found. + // + while (bcpgInput.NextPacketTag() == PacketTag.Experimental2) + { + bcpgInput.ReadPacket(); + } + + TrustPacket trust = ReadOptionalTrustPacket(bcpgInput); + + // revocation and direct signatures + ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput); + + ArrayList ids, idTrusts, idSigs; + ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); + + keys.Add(new PgpSecretKey(secret, trust, keySigs, ids, idTrusts, idSigs)); + + + // Read subkeys + while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey) + { + SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket(); + + // + // ignore GPG comment packets if found. + // + while (bcpgInput.NextPacketTag() == PacketTag.Experimental2) + { + bcpgInput.ReadPacket(); + } + + TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput); + ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); + + keys.Add(new PgpSecretKey(sub, subTrust, sigList)); + } + } + + /// Return the public key for the master key. + public PgpPublicKey GetPublicKey() + { + return ((PgpSecretKey) keys[0]).PublicKey; + } + + /// Return the master private key. + public PgpSecretKey GetSecretKey() + { + return (PgpSecretKey) keys[0]; + } + + /// Allows enumeration of the secret keys. + /// An IEnumerable of PgpSecretKey objects. + public IEnumerable GetSecretKeys() + { + return new EnumerableProxy(keys); + } + + public PgpSecretKey GetSecretKey( + long keyId) + { + foreach (PgpSecretKey k in keys) + { + if (keyId == k.KeyId) + { + return k; + } + } + + return null; + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + foreach (PgpSecretKey k in keys) + { + k.Encode(outStr); + } + } + + /// + /// Returns a new key ring with the secret key passed in either added or + /// replacing an existing one with the same key ID. + /// + /// The secret key ring to be modified. + /// The secret key to be inserted. + /// A new PgpSecretKeyRing + public static PgpSecretKeyRing InsertSecretKey( + PgpSecretKeyRing secRing, + PgpSecretKey secKey) + { + ArrayList keys = new ArrayList(secRing.keys); + bool found = false; + bool masterFound = false; + + for (int i = 0; i != keys.Count; i++) + { + PgpSecretKey key = (PgpSecretKey) keys[i]; + + if (key.KeyId == secKey.KeyId) + { + found = true; + keys[i] = secKey; + } + if (key.IsMasterKey) + { + masterFound = true; + } + } + + if (!found) + { + if (secKey.IsMasterKey && masterFound) + throw new ArgumentException("cannot add a master key to a ring that already has one"); + + keys.Add(secKey); + } + + return new PgpSecretKeyRing(keys); + } + + /// Returns a new key ring with the secret key passed in removed from the key ring. + /// The secret key ring to be modified. + /// The secret key to be removed. + /// A new PgpSecretKeyRing, or null if secKey is not found. + public static PgpSecretKeyRing RemoveSecretKey( + PgpSecretKeyRing secRing, + PgpSecretKey secKey) + { + ArrayList keys = new ArrayList(secRing.keys); + bool found = false; + + for (int i = 0; i < keys.Count; i++) + { + PgpSecretKey key = (PgpSecretKey)keys[i]; + + if (key.KeyId == secKey.KeyId) + { + found = true; + keys.RemoveAt(i); + } + } + + return found ? new PgpSecretKeyRing(keys) : null; + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSecretKeyRingBundle.cs b/iTechSharp/srcbc/openpgp/PgpSecretKeyRingBundle.cs new file mode 100644 index 0000000..fa83a3a --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSecretKeyRingBundle.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Often a PGP key ring file is made up of a succession of master/sub-key key rings. + /// If you want to read an entire secret key file in one hit this is the class for you. + /// + public class PgpSecretKeyRingBundle + { + private readonly IDictionary secretRings; + private readonly ArrayList order; + + private PgpSecretKeyRingBundle( + IDictionary secretRings, + ArrayList order) + { + this.secretRings = secretRings; + this.order = order; + } + + public PgpSecretKeyRingBundle( + byte[] encoding) + : this(new MemoryStream(encoding, false)) + { + } + + /// Build a PgpSecretKeyRingBundle from the passed in input stream. + /// Input stream containing data. + /// If a problem parsing the stream occurs. + /// If an object is encountered which isn't a PgpSecretKeyRing. + public PgpSecretKeyRingBundle( + Stream inputStream) + : this(new PgpObjectFactory(inputStream).AllPgpObjects()) + { + } + + public PgpSecretKeyRingBundle( + IEnumerable e) + { + this.secretRings = new Hashtable(); + this.order = new ArrayList(); + + foreach (object obj in e) + { + PgpSecretKeyRing pgpSecret = obj as PgpSecretKeyRing; + + if (pgpSecret == null) + { + throw new PgpException(obj.GetType().FullName + " found where PgpSecretKeyRing expected"); + } + + long key = pgpSecret.GetPublicKey().KeyId; + secretRings.Add(key, pgpSecret); + order.Add(key); + } + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return order.Count; } + } + + /// Return the number of rings in this collection. + public int Count + { + get { return order.Count; } + } + + /// Allow enumeration of the secret key rings making up this collection. + public IEnumerable GetKeyRings() + { + return new EnumerableProxy(secretRings.Values); + } + + /// Allow enumeration of the key rings associated with the passed in userId. + /// The user ID to be matched. + /// An IEnumerable of key rings which matched (possibly none). + public IEnumerable GetKeyRings( + string userId) + { + return GetKeyRings(userId, false, false); + } + + /// Allow enumeration of the key rings associated with the passed in userId. + /// The user ID to be matched. + /// If true, userId need only be a substring of an actual ID string to match. + /// An IEnumerable of key rings which matched (possibly none). + public IEnumerable GetKeyRings( + string userId, + bool matchPartial) + { + return GetKeyRings(userId, matchPartial, false); + } + + /// Allow enumeration of the key rings associated with the passed in userId. + /// The user ID to be matched. + /// If true, userId need only be a substring of an actual ID string to match. + /// If true, case is ignored in user ID comparisons. + /// An IEnumerable of key rings which matched (possibly none). + public IEnumerable GetKeyRings( + string userId, + bool matchPartial, + bool ignoreCase) + { + IList rings = new ArrayList(); + + if (ignoreCase) + { + userId = userId.ToLower(CultureInfo.InvariantCulture); + } + + foreach (PgpSecretKeyRing secRing in GetKeyRings()) + { + foreach (string nextUserID in secRing.GetSecretKey().UserIds) + { + string next = nextUserID; + if (ignoreCase) + { + next = next.ToLower(CultureInfo.InvariantCulture); + } + + if (matchPartial) + { + if (next.IndexOf(userId) > -1) + { + rings.Add(secRing); + } + } + else + { + if (next.Equals(userId)) + { + rings.Add(secRing); + } + } + } + } + + return new EnumerableProxy(rings); + } + + /// Return the PGP secret key associated with the given key id. + /// The ID of the secret key to return. + public PgpSecretKey GetSecretKey( + long keyId) + { + foreach (PgpSecretKeyRing secRing in GetKeyRings()) + { + PgpSecretKey sec = secRing.GetSecretKey(keyId); + + if (sec != null) + { + return sec; + } + } + + return null; + } + + /// Return the secret key ring which contains the key referred to by keyId + /// The ID of the secret key + public PgpSecretKeyRing GetSecretKeyRing( + long keyId) + { + long id = keyId; + + if (secretRings.Contains(id)) + { + return (PgpSecretKeyRing) secretRings[id]; + } + + foreach (PgpSecretKeyRing secretRing in GetKeyRings()) + { + PgpSecretKey secret = secretRing.GetSecretKey(keyId); + + if (secret != null) + { + return secretRing; + } + } + + return null; + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); + + foreach (long key in order) + { + PgpSecretKeyRing pub = (PgpSecretKeyRing) secretRings[key]; + + pub.Encode(bcpgOut); + } + } + + /// + /// Return a new bundle containing the contents of the passed in bundle and + /// the passed in secret key ring. + /// + /// The PgpSecretKeyRingBundle the key ring is to be added to. + /// The key ring to be added. + /// A new PgpSecretKeyRingBundle merging the current one with the passed in key ring. + /// If the keyId for the passed in key ring is already present. + public static PgpSecretKeyRingBundle AddSecretKeyRing( + PgpSecretKeyRingBundle bundle, + PgpSecretKeyRing secretKeyRing) + { + long key = secretKeyRing.GetPublicKey().KeyId; + + if (bundle.secretRings.Contains(key)) + { + throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring."); + } + + IDictionary newSecretRings = new Hashtable(bundle.secretRings); + ArrayList newOrder = new ArrayList(bundle.order); + + newSecretRings[key] = secretKeyRing; + newOrder.Add(key); + + return new PgpSecretKeyRingBundle(newSecretRings, newOrder); + } + + /// + /// Return a new bundle containing the contents of the passed in bundle with + /// the passed in secret key ring removed. + /// + /// The PgpSecretKeyRingBundle the key ring is to be removed from. + /// The key ring to be removed. + /// A new PgpSecretKeyRingBundle not containing the passed in key ring. + /// If the keyId for the passed in key ring is not present. + public static PgpSecretKeyRingBundle RemoveSecretKeyRing( + PgpSecretKeyRingBundle bundle, + PgpSecretKeyRing secretKeyRing) + { + long key = secretKeyRing.GetPublicKey().KeyId; + + if (!bundle.secretRings.Contains(key)) + { + throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring."); + } + + IDictionary newSecretRings = new Hashtable(bundle.secretRings); + ArrayList newOrder = new ArrayList(bundle.order); + + newSecretRings.Remove(key); + newOrder.Remove(key); + + return new PgpSecretKeyRingBundle(newSecretRings, newOrder); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSignature.cs b/iTechSharp/srcbc/openpgp/PgpSignature.cs new file mode 100644 index 0000000..1b939ab --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSignature.cs @@ -0,0 +1,409 @@ +using System; +using System.IO; +using Org.BouncyCastle.Asn1; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A PGP signature object. + public class PgpSignature + { + public const int BinaryDocument = 0x00; + public const int CanonicalTextDocument = 0x01; + public const int StandAlone = 0x02; + + public const int DefaultCertification = 0x10; + public const int NoCertification = 0x11; + public const int CasualCertification = 0x12; + public const int PositiveCertification = 0x13; + + public const int SubkeyBinding = 0x18; + public const int DirectKey = 0x1f; + public const int KeyRevocation = 0x20; + public const int SubkeyRevocation = 0x28; + public const int CertificationRevocation = 0x30; + public const int Timestamp = 0x40; + + private readonly SignaturePacket sigPck; + private readonly int signatureType; + private readonly TrustPacket trustPck; + + private ISigner sig; + private byte lastb; // Initial value anything but '\r' + + internal PgpSignature( + BcpgInputStream bcpgInput) + : this((SignaturePacket)bcpgInput.ReadPacket()) + { + } + + internal PgpSignature( + SignaturePacket sigPacket) + : this(sigPacket, null) + { + } + + internal PgpSignature( + SignaturePacket sigPacket, + TrustPacket trustPacket) + { + if (sigPacket == null) + throw new ArgumentNullException("sigPacket"); + + this.sigPck = sigPacket; + this.signatureType = sigPck.SignatureType; + this.trustPck = trustPacket; + } + + private void GetSig() + { + this.sig = SignerUtilities.GetSigner( + PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm)); + } + + /// The OpenPGP version number for this signature. + public int Version + { + get { return sigPck.Version; } + } + + /// The key algorithm associated with this signature. + public PublicKeyAlgorithmTag KeyAlgorithm + { + get { return sigPck.KeyAlgorithm; } + } + + /// The hash algorithm associated with this signature. + public HashAlgorithmTag HashAlgorithm + { + get { return sigPck.HashAlgorithm; } + } + + public void InitVerify( + PgpPublicKey pubKey) + { + lastb = 0; + if (sig == null) + { + GetSig(); + } + try + { + sig.Init(false, pubKey.GetKey()); + } + catch (InvalidKeyException e) + { + throw new PgpException("invalid key.", e); + } + } + + public void Update( + byte b) + { + if (signatureType == CanonicalTextDocument) + { + doCanonicalUpdateByte(b); + } + else + { + sig.Update(b); + } + } + + private void doCanonicalUpdateByte( + byte b) + { + if (b == '\r') + { + doUpdateCRLF(); + } + else if (b == '\n') + { + if (lastb != '\r') + { + doUpdateCRLF(); + } + } + else + { + sig.Update(b); + } + + lastb = b; + } + + private void doUpdateCRLF() + { + sig.Update((byte)'\r'); + sig.Update((byte)'\n'); + } + + public void Update( + params byte[] bytes) + { + Update(bytes, 0, bytes.Length); + } + + public void Update( + byte[] bytes, + int off, + int length) + { + if (signatureType == CanonicalTextDocument) + { + int finish = off + length; + + for (int i = off; i != finish; i++) + { + doCanonicalUpdateByte(bytes[i]); + } + } + else + { + sig.BlockUpdate(bytes, off, length); + } + } + + public bool Verify() + { + byte[] trailer = GetSignatureTrailer(); + sig.BlockUpdate(trailer, 0, trailer.Length); + + return sig.VerifySignature(GetSignature()); + } + + private void UpdateWithIdData( + int header, + byte[] idBytes) + { + this.Update( + (byte) header, + (byte)(idBytes.Length >> 24), + (byte)(idBytes.Length >> 16), + (byte)(idBytes.Length >> 8), + (byte)(idBytes.Length)); + this.Update(idBytes); + } + + private void UpdateWithPublicKey( + PgpPublicKey key) + { + byte[] keyBytes = GetEncodedPublicKey(key); + + this.Update( + (byte) 0x99, + (byte)(keyBytes.Length >> 8), + (byte)(keyBytes.Length)); + this.Update(keyBytes); + } + + /// + /// Verify the signature as certifying the passed in public key as associated + /// with the passed in user attributes. + /// + /// User attributes the key was stored under. + /// The key to be verified. + /// True, if the signature matches, false otherwise. + public bool VerifyCertification( + PgpUserAttributeSubpacketVector userAttributes, + PgpPublicKey key) + { + UpdateWithPublicKey(key); + + // + // hash in the userAttributes + // + try + { + MemoryStream bOut = new MemoryStream(); + foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray()) + { + packet.Encode(bOut); + } + UpdateWithIdData(0xd1, bOut.ToArray()); + } + catch (IOException e) + { + throw new PgpException("cannot encode subpacket array", e); + } + + this.Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(this.GetSignature()); + } + + /// + /// Verify the signature as certifying the passed in public key as associated + /// with the passed in ID. + /// + /// ID the key was stored under. + /// The key to be verified. + /// True, if the signature matches, false otherwise. + public bool VerifyCertification( + string id, + PgpPublicKey key) + { + UpdateWithPublicKey(key); + + // + // hash in the id + // + UpdateWithIdData(0xb4, Strings.ToByteArray(id)); + + Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(GetSignature()); + } + + /// Verify a certification for the passed in key against the passed in master key. + /// The key we are verifying against. + /// The key we are verifying. + /// True, if the certification is valid, false otherwise. + public bool VerifyCertification( + PgpPublicKey masterKey, + PgpPublicKey pubKey) + { + UpdateWithPublicKey(masterKey); + UpdateWithPublicKey(pubKey); + + Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(GetSignature()); + } + + /// Verify a key certification, such as revocation, for the passed in key. + /// The key we are checking. + /// True, if the certification is valid, false otherwise. + public bool VerifyCertification( + PgpPublicKey pubKey) + { + if (SignatureType != KeyRevocation + && SignatureType != SubkeyRevocation) + { + throw new InvalidOperationException("signature is not a key signature"); + } + + UpdateWithPublicKey(pubKey); + + Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(GetSignature()); + } + + public int SignatureType + { + get { return sigPck.SignatureType; } + } + + /// The ID of the key that created the signature. + public long KeyId + { + get { return sigPck.KeyId; } + } + + [Obsolete("Use 'CreationTime' property instead")] + public DateTime GetCreationTime() + { + return CreationTime; + } + + /// The creation time of this signature. + public DateTime CreationTime + { + get { return DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime); } + } + + public byte[] GetSignatureTrailer() + { + return sigPck.GetSignatureTrailer(); + } + + public PgpSignatureSubpacketVector GetHashedSubPackets() + { + return createSubpacketVector(sigPck.GetHashedSubPackets()); + } + + public PgpSignatureSubpacketVector GetUnhashedSubPackets() + { + return createSubpacketVector(sigPck.GetUnhashedSubPackets()); + } + + private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks) + { + return pcks == null ? null : new PgpSignatureSubpacketVector(pcks); + } + + public byte[] GetSignature() + { + MPInteger[] sigValues = sigPck.GetSignature(); + byte[] signature; + + if (sigValues != null) + { + if (sigValues.Length == 1) // an RSA signature + { + signature = sigValues[0].Value.ToByteArrayUnsigned(); + } + else + { + try + { + signature = new DerSequence( + new DerInteger(sigValues[0].Value), + new DerInteger(sigValues[1].Value)).GetEncoded(); + } + catch (IOException e) + { + throw new PgpException("exception encoding DSA sig.", e); + } + } + } + else + { + signature = sigPck.GetSignatureBytes(); + } + + return signature; + } + + // TODO Handle the encoding stuff by subclassing BcpgObject? + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStream) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream); + + bcpgOut.WritePacket(sigPck); + + if (trustPck != null) + { + bcpgOut.WritePacket(trustPck); + } + } + + private byte[] GetEncodedPublicKey( + PgpPublicKey pubKey) + { + try + { + return pubKey.publicPk.GetEncodedContents(); + } + catch (IOException e) + { + throw new PgpException("exception preparing key.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs b/iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs new file mode 100644 index 0000000..8913972 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs @@ -0,0 +1,393 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Bcpg.Sig; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Generator for PGP signatures. + // TODO Should be able to implement ISigner? + public class PgpSignatureGenerator + { + private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0]; + + private PublicKeyAlgorithmTag keyAlgorithm; + private HashAlgorithmTag hashAlgorithm; + private PgpPrivateKey privKey; + private ISigner sig; + private IDigest dig; + private int signatureType; + private byte lastb; + + private SignatureSubpacket[] unhashed = EmptySignatureSubpackets; + private SignatureSubpacket[] hashed = EmptySignatureSubpackets; + + /// Create a generator for the passed in keyAlgorithm and hashAlgorithm codes. + public PgpSignatureGenerator( + PublicKeyAlgorithmTag keyAlgorithm, + HashAlgorithmTag hashAlgorithm) + { + this.keyAlgorithm = keyAlgorithm; + this.hashAlgorithm = hashAlgorithm; + + dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm)); + sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm)); + } + + /// Initialise the generator for signing. + public void InitSign( + int sigType, + PgpPrivateKey key) + { + InitSign(sigType, key, null); + } + + /// Initialise the generator for signing. + public void InitSign( + int sigType, + PgpPrivateKey key, + SecureRandom random) + { + this.privKey = key; + this.signatureType = sigType; + + try + { + ICipherParameters cp = key.Key; + if (random != null) + { + cp = new ParametersWithRandom(key.Key, random); + } + + sig.Init(true, cp); + } + catch (InvalidKeyException e) + { + throw new PgpException("invalid key.", e); + } + + dig.Reset(); + lastb = 0; + } + + public void Update( + byte b) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + doCanonicalUpdateByte(b); + } + else + { + doUpdateByte(b); + } + } + + private void doCanonicalUpdateByte( + byte b) + { + if (b == '\r') + { + doUpdateCRLF(); + } + else if (b == '\n') + { + if (lastb != '\r') + { + doUpdateCRLF(); + } + } + else + { + doUpdateByte(b); + } + + lastb = b; + } + + private void doUpdateCRLF() + { + doUpdateByte((byte)'\r'); + doUpdateByte((byte)'\n'); + } + + private void doUpdateByte( + byte b) + { + sig.Update(b); + dig.Update(b); + } + + public void Update( + params byte[] b) + { + Update(b, 0, b.Length); + } + + public void Update( + byte[] b, + int off, + int len) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + int finish = off + len; + + for (int i = off; i != finish; i++) + { + doCanonicalUpdateByte(b[i]); + } + } + else + { + sig.BlockUpdate(b, off, len); + dig.BlockUpdate(b, off, len); + } + } + + public void SetHashedSubpackets( + PgpSignatureSubpacketVector hashedPackets) + { + hashed = hashedPackets == null + ? EmptySignatureSubpackets + : hashedPackets.ToSubpacketArray(); + } + + public void SetUnhashedSubpackets( + PgpSignatureSubpacketVector unhashedPackets) + { + unhashed = unhashedPackets == null + ? EmptySignatureSubpackets + : unhashedPackets.ToSubpacketArray(); + } + + /// Return the one pass header associated with the current signature. + public PgpOnePassSignature GenerateOnePassVersion( + bool isNested) + { + return new PgpOnePassSignature( + new OnePassSignaturePacket( + signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested)); + } + + /// Return a signature object containing the current signature state. + public PgpSignature Generate() + { + SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed; + + if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime)) + { + hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow)); + } + + if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId) + && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId)) + { + unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId)); + } + + int version = 4; + byte[] hData; + + try + { + MemoryStream hOut = new MemoryStream(); + + for (int i = 0; i != hPkts.Length; i++) + { + hPkts[i].Encode(hOut); + } + + byte[] data = hOut.ToArray(); + + MemoryStream sOut = new MemoryStream(data.Length + 6); + sOut.WriteByte((byte)version); + sOut.WriteByte((byte)signatureType); + sOut.WriteByte((byte)keyAlgorithm); + sOut.WriteByte((byte)hashAlgorithm); + sOut.WriteByte((byte)(data.Length >> 8)); + sOut.WriteByte((byte)data.Length); + sOut.Write(data, 0, data.Length); + + hData = sOut.ToArray(); + } + catch (IOException e) + { + throw new PgpException("exception encoding hashed data.", e); + } + + sig.BlockUpdate(hData, 0, hData.Length); + dig.BlockUpdate(hData, 0, hData.Length); + + hData = new byte[] + { + (byte) version, + 0xff, + (byte)(hData.Length >> 24), + (byte)(hData.Length >> 16), + (byte)(hData.Length >> 8), + (byte) hData.Length + }; + + sig.BlockUpdate(hData, 0, hData.Length); + dig.BlockUpdate(hData, 0, hData.Length); + + byte[] sigBytes = sig.GenerateSignature(); + byte[] digest = DigestUtilities.DoFinal(dig); + byte[] fingerPrint = new byte[] { digest[0], digest[1] }; + + // an RSA signature + bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign + || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral; + + MPInteger[] sigValues = isRsa + ? PgpUtilities.RsaSigToMpi(sigBytes) + : PgpUtilities.DsaSigToMpi(sigBytes); + + return new PgpSignature( + new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm, + hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues)); + } + + /// Generate a certification for the passed in ID and key. + /// The ID we are certifying against the public key. + /// The key we are certifying against the ID. + /// The certification. + public PgpSignature GenerateCertification( + string id, + PgpPublicKey pubKey) + { + UpdateWithPublicKey(pubKey); + + // + // hash in the id + // + UpdateWithIdData(0xb4, Strings.ToByteArray(id)); + + return Generate(); + } + + /// Generate a certification for the passed in userAttributes. + /// The ID we are certifying against the public key. + /// The key we are certifying against the ID. + /// The certification. + public PgpSignature GenerateCertification( + PgpUserAttributeSubpacketVector userAttributes, + PgpPublicKey pubKey) + { + UpdateWithPublicKey(pubKey); + + // + // hash in the attributes + // + try + { + MemoryStream bOut = new MemoryStream(); + foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray()) + { + packet.Encode(bOut); + } + UpdateWithIdData(0xd1, bOut.ToArray()); + } + catch (IOException e) + { + throw new PgpException("cannot encode subpacket array", e); + } + + return this.Generate(); + } + + /// Generate a certification for the passed in key against the passed in master key. + /// The key we are certifying against. + /// The key we are certifying. + /// The certification. + public PgpSignature GenerateCertification( + PgpPublicKey masterKey, + PgpPublicKey pubKey) + { + UpdateWithPublicKey(masterKey); + UpdateWithPublicKey(pubKey); + + return Generate(); + } + + /// Generate a certification, such as a revocation, for the passed in key. + /// The key we are certifying. + /// The certification. + public PgpSignature GenerateCertification( + PgpPublicKey pubKey) + { + UpdateWithPublicKey(pubKey); + + return Generate(); + } + + private byte[] GetEncodedPublicKey( + PgpPublicKey pubKey) + { + try + { + return pubKey.publicPk.GetEncodedContents(); + } + catch (IOException e) + { + throw new PgpException("exception preparing key.", e); + } + } + + private bool packetPresent( + SignatureSubpacket[] packets, + SignatureSubpacketTag type) + { + for (int i = 0; i != packets.Length; i++) + { + if (packets[i].SubpacketType == type) + { + return true; + } + } + + return false; + } + + private SignatureSubpacket[] insertSubpacket( + SignatureSubpacket[] packets, + SignatureSubpacket subpacket) + { + SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1]; + tmp[0] = subpacket; + packets.CopyTo(tmp, 1); + return tmp; + } + + private void UpdateWithIdData( + int header, + byte[] idBytes) + { + this.Update( + (byte) header, + (byte)(idBytes.Length >> 24), + (byte)(idBytes.Length >> 16), + (byte)(idBytes.Length >> 8), + (byte)(idBytes.Length)); + this.Update(idBytes); + } + + private void UpdateWithPublicKey( + PgpPublicKey key) + { + byte[] keyBytes = GetEncodedPublicKey(key); + + this.Update( + (byte) 0x99, + (byte)(keyBytes.Length >> 8), + (byte)(keyBytes.Length)); + this.Update(keyBytes); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSignatureList.cs b/iTechSharp/srcbc/openpgp/PgpSignatureList.cs new file mode 100644 index 0000000..61976fc --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSignatureList.cs @@ -0,0 +1,51 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A list of PGP signatures - normally in the signature block after literal data. + public class PgpSignatureList + : PgpObject + { + private PgpSignature[] sigs; + + public PgpSignatureList( + PgpSignature[] sigs) + { + this.sigs = (PgpSignature[]) sigs.Clone(); + } + + public PgpSignatureList( + PgpSignature sig) + { + this.sigs = new PgpSignature[]{ sig }; + } + + public PgpSignature this[int index] + { + get { return sigs[index]; } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public PgpSignature Get( + int index) + { + return this[index]; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return sigs.Length; } + } + + public int Count + { + get { return sigs.Length; } + } + + public bool IsEmpty + { + get { return (sigs.Length == 0); } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs b/iTechSharp/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs new file mode 100644 index 0000000..858fc60 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Bcpg.Sig; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Generator for signature subpackets. + public class PgpSignatureSubpacketGenerator + { + private ArrayList list = new ArrayList(); + + public void SetRevocable( + bool isCritical, + bool isRevocable) + { + list.Add(new Revocable(isCritical, isRevocable)); + } + + public void SetExportable( + bool isCritical, + bool isExportable) + { + list.Add(new Exportable(isCritical, isExportable)); + } + + /// + /// Add a TrustSignature packet to the signature. The values for depth and trust are largely + /// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13. + /// + /// true if the packet is critical. + /// depth level. + /// trust amount. + public void SetTrust( + bool isCritical, + int depth, + int trustAmount) + { + list.Add(new TrustSignature(isCritical, depth, trustAmount)); + } + + /// + /// Set the number of seconds a key is valid for after the time of its creation. + /// A value of zero means the key never expires. + /// + /// True, if should be treated as critical, false otherwise. + /// The number of seconds the key is valid, or zero if no expiry. + public void SetKeyExpirationTime( + bool isCritical, + long seconds) + { + list.Add(new KeyExpirationTime(isCritical, seconds)); + } + + /// + /// Set the number of seconds a signature is valid for after the time of its creation. + /// A value of zero means the signature never expires. + /// + /// True, if should be treated as critical, false otherwise. + /// The number of seconds the signature is valid, or zero if no expiry. + public void SetSignatureExpirationTime( + bool isCritical, + long seconds) + { + list.Add(new SignatureExpirationTime(isCritical, seconds)); + } + + /// + /// Set the creation time for the signature. + ///

      + /// Note: this overrides the generation of a creation time when the signature + /// is generated.

      + ///
      + public void SetSignatureCreationTime( + bool isCritical, + DateTime date) + { + list.Add(new SignatureCreationTime(isCritical, date)); + } + + public void SetPreferredHashAlgorithms( + bool isCritical, + int[] algorithms) + { + list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms)); + } + + public void SetPreferredSymmetricAlgorithms( + bool isCritical, + int[] algorithms) + { + list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms)); + } + + public void SetPreferredCompressionAlgorithms( + bool isCritical, + int[] algorithms) + { + list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms)); + } + + public void SetKeyFlags( + bool isCritical, + int flags) + { + list.Add(new KeyFlags(isCritical, flags)); + } + + public void SetSignerUserId( + bool isCritical, + string userId) + { + if (userId == null) + throw new ArgumentNullException("userId"); + + list.Add(new SignerUserId(isCritical, userId)); + } + + public void SetPrimaryUserId( + bool isCritical, + bool isPrimaryUserId) + { + list.Add(new PrimaryUserId(isCritical, isPrimaryUserId)); + } + + public void SetNotationData( + bool isCritical, + bool isHumanReadable, + string notationName, + string notationValue) + { + list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue)); + } + + public PgpSignatureSubpacketVector Generate() + { + return new PgpSignatureSubpacketVector( + (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket))); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpSignatureSubpacketVector.cs b/iTechSharp/srcbc/openpgp/PgpSignatureSubpacketVector.cs new file mode 100644 index 0000000..f57b7e5 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpSignatureSubpacketVector.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Bcpg.Sig; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Container for a list of signature subpackets. + public class PgpSignatureSubpacketVector + { + private readonly SignatureSubpacket[] packets; + + internal PgpSignatureSubpacketVector( + SignatureSubpacket[] packets) + { + this.packets = packets; + } + + public SignatureSubpacket GetSubpacket( + SignatureSubpacketTag type) + { + for (int i = 0; i != packets.Length; i++) + { + if (packets[i].SubpacketType == type) + { + return packets[i]; + } + } + + return null; + } + + /** + * Return all signature subpackets of the passed in type. + * @param type subpacket type code + * @return an array of zero or more matching subpackets. + */ + public SignatureSubpacket[] GetSubpackets( + SignatureSubpacketTag type) + { + ArrayList list = new ArrayList(); + + for (int i = 0; i != packets.Length; i++) + { + if (packets[i].SubpacketType == type) + { + list.Add(packets[i]); + } + } + + return (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket)); + } + + public NotationData[] GetNotationDataOccurences() + { + SignatureSubpacket[] notations = GetSubpackets(SignatureSubpacketTag.NotationData); + NotationData[] vals = new NotationData[notations.Length]; + + for (int i = 0; i < notations.Length; i++) + { + vals[i] = (NotationData) notations[i]; + } + + return vals; + } + + public long GetIssuerKeyId() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.IssuerKeyId); + + return p == null ? 0 : ((IssuerKeyId) p).KeyId; + } + + public bool HasSignatureCreationTime() + { + return GetSubpacket(SignatureSubpacketTag.CreationTime) != null; + } + + public DateTime GetSignatureCreationTime() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.CreationTime); + + if (p == null) + { + throw new PgpException("SignatureCreationTime not available"); + } + + return ((SignatureCreationTime)p).GetTime(); + } + + /// + /// Return the number of seconds a signature is valid for after its creation date. + /// A value of zero means the signature never expires. + /// + /// Seconds a signature is valid for. + public long GetSignatureExpirationTime() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.ExpireTime); + + return p == null ? 0 : ((SignatureExpirationTime) p).Time; + } + + /// + /// Return the number of seconds a key is valid for after its creation date. + /// A value of zero means the key never expires. + /// + /// Seconds a signature is valid for. + public long GetKeyExpirationTime() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyExpireTime); + + return p == null ? 0 : ((KeyExpirationTime) p).Time; + } + + public int[] GetPreferredHashAlgorithms() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms); + + return p == null ? null : ((PreferredAlgorithms) p).GetPreferences(); + } + + public int[] GetPreferredSymmetricAlgorithms() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms); + + return p == null ? null : ((PreferredAlgorithms) p).GetPreferences(); + } + + public int[] GetPreferredCompressionAlgorithms() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms); + + return p == null ? null : ((PreferredAlgorithms) p).GetPreferences(); + } + + public int GetKeyFlags() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyFlags); + + return p == null ? 0 : ((KeyFlags) p).Flags; + } + + public string GetSignerUserId() + { + SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.SignerUserId); + + return p == null ? null : ((SignerUserId) p).GetId(); + } + + public SignatureSubpacketTag[] GetCriticalTags() + { + int count = 0; + for (int i = 0; i != packets.Length; i++) + { + if (packets[i].IsCritical()) + { + count++; + } + } + + SignatureSubpacketTag[] list = new SignatureSubpacketTag[count]; + + count = 0; + + for (int i = 0; i != packets.Length; i++) + { + if (packets[i].IsCritical()) + { + list[count++] = packets[i].SubpacketType; + } + } + + return list; + } + + [Obsolete("Use 'Count' property instead")] + public int Size + { + get { return packets.Length; } + } + + /// Return the number of packets this vector contains. + public int Count + { + get { return packets.Length; } + } + + internal SignatureSubpacket[] ToSubpacketArray() + { + return packets; + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs b/iTechSharp/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs new file mode 100644 index 0000000..4cdbeda --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs @@ -0,0 +1,81 @@ +using Org.BouncyCastle.Bcpg.Attr; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Container for a list of user attribute subpackets. + public class PgpUserAttributeSubpacketVector + { + private readonly UserAttributeSubpacket[] packets; + + internal PgpUserAttributeSubpacketVector( + UserAttributeSubpacket[] packets) + { + this.packets = packets; + } + + public UserAttributeSubpacket GetSubpacket( + UserAttributeSubpacketTag type) + { + for (int i = 0; i != packets.Length; i++) + { + if (packets[i].SubpacketType == type) + { + return packets[i]; + } + } + + return null; + } + + public ImageAttrib GetImageAttribute() + { + UserAttributeSubpacket p = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute); + + return p == null ? null : (ImageAttrib) p; + } + + internal UserAttributeSubpacket[] ToSubpacketArray() + { + return packets; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + PgpUserAttributeSubpacketVector other = obj as PgpUserAttributeSubpacketVector; + + if (other == null) + return false; + + if (other.packets.Length != packets.Length) + { + return false; + } + + for (int i = 0; i != packets.Length; i++) + { + if (!other.packets[i].Equals(packets[i])) + { + return false; + } + } + + return true; + } + + public override int GetHashCode() + { + int code = 0; + + foreach (object o in packets) + { + code ^= o.GetHashCode(); + } + + return code; + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpUtilities.cs b/iTechSharp/srcbc/openpgp/PgpUtilities.cs new file mode 100644 index 0000000..7fc33c9 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpUtilities.cs @@ -0,0 +1,431 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Basic utility class. + public sealed class PgpUtilities + { + private PgpUtilities() + { + } + + public static MPInteger[] DsaSigToMpi( + byte[] encoding) + { + DerInteger i1, i2; + + try + { + Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding); + + i1 = (DerInteger) s[0]; + i2 = (DerInteger) s[1]; + } + catch (IOException e) + { + throw new PgpException("exception encoding signature", e); + } + + return new MPInteger[]{ new MPInteger(i1.Value), new MPInteger(i2.Value) }; + } + + public static MPInteger[] RsaSigToMpi( + byte[] encoding) + { + return new MPInteger[]{ new MPInteger(new BigInteger(1, encoding)) }; + } + + public static string GetDigestName( + HashAlgorithmTag hashAlgorithm) + { + switch (hashAlgorithm) + { + case HashAlgorithmTag.Sha1: + return "SHA1"; + case HashAlgorithmTag.MD2: + return "MD2"; + case HashAlgorithmTag.MD5: + return "MD5"; + case HashAlgorithmTag.RipeMD160: + return "RIPEMD160"; + case HashAlgorithmTag.Sha224: + return "SHA224"; + case HashAlgorithmTag.Sha256: + return "SHA256"; + case HashAlgorithmTag.Sha384: + return "SHA384"; + case HashAlgorithmTag.Sha512: + return "SHA512"; + default: + throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm); + } + } + + public static string GetSignatureName( + PublicKeyAlgorithmTag keyAlgorithm, + HashAlgorithmTag hashAlgorithm) + { + string encAlg; + switch (keyAlgorithm) + { + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + encAlg = "RSA"; + break; + case PublicKeyAlgorithmTag.Dsa: + encAlg = "DSA"; + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases. + case PublicKeyAlgorithmTag.ElGamalGeneral: + encAlg = "ElGamal"; + break; + default: + throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm); + } + + return GetDigestName(hashAlgorithm) + "with" + encAlg; + } + + public static string GetSymmetricCipherName( + SymmetricKeyAlgorithmTag algorithm) + { + switch (algorithm) + { + case SymmetricKeyAlgorithmTag.Null: + return null; + case SymmetricKeyAlgorithmTag.TripleDes: + return "DESEDE"; + case SymmetricKeyAlgorithmTag.Idea: + return "IDEA"; + case SymmetricKeyAlgorithmTag.Cast5: + return "CAST5"; + case SymmetricKeyAlgorithmTag.Blowfish: + return "Blowfish"; + case SymmetricKeyAlgorithmTag.Safer: + return "SAFER"; + case SymmetricKeyAlgorithmTag.Des: + return "DES"; + case SymmetricKeyAlgorithmTag.Aes128: + return "AES"; + case SymmetricKeyAlgorithmTag.Aes192: + return "AES"; + case SymmetricKeyAlgorithmTag.Aes256: + return "AES"; + case SymmetricKeyAlgorithmTag.Twofish: + return "Twofish"; + default: + throw new PgpException("unknown symmetric algorithm: " + algorithm); + } + } + + public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm) + { + int keySize; + switch (algorithm) + { + case SymmetricKeyAlgorithmTag.Des: + keySize = 64; + break; + case SymmetricKeyAlgorithmTag.Idea: + case SymmetricKeyAlgorithmTag.Cast5: + case SymmetricKeyAlgorithmTag.Blowfish: + case SymmetricKeyAlgorithmTag.Safer: + case SymmetricKeyAlgorithmTag.Aes128: + keySize = 128; + break; + case SymmetricKeyAlgorithmTag.TripleDes: + case SymmetricKeyAlgorithmTag.Aes192: + keySize = 192; + break; + case SymmetricKeyAlgorithmTag.Aes256: + case SymmetricKeyAlgorithmTag.Twofish: + keySize = 256; + break; + default: + throw new PgpException("unknown symmetric algorithm: " + algorithm); + } + + return keySize; + } + + public static KeyParameter MakeKey( + SymmetricKeyAlgorithmTag algorithm, + byte[] keyBytes) + { + string algName = GetSymmetricCipherName(algorithm); + + return ParameterUtilities.CreateKeyParameter(algName, keyBytes); + } + + public static KeyParameter MakeRandomKey( + SymmetricKeyAlgorithmTag algorithm, + SecureRandom random) + { + int keySize = GetKeySize(algorithm); + byte[] keyBytes = new byte[(keySize + 7) / 8]; + random.NextBytes(keyBytes); + return MakeKey(algorithm, keyBytes); + } + + public static KeyParameter MakeKeyFromPassPhrase( + SymmetricKeyAlgorithmTag algorithm, + S2k s2k, + char[] passPhrase) + { + int keySize = GetKeySize(algorithm); + byte[] pBytes = Strings.ToByteArray(new string(passPhrase)); + byte[] keyBytes = new byte[(keySize + 7) / 8]; + + int generatedBytes = 0; + int loopCount = 0; + + while (generatedBytes < keyBytes.Length) + { + IDigest digest; + if (s2k != null) + { + try + { + switch (s2k.HashAlgorithm) + { + case HashAlgorithmTag.Sha1: + digest = DigestUtilities.GetDigest("SHA1"); + break; + default: + throw new PgpException("unknown hash algorithm: " + s2k.HashAlgorithm); + } + } + catch (Exception e) + { + throw new PgpException("can't find S2k digest", e); + } + + for (int i = 0; i != loopCount; i++) + { + digest.Update(0); + } + + byte[] iv = s2k.GetIV(); + + switch (s2k.Type) + { + case S2k.Simple: + digest.BlockUpdate(pBytes, 0, pBytes.Length); + break; + case S2k.Salted: + digest.BlockUpdate(iv, 0, iv.Length); + digest.BlockUpdate(pBytes, 0, pBytes.Length); + break; + case S2k.SaltedAndIterated: + long count = s2k.IterationCount; + digest.BlockUpdate(iv, 0, iv.Length); + digest.BlockUpdate(pBytes, 0, pBytes.Length); + + count -= iv.Length + pBytes.Length; + + while (count > 0) + { + if (count < iv.Length) + { + digest.BlockUpdate(iv, 0, (int)count); + break; + } + else + { + digest.BlockUpdate(iv, 0, iv.Length); + count -= iv.Length; + } + + if (count < pBytes.Length) + { + digest.BlockUpdate(pBytes, 0, (int)count); + count = 0; + } + else + { + digest.BlockUpdate(pBytes, 0, pBytes.Length); + count -= pBytes.Length; + } + } + break; + default: + throw new PgpException("unknown S2k type: " + s2k.Type); + } + } + else + { + try + { + digest = DigestUtilities.GetDigest("MD5"); + + for (int i = 0; i != loopCount; i++) + { + digest.Update(0); + } + + digest.BlockUpdate(pBytes, 0, pBytes.Length); + } + catch (Exception e) + { + throw new PgpException("can't find MD5 digest", e); + } + } + + byte[] dig = DigestUtilities.DoFinal(digest); + + if (dig.Length > (keyBytes.Length - generatedBytes)) + { + Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes); + } + else + { + Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length); + } + + generatedBytes += dig.Length; + + loopCount++; + } + + Array.Clear(pBytes, 0, pBytes.Length); + + return MakeKey(algorithm, keyBytes); + } + + /// Write out the passed in file as a literal data packet. + public static void WriteFileToLiteralData( + Stream outputStream, + char fileType, + FileInfo file) + { + Stream inStr = file.OpenRead(); + Stream outStr = new PgpLiteralDataGenerator().Open( + outputStream, fileType, file.Name, file.Length, file.LastWriteTime); + + Streams.PipeAll(inStr, outStr); + + inStr.Close(); + outStr.Close(); + } + + /// Write out the passed in file as a literal data packet in partial packet format. + public static void WriteFileToLiteralData( + Stream outputStream, + char fileType, + FileInfo file, + byte[] buffer) + { + PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); + Stream pOut = lData.Open(outputStream, fileType, file.Name, file.LastWriteTime, buffer); + FileStream inputStream = file.OpenRead(); + byte[] buf = new byte[buffer.Length]; + + int len; + while ((len = inputStream.Read(buf, 0, buf.Length)) > 0) + { + pOut.Write(buf, 0, len); + } + + lData.Close(); + inputStream.Close(); + } + + private const int ReadAhead = 60; + + private static bool IsPossiblyBase64( + int ch) + { + return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '/') + || (ch == '\r') || (ch == '\n'); + } + + /// + /// Return either an ArmoredInputStream or a BcpgInputStream based on whether + /// the initial characters of the stream are binary PGP encodings or not. + /// + public static Stream GetDecoderStream( + Stream inputStream) + { + // TODO Remove this restriction? + if (!inputStream.CanSeek) + throw new ArgumentException("inputStream must be seek-able", "inputStream"); + + long markedPos = inputStream.Position; + + int ch = inputStream.ReadByte(); + if ((ch & 0x80) != 0) + { + inputStream.Position = markedPos; + + return inputStream; + } + else + { + if (!IsPossiblyBase64(ch)) + { + inputStream.Position = markedPos; + + return new ArmoredInputStream(inputStream); + } + + byte[] buf = new byte[ReadAhead]; + int count = 1; + int index = 1; + + buf[0] = (byte)ch; + while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0) + { + if (!IsPossiblyBase64(ch)) + { + inputStream.Position = markedPos; + + return new ArmoredInputStream(inputStream); + } + + if (ch != '\n' && ch != '\r') + { + buf[index++] = (byte)ch; + } + + count++; + } + + inputStream.Position = markedPos; + + // + // nothing but new lines, little else, assume regular armoring + // + if (count < 4) + { + return new ArmoredInputStream(inputStream); + } + + // + // test our non-blank data + // + byte[] firstBlock = new byte[8]; + Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length); + byte[] decoded = Base64.Decode(firstBlock); + + // + // it's a base64 PGP block. + // + bool hasHeaders = (decoded[0] & 0x80) == 0; + + return new ArmoredInputStream(inputStream, hasHeaders); + } + } + } +} diff --git a/iTechSharp/srcbc/openpgp/PgpV3SignatureGenerator.cs b/iTechSharp/srcbc/openpgp/PgpV3SignatureGenerator.cs new file mode 100644 index 0000000..fc8b42d --- /dev/null +++ b/iTechSharp/srcbc/openpgp/PgpV3SignatureGenerator.cs @@ -0,0 +1,199 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Generator for old style PGP V3 Signatures. + // TODO Should be able to implement ISigner? + public class PgpV3SignatureGenerator + { + private PublicKeyAlgorithmTag keyAlgorithm; + private HashAlgorithmTag hashAlgorithm; + private PgpPrivateKey privKey; + private ISigner sig; + private IDigest dig; + private int signatureType; + private byte lastb; + + /// Create a generator for the passed in keyAlgorithm and hashAlgorithm codes. + public PgpV3SignatureGenerator( + PublicKeyAlgorithmTag keyAlgorithm, + HashAlgorithmTag hashAlgorithm) + { + this.keyAlgorithm = keyAlgorithm; + this.hashAlgorithm = hashAlgorithm; + + dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm)); + sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm)); + } + + /// Initialise the generator for signing. + public void InitSign( + int sigType, + PgpPrivateKey key) + { + InitSign(sigType, key, null); + } + + /// Initialise the generator for signing. + public void InitSign( + int sigType, + PgpPrivateKey key, + SecureRandom random) + { + this.privKey = key; + this.signatureType = sigType; + + try + { + ICipherParameters cp = key.Key; + if (random != null) + { + cp = new ParametersWithRandom(key.Key, random); + } + + sig.Init(true, cp); + } + catch (InvalidKeyException e) + { + throw new PgpException("invalid key.", e); + } + + dig.Reset(); + lastb = 0; + } + + public void Update( + byte b) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + doCanonicalUpdateByte(b); + } + else + { + doUpdateByte(b); + } + } + + private void doCanonicalUpdateByte( + byte b) + { + if (b == '\r') + { + doUpdateCRLF(); + } + else if (b == '\n') + { + if (lastb != '\r') + { + doUpdateCRLF(); + } + } + else + { + doUpdateByte(b); + } + + lastb = b; + } + + private void doUpdateCRLF() + { + doUpdateByte((byte)'\r'); + doUpdateByte((byte)'\n'); + } + + private void doUpdateByte( + byte b) + { + sig.Update(b); + dig.Update(b); + } + + public void Update( + byte[] b) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + for (int i = 0; i != b.Length; i++) + { + doCanonicalUpdateByte(b[i]); + } + } + else + { + sig.BlockUpdate(b, 0, b.Length); + dig.BlockUpdate(b, 0, b.Length); + } + } + + public void Update( + byte[] b, + int off, + int len) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + int finish = off + len; + + for (int i = off; i != finish; i++) + { + doCanonicalUpdateByte(b[i]); + } + } + else + { + sig.BlockUpdate(b, off, len); + dig.BlockUpdate(b, off, len); + } + } + + /// Return the one pass header associated with the current signature. + public PgpOnePassSignature GenerateOnePassVersion( + bool isNested) + { + return new PgpOnePassSignature( + new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested)); + } + + /// Return a V3 signature object containing the current signature state. + public PgpSignature Generate() + { + long creationTime = DateTimeUtilities.CurrentUnixMs() / 1000L; + + byte[] hData = new byte[] + { + (byte) signatureType, + (byte)(creationTime >> 24), + (byte)(creationTime >> 16), + (byte)(creationTime >> 8), + (byte) creationTime + }; + + sig.BlockUpdate(hData, 0, hData.Length); + dig.BlockUpdate(hData, 0, hData.Length); + + byte[] sigBytes = sig.GenerateSignature(); + byte[] digest = DigestUtilities.DoFinal(dig); + byte[] fingerPrint = new byte[]{ digest[0], digest[1] }; + + // an RSA signature + bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign + || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral; + + MPInteger[] sigValues = isRsa + ? PgpUtilities.RsaSigToMpi(sigBytes) + : PgpUtilities.DsaSigToMpi(sigBytes); + + return new PgpSignature( + new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm, + hashAlgorithm, creationTime * 1000L, fingerPrint, sigValues)); + } + } +} diff --git a/iTechSharp/srcbc/openpgp/WrappedGeneratorStream.cs b/iTechSharp/srcbc/openpgp/WrappedGeneratorStream.cs new file mode 100644 index 0000000..6fc7329 --- /dev/null +++ b/iTechSharp/srcbc/openpgp/WrappedGeneratorStream.cs @@ -0,0 +1,25 @@ +using System.IO; + +using Org.BouncyCastle.Asn1.Utilities; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + public class WrappedGeneratorStream + : FilterStream + { + private readonly IStreamGenerator gen; + + public WrappedGeneratorStream( + IStreamGenerator gen, + Stream str) + : base(str) + { + this.gen = gen; + } + + public override void Close() + { + gen.Close(); + } + } +} diff --git a/iTechSharp/srcbc/openssl/IPasswordFinder.cs b/iTechSharp/srcbc/openssl/IPasswordFinder.cs new file mode 100644 index 0000000..4fcef1b --- /dev/null +++ b/iTechSharp/srcbc/openssl/IPasswordFinder.cs @@ -0,0 +1,9 @@ +using System; + +namespace Org.BouncyCastle.OpenSsl +{ + public interface IPasswordFinder + { + char[] GetPassword(); + } +} diff --git a/iTechSharp/srcbc/openssl/PEMReader.cs b/iTechSharp/srcbc/openssl/PEMReader.cs new file mode 100644 index 0000000..8d63847 --- /dev/null +++ b/iTechSharp/srcbc/openssl/PEMReader.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.OpenSsl +{ + /** + * Class for reading OpenSSL PEM encoded streams containing + * X509 certificates, PKCS8 encoded keys and PKCS7 objects. + *

      + * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and + * Certificates will be returned using the appropriate java.security type.

      + */ + public class PemReader + { + private readonly TextReader reader; + private readonly IPasswordFinder pFinder; + + public TextReader Reader + { + get { return reader; } + } + + /** + * Create a new PemReader + * + * @param reader the Reader + */ + public PemReader( + TextReader reader) + : this(reader, null) + { + } + + /** + * Create a new PemReader with a password finder + * + * @param reader the Reader + * @param pFinder the password finder + */ + public PemReader( + TextReader reader, + IPasswordFinder pFinder) + { + if (reader == null) + throw new ArgumentNullException("reader"); + + this.reader = reader; + this.pFinder = pFinder; + } + + private const string BeginString = "-----BEGIN "; + + public object ReadObject() + { + string line; + while ((line = reader.ReadLine()) != null) + { + int startPos = line.IndexOf(BeginString); + if (startPos == -1) + continue; + + startPos += BeginString.Length; + + int endPos = line.IndexOf('-', startPos); + if (endPos == -1) + endPos = line.Length; + + string headerName = line.Substring(startPos, endPos - startPos).Trim(); + //Console.WriteLine("[" + headerName + "]"); + + string endMarker = "-----END " + headerName; + + switch (headerName) + { + case "PUBLIC KEY": + return ReadPublicKey(endMarker); + case "RSA PUBLIC KEY": + return ReadRsaPublicKey(endMarker); + case "CERTIFICATE REQUEST": + case "NEW CERTIFICATE REQUEST": + return ReadCertificateRequest(endMarker); + case "CERTIFICATE": + case "X509 CERTIFICATE": + return ReadCertificate(endMarker); + case "PKCS7": + return ReadPkcs7(endMarker); + case "X509 CRL": + return ReadCrl(endMarker); + case "ATTRIBUTE CERTIFICATE": + return ReadAttributeCertificate(endMarker); + case "RSA PRIVATE KEY": + return ReadKeyPair("RSA", endMarker); + case "DSA PRIVATE KEY": + return ReadKeyPair("DSA", endMarker); + // TODO Add back in when tests done, and return type issue resolved + //case "EC PARAMETERS": + // return ReadECParameters(endMarker); + case "EC PRIVATE KEY": + return ReadECPrivateKey(endMarker); + default: + // TODO Throw an exception for an unknown header? + + // Ignore contents + ReadBytes(endMarker); + break; + } + } + + return null; + } + + private byte[] ReadBytes( + string endMarker) + { + return ReadBytesAndFields(endMarker, null); + } + + private byte[] ReadBytesAndFields( + string endMarker, + IDictionary fields) + { + StringBuilder buf = new StringBuilder(); + + string line; + while ((line = reader.ReadLine()) != null + && line.IndexOf(endMarker) == -1) + { + int colonPos = line.IndexOf(':'); + + if (colonPos == -1) + { + buf.Append(line.Trim()); + } + else if (fields != null) + { + // Process field + string fieldName = line.Substring(0, colonPos).Trim(); + + if (fieldName.StartsWith("X-")) + fieldName = fieldName.Substring(2); + + string fieldValue = line.Substring(colonPos + 1).Trim(); + + // TODO Complain if field already specified? + fields[fieldName] = fieldValue; + } + } + + if (line == null) + { + throw new IOException(endMarker + " not found"); + } + + if (buf.Length % 4 != 0) + { + throw new IOException("base64 data appears to be truncated"); + } + + return Base64.Decode(buf.ToString()); + } + + private AsymmetricKeyParameter ReadRsaPublicKey( + string endMarker) + { + RsaPublicKeyStructure rsaPubStructure = RsaPublicKeyStructure.GetInstance( + Asn1Object.FromByteArray( + ReadBytes(endMarker))); + + return new RsaKeyParameters( + false, // not private + rsaPubStructure.Modulus, + rsaPubStructure.PublicExponent); + } + + private AsymmetricKeyParameter ReadPublicKey( + string endMarker) + { + return PublicKeyFactory.CreateKey( + ReadBytes(endMarker)); + } + + /** + * Reads in a X509Certificate. + * + * @return the X509Certificate + * @throws IOException if an I/O error occured + */ + private X509Certificate ReadCertificate( + string endMarker) + { + byte[] bytes = ReadBytes(endMarker); + + try + { + return new X509CertificateParser().ReadCertificate(bytes); + } + catch (Exception e) + { + throw new IOException("problem parsing cert: " + e.ToString()); + } + } + + /** + * Reads in a X509CRL. + * + * @return the X509Certificate + * @throws IOException if an I/O error occured + */ + private X509Crl ReadCrl( + string endMarker) + { + byte[] bytes = ReadBytes(endMarker); + + try + { + return new X509CrlParser().ReadCrl(bytes); + } + catch (Exception e) + { + throw new IOException("problem parsing cert: " + e.ToString()); + } + } + + /** + * Reads in a PKCS10 certification request. + * + * @return the certificate request. + * @throws IOException if an I/O error occured + */ + private Pkcs10CertificationRequest ReadCertificateRequest( + string endMarker) + { + byte[] bytes = ReadBytes(endMarker); + + try + { + return new Pkcs10CertificationRequest(bytes); + } + catch (Exception e) + { + throw new IOException("problem parsing cert: " + e.ToString()); + } + } + + /** + * Reads in a X509 Attribute Certificate. + * + * @return the X509 Attribute Certificate + * @throws IOException if an I/O error occured + */ + private IX509AttributeCertificate ReadAttributeCertificate( + string endMarker) + { + byte[] bytes = ReadBytes(endMarker); + + return new X509V2AttributeCertificate(bytes); + } + + /** + * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS + * API. + * + * @return the X509Certificate + * @throws IOException if an I/O error occured + */ + // TODO Consider returning Asn1.Pkcs.ContentInfo + private Asn1.Cms.ContentInfo ReadPkcs7( + string endMarker) + { + byte[] bytes = ReadBytes(endMarker); + + try + { + return Asn1.Cms.ContentInfo.GetInstance( + Asn1Object.FromByteArray(bytes)); + } + catch (Exception e) + { + throw new IOException("problem parsing PKCS7 object: " + e.ToString()); + } + } + + /** + * Read a Key Pair + */ + private AsymmetricCipherKeyPair ReadKeyPair( + string type, + string endMarker) + { + // + // extract the key + // + IDictionary fields = new Hashtable(); + byte[] keyBytes = ReadBytesAndFields(endMarker, fields); + + string procType = (string) fields["Proc-Type"]; + + if (procType == "4,ENCRYPTED") + { + if (pFinder == null) + throw new InvalidOperationException("No password finder specified, but a password is required"); + + char[] password = pFinder.GetPassword(); + + if (password == null) + throw new IOException("Password is null, but a password is required"); + + string dekInfo = (string) fields["DEK-Info"]; + string[] tknz = dekInfo.Split(','); + + string dekAlgName = tknz[0].Trim(); + byte[] iv = Hex.Decode(tknz[1].Trim()); + + keyBytes = PemUtilities.Crypt(false, keyBytes, password, dekAlgName, iv); + } + + try + { + AsymmetricKeyParameter pubSpec, privSpec; + Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(keyBytes); + + switch (type) + { + case "RSA": + { + RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq); + + pubSpec = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent); + privSpec = new RsaPrivateCrtKeyParameters( + rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, + rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, + rsa.Coefficient); + + break; + } + + case "DSA": + { + // TODO Create an ASN1 object somewhere for this? + //DerInteger v = (DerInteger)seq[0]; + DerInteger p = (DerInteger)seq[1]; + DerInteger q = (DerInteger)seq[2]; + DerInteger g = (DerInteger)seq[3]; + DerInteger y = (DerInteger)seq[4]; + DerInteger x = (DerInteger)seq[5]; + + DsaParameters parameters = new DsaParameters(p.Value, q.Value, g.Value); + + privSpec = new DsaPrivateKeyParameters(x.Value, parameters); + pubSpec = new DsaPublicKeyParameters(y.Value, parameters); + + break; + } + + default: + throw new ArgumentException("Unknown key type: " + type, "type"); + } + + return new AsymmetricCipherKeyPair(pubSpec, privSpec); + } + catch (Exception e) + { + throw new IOException( + "problem creating " + type + " private key: " + e.ToString()); + } + } + + // TODO Add an equivalent class for ECNamedCurveParameterSpec? + //private ECNamedCurveParameterSpec ReadECParameters( + private X9ECParameters ReadECParameters( + string endMarker) + { + byte[] bytes = ReadBytes(endMarker); + DerObjectIdentifier oid = (DerObjectIdentifier) Asn1Object.FromByteArray(bytes); + + //return ECNamedCurveTable.getParameterSpec(oid.Id); + return GetCurveParameters(oid.Id); + } + + //private static ECDomainParameters GetCurveParameters( + private static X9ECParameters GetCurveParameters( + string name) + { + // TODO ECGost3410NamedCurves support (returns ECDomainParameters though) + X9ECParameters ecP = X962NamedCurves.GetByName(name); + + if (ecP == null) + { + ecP = SecNamedCurves.GetByName(name); + if (ecP == null) + { + ecP = NistNamedCurves.GetByName(name); + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.GetByName(name); + + if (ecP == null) + throw new Exception("unknown curve name: " + name); + } + } + } + + //return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed()); + return ecP; + } + + private AsymmetricCipherKeyPair ReadECPrivateKey( + string endMarker) + { + try + { + byte[] bytes = ReadBytes(endMarker); + ECPrivateKeyStructure pKey = new ECPrivateKeyStructure( + (Asn1Sequence) Asn1Object.FromByteArray(bytes)); + AlgorithmIdentifier algId = new AlgorithmIdentifier( + X9ObjectIdentifiers.IdECPublicKey, pKey.GetParameters()); + + PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.ToAsn1Object()); + SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.GetPublicKey().GetBytes()); + + // TODO Are the keys returned here ECDSA, as Java version forces? + return new AsymmetricCipherKeyPair( + PublicKeyFactory.CreateKey(pubInfo), + PrivateKeyFactory.CreateKey(privInfo)); + } + catch (InvalidCastException e) + { + throw new IOException("wrong ASN.1 object found in stream.", e); + } + catch (Exception e) + { + throw new IOException("problem parsing EC private key.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/openssl/PEMUtilities.cs b/iTechSharp/srcbc/openssl/PEMUtilities.cs new file mode 100644 index 0000000..ca944a8 --- /dev/null +++ b/iTechSharp/srcbc/openssl/PEMUtilities.cs @@ -0,0 +1,138 @@ +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.OpenSsl +{ + internal sealed class PemUtilities + { + internal static bool ParseDekAlgName( + string dekAlgName, + out string baseAlg, + out string mode) + { + baseAlg = dekAlgName; + mode = "ECB"; + + if (dekAlgName == "DES-EDE" || dekAlgName == "DES-EDE3") + return true; + + int pos = dekAlgName.LastIndexOf('-'); + if (pos < 0) + return false; + + baseAlg = dekAlgName.Substring(0, pos); + mode = dekAlgName.Substring(pos + 1); + + return true; + } + + internal static byte[] Crypt( + bool encrypt, + byte[] bytes, + char[] password, + string dekAlgName, + byte[] iv) + { + string baseAlg, mode; + if (!ParseDekAlgName(dekAlgName, out baseAlg, out mode)) + throw new ArgumentException("Unknown DEK algorithm: " + dekAlgName, "dekAlgName"); + + string padding; + switch (mode) + { + case "CBC": + case "ECB": + padding = "PKCS5Padding"; + break; + case "CFB": + case "OFB": + padding = "NoPadding"; + break; + default: + throw new ArgumentException("Unknown DEK algorithm: " + dekAlgName, "dekAlgName"); + } + + string algorithm; + + byte[] salt = iv; + switch (baseAlg) + { + case "AES-128": + case "AES-192": + case "AES-256": + algorithm = "AES"; + if (salt.Length > 8) + { + salt = new byte[8]; + Array.Copy(iv, 0, salt, 0, salt.Length); + } + break; + case "BF": + algorithm = "BLOWFISH"; + break; + case "DES": + algorithm = "DES"; + break; + case "DES-EDE": + case "DES-EDE3": + algorithm = "DESede"; + break; + case "RC2": + case "RC2-40": + case "RC2-64": + algorithm = "RC2"; + break; + default: + throw new ArgumentException("Unknown DEK algorithm: " + dekAlgName, "dekAlgName"); + } + + string cipherName = algorithm + "/" + mode + "/" + padding; + IBufferedCipher cipher = CipherUtilities.GetCipher(cipherName); + + ICipherParameters cParams = GetCipherParameters(password, baseAlg, salt); + + if (mode != "ECB") + { + cParams = new ParametersWithIV(cParams, iv); + } + + cipher.Init(encrypt, cParams); + + return cipher.DoFinal(bytes); + } + + private static ICipherParameters GetCipherParameters( + char[] password, + string baseAlg, + byte[] salt) + { + string algorithm; + int keyBits; + switch (baseAlg) + { + case "AES-128": keyBits = 128; algorithm = "AES128"; break; + case "AES-192": keyBits = 192; algorithm = "AES192"; break; + case "AES-256": keyBits = 256; algorithm = "AES256"; break; + case "BF": keyBits = 128; algorithm = "BLOWFISH"; break; + case "DES": keyBits = 64; algorithm = "DES"; break; + case "DES-EDE": keyBits = 128; algorithm = "DESEDE"; break; + case "DES-EDE3": keyBits = 192; algorithm = "DESEDE3"; break; + case "RC2": keyBits = 128; algorithm = "RC2"; break; + case "RC2-40": keyBits = 40; algorithm = "RC2"; break; + case "RC2-64": keyBits = 64; algorithm = "RC2"; break; + default: + return null; + } + + OpenSslPbeParametersGenerator pGen = new OpenSslPbeParametersGenerator(); + + pGen.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt); + + return pGen.GenerateDerivedParameters(algorithm, keyBits); + } + } +} diff --git a/iTechSharp/srcbc/openssl/PEMWriter.cs b/iTechSharp/srcbc/openssl/PEMWriter.cs new file mode 100644 index 0000000..bea67b6 --- /dev/null +++ b/iTechSharp/srcbc/openssl/PEMWriter.cs @@ -0,0 +1,278 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.OpenSsl +{ + /// General purpose writer for OpenSSL PEM objects. + public class PemWriter + { + private readonly TextWriter writer; + + public TextWriter Writer + { + get { return writer; } + } + + /// The TextWriter object to write the output to. + public PemWriter( + TextWriter writer) + { + if (writer == null) + throw new ArgumentNullException("writer"); + + this.writer = writer; + } + + public void WriteObject( + object obj) + { + if (obj == null) + throw new ArgumentNullException("obj"); + + string type; + byte[] encoding; + + if (obj is X509Certificate) + { + // TODO Should we prefer "X509 CERTIFICATE" here? + type = "CERTIFICATE"; + try + { + encoding = ((X509Certificate)obj).GetEncoded(); + } + catch (CertificateEncodingException e) + { + throw new IOException("Cannot Encode object: " + e.ToString()); + } + } + else if (obj is X509Crl) + { + type = "X509 CRL"; + try + { + encoding = ((X509Crl)obj).GetEncoded(); + } + catch (CrlException e) + { + throw new IOException("Cannot Encode object: " + e.ToString()); + } + } + else if (obj is AsymmetricCipherKeyPair) + { + WriteObject(((AsymmetricCipherKeyPair)obj).Private); + return; + } + else if (obj is AsymmetricKeyParameter) + { + AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj; + if (akp.IsPrivate) + { + string keyType; + encoding = EncodePrivateKey(akp, out keyType); + + type = keyType + " PRIVATE KEY"; + } + else + { + type = "PUBLIC KEY"; + + encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded(); + } + } + else if (obj is IX509AttributeCertificate) + { + type = "ATTRIBUTE CERTIFICATE"; + encoding = ((X509V2AttributeCertificate)obj).GetEncoded(); + } + else if (obj is Pkcs10CertificationRequest) + { + type = "CERTIFICATE REQUEST"; + encoding = ((Pkcs10CertificationRequest)obj).GetEncoded(); + } + else if (obj is Asn1.Cms.ContentInfo) + { + type = "PKCS7"; + encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded(); + } + else + { + throw new ArgumentException("Object type not supported: " + obj.GetType().FullName, "obj"); + } + + WritePemBlock(type, encoding); + } + + public void WriteObject( + object obj, + string algorithm, + char[] password, + SecureRandom random) + { + if (obj == null) + throw new ArgumentNullException("obj"); + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + if (password == null) + throw new ArgumentNullException("password"); + if (random == null) + throw new ArgumentNullException("random"); + + if (obj is AsymmetricCipherKeyPair) + { + WriteObject(((AsymmetricCipherKeyPair) obj).Private, algorithm, password, random); + return; + } + + string type = null; + byte[] keyData = null; + + if (obj is AsymmetricKeyParameter) + { + AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj; + if (akp.IsPrivate) + { + string keyType; + keyData = EncodePrivateKey(akp, out keyType); + + type = keyType + " PRIVATE KEY"; + } + } + + if (type == null || keyData == null) + { + // TODO Support other types? + throw new ArgumentException("Object type not supported: " + obj.GetType().FullName, "obj"); + } + + + string dekAlgName = algorithm.ToUpper(CultureInfo.InvariantCulture); + + // Note: For backward compatibility + if (dekAlgName == "DESEDE") + { + dekAlgName = "DES-EDE3-CBC"; + } + + int ivLength = dekAlgName.StartsWith("AES-") ? 16 : 8; + + byte[] iv = new byte[ivLength]; + random.NextBytes(iv); + + byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv); + byte[] hexIV = Hex.Encode(iv); + + WritePemBlock(type, encData, + "Proc-Type: 4,ENCRYPTED", + "DEK-Info: " + dekAlgName + "," + Encoding.ASCII.GetString(hexIV, 0, hexIV.Length)); + } + + private byte[] EncodePrivateKey( + AsymmetricKeyParameter akp, + out string keyType) + { + PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp); + + DerObjectIdentifier oid = info.AlgorithmID.ObjectID; + + if (oid.Equals(X9ObjectIdentifiers.IdDsa)) + { + keyType = "DSA"; + + DsaParameter p = DsaParameter.GetInstance(info.AlgorithmID.Parameters); + + BigInteger x = ((DsaPrivateKeyParameters) akp).X; + BigInteger y = p.G.ModPow(x, p.P); + + // TODO Create an ASN1 object somewhere for this? + return new DerSequence( + new DerInteger(0), + new DerInteger(p.P), + new DerInteger(p.Q), + new DerInteger(p.G), + new DerInteger(y), + new DerInteger(x)).GetEncoded(); + } + + if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption)) + { + keyType = "RSA"; + return info.PrivateKey.GetEncoded(); + } + + throw new ArgumentException("Cannot handle private key of type: " + akp.GetType().FullName, "akp"); + } + + private void WritePemBlock( + string type, + byte[] data, + params string[] fields) + { + WriteHeader(type); + + if (fields.Length > 0) + { + foreach (string field in fields) + { + writer.WriteLine(field); + } + + writer.WriteLine(); + } + + WriteBytes(Base64.Encode(data)); + + WriteFooter(type); + } + + private void WriteHeader( + string type) + { + writer.WriteLine("-----BEGIN " + type + "-----"); + } + + private void WriteFooter( + string type) + { + writer.WriteLine("-----END " + type + "-----"); + } + + private const int LineLength = 64; + + private void WriteBytes( + byte[] bytes) + { + int pos = 0; + int remaining = bytes.Length; + char[] buf = new char[LineLength]; + + while (remaining > LineLength) + { + Encoding.ASCII.GetChars(bytes, pos, LineLength, buf, 0); + writer.WriteLine(buf); + + pos += LineLength; + remaining -= LineLength; + } + + Encoding.ASCII.GetChars(bytes, pos, remaining, buf, 0); + writer.WriteLine(buf, 0, remaining); + } + } +} diff --git a/iTechSharp/srcbc/pkcs/AsymmetricKeyEntry.cs b/iTechSharp/srcbc/pkcs/AsymmetricKeyEntry.cs new file mode 100644 index 0000000..ad308ea --- /dev/null +++ b/iTechSharp/srcbc/pkcs/AsymmetricKeyEntry.cs @@ -0,0 +1,32 @@ +using System.Collections; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Pkcs +{ + public class AsymmetricKeyEntry + : Pkcs12Entry + { + private readonly AsymmetricKeyParameter key; + + public AsymmetricKeyEntry( + AsymmetricKeyParameter key) + : base(new Hashtable()) + { + this.key = key; + } + + public AsymmetricKeyEntry( + AsymmetricKeyParameter key, + Hashtable attributes) + : base(attributes) + { + this.key = key; + } + + public AsymmetricKeyParameter Key + { + get { return this.key; } + } + } +} diff --git a/iTechSharp/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs b/iTechSharp/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs new file mode 100644 index 0000000..1292dd4 --- /dev/null +++ b/iTechSharp/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs @@ -0,0 +1,75 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pkcs +{ + public sealed class EncryptedPrivateKeyInfoFactory + { + private EncryptedPrivateKeyInfoFactory() + { + } + + public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( + DerObjectIdentifier algorithm, + char[] passPhrase, + byte[] salt, + int iterationCount, + AsymmetricKeyParameter key) + { + return CreateEncryptedPrivateKeyInfo( + algorithm.Id, passPhrase, salt, iterationCount, + PrivateKeyInfoFactory.CreatePrivateKeyInfo(key)); + } + + public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( + string algorithm, + char[] passPhrase, + byte[] salt, + int iterationCount, + AsymmetricKeyParameter key) + { + return CreateEncryptedPrivateKeyInfo( + algorithm, passPhrase, salt, iterationCount, + PrivateKeyInfoFactory.CreatePrivateKeyInfo(key)); + } + + public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( + string algorithm, + char[] passPhrase, + byte[] salt, + int iterationCount, + PrivateKeyInfo keyInfo) + { + if (!PbeUtilities.IsPbeAlgorithm(algorithm)) + throw new ArgumentException("attempt to use non-Pbe algorithm with Pbe EncryptedPrivateKeyInfo generation"); + + IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher; + + if (cipher == null) + { + // TODO Throw exception? + } + + Asn1Encodable parameters = PbeUtilities.GenerateAlgorithmParameters( + algorithm, salt, iterationCount); + + ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters( + algorithm, passPhrase, parameters); + + cipher.Init(true, keyParameters); + + byte[] keyBytes = keyInfo.GetEncoded(); + byte[] encoding = cipher.DoFinal(keyBytes); + + DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm); + AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, parameters); + + return new EncryptedPrivateKeyInfo(algID, encoding); + } + } +} diff --git a/iTechSharp/srcbc/pkcs/Pkcs10CertificationRequest.cs b/iTechSharp/srcbc/pkcs/Pkcs10CertificationRequest.cs new file mode 100644 index 0000000..d090657 --- /dev/null +++ b/iTechSharp/srcbc/pkcs/Pkcs10CertificationRequest.cs @@ -0,0 +1,447 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Pkcs +{ + /// + /// A class for verifying and creating Pkcs10 Certification requests. + /// + /// + /// CertificationRequest ::= Sequence { + /// certificationRequestInfo CertificationRequestInfo, + /// signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + /// signature BIT STRING + /// } + /// + /// CertificationRequestInfo ::= Sequence { + /// version Integer { v1(0) } (v1,...), + /// subject Name, + /// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + /// attributes [0] Attributes{{ CRIAttributes }} + /// } + /// + /// Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }} + /// + /// Attr { ATTRIBUTE:IOSet } ::= Sequence { + /// type ATTRIBUTE.&id({IOSet}), + /// values Set SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + /// } + /// + /// see + public class Pkcs10CertificationRequest + : CertificationRequest + { + private static readonly Hashtable algorithms = new Hashtable(); + private static readonly Hashtable exParams = new Hashtable(); + private static readonly Hashtable keyAlgorithms = new Hashtable(); + private static readonly Hashtable oids = new Hashtable(); + private static readonly ISet noParams = new HashSet(); + + static Pkcs10CertificationRequest() + { + algorithms.Add("MD2WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.2")); + algorithms.Add("MD2WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.2")); + algorithms.Add("MD5WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.Add("MD5WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.Add("RSAWITHMD5", new DerObjectIdentifier("1.2.840.113549.1.1.4")); + algorithms.Add("SHA1WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.Add("SHA1WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("RSAWITHSHA1", new DerObjectIdentifier("1.2.840.113549.1.1.5")); + algorithms.Add("RIPEMD160WITHRSAENCRYPTION", new DerObjectIdentifier("1.3.36.3.3.1.2")); + algorithms.Add("RIPEMD160WITHRSA", new DerObjectIdentifier("1.3.36.3.3.1.2")); + algorithms.Add("SHA1WITHDSA", new DerObjectIdentifier("1.2.840.10040.4.3")); + algorithms.Add("DSAWITHSHA1", new DerObjectIdentifier("1.2.840.10040.4.3")); + algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224); + algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256); + algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224); + algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256); + algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384); + algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512); + algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + + // + // reverse mappings + // + oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA"); + oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA"); + oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410"); + oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, "GOST3411WITHECGOST3410"); + + oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); + oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA"); + oids.Add(new DerObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA"); + oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA"); + oids.Add(OiwObjectIdentifiers.Sha1WithRsa, "SHA1WITHRSA"); + oids.Add(OiwObjectIdentifiers.DsaWithSha1, "SHA1WITHDSA"); + oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA"); + oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA"); + + // + // key types + // + keyAlgorithms.Add(PkcsObjectIdentifiers.RsaEncryption, "RSA"); + keyAlgorithms.Add(X9ObjectIdentifiers.IdDsa, "DSA"); + + // + // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. + // The parameters field SHALL be NULL for RSA based signature algorithms. + // + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512); + noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1); + noParams.Add(NistObjectIdentifiers.DsaWithSha224); + noParams.Add(NistObjectIdentifiers.DsaWithSha256); + + // + // RFC 4491 + // + noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + + // + // explicit params + // + AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance); + exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20)); + + AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance); + exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28)); + + AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance); + exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32)); + + AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance); + exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48)); + + AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance); + exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64)); + } + + private static RsassaPssParameters CreatePssParams( + AlgorithmIdentifier hashAlgId, + int saltSize) + { + return new RsassaPssParameters( + hashAlgId, + new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId), + new DerInteger(saltSize), + new DerInteger(1)); + } + + public Pkcs10CertificationRequest( + byte[] encoded) + : base((Asn1Sequence) Asn1Object.FromByteArray(encoded)) + { + } + + public Pkcs10CertificationRequest( + Asn1Sequence seq) + : base(seq) + { + } + + public Pkcs10CertificationRequest( + Stream input) + : base((Asn1Sequence) Asn1Object.FromStream(input)) + { + } + + /// + /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials. + /// + ///Name of Sig Alg. + /// X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" + /// Public Key to be included in cert reqest. + /// ASN1Set of Attributes. + /// Matching Private key for nominated (above) public key to be used to sign the request. + public Pkcs10CertificationRequest( + string signatureAlgorithm, + X509Name subject, + AsymmetricKeyParameter publicKey, + Asn1Set attributes, + AsymmetricKeyParameter signingKey) + { + if (signatureAlgorithm == null) + throw new ArgumentNullException("signatureAlgorithm"); + if (subject == null) + throw new ArgumentNullException("subject"); + if (publicKey == null) + throw new ArgumentNullException("publicKey"); + if (publicKey.IsPrivate) + throw new ArgumentException("expected public key", "publicKey"); + if (!signingKey.IsPrivate) + throw new ArgumentException("key for signing must be private", "signingKey"); + +// DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm); + string algorithmName = signatureAlgorithm.ToUpper(CultureInfo.InvariantCulture); + DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName]; + + if (sigOid == null) + throw new ArgumentException("Unknown signature type requested"); + + if (noParams.Contains(sigOid)) + { + this.sigAlgId = new AlgorithmIdentifier(sigOid); + } + else if (exParams.ContainsKey(algorithmName)) + { + this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]); + } + else + { + this.sigAlgId = new AlgorithmIdentifier(sigOid, null); + } + + SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); + + this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes); + + ISigner sig = SignerUtilities.GetSigner(signatureAlgorithm); + + sig.Init(true, signingKey); + + try + { + // Encode. + byte[] b = reqInfo.GetDerEncoded(); + sig.BlockUpdate(b, 0, b.Length); + } + catch (Exception e) + { + throw new ArgumentException("exception encoding TBS cert request", e); + } + + // Generate Signature. + sigBits = new DerBitString(sig.GenerateSignature()); + } + +// internal Pkcs10CertificationRequest( +// Asn1InputStream seqStream) +// { +// Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject(); +// try +// { +// this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]); +// this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]); +// this.sigBits = (DerBitString) seq[2]; +// } +// catch (Exception ex) +// { +// throw new ArgumentException("Create From Asn1Sequence: " + ex.Message); +// } +// } + + /// + /// Get the public key. + /// + /// The public key. + public AsymmetricKeyParameter GetPublicKey() + { + return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo); + } + + /// + /// Verify Pkcs10 Cert Request is valid. + /// + /// true = valid. + public bool Verify() + { + return Verify(this.GetPublicKey()); + } + + public bool Verify( + AsymmetricKeyParameter publicKey) + { + ISigner sig; + + try + { + sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId)); + } + catch (Exception e) + { + // try an alternate + string alt = (string) oids[sigAlgId.ObjectID]; + + if (alt != null) + { + sig = SignerUtilities.GetSigner(alt); + } + else + { + throw e; + } + } + + SetSignatureParameters(sig, sigAlgId.Parameters); + + sig.Init(false, publicKey); + + try + { + byte[] b = reqInfo.GetDerEncoded(); + sig.BlockUpdate(b, 0, b.Length); + } + catch (Exception e) + { + throw new SignatureException("exception encoding TBS cert request", e); + } + + return sig.VerifySignature(sigBits.GetBytes()); + } + +// /// +// /// Get the Der Encoded Pkcs10 Certification Request. +// /// +// /// A byte array. +// public byte[] GetEncoded() +// { +// return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded(); +// } + + // TODO Figure out how to set parameters on an ISigner + private void SetSignatureParameters( + ISigner signature, + Asn1Encodable asn1Params) + { + if (asn1Params != null && !(asn1Params is Asn1Null)) + { +// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm()); +// +// try +// { +// sigParams.init(asn1Params.ToAsn1Object().GetDerEncoded()); +// } +// catch (IOException e) +// { +// throw new SignatureException("IOException decoding parameters: " + e.Message); +// } + + if (signature.AlgorithmName.EndsWith("MGF1")) + { + throw Platform.CreateNotImplementedException("signature algorithm with MGF1"); + +// try +// { +// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class)); +// } +// catch (GeneralSecurityException e) +// { +// throw new SignatureException("Exception extracting parameters: " + e.getMessage()); +// } + } + } + } + + internal static string GetSignatureName( + AlgorithmIdentifier sigAlgId) + { + Asn1Encodable asn1Params = sigAlgId.Parameters; + + if (asn1Params != null && !(asn1Params is Asn1Null)) + { + if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss)) + { + RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(asn1Params); + return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1"; + } + } + + return sigAlgId.ObjectID.Id; + } + + private static string GetDigestAlgName( + DerObjectIdentifier digestAlgOID) + { + if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID)) + { + return "MD5"; + } + else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID)) + { + return "SHA1"; + } + else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID)) + { + return "SHA224"; + } + else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID)) + { + return "SHA256"; + } + else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID)) + { + return "SHA384"; + } + else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID)) + { + return "SHA512"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID)) + { + return "RIPEMD128"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID)) + { + return "RIPEMD160"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID)) + { + return "RIPEMD256"; + } + else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID)) + { + return "GOST3411"; + } + else + { + return digestAlgOID.Id; + } + } + } +} diff --git a/iTechSharp/srcbc/pkcs/Pkcs12Entry.cs b/iTechSharp/srcbc/pkcs/Pkcs12Entry.cs new file mode 100644 index 0000000..8b634d9 --- /dev/null +++ b/iTechSharp/srcbc/pkcs/Pkcs12Entry.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Pkcs +{ + public abstract class Pkcs12Entry + { + private readonly Hashtable attributes; + + protected internal Pkcs12Entry( + Hashtable attributes) + { + this.attributes = attributes; + + foreach (DictionaryEntry entry in attributes) + { + if (!(entry.Key is string)) + throw new ArgumentException("Attribute keys must be of type: " + typeof(string).FullName, "attributes"); + if (!(entry.Value is Asn1Encodable)) + throw new ArgumentException("Attribute values must be of type: " + typeof(Asn1Encodable).FullName, "attributes"); + } + } + + [Obsolete("Use 'object[index]' syntax instead")] + public Asn1Encodable GetBagAttribute( + DerObjectIdentifier oid) + { + return (Asn1Encodable)this.attributes[oid.Id]; + } + + [Obsolete("Use 'object[index]' syntax instead")] + public Asn1Encodable GetBagAttribute( + string oid) + { + return (Asn1Encodable)this.attributes[oid]; + } + + [Obsolete("Use 'BagAttributeKeys' property")] + public IEnumerator GetBagAttributeKeys() + { + return this.attributes.Keys.GetEnumerator(); + } + + public Asn1Encodable this[ + DerObjectIdentifier oid] + { + get { return (Asn1Encodable) this.attributes[oid.Id]; } + } + + public Asn1Encodable this[ + string oid] + { + get { return (Asn1Encodable) this.attributes[oid]; } + } + + public IEnumerable BagAttributeKeys + { + get { return new EnumerableProxy(this.attributes.Keys); } + } + } +} diff --git a/iTechSharp/srcbc/pkcs/Pkcs12Store.cs b/iTechSharp/srcbc/pkcs/Pkcs12Store.cs new file mode 100644 index 0000000..b5504ef --- /dev/null +++ b/iTechSharp/srcbc/pkcs/Pkcs12Store.cs @@ -0,0 +1,1129 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Pkcs +{ + public class Pkcs12Store + { + private readonly IgnoresCaseHashtable keys = new IgnoresCaseHashtable(); + private readonly Hashtable localIds = new Hashtable(); + private readonly IgnoresCaseHashtable certs = new IgnoresCaseHashtable(); + private readonly Hashtable chainCerts = new Hashtable(); + private readonly Hashtable keyCerts = new Hashtable(); + + private static readonly DerObjectIdentifier keyAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc; + private static readonly DerObjectIdentifier CertAlgorithm = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc; + private int MinIterations = 1024; + private int saltSize = 20; + + private static SubjectKeyIdentifier CreateSubjectKeyID( + AsymmetricKeyParameter pubKey) + { + return new SubjectKeyIdentifier( + SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey)); + } + + internal class CertId + { + private readonly byte[] id; + + internal CertId( + AsymmetricKeyParameter pubKey) + { + this.id = CreateSubjectKeyID(pubKey).GetKeyIdentifier(); + } + + internal CertId( + byte[] id) + { + this.id = id; + } + + internal byte[] Id + { + get { return id; } + } + + public override int GetHashCode() + { + return Arrays.GetHashCode(id); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + CertId other = obj as CertId; + + if (other == null) + return false; + + return Arrays.AreEqual(id, other.id); + } + } + + public Pkcs12Store() + { + } + + public Pkcs12Store( + Stream input, + char[] password) + { + if (input == null) + throw new ArgumentNullException("input"); + if (password == null) + throw new ArgumentNullException("password"); + + Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input); + Pfx bag = new Pfx(obj); + ContentInfo info = bag.AuthSafe; + bool unmarkedKey = false; + bool wrongPkcs12Zero = false; + + if (bag.MacData != null) // check the mac code + { + MacData mData = bag.MacData; + DigestInfo dInfo = mData.Mac; + AlgorithmIdentifier algId = dInfo.AlgorithmID; + byte[] salt = mData.GetSalt(); + int itCount = mData.IterationCount.IntValue; + + byte[] data = ((Asn1OctetString) info.Content).GetOctets(); + + byte[] mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, false, data); + byte[] dig = dInfo.GetDigest(); + + if (!Arrays.AreEqual(mac, dig)) + { + if (password.Length > 0) + throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file."); + + // Try with incorrect zero length password + mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, true, data); + + if (!Arrays.AreEqual(mac, dig)) + throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file."); + + wrongPkcs12Zero = true; + } + } + + ArrayList chain = new ArrayList(); + + if (info.ContentType.Equals(PkcsObjectIdentifiers.Data)) + { + byte[] octs = ((Asn1OctetString)info.Content).GetOctets(); + AuthenticatedSafe authSafe = new AuthenticatedSafe( + (Asn1Sequence) Asn1OctetString.FromByteArray(octs)); + ContentInfo[] cis = authSafe.GetContentInfo(); + + foreach (ContentInfo ci in cis) + { + DerObjectIdentifier oid = ci.ContentType; + + if (oid.Equals(PkcsObjectIdentifiers.Data)) + { + byte[] octets = ((Asn1OctetString)ci.Content).GetOctets(); + Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets); + + foreach (Asn1Sequence subSeq in seq) + { + SafeBag b = new SafeBag(subSeq); + + if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag)) + { + EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue); + PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo( + password, wrongPkcs12Zero, eIn); + AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo); + + // + // set the attributes on the key + // + Hashtable attributes = new Hashtable(); + AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes); + string alias = null; + Asn1OctetString localId = null; + + if (b.BagAttributes != null) + { + foreach (Asn1Sequence sq in b.BagAttributes) + { + DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0]; + Asn1Set attrSet = (Asn1Set) sq[1]; + Asn1Encodable attr = null; + + if (attrSet.Count > 0) + { + // TODO We should be adding all attributes in the set + attr = attrSet[0]; + + // TODO We might want to "merge" attribute sets with + // the same OID - currently, it is an error + attributes.Add(aOid.Id, attr); + + if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName)) + { + alias = ((DerBmpString)attr).GetString(); + // TODO Do these in a separate loop, just collect aliases here + keys[alias] = pkcs12Key; + } + else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID)) + { + localId = (Asn1OctetString)attr; + } + } + } + } + + if (localId != null) + { + byte[] hex = Hex.Encode(localId.GetOctets()); + string name = Encoding.ASCII.GetString(hex, 0, hex.Length); + + if (alias == null) + { + keys[name] = pkcs12Key; + } + else + { + // TODO There may have been more than one alias + localIds[alias] = name; + } + } + else + { + unmarkedKey = true; + keys["unmarked"] = pkcs12Key; + } + } + else if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag)) + { + chain.Add(b); + } + else + { + Console.WriteLine("extra " + b.BagID); + Console.WriteLine("extra " + Asn1Dump.DumpAsString(b)); + } + } + } + else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData)) + { + EncryptedData d = EncryptedData.GetInstance(ci.Content); + byte[] octets = CryptPbeData(false, d.EncryptionAlgorithm, + password, wrongPkcs12Zero, d.Content.GetOctets()); + Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets); + + foreach (Asn1Sequence subSeq in seq) + { + SafeBag b = new SafeBag(subSeq); + + if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag)) + { + chain.Add(b); + } + else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag)) + { + EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue); + PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo( + password, wrongPkcs12Zero, eIn); + AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo); + + // + // set the attributes on the key + // + Hashtable attributes = new Hashtable(); + AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes); + string alias = null; + Asn1OctetString localId = null; + + foreach (Asn1Sequence sq in b.BagAttributes) + { + DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0]; + Asn1Set attrSet = (Asn1Set) sq[1]; + Asn1Encodable attr = null; + + if (attrSet.Count > 0) + { + // TODO We should be adding all attributes in the set + attr = attrSet[0]; + + // TODO We might want to "merge" attribute sets with + // the same OID - currently, it is an error + attributes.Add(aOid.Id, attr); + + if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName)) + { + alias = ((DerBmpString)attr).GetString(); + // TODO Do these in a separate loop, just collect aliases here + keys[alias] = pkcs12Key; + } + else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID)) + { + localId = (Asn1OctetString)attr; + } + } + } + + // TODO Should we be checking localIds != null here + // as for PkcsObjectIdentifiers.Data version above? + + byte[] hex = Hex.Encode(localId.GetOctets()); + string name = Encoding.ASCII.GetString(hex, 0, hex.Length); + + if (alias == null) + { + keys[name] = pkcs12Key; + } + else + { + // TODO There may have been more than one alias + localIds[alias] = name; + } + } + else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag)) + { + PrivateKeyInfo privKeyInfo = PrivateKeyInfo.GetInstance(b.BagValue); + AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo); + + // + // set the attributes on the key + // + string alias = null; + Asn1OctetString localId = null; + Hashtable attributes = new Hashtable(); + AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes); + + foreach (Asn1Sequence sq in b.BagAttributes) + { + DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0]; + Asn1Set attrSet = (Asn1Set) sq[1]; + Asn1Encodable attr = null; + + if (attrSet.Count > 0) + { + // TODO We should be adding all attributes in the set + attr = attrSet[0]; + + // TODO We might want to "merge" attribute sets with + // the same OID - currently, it is an error + attributes.Add(aOid.Id, attr); + + if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName)) + { + alias = ((DerBmpString)attr).GetString(); + // TODO Do these in a separate loop, just collect aliases here + keys[alias] = pkcs12Key; + } + else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID)) + { + localId = (Asn1OctetString)attr; + } + } + } + + // TODO Should we be checking localIds != null here + // as for PkcsObjectIdentifiers.Data version above? + + byte[] hex = Hex.Encode(localId.GetOctets()); + string name = Encoding.ASCII.GetString(hex, 0, hex.Length); + + if (alias == null) + { + keys[name] = pkcs12Key; + } + else + { + // TODO There may have been more than one alias + localIds[alias] = name; + } + } + else + { + Console.WriteLine("extra " + b.BagID); + Console.WriteLine("extra " + Asn1Dump.DumpAsString(b)); + } + } + } + else + { + Console.WriteLine("extra " + oid); + Console.WriteLine("extra " + Asn1Dump.DumpAsString(ci.Content)); + } + } + } + + certs = new IgnoresCaseHashtable(); + chainCerts = new Hashtable(); + keyCerts = new Hashtable(); + + foreach (SafeBag b in chain) + { + CertBag cb = new CertBag((Asn1Sequence)b.BagValue); + byte[] octets = ((Asn1OctetString) cb.CertValue).GetOctets(); + X509Certificate cert = new X509CertificateParser().ReadCertificate(octets); + + // + // set the attributes + // + Hashtable attributes = new Hashtable(); + Asn1OctetString localId = null; + string alias = null; + + if (b.BagAttributes != null) + { + foreach (Asn1Sequence sq in b.BagAttributes) + { + DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0]; + Asn1Set attrSet = (Asn1Set) sq[1]; + + if (attrSet.Count > 0) + { + // TODO We should be adding all attributes in the set + Asn1Encodable attr = attrSet[0]; + + // TODO We might want to "merge" attribute sets with + // the same OID - currently, it is an error + attributes.Add(aOid.Id, attr); + + if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName)) + { + alias = ((DerBmpString)attr).GetString(); + } + else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID)) + { + localId = (Asn1OctetString)attr; + } + } + } + } + + CertId certId = new CertId(cert.GetPublicKey()); + X509CertificateEntry pkcs12Cert = new X509CertificateEntry(cert, attributes); + + chainCerts[certId] = pkcs12Cert; + + if (unmarkedKey) + { + if (keyCerts.Count == 0) + { + byte[] hex = Hex.Encode(certId.Id); + string name = Encoding.ASCII.GetString(hex, 0, hex.Length); + + keyCerts[name] = pkcs12Cert; + + object temp = keys["unmarked"]; + keys.Remove("unmarked"); + keys[name] = temp; + } + } + else + { + if (localId != null) + { + byte[] hex = Hex.Encode(localId.GetOctets()); + string name = Encoding.ASCII.GetString(hex, 0, hex.Length); + + keyCerts[name] = pkcs12Cert; + } + + if (alias != null) + { + // TODO There may have been more than one alias + certs[alias] = pkcs12Cert; + } + } + } + } + + public AsymmetricKeyEntry GetKey( + string alias) + { + if (alias == null) + throw new ArgumentNullException("alias"); + + return (AsymmetricKeyEntry)keys[alias]; + } + + public bool IsCertificateEntry( + string alias) + { + if (alias == null) + throw new ArgumentNullException("alias"); + + return (certs[alias] != null && keys[alias] == null); + } + + public bool IsKeyEntry( + string alias) + { + if (alias == null) + throw new ArgumentNullException("alias"); + + return (keys[alias] != null); + } + + private Hashtable GetAliasesTable() + { + Hashtable tab = new Hashtable(); + + foreach (string key in certs.Keys) + { + tab[key] = "cert"; + } + + foreach (string a in keys.Keys) + { + if (tab[a] == null) + { + tab[a] = "key"; + } + } + + return tab; + } + + public IEnumerable Aliases + { + get { return new EnumerableProxy(GetAliasesTable().Keys); } + } + + public bool ContainsAlias( + string alias) + { + return certs[alias] != null || keys[alias] != null; + } + + /** + * simply return the cert entry for the private key + */ + public X509CertificateEntry GetCertificate( + string alias) + { + if (alias == null) + throw new ArgumentNullException("alias"); + + X509CertificateEntry c = (X509CertificateEntry) certs[alias]; + + // + // look up the key table - and try the local key id + // + if (c == null) + { + string id = (string)localIds[alias]; + if (id != null) + { + c = (X509CertificateEntry)keyCerts[id]; + } + else + { + c = (X509CertificateEntry)keyCerts[alias]; + } + } + + return c; + } + + public string GetCertificateAlias( + X509Certificate cert) + { + if (cert == null) + throw new ArgumentNullException("cert"); + + foreach (DictionaryEntry entry in certs) + { + X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value; + if (entryValue.Certificate.Equals(cert)) + { + return (string) entry.Key; + } + } + + foreach (DictionaryEntry entry in keyCerts) + { + X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value; + if (entryValue.Certificate.Equals(cert)) + { + return (string) entry.Key; + } + } + + return null; + } + + public X509CertificateEntry[] GetCertificateChain( + string alias) + { + if (alias == null) + throw new ArgumentNullException("alias"); + + if (!IsKeyEntry(alias)) + { + return null; + } + + X509CertificateEntry c = GetCertificate(alias); + + if (c != null) + { + ArrayList cs = new ArrayList(); + + while (c != null) + { + X509Certificate x509c = c.Certificate; + X509CertificateEntry nextC = null; + + Asn1OctetString ext = x509c.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier); + if (ext != null) + { + AuthorityKeyIdentifier id = AuthorityKeyIdentifier.GetInstance( + Asn1Object.FromByteArray(ext.GetOctets())); + + if (id.GetKeyIdentifier() != null) + { + nextC = (X509CertificateEntry) chainCerts[new CertId(id.GetKeyIdentifier())]; + } + } + + if (nextC == null) + { + // + // no authority key id, try the Issuer DN + // + X509Name i = x509c.IssuerDN; + X509Name s = x509c.SubjectDN; + + if (!i.Equivalent(s)) + { + foreach (CertId certId in chainCerts.Keys) + { + X509CertificateEntry x509CertEntry = (X509CertificateEntry) chainCerts[certId]; + + X509Certificate crt = x509CertEntry.Certificate; + + X509Name sub = crt.SubjectDN; + if (sub.Equivalent(i)) + { + try + { + x509c.Verify(crt.GetPublicKey()); + + nextC = x509CertEntry; + break; + } + catch (InvalidKeyException) + { + // TODO What if it doesn't verify? + } + } + } + } + } + + cs.Add(c); + if (nextC != c) // self signed - end of the chain + { + c = nextC; + } + else + { + c = null; + } + } + + return (X509CertificateEntry[]) cs.ToArray(typeof(X509CertificateEntry)); + } + + return null; + } + + public void SetCertificateEntry( + string alias, + X509CertificateEntry certEntry) + { + if (alias == null) + throw new ArgumentNullException("alias"); + if (certEntry == null) + throw new ArgumentNullException("certEntry"); + if (keys[alias] != null) + throw new ArgumentException("There is a key entry with the name " + alias + "."); + + certs[alias] = certEntry; + chainCerts[new CertId(certEntry.Certificate.GetPublicKey())] = certEntry; + } + + public void SetKeyEntry( + string alias, + AsymmetricKeyEntry keyEntry, + X509CertificateEntry[] chain) + { + if (alias == null) + throw new ArgumentNullException("alias"); + if (keyEntry == null) + throw new ArgumentNullException("keyEntry"); + if (keyEntry.Key.IsPrivate && (chain == null)) + throw new ArgumentException("No certificate chain for private key"); + + if (keys[alias] != null) + { + DeleteEntry(alias); + } + + keys[alias] = keyEntry; + certs[alias] = chain[0]; + + for (int i = 0; i != chain.Length; i++) + { + chainCerts[new CertId(chain[i].Certificate.GetPublicKey())] = chain[i]; + } + } + + public void DeleteEntry( + string alias) + { + if (alias == null) + throw new ArgumentNullException("alias"); + + AsymmetricKeyEntry k = (AsymmetricKeyEntry)keys[alias]; + if (k != null) + { + keys.Remove(alias); + } + + X509CertificateEntry c = (X509CertificateEntry)certs[alias]; + + if (c != null) + { + certs.Remove(alias); + chainCerts.Remove(new CertId(c.Certificate.GetPublicKey())); + } + + if (k != null) + { + string id = (string)localIds[alias]; + if (id != null) + { + localIds.Remove(alias); + c = (X509CertificateEntry)keyCerts[id]; + } + if (c != null) + { + keyCerts.Remove(id); + chainCerts.Remove(new CertId(c.Certificate.GetPublicKey())); + } + } + + if (c == null && k == null) + { + throw new ArgumentException("no such entry as " + alias); + } + } + + public bool IsEntryOfType( + string alias, + Type entryType) + { + if (entryType == typeof(X509CertificateEntry)) + return IsCertificateEntry(alias); + + if (entryType == typeof(AsymmetricKeyEntry)) + return IsKeyEntry(alias) && GetCertificate(alias) != null; + + return false; + } + + [Obsolete("Use 'Count' property instead")] + public int Size() + { + return Count; + } + + public int Count + { + // TODO Seems a little inefficient + get { return GetAliasesTable().Count; } + } + + public void Save( + Stream stream, + char[] password, + SecureRandom random) + { + if (stream == null) + throw new ArgumentNullException("stream"); + if (password == null) + throw new ArgumentNullException("password"); + if (random == null) + throw new ArgumentNullException("random"); + + // + // handle the key + // + Asn1EncodableVector keyS = new Asn1EncodableVector(); + foreach (string name in keys.Keys) + { + byte[] kSalt = new byte[saltSize]; + random.NextBytes(kSalt); + + AsymmetricKeyEntry privKey = (AsymmetricKeyEntry) keys[name]; + EncryptedPrivateKeyInfo kInfo = + EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo( + keyAlgorithm, password, kSalt, MinIterations, privKey.Key); + + Asn1EncodableVector kName = new Asn1EncodableVector(); + + foreach (string oid in privKey.BagAttributeKeys) + { + Asn1Encodable entry = privKey[oid]; + + // NB: Ignore any existing FriendlyName + if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id)) + continue; + + kName.Add( + new DerSequence( + new DerObjectIdentifier(oid), + new DerSet(entry))); + } + + // + // make sure we are using the local alias on store + // + // NB: We always set the FriendlyName based on 'name' + //if (privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null) + { + kName.Add( + new DerSequence( + PkcsObjectIdentifiers.Pkcs9AtFriendlyName, + new DerSet(new DerBmpString(name)))); + } + + // + // make sure we have a local key-id + // + if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null) + { + X509CertificateEntry ct = GetCertificate(name); + AsymmetricKeyParameter pubKey = ct.Certificate.GetPublicKey(); + SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey); + + kName.Add( + new DerSequence( + PkcsObjectIdentifiers.Pkcs9AtLocalKeyID, + new DerSet(subjectKeyID))); + } + + SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName)); + keyS.Add(kBag); + } + + byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded(); + + BerOctetString keyString = new BerOctetString(derEncodedBytes); + + // + // certificate processing + // + byte[] cSalt = new byte[saltSize]; + + random.NextBytes(cSalt); + + Asn1EncodableVector certSeq = new Asn1EncodableVector(); + Pkcs12PbeParams cParams = new Pkcs12PbeParams(cSalt, MinIterations); + AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(CertAlgorithm, cParams.ToAsn1Object()); + ISet doneCerts = new HashSet(); + + foreach (string name in keys.Keys) + { + X509CertificateEntry certEntry = GetCertificate(name); + CertBag cBag = new CertBag( + PkcsObjectIdentifiers.X509Certificate, + new DerOctetString(certEntry.Certificate.GetEncoded())); + + Asn1EncodableVector fName = new Asn1EncodableVector(); + + foreach (string oid in certEntry.BagAttributeKeys) + { + Asn1Encodable entry = certEntry[oid]; + + // NB: Ignore any existing FriendlyName + if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id)) + continue; + + fName.Add( + new DerSequence( + new DerObjectIdentifier(oid), + new DerSet(entry))); + } + + // + // make sure we are using the local alias on store + // + // NB: We always set the FriendlyName based on 'name' + //if (certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null) + { + fName.Add( + new DerSequence( + PkcsObjectIdentifiers.Pkcs9AtFriendlyName, + new DerSet(new DerBmpString(name)))); + } + + // + // make sure we have a local key-id + // + if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null) + { + AsymmetricKeyParameter pubKey = certEntry.Certificate.GetPublicKey(); + SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey); + + fName.Add( + new DerSequence( + PkcsObjectIdentifiers.Pkcs9AtLocalKeyID, + new DerSet(subjectKeyID))); + } + + SafeBag sBag = new SafeBag( + PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)); + + certSeq.Add(sBag); + + doneCerts.Add(certEntry.Certificate); + } + + foreach (string certId in certs.Keys) + { + X509CertificateEntry cert = (X509CertificateEntry)certs[certId]; + + if (keys[certId] != null) + continue; + + CertBag cBag = new CertBag( + PkcsObjectIdentifiers.X509Certificate, + new DerOctetString(cert.Certificate.GetEncoded())); + + Asn1EncodableVector fName = new Asn1EncodableVector(); + + foreach (string oid in cert.BagAttributeKeys) + { + Asn1Encodable entry = cert[oid]; + + // NB: Ignore any existing FriendlyName + if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id)) + continue; + + fName.Add( + new DerSequence( + new DerObjectIdentifier(oid), + new DerSet(entry))); + } + + // + // make sure we are using the local alias on store + // + // NB: We always set the FriendlyName based on 'certId' + //if (cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null) + { + fName.Add( + new DerSequence( + PkcsObjectIdentifiers.Pkcs9AtFriendlyName, + new DerSet(new DerBmpString(certId)))); + } + + SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, + cBag.ToAsn1Object(), new DerSet(fName)); + + certSeq.Add(sBag); + + doneCerts.Add(cert.Certificate); + } + + foreach (CertId certId in chainCerts.Keys) + { + X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId]; + + if (doneCerts.Contains(cert.Certificate)) + continue; + + CertBag cBag = new CertBag( + PkcsObjectIdentifiers.X509Certificate, + new DerOctetString(cert.Certificate.GetEncoded())); + + Asn1EncodableVector fName = new Asn1EncodableVector(); + + foreach (string oid in cert.BagAttributeKeys) + { + fName.Add( + new DerSequence( + new DerObjectIdentifier(oid), + new DerSet(cert[oid]))); + } + + SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)); + + certSeq.Add(sBag); + } + + derEncodedBytes = new DerSequence(certSeq).GetDerEncoded(); + + byte[] certBytes = CryptPbeData(true, cAlgId, password, false, derEncodedBytes); + + EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes)); + + ContentInfo[] info = new ContentInfo[] + { + new ContentInfo(PkcsObjectIdentifiers.Data, keyString), + new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object()) + }; + + byte[] data = new AuthenticatedSafe(info).GetEncoded(); + + ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(data)); + + // + // create the mac + // + byte[] mSalt = new byte[20]; + random.NextBytes(mSalt); + + byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1, + mSalt, MinIterations, password, false, data); + + AlgorithmIdentifier algId = new AlgorithmIdentifier( + OiwObjectIdentifiers.IdSha1, DerNull.Instance); + DigestInfo dInfo = new DigestInfo(algId, mac); + + MacData mData = new MacData(dInfo, mSalt, MinIterations); + + // + // output the Pfx + // + Pfx pfx = new Pfx(mainInfo, mData); + + BerOutputStream berOut = new BerOutputStream(stream); + berOut.WriteObject(pfx); + } + + private static byte[] CalculatePbeMac( + DerObjectIdentifier oid, + byte[] salt, + int itCount, + char[] password, + bool wrongPkcs12Zero, + byte[] data) + { + Asn1Encodable asn1Params = PbeUtilities.GenerateAlgorithmParameters( + oid, salt, itCount); + ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters( + oid, password, wrongPkcs12Zero, asn1Params); + + IMac mac = (IMac) PbeUtilities.CreateEngine(oid); + mac.Init(cipherParams); + mac.BlockUpdate(data, 0, data.Length); + return MacUtilities.DoFinal(mac); + } + + private static byte[] CryptPbeData( + bool forEncryption, + AlgorithmIdentifier algId, + char[] password, + bool wrongPkcs12Zero, + byte[] data) + { + Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(algId.Parameters); + ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters( + algId.ObjectID, password, wrongPkcs12Zero, pbeParams); + + IBufferedCipher cipher = PbeUtilities.CreateEngine(algId.ObjectID) as IBufferedCipher; + + if (cipher == null) + throw new Exception("Unknown encryption algorithm: " + algId.ObjectID); + + cipher.Init(forEncryption, cipherParams); + + return cipher.DoFinal(data); + } + + private class IgnoresCaseHashtable + : IEnumerable + { + private readonly Hashtable orig = new Hashtable(); + private readonly Hashtable keys = new Hashtable(); + + public IEnumerator GetEnumerator() + { + return orig.GetEnumerator(); + } + + public ICollection Keys + { + get { return orig.Keys; } + } + + public object Remove( + string alias) + { + string lower = alias.ToLower(CultureInfo.InvariantCulture); + string k = (string) keys[lower]; + + if (k == null) + return null; + + keys.Remove(lower); + + object o = orig[k]; + orig.Remove(k); + return o; + } + + public object this[ + string alias] + { + get + { + string lower = alias.ToLower(CultureInfo.InvariantCulture); + string k = (string) keys[lower]; + + if (k == null) + return null; + + return orig[k]; + } + set + { + string lower = alias.ToLower(CultureInfo.InvariantCulture); + string k = (string) keys[lower]; + if (k != null) + { + orig.Remove(k); + } + keys[lower] = alias; + orig[alias] = value; + } + } + + public ICollection Values + { + get { return orig.Values; } + } + } + } +} diff --git a/iTechSharp/srcbc/pkcs/PrivateKeyInfoFactory.cs b/iTechSharp/srcbc/pkcs/PrivateKeyInfoFactory.cs new file mode 100644 index 0000000..1f293e4 --- /dev/null +++ b/iTechSharp/srcbc/pkcs/PrivateKeyInfoFactory.cs @@ -0,0 +1,211 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Pkcs +{ + public sealed class PrivateKeyInfoFactory + { + private PrivateKeyInfoFactory() + { + } + + public static PrivateKeyInfo CreatePrivateKeyInfo( + AsymmetricKeyParameter key) + { + if (key == null) + throw new ArgumentNullException("key"); + if (!key.IsPrivate) + throw new ArgumentException("Public key passed - private key expected", "key"); + + if (key is ElGamalPrivateKeyParameters) + { + ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key; + return new PrivateKeyInfo( + new AlgorithmIdentifier( + OiwObjectIdentifiers.ElGamalAlgorithm, + new ElGamalParameter( + _key.Parameters.P, + _key.Parameters.G).ToAsn1Object()), + new DerInteger(_key.X)); + } + + if (key is DsaPrivateKeyParameters) + { + DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key; + return new PrivateKeyInfo( + new AlgorithmIdentifier( + X9ObjectIdentifiers.IdDsa, + new DsaParameter( + _key.Parameters.P, + _key.Parameters.Q, + _key.Parameters.G).ToAsn1Object()), + new DerInteger(_key.X)); + } + + if (key is DHPrivateKeyParameters) + { + /* + Process DH private key. + The value for L was set to zero implicitly. + This is the same action as found in JCEDHPrivateKey GetEncoded method. + */ + + DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key; + + DHParameter withNewL = new DHParameter( + _key.Parameters.P, _key.Parameters.G, 0); + + return new PrivateKeyInfo( + new AlgorithmIdentifier( + PkcsObjectIdentifiers.DhKeyAgreement, + withNewL.ToAsn1Object()), + new DerInteger(_key.X)); + } + + if (key is RsaKeyParameters) + { + AlgorithmIdentifier algID = new AlgorithmIdentifier( + PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance); + + RsaPrivateKeyStructure keyStruct; + if (key is RsaPrivateCrtKeyParameters) + { + RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key; + + keyStruct = new RsaPrivateKeyStructure( + _key.Modulus, + _key.PublicExponent, + _key.Exponent, + _key.P, + _key.Q, + _key.DP, + _key.DQ, + _key.QInv); + } + else + { + RsaKeyParameters _key = (RsaKeyParameters) key; + + keyStruct = new RsaPrivateKeyStructure( + _key.Modulus, + BigInteger.Zero, + _key.Exponent, + BigInteger.Zero, + BigInteger.Zero, + BigInteger.Zero, + BigInteger.Zero, + BigInteger.Zero); + } + + return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object()); + } + + if (key is ECPrivateKeyParameters) + { + ECPrivateKeyParameters _key = (ECPrivateKeyParameters)key; + AlgorithmIdentifier algID; + + if (_key.AlgorithmName == "ECGOST3410") + { + if (_key.PublicKeyParamSet == null) + throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set"); + + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet); + + algID = new AlgorithmIdentifier( + CryptoProObjectIdentifiers.GostR3410x2001, + gostParams.ToAsn1Object()); + } + else + { + X9ECParameters ecP = new X9ECParameters( + _key.Parameters.Curve, + _key.Parameters.G, + _key.Parameters.N, + _key.Parameters.H, + _key.Parameters.GetSeed()); + + X962Parameters x962 = new X962Parameters(ecP); + + algID = new AlgorithmIdentifier( + X9ObjectIdentifiers.IdECPublicKey, + x962.ToAsn1Object()); + } + + return new PrivateKeyInfo(algID, new ECPrivateKeyStructure(_key.D).ToAsn1Object()); + } + + if (key is Gost3410PrivateKeyParameters) + { + Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key; + + if (_key.PublicKeyParamSet == null) + throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set"); + + byte[] keyEnc = _key.X.ToByteArrayUnsigned(); + byte[] keyBytes = new byte[keyEnc.Length]; + + for (int i = 0; i != keyBytes.Length; i++) + { + keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian + } + + Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters( + _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet, null); + + AlgorithmIdentifier algID = new AlgorithmIdentifier( + CryptoProObjectIdentifiers.GostR3410x94, + algParams.ToAsn1Object()); + + return new PrivateKeyInfo(algID, new DerOctetString(keyBytes)); + } + + throw new ArgumentException("Class provided is not convertible: " + key.GetType().FullName); + } + + public static PrivateKeyInfo CreatePrivateKeyInfo( + char[] passPhrase, + EncryptedPrivateKeyInfo encInfo) + { + return CreatePrivateKeyInfo(passPhrase, false, encInfo); + } + + public static PrivateKeyInfo CreatePrivateKeyInfo( + char[] passPhrase, + bool wrongPkcs12Zero, + EncryptedPrivateKeyInfo encInfo) + { + AlgorithmIdentifier algID = encInfo.EncryptionAlgorithm; + IBufferedCipher cipher = PbeUtilities.CreateEngine(algID.ObjectID) as IBufferedCipher; + + if (cipher == null) + { + // TODO Throw exception? + } + + ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters( + algID.ObjectID, passPhrase, wrongPkcs12Zero, algID.Parameters); + + cipher.Init(false, keyParameters); + + byte[] keyBytes = encInfo.GetEncryptedData(); + byte[] encoding = cipher.DoFinal(keyBytes); + Asn1Object asn1Data = Asn1Object.FromByteArray(encoding); + + return PrivateKeyInfo.GetInstance(asn1Data); + } + } +} diff --git a/iTechSharp/srcbc/pkcs/X509CertificateEntry.cs b/iTechSharp/srcbc/pkcs/X509CertificateEntry.cs new file mode 100644 index 0000000..f862275 --- /dev/null +++ b/iTechSharp/srcbc/pkcs/X509CertificateEntry.cs @@ -0,0 +1,32 @@ +using System.Collections; + +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Pkcs +{ + public class X509CertificateEntry + : Pkcs12Entry + { + private readonly X509Certificate cert; + + public X509CertificateEntry( + X509Certificate cert) + : base(new Hashtable()) + { + this.cert = cert; + } + + public X509CertificateEntry( + X509Certificate cert, + Hashtable attributes) + : base(attributes) + { + this.cert = cert; + } + + public X509Certificate Certificate + { + get { return this.cert; } + } + } +} diff --git a/iTechSharp/srcbc/security/AgreementUtilities.cs b/iTechSharp/srcbc/security/AgreementUtilities.cs new file mode 100644 index 0000000..4f13edc --- /dev/null +++ b/iTechSharp/srcbc/security/AgreementUtilities.cs @@ -0,0 +1,99 @@ +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Agreement.Kdf; +using Org.BouncyCastle.Crypto.Digests; + +namespace Org.BouncyCastle.Security +{ + /// + /// Utility class for creating IBasicAgreement objects from their names/Oids + /// + public sealed class AgreementUtilities + { + private AgreementUtilities() + { + } + + private static readonly Hashtable algorithms = new Hashtable(); + // private static readonly Hashtable oids = new Hashtable(); + + static AgreementUtilities() + { + //algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?; + algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "DHWITHSHA1KDF"; + //algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = ?; + } + + public static IBasicAgreement GetBasicAgreement( + DerObjectIdentifier oid) + { + return GetBasicAgreement(oid.Id); + } + + public static IBasicAgreement GetBasicAgreement( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + switch (mechanism) + { + case "DH": + return new DHBasicAgreement(); + case "ECDH": + return new ECDHBasicAgreement(); + case "ECDHC": + return new ECDHCBasicAgreement(); + } + + throw new SecurityUtilityException("Basic Agreement " + algorithm + " not recognised."); + } + + public static IBasicAgreement GetBasicAgreementWithKdf( + DerObjectIdentifier oid, + string wrapAlgorithm) + { + return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm); + } + + public static IBasicAgreement GetBasicAgreementWithKdf( + string agreeAlgorithm, + string wrapAlgorithm) + { + string upper = agreeAlgorithm.ToUpper(CultureInfo.InvariantCulture); + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + switch (mechanism) + { + case "DHWITHSHA1KDF": + return new ECDHWithKdfBasicAgreement( + wrapAlgorithm, + new ECDHKekGenerator( + new Sha1Digest())); + } + + throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised."); + } + + public static string GetAlgorithmName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + } +} diff --git a/iTechSharp/srcbc/security/CipherUtilities.cs b/iTechSharp/srcbc/security/CipherUtilities.cs new file mode 100644 index 0000000..0036fb2 --- /dev/null +++ b/iTechSharp/srcbc/security/CipherUtilities.cs @@ -0,0 +1,566 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Encodings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; + +namespace Org.BouncyCastle.Security +{ + /// + /// Cipher Utility class contains methods that can not be specifically grouped into other classes. + /// + public sealed class CipherUtilities + { + private static readonly Hashtable algorithms = new Hashtable(); + private static readonly Hashtable oids = new Hashtable(); + + static CipherUtilities() + { + // TODO Flesh out the list of aliases + + algorithms[NistObjectIdentifiers.IdAes128Ecb.Id] = "AES/ECB/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes192Ecb.Id] = "AES/ECB/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes256Ecb.Id] = "AES/ECB/PKCS7PADDING"; + algorithms["AES/ECB/PKCS7"] = "AES/ECB/PKCS7PADDING"; + algorithms["AES//PKCS7"] = "AES/ECB/PKCS7PADDING"; + algorithms["AES//PKCS7PADDING"] = "AES/ECB/PKCS7PADDING"; + algorithms["AES/ECB/PKCS5"] = "AES/ECB/PKCS7PADDING"; + algorithms["AES/ECB/PKCS5PADDING"] = "AES/ECB/PKCS7PADDING"; + algorithms["AES//PKCS5"] = "AES/ECB/PKCS7PADDING"; + algorithms["AES//PKCS5PADDING"] = "AES/ECB/PKCS7PADDING"; + + algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "AES/CBC/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "AES/CBC/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "AES/CBC/PKCS7PADDING"; + algorithms["AES/CBC/PKCS7"] = "AES/CBC/PKCS7PADDING"; + algorithms["AES/CBC/PKCS5"] = "AES/CBC/PKCS7PADDING"; + algorithms["AES/CBC/PKCS5PADDING"] = "AES/CBC/PKCS7PADDING"; + + algorithms[NistObjectIdentifiers.IdAes128Ofb.Id] = "AES/OFB/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes192Ofb.Id] = "AES/OFB/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes256Ofb.Id] = "AES/OFB/PKCS7PADDING"; + algorithms["AES/OFB/PKCS7"] = "AES/OFB/PKCS7PADDING"; + algorithms["AES/OFB/PKCS5"] = "AES/OFB/PKCS7PADDING"; + algorithms["AES/OFB/PKCS5PADDING"] = "AES/OFB/PKCS7PADDING"; + + algorithms[NistObjectIdentifiers.IdAes128Cfb.Id] = "AES/CFB/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes192Cfb.Id] = "AES/CFB/PKCS7PADDING"; + algorithms[NistObjectIdentifiers.IdAes256Cfb.Id] = "AES/CFB/PKCS7PADDING"; + algorithms["AES/CFB/PKCS7"] = "AES/CFB/PKCS7PADDING"; + algorithms["AES/CFB/PKCS5"] = "AES/CFB/PKCS7PADDING"; + algorithms["AES/CFB/PKCS5PADDING"] = "AES/CFB/PKCS7PADDING"; + + algorithms["RSA//PKCS1"] = "RSA//PKCS1PADDING"; + algorithms["RSA/ECB/PKCS1"] = "RSA//PKCS1PADDING"; + algorithms["RSA/ECB/PKCS1PADDING"] = "RSA//PKCS1PADDING"; + algorithms[PkcsObjectIdentifiers.RsaEncryption.Id] = "RSA//PKCS1PADDING"; + + algorithms[OiwObjectIdentifiers.DesCbc.Id] = "DES/CBC"; + algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDE/CBC"; + algorithms[PkcsObjectIdentifiers.RC2Cbc.Id] = "RC2/CBC"; + algorithms["1.3.6.1.4.1.188.7.1.1.2"] = "IDEA/CBC"; + algorithms["1.2.840.113533.7.66.10"] = "CAST5/CBC"; + + algorithms["RC4"] = "ARC4"; + algorithms["ARCFOUR"] = "ARC4"; + algorithms["1.2.840.113549.3.4"] = "ARC4"; + + + + algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEWITHSHAAND128BITRC4"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEWITHSHAAND128BITRC4"; + algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEWITHSHAAND40BITRC4"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEWITHSHAAND40BITRC4"; + + algorithms["PBEWITHSHA1ANDDES"] = "PBEWITHSHA1ANDDES-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEWITHSHA1ANDDES-CBC"; + algorithms["PBEWITHSHA1ANDRC2"] = "PBEWITHSHA1ANDRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEWITHSHA1ANDRC2-CBC"; + + algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"; + algorithms["PBEWITHSHAAND3KEYTRIPLEDES"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"; + algorithms["PBEWITHSHA1ANDDESEDE"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"; + + algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC"; + + algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEWITHSHAAND128BITRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEWITHSHAAND128BITRC2-CBC"; + + algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEWITHSHAAND40BITRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEWITHSHAAND40BITRC2-CBC"; + + algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC"; + algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC"; + + algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC"; + algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC"; + + algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC"; + algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC"; + + algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEWITHSHA256AND128BITAES-CBC-BC"; + algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEWITHSHA256AND192BITAES-CBC-BC"; + algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEWITHSHA256AND256BITAES-CBC-BC"; + + + algorithms["GOST"] = "GOST28147"; + algorithms["GOST-28147"] = "GOST28147"; + algorithms[CryptoProObjectIdentifiers.GostR28147Cbc.Id] = "GOST28147/CBC/PKCS7PADDING"; + + algorithms["RC5-32"] = "RC5"; + + algorithms[NttObjectIdentifiers.IdCamellia128Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING"; + algorithms[NttObjectIdentifiers.IdCamellia192Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING"; + algorithms[NttObjectIdentifiers.IdCamellia256Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING"; + + algorithms[KisaObjectIdentifiers.IdSeedCbc.Id] = "SEED/CBC/PKCS7PADDING"; + } + + private CipherUtilities() + { + } + + /// + /// Returns a ObjectIdentifier for a give encoding. + /// + /// A string representation of the encoding. + /// A DerObjectIdentifier, null if the Oid is not available. + // TODO Don't really want to support this + public static DerObjectIdentifier GetObjectIdentifier( + string mechanism) + { + if (mechanism == null) + throw new ArgumentNullException("mechanism"); + + mechanism = mechanism.ToUpper(CultureInfo.InvariantCulture); + string aliased = (string) algorithms[mechanism]; + + if (aliased != null) + mechanism = aliased; + + return (DerObjectIdentifier) oids[mechanism]; + } + + public static ICollection Algorithms + { + get { return oids.Keys; } + } + + public static IBufferedCipher GetCipher( + DerObjectIdentifier oid) + { + return GetCipher(oid.Id); + } + + public static IBufferedCipher GetCipher( + string algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + algorithm = algorithm.ToUpper(CultureInfo.InvariantCulture); + + string aliased = (string) algorithms[algorithm]; + + if (aliased != null) + algorithm = aliased; + + + + IBasicAgreement iesAgreement = null; + if (algorithm == "IES") + { + iesAgreement = new DHBasicAgreement(); + } + else if (algorithm == "ECIES") + { + iesAgreement = new ECDHBasicAgreement(); + } + + if (iesAgreement != null) + { + return new BufferedIesCipher( + new IesEngine( + iesAgreement, + new Kdf2BytesGenerator( + new Sha1Digest()), + new HMac( + new Sha1Digest()))); + } + + + + if (algorithm.StartsWith("PBE")) + { + switch (algorithm) + { + case "PBEWITHSHAAND2-KEYTRIPLEDES-CBC": + case "PBEWITHSHAAND3-KEYTRIPLEDES-CBC": + return new PaddedBufferedBlockCipher( + new CbcBlockCipher(new DesEdeEngine())); + + case "PBEWITHSHAAND128BITRC2-CBC": + case "PBEWITHSHAAND40BITRC2-CBC": + return new PaddedBufferedBlockCipher( + new CbcBlockCipher(new RC2Engine())); + + case "PBEWITHSHAAND128BITAES-CBC-BC": + case "PBEWITHSHAAND192BITAES-CBC-BC": + case "PBEWITHSHAAND256BITAES-CBC-BC": + case "PBEWITHSHA256AND128BITAES-CBC-BC": + case "PBEWITHSHA256AND192BITAES-CBC-BC": + case "PBEWITHSHA256AND256BITAES-CBC-BC": + case "PBEWITHMD5AND128BITAES-CBC-OPENSSL": + case "PBEWITHMD5AND192BITAES-CBC-OPENSSL": + case "PBEWITHMD5AND256BITAES-CBC-OPENSSL": + return new PaddedBufferedBlockCipher( + new CbcBlockCipher(new AesFastEngine())); + + case "PBEWITHSHA1ANDDES-CBC": + return new PaddedBufferedBlockCipher( + new CbcBlockCipher(new DesEngine())); + + case "PBEWITHSHA1ANDRC2-CBC": + return new PaddedBufferedBlockCipher( + new CbcBlockCipher(new RC2Engine())); + } + } + + + + string[] parts = algorithm.Split('/'); + + IBlockCipher blockCipher = null; + IAsymmetricBlockCipher asymBlockCipher = null; + IStreamCipher streamCipher = null; + + switch (parts[0]) + { + case "AES": + blockCipher = new AesFastEngine(); + break; + case "ARC4": + streamCipher = new RC4Engine(); + break; + case "BLOWFISH": + blockCipher = new BlowfishEngine(); + break; + case "CAMELLIA": + blockCipher = new CamelliaEngine(); + break; + case "CAST5": + blockCipher = new Cast5Engine(); + break; + case "CAST6": + blockCipher = new Cast6Engine(); + break; + case "DES": + blockCipher = new DesEngine(); + break; + case "DESEDE": + blockCipher = new DesEdeEngine(); + break; + case "ELGAMAL": + asymBlockCipher = new ElGamalEngine(); + break; + case "GOST28147": + blockCipher = new Gost28147Engine(); + break; + case "HC128": + streamCipher = new HC128Engine(); + break; + case "HC256": + streamCipher = new HC256Engine(); + break; + case "IDEA": + blockCipher = new IdeaEngine(); + break; + case "NOEKEON": + blockCipher = new NoekeonEngine(); + break; + case "PBEWITHSHAAND128BITRC4": + case "PBEWITHSHAAND40BITRC4": + streamCipher = new RC4Engine(); + break; + case "RC2": + blockCipher = new RC2Engine(); + break; + case "RC5": + blockCipher = new RC532Engine(); + break; + case "RC5-64": + blockCipher = new RC564Engine(); + break; + case "RC6": + blockCipher = new RC6Engine(); + break; + case "RIJNDAEL": + blockCipher = new RijndaelEngine(); + break; + case "RSA": + asymBlockCipher = new RsaBlindedEngine(); + break; + case "SALSA20": + streamCipher = new Salsa20Engine(); + break; + case "SEED": + blockCipher = new SeedEngine(); + break; + case "SERPENT": + blockCipher = new SerpentEngine(); + break; + case "SKIPJACK": + blockCipher = new SkipjackEngine(); + break; + case "TEA": + blockCipher = new TeaEngine(); + break; + case "TWOFISH": + blockCipher = new TwofishEngine(); + break; + case "VMPC": + streamCipher = new VmpcEngine(); + break; + case "VMPC-KSA3": + streamCipher = new VmpcKsa3Engine(); + break; + case "XTEA": + blockCipher = new XteaEngine(); + break; + default: + throw new SecurityUtilityException("Cipher " + algorithm + " not recognised."); + } + + if (streamCipher != null) + { + if (parts.Length > 1) + throw new ArgumentException("Modes and paddings not used for stream ciphers"); + + return new BufferedStreamCipher(streamCipher); + } + + + bool cts = false; + bool padded = true; + IBlockCipherPadding padding = null; + IAeadBlockCipher aeadBlockCipher = null; + + if (parts.Length > 2) + { + if (streamCipher != null) + throw new ArgumentException("Paddings not used for stream ciphers"); + + switch (parts[2]) + { + case "NOPADDING": + padded = false; + break; + case "": + case "RAW": + break; + case "ISO10126PADDING": + case "ISO10126D2PADDING": + case "ISO10126-2PADDING": + padding = new ISO10126d2Padding(); + break; + case "ISO7816-4PADDING": + case "ISO9797-1PADDING": + padding = new ISO7816d4Padding(); + break; + case "ISO9796-1": + case "ISO9796-1PADDING": + asymBlockCipher = new ISO9796d1Encoding(asymBlockCipher); + break; + case "OAEP": + case "OAEPPADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher); + break; + case "OAEPWITHMD5ANDMGF1PADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher, new MD5Digest()); + break; + case "OAEPWITHSHA1ANDMGF1PADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha1Digest()); + break; + case "OAEPWITHSHA224ANDMGF1PADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha224Digest()); + break; + case "OAEPWITHSHA256ANDMGF1PADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha256Digest()); + break; + case "OAEPWITHSHA384ANDMGF1PADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha384Digest()); + break; + case "OAEPWITHSHA512ANDMGF1PADDING": + asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha512Digest()); + break; + case "PKCS1": + case "PKCS1PADDING": + asymBlockCipher = new Pkcs1Encoding(asymBlockCipher); + break; + case "PKCS5": + case "PKCS5PADDING": + case "PKCS7": + case "PKCS7PADDING": + // NB: Padding defaults to Pkcs7Padding already + break; + case "TBCPADDING": + padding = new TbcPadding(); + break; + case "WITHCTS": + cts = true; + break; + case "X9.23PADDING": + case "X923PADDING": + padding = new X923Padding(); + break; + case "ZEROBYTEPADDING": + padding = new ZeroBytePadding(); + break; + default: + throw new SecurityUtilityException("Cipher " + algorithm + " not recognised."); + } + } + + string mode = ""; + if (parts.Length > 1) + { + mode = parts[1]; + + int di = GetDigitIndex(mode); + string modeName = di >= 0 ? mode.Substring(0, di) : mode; + + switch (modeName) + { + case "": + case "ECB": + case "NONE": + break; + case "CBC": + blockCipher = new CbcBlockCipher(blockCipher); + break; + case "CCM": + aeadBlockCipher = new CcmBlockCipher(blockCipher); + break; + case "CFB": + { + int bits = (di < 0) + ? 8 * blockCipher.GetBlockSize() + : int.Parse(mode.Substring(di)); + + blockCipher = new CfbBlockCipher(blockCipher, bits); + break; + } + case "CTR": + blockCipher = new SicBlockCipher(blockCipher); + break; + case "CTS": + cts = true; + blockCipher = new CbcBlockCipher(blockCipher); + break; + case "EAX": + aeadBlockCipher = new EaxBlockCipher(blockCipher); + break; + case "GCM": + aeadBlockCipher = new GcmBlockCipher(blockCipher); + break; + case "GOFB": + blockCipher = new GOfbBlockCipher(blockCipher); + break; + case "OFB": + { + int bits = (di < 0) + ? 8 * blockCipher.GetBlockSize() + : int.Parse(mode.Substring(di)); + + blockCipher = new OfbBlockCipher(blockCipher, bits); + break; + } + case "OPENPGPCFB": + blockCipher = new OpenPgpCfbBlockCipher(blockCipher); + break; + case "SIC": + if (blockCipher.GetBlockSize() < 16) + { + throw new ArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)"); + } + blockCipher = new SicBlockCipher(blockCipher); + break; + default: + throw new SecurityUtilityException("Cipher " + algorithm + " not recognised."); + } + } + + if (aeadBlockCipher != null) + { + if (cts) + throw new SecurityUtilityException("CTS mode not valid for AEAD ciphers."); + if (padded && parts.Length > 1 && parts[2] != "") + throw new SecurityUtilityException("Bad padding specified for AEAD cipher."); + + return new BufferedAeadBlockCipher(aeadBlockCipher); + } + + if (blockCipher != null) + { + if (cts) + { + return new CtsBlockCipher(blockCipher); + } + + if (!padded || blockCipher.IsPartialBlockOkay) + { + return new BufferedBlockCipher(blockCipher); + } + + if (padding != null) + { + return new PaddedBufferedBlockCipher(blockCipher, padding); + } + + return new PaddedBufferedBlockCipher(blockCipher); + } + + if (asymBlockCipher != null) + { + return new BufferedAsymmetricBlockCipher(asymBlockCipher); + } + + throw new SecurityUtilityException("Cipher " + algorithm + " not recognised."); + } + + public static string GetAlgorithmName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + + private static int GetDigitIndex( + string s) + { + for (int i = 0; i < s.Length; ++i) + { + if (char.IsDigit(s[i])) + return i; + } + + return -1; + } + } +} diff --git a/iTechSharp/srcbc/security/DigestUtilities.cs b/iTechSharp/srcbc/security/DigestUtilities.cs new file mode 100644 index 0000000..232c557 --- /dev/null +++ b/iTechSharp/srcbc/security/DigestUtilities.cs @@ -0,0 +1,150 @@ +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Security +{ + + /// + /// Utility class for creating IDigest objects from their names/Oids + /// + public sealed class DigestUtilities + { + private DigestUtilities() + { + } + + private static readonly Hashtable algorithms = new Hashtable(); + private static readonly Hashtable oids = new Hashtable(); + + static DigestUtilities() + { + algorithms[PkcsObjectIdentifiers.MD2.Id] = "MD2"; + algorithms[PkcsObjectIdentifiers.MD4.Id] = "MD4"; + algorithms[PkcsObjectIdentifiers.MD5.Id] = "MD5"; + + algorithms["SHA1"] = "SHA-1"; + algorithms[OiwObjectIdentifiers.IdSha1.Id] = "SHA-1"; + algorithms["SHA224"] = "SHA-224"; + algorithms[NistObjectIdentifiers.IdSha224.Id] = "SHA-224"; + algorithms["SHA256"] = "SHA-256"; + algorithms[NistObjectIdentifiers.IdSha256.Id] = "SHA-256"; + algorithms["SHA384"] = "SHA-384"; + algorithms[NistObjectIdentifiers.IdSha384.Id] = "SHA-384"; + algorithms["SHA512"] = "SHA-512"; + algorithms[NistObjectIdentifiers.IdSha512.Id] = "SHA-512"; + + algorithms["RIPEMD-128"] = "RIPEMD128"; + algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "RIPEMD128"; + algorithms["RIPEMD-160"] = "RIPEMD160"; + algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "RIPEMD160"; + algorithms["RIPEMD-256"] = "RIPEMD256"; + algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "RIPEMD256"; + algorithms["RIPEMD-320"] = "RIPEMD320"; +// algorithms[TeleTrusTObjectIdentifiers.RipeMD320.Id] = "RIPEMD320"; + + algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411"; + + + + oids["MD2"] = PkcsObjectIdentifiers.MD2; + oids["MD4"] = PkcsObjectIdentifiers.MD4; + oids["MD5"] = PkcsObjectIdentifiers.MD5; + oids["SHA-1"] = OiwObjectIdentifiers.IdSha1; + oids["SHA-224"] = NistObjectIdentifiers.IdSha224; + oids["SHA-256"] = NistObjectIdentifiers.IdSha256; + oids["SHA-384"] = NistObjectIdentifiers.IdSha384; + oids["SHA-512"] = NistObjectIdentifiers.IdSha512; + oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128; + oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160; + oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256; + oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411; + } + + /// + /// Returns a ObjectIdentifier for a given digest mechanism. + /// + /// A string representation of the digest meanism. + /// A DerObjectIdentifier, null if the Oid is not available. + + public static DerObjectIdentifier GetObjectIdentifier( + string mechanism) + { + mechanism = (string) algorithms[mechanism.ToUpper(CultureInfo.InvariantCulture)]; + + if (mechanism != null) + { + return (DerObjectIdentifier)oids[mechanism]; + } + + return null; + } + + public static ICollection Algorithms + { + get { return oids.Keys; } + } + + public static IDigest GetDigest( + DerObjectIdentifier id) + { + return GetDigest(id.Id); + } + + public static IDigest GetDigest( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + switch (mechanism) + { + case "GOST3411": return new Gost3411Digest(); + case "MD2": return new MD2Digest(); + case "MD4": return new MD4Digest(); + case "MD5": return new MD5Digest(); + case "RIPEMD128": return new RipeMD128Digest(); + case "RIPEMD160": return new RipeMD160Digest(); + case "RIPEMD256": return new RipeMD256Digest(); + case "RIPEMD320": return new RipeMD320Digest(); + case "SHA-1": return new Sha1Digest(); + case "SHA-224": return new Sha224Digest(); + case "SHA-256": return new Sha256Digest(); + case "SHA-384": return new Sha384Digest(); + case "SHA-512": return new Sha512Digest(); + case "TIGER": return new TigerDigest(); + case "WHIRLPOOL": return new WhirlpoolDigest(); + default: + throw new SecurityUtilityException("Digest " + mechanism + " not recognised."); + } + } + + public static string GetAlgorithmName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + + public static byte[] DoFinal( + IDigest digest) + { + byte[] b = new byte[digest.GetDigestSize()]; + digest.DoFinal(b, 0); + return b; + } + } +} diff --git a/iTechSharp/srcbc/security/DotNetUtilities.cs b/iTechSharp/srcbc/security/DotNetUtilities.cs new file mode 100644 index 0000000..7b32204 --- /dev/null +++ b/iTechSharp/srcbc/security/DotNetUtilities.cs @@ -0,0 +1,163 @@ +#if !NETCF_1_0 + +using System; +using System.Security.Cryptography; +using SystemX509 = System.Security.Cryptography.X509Certificates; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Security +{ + /// + /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world. + /// + public sealed class DotNetUtilities + { + private DotNetUtilities() + { + } + + /// + /// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure. + /// + /// + /// A System.Security.Cryptography.X509Certificate. + public static SystemX509.X509Certificate ToX509Certificate( + X509CertificateStructure x509Struct) + { + return new SystemX509.X509Certificate(x509Struct.GetDerEncoded()); + } + + public static SystemX509.X509Certificate ToX509Certificate( + X509Certificate x509Cert) + { + return new SystemX509.X509Certificate(x509Cert.GetEncoded()); + } + + public static X509Certificate FromX509Certificate( + SystemX509.X509Certificate x509Cert) + { + return new X509CertificateParser().ReadCertificate(x509Cert.GetRawCertData()); + } + + public static AsymmetricCipherKeyPair GetDsaKeyPair( + DSACryptoServiceProvider dsaCsp) + { + return GetDsaKeyPair(dsaCsp.ExportParameters(true)); + } + + public static AsymmetricCipherKeyPair GetDsaKeyPair( + DSAParameters dp) + { + DsaValidationParameters validationParameters = (dp.Seed != null) + ? new DsaValidationParameters(dp.Seed, dp.Counter) + : null; + + DsaParameters parameters = new DsaParameters( + new BigInteger(1, dp.P), + new BigInteger(1, dp.Q), + new BigInteger(1, dp.G), + validationParameters); + + DsaPublicKeyParameters pubKey = new DsaPublicKeyParameters( + new BigInteger(1, dp.Y), + parameters); + + DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters( + new BigInteger(1, dp.X), + parameters); + + return new AsymmetricCipherKeyPair(pubKey, privKey); + } + + public static DsaPublicKeyParameters GetDsaPublicKey( + DSACryptoServiceProvider dsaCsp) + { + return GetDsaPublicKey(dsaCsp.ExportParameters(false)); + } + + public static DsaPublicKeyParameters GetDsaPublicKey( + DSAParameters dp) + { + DsaValidationParameters validationParameters = (dp.Seed != null) + ? new DsaValidationParameters(dp.Seed, dp.Counter) + : null; + + DsaParameters parameters = new DsaParameters( + new BigInteger(1, dp.P), + new BigInteger(1, dp.Q), + new BigInteger(1, dp.G), + validationParameters); + + return new DsaPublicKeyParameters( + new BigInteger(1, dp.Y), + parameters); + } + + public static AsymmetricCipherKeyPair GetRsaKeyPair( + RSACryptoServiceProvider rsaCsp) + { + return GetRsaKeyPair(rsaCsp.ExportParameters(true)); + } + + public static AsymmetricCipherKeyPair GetRsaKeyPair( + RSAParameters rp) + { + BigInteger modulus = new BigInteger(1, rp.Modulus); + BigInteger pubExp = new BigInteger(1, rp.Exponent); + + RsaKeyParameters pubKey = new RsaKeyParameters( + false, + modulus, + pubExp); + + RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters( + modulus, + pubExp, + new BigInteger(1, rp.D), + new BigInteger(1, rp.P), + new BigInteger(1, rp.Q), + new BigInteger(1, rp.DP), + new BigInteger(1, rp.DQ), + new BigInteger(1, rp.InverseQ)); + + return new AsymmetricCipherKeyPair(pubKey, privKey); + } + + public static RsaKeyParameters GetRsaPublicKey( + RSACryptoServiceProvider rsaCsp) + { + return GetRsaPublicKey(rsaCsp.ExportParameters(false)); + } + + public static RsaKeyParameters GetRsaPublicKey( + RSAParameters rp) + { + return new RsaKeyParameters( + false, + new BigInteger(1, rp.Modulus), + new BigInteger(1, rp.Exponent)); + } + + public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey) + { + if (privateKey is DSACryptoServiceProvider) + { + return GetDsaKeyPair((DSACryptoServiceProvider) privateKey); + } + + if (privateKey is RSACryptoServiceProvider) + { + return GetRsaKeyPair((RSACryptoServiceProvider) privateKey); + } + + throw new ArgumentException("Unsupported algorithm specified", "privateKey"); + } + } +} + +#endif diff --git a/iTechSharp/srcbc/security/GeneralSecurityException.cs b/iTechSharp/srcbc/security/GeneralSecurityException.cs new file mode 100644 index 0000000..c0e412f --- /dev/null +++ b/iTechSharp/srcbc/security/GeneralSecurityException.cs @@ -0,0 +1,26 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + public class GeneralSecurityException + : Exception + { + public GeneralSecurityException() + : base() + { + } + + public GeneralSecurityException( + string message) + : base(message) + { + } + + public GeneralSecurityException( + string message, + Exception exception) + : base(message, exception) + { + } + } +} diff --git a/iTechSharp/srcbc/security/GeneratorUtilities.cs b/iTechSharp/srcbc/security/GeneratorUtilities.cs new file mode 100644 index 0000000..e71667a --- /dev/null +++ b/iTechSharp/srcbc/security/GeneratorUtilities.cs @@ -0,0 +1,352 @@ +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Iana; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; + +namespace Org.BouncyCastle.Security +{ + public sealed class GeneratorUtilities + { + private GeneratorUtilities() + { + } + + private static readonly Hashtable kgAlgorithms = new Hashtable(); + private static readonly Hashtable kpgAlgorithms = new Hashtable(); + + static GeneratorUtilities() + { + // + // key generators. + // + AddKgAlgorithm("AES", + "AESWRAP"); + AddKgAlgorithm("AES128", + "2.16.840.1.101.3.4.2", + NistObjectIdentifiers.IdAes128Cbc, + NistObjectIdentifiers.IdAes128Cfb, + NistObjectIdentifiers.IdAes128Ecb, + NistObjectIdentifiers.IdAes128Ofb, + NistObjectIdentifiers.IdAes128Wrap); + AddKgAlgorithm("AES192", + "2.16.840.1.101.3.4.22", + NistObjectIdentifiers.IdAes192Cbc, + NistObjectIdentifiers.IdAes192Cfb, + NistObjectIdentifiers.IdAes192Ecb, + NistObjectIdentifiers.IdAes192Ofb, + NistObjectIdentifiers.IdAes192Wrap); + AddKgAlgorithm("AES256", + "2.16.840.1.101.3.4.42", + NistObjectIdentifiers.IdAes256Cbc, + NistObjectIdentifiers.IdAes256Cfb, + NistObjectIdentifiers.IdAes256Ecb, + NistObjectIdentifiers.IdAes256Ofb, + NistObjectIdentifiers.IdAes256Wrap); + AddKgAlgorithm("BLOWFISH"); + AddKgAlgorithm("CAMELLIA", + "CAMELLIAWRAP"); + AddKgAlgorithm("CAMELLIA128", + NttObjectIdentifiers.IdCamellia128Cbc, + NttObjectIdentifiers.IdCamellia128Wrap); + AddKgAlgorithm("CAMELLIA192", + NttObjectIdentifiers.IdCamellia192Cbc, + NttObjectIdentifiers.IdCamellia192Wrap); + AddKgAlgorithm("CAMELLIA256", + NttObjectIdentifiers.IdCamellia256Cbc, + NttObjectIdentifiers.IdCamellia256Wrap); + AddKgAlgorithm("CAST5", + "1.2.840.113533.7.66.10"); + AddKgAlgorithm("CAST6"); + AddKgAlgorithm("DES", + OiwObjectIdentifiers.DesCbc); + AddKgAlgorithm("DESEDE", + "DESEDEWRAP", + PkcsObjectIdentifiers.IdAlgCms3DesWrap); + AddKgAlgorithm("DESEDE3", + PkcsObjectIdentifiers.DesEde3Cbc); + AddKgAlgorithm("GOST28147", + "GOST", + "GOST-28147", + CryptoProObjectIdentifiers.GostR28147Cbc); + AddKgAlgorithm("HC128"); + AddKgAlgorithm("HC256"); + AddKgAlgorithm("IDEA", + "1.3.6.1.4.1.188.7.1.1.2"); + AddKgAlgorithm("NOEKEON"); + AddKgAlgorithm("RC2", + PkcsObjectIdentifiers.RC2Cbc, + PkcsObjectIdentifiers.IdAlgCmsRC2Wrap); + AddKgAlgorithm("RC4", + "ARC4", + "1.2.840.113549.3.4"); + AddKgAlgorithm("RC5", + "RC5-32"); + AddKgAlgorithm("RC5-64"); + AddKgAlgorithm("RC6"); + AddKgAlgorithm("RIJNDAEL"); + AddKgAlgorithm("SALSA20"); + AddKgAlgorithm("SEED", + KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap, + KisaObjectIdentifiers.IdSeedCbc); + AddKgAlgorithm("SERPENT"); + AddKgAlgorithm("SKIPJACK"); + AddKgAlgorithm("TEA"); + AddKgAlgorithm("TWOFISH"); + AddKgAlgorithm("VMPC"); + AddKgAlgorithm("VMPC-KSA3"); + AddKgAlgorithm("XTEA"); + + // + // HMac key generators + // + AddHMacKeyGenerator("MD2"); + AddHMacKeyGenerator("MD4"); + AddHMacKeyGenerator("MD5", + IanaObjectIdentifiers.HmacMD5); + AddHMacKeyGenerator("SHA1", + PkcsObjectIdentifiers.IdHmacWithSha1, + IanaObjectIdentifiers.HmacSha1); + AddHMacKeyGenerator("SHA224", + PkcsObjectIdentifiers.IdHmacWithSha224); + AddHMacKeyGenerator("SHA256", + PkcsObjectIdentifiers.IdHmacWithSha256); + AddHMacKeyGenerator("SHA384", + PkcsObjectIdentifiers.IdHmacWithSha384); + AddHMacKeyGenerator("SHA512", + PkcsObjectIdentifiers.IdHmacWithSha512); + AddHMacKeyGenerator("RIPEMD128"); + AddHMacKeyGenerator("RIPEMD160", + IanaObjectIdentifiers.HmacRipeMD160); + AddHMacKeyGenerator("TIGER", + IanaObjectIdentifiers.HmacTiger); + + + + // + // key pair generators. + // + AddKpgAlgorithm("DH"); + AddKpgAlgorithm("DSA"); + AddKpgAlgorithm("EC"); + AddKpgAlgorithm("ECDH", + "ECIES"); + AddKpgAlgorithm("ECDHC"); + AddKpgAlgorithm("ECDSA"); + AddKpgAlgorithm("ECGOST3410", + "ECGOST-3410", + "GOST-3410-2001"); + AddKpgAlgorithm("ELGAMAL"); + AddKpgAlgorithm("GOST3410", + "GOST-3410", + "GOST-3410-94"); + AddKpgAlgorithm("RSA", + "1.2.840.113549.1.1.1"); + } + + private static void AddKgAlgorithm( + string canonicalName, + params object[] aliases) + { + kgAlgorithms[canonicalName] = canonicalName; + + foreach (object alias in aliases) + { + kgAlgorithms[alias.ToString()] = canonicalName; + } + } + + private static void AddKpgAlgorithm( + string canonicalName, + params object[] aliases) + { + kpgAlgorithms[canonicalName] = canonicalName; + + foreach (object alias in aliases) + { + kpgAlgorithms[alias.ToString()] = canonicalName; + } + } + + private static void AddHMacKeyGenerator( + string algorithm, + params object[] aliases) + { + string mainName = "HMAC" + algorithm; + + kgAlgorithms[mainName] = mainName; + kgAlgorithms["HMAC-" + algorithm] = mainName; + kgAlgorithms["HMAC/" + algorithm] = mainName; + + foreach (object alias in aliases) + { + kgAlgorithms[alias.ToString()] = mainName; + } + } + + // TODO Consider making this public + internal static string GetCanonicalKeyGeneratorAlgorithm( + string algorithm) + { + return (string) kgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + } + + // TODO Consider making this public + internal static string GetCanonicalKeyPairGeneratorAlgorithm( + string algorithm) + { + return (string) kpgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + } + + public static CipherKeyGenerator GetKeyGenerator( + DerObjectIdentifier oid) + { + return GetKeyGenerator(oid.Id); + } + + public static CipherKeyGenerator GetKeyGenerator( + string algorithm) + { + string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm); + + if (canonicalName == null) + throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised."); + + switch (canonicalName) + { + case "DES": + return new DesKeyGenerator(64); + case "DESEDE": + return new DesEdeKeyGenerator(128); + case "DESEDE3": + return new DesEdeKeyGenerator(192); + case "AES": + return new CipherKeyGenerator(192); + case "AES128": + return new CipherKeyGenerator(128); + case "AES192": + return new CipherKeyGenerator(192); + case "AES256": + return new CipherKeyGenerator(256); + case "BLOWFISH": + return new CipherKeyGenerator(448); + case "CAMELLIA": + return new CipherKeyGenerator(256); + case "CAMELLIA128": + return new CipherKeyGenerator(128); + case "CAMELLIA192": + return new CipherKeyGenerator(192); + case "CAMELLIA256": + return new CipherKeyGenerator(256); + case "CAST5": + return new CipherKeyGenerator(128); + case "CAST6": + return new CipherKeyGenerator(256); + case "GOST28147": + return new CipherKeyGenerator(256); + case "HC128": + return new CipherKeyGenerator(128); + case "HC256": + return new CipherKeyGenerator(256); + case "HMACMD2": + case "HMACMD4": + case "HMACMD5": + return new CipherKeyGenerator(128); + case "HMACSHA1": + return new CipherKeyGenerator(160); + case "HMACSHA224": + return new CipherKeyGenerator(224); + case "HMACSHA256": + return new CipherKeyGenerator(256); + case "HMACSHA384": + return new CipherKeyGenerator(384); + case "HMACSHA512": + return new CipherKeyGenerator(512); + case "HMACRIPEMD128": + return new CipherKeyGenerator(128); + case "HMACRIPEMD160": + return new CipherKeyGenerator(160); + case "HMACTIGER": + return new CipherKeyGenerator(192); + case "IDEA": + return new CipherKeyGenerator(128); + case "NOEKEON": + return new CipherKeyGenerator(128); + case "RC2": + case "RC4": + case "RC5": + return new CipherKeyGenerator(128); + case "RC5-64": + case "RC6": + return new CipherKeyGenerator(256); + case "RIJNDAEL": + return new CipherKeyGenerator(192); + case "SALSA20": + return new CipherKeyGenerator(128); + case "SEED": + return new CipherKeyGenerator(128); + case "SERPENT": + return new CipherKeyGenerator(192); + case "SKIPJACK": + return new CipherKeyGenerator(80); + case "TEA": + case "XTEA": + return new CipherKeyGenerator(128); + case "TWOFISH": + return new CipherKeyGenerator(256); + case "VMPC": + case "VMPC-KSA3": + return new CipherKeyGenerator(128); + } + + throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised."); + } + + public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator( + DerObjectIdentifier oid) + { + return GetKeyPairGenerator(oid.Id); + } + + public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator( + string algorithm) + { + string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm); + + if (canonicalName == null) + throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised."); + + switch (canonicalName) + { + case "DH": + return new DHKeyPairGenerator(); + case "DSA": + return new DsaKeyPairGenerator(); + case "EC": + case "ECDH": + case "ECDHC": + case "ECDSA": + case "ECGOST3410": + return new ECKeyPairGenerator(canonicalName); + case "ELGAMAL": + return new ElGamalKeyPairGenerator(); + case "GOST3410": + return new Gost3410KeyPairGenerator(); + case "RSA": + return new RsaKeyPairGenerator(); + default: + break; + } + + throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised."); + } + } +} diff --git a/iTechSharp/srcbc/security/InvalidKeyException.cs b/iTechSharp/srcbc/security/InvalidKeyException.cs new file mode 100644 index 0000000..97d48e0 --- /dev/null +++ b/iTechSharp/srcbc/security/InvalidKeyException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + public class InvalidKeyException : KeyException + { + public InvalidKeyException() : base() { } + public InvalidKeyException(string message) : base(message) { } + public InvalidKeyException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/InvalidParameterException.cs b/iTechSharp/srcbc/security/InvalidParameterException.cs new file mode 100644 index 0000000..08ca4a0 --- /dev/null +++ b/iTechSharp/srcbc/security/InvalidParameterException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + public class InvalidParameterException : KeyException + { + public InvalidParameterException() : base() { } + public InvalidParameterException(string message) : base(message) { } + public InvalidParameterException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/KeyException.cs b/iTechSharp/srcbc/security/KeyException.cs new file mode 100644 index 0000000..f19264e --- /dev/null +++ b/iTechSharp/srcbc/security/KeyException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + public class KeyException : GeneralSecurityException + { + public KeyException() : base() { } + public KeyException(string message) : base(message) { } + public KeyException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/MacUtilities.cs b/iTechSharp/srcbc/security/MacUtilities.cs new file mode 100644 index 0000000..d782ca1 --- /dev/null +++ b/iTechSharp/srcbc/security/MacUtilities.cs @@ -0,0 +1,220 @@ +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Iana; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Paddings; + +namespace Org.BouncyCastle.Security +{ + /// + /// Utility class for creating HMac object from their names/Oids + /// + public sealed class MacUtilities + { + private MacUtilities() + { + } + + private static readonly Hashtable algorithms = new Hashtable(); +// private static readonly Hashtable oids = new Hashtable(); + + static MacUtilities() + { + algorithms[IanaObjectIdentifiers.HmacMD5.Id] = "HMAC-MD5"; + algorithms[IanaObjectIdentifiers.HmacRipeMD160.Id] = "HMAC-RIPEMD160"; + algorithms[IanaObjectIdentifiers.HmacSha1.Id] = "HMAC-SHA1"; + algorithms[IanaObjectIdentifiers.HmacTiger.Id] = "HMAC-TIGER"; + + algorithms[PkcsObjectIdentifiers.IdHmacWithSha1.Id] = "HMAC-SHA1"; + algorithms[PkcsObjectIdentifiers.IdHmacWithSha224.Id] = "HMAC-SHA224"; + algorithms[PkcsObjectIdentifiers.IdHmacWithSha256.Id] = "HMAC-SHA256"; + algorithms[PkcsObjectIdentifiers.IdHmacWithSha384.Id] = "HMAC-SHA384"; + algorithms[PkcsObjectIdentifiers.IdHmacWithSha512.Id] = "HMAC-SHA512"; + + algorithms["DES"] = "DESMAC"; + algorithms["DES/CFB8"] = "DESMAC/CFB8"; + algorithms["DESEDE"] = "DESEDEMAC"; + algorithms["DESEDE/CFB8"] = "DESEDEMAC/CFB8"; + algorithms["DESISO9797MAC"] = "DESWITHISO9797"; + algorithms["DESEDE64"] = "DESEDEMAC64"; + + algorithms["DESEDE64WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING"; + algorithms["DESEDEISO9797ALG1MACWITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING"; + algorithms["DESEDEISO9797ALG1WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING"; + + algorithms["ISO9797ALG3"] = "ISO9797ALG3MAC"; + algorithms["ISO9797ALG3MACWITHISO7816-4PADDING"] = "ISO9797ALG3WITHISO7816-4PADDING"; + + algorithms["SKIPJACK"] = "SKIPJACKMAC"; + algorithms["SKIPJACK/CFB8"] = "SKIPJACKMAC/CFB8"; + algorithms["IDEA"] = "IDEAMAC"; + algorithms["IDEA/CFB8"] = "IDEAMAC/CFB8"; + algorithms["RC2"] = "RC2MAC"; + algorithms["RC2/CFB8"] = "RC2MAC/CFB8"; + algorithms["RC5"] = "RC5MAC"; + algorithms["RC5/CFB8"] = "RC5MAC/CFB8"; + algorithms["GOST28147"] = "GOST28147MAC"; + algorithms["VMPC"] = "VMPCMAC"; + algorithms["VMPC-MAC"] = "VMPCMAC"; + + algorithms["PBEWITHHMACSHA"] = "PBEWITHHMACSHA1"; + algorithms["1.3.14.3.2.26"] = "PBEWITHHMACSHA1"; + } + +// /// +// /// Returns a ObjectIdentifier for a given digest mechanism. +// /// +// /// A string representation of the digest meanism. +// /// A DerObjectIdentifier, null if the Oid is not available. +// public static DerObjectIdentifier GetObjectIdentifier( +// string mechanism) +// { +// mechanism = (string) algorithms[mechanism.ToUpper(CultureInfo.InvariantCulture)]; +// +// if (mechanism != null) +// { +// return (DerObjectIdentifier)oids[mechanism]; +// } +// +// return null; +// } + +// public static ICollection Algorithms +// { +// get { return oids.Keys; } +// } + + public static IMac GetMac( + DerObjectIdentifier id) + { + return GetMac(id.Id); + } + + public static IMac GetMac( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + if (mechanism.StartsWith("PBEWITH")) + { + mechanism = mechanism.Substring("PBEWITH".Length); + } + + if (mechanism.StartsWith("HMAC")) + { + string digestName; + if (mechanism.StartsWith("HMAC-") || mechanism.StartsWith("HMAC/")) + { + digestName = mechanism.Substring(5); + } + else + { + digestName = mechanism.Substring(4); + } + + return new HMac(DigestUtilities.GetDigest(digestName)); + } + + if (mechanism == "DESMAC") + { + return new CbcBlockCipherMac(new DesEngine()); + } + if (mechanism == "DESMAC/CFB8") + { + return new CfbBlockCipherMac(new DesEngine()); + } + if (mechanism == "DESEDEMAC") + { + return new CbcBlockCipherMac(new DesEdeEngine()); + } + if (mechanism == "DESEDEMAC/CFB8") + { + return new CfbBlockCipherMac(new DesEdeEngine()); + } + if (mechanism == "DESEDEMAC64") + { + return new CbcBlockCipherMac(new DesEdeEngine(), 64); + } + if (mechanism == "DESEDEMAC64WITHISO7816-4PADDING") + { + return new CbcBlockCipherMac(new DesEdeEngine(), 64, new ISO7816d4Padding()); + } + if (mechanism == "DESWITHISO9797" + || mechanism == "ISO9797ALG3MAC") + { + return new ISO9797Alg3Mac(new DesEngine()); + } + if (mechanism == "ISO9797ALG3WITHISO7816-4PADDING") + { + return new ISO9797Alg3Mac(new DesEngine(), new ISO7816d4Padding()); + } + if (mechanism == "SKIPJACKMAC") + { + return new CbcBlockCipherMac(new SkipjackEngine()); + } + if (mechanism == "SKIPJACKMAC/CFB8") + { + return new CfbBlockCipherMac(new SkipjackEngine()); + } + if (mechanism == "IDEAMAC") + { + return new CbcBlockCipherMac(new IdeaEngine()); + } + if (mechanism == "IDEAMAC/CFB8") + { + return new CfbBlockCipherMac(new IdeaEngine()); + } + if (mechanism == "RC2MAC") + { + return new CbcBlockCipherMac(new RC2Engine()); + } + if (mechanism == "RC2MAC/CFB8") + { + return new CfbBlockCipherMac(new RC2Engine()); + } + if (mechanism == "RC5MAC") + { + return new CbcBlockCipherMac(new RC532Engine()); + } + if (mechanism == "RC5MAC/CFB8") + { + return new CfbBlockCipherMac(new RC532Engine()); + } + if (mechanism == "GOST28147MAC") + { + return new Gost28147Mac(); + } + if (mechanism == "VMPCMAC") + { + return new VmpcMac(); + } + throw new SecurityUtilityException("Mac " + mechanism + " not recognised."); + } + + public static string GetAlgorithmName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + + public static byte[] DoFinal( + IMac mac) + { + byte[] b = new byte[mac.GetMacSize()]; + mac.DoFinal(b, 0); + return b; + } + } +} diff --git a/iTechSharp/srcbc/security/NoSuchAlgorithmException.cs b/iTechSharp/srcbc/security/NoSuchAlgorithmException.cs new file mode 100644 index 0000000..25c0ab0 --- /dev/null +++ b/iTechSharp/srcbc/security/NoSuchAlgorithmException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + [Obsolete("Never thrown")] + public class NoSuchAlgorithmException : GeneralSecurityException + { + public NoSuchAlgorithmException() : base() {} + public NoSuchAlgorithmException(string message) : base(message) {} + public NoSuchAlgorithmException(string message, Exception exception) : base(message, exception) {} + } +} diff --git a/iTechSharp/srcbc/security/ParameterUtilities.cs b/iTechSharp/srcbc/security/ParameterUtilities.cs new file mode 100644 index 0000000..7525ced --- /dev/null +++ b/iTechSharp/srcbc/security/ParameterUtilities.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Misc; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Security +{ + public sealed class ParameterUtilities + { + private ParameterUtilities() + { + } + + private static readonly Hashtable algorithms = new Hashtable(); + + static ParameterUtilities() + { + AddAlgorithm("AES", + "AESWRAP"); + AddAlgorithm("AES128", + "2.16.840.1.101.3.4.2", + NistObjectIdentifiers.IdAes128Cbc, + NistObjectIdentifiers.IdAes128Cfb, + NistObjectIdentifiers.IdAes128Ecb, + NistObjectIdentifiers.IdAes128Ofb, + NistObjectIdentifiers.IdAes128Wrap); + AddAlgorithm("AES192", + "2.16.840.1.101.3.4.22", + NistObjectIdentifiers.IdAes192Cbc, + NistObjectIdentifiers.IdAes192Cfb, + NistObjectIdentifiers.IdAes192Ecb, + NistObjectIdentifiers.IdAes192Ofb, + NistObjectIdentifiers.IdAes192Wrap); + AddAlgorithm("AES256", + "2.16.840.1.101.3.4.42", + NistObjectIdentifiers.IdAes256Cbc, + NistObjectIdentifiers.IdAes256Cfb, + NistObjectIdentifiers.IdAes256Ecb, + NistObjectIdentifiers.IdAes256Ofb, + NistObjectIdentifiers.IdAes256Wrap); + AddAlgorithm("BLOWFISH"); + AddAlgorithm("CAMELLIA", + "CAMELLIAWRAP"); + AddAlgorithm("CAMELLIA128", + NttObjectIdentifiers.IdCamellia128Cbc, + NttObjectIdentifiers.IdCamellia128Wrap); + AddAlgorithm("CAMELLIA192", + NttObjectIdentifiers.IdCamellia192Cbc, + NttObjectIdentifiers.IdCamellia192Wrap); + AddAlgorithm("CAMELLIA256", + NttObjectIdentifiers.IdCamellia256Cbc, + NttObjectIdentifiers.IdCamellia256Wrap); + AddAlgorithm("CAST5", + "1.2.840.113533.7.66.10"); + AddAlgorithm("CAST6"); + AddAlgorithm("DES", + OiwObjectIdentifiers.DesCbc); + AddAlgorithm("DESEDE", + "DESEDEWRAP", + PkcsObjectIdentifiers.IdAlgCms3DesWrap); + AddAlgorithm("DESEDE3", + PkcsObjectIdentifiers.DesEde3Cbc); + AddAlgorithm("GOST28147", + "GOST", + "GOST-28147", + CryptoProObjectIdentifiers.GostR28147Cbc); + AddAlgorithm("HC128"); + AddAlgorithm("HC256"); + AddAlgorithm("IDEA", + "1.3.6.1.4.1.188.7.1.1.2"); + AddAlgorithm("NOEKEON"); + AddAlgorithm("RC2", + PkcsObjectIdentifiers.RC2Cbc, + PkcsObjectIdentifiers.IdAlgCmsRC2Wrap); + AddAlgorithm("RC4", + "ARC4", + "1.2.840.113549.3.4"); + AddAlgorithm("RC5", + "RC5-32"); + AddAlgorithm("RC5-64"); + AddAlgorithm("RC6"); + AddAlgorithm("RIJNDAEL"); + AddAlgorithm("SALSA20"); + AddAlgorithm("SEED", + KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap, + KisaObjectIdentifiers.IdSeedCbc); + AddAlgorithm("SERPENT"); + AddAlgorithm("SKIPJACK"); + AddAlgorithm("TEA"); + AddAlgorithm("TWOFISH"); + AddAlgorithm("VMPC"); + AddAlgorithm("VMPC-KSA3"); + AddAlgorithm("XTEA"); + } + + private static void AddAlgorithm( + string canonicalName, + params object[] aliases) + { + algorithms[canonicalName] = canonicalName; + + foreach (object alias in aliases) + { + algorithms[alias.ToString()] = canonicalName; + } + } + + public static string GetCanonicalAlgorithmName( + string algorithm) + { + return (string) algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + } + + public static KeyParameter CreateKeyParameter( + DerObjectIdentifier algOid, + byte[] keyBytes) + { + return CreateKeyParameter(algOid.Id, keyBytes, 0, keyBytes.Length); + } + + public static KeyParameter CreateKeyParameter( + string algorithm, + byte[] keyBytes) + { + return CreateKeyParameter(algorithm, keyBytes, 0, keyBytes.Length); + } + + public static KeyParameter CreateKeyParameter( + DerObjectIdentifier algOid, + byte[] keyBytes, + int offset, + int length) + { + return CreateKeyParameter(algOid.Id, keyBytes, offset, length); + } + + public static KeyParameter CreateKeyParameter( + string algorithm, + byte[] keyBytes, + int offset, + int length) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + string canonical = GetCanonicalAlgorithmName(algorithm); + + if (canonical == null) + throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); + + switch (canonical) + { + case "DES": + return new DesParameters(keyBytes, offset, length); + case "DESEDE": + case "DESEDE3": + return new DesEdeParameters(keyBytes, offset, length); + case "RC2": + return new RC2Parameters(keyBytes, offset, length); + default: + return new KeyParameter(keyBytes, offset, length); + } + } + + public static ICipherParameters GetCipherParameters( + DerObjectIdentifier algOid, + ICipherParameters key, + Asn1Object asn1Params) + { + return GetCipherParameters(algOid.Id, key, asn1Params); + } + + public static ICipherParameters GetCipherParameters( + string algorithm, + ICipherParameters key, + Asn1Object asn1Params) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + string canonical = GetCanonicalAlgorithmName(algorithm); + + if (canonical == null) + throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); + + byte[] iv = null; + + try + { + switch (canonical) + { + case "AES": + case "AES128": + case "AES192": + case "AES256": + case "BLOWFISH": + case "CAMELLIA": + case "CAMELLIA128": + case "CAMELLIA192": + case "CAMELLIA256": + case "DES": + case "DESEDE": + case "DESEDE3": + case "NOEKEON": + case "RIJNDAEL": + case "SEED": + case "SKIPJACK": + case "TWOFISH": + iv = ((Asn1OctetString) asn1Params).GetOctets(); + break; + case "RC2": + iv = RC2CbcParameter.GetInstance(asn1Params).GetIV(); + break; + case "IDEA": + iv = IdeaCbcPar.GetInstance(asn1Params).GetIV(); + break; + case "CAST5": + iv = Cast5CbcParameters.GetInstance(asn1Params).GetIV(); + break; + } + } + catch (Exception e) + { + throw new ArgumentException("Could not process ASN.1 parameters", e); + } + + if (iv != null) + { + return new ParametersWithIV(key, iv); + } + + throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); + } + + public static Asn1Encodable GenerateParameters( + DerObjectIdentifier algID, + SecureRandom random) + { + return GenerateParameters(algID.Id, random); + } + + public static Asn1Encodable GenerateParameters( + string algorithm, + SecureRandom random) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + string canonical = GetCanonicalAlgorithmName(algorithm); + + if (canonical == null) + throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); + + switch (canonical) + { + // TODO These algorithms support an IV (see GetCipherParameters) + // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them +// case "BLOWFISH": +// case "RIJNDAEL": +// case "SKIPJACK": +// case "TWOFISH": + + case "AES": + case "AES128": + case "AES192": + case "AES256": + return CreateIVOctetString(random, 16); + case "CAMELLIA": + case "CAMELLIA128": + case "CAMELLIA192": + case "CAMELLIA256": + return CreateIVOctetString(random, 16); + case "CAST5": + return new Cast5CbcParameters(CreateIV(random, 8), 128); + case "DES": + case "DESEDE": + case "DESEDE3": + return CreateIVOctetString(random, 8); + case "IDEA": + return new IdeaCbcPar(CreateIV(random, 8)); + case "NOEKEON": + return CreateIVOctetString(random, 16); + case "RC2": + return new RC2CbcParameter(CreateIV(random, 8)); + case "SEED": + return CreateIVOctetString(random, 16); + } + + throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised."); + } + + private static Asn1OctetString CreateIVOctetString( + SecureRandom random, + int ivLength) + { + return new DerOctetString(CreateIV(random, ivLength)); + } + + private static byte[] CreateIV( + SecureRandom random, + int ivLength) + { + byte[] iv = new byte[ivLength]; + random.NextBytes(iv); + return iv; + } + } +} diff --git a/iTechSharp/srcbc/security/PbeUtilities.cs b/iTechSharp/srcbc/security/PbeUtilities.cs new file mode 100644 index 0000000..95270cb --- /dev/null +++ b/iTechSharp/srcbc/security/PbeUtilities.cs @@ -0,0 +1,554 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; + +namespace Org.BouncyCastle.Security +{ + /// + /// + /// + public sealed class PbeUtilities + { + private PbeUtilities() + { + } + + const string Pkcs5S1 = "Pkcs5S1"; + const string Pkcs5S2 = "Pkcs5S2"; + const string Pkcs12 = "Pkcs12"; + const string OpenSsl = "OpenSsl"; + + private static readonly Hashtable algorithms = new Hashtable(); + private static readonly Hashtable algorithmType = new Hashtable(); + private static readonly Hashtable oids = new Hashtable(); + + static PbeUtilities() + { + algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1"; + algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2"; + algorithms["PBEWITHMD2ANDDES-CBC"] = "PBEwithMD2andDES-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithMD2AndDesCbc.Id] = "PBEwithMD2andDES-CBC"; + algorithms["PBEWITHMD2ANDRC2-CBC"] = "PBEwithMD2andRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc.Id] = "PBEwithMD2andRC2-CBC"; + algorithms["PBEWITHMD5ANDDES-CBC"] = "PBEwithMD5andDES-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithMD5AndDesCbc.Id] = "PBEwithMD5andDES-CBC"; + algorithms["PBEWITHMD5ANDRC2-CBC"] = "PBEwithMD5andRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc.Id] = "PBEwithMD5andRC2-CBC"; + algorithms["PBEWITHSHA1ANDDES"] = "PBEwithSHA-1andDES-CBC"; + algorithms["PBEWITHSHA-1ANDDES"] = "PBEwithSHA-1andDES-CBC"; + algorithms["PBEWITHSHA1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC"; + algorithms["PBEWITHSHA-1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEwithSHA-1andDES-CBC"; + algorithms["PBEWITHSHA1ANDRC2"] = "PBEwithSHA-1andRC2-CBC"; + algorithms["PBEWITHSHA-1ANDRC2"] = "PBEwithSHA-1andRC2-CBC"; + algorithms["PBEWITHSHA1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC"; + algorithms["PBEWITHSHA-1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEwithSHA-1andRC2-CBC"; + algorithms["PKCS12"] = "Pkcs12"; + algorithms["PBEWITHSHAAND128BITRC4"] = "PBEwithSHA-1and128bitRC4"; + algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4"; + algorithms["PBEWITHSHA-1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEwithSHA-1and128bitRC4"; + algorithms["PBEWITHSHAAND40BITRC4"] = "PBEwithSHA-1and40bitRC4"; + algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4"; + algorithms["PBEWITHSHA-1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEwithSHA-1and40bitRC4"; + algorithms["PBEWITHSHAAND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms["PBEWITHSHAAND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms["PBEWITHSHA1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms["PBEWITHSHA-1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms["PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEwithSHA-1and3-keyDESEDE-CBC"; + algorithms["PBEWITHSHAAND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms["PBEWITHSHAAND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms["PBEWITHSHA1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms["PBEWITHSHA-1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms["PBEWITHSHA-1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEwithSHA-1and2-keyDESEDE-CBC"; + algorithms["PBEWITHSHAAND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC"; + algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC"; + algorithms["PBEWITHSHA-1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEwithSHA-1and128bitRC2-CBC"; + algorithms["PBEWITHSHAAND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC"; + algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC"; + algorithms["PBEWITHSHA-1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC"; + algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEwithSHA-1and40bitRC2-CBC"; + algorithms["PBEWITHSHAAND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC"; + algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC"; + algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC"; + algorithms["PBEWITHSHAAND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC"; + algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC"; + algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC"; + algorithms["PBEWITHSHAAND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC"; + algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC"; + algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC"; + algorithms["PBEWITHSHA256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC"; + algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC"; + algorithms["PBEWITHSHA256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC"; + algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC"; + algorithms["PBEWITHSHA256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC"; + algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC"; + algorithms["PBEWITHSHAANDIDEA"] = "PBEwithSHA-1andIDEA-CBC"; + algorithms["PBEWITHSHAANDIDEA-CBC"] = "PBEwithSHA-1andIDEA-CBC"; + algorithms["PBEWITHSHAANDTWOFISH"] = "PBEwithSHA-1andTWOFISH-CBC"; + algorithms["PBEWITHSHAANDTWOFISH-CBC"] = "PBEwithSHA-1andTWOFISH-CBC"; + algorithms["PBEWITHHMACSHA1"] = "PBEwithHmacSHA-1"; + algorithms["PBEWITHHMACSHA-1"] = "PBEwithHmacSHA-1"; + algorithms[OiwObjectIdentifiers.IdSha1.Id] = "PBEwithHmacSHA-1"; + algorithms["PBEWITHHMACSHA224"] = "PBEwithHmacSHA-224"; + algorithms["PBEWITHHMACSHA-224"] = "PBEwithHmacSHA-224"; + algorithms[NistObjectIdentifiers.IdSha224.Id] = "PBEwithHmacSHA-224"; + algorithms["PBEWITHHMACSHA256"] = "PBEwithHmacSHA-256"; + algorithms["PBEWITHHMACSHA-256"] = "PBEwithHmacSHA-256"; + algorithms[NistObjectIdentifiers.IdSha256.Id] = "PBEwithHmacSHA-256"; + algorithms["PBEWITHHMACRIPEMD128"] = "PBEwithHmacRipeMD128"; + algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "PBEwithHmacRipeMD128"; + algorithms["PBEWITHHMACRIPEMD160"] = "PBEwithHmacRipeMD160"; + algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "PBEwithHmacRipeMD160"; + algorithms["PBEWITHHMACRIPEMD256"] = "PBEwithHmacRipeMD256"; + algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "PBEwithHmacRipeMD256"; + algorithms["PBEWITHHMACTIGER"] = "PBEwithHmacTiger"; + + algorithms["PBEWITHMD5AND128BITAES-CBC-OPENSSL"] = "PBEwithMD5and128bitAES-CBC-OpenSSL"; + algorithms["PBEWITHMD5AND192BITAES-CBC-OPENSSL"] = "PBEwithMD5and192bitAES-CBC-OpenSSL"; + algorithms["PBEWITHMD5AND256BITAES-CBC-OPENSSL"] = "PBEwithMD5and256bitAES-CBC-OpenSSL"; + + algorithmType["Pkcs5scheme1"] = Pkcs5S1; + algorithmType["Pkcs5scheme2"] = Pkcs5S2; + algorithmType["PBEwithMD2andDES-CBC"] = Pkcs5S1; + algorithmType["PBEwithMD2andRC2-CBC"] = Pkcs5S1; + algorithmType["PBEwithMD5andDES-CBC"] = Pkcs5S1; + algorithmType["PBEwithMD5andRC2-CBC"] = Pkcs5S1; + algorithmType["PBEwithSHA-1andDES-CBC"] = Pkcs5S1; + algorithmType["PBEwithSHA-1andRC2-CBC"] = Pkcs5S1; + algorithmType["Pkcs12"] = Pkcs12; + algorithmType["PBEwithSHA-1and128bitRC4"] = Pkcs12; + algorithmType["PBEwithSHA-1and40bitRC4"] = Pkcs12; + algorithmType["PBEwithSHA-1and3-keyDESEDE-CBC"] = Pkcs12; + algorithmType["PBEwithSHA-1and2-keyDESEDE-CBC"] = Pkcs12; + algorithmType["PBEwithSHA-1and128bitRC2-CBC"] = Pkcs12; + algorithmType["PBEwithSHA-1and40bitRC2-CBC"] = Pkcs12; + algorithmType["PBEwithSHA-1and128bitAES-CBC-BC"] = Pkcs12; + algorithmType["PBEwithSHA-1and192bitAES-CBC-BC"] = Pkcs12; + algorithmType["PBEwithSHA-1and256bitAES-CBC-BC"] = Pkcs12; + algorithmType["PBEwithSHA-256and128bitAES-CBC-BC"] = Pkcs12; + algorithmType["PBEwithSHA-256and192bitAES-CBC-BC"] = Pkcs12; + algorithmType["PBEwithSHA-256and256bitAES-CBC-BC"] = Pkcs12; + algorithmType["PBEwithSHA-1andIDEA-CBC"] = "Pkcs12"; + algorithmType["PBEwithSHA-1andTWOFISH-CBC"] = "Pkcs12"; + algorithmType["PBEwithHmacSHA-1"] = Pkcs12; + algorithmType["PBEwithHmacSHA-224"] = Pkcs12; + algorithmType["PBEwithHmacSHA-256"] = Pkcs12; + algorithmType["PBEwithHmacRipeMD128"] = Pkcs12; + algorithmType["PBEwithHmacRipeMD160"] = Pkcs12; + algorithmType["PBEwithHmacRipeMD256"] = Pkcs12; + algorithmType["PBEwithHmacTiger"] = Pkcs12; + + algorithmType["PBEwithMD5and128bitAES-CBC-OpenSSL"] = OpenSsl; + algorithmType["PBEwithMD5and192bitAES-CBC-OpenSSL"] = OpenSsl; + algorithmType["PBEwithMD5and256bitAES-CBC-OpenSSL"] = OpenSsl; + + oids["PBEwithMD2andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndDesCbc; + oids["PBEwithMD2andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc; + oids["PBEwithMD5andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndDesCbc; + oids["PBEwithMD5andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc; + oids["PBEwithSHA-1andDES-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndDesCbc; + oids["PBEwithSHA-1andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc; + oids["PBEwithSHA-1and128bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4; + oids["PBEwithSHA-1and40bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4; + oids["PBEwithSHA-1and3-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc; + oids["PBEwithSHA-1and2-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc; + oids["PBEwithSHA-1and128bitRC2-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc; + oids["PBEwithSHA-1and40bitRC2-CBC"] = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc; + oids["PBEwithHmacSHA-1"] = OiwObjectIdentifiers.IdSha1; + oids["PBEwithHmacSHA-224"] = NistObjectIdentifiers.IdSha224; + oids["PBEwithHmacSHA-256"] = NistObjectIdentifiers.IdSha256; + oids["PBEwithHmacRipeMD128"] = TeleTrusTObjectIdentifiers.RipeMD128; + oids["PBEwithHmacRipeMD160"] = TeleTrusTObjectIdentifiers.RipeMD160; + oids["PBEwithHmacRipeMD256"] = TeleTrusTObjectIdentifiers.RipeMD256; + } + + static PbeParametersGenerator MakePbeGenerator( + string type, + IDigest digest, + byte[] key, + byte[] salt, + int iterationCount) + { + PbeParametersGenerator generator; + + if (type.Equals(Pkcs5S1)) + { + generator = new Pkcs5S1ParametersGenerator(digest); + } + else if (type.Equals(Pkcs5S2)) + { + generator = new Pkcs5S2ParametersGenerator(); + } + else if (type.Equals(Pkcs12)) + { + generator = new Pkcs12ParametersGenerator(digest); + } + else if (type.Equals(OpenSsl)) + { + generator = new OpenSslPbeParametersGenerator(); + } + else + { + throw new ArgumentException("Unknown PBE type: " + type, "type"); + } + + generator.Init(key, salt, iterationCount); + return generator; + } + + /// + /// Returns a ObjectIdentifier for a give encoding. + /// + /// A string representation of the encoding. + /// A DerObjectIdentifier, null if the Oid is not available. + public static DerObjectIdentifier GetObjectIdentifier( + string mechanism) + { + mechanism = (string) algorithms[mechanism.ToUpper(CultureInfo.InvariantCulture)]; + if (mechanism != null) + { + return (DerObjectIdentifier)oids[mechanism]; + } + return null; + } + + public static ICollection Algorithms + { + get { return oids.Keys; } + } + + public static bool IsPkcs12( + string algorithm) + { + string mechanism = (string) algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + + return mechanism != null && Pkcs12.Equals(algorithmType[mechanism]); + } + + public static bool IsPkcs5Scheme1( + string algorithm) + { + string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + + return mechanism != null && Pkcs5S1.Equals(algorithmType[mechanism]); + } + + public static bool IsPkcs5Scheme2( + string algorithm) + { + string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + + return mechanism != null && Pkcs5S2.Equals(algorithmType[mechanism]); + } + + public static bool IsOpenSsl( + string algorithm) + { + string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + + return mechanism != null && OpenSsl.Equals(algorithmType[mechanism]); + } + + public static bool IsPbeAlgorithm( + string algorithm) + { + string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + + return mechanism != null && algorithmType[mechanism] != null; + } + + public static Asn1Encodable GenerateAlgorithmParameters( + DerObjectIdentifier algorithmOid, + byte[] salt, + int iterationCount) + { + return GenerateAlgorithmParameters(algorithmOid.Id, salt, iterationCount); + } + + public static Asn1Encodable GenerateAlgorithmParameters( + string algorithm, + byte[] salt, + int iterationCount) + { + if (IsPkcs12(algorithm)) + { + return new Pkcs12PbeParams(salt, iterationCount); + } + else if (IsPkcs5Scheme2(algorithm)) + { + return new Pbkdf2Params(salt, iterationCount); + } + else + { + return new PbeParameter(salt, iterationCount); + } + } + + public static ICipherParameters GenerateCipherParameters( + DerObjectIdentifier algorithmOid, + char[] password, + Asn1Encodable pbeParameters) + { + return GenerateCipherParameters(algorithmOid.Id, password, false, pbeParameters); + } + + public static ICipherParameters GenerateCipherParameters( + DerObjectIdentifier algorithmOid, + char[] password, + bool wrongPkcs12Zero, + Asn1Encodable pbeParameters) + { + return GenerateCipherParameters(algorithmOid.Id, password, wrongPkcs12Zero, pbeParameters); + } + + public static ICipherParameters GenerateCipherParameters( + string algorithm, + char[] password, + Asn1Encodable pbeParameters) + { + return GenerateCipherParameters(algorithm, password, false, pbeParameters); + } + + public static ICipherParameters GenerateCipherParameters( + string algorithm, + char[] password, + bool wrongPkcs12Zero, + Asn1Encodable pbeParameters) + { + string mechanism = (string) algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + byte[] keyBytes; + //string type = (string)algorithmType[mechanism]; + byte[] salt; + int iterationCount; + + if (IsPkcs12(mechanism)) + { + Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(pbeParameters); + salt = pbeParams.GetIV(); + iterationCount = pbeParams.Iterations.IntValue; + keyBytes = PbeParametersGenerator.Pkcs12PasswordToBytes(password, wrongPkcs12Zero); + } + else if (IsPkcs5Scheme2(mechanism)) + { + Pbkdf2Params pbeParams = Pbkdf2Params.GetInstance(pbeParameters); + salt = pbeParams.GetSalt(); + iterationCount = pbeParams.IterationCount.IntValue; + keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password); + } + else + { + PbeParameter pbeParams = PbeParameter.GetInstance(pbeParameters); + salt = pbeParams.GetSalt(); + iterationCount = pbeParams.IterationCount.IntValue; + keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password); + } + + ICipherParameters parameters = null; + + if (mechanism.StartsWith("PBEwithSHA-1")) + { + PbeParametersGenerator generator = MakePbeGenerator( + (string) algorithmType[mechanism], new Sha1Digest(), keyBytes, salt, iterationCount); + + if (mechanism.Equals("PBEwithSHA-1and128bitRC4")) + { + parameters = generator.GenerateDerivedParameters("RC4", 128); + } + else if (mechanism.Equals("PBEwithSHA-1and40bitRC4")) + { + parameters = generator.GenerateDerivedParameters("RC4", 40); + } + else if (mechanism.Equals("PBEwithSHA-1and3-keyDESEDE-CBC")) + { + parameters = generator.GenerateDerivedParameters("DESEDE", 192, 64); + } + else if (mechanism.Equals("PBEwithSHA-1and2-keyDESEDE-CBC")) + { + parameters = generator.GenerateDerivedParameters("DESEDE", 128, 64); + } + else if (mechanism.Equals("PBEwithSHA-1and128bitRC2-CBC")) + { + parameters = generator.GenerateDerivedParameters("RC2", 128, 64); + } + else if (mechanism.Equals("PBEwithSHA-1and40bitRC2-CBC")) + { + parameters = generator.GenerateDerivedParameters("RC2", 40, 64); + } + else if (mechanism.Equals("PBEwithSHA-1andDES-CBC")) + { + parameters = generator.GenerateDerivedParameters("DES", 64, 64); + } + else if (mechanism.Equals("PBEwithSHA-1andRC2-CBC")) + { + parameters = generator.GenerateDerivedParameters("RC2", 64, 64); + } + else if (mechanism.Equals("PBEwithSHA-1and128bitAES-CBC-BC")) + { + parameters = generator.GenerateDerivedParameters("AES", 128, 128); + } + else if (mechanism.Equals("PBEwithSHA-1and192bitAES-CBC-BC")) + { + parameters = generator.GenerateDerivedParameters("AES", 192, 128); + } + else if (mechanism.Equals("PBEwithSHA-1and256bitAES-CBC-BC")) + { + parameters = generator.GenerateDerivedParameters("AES", 256, 128); + } + } + else if (mechanism.StartsWith("PBEwithSHA-256")) + { + PbeParametersGenerator generator = MakePbeGenerator( + (string) algorithmType[mechanism], new Sha256Digest(), keyBytes, salt, iterationCount); + + if (mechanism.Equals("PBEwithSHA-256and128bitAES-CBC-BC")) + { + parameters = generator.GenerateDerivedParameters("AES", 128, 128); + } + else if (mechanism.Equals("PBEwithSHA-256and192bitAES-CBC-BC")) + { + parameters = generator.GenerateDerivedParameters("AES", 192, 128); + } + else if (mechanism.Equals("PBEwithSHA-256and256bitAES-CBC-BC")) + { + parameters = generator.GenerateDerivedParameters("AES", 256, 128); + } + } + else if (mechanism.StartsWith("PBEwithMD5")) + { + PbeParametersGenerator generator = MakePbeGenerator( + (string)algorithmType[mechanism], new MD5Digest(), keyBytes, salt, iterationCount); + + if (mechanism.Equals("PBEwithMD5andDES-CBC")) + { + parameters = generator.GenerateDerivedParameters("DES", 64, 64); + } + else if (mechanism.Equals("PBEwithMD5andRC2-CBC")) + { + parameters = generator.GenerateDerivedParameters("RC2", 64, 64); + } + else if (mechanism.Equals("PBEwithMD5and128bitAES-CBC-OpenSSL")) + { + parameters = generator.GenerateDerivedParameters("AES", 128, 128); + } + else if (mechanism.Equals("PBEwithMD5and192bitAES-CBC-OpenSSL")) + { + parameters = generator.GenerateDerivedParameters("AES", 192, 128); + } + else if (mechanism.Equals("PBEwithMD5and256bitAES-CBC-OpenSSL")) + { + parameters = generator.GenerateDerivedParameters("AES", 256, 128); + } + } + else if (mechanism.StartsWith("PBEwithMD2")) + { + PbeParametersGenerator generator = MakePbeGenerator( + (string)algorithmType[mechanism], new MD2Digest(), keyBytes, salt, iterationCount); + if (mechanism.Equals("PBEwithMD2andDES-CBC")) + { + parameters = generator.GenerateDerivedParameters("DES", 64, 64); + } + else if (mechanism.Equals("PBEwithMD2andRC2-CBC")) + { + parameters = generator.GenerateDerivedParameters("RC2", 64, 64); + } + } + else if (mechanism.StartsWith("PBEwithHmac")) + { + string digestName = mechanism.Substring("PBEwithHmac".Length); + IDigest digest = DigestUtilities.GetDigest(digestName); + + PbeParametersGenerator generator = MakePbeGenerator( + (string) algorithmType[mechanism], digest, keyBytes, salt, iterationCount); + + int bitLen = digest.GetDigestSize() * 8; + parameters = generator.GenerateDerivedMacParameters(bitLen); + } + + Array.Clear(keyBytes, 0, keyBytes.Length); + + return parameters; + } + + public static object CreateEngine( + DerObjectIdentifier algorithmOid) + { + return CreateEngine(algorithmOid.Id); + } + + private static bool EndsWith( + string s, + string ending) + { + int pos = s.Length - ending.Length; + + return pos >= 0 && s.Substring(pos) == ending; + } + + public static object CreateEngine( + string algorithm) + { + string mechanism = (string)algorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + + if (mechanism.StartsWith("PBEwithHmac")) + { + string digestName = mechanism.Substring("PBEwithHmac".Length); + + return MacUtilities.GetMac("HMAC/" + digestName); + } + + if (mechanism.StartsWith("PBEwithMD2") + || mechanism.StartsWith("PBEwithMD5") + || mechanism.StartsWith("PBEwithSHA-1")) + { + if (EndsWith(mechanism, "RC2-CBC")) + { + return CipherUtilities.GetCipher("RC2/CBC"); + } + + if (EndsWith(mechanism, "RC4")) + { + return CipherUtilities.GetCipher("RC4"); + } + + if (EndsWith(mechanism, "DES-CBC")) + { + return CipherUtilities.GetCipher("DES/CBC"); + } + + if (EndsWith(mechanism, "DESEDE-CBC")) + { + return CipherUtilities.GetCipher("DESEDE/CBC"); + } + } + + return null; + } + + public static string GetEncodingName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + } +} diff --git a/iTechSharp/srcbc/security/PrivateKeyFactory.cs b/iTechSharp/srcbc/security/PrivateKeyFactory.cs new file mode 100644 index 0000000..a24c9c2 --- /dev/null +++ b/iTechSharp/srcbc/security/PrivateKeyFactory.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Security +{ + public sealed class PrivateKeyFactory + { + private PrivateKeyFactory() + { + } + + public static AsymmetricKeyParameter CreateKey( + byte[] privateKeyInfoData) + { + return CreateKey( + PrivateKeyInfo.GetInstance( + Asn1Object.FromByteArray(privateKeyInfoData))); + } + + public static AsymmetricKeyParameter CreateKey( + Stream inStr) + { + return CreateKey( + PrivateKeyInfo.GetInstance( + Asn1Object.FromStream(inStr))); + } + + public static AsymmetricKeyParameter CreateKey( + PrivateKeyInfo keyInfo) + { + AlgorithmIdentifier algID = keyInfo.AlgorithmID; + DerObjectIdentifier algOid = algID.ObjectID; + + if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)) + { + RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure( + Asn1Sequence.GetInstance(keyInfo.PrivateKey)); + + return new RsaPrivateCrtKeyParameters( + keyStructure.Modulus, + keyStructure.PublicExponent, + keyStructure.PrivateExponent, + keyStructure.Prime1, + keyStructure.Prime2, + keyStructure.Exponent1, + keyStructure.Exponent2, + keyStructure.Coefficient); + } + else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement)) + { + DHParameter para = new DHParameter( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + DerInteger derX = (DerInteger)keyInfo.PrivateKey; + + return new DHPrivateKeyParameters( + derX.Value, + new DHParameters(para.P, para.G)); + } + else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm)) + { + ElGamalParameter para = new ElGamalParameter( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + DerInteger derX = (DerInteger)keyInfo.PrivateKey; + + return new ElGamalPrivateKeyParameters( + derX.Value, + new ElGamalParameters(para.P, para.G)); + } + else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)) + { + DsaParameter para = DsaParameter.GetInstance( + algID.Parameters.ToAsn1Object()); + DerInteger derX = (DerInteger) keyInfo.PrivateKey; + + return new DsaPrivateKeyParameters( + derX.Value, + new DsaParameters(para.P, para.Q, para.G)); + } + else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) + { + X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object()); + X9ECParameters ecP; + + if (para.IsNamedCurve) + { + // TODO ECGost3410NamedCurves support (returns ECDomainParameters though) + + DerObjectIdentifier oid = (DerObjectIdentifier) para.Parameters; + ecP = X962NamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = SecNamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = NistNamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.GetByOid(oid); + } + } + } + } + else + { + ecP = new X9ECParameters((Asn1Sequence) para.Parameters); + } + + ECDomainParameters dParams = new ECDomainParameters( + ecP.Curve, + ecP.G, + ecP.N, + ecP.H, + ecP.GetSeed()); + + ECPrivateKeyStructure ec = new ECPrivateKeyStructure( + Asn1Sequence.GetInstance(keyInfo.PrivateKey)); + + return new ECPrivateKeyParameters(ec.GetKey(), dParams); + } + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)) + { + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + + ECPrivateKeyStructure ec = new ECPrivateKeyStructure( + Asn1Sequence.GetInstance(keyInfo.PrivateKey)); + + ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + + if (ecP == null) + return null; + + return new ECPrivateKeyParameters(ec.GetKey(), gostParams.PublicKeyParamSet); + } + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) + { + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + + DerOctetString derX = (DerOctetString) keyInfo.PrivateKey; + byte[] keyEnc = derX.GetOctets(); + byte[] keyBytes = new byte[keyEnc.Length]; + + for (int i = 0; i != keyEnc.Length; i++) + { + keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian + } + + BigInteger x = new BigInteger(1, keyBytes); + + return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet); + } + else + { + throw new SecurityUtilityException("algorithm identifier in key not recognised"); + } + } + } +} diff --git a/iTechSharp/srcbc/security/PublicKeyFactory.cs b/iTechSharp/srcbc/security/PublicKeyFactory.cs new file mode 100644 index 0000000..062525f --- /dev/null +++ b/iTechSharp/srcbc/security/PublicKeyFactory.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Security +{ + public sealed class PublicKeyFactory + { + private PublicKeyFactory() + { + } + + public static AsymmetricKeyParameter CreateKey( + byte[] keyInfoData) + { + return CreateKey( + SubjectPublicKeyInfo.GetInstance( + Asn1Object.FromByteArray(keyInfoData))); + } + + public static AsymmetricKeyParameter CreateKey( + Stream inStr) + { + return CreateKey( + SubjectPublicKeyInfo.GetInstance( + Asn1Object.FromStream(inStr))); + } + + public static AsymmetricKeyParameter CreateKey( + SubjectPublicKeyInfo keyInfo) + { + AlgorithmIdentifier algID = keyInfo.AlgorithmID; + DerObjectIdentifier algOid = algID.ObjectID; + + if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption) + || algOid.Equals(X509ObjectIdentifiers.IdEARsa)) + { + RsaPublicKeyStructure pubKey = RsaPublicKeyStructure.GetInstance( + keyInfo.GetPublicKey()); + + return new RsaKeyParameters(false, pubKey.Modulus, pubKey.PublicExponent); + } + else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement) + || algOid.Equals(X9ObjectIdentifiers.DHPublicNumber)) + { + DHParameter para = new DHParameter( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + DerInteger derY = (DerInteger) keyInfo.GetPublicKey(); + + return new DHPublicKeyParameters(derY.Value, new DHParameters(para.P, para.G)); + } + else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm)) + { + ElGamalParameter para = new ElGamalParameter( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + DerInteger derY = (DerInteger) keyInfo.GetPublicKey(); + + return new ElGamalPublicKeyParameters( + derY.Value, + new ElGamalParameters(para.P, para.G)); + } + else if (algOid.Equals(X9ObjectIdentifiers.IdDsa) + || algOid.Equals(OiwObjectIdentifiers.DsaWithSha1)) + { + DerInteger derY = (DerInteger) keyInfo.GetPublicKey(); + + Asn1Encodable ae = algID.Parameters; + Asn1Object ao = ae == null ? null : ae.ToAsn1Object(); + + DsaParameter para = DsaParameter.GetInstance(ao); + + return new DsaPublicKeyParameters( + derY.Value, + new DsaParameters(para.P, para.Q, para.G)); + } + else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) + { + X962Parameters para = new X962Parameters( + algID.Parameters.ToAsn1Object()); + X9ECParameters ecP; + + if (para.IsNamedCurve) + { + // TODO ECGost3410NamedCurves support (returns ECDomainParameters though) + + DerObjectIdentifier oid = (DerObjectIdentifier)para.Parameters; + ecP = X962NamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = SecNamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = NistNamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.GetByOid(oid); + } + } + } + } + else + { + ecP = new X9ECParameters((Asn1Sequence)para.Parameters.ToAsn1Object()); + } + + ECDomainParameters dParams = new ECDomainParameters( + ecP.Curve, + ecP.G, + ecP.N, + ecP.H, + ecP.GetSeed()); + + DerBitString bits = keyInfo.PublicKeyData; + byte[] data = bits.GetBytes(); + Asn1OctetString key = new DerOctetString(data); + + X9ECPoint derQ = new X9ECPoint(dParams.Curve, key); + + return new ECPublicKeyParameters(derQ.Point, dParams); + } + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)) + { + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + (Asn1Sequence) algID.Parameters); + + Asn1OctetString key; + try + { + key = (Asn1OctetString) keyInfo.GetPublicKey(); + } + catch (IOException) + { + throw new ArgumentException("invalid info structure in GOST3410 public key"); + } + + byte[] keyEnc = key.GetOctets(); + byte[] x = new byte[32]; + byte[] y = new byte[32]; + + for (int i = 0; i != y.Length; i++) + { + x[i] = keyEnc[32 - 1 - i]; + } + + for (int i = 0; i != x.Length; i++) + { + y[i] = keyEnc[64 - 1 - i]; + } + + ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + + if (ecP == null) + return null; + + ECPoint q = ecP.Curve.CreatePoint(new BigInteger(1, x), new BigInteger(1, y), false); + + return new ECPublicKeyParameters(q, gostParams.PublicKeyParamSet); + } + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) + { + Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters( + (Asn1Sequence) algID.Parameters); + + DerOctetString derY; + try + { + derY = (DerOctetString) keyInfo.GetPublicKey(); + } + catch (IOException) + { + throw new ArgumentException("invalid info structure in GOST3410 public key"); + } + + byte[] keyEnc = derY.GetOctets(); + byte[] keyBytes = new byte[keyEnc.Length]; + + for (int i = 0; i != keyEnc.Length; i++) + { + keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian + } + + BigInteger y = new BigInteger(1, keyBytes); + + return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet); + } + else + { + throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid); + } + } + } +} diff --git a/iTechSharp/srcbc/security/SecureRandom.cs b/iTechSharp/srcbc/security/SecureRandom.cs new file mode 100644 index 0000000..86ddc8f --- /dev/null +++ b/iTechSharp/srcbc/security/SecureRandom.cs @@ -0,0 +1,224 @@ +using System; +using System.Globalization; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Prng; + +namespace Org.BouncyCastle.Security +{ + public class SecureRandom + : Random + { + private static readonly SecureRandom[] master = { null }; + private static SecureRandom Master + { + get + { + if (master[0] == null) + { + IRandomGenerator gen = new DigestRandomGenerator(new Sha256Digest()); + gen = new ReversedWindowGenerator(gen, 32); + SecureRandom sr = master[0] = new SecureRandom(gen); + + sr.SetSeed(DateTime.Now.Ticks); + sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(24, true)); + sr.GenerateSeed(1 + sr.Next(32)); + } + + return master[0]; + } + } + + public static SecureRandom GetInstance( + string algorithm) + { + // TODO Compared to JDK, we don't auto-seed if the client forgets - problem? + + // TODO Support all digests more generally, by stripping PRNG and calling DigestUtilities? + IDigest digest = null; + switch (algorithm.ToUpper(CultureInfo.InvariantCulture)) + { + case "SHA1PRNG": + digest = new Sha1Digest(); + break; + case "SHA256PRNG": + digest = new Sha256Digest(); + break; + } + + if (digest != null) + { + return new SecureRandom(new DigestRandomGenerator(digest)); + } + + throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm"); + } + + public static byte[] GetSeed( + int length) + { + return Master.GenerateSeed(length); + } + + protected IRandomGenerator generator; + + public SecureRandom() + : base(0) + { + this.generator = new DigestRandomGenerator(new Sha1Digest()); + SetSeed(GetSeed(8)); + } + + public SecureRandom( + byte[] inSeed) + : base(0) + { + this.generator = new DigestRandomGenerator(new Sha1Digest()); + SetSeed(inSeed); + } + + /// Use the specified instance of IRandomGenerator as random source. + /// + /// This constructor performs no seeding of either the IRandomGenerator or the + /// constructed SecureRandom. It is the responsibility of the client to provide + /// proper seed material as necessary/appropriate for the given IRandomGenerator + /// implementation. + /// + /// The source to generate all random bytes from. + public SecureRandom( + IRandomGenerator generator) + : base(0) + { + this.generator = generator; + } + + public virtual byte[] GenerateSeed( + int length) + { + SetSeed(DateTime.Now.Ticks); + + byte[] rv = new byte[length]; + NextBytes(rv); + return rv; + } + + public virtual void SetSeed( + byte[] inSeed) + { + generator.AddSeedMaterial(inSeed); + } + + public virtual void SetSeed( + long seed) + { + generator.AddSeedMaterial(seed); + } + + public override int Next() + { + for (;;) + { + int i = NextInt() & int.MaxValue; + + if (i != int.MaxValue) + return i; + } + } + + public override int Next( + int maxValue) + { + if (maxValue < 2) + { + if (maxValue < 0) + throw new ArgumentOutOfRangeException("maxValue < 0"); + + return 0; + } + + // Test whether maxValue is a power of 2 + if ((maxValue & -maxValue) == maxValue) + { + int val = NextInt() & int.MaxValue; + long lr = ((long) maxValue * (long) val) >> 31; + return (int) lr; + } + + int bits, result; + do + { + bits = NextInt() & int.MaxValue; + result = bits % maxValue; + } + while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow + + return result; + } + + public override int Next( + int minValue, + int maxValue) + { + if (maxValue <= minValue) + { + if (maxValue == minValue) + return minValue; + + throw new ArgumentException("maxValue cannot be less than minValue"); + } + + int diff = maxValue - minValue; + if (diff > 0) + return minValue + Next(diff); + + for (;;) + { + int i = NextInt(); + + if (i >= minValue && i < maxValue) + return i; + } + } + + public override void NextBytes( + byte[] buffer) + { + generator.NextBytes(buffer); + } + + public virtual void NextBytes( + byte[] buffer, + int start, + int length) + { + generator.NextBytes(buffer, start, length); + } + + private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0); + + public override double NextDouble() + { + return Convert.ToDouble((ulong) NextLong()) / DoubleScale; + } + + public virtual int NextInt() + { + byte[] intBytes = new byte[4]; + NextBytes(intBytes); + + int result = 0; + for (int i = 0; i < 4; i++) + { + result = (result << 8) + (intBytes[i] & 0xff); + } + + return result; + } + + public virtual long NextLong() + { + return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt(); + } + } +} diff --git a/iTechSharp/srcbc/security/SecurityUtilityException.cs b/iTechSharp/srcbc/security/SecurityUtilityException.cs new file mode 100644 index 0000000..8a5ea68 --- /dev/null +++ b/iTechSharp/srcbc/security/SecurityUtilityException.cs @@ -0,0 +1,33 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + public class SecurityUtilityException + : Exception + { + /** + * base constructor. + */ + public SecurityUtilityException() + { + } + + /** + * create a SecurityUtilityException with the given message. + * + * @param message the message to be carried with the exception. + */ + public SecurityUtilityException( + string message) + : base(message) + { + } + + public SecurityUtilityException( + string message, + Exception exception) + : base(message, exception) + { + } + } +} diff --git a/iTechSharp/srcbc/security/SignatureException.cs b/iTechSharp/srcbc/security/SignatureException.cs new file mode 100644 index 0000000..5ae4cbc --- /dev/null +++ b/iTechSharp/srcbc/security/SignatureException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security +{ + public class SignatureException : GeneralSecurityException + { + public SignatureException() : base() { } + public SignatureException(string message) : base(message) { } + public SignatureException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/SignerUtilities.cs b/iTechSharp/srcbc/security/SignerUtilities.cs new file mode 100644 index 0000000..0c58b30 --- /dev/null +++ b/iTechSharp/srcbc/security/SignerUtilities.cs @@ -0,0 +1,517 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Signers; + +namespace Org.BouncyCastle.Security +{ + /// + /// Signer Utility class contains methods that can not be specifically grouped into other classes. + /// + public sealed class SignerUtilities + { + private SignerUtilities() + { + } + + internal static readonly Hashtable algorithms = new Hashtable(); + internal static readonly Hashtable oids = new Hashtable(); + + static SignerUtilities() + { + algorithms["MD2WITHRSA"] = "MD2withRSA"; + algorithms["MD2WITHRSAENCRYPTION"] = "MD2withRSA"; + algorithms[PkcsObjectIdentifiers.MD2WithRsaEncryption.Id] = "MD2withRSA"; + + algorithms["MD4WITHRSA"] = "MD4withRSA"; + algorithms["MD4WITHRSAENCRYPTION"] = "MD4withRSA"; + algorithms[PkcsObjectIdentifiers.MD4WithRsaEncryption.Id] = "MD4withRSA"; + + algorithms["MD5WITHRSA"] = "MD5withRSA"; + algorithms["MD5WITHRSAENCRYPTION"] = "MD5withRSA"; + algorithms[PkcsObjectIdentifiers.MD5WithRsaEncryption.Id] = "MD5withRSA"; + + algorithms["SHA1WITHRSA"] = "SHA-1withRSA"; + algorithms["SHA1WITHRSAENCRYPTION"] = "SHA-1withRSA"; + algorithms[PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id] = "SHA-1withRSA"; + algorithms["SHA-1WITHRSA"] = "SHA-1withRSA"; + + algorithms["SHA224WITHRSA"] = "SHA-224withRSA"; + algorithms["SHA224WITHRSAENCRYPTION"] = "SHA-224withRSA"; + algorithms[PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id] = "SHA-224withRSA"; + algorithms["SHA-224WITHRSA"] = "SHA-224withRSA"; + + algorithms["SHA256WITHRSA"] = "SHA-256withRSA"; + algorithms["SHA256WITHRSAENCRYPTION"] = "SHA-256withRSA"; + algorithms[PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id] = "SHA-256withRSA"; + algorithms["SHA-256WITHRSA"] = "SHA-256withRSA"; + + algorithms["SHA384WITHRSA"] = "SHA-384withRSA"; + algorithms["SHA384WITHRSAENCRYPTION"] = "SHA-384withRSA"; + algorithms[PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id] = "SHA-384withRSA"; + algorithms["SHA-384WITHRSA"] = "SHA-384withRSA"; + + algorithms["SHA512WITHRSA"] = "SHA-512withRSA"; + algorithms["SHA512WITHRSAENCRYPTION"] = "SHA-512withRSA"; + algorithms[PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id] = "SHA-512withRSA"; + algorithms["SHA-512WITHRSA"] = "SHA-512withRSA"; + + algorithms["PSSWITHRSA"] = "PSSwithRSA"; + algorithms["RSASSA-PSS"] = "PSSwithRSA"; + algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA"; + + algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1"; + algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1"; + algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1"; + algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1"; + + algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1"; + algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1"; + algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1"; + algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1"; + + algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1"; + algorithms["SHA-256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1"; + algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1"; + algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1"; + + algorithms["SHA384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1"; + algorithms["SHA-384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1"; + algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1"; + algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1"; + + algorithms["SHA512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1"; + algorithms["SHA-512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1"; + algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1"; + algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1"; + + algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA"; + algorithms["RIPEMD128WITHRSAENCRYPTION"] = "RIPEMD128withRSA"; + algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128.Id] = "RIPEMD128withRSA"; + + algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA"; + algorithms["RIPEMD160WITHRSAENCRYPTION"] = "RIPEMD160withRSA"; + algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160.Id] = "RIPEMD160withRSA"; + + algorithms["RIPEMD256WITHRSA"] = "RIPEMD256withRSA"; + algorithms["RIPEMD256WITHRSAENCRYPTION"] = "RIPEMD256withRSA"; + algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256.Id] = "RIPEMD256withRSA"; + + algorithms["NONEWITHDSA"] = "NONEwithDSA"; + algorithms["DSAWITHNONE"] = "NONEwithDSA"; + + algorithms["DSA"] = "SHA-1withDSA"; + algorithms["DSAWITHSHA1"] = "SHA-1withDSA"; + algorithms["DSAWITHSHA-1"] = "SHA-1withDSA"; + algorithms["SHA/DSA"] = "SHA-1withDSA"; + algorithms["SHA1/DSA"] = "SHA-1withDSA"; + algorithms["SHA-1/DSA"] = "SHA-1withDSA"; + algorithms["SHA1WITHDSA"] = "SHA-1withDSA"; + algorithms["SHA-1WITHDSA"] = "SHA-1withDSA"; + algorithms[X9ObjectIdentifiers.IdDsaWithSha1.Id] = "SHA-1withDSA"; + + algorithms["DSAWITHSHA224"] = "SHA-224withDSA"; + algorithms["DSAWITHSHA-224"] = "SHA-224withDSA"; + algorithms["SHA224/DSA"] = "SHA-224withDSA"; + algorithms["SHA-224/DSA"] = "SHA-224withDSA"; + algorithms["SHA224WITHDSA"] = "SHA-224withDSA"; + algorithms["SHA-224WITHDSA"] = "SHA-224withDSA"; + algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA"; + + algorithms["DSAWITHSHA256"] = "SHA-256withDSA"; + algorithms["DSAWITHSHA-256"] = "SHA-256withDSA"; + algorithms["SHA256/DSA"] = "SHA-256withDSA"; + algorithms["SHA-256/DSA"] = "SHA-256withDSA"; + algorithms["SHA256WITHDSA"] = "SHA-256withDSA"; + algorithms["SHA-256WITHDSA"] = "SHA-256withDSA"; + algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA"; + + algorithms["DSAWITHSHA384"] = "SHA-384withDSA"; + algorithms["DSAWITHSHA-384"] = "SHA-384withDSA"; + algorithms["SHA384/DSA"] = "SHA-384withDSA"; + algorithms["SHA-384/DSA"] = "SHA-384withDSA"; + algorithms["SHA384WITHDSA"] = "SHA-384withDSA"; + algorithms["SHA-384WITHDSA"] = "SHA-384withDSA"; + algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA"; + + algorithms["DSAWITHSHA512"] = "SHA-512withDSA"; + algorithms["DSAWITHSHA-512"] = "SHA-512withDSA"; + algorithms["SHA512/DSA"] = "SHA-512withDSA"; + algorithms["SHA-512/DSA"] = "SHA-512withDSA"; + algorithms["SHA512WITHDSA"] = "SHA-512withDSA"; + algorithms["SHA-512WITHDSA"] = "SHA-512withDSA"; + algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA"; + + + algorithms["ECDSA"] = "SHA-1withECDSA"; + algorithms["SHA1/ECDSA"] = "SHA-1withECDSA"; + algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA"; + algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA"; + algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA"; + algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA"; + algorithms["SHA-1WITHECDSA"] = "SHA-1withECDSA"; + algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA"; + algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA"; + + algorithms["SHA224/ECDSA"] = "SHA-224withECDSA"; + algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA"; + algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA"; + algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA"; + algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA"; + algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA"; + algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA"; + + algorithms["SHA256/ECDSA"] = "SHA-256withECDSA"; + algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA"; + algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA"; + algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA"; + algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA"; + algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA"; + algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA"; + + algorithms["SHA384/ECDSA"] = "SHA-384withECDSA"; + algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA"; + algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA"; + algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA"; + algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA"; + algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA"; + algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA"; + + algorithms["SHA512/ECDSA"] = "SHA-512withECDSA"; + algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA"; + algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA"; + algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA"; + algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA"; + algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA"; + algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA"; + + algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA"; + algorithms["SHA-512/ECDSA"] = "RIPEMD160withECDSA"; + algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA"; + algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA"; + algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA"; + algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA"; + algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA"; + + algorithms["GOST-3410"] = "GOST3410"; + algorithms["GOST-3410-94"] = "GOST3410"; + algorithms["GOST3411WITHGOST3410"] = "GOST3410"; + algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410"; + + algorithms["ECGOST-3410"] = "ECGOST3410"; + algorithms["ECGOST-3410-2001"] = "ECGOST3410"; + algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410"; + algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410"; + + + + oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption; + oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption; + oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption; + + oids["SHA-1withRSA"] = PkcsObjectIdentifiers.Sha1WithRsaEncryption; + oids["SHA-224withRSA"] = PkcsObjectIdentifiers.Sha224WithRsaEncryption; + oids["SHA-256withRSA"] = PkcsObjectIdentifiers.Sha256WithRsaEncryption; + oids["SHA-384withRSA"] = PkcsObjectIdentifiers.Sha384WithRsaEncryption; + oids["SHA-512withRSA"] = PkcsObjectIdentifiers.Sha512WithRsaEncryption; + + oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss; + oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss; + oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss; + oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss; + oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss; + oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss; + + oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128; + oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160; + oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256; + + oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1; + + oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1; + oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224; + oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256; + oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384; + oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512; + + oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94; + oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001; + } + + /// + /// Returns a ObjectIdentifier for a give encoding. + /// + /// A string representation of the encoding. + /// A DerObjectIdentifier, null if the Oid is not available. + // TODO Don't really want to support this + public static DerObjectIdentifier GetObjectIdentifier( + string mechanism) + { + if (mechanism == null) + throw new ArgumentNullException("mechanism"); + + mechanism = mechanism.ToUpper(CultureInfo.InvariantCulture); + string aliased = (string) algorithms[mechanism]; + + if (aliased != null) + mechanism = aliased; + + return (DerObjectIdentifier) oids[mechanism]; + } + + public static ICollection Algorithms + { + get { return oids.Keys; } + } + + public static ISigner GetSigner( + DerObjectIdentifier id) + { + return GetSigner(id.Id); + } + + public static ISigner GetSigner( + string algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + algorithm = algorithm.ToUpper(CultureInfo.InvariantCulture); + + string mechanism = (string) algorithms[algorithm]; + + if (mechanism == null) + mechanism = algorithm; + + if (mechanism.Equals("MD2withRSA")) + { + return (new RsaDigestSigner(new MD2Digest())); + } + if (mechanism.Equals("MD4withRSA")) + { + return (new RsaDigestSigner(new MD4Digest())); + } + if (mechanism.Equals("MD5withRSA")) + { + return (new RsaDigestSigner(new MD5Digest())); + } + if (mechanism.Equals("SHA-1withRSA")) + { + return (new RsaDigestSigner(new Sha1Digest())); + } + if (mechanism.Equals("SHA-224withRSA")) + { + return (new RsaDigestSigner(new Sha224Digest())); + } + if (mechanism.Equals("SHA-256withRSA")) + { + return (new RsaDigestSigner(new Sha256Digest())); + } + if (mechanism.Equals("SHA-384withRSA")) + { + return (new RsaDigestSigner(new Sha384Digest())); + } + if (mechanism.Equals("SHA-512withRSA")) + { + return (new RsaDigestSigner(new Sha512Digest())); + } + if (mechanism.Equals("RIPEMD128withRSA")) + { + return (new RsaDigestSigner(new RipeMD128Digest())); + } + if (mechanism.Equals("RIPEMD160withRSA")) + { + return (new RsaDigestSigner(new RipeMD160Digest())); + } + if (mechanism.Equals("RIPEMD256withRSA")) + { + return (new RsaDigestSigner(new RipeMD256Digest())); + } + + if (mechanism.Equals("PSSwithRSA")) + { + // TODO The Sha1Digest here is a default. In JCE version, the actual digest + // to be used can be overridden by subsequent parameter settings. + return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest())); + } + if (mechanism.Equals("SHA-1withRSAandMGF1")) + { + return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest())); + } + if (mechanism.Equals("SHA-224withRSAandMGF1")) + { + return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest())); + } + if (mechanism.Equals("SHA-256withRSAandMGF1")) + { + return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest())); + } + if (mechanism.Equals("SHA-384withRSAandMGF1")) + { + return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest())); + } + if (mechanism.Equals("SHA-512withRSAandMGF1")) + { + return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest())); + } + + if (mechanism.Equals("NONEwithDSA")) + { + return (new DsaDigestSigner(new DsaSigner(), new NullDigest())); + } + if (mechanism.Equals("SHA-1withDSA")) + { + return (new DsaDigestSigner(new DsaSigner(), new Sha1Digest())); + } + if (mechanism.Equals("SHA-224withDSA")) + { + return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest())); + } + if (mechanism.Equals("SHA-256withDSA")) + { + return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest())); + } + if (mechanism.Equals("SHA-384withDSA")) + { + return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest())); + } + if (mechanism.Equals("SHA-512withDSA")) + { + return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest())); + } + + if (mechanism.Equals("SHA-1withECDSA")) + { + return (new DsaDigestSigner(new ECDsaSigner(), new Sha1Digest())); + } + if (mechanism.Equals("SHA-224withECDSA")) + { + return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest())); + } + if (mechanism.Equals("SHA-256withECDSA")) + { + return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest())); + } + if (mechanism.Equals("SHA-384withECDSA")) + { + return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest())); + } + if (mechanism.Equals("SHA-512withECDSA")) + { + return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest())); + } + + if (mechanism.Equals("RIPEMD160withECDSA")) + { + return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest())); + } + + if (mechanism.Equals("SHA1WITHECNR")) + { + return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest())); + } + if (mechanism.Equals("SHA224WITHECNR")) + { + return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest())); + } + if (mechanism.Equals("SHA256WITHECNR")) + { + return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest())); + } + if (mechanism.Equals("SHA384WITHECNR")) + { + return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest())); + } + if (mechanism.Equals("SHA512WITHECNR")) + { + return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest())); + } + + if (mechanism.Equals("GOST3410")) + { + return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest()); + } + if (mechanism.Equals("ECGOST3410")) + { + return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest()); + } + + if (mechanism.Equals("SHA1WITHRSA/ISO9796-2")) + { + return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true); + } + if (mechanism.Equals("MD5WITHRSA/ISO9796-2")) + { + return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true); + } + if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2")) + { + return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true); + } + + throw new SecurityUtilityException("Signer " + algorithm + " not recognised."); + } + + public static string GetEncodingName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + + private class NullDigest : IDigest + { + private readonly MemoryStream bOut = new MemoryStream(); + + public string AlgorithmName + { + get { return "NULL"; } + } + + public int GetByteLength() + { + // TODO Is this okay? + return 0; + } + + public int GetDigestSize() + { + return (int) bOut.Length; + } + + public void Update(byte b) + { + bOut.WriteByte(b); + } + + public void BlockUpdate(byte[] inBytes, int inOff, int len) + { + bOut.Write(inBytes, inOff, len); + } + + public int DoFinal(byte[] outBytes, int outOff) + { + byte[] res = bOut.ToArray(); + res.CopyTo(outBytes, outOff); + return res.Length; + } + + public void Reset() + { + bOut.SetLength(0); + } + } + + } +} diff --git a/iTechSharp/srcbc/security/WrapperUtilities.cs b/iTechSharp/srcbc/security/WrapperUtilities.cs new file mode 100644 index 0000000..f93c89e --- /dev/null +++ b/iTechSharp/srcbc/security/WrapperUtilities.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; + +namespace Org.BouncyCastle.Security +{ + /// + /// Utility class for creating IWrapper objects from their names/Oids + /// + public sealed class WrapperUtilities + { + private WrapperUtilities() + { + } + + private static readonly Hashtable algorithms = new Hashtable(); +// private static readonly Hashtable oids = new Hashtable(); + + static WrapperUtilities() + { + algorithms[NistObjectIdentifiers.IdAes128Wrap.Id] = "AESWRAP"; + algorithms[NistObjectIdentifiers.IdAes192Wrap.Id] = "AESWRAP"; + algorithms[NistObjectIdentifiers.IdAes256Wrap.Id] = "AESWRAP"; + + algorithms[NttObjectIdentifiers.IdCamellia128Wrap.Id] = "CAMELLIAWRAP"; + algorithms[NttObjectIdentifiers.IdCamellia192Wrap.Id] = "CAMELLIAWRAP"; + algorithms[NttObjectIdentifiers.IdCamellia256Wrap.Id] = "CAMELLIAWRAP"; + + algorithms[PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id] = "DESEDEWRAP"; + + algorithms[PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id] = "RC2WRAP"; + + algorithms[KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id] = "SEEDWRAP"; + } + + public static IWrapper GetWrapper( + DerObjectIdentifier oid) + { + return GetWrapper(oid.Id); + } + + public static IWrapper GetWrapper( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + switch (mechanism) + { + case "AESWRAP": + return new AesWrapEngine(); + case "CAMELLIAWRAP": + return new CamelliaWrapEngine(); + case "DESEDEWRAP": + return new DesEdeWrapEngine(); + case "RC2WRAP": + return new RC2WrapEngine(); + case "SEEDWRAP": + return new SeedWrapEngine(); + case "DESEDERFC3211WRAP": + return new Rfc3211WrapEngine(new DesEdeEngine()); + case "AESRFC3211WRAP": + return new Rfc3211WrapEngine(new AesFastEngine()); + case "CAMELLIARFC3211WRAP": + return new Rfc3211WrapEngine(new CamelliaEngine()); + } + + // Create an IBufferedCipher and use it as IWrapper (via BufferedCipherWrapper) + IBufferedCipher blockCipher = CipherUtilities.GetCipher(algorithm); + + if (blockCipher != null) + return new BufferedCipherWrapper(blockCipher); + + throw new SecurityUtilityException("Wrapper " + algorithm + " not recognised."); + } + + public static string GetAlgorithmName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + + private class BufferedCipherWrapper + : IWrapper + { + private readonly IBufferedCipher cipher; + private bool forWrapping; + + public BufferedCipherWrapper( + IBufferedCipher cipher) + { + this.cipher = cipher; + } + + public string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + public void Init( + bool forWrapping, + ICipherParameters parameters) + { + this.forWrapping = forWrapping; + + cipher.Init(forWrapping, parameters); + } + + public byte[] Wrap( + byte[] input, + int inOff, + int length) + { + if (!forWrapping) + throw new InvalidOperationException("Not initialised for wrapping"); + + return cipher.DoFinal(input, inOff, length); + } + + public byte[] Unwrap( + byte[] input, + int inOff, + int length) + { + if (forWrapping) + throw new InvalidOperationException("Not initialised for Unwrapping"); + + return cipher.DoFinal(input, inOff, length); + } + } + } +} diff --git a/iTechSharp/srcbc/security/cert/CertificateEncodingException.cs b/iTechSharp/srcbc/security/cert/CertificateEncodingException.cs new file mode 100644 index 0000000..ae6a566 --- /dev/null +++ b/iTechSharp/srcbc/security/cert/CertificateEncodingException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security.Certificates +{ + public class CertificateEncodingException : CertificateException + { + public CertificateEncodingException() : base() { } + public CertificateEncodingException(string msg) : base(msg) { } + public CertificateEncodingException(string msg, Exception e) : base(msg, e) { } + } +} diff --git a/iTechSharp/srcbc/security/cert/CertificateException.cs b/iTechSharp/srcbc/security/cert/CertificateException.cs new file mode 100644 index 0000000..fa403c7 --- /dev/null +++ b/iTechSharp/srcbc/security/cert/CertificateException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security.Certificates +{ + public class CertificateException : GeneralSecurityException + { + public CertificateException() : base() { } + public CertificateException(string message) : base(message) { } + public CertificateException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/cert/CertificateExpiredException.cs b/iTechSharp/srcbc/security/cert/CertificateExpiredException.cs new file mode 100644 index 0000000..33a5480 --- /dev/null +++ b/iTechSharp/srcbc/security/cert/CertificateExpiredException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security.Certificates +{ + public class CertificateExpiredException : CertificateException + { + public CertificateExpiredException() : base() { } + public CertificateExpiredException(string message) : base(message) { } + public CertificateExpiredException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/cert/CertificateNotYetValidException.cs b/iTechSharp/srcbc/security/cert/CertificateNotYetValidException.cs new file mode 100644 index 0000000..b9210e5 --- /dev/null +++ b/iTechSharp/srcbc/security/cert/CertificateNotYetValidException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security.Certificates +{ + public class CertificateNotYetValidException : CertificateException + { + public CertificateNotYetValidException() : base() { } + public CertificateNotYetValidException(string message) : base(message) { } + public CertificateNotYetValidException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/cert/CertificateParsingException.cs b/iTechSharp/srcbc/security/cert/CertificateParsingException.cs new file mode 100644 index 0000000..9a1d011 --- /dev/null +++ b/iTechSharp/srcbc/security/cert/CertificateParsingException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security.Certificates +{ + public class CertificateParsingException : CertificateException + { + public CertificateParsingException() : base() { } + public CertificateParsingException(string message) : base(message) { } + public CertificateParsingException(string message, Exception exception) : base(message, exception) { } + } +} diff --git a/iTechSharp/srcbc/security/cert/CrlException.cs b/iTechSharp/srcbc/security/cert/CrlException.cs new file mode 100644 index 0000000..59e4f20 --- /dev/null +++ b/iTechSharp/srcbc/security/cert/CrlException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Org.BouncyCastle.Security.Certificates +{ + public class CrlException : GeneralSecurityException + { + public CrlException() : base() { } + public CrlException(string msg) : base(msg) {} + public CrlException(string msg, Exception e) : base(msg, e) {} + } +} diff --git a/iTechSharp/srcbc/tsp/GenTimeAccuracy.cs b/iTechSharp/srcbc/tsp/GenTimeAccuracy.cs new file mode 100644 index 0000000..8a2f299 --- /dev/null +++ b/iTechSharp/srcbc/tsp/GenTimeAccuracy.cs @@ -0,0 +1,33 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Tsp; + +namespace Org.BouncyCastle.Tsp +{ + public class GenTimeAccuracy + { + private Accuracy accuracy; + + public GenTimeAccuracy( + Accuracy accuracy) + { + this.accuracy = accuracy; + } + + public int Seconds { get { return GetTimeComponent(accuracy.Seconds); } } + + public int Millis { get { return GetTimeComponent(accuracy.Millis); } } + + public int Micros { get { return GetTimeComponent(accuracy.Micros); } } + + private int GetTimeComponent( + DerInteger time) + { + return time == null ? 0 : time.Value.IntValue; + } + + public override string ToString() + { + return Seconds + "." + Millis.ToString("000") + Micros.ToString("000"); + } + } +} diff --git a/iTechSharp/srcbc/tsp/TSPAlgorithms.cs b/iTechSharp/srcbc/tsp/TSPAlgorithms.cs new file mode 100644 index 0000000..7a5ad4e --- /dev/null +++ b/iTechSharp/srcbc/tsp/TSPAlgorithms.cs @@ -0,0 +1,47 @@ +using System.Collections; + +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; + +namespace Org.BouncyCastle.Tsp +{ + /** + * Recognised hash algorithms for the time stamp protocol. + */ + public abstract class TspAlgorithms + { + public static readonly string MD5 = PkcsObjectIdentifiers.MD5.Id; + + public static readonly string Sha1 = OiwObjectIdentifiers.IdSha1.Id; + + public static readonly string Sha224 = NistObjectIdentifiers.IdSha224.Id; + public static readonly string Sha256 = NistObjectIdentifiers.IdSha256.Id; + public static readonly string Sha384 = NistObjectIdentifiers.IdSha384.Id; + public static readonly string Sha512 = NistObjectIdentifiers.IdSha512.Id; + + public static readonly string RipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id; + public static readonly string RipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id; + public static readonly string RipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id; + + public static readonly string Gost3411 = CryptoProObjectIdentifiers.GostR3411.Id; + + public static readonly ArrayList Allowed; + + static TspAlgorithms() + { + string[] algs = new string[] + { + Gost3411, MD5, Sha1, Sha224, Sha256, Sha384, Sha512, RipeMD128, RipeMD160, RipeMD256 + }; + + Allowed = new ArrayList(); + foreach (string alg in algs) + { + Allowed.Add(alg); + } + } + } +} diff --git a/iTechSharp/srcbc/tsp/TSPException.cs b/iTechSharp/srcbc/tsp/TSPException.cs new file mode 100644 index 0000000..a5e2416 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TSPException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Tsp +{ + public class TspException + : Exception + { + public TspException() + { + } + + public TspException( + string message) + : base(message) + { + } + + public TspException( + string message, + Exception e) + : base(message, e) + { + } + } +} diff --git a/iTechSharp/srcbc/tsp/TSPUtil.cs b/iTechSharp/srcbc/tsp/TSPUtil.cs new file mode 100644 index 0000000..873e1b8 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TSPUtil.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Tsp +{ + public class TspUtil + { + private static readonly IDictionary digestLengths = new Hashtable(); + private static readonly IDictionary digestNames = new Hashtable(); + + static TspUtil() + { + digestLengths.Add(PkcsObjectIdentifiers.MD5.Id, 16); + digestLengths.Add(OiwObjectIdentifiers.IdSha1.Id, 20); + digestLengths.Add(NistObjectIdentifiers.IdSha224.Id, 28); + digestLengths.Add(NistObjectIdentifiers.IdSha256.Id, 32); + digestLengths.Add(NistObjectIdentifiers.IdSha384.Id, 48); + digestLengths.Add(NistObjectIdentifiers.IdSha512.Id, 64); + + digestNames.Add(PkcsObjectIdentifiers.MD5.Id, "MD5"); + digestNames.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1"); + digestNames.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224"); + digestNames.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256"); + digestNames.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384"); + digestNames.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512"); + digestNames.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id, "SHA1"); + digestNames.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id, "SHA224"); + digestNames.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, "SHA256"); + digestNames.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id, "SHA384"); + digestNames.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id, "SHA512"); + digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128"); + digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160"); + digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256"); + digestNames.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411"); + } + + /** + * Validate the passed in certificate as being of the correct type to be used + * for time stamping. To be valid it must have an ExtendedKeyUsage extension + * which has a key purpose identifier of id-kp-timeStamping. + * + * @param cert the certificate of interest. + * @throws TspValidationException if the certicate fails on one of the check points. + */ + public static void ValidateCertificate( + X509Certificate cert) + { + if (cert.Version != 3) + throw new ArgumentException("Certificate must have an ExtendedKeyUsage extension."); + + Asn1OctetString ext = cert.GetExtensionValue(X509Extensions.ExtendedKeyUsage); + if (ext == null) + throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension."); + + if (!cert.GetCriticalExtensionOids().Contains(X509Extensions.ExtendedKeyUsage.Id)) + throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical."); + + try + { + ExtendedKeyUsage extKey = ExtendedKeyUsage.GetInstance( + Asn1Object.FromByteArray(ext.GetOctets())); + + if (!extKey.HasKeyPurposeId(KeyPurposeID.IdKPTimeStamping) || extKey.Count != 1) + throw new TspValidationException("ExtendedKeyUsage not solely time stamping."); + } + catch (IOException) + { + throw new TspValidationException("cannot process ExtendedKeyUsage extension"); + } + } + + /// + /// Return the digest algorithm using one of the standard JCA string + /// representations rather than the algorithm identifier (if possible). + /// + internal static string GetDigestAlgName( + string digestAlgOID) + { + string digestName = (string) digestNames[digestAlgOID]; + + return digestName != null ? digestName : digestAlgOID; + } + + internal static int GetDigestLength( + string digestAlgOID) + { + string digestName = GetDigestAlgName(digestAlgOID); + + try + { + if (digestLengths.Contains(digestAlgOID)) + { + return (int) digestLengths[digestAlgOID]; + } + + return DigestUtilities.GetDigest(digestName).GetDigestSize(); + } + catch (SecurityUtilityException e) + { + throw new TspException("digest algorithm cannot be found.", e); + } + } + } +} diff --git a/iTechSharp/srcbc/tsp/TSPValidationException.cs b/iTechSharp/srcbc/tsp/TSPValidationException.cs new file mode 100644 index 0000000..7cb4ff5 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TSPValidationException.cs @@ -0,0 +1,39 @@ +namespace Org.BouncyCastle.Tsp +{ + /** + * Exception thrown if a TSP request or response fails to validate. + *

      + * If a failure code is assciated with the exception it can be retrieved using + * the getFailureCode() method.

      + */ + public class TspValidationException + : TspException + { + private int failureCode; + + public TspValidationException( + string message) + : base(message) + { + this.failureCode = -1; + } + + public TspValidationException( + string message, + int failureCode) + : base(message) + { + this.failureCode = failureCode; + } + + /** + * Return the failure code associated with this exception - if one is set. + * + * @return the failure code if set, -1 otherwise. + */ + public int FailureCode + { + get { return failureCode; } + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampRequest.cs b/iTechSharp/srcbc/tsp/TimeStampRequest.cs new file mode 100644 index 0000000..7205a9a --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampRequest.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Tsp +{ + /** + * Base class for an RFC 3161 Time Stamp Request. + */ + public class TimeStampRequest + : X509ExtensionBase + { + private TimeStampReq req; + + public TimeStampRequest( + TimeStampReq req) + { + this.req = req; + } + + /** + * Create a TimeStampRequest from the past in byte array. + * + * @param req byte array containing the request. + * @throws IOException if the request is malformed. + */ + public TimeStampRequest( + byte[] req) + : this(new Asn1InputStream(req)) + { + } + + /** + * Create a TimeStampRequest from the past in input stream. + * + * @param in input stream containing the request. + * @throws IOException if the request is malformed. + */ + public TimeStampRequest( + Stream input) + : this(new Asn1InputStream(input)) + { + } + + private TimeStampRequest( + Asn1InputStream str) + { + try + { + this.req = TimeStampReq.GetInstance(str.ReadObject()); + } + catch (InvalidCastException e) + { + throw new IOException("malformed request: " + e); + } + catch (ArgumentException e) + { + throw new IOException("malformed request: " + e); + } + } + + public int Version + { + get { return req.Version.Value.IntValue; } + } + + public string MessageImprintAlgOid + { + get { return req.MessageImprint.HashAlgorithm.ObjectID.Id; } + } + + public byte[] GetMessageImprintDigest() + { + return req.MessageImprint.GetHashedMessage(); + } + + public string ReqPolicy + { + get + { + return req.ReqPolicy == null + ? null + : req.ReqPolicy.Id; + } + } + + public BigInteger Nonce + { + get + { + return req.Nonce == null + ? null + : req.Nonce.Value; + } + } + + public bool CertReq + { + get + { + return req.CertReq == null + ? false + : req.CertReq.IsTrue; + } + } + + /** + * Validate the timestamp request, checking the digest to see if it is of an + * accepted type and whether it is of the correct length for the algorithm specified. + * + * @param algorithms a set of string OIDS giving accepted algorithms. + * @param policies if non-null a set of policies we are willing to sign under. + * @param extensions if non-null a set of extensions we are willing to accept. + * @throws TspException if the request is invalid, or processing fails. + */ + public void Validate( + IList algorithms, + IList policies, + IList extensions) + { + if (!algorithms.Contains(this.MessageImprintAlgOid)) + { + throw new TspValidationException("request contains unknown algorithm.", PkiFailureInfo.BadAlg); + } + + if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy)) + { + throw new TspValidationException("request contains unknown policy.", PkiFailureInfo.UnacceptedPolicy); + } + + if (this.Extensions != null && extensions != null) + { + foreach (DerObjectIdentifier oid in this.Extensions.ExtensionOids) + { + if (!extensions.Contains(oid.Id)) + { + throw new TspValidationException("request contains unknown extension.", + PkiFailureInfo.UnacceptedExtension); + } + } + } + + int digestLength = TspUtil.GetDigestLength(this.MessageImprintAlgOid); + + if (digestLength != this.GetMessageImprintDigest().Length) + { + throw new TspValidationException("imprint digest the wrong length.", + PkiFailureInfo.BadDataFormat); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return req.GetEncoded(); + } + + internal X509Extensions Extensions + { + get { return req.Extensions; } + } + + protected override X509Extensions GetX509Extensions() + { + return Extensions; + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampRequestGenerator.cs b/iTechSharp/srcbc/tsp/TimeStampRequestGenerator.cs new file mode 100644 index 0000000..fc37d32 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampRequestGenerator.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Tsp +{ + /** + * Generator for RFC 3161 Time Stamp Request objects. + */ + public class TimeStampRequestGenerator + { + private DerObjectIdentifier reqPolicy; + + private DerBoolean certReq; + + private Hashtable extensions = new Hashtable(); + private ArrayList extOrdering = new ArrayList(); + + public void SetReqPolicy( + string reqPolicy) + { + this.reqPolicy = new DerObjectIdentifier(reqPolicy); + } + + public void SetCertReq( + bool certReq) + { + this.certReq = DerBoolean.GetInstance(certReq); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * @throws IOException + */ + public void AddExtension( + string oid, + bool critical, + Asn1Encodable value) + { + this.AddExtension(oid, critical, value.GetEncoded()); + } + + /** + * add a given extension field for the standard extensions tag + * The value parameter becomes the contents of the octet string associated + * with the extension. + */ + public void AddExtension( + string oid, + bool critical, + byte[] value) + { + DerObjectIdentifier derOid = new DerObjectIdentifier(oid); + extensions[derOid] = new X509Extension(critical, new DerOctetString(value)); + extOrdering.Add(derOid); + } + + public TimeStampRequest Generate( + string digestAlgorithm, + byte[] digest) + { + return this.Generate(digestAlgorithm, digest, null); + } + + public TimeStampRequest Generate( + string digestAlgorithmOid, + byte[] digest, + BigInteger nonce) + { + if (digestAlgorithmOid == null) + { + throw new ArgumentException("No digest algorithm specified"); + } + + DerObjectIdentifier digestAlgOid = new DerObjectIdentifier(digestAlgorithmOid); + + AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOid, DerNull.Instance); + MessageImprint messageImprint = new MessageImprint(algID, digest); + + X509Extensions ext = null; + + if (extOrdering.Count != 0) + { + ext = new X509Extensions(extOrdering, extensions); + } + + DerInteger derNonce = nonce == null + ? null + : new DerInteger(nonce); + + return new TimeStampRequest( + new TimeStampReq(messageImprint, reqPolicy, derNonce, certReq, ext)); + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampResponse.cs b/iTechSharp/srcbc/tsp/TimeStampResponse.cs new file mode 100644 index 0000000..fca71f7 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampResponse.cs @@ -0,0 +1,173 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Tsp +{ + /** + * Base class for an RFC 3161 Time Stamp Response object. + */ + public class TimeStampResponse + { + private TimeStampResp resp; + private TimeStampToken timeStampToken; + + public TimeStampResponse( + TimeStampResp resp) + { + this.resp = resp; + + if (resp.TimeStampToken != null) + { + timeStampToken = new TimeStampToken(resp.TimeStampToken); + } + } + + /** + * Create a TimeStampResponse from a byte array containing an ASN.1 encoding. + * + * @param resp the byte array containing the encoded response. + * @throws TspException if the response is malformed. + * @throws IOException if the byte array doesn't represent an ASN.1 encoding. + */ + public TimeStampResponse( + byte[] resp) + : this(readTimeStampResp(new Asn1InputStream(resp))) + { + } + + /** + * Create a TimeStampResponse from an input stream containing an ASN.1 encoding. + * + * @param input the input stream containing the encoded response. + * @throws TspException if the response is malformed. + * @throws IOException if the stream doesn't represent an ASN.1 encoding. + */ + public TimeStampResponse( + Stream input) + : this(readTimeStampResp(new Asn1InputStream(input))) + { + } + + private static TimeStampResp readTimeStampResp( + Asn1InputStream input) + { + try + { + return TimeStampResp.GetInstance(input.ReadObject()); + } + catch (ArgumentException e) + { + throw new TspException("malformed timestamp response: " + e, e); + } + catch (InvalidCastException e) + { + throw new TspException("malformed timestamp response: " + e, e); + } + } + + public int Status + { + get { return resp.Status.Status.IntValue; } + } + + public string GetStatusString() + { + if (resp.Status.StatusString == null) + { + return null; + } + + StringBuilder statusStringBuf = new StringBuilder(); + PkiFreeText text = resp.Status.StatusString; + for (int i = 0; i != text.Count; i++) + { + statusStringBuf.Append(text[i].GetString()); + } + + return statusStringBuf.ToString(); + } + + public PkiFailureInfo GetFailInfo() + { + if (resp.Status.FailInfo == null) + { + return null; + } + + return new PkiFailureInfo(resp.Status.FailInfo); + } + + public TimeStampToken TimeStampToken + { + get { return timeStampToken; } + } + + /** + * Check this response against to see if it a well formed response for + * the passed in request. Validation will include checking the time stamp + * token if the response status is GRANTED or GRANTED_WITH_MODS. + * + * @param request the request to be checked against + * @throws TspException if the request can not match this response. + */ + public void Validate( + TimeStampRequest request) + { + TimeStampToken tok = this.TimeStampToken; + + if (tok != null) + { + TimeStampTokenInfo tstInfo = tok.TimeStampInfo; + + if (request.Nonce != null && !request.Nonce.Equals(tstInfo.Nonce)) + { + throw new TspValidationException("response contains wrong nonce value."); + } + + if (this.Status != (int) PkiStatus.Granted && this.Status != (int) PkiStatus.GrantedWithMods) + { + throw new TspValidationException("time stamp token found in failed request."); + } + + if (!Arrays.AreEqual(request.GetMessageImprintDigest(), tstInfo.GetMessageImprintDigest())) + { + throw new TspValidationException("response for different message imprint digest."); + } + + if (!tstInfo.MessageImprintAlgOid.Equals(request.MessageImprintAlgOid)) + { + throw new TspValidationException("response for different message imprint algorithm."); + } + + if (tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate] == null) + { + throw new TspValidationException("no signing certificate attribute present."); + } + + if (request.ReqPolicy != null && !request.ReqPolicy.Equals(tstInfo.Policy)) + { + throw new TspValidationException("TSA policy wrong for request."); + } + } + else if (this.Status == (int) PkiStatus.Granted || this.Status == (int) PkiStatus.GrantedWithMods) + { + throw new TspValidationException("no time stamp token found and one expected."); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] GetEncoded() + { + return resp.GetEncoded(); + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampResponseGenerator.cs b/iTechSharp/srcbc/tsp/TimeStampResponseGenerator.cs new file mode 100644 index 0000000..0ae3b30 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampResponseGenerator.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Tsp +{ + /** + * Generator for RFC 3161 Time Stamp Responses. + */ + public class TimeStampResponseGenerator + { + private PkiStatus status; + + private Asn1EncodableVector statusStrings; + + private int failInfo; + private TimeStampTokenGenerator tokenGenerator; + private IList acceptedAlgorithms; + private IList acceptedPolicies; + private IList acceptedExtensions; + + public TimeStampResponseGenerator( + TimeStampTokenGenerator tokenGenerator, + IList acceptedAlgorithms) + : this(tokenGenerator, acceptedAlgorithms, null, null) + { + } + + public TimeStampResponseGenerator( + TimeStampTokenGenerator tokenGenerator, + IList acceptedAlgorithms, + IList acceptedPolicy) + : this(tokenGenerator, acceptedAlgorithms, acceptedPolicy, null) + { + } + + public TimeStampResponseGenerator( + TimeStampTokenGenerator tokenGenerator, + IList acceptedAlgorithms, + IList acceptedPolicies, + IList acceptedExtensions) + { + this.tokenGenerator = tokenGenerator; + this.acceptedAlgorithms = acceptedAlgorithms; + this.acceptedPolicies = acceptedPolicies; + this.acceptedExtensions = acceptedExtensions; + + statusStrings = new Asn1EncodableVector(); + } + + private void addStatusString( + string statusString) + { + statusStrings.Add(new DerUtf8String(statusString)); + } + + private void setFailInfoField(int field) + { + failInfo = failInfo | field; + } + + private PkiStatusInfo getPkiStatusInfo() + { + Asn1EncodableVector v = new Asn1EncodableVector( + new DerInteger((int) status)); + + if (statusStrings.Count > 0) + { + v.Add(new PkiFreeText(new DerSequence(statusStrings))); + } + + if (failInfo != 0) + { + v.Add(new FailInfo(failInfo)); + } + + return new PkiStatusInfo(new DerSequence(v)); + } + + public TimeStampResponse Generate( + TimeStampRequest request, + BigInteger serialNumber, + DateTime genTime) + { + TimeStampResp resp; + + try + { + request.Validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions); + + status = PkiStatus.Granted; + this.addStatusString("Operation Okay"); + + PkiStatusInfo pkiStatusInfo = getPkiStatusInfo(); + + ContentInfo tstTokenContentInfo; + try + { + TimeStampToken token = tokenGenerator.Generate(request, serialNumber, genTime); + byte[] encoded = token.ToCmsSignedData().GetEncoded(); + + tstTokenContentInfo = ContentInfo.GetInstance(Asn1Object.FromByteArray(encoded)); + } + catch (IOException ioEx) + { + throw new TspException( + "Timestamp token received cannot be converted to ContentInfo", ioEx); + } + + resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo); + } + catch (TspValidationException e) + { + status = PkiStatus.Rejection; + + this.setFailInfoField(e.FailureCode); + this.addStatusString(e.Message); + + PkiStatusInfo pkiStatusInfo = getPkiStatusInfo(); + + resp = new TimeStampResp(pkiStatusInfo, null); + } + + try + { + return new TimeStampResponse(resp); + } + catch (IOException) + { + throw new TspException("created badly formatted response!"); + } + } + + class FailInfo + : DerBitString + { + internal FailInfo( + int failInfoValue) + : base(GetBytes(failInfoValue), GetPadBits(failInfoValue)) + { + } + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampToken.cs b/iTechSharp/srcbc/tsp/TimeStampToken.cs new file mode 100644 index 0000000..17b5853 --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampToken.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ess; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Tsp +{ + public class TimeStampToken + { + private readonly CmsSignedData tsToken; + private readonly SignerInformation tsaSignerInfo; +// private readonly DateTime genTime; + private readonly TimeStampTokenInfo tstInfo; + private readonly CertID certID; + + public TimeStampToken( + Asn1.Cms.ContentInfo contentInfo) + : this(new CmsSignedData(contentInfo)) + { + } + + public TimeStampToken( + CmsSignedData signedData) + { + this.tsToken = signedData; + + if (!this.tsToken.SignedContentTypeOid.Equals(PkcsObjectIdentifiers.IdCTTstInfo.Id)) + { + throw new TspValidationException("ContentInfo object not for a time stamp."); + } + + ICollection signers = tsToken.GetSignerInfos().GetSigners(); + + if (signers.Count != 1) + { + throw new ArgumentException("Time-stamp token signed by " + + signers.Count + + " signers, but it must contain just the TSA signature."); + } + + + IEnumerator signerEnum = signers.GetEnumerator(); + + signerEnum.MoveNext(); + tsaSignerInfo = (SignerInformation) signerEnum.Current; + + try + { + CmsProcessable content = tsToken.SignedContent; + MemoryStream bOut = new MemoryStream(); + + content.Write(bOut); + + this.tstInfo = new TimeStampTokenInfo( + TstInfo.GetInstance( + Asn1Object.FromByteArray(bOut.ToArray()))); + + Asn1.Cms.Attribute attr = tsaSignerInfo.SignedAttributes[ + PkcsObjectIdentifiers.IdAASigningCertificate]; + +// if (attr == null) +// { +// throw new TspValidationException( +// "no signing certificate attribute found, time stamp invalid."); +// } +// +// SigningCertificate signCert = SigningCertificate.GetInstance( +// attr.AttrValues[0]); +// +// this.certID = EssCertID.GetInstance(signCert.GetCerts()[0]); + + if (attr != null) + { + SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]); + + this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0])); + } + else + { + attr = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2]; + + if (attr == null) + throw new TspValidationException("no signing certificate attribute found, time stamp invalid."); + + SigningCertificateV2 signCertV2 = SigningCertificateV2.GetInstance(attr.AttrValues[0]); + + this.certID = new CertID(EssCertIDv2.GetInstance(signCertV2.GetCerts()[0])); + } + } + catch (CmsException e) + { + throw new TspException(e.Message, e.InnerException); + } + } + + public TimeStampTokenInfo TimeStampInfo + { + get { return tstInfo; } + } + + public SignerID SignerID + { + get { return tsaSignerInfo.SignerID; } + } + + public Asn1.Cms.AttributeTable SignedAttributes + { + get { return tsaSignerInfo.SignedAttributes; } + } + + public Asn1.Cms.AttributeTable UnsignedAttributes + { + get { return tsaSignerInfo.UnsignedAttributes; } + } + +// public IX509Store GetCertificatesAndCrls( +// string type) +// { +// return tsToken.GetCertificatesAndCrls(type); +// } + + public IX509Store GetCertificates( + string type) + { + return tsToken.GetCertificates(type); + } + + public IX509Store GetCrls( + string type) + { + return tsToken.GetCrls(type); + } + + /** + * Validate the time stamp token. + *

      + * To be valid the token must be signed by the passed in certificate and + * the certificate must be the one referred to by the SigningCertificate + * attribute included in the hashed attributes of the token. The + * certificate must also have the ExtendedKeyUsageExtension with only + * KeyPurposeID.IdKPTimeStamping and have been valid at the time the + * timestamp was created. + *

      + *

      + * A successful call to validate means all the above are true. + *

      + */ + public void Validate( + X509Certificate cert) + { + IDigest digest; + try + { + digest = DigestUtilities.GetDigest(certID.GetHashAlgorithm()); + } + catch (SecurityUtilityException e) + { + throw new TspException("cannot find algorithm: " + e.Message, e); + } + + try + { + byte[] certEncoded = cert.GetEncoded(); + digest.BlockUpdate(certEncoded, 0, certEncoded.Length); + byte[] hash = DigestUtilities.DoFinal(digest); + + if (!Arrays.AreEqual(certID.GetCertHash(), hash)) + { + throw new TspValidationException("certificate hash does not match certID hash."); + } + + if (certID.IssuerSerial != null) + { + if (!certID.IssuerSerial.Serial.Value.Equals(cert.SerialNumber)) + { + throw new TspValidationException("certificate serial number does not match certID for signature."); + } + + GeneralName[] names = certID.IssuerSerial.Issuer.GetNames(); + X509Name principal = PrincipalUtilities.GetIssuerX509Principal(cert); + bool found = false; + + for (int i = 0; i != names.Length; i++) + { + if (names[i].TagNo == 4 + && X509Name.GetInstance(names[i].Name).Equivalent(principal)) + { + found = true; + break; + } + } + + if (!found) + { + throw new TspValidationException("certificate name does not match certID for signature. "); + } + } + + TspUtil.ValidateCertificate(cert); + + cert.CheckValidity(tstInfo.GenTime); + + if (!tsaSignerInfo.Verify(cert)) + { + throw new TspValidationException("signature not created by certificate."); + } + } + catch (CmsException e) + { + if (e.InnerException != null) + { + throw new TspException(e.Message, e.InnerException); + } + + throw new TspException("CMS exception: " + e, e); + } + catch (CertificateEncodingException e) + { + throw new TspException("problem processing certificate: " + e, e); + } + } + + /** + * Return the underlying CmsSignedData object. + * + * @return the underlying CMS structure. + */ + public CmsSignedData ToCmsSignedData() + { + return tsToken; + } + + /** + * Return a ASN.1 encoded byte stream representing the encoded object. + * + * @throws IOException if encoding fails. + */ + public byte[] GetEncoded() + { + return tsToken.GetEncoded(); + } + + + // perhaps this should be done using an interface on the ASN.1 classes... + private class CertID + { + private EssCertID certID; + private EssCertIDv2 certIDv2; + + internal CertID(EssCertID certID) + { + this.certID = certID; + this.certIDv2 = null; + } + + internal CertID(EssCertIDv2 certID) + { + this.certIDv2 = certID; + this.certID = null; + } + + public string GetHashAlgorithm() + { + if (certID != null) + return "SHA-1"; + + if (NistObjectIdentifiers.IdSha256.Equals(certIDv2.HashAlgorithm.ObjectID)) + return "SHA-256"; + + return certIDv2.HashAlgorithm.ObjectID.Id; + } + + public byte[] GetCertHash() + { + return certID != null + ? certID.GetCertHash() + : certIDv2.GetCertHash(); + } + + public IssuerSerial IssuerSerial + { + get + { + return certID != null + ? certID.IssuerSerial + : certIDv2.IssuerSerial; + } + } + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampTokenGenerator.cs b/iTechSharp/srcbc/tsp/TimeStampTokenGenerator.cs new file mode 100644 index 0000000..5b9572a --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampTokenGenerator.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Ess; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Tsp +{ + public class TimeStampTokenGenerator + { + private int accuracySeconds = -1; + private int accuracyMillis = -1; + private int accuracyMicros = -1; + private bool ordering = false; + private GeneralName tsa = null; + private string tsaPolicyOID; + + private AsymmetricKeyParameter key; + private X509Certificate cert; + private string digestOID; + private Asn1.Cms.AttributeTable signedAttr; + private Asn1.Cms.AttributeTable unsignedAttr; + private IX509Store x509Certs; + private IX509Store x509Crls; + + /** + * basic creation - only the default attributes will be included here. + */ + public TimeStampTokenGenerator( + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string tsaPolicyOID) + : this(key, cert, digestOID, tsaPolicyOID, null, null) + { + } + + /** + * create with a signer with extra signed/unsigned attributes. + */ + public TimeStampTokenGenerator( + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string tsaPolicyOID, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + this.key = key; + this.cert = cert; + this.digestOID = digestOID; + this.tsaPolicyOID = tsaPolicyOID; + this.unsignedAttr = unsignedAttr; + + TspUtil.ValidateCertificate(cert); + + // + // add the essCertid + // + Hashtable signedAttrs; + if (signedAttr != null) + { + signedAttrs = signedAttr.ToHashtable(); + } + else + { + signedAttrs = new Hashtable(); + } + + IDigest digest; + try + { + digest = DigestUtilities.GetDigest("SHA-1"); + } + catch (Exception e) + { + throw new TspException("Can't find a SHA-1 implementation.", e); + } + + try + { + byte[] certEncoded = cert.GetEncoded(); + digest.BlockUpdate(certEncoded, 0, certEncoded.Length); + byte[] hash = DigestUtilities.DoFinal(digest); + + EssCertID essCertid = new EssCertID(hash); + + Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute( + PkcsObjectIdentifiers.IdAASigningCertificate, + new DerSet(new SigningCertificate(essCertid))); + + signedAttrs[attr.AttrType] = attr; + } + catch (CertificateEncodingException e) + { + throw new TspException("Exception processing certificate.", e); + } + + this.signedAttr = new Asn1.Cms.AttributeTable(signedAttrs); + } + + public void SetCertificates( + IX509Store certificates) + { + this.x509Certs = certificates; + } + + public void SetCrls( + IX509Store crls) + { + this.x509Crls = crls; + } + + public void SetAccuracySeconds( + int accuracySeconds) + { + this.accuracySeconds = accuracySeconds; + } + + public void SetAccuracyMillis( + int accuracyMillis) + { + this.accuracyMillis = accuracyMillis; + } + + public void SetAccuracyMicros( + int accuracyMicros) + { + this.accuracyMicros = accuracyMicros; + } + + public void SetOrdering( + bool ordering) + { + this.ordering = ordering; + } + + public void SetTsa( + GeneralName tsa) + { + this.tsa = tsa; + } + + //------------------------------------------------------------------------------ + + public TimeStampToken Generate( + TimeStampRequest request, + BigInteger serialNumber, + DateTime genTime) + { + DerObjectIdentifier digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid); + + AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance); + MessageImprint messageImprint = new MessageImprint(algID, request.GetMessageImprintDigest()); + + Accuracy accuracy = null; + if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0) + { + DerInteger seconds = null; + if (accuracySeconds > 0) + { + seconds = new DerInteger(accuracySeconds); + } + + DerInteger millis = null; + if (accuracyMillis > 0) + { + millis = new DerInteger(accuracyMillis); + } + + DerInteger micros = null; + if (accuracyMicros > 0) + { + micros = new DerInteger(accuracyMicros); + } + + accuracy = new Accuracy(seconds, millis, micros); + } + + DerBoolean derOrdering = null; + if (ordering) + { + derOrdering = DerBoolean.GetInstance(ordering); + } + + DerInteger nonce = null; + if (request.Nonce != null) + { + nonce = new DerInteger(request.Nonce); + } + + DerObjectIdentifier tsaPolicy = new DerObjectIdentifier(tsaPolicyOID); + if (request.ReqPolicy != null) + { + tsaPolicy = new DerObjectIdentifier(request.ReqPolicy); + } + + TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint, + new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy, + derOrdering, nonce, tsa, request.Extensions); + + try + { + CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator(); + + byte[] derEncodedTstInfo = tstInfo.GetDerEncoded(); + + if (request.CertReq) + { + signedDataGenerator.AddCertificates(x509Certs); + } + + signedDataGenerator.AddCrls(x509Crls); + signedDataGenerator.AddSigner(key, cert, digestOID, signedAttr, unsignedAttr); + + CmsSignedData signedData = signedDataGenerator.Generate( + PkcsObjectIdentifiers.IdCTTstInfo.Id, + new CmsProcessableByteArray(derEncodedTstInfo), + true); + + return new TimeStampToken(signedData); + } + catch (CmsException cmsEx) + { + throw new TspException("Error generating time-stamp token", cmsEx); + } + catch (IOException e) + { + throw new TspException("Exception encoding info", e); + } + catch (X509StoreException e) + { + throw new TspException("Exception handling CertStore", e); + } +// catch (InvalidAlgorithmParameterException e) +// { +// throw new TspException("Exception handling CertStore CRLs", e); +// } + } + } +} diff --git a/iTechSharp/srcbc/tsp/TimeStampTokenInfo.cs b/iTechSharp/srcbc/tsp/TimeStampTokenInfo.cs new file mode 100644 index 0000000..06112de --- /dev/null +++ b/iTechSharp/srcbc/tsp/TimeStampTokenInfo.cs @@ -0,0 +1,102 @@ +using System; + +using Org.BouncyCastle.Asn1.Tsp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Tsp +{ + public class TimeStampTokenInfo + { + private TstInfo tstInfo; + private DateTime genTime; + + public TimeStampTokenInfo( + TstInfo tstInfo) + { + this.tstInfo = tstInfo; + + try + { + this.genTime = tstInfo.GenTime.ToDateTime(); + } + catch (Exception e) + { + throw new TspException("unable to parse genTime field: " + e.Message); + } + } + + public bool IsOrdered + { + get { return tstInfo.Ordering.IsTrue; } + } + + public Accuracy Accuracy + { + get { return tstInfo.Accuracy; } + } + + public DateTime GenTime + { + get { return genTime; } + } + + public GenTimeAccuracy GenTimeAccuracy + { + get + { + return this.Accuracy == null + ? null + : new GenTimeAccuracy(this.Accuracy); + } + } + + public string Policy + { + get { return tstInfo.Policy.Id; } + } + + public BigInteger SerialNumber + { + get { return tstInfo.SerialNumber.Value; } + } + + public GeneralName Tsa + { + get { return tstInfo.Tsa; } + } + + /** + * @return the nonce value, null if there isn't one. + */ + public BigInteger Nonce + { + get + { + return tstInfo.Nonce == null + ? null + : tstInfo.Nonce.Value; + } + } + + public string MessageImprintAlgOid + { + get { return tstInfo.MessageImprint.HashAlgorithm.ObjectID.Id; } + } + + public byte[] GetMessageImprintDigest() + { + return tstInfo.MessageImprint.GetHashedMessage(); + } + + public byte[] GetEncoded() + { + return tstInfo.GetEncoded(); + } + + public TstInfo TstInfo + { + get { return tstInfo; } + } + } +} diff --git a/iTechSharp/srcbc/util/Arrays.cs b/iTechSharp/srcbc/util/Arrays.cs new file mode 100644 index 0000000..ffad2de --- /dev/null +++ b/iTechSharp/srcbc/util/Arrays.cs @@ -0,0 +1,134 @@ +using System; +using System.Text; + +namespace Org.BouncyCastle.Utilities +{ + + /// General array utilities. + public sealed class Arrays + { + private Arrays() + { + } + + /// + /// Are two arrays equal. + /// + /// Left side. + /// Right side. + /// True if equal. + public static bool AreEqual( + byte[] a, + byte[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + [Obsolete("Use 'AreEqual' method instead")] + public static bool AreSame( + byte[] a, + byte[] b) + { + return AreEqual(a, b); + } + + public static bool AreEqual( + int[] a, + int[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + private static bool HaveSameContents( + byte[] a, + byte[] b) + { + if (a.Length != b.Length) + return false; + + for (int i = 0; i < a.Length; i++) + { + if (a[i] != b[i]) + return false; + } + + return true; + } + + private static bool HaveSameContents( + int[] a, + int[] b) + { + if (a.Length != b.Length) + return false; + + for (int i = 0; i < a.Length; i++) + { + if (a[i] != b[i]) + return false; + } + + return true; + } + + public static string ToString( + object[] a) + { + StringBuilder sb = new StringBuilder('['); + if (a.Length > 0) + { + sb.Append(a[0]); + for (int index = 1; index < a.Length; ++index) + { + sb.Append(", ").Append(a[index]); + } + } + sb.Append(']'); + return sb.ToString(); + } + + public static int GetHashCode( + byte[] data) + { + if (data == null) + { + return 0; + } + + int i = data.Length; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[i]; + } + + return hc; + } + + public static byte[] Clone( + byte[] data) + { + return data == null ? null : (byte[]) data.Clone(); + } + + public static int[] Clone( + int[] data) + { + return data == null ? null : (int[]) data.Clone(); + } + } +} diff --git a/iTechSharp/srcbc/util/BigIntegers.cs b/iTechSharp/srcbc/util/BigIntegers.cs new file mode 100644 index 0000000..f9b06fa --- /dev/null +++ b/iTechSharp/srcbc/util/BigIntegers.cs @@ -0,0 +1,28 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Utilities +{ + /** + * BigInteger utilities. + */ + public sealed class BigIntegers + { + private BigIntegers() + { + } + + /** + * Return the passed in value as an unsigned byte array. + * + * @param value value to be converted. + * @return a byte array without a leading zero byte if present in the signed encoding. + */ + public static byte[] AsUnsignedByteArray( + BigInteger n) + { + return n.ToByteArrayUnsigned(); + } + } +} diff --git a/iTechSharp/srcbc/util/Platform.cs b/iTechSharp/srcbc/util/Platform.cs new file mode 100644 index 0000000..c36bcfa --- /dev/null +++ b/iTechSharp/srcbc/util/Platform.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using System.Text; + +namespace Org.BouncyCastle.Utilities +{ + internal sealed class Platform + { + private Platform() + { + } + +#if NETCF_1_0 + internal static Exception CreateNotImplementedException( + string message) + { + return new Exception("Not implemented: " + message); + } + + internal static bool Equals( + object a, + object b) + { + return a == b || (a != null && b != null && a.Equals(b)); + } + + internal static string GetEnvironmentVariable( + string variable) + { + return null; + } + + private static string GetNewLine() + { + MemoryStream buf = new MemoryStream(); + StreamWriter w = new StreamWriter(buf, Encoding.ASCII); + w.WriteLine(); + w.Close(); + byte[] bs = buf.ToArray(); + return Encoding.ASCII.GetString(bs, 0, bs.Length); + } +#else + internal static Exception CreateNotImplementedException( + string message) + { + return new NotImplementedException(message); + } + + internal static string GetEnvironmentVariable( + string variable) + { + try + { + return Environment.GetEnvironmentVariable(variable); + } + catch (System.Security.SecurityException) + { + // We don't have the required permission to read this environment variable, + // which is fine, just act as if it's not set + return null; + } + } + + private static string GetNewLine() + { + return Environment.NewLine; + } +#endif + + internal static readonly string NewLine = GetNewLine(); + } +} diff --git a/iTechSharp/srcbc/util/Strings.cs b/iTechSharp/srcbc/util/Strings.cs new file mode 100644 index 0000000..1002f3c --- /dev/null +++ b/iTechSharp/srcbc/util/Strings.cs @@ -0,0 +1,34 @@ +using System; + +namespace Org.BouncyCastle.Utilities +{ + /// General string utilities. + public sealed class Strings + { + private Strings() + { + } + + public static string FromByteArray( + byte[] bs) + { + char[] cs = new char[bs.Length]; + for (int i = 0; i < cs.Length; ++i) + { + cs[i] = Convert.ToChar(bs[i]); + } + return new string(cs); + } + + public static byte[] ToByteArray( + string s) + { + byte[] bs = new byte[s.Length]; + for (int i = 0; i < bs.Length; ++i) + { + bs[i] = Convert.ToByte(s[i]); + } + return bs; + } + } +} diff --git a/iTechSharp/srcbc/util/bzip2/BZip2Constants.cs b/iTechSharp/srcbc/util/bzip2/BZip2Constants.cs new file mode 100644 index 0000000..09c2717 --- /dev/null +++ b/iTechSharp/srcbc/util/bzip2/BZip2Constants.cs @@ -0,0 +1,139 @@ +using System; + +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace Org.BouncyCastle.Apache.Bzip2 +{ + /** + * Base class for both the compress and decompress classes. + * Holds common arrays, and static data. + * + * @author
      Keiron Liddle + */ + public class BZip2Constants { + + public const int baseBlockSize = 100000; + public const int MAX_ALPHA_SIZE = 258; + public const int MAX_CODE_LEN = 23; + public const int RUNA = 0; + public const int RUNB = 1; + public const int N_GROUPS = 6; + public const int G_SIZE = 50; + public const int N_ITERS = 4; + public const int MAX_SELECTORS = (2 + (900000 / G_SIZE)); + public const int NUM_OVERSHOOT_BYTES = 20; + + public static int[] rNums = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 + }; + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/bzip2/CBZip2InputStream.cs b/iTechSharp/srcbc/util/bzip2/CBZip2InputStream.cs new file mode 100644 index 0000000..dcd5be8 --- /dev/null +++ b/iTechSharp/srcbc/util/bzip2/CBZip2InputStream.cs @@ -0,0 +1,954 @@ +using System; +using System.IO; +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2001-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace Org.BouncyCastle.Apache.Bzip2 +{ + /** + * An input stream that decompresses from the BZip2 format (with the file + * header chars) to be read as any other stream. + * + * @author Keiron Liddle + * + * NB: note this class has been modified to read the leading BZ from the + * start of the BZIP2 stream to make it compatible with other PGP programs. + */ + public class CBZip2InputStream : Stream + { + private static void Cadvise() { + //System.out.Println("CRC Error"); + //throw new CCoruptionError(); + } + + private static void BadBGLengths() { + Cadvise(); + } + + private static void BitStreamEOF() { + Cadvise(); + } + + private static void CompressedStreamEOF() { + Cadvise(); + } + + private void MakeMaps() { + int i; + nInUse = 0; + for (i = 0; i < 256; i++) { + if (inUse[i]) { + seqToUnseq[nInUse] = (char) i; + unseqToSeq[i] = (char) nInUse; + nInUse++; + } + } + } + + /* + index of the last char in the block, so + the block size == last + 1. + */ + private int last; + + /* + index in zptr[] of original string after sorting. + */ + private int origPtr; + + /* + always: in the range 0 .. 9. + The current block size is 100000 * this number. + */ + private int blockSize100k; + + private bool blockRandomised; + + private int bsBuff; + private int bsLive; + private CRC mCrc = new CRC(); + + private bool[] inUse = new bool[256]; + private int nInUse; + + private char[] seqToUnseq = new char[256]; + private char[] unseqToSeq = new char[256]; + + private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; + private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; + + private int[] tt; + private char[] ll8; + + /* + freq table collected to save a pass over the data + during decompression. + */ + private int[] unzftab = new int[256]; + + private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + private int[] minLens = new int[BZip2Constants.N_GROUPS]; + + private Stream bsStream; + + private bool streamEnd = false; + + private int currentChar = -1; + + private const int START_BLOCK_STATE = 1; + private const int RAND_PART_A_STATE = 2; + private const int RAND_PART_B_STATE = 3; + private const int RAND_PART_C_STATE = 4; + private const int NO_RAND_PART_A_STATE = 5; + private const int NO_RAND_PART_B_STATE = 6; + private const int NO_RAND_PART_C_STATE = 7; + + private int currentState = START_BLOCK_STATE; + + private int storedBlockCRC, storedCombinedCRC; + private int computedBlockCRC, computedCombinedCRC; + + int i2, count, chPrev, ch2; + int i, tPos; + int rNToGo = 0; + int rTPos = 0; + int j2; + char z; + + public CBZip2InputStream(Stream zStream) { + ll8 = null; + tt = null; + BsSetStream(zStream); + Initialize(); + InitBlock(); + SetupBlock(); + } + + internal static int[][] InitIntArray(int n1, int n2) { + int[][] a = new int[n1][]; + for (int k = 0; k < n1; ++k) { + a[k] = new int[n2]; + } + return a; + } + + internal static char[][] InitCharArray(int n1, int n2) { + char[][] a = new char[n1][]; + for (int k = 0; k < n1; ++k) { + a[k] = new char[n2]; + } + return a; + } + + public override int ReadByte() { + if (streamEnd) { + return -1; + } else { + int retChar = currentChar; + switch (currentState) { + case START_BLOCK_STATE: + break; + case RAND_PART_A_STATE: + break; + case RAND_PART_B_STATE: + SetupRandPartB(); + break; + case RAND_PART_C_STATE: + SetupRandPartC(); + break; + case NO_RAND_PART_A_STATE: + break; + case NO_RAND_PART_B_STATE: + SetupNoRandPartB(); + break; + case NO_RAND_PART_C_STATE: + SetupNoRandPartC(); + break; + default: + break; + } + return retChar; + } + } + + private void Initialize() { + char magic3, magic4; + magic3 = BsGetUChar(); + magic4 = BsGetUChar(); + if (magic3 != 'B' && magic4 != 'Z') + { + throw new IOException("Not a BZIP2 marked stream"); + } + magic3 = BsGetUChar(); + magic4 = BsGetUChar(); + if (magic3 != 'h' || magic4 < '1' || magic4 > '9') { + BsFinishedWithStream(); + streamEnd = true; + return; + } + + SetDecompressStructureSizes(magic4 - '0'); + computedCombinedCRC = 0; + } + + private void InitBlock() { + char magic1, magic2, magic3, magic4; + char magic5, magic6; + magic1 = BsGetUChar(); + magic2 = BsGetUChar(); + magic3 = BsGetUChar(); + magic4 = BsGetUChar(); + magic5 = BsGetUChar(); + magic6 = BsGetUChar(); + if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 + && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) { + Complete(); + return; + } + + if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 + || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) { + BadBlockHeader(); + streamEnd = true; + return; + } + + storedBlockCRC = BsGetInt32(); + + if (BsR(1) == 1) { + blockRandomised = true; + } else { + blockRandomised = false; + } + + // currBlockNo++; + GetAndMoveToFrontDecode(); + + mCrc.InitialiseCRC(); + currentState = START_BLOCK_STATE; + } + + private void EndBlock() { + computedBlockCRC = mCrc.GetFinalCRC(); + /* A bad CRC is considered a fatal error. */ + if (storedBlockCRC != computedBlockCRC) { + CrcError(); + } + + computedCombinedCRC = (computedCombinedCRC << 1) + | (int)(((uint)computedCombinedCRC) >> 31); + computedCombinedCRC ^= computedBlockCRC; + } + + private void Complete() { + storedCombinedCRC = BsGetInt32(); + if (storedCombinedCRC != computedCombinedCRC) { + CrcError(); + } + + BsFinishedWithStream(); + streamEnd = true; + } + + private static void BlockOverrun() { + Cadvise(); + } + + private static void BadBlockHeader() { + Cadvise(); + } + + private static void CrcError() { + Cadvise(); + } + + private void BsFinishedWithStream() { + try { + if (this.bsStream != null) { + this.bsStream.Close(); + this.bsStream = null; + } + } catch { + //ignore + } + } + + private void BsSetStream(Stream f) { + bsStream = f; + bsLive = 0; + bsBuff = 0; + } + + private int BsR(int n) { + int v; + while (bsLive < n) { + int zzi; + char thech = '\0'; + try { + thech = (char) bsStream.ReadByte(); + } catch (IOException) { + CompressedStreamEOF(); + } + if (thech == '\uffff') { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + + v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1); + bsLive -= n; + return v; + } + + private char BsGetUChar() { + return (char) BsR(8); + } + + private int BsGetint() { + int u = 0; + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + u = (u << 8) | BsR(8); + return u; + } + + private int BsGetIntVS(int numBits) { + return (int) BsR(numBits); + } + + private int BsGetInt32() { + return (int) BsGetint(); + } + + private void HbCreateDecodeTables(int[] limit, int[] basev, + int[] perm, char[] length, + int minLen, int maxLen, int alphaSize) { + int pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) { + for (j = 0; j < alphaSize; j++) { + if (length[j] == i) { + perm[pp] = j; + pp++; + } + } + } + + for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) { + basev[i] = 0; + } + for (i = 0; i < alphaSize; i++) { + basev[length[i] + 1]++; + } + + for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) { + basev[i] += basev[i - 1]; + } + + for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) { + limit[i] = 0; + } + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (basev[i + 1] - basev[i]); + limit[i] = vec - 1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) { + basev[i] = ((limit[i - 1] + 1) << 1) - basev[i]; + } + } + + private void RecvDecodingTables() { + char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int i, j, t, nGroups, nSelectors, alphaSize; + int minLen, maxLen; + bool[] inUse16 = new bool[16]; + + /* Receive the mapping table */ + for (i = 0; i < 16; i++) { + if (BsR(1) == 1) { + inUse16[i] = true; + } else { + inUse16[i] = false; + } + } + + for (i = 0; i < 256; i++) { + inUse[i] = false; + } + + for (i = 0; i < 16; i++) { + if (inUse16[i]) { + for (j = 0; j < 16; j++) { + if (BsR(1) == 1) { + inUse[i * 16 + j] = true; + } + } + } + } + + MakeMaps(); + alphaSize = nInUse + 2; + + /* Now the selectors */ + nGroups = BsR(3); + nSelectors = BsR(15); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (BsR(1) == 1) { + j++; + } + selectorMtf[i] = (char) j; + } + + /* Undo the MTF values for the selectors. */ + { + char[] pos = new char[BZip2Constants.N_GROUPS]; + char tmp, v; + for (v = '\0'; v < nGroups; v++) { + pos[v] = v; + } + + for (i = 0; i < nSelectors; i++) { + v = selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { + pos[v] = pos[v - 1]; + v--; + } + pos[0] = tmp; + selector[i] = tmp; + } + } + + /* Now the coding tables */ + for (t = 0; t < nGroups; t++) { + int curr = BsR(5); + for (i = 0; i < alphaSize; i++) { + while (BsR(1) == 1) { + if (BsR(1) == 0) { + curr++; + } else { + curr--; + } + } + len[t][i] = (char) curr; + } + } + + /* Create the Huffman decoding tables */ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (len[t][i] > maxLen) { + maxLen = len[t][i]; + } + if (len[t][i] < minLen) { + minLen = len[t][i]; + } + } + HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen, + maxLen, alphaSize); + minLens[t] = minLen; + } + } + + private void GetAndMoveToFrontDecode() { + char[] yy = new char[256]; + int i, j, nextSym, limitLast; + int EOB, groupNo, groupPos; + + limitLast = BZip2Constants.baseBlockSize * blockSize100k; + origPtr = BsGetIntVS(24); + + RecvDecodingTables(); + EOB = nInUse + 1; + groupNo = -1; + groupPos = 0; + + /* + Setting up the unzftab entries here is not strictly + necessary, but it does save having to do it later + in a separate pass, and so saves a block's worth of + cache misses. + */ + for (i = 0; i <= 255; i++) { + unzftab[i] = 0; + } + + for (i = 0; i <= 255; i++) { + yy[i] = (char) i; + } + + last = -1; + + { + int zt, zn, zvec, zj; + if (groupPos == 0) { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) { + zn++; + { + { + while (bsLive < 1) { + int zzi; + char thech = '\0'; + try { + thech = (char) bsStream.ReadByte(); + } catch (IOException) { + CompressedStreamEOF(); + } + if (thech == '\uffff') { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + + while (true) { + + if (nextSym == EOB) { + break; + } + + if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) { + char ch; + int s = -1; + int N = 1; + do { + if (nextSym == BZip2Constants.RUNA) { + s = s + (0 + 1) * N; + } else if (nextSym == BZip2Constants.RUNB) { + s = s + (1 + 1) * N; + } + N = N * 2; + { + int zt, zn, zvec, zj; + if (groupPos == 0) { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) { + zn++; + { + { + while (bsLive < 1) { + int zzi; + char thech = '\0'; + try { + thech = (char) bsStream.ReadByte(); + } catch (IOException) { + CompressedStreamEOF(); + } + if (thech == '\uffff') { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB); + + s++; + ch = seqToUnseq[yy[0]]; + unzftab[ch] += s; + + while (s > 0) { + last++; + ll8[last] = ch; + s--; + } + + if (last >= limitLast) { + BlockOverrun(); + } + continue; + } else { + char tmp; + last++; + if (last >= limitLast) { + BlockOverrun(); + } + + tmp = yy[nextSym - 1]; + unzftab[seqToUnseq[tmp]]++; + ll8[last] = seqToUnseq[tmp]; + + /* + This loop is hammered during decompression, + hence the unrolling. + + for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1]; + */ + + j = nextSym - 1; + for (; j > 3; j -= 4) { + yy[j] = yy[j - 1]; + yy[j - 1] = yy[j - 2]; + yy[j - 2] = yy[j - 3]; + yy[j - 3] = yy[j - 4]; + } + for (; j > 0; j--) { + yy[j] = yy[j - 1]; + } + + yy[0] = tmp; + { + int zt, zn, zvec, zj; + if (groupPos == 0) { + groupNo++; + groupPos = BZip2Constants.G_SIZE; + } + groupPos--; + zt = selector[groupNo]; + zn = minLens[zt]; + zvec = BsR(zn); + while (zvec > limit[zt][zn]) { + zn++; + { + { + while (bsLive < 1) { + int zzi; + char thech = '\0'; + try { + thech = (char) bsStream.ReadByte(); + } catch (IOException) { + CompressedStreamEOF(); + } + zzi = thech; + bsBuff = (bsBuff << 8) | (zzi & 0xff); + bsLive += 8; + } + } + zj = (bsBuff >> (bsLive - 1)) & 1; + bsLive--; + } + zvec = (zvec << 1) | zj; + } + nextSym = perm[zt][zvec - basev[zt][zn]]; + } + continue; + } + } + } + + private void SetupBlock() { + int[] cftab = new int[257]; + char ch; + + cftab[0] = 0; + for (i = 1; i <= 256; i++) { + cftab[i] = unzftab[i - 1]; + } + for (i = 1; i <= 256; i++) { + cftab[i] += cftab[i - 1]; + } + + for (i = 0; i <= last; i++) { + ch = (char) ll8[i]; + tt[cftab[ch]] = i; + cftab[ch]++; + } + cftab = null; + + tPos = tt[origPtr]; + + count = 0; + i2 = 0; + ch2 = 256; /* not a char and not EOF */ + + if (blockRandomised) { + rNToGo = 0; + rTPos = 0; + SetupRandPartA(); + } else { + SetupNoRandPartA(); + } + } + + private void SetupRandPartA() { + if (i2 <= last) { + chPrev = ch2; + ch2 = ll8[tPos]; + tPos = tt[tPos]; + if (rNToGo == 0) { + rNToGo = BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) { + rTPos = 0; + } + } + rNToGo--; + ch2 ^= (int) ((rNToGo == 1) ? 1 : 0); + i2++; + + currentChar = ch2; + currentState = RAND_PART_B_STATE; + mCrc.UpdateCRC(ch2); + } else { + EndBlock(); + InitBlock(); + SetupBlock(); + } + } + + private void SetupNoRandPartA() { + if (i2 <= last) { + chPrev = ch2; + ch2 = ll8[tPos]; + tPos = tt[tPos]; + i2++; + + currentChar = ch2; + currentState = NO_RAND_PART_B_STATE; + mCrc.UpdateCRC(ch2); + } else { + EndBlock(); + InitBlock(); + SetupBlock(); + } + } + + private void SetupRandPartB() { + if (ch2 != chPrev) { + currentState = RAND_PART_A_STATE; + count = 1; + SetupRandPartA(); + } else { + count++; + if (count >= 4) { + z = ll8[tPos]; + tPos = tt[tPos]; + if (rNToGo == 0) { + rNToGo = BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) { + rTPos = 0; + } + } + rNToGo--; + z ^= (char)((rNToGo == 1) ? 1 : 0); + j2 = 0; + currentState = RAND_PART_C_STATE; + SetupRandPartC(); + } else { + currentState = RAND_PART_A_STATE; + SetupRandPartA(); + } + } + } + + private void SetupRandPartC() { + if (j2 < (int) z) { + currentChar = ch2; + mCrc.UpdateCRC(ch2); + j2++; + } else { + currentState = RAND_PART_A_STATE; + i2++; + count = 0; + SetupRandPartA(); + } + } + + private void SetupNoRandPartB() { + if (ch2 != chPrev) { + currentState = NO_RAND_PART_A_STATE; + count = 1; + SetupNoRandPartA(); + } else { + count++; + if (count >= 4) { + z = ll8[tPos]; + tPos = tt[tPos]; + currentState = NO_RAND_PART_C_STATE; + j2 = 0; + SetupNoRandPartC(); + } else { + currentState = NO_RAND_PART_A_STATE; + SetupNoRandPartA(); + } + } + } + + private void SetupNoRandPartC() { + if (j2 < (int) z) { + currentChar = ch2; + mCrc.UpdateCRC(ch2); + j2++; + } else { + currentState = NO_RAND_PART_A_STATE; + i2++; + count = 0; + SetupNoRandPartA(); + } + } + + private void SetDecompressStructureSizes(int newSize100k) { + if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k + && blockSize100k <= 9)) { + // throw new IOException("Invalid block size"); + } + + blockSize100k = newSize100k; + + if (newSize100k == 0) { + return; + } + + int n = BZip2Constants.baseBlockSize * newSize100k; + ll8 = new char[n]; + tt = new int[n]; + } + + public override void Flush() { + } + + public override int Read(byte[] buffer, int offset, int count) { + int c = -1; + int k; + for (k = 0; k < count; ++k) { + c = ReadByte(); + if (c == -1) + break; + buffer[k + offset] = (byte)c; + } + return k; + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + } + + public override bool CanRead { + get { + return true; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return false; + } + } + + public override long Length { + get { + return 0; + } + } + + public override long Position { + get { + return 0; + } + set { + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/bzip2/CBZip2OutputStream.cs b/iTechSharp/srcbc/util/bzip2/CBZip2OutputStream.cs new file mode 100644 index 0000000..c949143 --- /dev/null +++ b/iTechSharp/srcbc/util/bzip2/CBZip2OutputStream.cs @@ -0,0 +1,1731 @@ +using System; +using System.IO; +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2001-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +/* + * This package is based on the work done by Keiron Liddle, Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace Org.BouncyCastle.Apache.Bzip2 +{ + /** + * An output stream that compresses into the BZip2 format (with the file + * header chars) into another stream. + * + * @author Keiron Liddle + * + * TODO: Update to BZip2 1.0.1 + * NB: note this class has been modified to add a leading BZ to the + * start of the BZIP2 stream to make it compatible with other PGP programs. + */ + public class CBZip2OutputStream : Stream + { + protected const int SETMASK = (1 << 21); + protected const int CLEARMASK = (~SETMASK); + protected const int GREATER_ICOST = 15; + protected const int LESSER_ICOST = 0; + protected const int SMALL_THRESH = 20; + protected const int DEPTH_THRESH = 10; + + /* + If you are ever unlucky/improbable enough + to get a stack overflow whilst sorting, + increase the following constant and try + again. In practice I have never seen the + stack go above 27 elems, so the following + limit seems very generous. + */ + protected const int QSORT_STACK_SIZE = 1000; + private bool finished; + + private static void Panic() { + //System.out.Println("panic"); + //throw new CError(); + } + + private void MakeMaps() { + int i; + nInUse = 0; + for (i = 0; i < 256; i++) { + if (inUse[i]) { + seqToUnseq[nInUse] = (char) i; + unseqToSeq[i] = (char) nInUse; + nInUse++; + } + } + } + + protected static void HbMakeCodeLengths(char[] len, int[] freq, + int alphaSize, int maxLen) { + /* + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + */ + int nNodes, nHeap, n1, n2, i, j, k; + bool tooLong; + + int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2]; + int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2]; + int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2]; + + for (i = 0; i < alphaSize; i++) { + weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + } + + while (true) { + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + { + int zz, tmp; + zz = nHeap; + tmp = heap[zz]; + while (weight[tmp] < weight[heap[zz >> 1]]) { + heap[zz] = heap[zz >> 1]; + zz >>= 1; + } + heap[zz] = tmp; + } + } + if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) { + Panic(); + } + + while (nHeap > 1) { + n1 = heap[1]; + heap[1] = heap[nHeap]; + nHeap--; + { + int zz = 0, yy = 0, tmp = 0; + zz = 1; + tmp = heap[zz]; + while (true) { + yy = zz << 1; + if (yy > nHeap) { + break; + } + if (yy < nHeap + && weight[heap[yy + 1]] < weight[heap[yy]]) { + yy++; + } + if (weight[tmp] < weight[heap[yy]]) { + break; + } + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; + } + n2 = heap[1]; + heap[1] = heap[nHeap]; + nHeap--; + { + int zz = 0, yy = 0, tmp = 0; + zz = 1; + tmp = heap[zz]; + while (true) { + yy = zz << 1; + if (yy > nHeap) { + break; + } + if (yy < nHeap + && weight[heap[yy + 1]] < weight[heap[yy]]) { + yy++; + } + if (weight[tmp] < weight[heap[yy]]) { + break; + } + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; + } + nNodes++; + parent[n1] = parent[n2] = nNodes; + + weight[nNodes] = (int)((uint)((weight[n1] & 0xffffff00) + + (weight[n2] & 0xffffff00)) + | (uint)(1 + (((weight[n1] & 0x000000ff) > + (weight[n2] & 0x000000ff)) ? + (weight[n1] & 0x000000ff) : + (weight[n2] & 0x000000ff)))); + + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + { + int zz = 0, tmp = 0; + zz = nHeap; + tmp = heap[zz]; + while (weight[tmp] < weight[heap[zz >> 1]]) { + heap[zz] = heap[zz >> 1]; + zz >>= 1; + } + heap[zz] = tmp; + } + } + if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) { + Panic(); + } + + tooLong = false; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { + k = parent[k]; + j++; + } + len[i - 1] = (char) j; + if (j > maxLen) { + tooLong = true; + } + } + + if (!tooLong) { + break; + } + + for (i = 1; i < alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } + } + + /* + index of the last char in the block, so + the block size == last + 1. + */ + int last; + + /* + index in zptr[] of original string after sorting. + */ + int origPtr; + + /* + always: in the range 0 .. 9. + The current block size is 100000 * this number. + */ + int blockSize100k; + + bool blockRandomised; + + int bytesOut; + int bsBuff; + int bsLive; + CRC mCrc = new CRC(); + + private bool[] inUse = new bool[256]; + private int nInUse; + + private char[] seqToUnseq = new char[256]; + private char[] unseqToSeq = new char[256]; + + private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; + private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; + + private char[] block; + private int[] quadrant; + private int[] zptr; + private short[] szptr; + private int[] ftab; + + private int nMTF; + + private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE]; + + /* + * Used when sorting. If too many long comparisons + * happen, we stop sorting, randomise the block + * slightly, and try again. + */ + private int workFactor; + private int workDone; + private int workLimit; + private bool firstAttempt; + private int nBlocksRandomised; + + private int currentChar = -1; + private int runLength = 0; + + public CBZip2OutputStream(Stream inStream) : this(inStream, 9) { + } + + public CBZip2OutputStream(Stream inStream, int inBlockSize) + { + block = null; + quadrant = null; + zptr = null; + ftab = null; + + inStream.WriteByte((byte)'B'); + inStream.WriteByte((byte)'Z'); + + BsSetStream(inStream); + + workFactor = 50; + if (inBlockSize > 9) { + inBlockSize = 9; + } + if (inBlockSize < 1) { + inBlockSize = 1; + } + blockSize100k = inBlockSize; + AllocateCompressStructures(); + Initialize(); + InitBlock(); + } + + /** + * + * modified by Oliver Merkel, 010128 + * + */ + public override void WriteByte(byte bv) { + int b = (256 + bv) % 256; + if (currentChar != -1) { + if (currentChar == b) { + runLength++; + if (runLength > 254) { + WriteRun(); + currentChar = -1; + runLength = 0; + } + } else { + WriteRun(); + runLength = 1; + currentChar = b; + } + } else { + currentChar = b; + runLength++; + } + } + + private void WriteRun() { + if (last < allowableBlockSize) { + inUse[currentChar] = true; + for (int i = 0; i < runLength; i++) { + mCrc.UpdateCRC((char) currentChar); + } + switch (runLength) { + case 1: + last++; + block[last + 1] = (char) currentChar; + break; + case 2: + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + break; + case 3: + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + break; + default: + inUse[runLength - 4] = true; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) currentChar; + last++; + block[last + 1] = (char) (runLength - 4); + break; + } + } else { + EndBlock(); + InitBlock(); + WriteRun(); + } + } + + bool closed = false; + + protected void Finalize() { + Close(); + } + + public override void Close() { + if (closed) { + return; + } + + Finish(); + + closed = true; + base.Close(); + bsStream.Close(); + } + + public void Finish() { + if (finished) { + return; + } + + if (runLength > 0) { + WriteRun(); + } + currentChar = -1; + EndBlock(); + EndCompression(); + finished = true; + Flush(); + } + + public override void Flush() { + bsStream.Flush(); + } + + private int blockCRC, combinedCRC; + + private void Initialize() { + bytesOut = 0; + nBlocksRandomised = 0; + + /* Write `magic' bytes h indicating file-format == huffmanised, + followed by a digit indicating blockSize100k. + */ + BsPutUChar('h'); + BsPutUChar('0' + blockSize100k); + + combinedCRC = 0; + } + + private int allowableBlockSize; + + private void InitBlock() { + // blockNo++; + mCrc.InitialiseCRC(); + last = -1; + // ch = 0; + + for (int i = 0; i < 256; i++) { + inUse[i] = false; + } + + /* 20 is just a paranoia constant */ + allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20; + } + + private void EndBlock() { + blockCRC = mCrc.GetFinalCRC(); + combinedCRC = (combinedCRC << 1) | (int)(((uint)combinedCRC) >> 31); + combinedCRC ^= blockCRC; + + /* sort the block and establish posn of original string */ + DoReversibleTransformation(); + + /* + A 6-byte block header, the value chosen arbitrarily + as 0x314159265359 :-). A 32 bit value does not really + give a strong enough guarantee that the value will not + appear by chance in the compressed datastream. Worst-case + probability of this event, for a 900k block, is about + 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits. + For a compressed file of size 100Gb -- about 100000 blocks -- + only a 48-bit marker will do. NB: normal compression/ + decompression do *not* rely on these statistical properties. + They are only important when trying to recover blocks from + damaged files. + */ + BsPutUChar(0x31); + BsPutUChar(0x41); + BsPutUChar(0x59); + BsPutUChar(0x26); + BsPutUChar(0x53); + BsPutUChar(0x59); + + /* Now the block's CRC, so it is in a known place. */ + BsPutint(blockCRC); + + /* Now a single bit indicating randomisation. */ + if (blockRandomised) { + BsW(1, 1); + nBlocksRandomised++; + } else { + BsW(1, 0); + } + + /* Finally, block's contents proper. */ + MoveToFrontCodeAndSend(); + } + + private void EndCompression() { + /* + Now another magic 48-bit number, 0x177245385090, to + indicate the end of the last block. (Sqrt(pi), if + you want to know. I did want to use e, but it contains + too much repetition -- 27 18 28 18 28 46 -- for me + to feel statistically comfortable. Call me paranoid.) + */ + BsPutUChar(0x17); + BsPutUChar(0x72); + BsPutUChar(0x45); + BsPutUChar(0x38); + BsPutUChar(0x50); + BsPutUChar(0x90); + + BsPutint(combinedCRC); + + BsFinishedWithStream(); + } + + private void HbAssignCodes(int[] code, char[] length, int minLen, + int maxLen, int alphaSize) { + int n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) { + if (length[i] == n) { + code[i] = vec; + vec++; + } + }; + vec <<= 1; + } + } + + private void BsSetStream(Stream f) { + bsStream = f; + bsLive = 0; + bsBuff = 0; + bytesOut = 0; + } + + private void BsFinishedWithStream() { + while (bsLive > 0) { + int ch = (bsBuff >> 24); + try { + bsStream.WriteByte((byte)ch); // write 8-bit + } catch (IOException e) { + throw e; + } + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + } + + private void BsW(int n, int v) { + while (bsLive >= 8) { + int ch = (bsBuff >> 24); + try { + bsStream.WriteByte((byte)ch); // write 8-bit + } catch (IOException e) { + throw e; + } + bsBuff <<= 8; + bsLive -= 8; + bytesOut++; + } + bsBuff |= (v << (32 - bsLive - n)); + bsLive += n; + } + + private void BsPutUChar(int c) { + BsW(8, c); + } + + private void BsPutint(int u) { + BsW(8, (u >> 24) & 0xff); + BsW(8, (u >> 16) & 0xff); + BsW(8, (u >> 8) & 0xff); + BsW(8, u & 0xff); + } + + private void BsPutIntVS(int numBits, int c) { + BsW(numBits, c); + } + + private void SendMTFValues() { + char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + + int v, t, i, j, gs, ge, totc, bt, bc, iter; + int nSelectors = 0, alphaSize, minLen, maxLen, selCtr; + int nGroups, nBytes; + + alphaSize = nInUse + 2; + for (t = 0; t < BZip2Constants.N_GROUPS; t++) { + for (v = 0; v < alphaSize; v++) { + len[t][v] = (char) GREATER_ICOST; + } + } + + /* Decide how many coding tables to use */ + if (nMTF <= 0) { + Panic(); + } + + if (nMTF < 200) { + nGroups = 2; + } else if (nMTF < 600) { + nGroups = 3; + } else if (nMTF < 1200) { + nGroups = 4; + } else if (nMTF < 2400) { + nGroups = 5; + } else { + nGroups = 6; + } + + /* Generate an initial set of coding tables */ { + int nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs - 1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize - 1) { + ge++; + aFreq += mtfFreq[ge]; + } + + if (ge > gs && nPart != nGroups && nPart != 1 + && ((nGroups - nPart) % 2 == 1)) { + aFreq -= mtfFreq[ge]; + ge--; + } + + for (v = 0; v < alphaSize; v++) { + if (v >= gs && v <= ge) { + len[nPart - 1][v] = (char) LESSER_ICOST; + } else { + len[nPart - 1][v] = (char) GREATER_ICOST; + } + } + + nPart--; + gs = ge + 1; + remF -= aFreq; + } + } + + int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + int[] fave = new int[BZip2Constants.N_GROUPS]; + short[] cost = new short[BZip2Constants.N_GROUPS]; + /* + Iterate up to N_ITERS times to improve the tables. + */ + for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) { + for (t = 0; t < nGroups; t++) { + fave[t] = 0; + } + + for (t = 0; t < nGroups; t++) { + for (v = 0; v < alphaSize; v++) { + rfreq[t][v] = 0; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (true) { + + /* Set group start & end marks. */ + if (gs >= nMTF) { + break; + } + ge = gs + BZip2Constants.G_SIZE - 1; + if (ge >= nMTF) { + ge = nMTF - 1; + } + + /* + Calculate the cost of this group as coded + by each of the coding tables. + */ + for (t = 0; t < nGroups; t++) { + cost[t] = 0; + } + + if (nGroups == 6) { + short cost0, cost1, cost2, cost3, cost4, cost5; + cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0; + for (i = gs; i <= ge; i++) { + short icv = szptr[i]; + cost0 += (short)len[0][icv]; + cost1 += (short)len[1][icv]; + cost2 += (short)len[2][icv]; + cost3 += (short)len[3][icv]; + cost4 += (short)len[4][icv]; + cost5 += (short)len[5][icv]; + } + cost[0] = cost0; + cost[1] = cost1; + cost[2] = cost2; + cost[3] = cost3; + cost[4] = cost4; + cost[5] = cost5; + } else { + for (i = gs; i <= ge; i++) { + short icv = szptr[i]; + for (t = 0; t < nGroups; t++) { + cost[t] += (short)len[t][icv]; + } + } + } + + /* + Find the coding table which is best for this group, + and record its identity in the selector table. + */ + bc = 999999999; + bt = -1; + for (t = 0; t < nGroups; t++) { + if (cost[t] < bc) { + bc = cost[t]; + bt = t; + } + }; + totc += bc; + fave[bt]++; + selector[nSelectors] = (char) bt; + nSelectors++; + + /* + Increment the symbol frequencies for the selected table. + */ + for (i = gs; i <= ge; i++) { + rfreq[bt][szptr[i]]++; + } + + gs = ge + 1; + } + + /* + Recompute the tables based on the accumulated frequencies. + */ + for (t = 0; t < nGroups; t++) { + HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20); + } + } + + rfreq = null; + fave = null; + cost = null; + + if (!(nGroups < 8)) { + Panic(); + } + if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) { + Panic(); + } + + + /* Compute MTF values for the selectors. */ + { + char[] pos = new char[BZip2Constants.N_GROUPS]; + char ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) { + pos[i] = (char) i; + } + for (i = 0; i < nSelectors; i++) { + ll_i = selector[i]; + j = 0; + tmp = pos[j]; + while (ll_i != tmp) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + } + pos[0] = tmp; + selectorMtf[i] = (char) j; + } + } + + int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE); + + /* Assign actual codes for the tables. */ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (len[t][i] > maxLen) { + maxLen = len[t][i]; + } + if (len[t][i] < minLen) { + minLen = len[t][i]; + } + } + if (maxLen > 20) { + Panic(); + } + if (minLen < 1) { + Panic(); + } + HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize); + } + + /* Transmit the mapping table. */ + { + bool[] inUse16 = new bool[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = false; + for (j = 0; j < 16; j++) { + if (inUse[i * 16 + j]) { + inUse16[i] = true; + } + } + } + + nBytes = bytesOut; + for (i = 0; i < 16; i++) { + if (inUse16[i]) { + BsW(1, 1); + } else { + BsW(1, 0); + } + } + + for (i = 0; i < 16; i++) { + if (inUse16[i]) { + for (j = 0; j < 16; j++) { + if (inUse[i * 16 + j]) { + BsW(1, 1); + } else { + BsW(1, 0); + } + } + } + } + + } + + /* Now the selectors. */ + nBytes = bytesOut; + BsW(3, nGroups); + BsW(15, nSelectors); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < selectorMtf[i]; j++) { + BsW(1, 1); + } + BsW(1, 0); + } + + /* Now the coding tables. */ + nBytes = bytesOut; + + for (t = 0; t < nGroups; t++) { + int curr = len[t][0]; + BsW(5, curr); + for (i = 0; i < alphaSize; i++) { + while (curr < len[t][i]) { + BsW(2, 2); + curr++; /* 10 */ + } + while (curr > len[t][i]) { + BsW(2, 3); + curr--; /* 11 */ + } + BsW(1, 0); + } + } + + /* And finally, the block data proper */ + nBytes = bytesOut; + selCtr = 0; + gs = 0; + while (true) { + if (gs >= nMTF) { + break; + } + ge = gs + BZip2Constants.G_SIZE - 1; + if (ge >= nMTF) { + ge = nMTF - 1; + } + for (i = gs; i <= ge; i++) { + BsW(len[selector[selCtr]][szptr[i]], + code[selector[selCtr]][szptr[i]]); + } + + gs = ge + 1; + selCtr++; + } + if (!(selCtr == nSelectors)) { + Panic(); + } + } + + private void MoveToFrontCodeAndSend() { + BsPutIntVS(24, origPtr); + GenerateMTFValues(); + SendMTFValues(); + } + + private Stream bsStream; + + private void SimpleSort(int lo, int hi, int d) { + int i, j, h, bigN, hp; + int v; + + bigN = hi - lo + 1; + if (bigN < 2) { + return; + } + + hp = 0; + while (incs[hp] < bigN) { + hp++; + } + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (true) { + /* copy 1 */ + if (i > hi) { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) { + zptr[j] = zptr[j - h]; + j = j - h; + if (j <= (lo + h - 1)) { + break; + } + } + zptr[j] = v; + i++; + + /* copy 2 */ + if (i > hi) { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) { + zptr[j] = zptr[j - h]; + j = j - h; + if (j <= (lo + h - 1)) { + break; + } + } + zptr[j] = v; + i++; + + /* copy 3 */ + if (i > hi) { + break; + } + v = zptr[i]; + j = i; + while (FullGtU(zptr[j - h] + d, v + d)) { + zptr[j] = zptr[j - h]; + j = j - h; + if (j <= (lo + h - 1)) { + break; + } + } + zptr[j] = v; + i++; + + if (workDone > workLimit && firstAttempt) { + return; + } + } + } + } + + private void Vswap(int p1, int p2, int n) { + int temp = 0; + while (n > 0) { + temp = zptr[p1]; + zptr[p1] = zptr[p2]; + zptr[p2] = temp; + p1++; + p2++; + n--; + } + } + + private char Med3(char a, char b, char c) { + char t; + if (a > b) { + t = a; + a = b; + b = t; + } + if (b > c) { + t = b; + b = c; + c = t; + } + if (a > b) { + b = a; + } + return b; + } + + internal class StackElem { + internal int ll; + internal int hh; + internal int dd; + } + + private void QSort3(int loSt, int hiSt, int dSt) { + int unLo, unHi, ltLo, gtHi, med, n, m; + int sp, lo, hi, d; + StackElem[] stack = new StackElem[QSORT_STACK_SIZE]; + for (int count = 0; count < QSORT_STACK_SIZE; count++) { + stack[count] = new StackElem(); + } + + sp = 0; + + stack[sp].ll = loSt; + stack[sp].hh = hiSt; + stack[sp].dd = dSt; + sp++; + + while (sp > 0) { + if (sp >= QSORT_STACK_SIZE) { + Panic(); + } + + sp--; + lo = stack[sp].ll; + hi = stack[sp].hh; + d = stack[sp].dd; + + if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) { + SimpleSort(lo, hi, d); + if (workDone > workLimit && firstAttempt) { + return; + } + continue; + } + + med = Med3(block[zptr[lo] + d + 1], + block[zptr[hi ] + d + 1], + block[zptr[(lo + hi) >> 1] + d + 1]); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (true) { + while (true) { + if (unLo > unHi) { + break; + } + n = ((int) block[zptr[unLo] + d + 1]) - med; + if (n == 0) { + int temp = 0; + temp = zptr[unLo]; + zptr[unLo] = zptr[ltLo]; + zptr[ltLo] = temp; + ltLo++; + unLo++; + continue; + }; + if (n > 0) { + break; + } + unLo++; + } + while (true) { + if (unLo > unHi) { + break; + } + n = ((int) block[zptr[unHi] + d + 1]) - med; + if (n == 0) { + int temp = 0; + temp = zptr[unHi]; + zptr[unHi] = zptr[gtHi]; + zptr[gtHi] = temp; + gtHi--; + unHi--; + continue; + }; + if (n < 0) { + break; + } + unHi--; + } + if (unLo > unHi) { + break; + } + int tempx = zptr[unLo]; + zptr[unLo] = zptr[unHi]; + zptr[unHi] = tempx; + unLo++; + unHi--; + } + + if (gtHi < ltLo) { + stack[sp].ll = lo; + stack[sp].hh = hi; + stack[sp].dd = d + 1; + sp++; + continue; + } + + n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo); + Vswap(lo, unLo - n, n); + m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi); + Vswap(unLo, hi - m + 1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + stack[sp].ll = lo; + stack[sp].hh = n; + stack[sp].dd = d; + sp++; + + stack[sp].ll = n + 1; + stack[sp].hh = m - 1; + stack[sp].dd = d + 1; + sp++; + + stack[sp].ll = m; + stack[sp].hh = hi; + stack[sp].dd = d; + sp++; + } + } + + private void MainSort() { + int i, j, ss, sb; + int[] runningOrder = new int[256]; + int[] copy = new int[256]; + bool[] bigDone = new bool[256]; + int c1, c2; + int numQSorted; + + /* + In the various block-sized structures, live data runs + from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First, + set up the overshoot area for block. + */ + + // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" ); + for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { + block[last + i + 2] = block[(i % (last + 1)) + 1]; + } + for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { + quadrant[i] = 0; + } + + block[0] = (char) (block[last + 1]); + + if (last < 4000) { + /* + Use SimpleSort(), since the full sorting mechanism + has quite a large constant overhead. + */ + for (i = 0; i <= last; i++) { + zptr[i] = i; + } + firstAttempt = false; + workDone = workLimit = 0; + SimpleSort(0, last, 0); + } else { + numQSorted = 0; + for (i = 0; i <= 255; i++) { + bigDone[i] = false; + } + + for (i = 0; i <= 65536; i++) { + ftab[i] = 0; + } + + c1 = block[0]; + for (i = 0; i <= last; i++) { + c2 = block[i + 1]; + ftab[(c1 << 8) + c2]++; + c1 = c2; + } + + for (i = 1; i <= 65536; i++) { + ftab[i] += ftab[i - 1]; + } + + c1 = block[1]; + for (i = 0; i < last; i++) { + c2 = block[i + 2]; + j = (c1 << 8) + c2; + c1 = c2; + ftab[j]--; + zptr[ftab[j]] = i; + } + + j = ((block[last + 1]) << 8) + (block[1]); + ftab[j]--; + zptr[ftab[j]] = last; + + /* + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + */ + + for (i = 0; i <= 255; i++) { + runningOrder[i] = i; + } + + { + int vv; + int h = 1; + do { + h = 3 * h + 1; + } + while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ((ftab[((runningOrder[j - h]) + 1) << 8] + - ftab[(runningOrder[j - h]) << 8]) > + (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) { + runningOrder[j] = runningOrder[j - h]; + j = j - h; + if (j <= (h - 1)) { + break; + } + } + runningOrder[j] = vv; + } + } while (h != 1); + } + + /* + The main sorting loop. + */ + for (i = 0; i <= 255; i++) { + + /* + Process big buckets, starting with the least full. + */ + ss = runningOrder[i]; + + /* + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j]. Hopefully + previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + */ + for (j = 0; j <= 255; j++) { + sb = (ss << 8) + j; + if (!((ftab[sb] & SETMASK) == SETMASK)) { + int lo = ftab[sb] & CLEARMASK; + int hi = (ftab[sb + 1] & CLEARMASK) - 1; + if (hi > lo) { + QSort3(lo, hi, 2); + numQSorted += (hi - lo + 1); + if (workDone > workLimit && firstAttempt) { + return; + } + } + ftab[sb] |= SETMASK; + } + } + + /* + The ss big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + */ + bigDone[ss] = true; + + if (i < 255) { + int bbStart = ftab[ss << 8] & CLEARMASK; + int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart; + int shifts = 0; + + while ((bbSize >> shifts) > 65534) { + shifts++; + } + + for (j = 0; j < bbSize; j++) { + int a2update = zptr[bbStart + j]; + int qVal = (j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) { + quadrant[a2update + last + 1] = qVal; + } + } + + if (!(((bbSize - 1) >> shifts) <= 65535)) { + Panic(); + } + } + + /* + Now scan this big bucket so as to synthesise the + sorted order for small buckets [t, ss] for all t != ss. + */ + for (j = 0; j <= 255; j++) { + copy[j] = ftab[(j << 8) + ss] & CLEARMASK; + } + + for (j = ftab[ss << 8] & CLEARMASK; + j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) { + c1 = block[zptr[j]]; + if (!bigDone[c1]) { + zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1; + copy[c1]++; + } + } + + for (j = 0; j <= 255; j++) { + ftab[(j << 8) + ss] |= SETMASK; + } + } + } + } + + private void RandomiseBlock() { + int i; + int rNToGo = 0; + int rTPos = 0; + for (i = 0; i < 256; i++) { + inUse[i] = false; + } + + for (i = 0; i <= last; i++) { + if (rNToGo == 0) { + rNToGo = (char) BZip2Constants.rNums[rTPos]; + rTPos++; + if (rTPos == 512) { + rTPos = 0; + } + } + rNToGo--; + block[i + 1] ^= (char)((rNToGo == 1) ? 1 : 0); + // handle 16 bit signed numbers + block[i + 1] &= (char)0xFF; + + inUse[block[i + 1]] = true; + } + } + + private void DoReversibleTransformation() { + int i; + + workLimit = workFactor * last; + workDone = 0; + blockRandomised = false; + firstAttempt = true; + + MainSort(); + + if (workDone > workLimit && firstAttempt) { + RandomiseBlock(); + workLimit = workDone = 0; + blockRandomised = true; + firstAttempt = false; + MainSort(); + } + + origPtr = -1; + for (i = 0; i <= last; i++) { + if (zptr[i] == 0) { + origPtr = i; + break; + } + }; + + if (origPtr == -1) { + Panic(); + } + } + + private bool FullGtU(int i1, int i2) { + int k; + char c1, c2; + int s1, s2; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + i1++; + i2++; + + k = last + 1; + + do { + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) { + return (s1 > s2); + } + i1++; + i2++; + + c1 = block[i1 + 1]; + c2 = block[i2 + 1]; + if (c1 != c2) { + return (c1 > c2); + } + s1 = quadrant[i1]; + s2 = quadrant[i2]; + if (s1 != s2) { + return (s1 > s2); + } + i1++; + i2++; + + if (i1 > last) { + i1 -= last; + i1--; + }; + if (i2 > last) { + i2 -= last; + i2--; + }; + + k -= 4; + workDone++; + } while (k >= 0); + + return false; + } + + /* + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. + */ + private int[] incs = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + + private void AllocateCompressStructures() { + int n = BZip2Constants.baseBlockSize * blockSize100k; + block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)]; + quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)]; + zptr = new int[n]; + ftab = new int[65537]; + + if (block == null || quadrant == null || zptr == null + || ftab == null) { + //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537; + //compressOutOfMemory ( totalDraw, n ); + } + + /* + The back end needs a place to store the MTF values + whilst it calculates the coding tables. We could + put them in the zptr array. However, these values + will fit in a short, so we overlay szptr at the + start of zptr, in the hope of reducing the number + of cache misses induced by the multiple traversals + of the MTF values when calculating coding tables. + Seems to improve compression speed by about 1%. + */ + // szptr = zptr; + + + szptr = new short[2 * n]; + } + + private void GenerateMTFValues() { + char[] yy = new char[256]; + int i, j; + char tmp; + char tmp2; + int zPend; + int wr; + int EOB; + + MakeMaps(); + EOB = nInUse + 1; + + for (i = 0; i <= EOB; i++) { + mtfFreq[i] = 0; + } + + wr = 0; + zPend = 0; + for (i = 0; i < nInUse; i++) { + yy[i] = (char) i; + } + + + for (i = 0; i <= last; i++) { + char ll_i; + + ll_i = unseqToSeq[block[zptr[i]]]; + + j = 0; + tmp = yy[j]; + while (ll_i != tmp) { + j++; + tmp2 = tmp; + tmp = yy[j]; + yy[j] = tmp2; + }; + yy[0] = tmp; + + if (j == 0) { + zPend++; + } else { + if (zPend > 0) { + zPend--; + while (true) { + switch (zPend % 2) { + case 0: + szptr[wr] = (short) BZip2Constants.RUNA; + wr++; + mtfFreq[BZip2Constants.RUNA]++; + break; + case 1: + szptr[wr] = (short) BZip2Constants.RUNB; + wr++; + mtfFreq[BZip2Constants.RUNB]++; + break; + }; + if (zPend < 2) { + break; + } + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + szptr[wr] = (short) (j + 1); + wr++; + mtfFreq[j + 1]++; + } + } + + if (zPend > 0) { + zPend--; + while (true) { + switch (zPend % 2) { + case 0: + szptr[wr] = (short) BZip2Constants.RUNA; + wr++; + mtfFreq[BZip2Constants.RUNA]++; + break; + case 1: + szptr[wr] = (short) BZip2Constants.RUNB; + wr++; + mtfFreq[BZip2Constants.RUNB]++; + break; + } + if (zPend < 2) { + break; + } + zPend = (zPend - 2) / 2; + } + } + + szptr[wr] = (short) EOB; + wr++; + mtfFreq[EOB]++; + + nMTF = wr; + } + + public override int Read(byte[] buffer, int offset, int count) { + return 0; + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + for (int k = 0; k < count; ++k) { + WriteByte(buffer[k + offset]); + } + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + return 0; + } + } + + public override long Position { + get { + return 0; + } + set { + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/bzip2/CRC.cs b/iTechSharp/srcbc/util/bzip2/CRC.cs new file mode 100644 index 0000000..2f57b94 --- /dev/null +++ b/iTechSharp/srcbc/util/bzip2/CRC.cs @@ -0,0 +1,170 @@ +using System; + +/* + * The Apache Software License), Version 1.1 + * + * Copyright (c) 2001-2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms), with or without + * modification), are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice), this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution), if + * any), must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately), this acknowlegement may appear in the software itself), + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission), please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES), INCLUDING), BUT NOT LIMITED TO), THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT), INDIRECT), INCIDENTAL), + * SPECIAL), EXEMPLARY), OR CONSEQUENTIAL DAMAGES (INCLUDING), BUT NOT + * LIMITED TO), PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE), DATA), OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY), WHETHER IN CONTRACT), STRICT LIABILITY), + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE), EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation), please see + * . + */ + +/* + * This package is based on the work done by Keiron Liddle), Aftex Software + * to whom the Ant project is very grateful for his + * great code. + */ + +namespace Org.BouncyCastle.Apache.Bzip2 +{ + /** + * A simple class the hold and calculate the CRC for sanity checking + * of the data. + * + * @author Keiron Liddle + */ + internal class CRC + { + public static int[] crc32Table = { + unchecked((int)0x00000000), unchecked((int)0x04c11db7), unchecked((int)0x09823b6e), unchecked((int)0x0d4326d9), + unchecked((int)0x130476dc), unchecked((int)0x17c56b6b), unchecked((int)0x1a864db2), unchecked((int)0x1e475005), + unchecked((int)0x2608edb8), unchecked((int)0x22c9f00f), unchecked((int)0x2f8ad6d6), unchecked((int)0x2b4bcb61), + unchecked((int)0x350c9b64), unchecked((int)0x31cd86d3), unchecked((int)0x3c8ea00a), unchecked((int)0x384fbdbd), + unchecked((int)0x4c11db70), unchecked((int)0x48d0c6c7), unchecked((int)0x4593e01e), unchecked((int)0x4152fda9), + unchecked((int)0x5f15adac), unchecked((int)0x5bd4b01b), unchecked((int)0x569796c2), unchecked((int)0x52568b75), + unchecked((int)0x6a1936c8), unchecked((int)0x6ed82b7f), unchecked((int)0x639b0da6), unchecked((int)0x675a1011), + unchecked((int)0x791d4014), unchecked((int)0x7ddc5da3), unchecked((int)0x709f7b7a), unchecked((int)0x745e66cd), + unchecked((int)0x9823b6e0), unchecked((int)0x9ce2ab57), unchecked((int)0x91a18d8e), unchecked((int)0x95609039), + unchecked((int)0x8b27c03c), unchecked((int)0x8fe6dd8b), unchecked((int)0x82a5fb52), unchecked((int)0x8664e6e5), + unchecked((int)0xbe2b5b58), unchecked((int)0xbaea46ef), unchecked((int)0xb7a96036), unchecked((int)0xb3687d81), + unchecked((int)0xad2f2d84), unchecked((int)0xa9ee3033), unchecked((int)0xa4ad16ea), unchecked((int)0xa06c0b5d), + unchecked((int)0xd4326d90), unchecked((int)0xd0f37027), unchecked((int)0xddb056fe), unchecked((int)0xd9714b49), + unchecked((int)0xc7361b4c), unchecked((int)0xc3f706fb), unchecked((int)0xceb42022), unchecked((int)0xca753d95), + unchecked((int)0xf23a8028), unchecked((int)0xf6fb9d9f), unchecked((int)0xfbb8bb46), unchecked((int)0xff79a6f1), + unchecked((int)0xe13ef6f4), unchecked((int)0xe5ffeb43), unchecked((int)0xe8bccd9a), unchecked((int)0xec7dd02d), + unchecked((int)0x34867077), unchecked((int)0x30476dc0), unchecked((int)0x3d044b19), unchecked((int)0x39c556ae), + unchecked((int)0x278206ab), unchecked((int)0x23431b1c), unchecked((int)0x2e003dc5), unchecked((int)0x2ac12072), + unchecked((int)0x128e9dcf), unchecked((int)0x164f8078), unchecked((int)0x1b0ca6a1), unchecked((int)0x1fcdbb16), + unchecked((int)0x018aeb13), unchecked((int)0x054bf6a4), unchecked((int)0x0808d07d), unchecked((int)0x0cc9cdca), + unchecked((int)0x7897ab07), unchecked((int)0x7c56b6b0), unchecked((int)0x71159069), unchecked((int)0x75d48dde), + unchecked((int)0x6b93dddb), unchecked((int)0x6f52c06c), unchecked((int)0x6211e6b5), unchecked((int)0x66d0fb02), + unchecked((int)0x5e9f46bf), unchecked((int)0x5a5e5b08), unchecked((int)0x571d7dd1), unchecked((int)0x53dc6066), + unchecked((int)0x4d9b3063), unchecked((int)0x495a2dd4), unchecked((int)0x44190b0d), unchecked((int)0x40d816ba), + unchecked((int)0xaca5c697), unchecked((int)0xa864db20), unchecked((int)0xa527fdf9), unchecked((int)0xa1e6e04e), + unchecked((int)0xbfa1b04b), unchecked((int)0xbb60adfc), unchecked((int)0xb6238b25), unchecked((int)0xb2e29692), + unchecked((int)0x8aad2b2f), unchecked((int)0x8e6c3698), unchecked((int)0x832f1041), unchecked((int)0x87ee0df6), + unchecked((int)0x99a95df3), unchecked((int)0x9d684044), unchecked((int)0x902b669d), unchecked((int)0x94ea7b2a), + unchecked((int)0xe0b41de7), unchecked((int)0xe4750050), unchecked((int)0xe9362689), unchecked((int)0xedf73b3e), + unchecked((int)0xf3b06b3b), unchecked((int)0xf771768c), unchecked((int)0xfa325055), unchecked((int)0xfef34de2), + unchecked((int)0xc6bcf05f), unchecked((int)0xc27dede8), unchecked((int)0xcf3ecb31), unchecked((int)0xcbffd686), + unchecked((int)0xd5b88683), unchecked((int)0xd1799b34), unchecked((int)0xdc3abded), unchecked((int)0xd8fba05a), + unchecked((int)0x690ce0ee), unchecked((int)0x6dcdfd59), unchecked((int)0x608edb80), unchecked((int)0x644fc637), + unchecked((int)0x7a089632), unchecked((int)0x7ec98b85), unchecked((int)0x738aad5c), unchecked((int)0x774bb0eb), + unchecked((int)0x4f040d56), unchecked((int)0x4bc510e1), unchecked((int)0x46863638), unchecked((int)0x42472b8f), + unchecked((int)0x5c007b8a), unchecked((int)0x58c1663d), unchecked((int)0x558240e4), unchecked((int)0x51435d53), + unchecked((int)0x251d3b9e), unchecked((int)0x21dc2629), unchecked((int)0x2c9f00f0), unchecked((int)0x285e1d47), + unchecked((int)0x36194d42), unchecked((int)0x32d850f5), unchecked((int)0x3f9b762c), unchecked((int)0x3b5a6b9b), + unchecked((int)0x0315d626), unchecked((int)0x07d4cb91), unchecked((int)0x0a97ed48), unchecked((int)0x0e56f0ff), + unchecked((int)0x1011a0fa), unchecked((int)0x14d0bd4d), unchecked((int)0x19939b94), unchecked((int)0x1d528623), + unchecked((int)0xf12f560e), unchecked((int)0xf5ee4bb9), unchecked((int)0xf8ad6d60), unchecked((int)0xfc6c70d7), + unchecked((int)0xe22b20d2), unchecked((int)0xe6ea3d65), unchecked((int)0xeba91bbc), unchecked((int)0xef68060b), + unchecked((int)0xd727bbb6), unchecked((int)0xd3e6a601), unchecked((int)0xdea580d8), unchecked((int)0xda649d6f), + unchecked((int)0xc423cd6a), unchecked((int)0xc0e2d0dd), unchecked((int)0xcda1f604), unchecked((int)0xc960ebb3), + unchecked((int)0xbd3e8d7e), unchecked((int)0xb9ff90c9), unchecked((int)0xb4bcb610), unchecked((int)0xb07daba7), + unchecked((int)0xae3afba2), unchecked((int)0xaafbe615), unchecked((int)0xa7b8c0cc), unchecked((int)0xa379dd7b), + unchecked((int)0x9b3660c6), unchecked((int)0x9ff77d71), unchecked((int)0x92b45ba8), unchecked((int)0x9675461f), + unchecked((int)0x8832161a), unchecked((int)0x8cf30bad), unchecked((int)0x81b02d74), unchecked((int)0x857130c3), + unchecked((int)0x5d8a9099), unchecked((int)0x594b8d2e), unchecked((int)0x5408abf7), unchecked((int)0x50c9b640), + unchecked((int)0x4e8ee645), unchecked((int)0x4a4ffbf2), unchecked((int)0x470cdd2b), unchecked((int)0x43cdc09c), + unchecked((int)0x7b827d21), unchecked((int)0x7f436096), unchecked((int)0x7200464f), unchecked((int)0x76c15bf8), + unchecked((int)0x68860bfd), unchecked((int)0x6c47164a), unchecked((int)0x61043093), unchecked((int)0x65c52d24), + unchecked((int)0x119b4be9), unchecked((int)0x155a565e), unchecked((int)0x18197087), unchecked((int)0x1cd86d30), + unchecked((int)0x029f3d35), unchecked((int)0x065e2082), unchecked((int)0x0b1d065b), unchecked((int)0x0fdc1bec), + unchecked((int)0x3793a651), unchecked((int)0x3352bbe6), unchecked((int)0x3e119d3f), unchecked((int)0x3ad08088), + unchecked((int)0x2497d08d), unchecked((int)0x2056cd3a), unchecked((int)0x2d15ebe3), unchecked((int)0x29d4f654), + unchecked((int)0xc5a92679), unchecked((int)0xc1683bce), unchecked((int)0xcc2b1d17), unchecked((int)0xc8ea00a0), + unchecked((int)0xd6ad50a5), unchecked((int)0xd26c4d12), unchecked((int)0xdf2f6bcb), unchecked((int)0xdbee767c), + unchecked((int)0xe3a1cbc1), unchecked((int)0xe760d676), unchecked((int)0xea23f0af), unchecked((int)0xeee2ed18), + unchecked((int)0xf0a5bd1d), unchecked((int)0xf464a0aa), unchecked((int)0xf9278673), unchecked((int)0xfde69bc4), + unchecked((int)0x89b8fd09), unchecked((int)0x8d79e0be), unchecked((int)0x803ac667), unchecked((int)0x84fbdbd0), + unchecked((int)0x9abc8bd5), unchecked((int)0x9e7d9662), unchecked((int)0x933eb0bb), unchecked((int)0x97ffad0c), + unchecked((int)0xafb010b1), unchecked((int)0xab710d06), unchecked((int)0xa6322bdf), unchecked((int)0xa2f33668), + unchecked((int)0xbcb4666d), unchecked((int)0xb8757bda), unchecked((int)0xb5365d03), unchecked((int)0xb1f740b4) + }; + + public CRC() { + InitialiseCRC(); + } + + internal void InitialiseCRC() { + globalCrc = unchecked((int)0xffffffff); + } + + internal int GetFinalCRC() { + return ~globalCrc; + } + + internal int GetGlobalCRC() { + return globalCrc; + } + + internal void SetGlobalCRC(int newCrc) { + globalCrc = newCrc; + } + + internal void UpdateCRC(int inCh) { + int temp = (globalCrc >> 24) ^ inCh; + if (temp < 0) { + temp = 256 + temp; + } + globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp]; + } + + internal int globalCrc; + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/collections/CollectionUtilities.cs b/iTechSharp/srcbc/util/collections/CollectionUtilities.cs new file mode 100644 index 0000000..152277d --- /dev/null +++ b/iTechSharp/srcbc/util/collections/CollectionUtilities.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; +using System.Text; + +namespace Org.BouncyCastle.Utilities.Collections +{ + public sealed class CollectionUtilities + { + private CollectionUtilities() + { + } + + public static bool CheckElementsAreOfType( + IEnumerable e, + Type t) + { + foreach (object o in e) + { + if (!t.IsInstanceOfType(o)) + return false; + } + return true; + } + + public static string ToString( + IEnumerable c) + { + StringBuilder sb = new StringBuilder("["); + + IEnumerator e = c.GetEnumerator(); + + if (e.MoveNext()) + { + sb.Append(e.Current.ToString()); + + while (e.MoveNext()) + { + sb.Append(", "); + sb.Append(e.Current.ToString()); + } + } + + sb.Append(']'); + + return sb.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/util/collections/EmptyEnumerable.cs b/iTechSharp/srcbc/util/collections/EmptyEnumerable.cs new file mode 100644 index 0000000..a61a078 --- /dev/null +++ b/iTechSharp/srcbc/util/collections/EmptyEnumerable.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Utilities.Collections +{ + public sealed class EmptyEnumerable + : IEnumerable + { + public static readonly IEnumerable Instance = new EmptyEnumerable(); + + private EmptyEnumerable() + { + } + + public IEnumerator GetEnumerator() + { + return EmptyEnumerator.Instance; + } + } + + public sealed class EmptyEnumerator + : IEnumerator + { + public static readonly IEnumerator Instance = new EmptyEnumerator(); + + private EmptyEnumerator() + { + } + + public bool MoveNext() + { + return false; + } + + public void Reset() + { + } + + public object Current + { + get { throw new InvalidOperationException("No elements"); } + } + } +} diff --git a/iTechSharp/srcbc/util/collections/EnumerableProxy.cs b/iTechSharp/srcbc/util/collections/EnumerableProxy.cs new file mode 100644 index 0000000..9eec4af --- /dev/null +++ b/iTechSharp/srcbc/util/collections/EnumerableProxy.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Utilities.Collections +{ + public sealed class EnumerableProxy + : IEnumerable + { + private readonly IEnumerable inner; + + public EnumerableProxy( + IEnumerable inner) + { + if (inner == null) + throw new ArgumentNullException("inner"); + + this.inner = inner; + } + + public IEnumerator GetEnumerator() + { + return inner.GetEnumerator(); + } + } +} diff --git a/iTechSharp/srcbc/util/collections/HashSet.cs b/iTechSharp/srcbc/util/collections/HashSet.cs new file mode 100644 index 0000000..10dc3af --- /dev/null +++ b/iTechSharp/srcbc/util/collections/HashSet.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Utilities.Collections +{ + public class HashSet + : ISet + { + private readonly Hashtable impl = new Hashtable(); + + public HashSet() + { + } + + public HashSet(ISet s) + { + foreach (object o in s) + { + Add(o); + } + } + + public void Add(object o) + { + impl[o] = null; + } + + public bool Contains(object o) + { + return impl.ContainsKey(o); + } + + public void CopyTo(Array array, int index) + { + impl.Keys.CopyTo(array, index); + } + + public int Count + { + get { return impl.Count; } + } + + public IEnumerator GetEnumerator() + { + return impl.Keys.GetEnumerator(); + } + + public bool IsSynchronized + { + get { return impl.IsSynchronized; } + } + + public void Remove(object o) + { + impl.Remove(o); + } + + public object SyncRoot + { + get { return impl.SyncRoot; } + } + } +} diff --git a/iTechSharp/srcbc/util/collections/ISet.cs b/iTechSharp/srcbc/util/collections/ISet.cs new file mode 100644 index 0000000..5d15355 --- /dev/null +++ b/iTechSharp/srcbc/util/collections/ISet.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.Utilities.Collections +{ + public interface ISet + : ICollection + { + void Add(object o); + bool Contains(object o); + void Remove(object o); + } +} diff --git a/iTechSharp/srcbc/util/date/DateTimeObject.cs b/iTechSharp/srcbc/util/date/DateTimeObject.cs new file mode 100644 index 0000000..793376b --- /dev/null +++ b/iTechSharp/srcbc/util/date/DateTimeObject.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.Utilities.Date +{ + public sealed class DateTimeObject + { + private readonly DateTime dt; + + public DateTimeObject( + DateTime dt) + { + this.dt = dt; + } + + public DateTime Value + { + get { return dt; } + } + + public override string ToString() + { + return dt.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/util/date/DateTimeUtilities.cs b/iTechSharp/srcbc/util/date/DateTimeUtilities.cs new file mode 100644 index 0000000..311ad5d --- /dev/null +++ b/iTechSharp/srcbc/util/date/DateTimeUtilities.cs @@ -0,0 +1,47 @@ +using System; + +namespace Org.BouncyCastle.Utilities.Date +{ + public class DateTimeUtilities + { + public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1); + + private DateTimeUtilities() + { + } + + /// + /// Return the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC) for a given DateTime value. + /// + /// A UTC DateTime value not before epoch. + /// Number of whole milliseconds after epoch. + /// 'dateTime' is before epoch. + public static long DateTimeToUnixMs( + DateTime dateTime) + { + if (dateTime.CompareTo(UnixEpoch) < 0) + throw new ArgumentException("DateTime value may not be before the epoch", "dateTime"); + + return (dateTime.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond; + } + + /// + /// Create a DateTime value from the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC). + /// + /// Number of milliseconds since the epoch. + /// A UTC DateTime value + public static DateTime UnixMsToDateTime( + long unixMs) + { + return new DateTime(unixMs * TimeSpan.TicksPerMillisecond + UnixEpoch.Ticks); + } + + /// + /// Return the current number of milliseconds since the Unix epoch (1 Jan., 1970 UTC). + /// + public static long CurrentUnixMs() + { + return DateTimeToUnixMs(DateTime.UtcNow); + } + } +} diff --git a/iTechSharp/srcbc/util/encoders/Base64.cs b/iTechSharp/srcbc/util/encoders/Base64.cs new file mode 100644 index 0000000..bee2446 --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/Base64.cs @@ -0,0 +1,115 @@ +using System; +using System.IO; +using System.Text; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + public sealed class Base64 + { +// private static readonly IEncoder encoder = new Base64Encoder(); + + private Base64() + { + } + + /** + * encode the input data producing a base 64 encoded byte array. + * + * @return a byte array containing the base 64 encoded data. + */ + public static byte[] Encode( + byte[] data) + { + string s = Convert.ToBase64String(data, 0, data.Length); + return Encoding.ASCII.GetBytes(s); + +// MemoryStream bOut = new MemoryStream(); +// encoder.Encode(data, 0, data.Length, bOut); +// return bOut.ToArray(); + } + + /** + * Encode the byte data to base 64 writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + Stream outStream) + { + string s = Convert.ToBase64String(data, 0, data.Length); + byte[] encoded = Encoding.ASCII.GetBytes(s); + outStream.Write(encoded, 0, encoded.Length); + return encoded.Length; + +// return encoder.Encode(data, 0, data.Length, outStream); + } + + /** + * Encode the byte data to base 64 writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + int off, + int length, + Stream outStream) + { + string s = Convert.ToBase64String(data, off, length); + byte[] encoded = Encoding.ASCII.GetBytes(s); + outStream.Write(encoded, 0, encoded.Length); + return encoded.Length; + +// return encoder.Encode(data, off, length, outStream); + } + + /** + * decode the base 64 encoded input data. It is assumed the input data is valid. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + byte[] data) + { + string s = Encoding.ASCII.GetString(data, 0, data.Length); + return Convert.FromBase64String(s); + +// MemoryStream bOut = new MemoryStream(); +// encoder.Decode(data, 0, data.Length, bOut); +// return bOut.ToArray(); + } + + /** + * decode the base 64 encoded string data - whitespace will be ignored. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + string data) + { + return Convert.FromBase64String(data); + +// MemoryStream bOut = new MemoryStream(); +// encoder.DecodeString(data, bOut); +// return bOut.ToArray(); + } + + /** + * decode the base 64 encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public static int Decode( + string data, + Stream outStream) + { + byte[] decoded = Decode(data); + outStream.Write(decoded, 0, decoded.Length); + return decoded.Length; + +// return encoder.DecodeString(data, outStream); + } + } +} diff --git a/iTechSharp/srcbc/util/encoders/Base64Encoder.cs b/iTechSharp/srcbc/util/encoders/Base64Encoder.cs new file mode 100644 index 0000000..c94ce9d --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/Base64Encoder.cs @@ -0,0 +1,307 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + public class Base64Encoder + : IEncoder + { + protected readonly byte[] encodingTable = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', + (byte)'7', (byte)'8', (byte)'9', + (byte)'+', (byte)'/' + }; + + protected byte padding = (byte)'='; + + /* + * set up the decoding table. + */ + protected readonly byte[] decodingTable = new byte[128]; + + protected void InitialiseDecodingTable() + { + for (int i = 0; i < encodingTable.Length; i++) + { + decodingTable[encodingTable[i]] = (byte)i; + } + } + + public Base64Encoder() + { + InitialiseDecodingTable(); + } + + /** + * encode the input data producing a base 64 output stream. + * + * @return the number of bytes produced. + */ + public int Encode( + byte[] data, + int off, + int length, + Stream outStream) + { + int modulus = length % 3; + int dataLength = (length - modulus); + int a1, a2, a3; + + for (int i = off; i < off + dataLength; i += 3) + { + a1 = data[i] & 0xff; + a2 = data[i + 1] & 0xff; + a3 = data[i + 2] & 0xff; + + outStream.WriteByte(encodingTable[(int) ((uint) a1 >> 2) & 0x3f]); + outStream.WriteByte(encodingTable[((a1 << 4) | (int) ((uint) a2 >> 4)) & 0x3f]); + outStream.WriteByte(encodingTable[((a2 << 2) | (int) ((uint) a3 >> 6)) & 0x3f]); + outStream.WriteByte(encodingTable[a3 & 0x3f]); + } + + /* + * process the tail end. + */ + int b1, b2, b3; + int d1, d2; + + switch (modulus) + { + case 0: /* nothing left to do */ + break; + case 1: + d1 = data[off + dataLength] & 0xff; + b1 = (d1 >> 2) & 0x3f; + b2 = (d1 << 4) & 0x3f; + + outStream.WriteByte(encodingTable[b1]); + outStream.WriteByte(encodingTable[b2]); + outStream.WriteByte(padding); + outStream.WriteByte(padding); + break; + case 2: + d1 = data[off + dataLength] & 0xff; + d2 = data[off + dataLength + 1] & 0xff; + + b1 = (d1 >> 2) & 0x3f; + b2 = ((d1 << 4) | (d2 >> 4)) & 0x3f; + b3 = (d2 << 2) & 0x3f; + + outStream.WriteByte(encodingTable[b1]); + outStream.WriteByte(encodingTable[b2]); + outStream.WriteByte(encodingTable[b3]); + outStream.WriteByte(padding); + break; + } + + return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4); + } + + private bool ignore( + char c) + { + return (c == '\n' || c =='\r' || c == '\t' || c == ' '); + } + + /** + * decode the base 64 encoded byte data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public int Decode( + byte[] data, + int off, + int length, + Stream outStream) + { + byte b1, b2, b3, b4; + int outLen = 0; + + int end = off + length; + + while (end > off) + { + if (!ignore((char)data[end - 1])) + { + break; + } + + end--; + } + + int i = off; + int finish = end - 4; + + i = nextI(data, i, finish); + + while (i < finish) + { + b1 = decodingTable[data[i++]]; + + i = nextI(data, i, finish); + + b2 = decodingTable[data[i++]]; + + i = nextI(data, i, finish); + + b3 = decodingTable[data[i++]]; + + i = nextI(data, i, finish); + + b4 = decodingTable[data[i++]]; + + outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4))); + outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2))); + outStream.WriteByte((byte)((b3 << 6) | b4)); + + outLen += 3; + + i = nextI(data, i, finish); + } + + outLen += decodeLastBlock(outStream, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]); + + return outLen; + } + + private int nextI( + byte[] data, + int i, + int finish) + { + while ((i < finish) && ignore((char)data[i])) + { + i++; + } + return i; + } + + /** + * decode the base 64 encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public int DecodeString( + string data, + Stream outStream) + { + // Platform Implementation +// byte[] bytes = Convert.FromBase64String(data); +// outStream.Write(bytes, 0, bytes.Length); +// return bytes.Length; + + byte b1, b2, b3, b4; + int length = 0; + + int end = data.Length; + + while (end > 0) + { + if (!ignore(data[end - 1])) + { + break; + } + + end--; + } + + int i = 0; + int finish = end - 4; + + i = nextI(data, i, finish); + + while (i < finish) + { + b1 = decodingTable[data[i++]]; + + i = nextI(data, i, finish); + + b2 = decodingTable[data[i++]]; + + i = nextI(data, i, finish); + + b3 = decodingTable[data[i++]]; + + i = nextI(data, i, finish); + + b4 = decodingTable[data[i++]]; + + outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4))); + outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2))); + outStream.WriteByte((byte)((b3 << 6) | b4)); + + length += 3; + + i = nextI(data, i, finish); + } + + length += decodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]); + + return length; + } + + private int decodeLastBlock( + Stream outStream, + char c1, + char c2, + char c3, + char c4) + { + if (c3 == padding) + { + byte b1 = decodingTable[c1]; + byte b2 = decodingTable[c2]; + + outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4))); + + return 1; + } + + if (c4 == padding) + { + byte b1 = decodingTable[c1]; + byte b2 = decodingTable[c2]; + byte b3 = decodingTable[c3]; + + outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4))); + outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2))); + + return 2; + } + + { + byte b1 = decodingTable[c1]; + byte b2 = decodingTable[c2]; + byte b3 = decodingTable[c3]; + byte b4 = decodingTable[c4]; + + outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4))); + outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2))); + outStream.WriteByte((byte)((b3 << 6) | b4)); + + return 3; + } + } + + private int nextI(string data, int i, int finish) + { + while ((i < finish) && ignore(data[i])) + { + i++; + } + return i; + } + } +} diff --git a/iTechSharp/srcbc/util/encoders/BufferedDecoder.cs b/iTechSharp/srcbc/util/encoders/BufferedDecoder.cs new file mode 100644 index 0000000..633cf1e --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/BufferedDecoder.cs @@ -0,0 +1,117 @@ +using System; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /// + /// A buffering class to allow translation from one format to another to + /// be done in discrete chunks. + /// + public class BufferedDecoder + { + internal byte[] buffer; + internal int bufOff; + + internal ITranslator translator; + + /// + /// Create a buffered Decoder. + /// + /// The translater to use. + /// The size of the buffer. + public BufferedDecoder( + ITranslator translator, + int bufferSize) + { + this.translator = translator; + + if ((bufferSize % translator.GetEncodedBlockSize()) != 0) + { + throw new ArgumentException("buffer size not multiple of input block size"); + } + + buffer = new byte[bufferSize]; +// bufOff = 0; + } + + /// + /// Process one byte of data. + /// + /// Data in. + /// Byte array for the output. + /// The offset in the output byte array to start writing from. + /// The amount of output bytes. + public int ProcessByte( + byte input, + byte[] output, + int outOff) + { + int resultLen = 0; + + buffer[bufOff++] = input; + + if (bufOff == buffer.Length) + { + resultLen = translator.Decode(buffer, 0, buffer.Length, output, outOff); + bufOff = 0; + } + + return resultLen; + } + + + /// + /// Process data from a byte array. + /// + /// The input data. + /// Start position within input data array. + /// Amount of data to process from input data array. + /// Array to store output. + /// Position in output array to start writing from. + /// The amount of output bytes. + public int ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] outBytes, + int outOff) + { + if (len < 0) + { + throw new ArgumentException("Can't have a negative input length!"); + } + + int resultLen = 0; + int gapLen = buffer.Length - bufOff; + + if (len > gapLen) + { + Array.Copy(input, inOff, buffer, bufOff, gapLen); + + resultLen += translator.Decode(buffer, 0, buffer.Length, outBytes, outOff); + + bufOff = 0; + + len -= gapLen; + inOff += gapLen; + outOff += resultLen; + + int chunkSize = len - (len % buffer.Length); + + resultLen += translator.Decode(input, inOff, chunkSize, outBytes, outOff); + + len -= chunkSize; + inOff += chunkSize; + } + + if (len != 0) + { + Array.Copy(input, inOff, buffer, bufOff, len); + + bufOff += len; + } + + return resultLen; + } + } + +} diff --git a/iTechSharp/srcbc/util/encoders/BufferedEncoder.cs b/iTechSharp/srcbc/util/encoders/BufferedEncoder.cs new file mode 100644 index 0000000..5c3b1ab --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/BufferedEncoder.cs @@ -0,0 +1,117 @@ +using System; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /// + /// A class that allows encoding of data using a specific encoder to be processed in chunks. + /// + public class BufferedEncoder + { + internal byte[] Buffer; + internal int bufOff; + + internal ITranslator translator; + + + /// + /// Create. + /// + /// The translator to use. + /// Size of the chunks. + public BufferedEncoder( + ITranslator translator, + int bufferSize) + { + this.translator = translator; + + if ((bufferSize % translator.GetEncodedBlockSize()) != 0) + { + throw new ArgumentException("buffer size not multiple of input block size"); + } + + Buffer = new byte[bufferSize]; +// bufOff = 0; + } + + + /// + /// Process one byte of data. + /// + /// The byte. + /// An array to store output in. + /// Offset within output array to start writing from. + /// + public int ProcessByte( + byte input, + byte[] outBytes, + int outOff) + { + int resultLen = 0; + + Buffer[bufOff++] = input; + + if (bufOff == Buffer.Length) + { + resultLen = translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff); + bufOff = 0; + } + + return resultLen; + } + + /// + /// Process data from a byte array. + /// + /// Input data Byte array containing data to be processed. + /// Start position within input data array. + /// Amount of input data to be processed. + /// Output data array. + /// Offset within output data array to start writing to. + /// The amount of data written. + public int ProcessBytes( + byte[] input, + int inOff, + int len, + byte[] outBytes, + int outOff) + { + if (len < 0) + { + throw new ArgumentException("Can't have a negative input length!"); + } + + int resultLen = 0; + int gapLen = Buffer.Length - bufOff; + + if (len > gapLen) + { + Array.Copy(input, inOff, Buffer, bufOff, gapLen); + + resultLen += translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff); + + bufOff = 0; + + len -= gapLen; + inOff += gapLen; + outOff += resultLen; + + int chunkSize = len - (len % Buffer.Length); + + resultLen += translator.Encode(input, inOff, chunkSize, outBytes, outOff); + + len -= chunkSize; + inOff += chunkSize; + } + + if (len != 0) + { + Array.Copy(input, inOff, Buffer, bufOff, len); + + bufOff += len; + } + + return resultLen; + } + } + +} diff --git a/iTechSharp/srcbc/util/encoders/Hex.cs b/iTechSharp/srcbc/util/encoders/Hex.cs new file mode 100644 index 0000000..6790288 --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/Hex.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /// + /// Class to decode and encode Hex. + /// + public sealed class Hex + { + private static readonly IEncoder encoder = new HexEncoder(); + + private Hex() + { + } + + /** + * encode the input data producing a Hex encoded byte array. + * + * @return a byte array containing the Hex encoded data. + */ + public static byte[] Encode( + byte[] data) + { + return Encode(data, 0, data.Length); + } + + /** + * encode the input data producing a Hex encoded byte array. + * + * @return a byte array containing the Hex encoded data. + */ + public static byte[] Encode( + byte[] data, + int off, + int length) + { + MemoryStream bOut = new MemoryStream(length * 2); + + encoder.Encode(data, off, length, bOut); + + return bOut.ToArray(); + } + + /** + * Hex encode the byte data writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + Stream outStream) + { + return encoder.Encode(data, 0, data.Length, outStream); + } + + /** + * Hex encode the byte data writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + int off, + int length, + Stream outStream) + { + return encoder.Encode(data, off, length, outStream); + } + + /** + * decode the Hex encoded input data. It is assumed the input data is valid. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + byte[] data) + { + MemoryStream bOut = new MemoryStream((data.Length + 1) / 2); + + encoder.Decode(data, 0, data.Length, bOut); + + return bOut.ToArray(); + } + + /** + * decode the Hex encoded string data - whitespace will be ignored. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + string data) + { + MemoryStream bOut = new MemoryStream((data.Length + 1) / 2); + + encoder.DecodeString(data, bOut); + + return bOut.ToArray(); + } + + /** + * decode the Hex encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public static int Decode( + string data, + Stream outStream) + { + return encoder.DecodeString(data, outStream); + } + } +} diff --git a/iTechSharp/srcbc/util/encoders/HexEncoder.cs b/iTechSharp/srcbc/util/encoders/HexEncoder.cs new file mode 100644 index 0000000..c47d621 --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/HexEncoder.cs @@ -0,0 +1,164 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + public class HexEncoder + : IEncoder + { + private static readonly byte[] encodingTable = + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' + }; + + /* + * set up the decoding table. + */ + internal static readonly byte[] decodingTable = new byte[128]; + + static HexEncoder() + { + for (int i = 0; i < encodingTable.Length; i++) + { + decodingTable[encodingTable[i]] = (byte)i; + } + + decodingTable['A'] = decodingTable['a']; + decodingTable['B'] = decodingTable['b']; + decodingTable['C'] = decodingTable['c']; + decodingTable['D'] = decodingTable['d']; + decodingTable['E'] = decodingTable['e']; + decodingTable['F'] = decodingTable['f']; + } + + /** + * encode the input data producing a Hex output stream. + * + * @return the number of bytes produced. + */ + public int Encode( + byte[] data, + int off, + int length, + Stream outStream) + { + for (int i = off; i < (off + length); i++) + { + int v = data[i]; + + outStream.WriteByte(encodingTable[v >> 4]); + outStream.WriteByte(encodingTable[v & 0xf]); + } + + return length * 2; + } + + private bool ignore( + char c) + { + return (c == '\n' || c =='\r' || c == '\t' || c == ' '); + } + + /** + * decode the Hex encoded byte data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public int Decode( + byte[] data, + int off, + int length, + Stream outStream) + { + byte b1, b2; + int outLen = 0; + int end = off + length; + + while (end > off) + { + if (!ignore((char)data[end - 1])) + { + break; + } + + end--; + } + + int i = off; + while (i < end) + { + while (i < end && ignore((char)data[i])) + { + i++; + } + + b1 = decodingTable[data[i++]]; + + while (i < end && ignore((char)data[i])) + { + i++; + } + + b2 = decodingTable[data[i++]]; + + outStream.WriteByte((byte)((b1 << 4) | b2)); + + outLen++; + } + + return outLen; + } + + /** + * decode the Hex encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public int DecodeString( + string data, + Stream outStream) + { + byte b1, b2; + int length = 0; + + int end = data.Length; + + while (end > 0) + { + if (!ignore(data[end - 1])) + { + break; + } + + end--; + } + + int i = 0; + while (i < end) + { + while (i < end && ignore(data[i])) + { + i++; + } + + b1 = decodingTable[data[i++]]; + + while (i < end && ignore(data[i])) + { + i++; + } + + b2 = decodingTable[data[i++]]; + + outStream.WriteByte((byte)((b1 << 4) | b2)); + + length++; + } + + return length; + } + } +} diff --git a/iTechSharp/srcbc/util/encoders/HexTranslator.cs b/iTechSharp/srcbc/util/encoders/HexTranslator.cs new file mode 100644 index 0000000..9775b69 --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/HexTranslator.cs @@ -0,0 +1,108 @@ +using System; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /// + /// A hex translator. + /// + public class HexTranslator : ITranslator + { + private static readonly byte[] hexTable = + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' + }; + + /// + /// Return encoded block size. + /// + /// 2 + public int GetEncodedBlockSize() + { + return 2; + } + + /// + /// Encode some data. + /// + /// Input data array. + /// Start position within input data array. + /// The amount of data to process. + /// The output data array. + /// The offset within the output data array to start writing from. + /// Amount of data encoded. + public int Encode( + byte[] input, + int inOff, + int length, + byte[] outBytes, + int outOff) + { + for (int i = 0, j = 0; i < length; i++, j += 2) + { + outBytes[outOff + j] = hexTable[(input[inOff] >> 4) & 0x0f]; + outBytes[outOff + j + 1] = hexTable[input[inOff] & 0x0f]; + + inOff++; + } + + return length * 2; + } + + /// + /// Returns the decoded block size. + /// + /// 1 + public int GetDecodedBlockSize() + { + return 1; + } + + /// + /// Decode data from a byte array. + /// + /// The input data array. + /// Start position within input data array. + /// The amounty of data to process. + /// The output data array. + /// The position within the output data array to start writing from. + /// The amount of data written. + public int Decode( + byte[] input, + int inOff, + int length, + byte[] outBytes, + int outOff) + { + int halfLength = length / 2; + byte left, right; + for (int i = 0; i < halfLength; i++) + { + left = input[inOff + i * 2]; + right = input[inOff + i * 2 + 1]; + + if (left < (byte)'a') + { + outBytes[outOff] = (byte)((left - '0') << 4); + } + else + { + outBytes[outOff] = (byte)((left - 'a' + 10) << 4); + } + if (right < (byte)'a') + { + outBytes[outOff] += (byte)(right - '0'); + } + else + { + outBytes[outOff] += (byte)(right - 'a' + 10); + } + + outOff++; + } + + return halfLength; + } + } + +} diff --git a/iTechSharp/srcbc/util/encoders/IEncoder.cs b/iTechSharp/srcbc/util/encoders/IEncoder.cs new file mode 100644 index 0000000..5887d5d --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/IEncoder.cs @@ -0,0 +1,18 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /** + * Encode and decode byte arrays (typically from binary to 7-bit ASCII + * encodings). + */ + public interface IEncoder + { + int Encode(byte[] data, int off, int length, Stream outStream); + + int Decode(byte[] data, int off, int length, Stream outStream); + + int DecodeString(string data, Stream outStream); + } +} diff --git a/iTechSharp/srcbc/util/encoders/Translator.cs b/iTechSharp/srcbc/util/encoders/Translator.cs new file mode 100644 index 0000000..10bd24b --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/Translator.cs @@ -0,0 +1,19 @@ +using System; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /// + /// Translator interface. + /// + public interface ITranslator + { + int GetEncodedBlockSize(); + + int Encode(byte[] input, int inOff, int length, byte[] outBytes, int outOff); + + int GetDecodedBlockSize(); + + int Decode(byte[] input, int inOff, int length, byte[] outBytes, int outOff); + } + +} diff --git a/iTechSharp/srcbc/util/encoders/UrlBase64.cs b/iTechSharp/srcbc/util/encoders/UrlBase64.cs new file mode 100644 index 0000000..94195ef --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/UrlBase64.cs @@ -0,0 +1,127 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /** + * Convert binary data to and from UrlBase64 encoding. This is identical to + * Base64 encoding, except that the padding character is "." and the other + * non-alphanumeric characters are "-" and "_" instead of "+" and "/". + *

      + * The purpose of UrlBase64 encoding is to provide a compact encoding of binary + * data that is safe for use as an URL parameter. Base64 encoding does not + * produce encoded values that are safe for use in URLs, since "/" can be + * interpreted as a path delimiter; "+" is the encoded form of a space; and + * "=" is used to separate a name from the corresponding value in an URL + * parameter. + *

      + */ + public class UrlBase64 + { + private static readonly IEncoder encoder = new UrlBase64Encoder(); + + /** + * Encode the input data producing a URL safe base 64 encoded byte array. + * + * @return a byte array containing the URL safe base 64 encoded data. + */ + public static byte[] Encode( + byte[] data) + { + MemoryStream bOut = new MemoryStream(); + + try + { + encoder.Encode(data, 0, data.Length, bOut); + } + catch (IOException e) + { + throw new Exception("exception encoding URL safe base64 string: " + e.Message, e); + } + + return bOut.ToArray(); + } + + /** + * Encode the byte data writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + Stream outStr) + { + return encoder.Encode(data, 0, data.Length, outStr); + } + + /** + * Decode the URL safe base 64 encoded input data - white space will be ignored. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + byte[] data) + { + MemoryStream bOut = new MemoryStream(); + + try + { + encoder.Decode(data, 0, data.Length, bOut); + } + catch (IOException e) + { + throw new Exception("exception decoding URL safe base64 string: " + e.Message, e); + } + + return bOut.ToArray(); + } + + /** + * decode the URL safe base 64 encoded byte data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public static int Decode( + byte[] data, + Stream outStr) + { + return encoder.Decode(data, 0, data.Length, outStr); + } + + /** + * decode the URL safe base 64 encoded string data - whitespace will be ignored. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + string data) + { + MemoryStream bOut = new MemoryStream(); + + try + { + encoder.DecodeString(data, bOut); + } + catch (IOException e) + { + throw new Exception("exception decoding URL safe base64 string: " + e.Message, e); + } + + return bOut.ToArray(); + } + + /** + * Decode the URL safe base 64 encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public static int Decode( + string data, + Stream outStr) + { + return encoder.DecodeString(data, outStr); + } + } +} diff --git a/iTechSharp/srcbc/util/encoders/UrlBase64Encoder.cs b/iTechSharp/srcbc/util/encoders/UrlBase64Encoder.cs new file mode 100644 index 0000000..5611a83 --- /dev/null +++ b/iTechSharp/srcbc/util/encoders/UrlBase64Encoder.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Encoders +{ + /** + * Convert binary data to and from UrlBase64 encoding. This is identical to + * Base64 encoding, except that the padding character is "." and the other + * non-alphanumeric characters are "-" and "_" instead of "+" and "/". + *

      + * The purpose of UrlBase64 encoding is to provide a compact encoding of binary + * data that is safe for use as an URL parameter. Base64 encoding does not + * produce encoded values that are safe for use in URLs, since "/" can be + * interpreted as a path delimiter; "+" is the encoded form of a space; and + * "=" is used to separate a name from the corresponding value in an URL + * parameter. + *

      + */ + public class UrlBase64Encoder + : Base64Encoder + { + public UrlBase64Encoder() + { + encodingTable[encodingTable.Length - 2] = (byte) '-'; + encodingTable[encodingTable.Length - 1] = (byte) '_'; + padding = (byte) '.'; + // we must re-create the decoding table with the new encoded values. + InitialiseDecodingTable(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/io/BaseInputStream.cs b/iTechSharp/srcbc/util/io/BaseInputStream.cs new file mode 100644 index 0000000..3ff4a19 --- /dev/null +++ b/iTechSharp/srcbc/util/io/BaseInputStream.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace Org.BouncyCastle.Utilities.IO +{ + public abstract class BaseInputStream : Stream + { + private bool closed; + + public sealed override bool CanRead { get { return !closed; } } + public sealed override bool CanSeek { get { return false; } } + public sealed override bool CanWrite { get { return false; } } + public override void Close() { closed = true; } + public sealed override void Flush() {} + public sealed override long Length { get { throw new NotSupportedException(); } } + public sealed override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int pos = offset; + try + { + int end = offset + count; + while (pos < end) + { + int b = ReadByte(); + if (b == -1) break; + buffer[pos++] = (byte) b; + } + } + catch (IOException) + { + if (pos == offset) throw; + } + return pos - offset; + } + + public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + public sealed override void SetLength(long value) { throw new NotSupportedException(); } + public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } + } +} diff --git a/iTechSharp/srcbc/util/io/BaseOutputStream.cs b/iTechSharp/srcbc/util/io/BaseOutputStream.cs new file mode 100644 index 0000000..6e6c6d3 --- /dev/null +++ b/iTechSharp/srcbc/util/io/BaseOutputStream.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace Org.BouncyCastle.Utilities.IO +{ + public abstract class BaseOutputStream : Stream + { + private bool closed; + + public sealed override bool CanRead { get { return false; } } + public sealed override bool CanSeek { get { return false; } } + public sealed override bool CanWrite { get { return !closed; } } + public override void Close() { closed = true; } + public override void Flush() {} + public sealed override long Length { get { throw new NotSupportedException(); } } + public sealed override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } + public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } + public sealed override void SetLength(long value) { throw new NotSupportedException(); } + + public override void Write(byte[] buffer, int offset, int count) + { + Debug.Assert(buffer != null); + Debug.Assert(0 <= offset && offset <= buffer.Length); + Debug.Assert(count >= 0); + + int end = offset + count; + + Debug.Assert(0 <= end && end <= buffer.Length); + + for (int i = offset; i < end; ++i) + { + this.WriteByte(buffer[i]); + } + } + + public virtual void Write(params byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + } +} diff --git a/iTechSharp/srcbc/util/io/PushbackStream.cs b/iTechSharp/srcbc/util/io/PushbackStream.cs new file mode 100644 index 0000000..9546942 --- /dev/null +++ b/iTechSharp/srcbc/util/io/PushbackStream.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1.Utilities; + +namespace Org.BouncyCastle.Utilities.IO +{ + public class PushbackStream + : FilterStream + { + private int buf = -1; + + public PushbackStream( + Stream s) + : base(s) + { + } + + public override int ReadByte() + { + if (buf != -1) + { + int tmp = buf; + buf = -1; + return tmp; + } + + return base.ReadByte(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (buf != -1 && count > 0) + { + // TODO Can this case be made more efficient? + buffer[offset] = (byte) buf; + buf = -1; + return 1; + } + + return base.Read(buffer, offset, count); + } + + public virtual void Unread(int b) + { + if (buf != -1) + throw new InvalidOperationException("Can only push back one byte"); + + buf = b & 0xFF; + } + } +} diff --git a/iTechSharp/srcbc/util/io/Streams.cs b/iTechSharp/srcbc/util/io/Streams.cs new file mode 100644 index 0000000..9e599f7 --- /dev/null +++ b/iTechSharp/srcbc/util/io/Streams.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.IO +{ + public sealed class Streams + { + private const int BufferSize = 512; + + private Streams() + { + } + + public static void Drain(Stream inStr) + { + byte[] bs = new byte[BufferSize]; + while (inStr.Read(bs, 0, bs.Length) > 0) + { + } + } + + public static byte[] ReadAll(Stream inStr) + { + MemoryStream buf = new MemoryStream(); + PipeAll(inStr, buf); + return buf.ToArray(); + } + + public static int ReadFully(Stream inStr, byte[] buf) + { + return ReadFully(inStr, buf, 0, buf.Length); + } + + public static int ReadFully(Stream inStr, byte[] buf, int off, int len) + { + int totalRead = 0; + while (totalRead < len) + { + int numRead = inStr.Read(buf, off + totalRead, len - totalRead); + if (numRead < 1) + break; + totalRead += numRead; + } + return totalRead; + } + + public static void PipeAll(Stream inStr, Stream outStr) + { + byte[] bs = new byte[BufferSize]; + int numRead; + while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0) + { + outStr.Write(bs, 0, numRead); + } + } + } +} diff --git a/iTechSharp/srcbc/util/net/IPAddress.cs b/iTechSharp/srcbc/util/net/IPAddress.cs new file mode 100644 index 0000000..b13edad --- /dev/null +++ b/iTechSharp/srcbc/util/net/IPAddress.cs @@ -0,0 +1,112 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Utilities.Net +{ + public class IPAddress + { + /** + * Validate the given IPv4 or IPv6 address. + * + * @param address the IP address as a string. + * + * @return true if a valid address, false otherwise + */ + public static bool IsValid( + string address) + { + return IsValidIPv4(address) || IsValidIPv6(address); + } + + /** + * Validate the given IPv4 address. + * + * @param address the IP address as a string. + * + * @return true if a valid IPv4 address, false otherwise + */ + private static bool IsValidIPv4( + string address) + { + if (address.Length == 0) + return false; + + BigInteger octet; + int octets = 0; + + string temp = address + "."; + + int pos; + int start = 0; + while (start < temp.Length + && (pos = temp.IndexOf('.', start)) > start) + { + if (octets == 4) + return false; + + try + { + octet = new BigInteger(temp.Substring(start, pos - start)); + } + catch (FormatException) + { + return false; + } + + if (octet.SignValue < 0 || octet.BitLength > 8) + return false; + + start = pos + 1; + ++octets; + } + + return octets == 4; + } + + /** + * Validate the given IPv6 address. + * + * @param address the IP address as a string. + * + * @return true if a valid IPv4 address, false otherwise + */ + private static bool IsValidIPv6( + string address) + { + if (address.Length == 0) + return false; + + BigInteger octet; + int octets = 0; + + string temp = address + ":"; + + int pos; + int start = 0; + while (start < temp.Length + && (pos = temp.IndexOf(':', start)) > start) + { + if (octets == 8) + return false; + + try + { + octet = new BigInteger(temp.Substring(start, pos - start), 16); + } + catch (FormatException) + { + return false; + } + + if (octet.SignValue < 0 || octet.BitLength > 16) + return false; + + start = pos + 1; + octets++; + } + + return octets == 8; + } + } +} diff --git a/iTechSharp/srcbc/util/zlib/Adler32.cs b/iTechSharp/srcbc/util/zlib/Adler32.cs new file mode 100644 index 0000000..7353475 --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/Adler32.cs @@ -0,0 +1,88 @@ +using System; +/* + * $Id: Adler32.cs,v 1.1.1.1 2007/01/24 16:41:26 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace Org.BouncyCastle.Utilities.Zlib { + + internal sealed class Adler32{ + + // largest prime smaller than 65536 + private const int BASE=65521; + // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + private const int NMAX=5552; + + internal long adler32(long adler, byte[] buf, int index, int len){ + if(buf == null){ return 1L; } + + long s1=adler&0xffff; + long s2=(adler>>16)&0xffff; + int k; + + while(len > 0) { + k=len=16){ + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + k-=16; + } + if(k!=0){ + do{ + s1+=buf[index++]&0xff; s2+=s1; + } + while(--k!=0); + } + s1%=BASE; + s2%=BASE; + } + return (s2<<16)|s1; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/zlib/Deflate.cs b/iTechSharp/srcbc/util/zlib/Deflate.cs new file mode 100644 index 0000000..ea85af3 --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/Deflate.cs @@ -0,0 +1,1640 @@ +using System; +/* + * $Id: Deflate.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace Org.BouncyCastle.Utilities.Zlib { + + public sealed class Deflate{ + + private const int MAX_MEM_LEVEL=9; + + private const int Z_DEFAULT_COMPRESSION=-1; + + private const int MAX_WBITS=15; // 32K LZ77 window + private const int DEF_MEM_LEVEL=8; + + internal class Config{ + internal int good_length; // reduce lazy search above this match length + internal int max_lazy; // do not perform lazy search above this match length + internal int nice_length; // quit search above this match length + internal int max_chain; + internal int func; + internal Config(int good_length, int max_lazy, + int nice_length, int max_chain, int func){ + this.good_length=good_length; + this.max_lazy=max_lazy; + this.nice_length=nice_length; + this.max_chain=max_chain; + this.func=func; + } + } + + private const int STORED=0; + private const int FAST=1; + private const int SLOW=2; + private static readonly Config[] config_table; + + static Deflate(){ + config_table=new Config[10]; + // good lazy nice chain + config_table[0]=new Config(0, 0, 0, 0, STORED); + config_table[1]=new Config(4, 4, 8, 4, FAST); + config_table[2]=new Config(4, 5, 16, 8, FAST); + config_table[3]=new Config(4, 6, 32, 32, FAST); + + config_table[4]=new Config(4, 4, 16, 16, SLOW); + config_table[5]=new Config(8, 16, 32, 32, SLOW); + config_table[6]=new Config(8, 16, 128, 128, SLOW); + config_table[7]=new Config(8, 32, 128, 256, SLOW); + config_table[8]=new Config(32, 128, 258, 1024, SLOW); + config_table[9]=new Config(32, 258, 258, 4096, SLOW); + } + + private static readonly String[] z_errmsg = { + "need dictionary", // Z_NEED_DICT 2 + "stream end", // Z_STREAM_END 1 + "", // Z_OK 0 + "file error", // Z_ERRNO (-1) + "stream error", // Z_STREAM_ERROR (-2) + "data error", // Z_DATA_ERROR (-3) + "insufficient memory", // Z_MEM_ERROR (-4) + "buffer error", // Z_BUF_ERROR (-5) + "incompatible version",// Z_VERSION_ERROR (-6) + "" + }; + + // block not completed, need more input or more output + private const int NeedMore=0; + + // block flush performed + private const int BlockDone=1; + + // finish started, need only more output at next deflate + private const int FinishStarted=2; + + // finish done, accept no more input or output + private const int FinishDone=3; + + // preset dictionary flag in zlib header + private const int PRESET_DICT=0x20; + + private const int Z_FILTERED=1; + private const int Z_HUFFMAN_ONLY=2; + private const int Z_DEFAULT_STRATEGY=0; + + private const int Z_NO_FLUSH=0; + private const int Z_PARTIAL_FLUSH=1; + private const int Z_SYNC_FLUSH=2; + private const int Z_FULL_FLUSH=3; + private const int Z_FINISH=4; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int INIT_STATE=42; + private const int BUSY_STATE=113; + private const int FINISH_STATE=666; + + // The deflate compression method + private const int Z_DEFLATED=8; + + private const int STORED_BLOCK=0; + private const int STATIC_TREES=1; + private const int DYN_TREES=2; + + // The three kinds of block type + private const int Z_BINARY=0; + private const int Z_ASCII=1; + private const int Z_UNKNOWN=2; + + private const int Buf_size=8*2; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + private const int REP_3_6=16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + private const int REPZ_3_10=17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + private const int REPZ_11_138=18; + + private const int MIN_MATCH=3; + private const int MAX_MATCH=258; + private const int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1); + + private const int MAX_BITS=15; + private const int D_CODES=30; + private const int BL_CODES=19; + private const int LENGTH_CODES=29; + private const int LITERALS=256; + private const int L_CODES=(LITERALS+1+LENGTH_CODES); + private const int HEAP_SIZE=(2*L_CODES+1); + + private const int END_BLOCK=256; + + internal ZStream strm; // pointer back to this zlib stream + internal int status; // as the name implies + internal byte[] pending_buf; // output still pending + internal int pending_buf_size; // size of pending_buf + internal int pending_out; // next pending byte to output to the stream + internal int pending; // nb of bytes in the pending buffer + internal int noheader; // suppress zlib header and adler32 + internal byte data_type; // UNKNOWN, BINARY or ASCII + internal byte method; // STORED (for zip only) or DEFLATED + internal int last_flush; // value of flush param for previous deflate call + + internal int w_size; // LZ77 window size (32K by default) + internal int w_bits; // log2(w_size) (8..16) + internal int w_mask; // w_size - 1 + + internal byte[] window; + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least wSize + // bytes. With this organization, matches are limited to a distance of + // wSize-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. Also, it limits + // the window size to 64K, which is quite useful on MSDOS. + // To do: use the user input buffer as sliding window. + + internal int window_size; + // Actual size of window: 2*wSize, except when the user input buffer + // is directly used as sliding window. + + internal short[] prev; + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + + internal short[] head; // Heads of the hash chains or NIL. + + internal int ins_h; // hash index of string to be inserted + internal int hash_size; // number of elements in hash table + internal int hash_bits; // log2(hash_size) + internal int hash_mask; // hash_size-1 + + // Number of bits by which ins_h must be shifted at each input + // step. It must be such that after MIN_MATCH steps, the oldest + // byte no longer takes part in the hash key, that is: + // hash_shift * MIN_MATCH >= hash_bits + internal int hash_shift; + + // Window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + internal int block_start; + + internal int match_length; // length of best match + internal int prev_match; // previous match + internal int match_available; // set if previous match exists + internal int strstart; // start of string to insert + internal int match_start; // start of matching string + internal int lookahead; // number of valid bytes ahead in window + + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + internal int prev_length; + + // To speed up deflation, hash chains are never searched beyond this + // length. A higher limit improves compression ratio but degrades the speed. + internal int max_chain_length; + + // Attempt to find a better match only when the current match is strictly + // smaller than this value. This mechanism is used only for compression + // levels >= 4. + internal int max_lazy_match; + + // Insert new strings in the hash table only if the match length is not + // greater than this length. This saves time but degrades compression. + // max_insert_length is used only for compression levels <= 3. + + internal int level; // compression level (1..9) + internal int strategy; // favor or force Huffman coding + + // Use a faster search when the previous match is longer than this + internal int good_match; + + // Stop searching when current match exceeds this + internal int nice_match; + + internal short[] dyn_ltree; // literal and length tree + internal short[] dyn_dtree; // distance tree + internal short[] bl_tree; // Huffman tree for bit lengths + + internal Tree l_desc=new Tree(); // desc for literal tree + internal Tree d_desc=new Tree(); // desc for distance tree + internal Tree bl_desc=new Tree(); // desc for bit length tree + + // number of codes at each bit length for an optimal tree + internal short[] bl_count=new short[MAX_BITS+1]; + + // heap used to build the Huffman trees + internal int[] heap=new int[2*L_CODES+1]; + + internal int heap_len; // number of elements in the heap + internal int heap_max; // element of largest frequency + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + // Depth of each subtree used as tie breaker for trees of equal frequency + internal byte[] depth=new byte[2*L_CODES+1]; + + internal int l_buf; // index for literals or lengths */ + + // Size of match buffer for literals/lengths. There are 4 reasons for + // limiting lit_bufsize to 64K: + // - frequencies can be kept in 16 bit counters + // - if compression is not successful for the first block, all input + // data is still in the window so we can still emit a stored block even + // when input comes from standard input. (This can also be done for + // all blocks if lit_bufsize is not greater than 32K.) + // - if compression is not successful for a file smaller than 64K, we can + // even emit a stored file instead of a stored block (saving 5 bytes). + // This is applicable only for zip (not gzip or zlib). + // - creating new Huffman trees less frequently may not provide fast + // adaptation to changes in the input data statistics. (Take for + // example a binary file with poorly compressible code followed by + // a highly compressible string table.) Smaller buffer sizes give + // fast adaptation but have of course the overhead of transmitting + // trees more frequently. + // - I can't count above 4 + internal int lit_bufsize; + + internal int last_lit; // running index in l_buf + + // Buffer for distances. To simplify the code, d_buf and l_buf have + // the same number of elements. To use different lengths, an extra flag + // array would be necessary. + + internal int d_buf; // index of pendig_buf + + internal int opt_len; // bit length of current block with optimal trees + internal int static_len; // bit length of current block with static trees + internal int matches; // number of string matches in current block + internal int last_eob_len; // bit length of EOB code for last block + + // Output buffer. bits are inserted starting at the bottom (least + // significant bits). + internal uint bi_buf; + + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + internal int bi_valid; + + internal Deflate(){ + dyn_ltree=new short[HEAP_SIZE*2]; + dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree + bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths + } + + internal void lm_init() { + window_size=2*w_size; + + head[hash_size-1]=0; + for(int i=0; i= 3; max_blindex--) { + if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break; + } + // Update opt_len to include the bit length tree and counts + opt_len += 3*(max_blindex+1) + 5+5+4; + + return max_blindex; + } + + + // Send the header for a block using dynamic Huffman trees: the counts, the + // lengths of the bit length codes, the literal tree and the distance tree. + // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + internal void send_all_trees(int lcodes, int dcodes, int blcodes){ + int rank; // index in bl_order + + send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes-1, 5); + send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) { + send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3); + } + send_tree(dyn_ltree, lcodes-1); // literal tree + send_tree(dyn_dtree, dcodes-1); // distance tree + } + + // Send a literal or distance tree in compressed form, using the codes in + // bl_tree. + internal void send_tree (short[] tree,// the tree to be sent + int max_code // and its largest code of non zero frequency + ){ + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0*2+1]; // length of next code + int count = 0; // repeat count of the current code + int max_count = 7; // max repeat count + int min_count = 4; // min repeat count + + if (nextlen == 0){ max_count = 138; min_count = 3; } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[(n+1)*2+1]; + if(++count < max_count && curlen == nextlen) { + continue; + } + else if(count < min_count) { + do { send_code(curlen, bl_tree); } while (--count != 0); + } + else if(curlen != 0){ + if(curlen != prevlen){ + send_code(curlen, bl_tree); count--; + } + send_code(REP_3_6, bl_tree); + send_bits(count-3, 2); + } + else if(count <= 10){ + send_code(REPZ_3_10, bl_tree); + send_bits(count-3, 3); + } + else{ + send_code(REPZ_11_138, bl_tree); + send_bits(count-11, 7); + } + count = 0; prevlen = curlen; + if(nextlen == 0){ + max_count = 138; min_count = 3; + } + else if(curlen == nextlen){ + max_count = 6; min_count = 3; + } + else{ + max_count = 7; min_count = 4; + } + } + } + + // Output a byte on the stream. + // IN assertion: there is enough room in pending_buf. + internal void put_byte(byte[] p, int start, int len){ + System.Array.Copy(p, start, pending_buf, pending, len); + pending+=len; + } + + internal void put_byte(byte c){ + pending_buf[pending++]=c; + } + internal void put_short(int w) { + pending_buf[pending++]=(byte)(w/*&0xff*/); + pending_buf[pending++]=(byte)(w>>8); + } + internal void putShortMSB(int b){ + pending_buf[pending++]=(byte)(b>>8); + pending_buf[pending++]=(byte)(b/*&0xff*/); + } + + internal void send_code(int c, short[] tree){ + int c2=c*2; + send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff)); + } + + internal void send_bits(int val, int length){ + if (bi_valid > Buf_size - length) { + bi_buf |= (uint)(val << bi_valid); + pending_buf[pending++]=(byte)(bi_buf/*&0xff*/); + pending_buf[pending++]=(byte)(bi_buf>>8); + bi_buf = ((uint)val) >> (Buf_size - bi_valid); + bi_valid += length - Buf_size; + } else { + bi_buf |= (uint)(val << bi_valid); + bi_valid += length; + } +// int len = length; +// if (bi_valid > (int)Buf_size - len) { +// int val = value; +// // bi_buf |= (val << bi_valid); +// bi_buf = (short)((ushort)bi_buf | (ushort)((val << bi_valid)&0xffff)); +// put_short(bi_buf); +// bi_buf = (short)(((uint)val) >> (Buf_size - bi_valid)); +// bi_valid += len - Buf_size; +// } else { +// // bi_buf |= (value) << bi_valid; +// bi_buf = (short)((ushort)bi_buf | (ushort)(((value) << bi_valid)&0xffff)); +// bi_valid += len; +// } + } + + // Send one empty static block to give enough lookahead for inflate. + // This takes 10 bits, of which 7 may remain in the bit buffer. + // The current inflate code requires 9 bits of lookahead. If the + // last two codes for the previous block (real code plus EOB) were coded + // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + // the last real code. In this case we send two empty static blocks instead + // of one. (There are no problems if the previous block is stored or fixed.) + // To simplify the code, we assume the worst case of last real code encoded + // on one bit only. + internal void _tr_align(){ + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + + bi_flush(); + + // Of the 10 bits for the empty block, we have already sent + // (10 - bi_valid) bits. The lookahead for the last real code (before + // the EOB of the previous block) was thus at least one plus the length + // of the EOB plus what we have just sent of the empty static block. + if (1 + last_eob_len + 10 - bi_valid < 9) { + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + bi_flush(); + } + last_eob_len = 7; + } + + + // Save the match info and tally the frequency counts. Return true if + // the current block must be flushed. + internal bool _tr_tally (int dist, // distance of matched string + int lc // match length-MIN_MATCH or unmatched char (if dist==0) + ){ + + pending_buf[d_buf+last_lit*2] = (byte)(dist>>8); + pending_buf[d_buf+last_lit*2+1] = (byte)dist; + + pending_buf[l_buf+last_lit] = (byte)lc; last_lit++; + + if (dist == 0) { + // lc is the unmatched char + dyn_ltree[lc*2]++; + } + else { + matches++; + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++; + dyn_dtree[Tree.d_code(dist)*2]++; + } + + if ((last_lit & 0x1fff) == 0 && level > 2) { + // Compute an upper bound for the compressed length + int out_length = last_lit*8; + int in_length = strstart - block_start; + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (int)((int)dyn_dtree[dcode*2] * + (5L+Tree.extra_dbits[dcode])); + } + out_length >>= 3; + if ((matches < (last_lit/2)) && out_length < in_length/2) return true; + } + + return (last_lit == lit_bufsize-1); + // We avoid equality with lit_bufsize because of wraparound at 64K + // on 16 bit machines and because stored blocks are restricted to + // 64K-1 bytes. + } + + // Send the block data compressed using the given Huffman trees + internal void compress_block(short[] ltree, short[] dtree){ + int dist; // distance of matched string + int lc; // match length or unmatched char (if dist == 0) + int lx = 0; // running index in l_buf + int code; // the code to send + int extra; // number of extra bits to send + + if (last_lit != 0){ + do{ + dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)| + (pending_buf[d_buf+lx*2+1]&0xff); + lc=(pending_buf[l_buf+lx])&0xff; lx++; + + if(dist == 0){ + send_code(lc, ltree); // send a literal byte + } + else{ + // Here, lc is the match length - MIN_MATCH + code = Tree._length_code[lc]; + + send_code(code+LITERALS+1, ltree); // send the length code + extra = Tree.extra_lbits[code]; + if(extra != 0){ + lc -= Tree.base_length[code]; + send_bits(lc, extra); // send the extra length bits + } + dist--; // dist is now the match distance - 1 + code = Tree.d_code(dist); + + send_code(code, dtree); // send the distance code + extra = Tree.extra_dbits[code]; + if (extra != 0) { + dist -= Tree.base_dist[code]; + send_bits(dist, extra); // send the extra distance bits + } + } // literal or match pair ? + + // Check that the overlay between pending_buf and d_buf+l_buf is ok: + } + while (lx < last_lit); + } + + send_code(END_BLOCK, ltree); + last_eob_len = ltree[END_BLOCK*2+1]; + } + + // Set the data type to ASCII or BINARY, using a crude approximation: + // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + // IN assertion: the fields freq of dyn_ltree are set and the total of all + // frequencies does not exceed 64K (to fit in an int on 16 bit machines). + internal void set_data_type(){ + int n = 0; + int ascii_freq = 0; + int bin_freq = 0; + while(n<7){ bin_freq += dyn_ltree[n*2]; n++;} + while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;} + while(n (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); + } + + // Flush the bit buffer, keeping at most 7 bits in it. + internal void bi_flush(){ + if (bi_valid == 16) { + pending_buf[pending++]=(byte)(bi_buf/*&0xff*/); + pending_buf[pending++]=(byte)(bi_buf>>8); + bi_buf=0; + bi_valid=0; + } + else if (bi_valid >= 8) { + pending_buf[pending++]=(byte)(bi_buf); + bi_buf>>=8; + bi_buf &= 0x00ff; + bi_valid-=8; + } + } + + // Flush the bit buffer and align the output on a byte boundary + internal void bi_windup(){ + if (bi_valid > 8) { + pending_buf[pending++]=(byte)(bi_buf); + pending_buf[pending++]=(byte)(bi_buf>>8); + } else if (bi_valid > 0) { + pending_buf[pending++]=(byte)(bi_buf); + } + bi_buf = 0; + bi_valid = 0; + } + + // Copy a stored block, storing first the length and its + // one's complement if requested. + internal void copy_block(int buf, // the input data + int len, // its length + bool header // true if block header must be written + ){ + //int index=0; + bi_windup(); // align on byte boundary + last_eob_len = 8; // enough lookahead for inflate + + if (header) { + put_short((short)len); + put_short((short)~len); + } + + // while(len--!=0) { + // put_byte(window[buf+index]); + // index++; + // } + put_byte(window, buf, len); + } + + internal void flush_block_only(bool eof){ + _tr_flush_block(block_start>=0 ? block_start : -1, + strstart-block_start, + eof); + block_start=strstart; + strm.flush_pending(); + } + + // Copy without compression as much as possible from the input stream, return + // the current block state. + // This function does not insert new strings in the dictionary since + // uncompressible data is probably not useful. This function is used + // only for the level=0 compression option. + // NOTE: this function should be optimized to avoid extra copying from + // window to pending_buf. + internal int deflate_stored(int flush){ + // Stored blocks are limited to 0xffff bytes, pending_buf is limited + // to pending_buf_size, and each stored block has a 5 byte header: + + int max_block_size = 0xffff; + int max_start; + + if(max_block_size > pending_buf_size - 5) { + max_block_size = pending_buf_size - 5; + } + + // Copy as much as possible from input to output: + while(true){ + // Fill the window as much as possible: + if(lookahead<=1){ + fill_window(); + if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore; + if(lookahead==0) break; // flush the current block + } + + strstart+=lookahead; + lookahead=0; + + // Emit a stored block if pending_buf will be full: + max_start=block_start+max_block_size; + if(strstart==0|| strstart>=max_start) { + // strstart == 0 is possible when wraparound on 16-bit machine + lookahead = (int)(strstart-max_start); + strstart = (int)max_start; + + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + + } + + // Flush if we may have to slide, otherwise block_start may become + // negative and the data will be gone: + if(strstart-block_start >= w_size-MIN_LOOKAHEAD) { + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + } + } + + flush_block_only(flush == Z_FINISH); + if(strm.avail_out==0) + return (flush == Z_FINISH) ? FinishStarted : NeedMore; + + return flush == Z_FINISH ? FinishDone : BlockDone; + } + + // Send a stored block + internal void _tr_stored_block(int buf, // input block + int stored_len, // length of input block + bool eof // true if this is the last block for a file + ){ + send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type + copy_block(buf, stored_len, true); // with header + } + + // Determine the best encoding for the current block: dynamic trees, static + // trees or store, and output the encoded block to the zip file. + internal void _tr_flush_block(int buf, // input block, or NULL if too old + int stored_len, // length of input block + bool eof // true if this is the last block for a file + ) { + int opt_lenb, static_lenb;// opt_len and static_len in bytes + int max_blindex = 0; // index of last bit length code of non zero freq + + // Build the Huffman trees unless a stored block is forced + if(level > 0) { + // Check if the file is ascii or binary + if(data_type == Z_UNKNOWN) set_data_type(); + + // Construct the literal and distance trees + l_desc.build_tree(this); + + d_desc.build_tree(this); + + // At this point, opt_len and static_len are the total bit lengths of + // the compressed block data, excluding the tree representations. + + // Build the bit length tree for the above two trees, and get the index + // in bl_order of the last bit length code to send. + max_blindex=build_bl_tree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb=(opt_len+3+7)>>3; + static_lenb=(static_len+3+7)>>3; + + if(static_lenb<=opt_lenb) opt_lenb=static_lenb; + } + else { + opt_lenb=static_lenb=stored_len+5; // force a stored block + } + + if(stored_len+4<=opt_lenb && buf != -1){ + // 4: two words for the lengths + // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + // Otherwise we can't have processed more than WSIZE input bytes since + // the last block flush, because compression would have been + // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + // transform a block into a stored block. + _tr_stored_block(buf, stored_len, eof); + } + else if(static_lenb == opt_lenb){ + send_bits((STATIC_TREES<<1)+(eof?1:0), 3); + compress_block(StaticTree.static_ltree, StaticTree.static_dtree); + } + else{ + send_bits((DYN_TREES<<1)+(eof?1:0), 3); + send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1); + compress_block(dyn_ltree, dyn_dtree); + } + + // The above check is made mod 2^32, for files larger than 512 MB + // and uLong implemented on 32 bits. + + init_block(); + + if(eof){ + bi_windup(); + } + } + + // Fill the window when the lookahead becomes insufficient. + // Updates strstart and lookahead. + // + // IN assertion: lookahead < MIN_LOOKAHEAD + // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + // At least one byte has been read, or avail_in == 0; reads are + // performed for at least two bytes (required for the zip translate_eol + // option -- not supported here). + internal void fill_window(){ + int n, m; + int p; + int more; // Amount of free space at the end of the window. + + do{ + more = (window_size-lookahead-strstart); + + // Deal with !@#$% 64K limit: + if(more==0 && strstart==0 && lookahead==0){ + more = w_size; + } + else if(more==-1) { + // Very unlikely, but possible on 16 bit machine if strstart == 0 + // and lookahead == 1 (input done one byte at time) + more--; + + // If the window is almost full and there is insufficient lookahead, + // move the upper half to the lower one to make room in the upper half. + } + else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) { + System.Array.Copy(window, w_size, window, 0, w_size); + match_start-=w_size; + strstart-=w_size; // we now have strstart >= MAX_DIST + block_start-=w_size; + + // Slide the hash table (could be avoided with 32 bit values + // at the expense of memory usage). We slide even when level == 0 + // to keep the hash table consistent if we switch back to level > 0 + // later. (Using level 0 permanently is not an optimal usage of + // zlib, so we don't care about this pathological case.) + + n = hash_size; + p=n; + do { + m = (head[--p]&0xffff); + head[p]=(short)(m>=w_size ? (m-w_size) : 0); + } + while (--n != 0); + + n = w_size; + p = n; + do { + m = (prev[--p]&0xffff); + prev[p] = (short)(m >= w_size ? (m-w_size) : 0); + // If n is not on any hash chain, prev[n] is garbage but + // its value will never be used. + } + while (--n!=0); + more += w_size; + } + + if (strm.avail_in == 0) return; + + // If there was no sliding: + // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + // more == window_size - lookahead - strstart + // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + // => more >= window_size - 2*WSIZE + 2 + // In the BIG_MEM or MMAP case (not yet supported), + // window_size == input_size + MIN_LOOKAHEAD && + // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + // Otherwise, window_size == 2*WSIZE so more >= 2. + // If there was sliding, more >= WSIZE. So in all cases, more >= 2. + + n = strm.read_buf(window, strstart + lookahead, more); + lookahead += n; + + // Initialize the hash value now that we have some input: + if(lookahead >= MIN_MATCH) { + ins_h = window[strstart]&0xff; + ins_h=(((ins_h)<= MIN_MATCH){ + ins_h=(((ins_h)<=MIN_MATCH){ + // check_match(strstart, match_start, match_length); + + bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if(match_length <= max_lazy_match && + lookahead >= MIN_MATCH) { + match_length--; // string at strstart already in hash table + do{ + strstart++; + + ins_h=((ins_h<= MIN_MATCH) { + ins_h=(((ins_h)< 4096))) { + + // If prev_match is also MIN_MATCH, match_start is garbage + // but we will ignore the current match anyway. + match_length = MIN_MATCH-1; + } + } + + // If there was a match at the previous step and the current + // match is not better, output the previous match: + if(prev_length >= MIN_MATCH && match_length <= prev_length) { + int max_insert = strstart + lookahead - MIN_MATCH; + // Do not insert strings in hash table beyond this. + + // check_match(strstart-1, prev_match, prev_length); + + bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH); + + // Insert in hash table all strings up to the end of the match. + // strstart-1 and strstart are already inserted. If there is not + // enough lookahead, the last two strings are not inserted in + // the hash table. + lookahead -= prev_length-1; + prev_length -= 2; + do{ + if(++strstart <= max_insert) { + ins_h=(((ins_h)<(w_size-MIN_LOOKAHEAD) ? + strstart-(w_size-MIN_LOOKAHEAD) : 0; + int nice_match=this.nice_match; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0. + + int wmask = w_mask; + + int strend = strstart + MAX_MATCH; + byte scan_end1 = window[scan+best_len-1]; + byte scan_end = window[scan+best_len]; + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + + // Do not waste too much time if we already have a good match: + if (prev_length >= good_match) { + chain_length >>= 2; + } + + // Do not look for matches beyond the end of the input. This is necessary + // to make deflate deterministic. + if (nice_match > lookahead) nice_match = lookahead; + + do { + match = cur_match; + + // Skip to next match if the match length cannot increase + // or if the match length is less than 2: + if (window[match+best_len] != scan_end || + window[match+best_len-1] != scan_end1 || + window[match] != window[scan] || + window[++match] != window[scan+1]) continue; + + // The check at best_len-1 can be removed because it will be made + // again later. (This heuristic is not always a win.) + // It is not necessary to compare scan[2] and match[2] since they + // are always equal when the other bytes match, given that + // the hash keys are equal and that HASH_BITS >= 8. + scan += 2; match++; + + // We check for insufficient lookahead only every 8th comparison; + // the 256th check will be made at strstart+258. + do { + } while (window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + scan < strend); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + + if(len>best_len) { + match_start = cur_match; + best_len = len; + if (len >= nice_match) break; + scan_end1 = window[scan+best_len-1]; + scan_end = window[scan+best_len]; + } + + } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit + && --chain_length != 0); + + if (best_len <= lookahead) return best_len; + return lookahead; + } + + internal int deflateInit(ZStream strm, int level, int bits){ + return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY); + } + internal int deflateInit(ZStream strm, int level){ + return deflateInit(strm, level, MAX_WBITS); + } + internal int deflateInit2(ZStream strm, int level, int method, int windowBits, + int memLevel, int strategy){ + int noheader = 0; + // byte[] my_version=ZLIB_VERSION; + + // + // if (version == null || version[0] != my_version[0] + // || stream_size != sizeof(z_stream)) { + // return Z_VERSION_ERROR; + // } + + strm.msg = null; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { // undocumented feature: suppress zlib header + noheader = 1; + windowBits = -windowBits; + } + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || + method != Z_DEFLATED || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + strm.dstate = (Deflate)this; + + this.noheader = noheader; + w_bits = windowBits; + w_size = 1 << w_bits; + w_mask = w_size - 1; + + hash_bits = memLevel + 7; + hash_size = 1 << hash_bits; + hash_mask = hash_size - 1; + hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH); + + window = new byte[w_size*2]; + prev = new short[w_size]; + head = new short[hash_size]; + + lit_bufsize = 1 << (memLevel + 6); // 16K elements by default + + // We overlay pending_buf and d_buf+l_buf. This works since the average + // output size for (length,distance) codes is <= 24 bits. + pending_buf = new byte[lit_bufsize*4]; + pending_buf_size = lit_bufsize*4; + + d_buf = lit_bufsize/2; + l_buf = (1+2)*lit_bufsize; + + this.level = level; + + //System.out.println("level="+level); + + this.strategy = strategy; + this.method = (byte)method; + + return deflateReset(strm); + } + + internal int deflateReset(ZStream strm){ + strm.total_in = strm.total_out = 0; + strm.msg = null; // + strm.data_type = Z_UNKNOWN; + + pending = 0; + pending_out = 0; + + if(noheader < 0) { + noheader = 0; // was set to -1 by deflate(..., Z_FINISH); + } + status = (noheader!=0) ? BUSY_STATE : INIT_STATE; + strm.adler=strm._adler.adler32(0, null, 0, 0); + + last_flush = Z_NO_FLUSH; + + tr_init(); + lm_init(); + return Z_OK; + } + + internal int deflateEnd(){ + if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){ + return Z_STREAM_ERROR; + } + // Deallocate in reverse order of allocations: + pending_buf=null; + head=null; + prev=null; + window=null; + // free + // dstate=null; + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; + } + + internal int deflateParams(ZStream strm, int _level, int _strategy){ + int err=Z_OK; + + if(_level == Z_DEFAULT_COMPRESSION){ + _level = 6; + } + if(_level < 0 || _level > 9 || + _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + if(config_table[level].func!=config_table[_level].func && + strm.total_in != 0) { + // Flush the last buffer: + err = strm.deflate(Z_PARTIAL_FLUSH); + } + + if(level != _level) { + level = _level; + max_lazy_match = config_table[level].max_lazy; + good_match = config_table[level].good_length; + nice_match = config_table[level].nice_length; + max_chain_length = config_table[level].max_chain; + } + strategy = _strategy; + return err; + } + + internal int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){ + int length = dictLength; + int index=0; + + if(dictionary == null || status != INIT_STATE) + return Z_STREAM_ERROR; + + strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength); + + if(length < MIN_MATCH) return Z_OK; + if(length > w_size-MIN_LOOKAHEAD){ + length = w_size-MIN_LOOKAHEAD; + index=dictLength-length; // use the tail of the dictionary + } + System.Array.Copy(dictionary, index, window, 0, length); + strstart = length; + block_start = length; + + // Insert all strings in the hash table (except for the last two bytes). + // s->lookahead stays null, so s->ins_h will be recomputed at the next + // call of fill_window. + + ins_h = window[0]&0xff; + ins_h=(((ins_h)<Z_FINISH || flush<0){ + return Z_STREAM_ERROR; + } + + if(strm.next_out == null || + (strm.next_in == null && strm.avail_in != 0) || + (status == FINISH_STATE && flush != Z_FINISH)) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)]; + return Z_STREAM_ERROR; + } + if(strm.avail_out == 0){ + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + this.strm = strm; // just in case + old_flush = last_flush; + last_flush = flush; + + // Write the zlib header + if(status == INIT_STATE) { + int header = (Z_DEFLATED+((w_bits-8)<<4))<<8; + int level_flags=((level-1)&0xff)>>1; + + if(level_flags>3) level_flags=3; + header |= (level_flags<<6); + if(strstart!=0) header |= PRESET_DICT; + header+=31-(header % 31); + + status=BUSY_STATE; + putShortMSB(header); + + + // Save the adler32 of the preset dictionary: + if(strstart!=0){ + putShortMSB((int)(strm.adler>>16)); + putShortMSB((int)(strm.adler&0xffff)); + } + strm.adler=strm._adler.adler32(0, null, 0, 0); + } + + // Flush as much pending output as possible + if(pending != 0) { + strm.flush_pending(); + if(strm.avail_out == 0) { + //System.out.println(" avail_out==0"); + // Since avail_out is 0, deflate will be called again with + // more output space, but possibly with both pending and + // avail_in equal to zero. There won't be anything to do, + // but this is not an error situation so make sure we + // return OK instead of BUF_ERROR at next call of deflate: + last_flush = -1; + return Z_OK; + } + + // Make sure there is something to do and avoid duplicate consecutive + // flushes. For repeated and useless calls with Z_FINISH, we keep + // returning Z_STREAM_END instead of Z_BUFF_ERROR. + } + else if(strm.avail_in==0 && flush <= old_flush && + flush != Z_FINISH) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // User must not provide more input after the first FINISH: + if(status == FINISH_STATE && strm.avail_in != 0) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // Start a new block or continue the current one. + if(strm.avail_in!=0 || lookahead!=0 || + (flush != Z_NO_FLUSH && status != FINISH_STATE)) { + int bstate=-1; + switch(config_table[level].func){ + case STORED: + bstate = deflate_stored(flush); + break; + case FAST: + bstate = deflate_fast(flush); + break; + case SLOW: + bstate = deflate_slow(flush); + break; + default: + break; + } + + if (bstate==FinishStarted || bstate==FinishDone) { + status = FINISH_STATE; + } + if (bstate==NeedMore || bstate==FinishStarted) { + if(strm.avail_out == 0) { + last_flush = -1; // avoid BUF_ERROR next call, see above + } + return Z_OK; + // If flush != Z_NO_FLUSH && avail_out == 0, the next call + // of deflate should use the same flush parameter to make sure + // that the flush is complete. So we don't have to output an + // empty block here, this will be done at next call. This also + // ensures that for a very small output buffer, we emit at most + // one empty block. + } + + if (bstate==BlockDone) { + if(flush == Z_PARTIAL_FLUSH) { + _tr_align(); + } + else { // FULL_FLUSH or SYNC_FLUSH + _tr_stored_block(0, 0, false); + // For a full flush, this empty block will be recognized + // as a special marker by inflate_sync(). + if(flush == Z_FULL_FLUSH) { + //state.head[s.hash_size-1]=0; + for(int i=0; i>16)); + putShortMSB((int)(strm.adler&0xffff)); + strm.flush_pending(); + + // If avail_out is zero, the application will call deflate again + // to flush the rest. + noheader = -1; // write the trailer only once! + return pending != 0 ? Z_OK : Z_STREAM_END; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/zlib/InfBlocks.cs b/iTechSharp/srcbc/util/zlib/InfBlocks.cs new file mode 100644 index 0000000..ad7d4b2 --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/InfBlocks.cs @@ -0,0 +1,618 @@ +using System; +/* + * $Id: InfBlocks.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace Org.BouncyCastle.Utilities.Zlib { + + internal sealed class InfBlocks{ + private const int MANY=1440; + + // And'ing with mask[n] masks the lower n bits + private static readonly int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + // Table for deflate from PKZIP's appnote.txt. + static readonly int[] border = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int TYPE=0; // get type bits (3, including end bit) + private const int LENS=1; // get lengths for stored + private const int STORED=2;// processing stored block + private const int TABLE=3; // get table lengths + private const int BTREE=4; // get bit lengths tree for a dynamic block + private const int DTREE=5; // get length, distance trees for a dynamic block + private const int CODES=6; // processing fixed or dynamic block + private const int DRY=7; // output remaining window bytes + private const int DONE=8; // finished last block, done + private const int BAD=9; // ot a data error--stuck here + + internal int mode; // current inflate_block mode + + internal int left; // if STORED, bytes left to copy + + internal int table; // table lengths (14 bits) + internal int index; // index into blens (or border) + internal int[] blens; // bit lengths of codes + internal int[] bb=new int[1]; // bit length tree depth + internal int[] tb=new int[1]; // bit length decoding tree + + internal InfCodes codes=new InfCodes(); // if CODES, current state + + int last; // true if this block is the last block + + // mode independent information + internal int bitk; // bits in bit buffer + internal int bitb; // bit buffer + internal int[] hufts; // single malloc for tree space + internal byte[] window; // sliding window + internal int end; // one byte after sliding window + internal int read; // window read pointer + internal int write; // window write pointer + internal Object checkfn; // check function + internal long check; // check on output + + internal InfTree inftree=new InfTree(); + + internal InfBlocks(ZStream z, Object checkfn, int w){ + hufts=new int[MANY*3]; + window=new byte[w]; + end=w; + this.checkfn = checkfn; + mode = TYPE; + reset(z, null); + } + + internal void reset(ZStream z, long[] c){ + if(c!=null) c[0]=check; + if(mode==BTREE || mode==DTREE){ + } + if(mode==CODES){ + codes.free(z); + } + mode=TYPE; + bitk=0; + bitb=0; + read=write=0; + + if(checkfn != null) + z.adler=check=z._adler.adler32(0L, null, 0, 0); + } + + internal int proc(ZStream z, int r){ + int t; // temporary storage + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; { // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} { + q=write;m=(int)(q> 1){ + case 0: { // stored + b>>=(3);k-=(3);} + t = k & 7; { // go to byte boundary + + b>>=(t);k-=(t);} + mode = LENS; // get length of stored block + break; + case 1: { // fixed + int[] bl=new int[1]; + int[] bd=new int[1]; + int[][] tl=new int[1][]; + int[][] td=new int[1][]; + + InfTree.inflate_trees_fixed(bl, bd, tl, td, z); + codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z); + } { + + b>>=(3);k-=(3);} + + mode = CODES; + break; + case 2: { // dynamic + + b>>=(3);k-=(3);} + + mode = TABLE; + break; + case 3: { // illegal + + b>>=(3);k-=(3);} + mode = BAD; + z.msg = "invalid block type"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + break; + case LENS: + + while(k<(32)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<> 16) & 0xffff) != (b & 0xffff)){ + mode = BAD; + z.msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE); + break; + case STORED: + if (n == 0){ + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + if(m==0){ + if(q==end&&read!=0){ + q=0; m=(int)(qn) t = n; + if(t>m) t = m; + System.Array.Copy(z.next_in, p, window, q, t); + p += t; n -= t; + q += t; m -= t; + if ((left -= t) != 0) + break; + mode = last!=0 ? DRY : TYPE; + break; + case TABLE: + + while(k<(14)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)< 29 || ((t >> 5) & 0x1f) > 29) { + mode = BAD; + z.msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if(blens==null || blens.Length>=(14);k-=(14);} + + index = 0; + mode = BTREE; + goto case BTREE; + case BTREE: + while (index < 4 + (table >> 10)){ + while(k<(3)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(3);k-=(3);} + } + + while(index < 19){ + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); + if (t != Z_OK){ + r = t; + if (r == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + index = 0; + mode = DTREE; + goto case DTREE; + case DTREE: + while (true){ + t = table; + if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){ + break; + } + + int i, j, c; + + t = bb[0]; + + while(k<(t)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(t);k-=(t); + blens[index++] = c; + } + else { // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + + while(k<(t+i)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(t);k-=(t); + + j += (b & inflate_mask[i]); + + b>>=(i);k-=(i); + + i = index; + t = table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)){ + blens=null; + mode = BAD; + z.msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + c = c == 16 ? blens[i-1] : 0; + do{ + blens[i++] = c; + } + while (--j!=0); + index = i; + } + } + + tb[0]=-1; { + int[] bl=new int[1]; + int[] bd=new int[1]; + int[] tl=new int[1]; + int[] td=new int[1]; + bl[0] = 9; // must be <= 9 for lookahead assumptions + bd[0] = 6; // must be <= 9 for lookahead assumptions + + t = table; + t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), + 1 + ((t >> 5) & 0x1f), + blens, bl, bd, tl, td, hufts, z); + + if (t != Z_OK){ + if (t == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + r = t; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z); + } + mode = CODES; + goto case CODES; + case CODES: + bitb=b; bitk=k; + z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + + if ((r = codes.proc(this, z, r)) != Z_STREAM_END){ + return inflate_flush(z, r); + } + r = Z_OK; + codes.free(z); + + p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk; + q=write;m=(int)(q z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(checkfn != null) + z.adler=check=z._adler.adler32(check, window, q, n); + + // copy as far as end of window + System.Array.Copy(window, q, z.next_out, p, n); + p += n; + q += n; + + // see if more to copy at beginning of window + if (q == end){ + // wrap pointers + q = 0; + if (write == end) + write = 0; + + // compute bytes to copy + n = write - q; + if (n > z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(checkfn != null) + z.adler=check=z._adler.adler32(check, window, q, n); + + // copy + System.Array.Copy(window, q, z.next_out, p, n); + p += n; + q += n; + } + + // update pointers + z.next_out_index = p; + read = q; + + // done + return r; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/zlib/InfCodes.cs b/iTechSharp/srcbc/util/zlib/InfCodes.cs new file mode 100644 index 0000000..d15dc16 --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/InfCodes.cs @@ -0,0 +1,611 @@ +using System; +/* + * $Id: InfCodes.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace Org.BouncyCastle.Utilities.Zlib { + + internal sealed class InfCodes{ + + private static readonly int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + private const int START=0; // x: set up for LEN + private const int LEN=1; // i: get length/literal/eob next + private const int LENEXT=2; // i: getting length extra (have base) + private const int DIST=3; // i: get distance next + private const int DISTEXT=4;// i: getting distance extra + private const int COPY=5; // o: copying bytes in window, waiting for space + private const int LIT=6; // o: got literal, waiting for output space + private const int WASH=7; // o: got eob, possibly still output waiting + private const int END=8; // x: got eob and all data flushed + private const int BADCODE=9;// x: got error + + int mode; // current inflate_codes mode + + // mode dependent information + int len; + + int[] tree; // pointer into tree + int tree_index=0; + int need; // bits needed + + int lit; + + // if EXT or COPY, where and how much + int get; // bits to get for extra + int dist; // distance back to copy from + + byte lbits; // ltree bits decoded per branch + byte dbits; // dtree bits decoder per branch + int[] ltree; // literal/length/eob tree + int ltree_index; // literal/length/eob tree + int[] dtree; // distance tree + int dtree_index; // distance tree + + internal InfCodes(){ + } + internal void init(int bl, int bd, + int[] tl, int tl_index, + int[] td, int td_index, ZStream z){ + mode=START; + lbits=(byte)bl; + dbits=(byte)bd; + ltree=tl; + ltree_index=tl_index; + dtree = td; + dtree_index=td_index; + tree=null; + } + + internal int proc(InfBlocks s, ZStream z, int r){ + int j; // temporary storage + int tindex; // temporary pointer + int e; // extra bits or operation + int b=0; // bit buffer + int k=0; // bits in bit buffer + int p=0; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int f; // pointer to copy strings from + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q= 258 && n >= 10){ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + r = inflate_fast(lbits, dbits, + ltree, ltree_index, + dtree, dtree_index, + s, z); + + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q>=(tree[tindex+1]); + k-=(tree[tindex+1]); + + e=tree[tindex]; + + if(e == 0){ // literal + lit = tree[tindex+2]; + mode = LIT; + break; + } + if((e & 16)!=0 ){ // length + get = e & 15; + len = tree[tindex+2]; + mode = LENEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3+tree[tindex+2]; + break; + } + if ((e & 32)!=0){ // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + + case LENEXT: // i: getting length extra (have base) + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + need = dbits; + tree = dtree; + tree_index=dtree_index; + mode = DIST; + goto case DIST; + case DIST: // i: get distance next + j = need; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1]; + k-=tree[tindex+1]; + + e = (tree[tindex]); + if((e & 16)!=0){ // distance + get = e & 15; + dist = tree[tindex+2]; + mode = DISTEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3 + tree[tindex+2]; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid distance code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + + case DISTEXT: // i: getting distance extra + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + mode = COPY; + goto case COPY; + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while(f < 0){ // modulo window size-"while" instead + f += s.end; // of "if" handles invalid distances + } + while (len!=0){ + + if(m==0){ + if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + s.write=q; r=s.inflate_flush(z,r); + q=s.write;m=q= 258 && n >= 10 + // get literal/length code + while(k<(20)){ // max bits for literal/length code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++] = (byte)tp[tp_index_t_3+2]; + m--; + continue; + } + do { + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + e &= 15; + c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]); + + b>>=e; k-=e; + + // decode distance base of block to copy + while(k<(15)){ // max bits for distance code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + // get extra bits to add to distance base + e &= 15; + while(k<(e)){ // get extra bits (up to 13) + n--; + b|=(z.next_in[p++]&0xff)<>=(e); k-=(e); + + // do the copy + m -= c; + if (q >= d){ // offset before dest + // just copy + r=q-d; + if(q-r>0 && 2>(q-r)){ + s.window[q++]=s.window[r++]; // minimum count is three, + s.window[q++]=s.window[r++]; // so unroll loop a little + c-=2; + } + else{ + System.Array.Copy(s.window, r, s.window, q, 2); + q+=2; r+=2; c-=2; + } + } + else{ // else offset after destination + r=q-d; + do{ + r+=s.end; // force pointer in window + }while(r<0); // covers invalid distances + e=s.end-r; + if(c>e){ // if source crosses, + c-=e; // wrapped copy + if(q-r>0 && e>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--e!=0); + } + else{ + System.Array.Copy(s.window, r, s.window, q, e); + q+=e; r+=e; e=0; + } + r = 0; // copy rest from start of window + } + + } + + // copy all or what's left + if(q-r>0 && c>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--c!=0); + } + else{ + System.Array.Copy(s.window, r, s.window, q, c); + q+=c; r+=c; c=0; + } + break; + } + else if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + e=tp[tp_index_t_3]; + } + else{ + z.msg = "invalid distance code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + break; + } + + if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + if((e=tp[tp_index_t_3])==0){ + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++]=(byte)tp[tp_index_t_3+2]; + m--; + break; + } + } + else if((e&32)!=0){ + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_STREAM_END; + } + else{ + z.msg="invalid literal/length code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + } + while(m>=258 && n>= 10); + + // not enough input or output--restore pointers and return + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_OK; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/zlib/InfTree.cs b/iTechSharp/srcbc/util/zlib/InfTree.cs new file mode 100644 index 0000000..6fc8175 --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/InfTree.cs @@ -0,0 +1,523 @@ +using System; +/* + * $Id: InfTree.cs,v 1.2 2008/05/12 15:24:47 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace Org.BouncyCastle.Utilities.Zlib { + + internal sealed class InfTree{ + + private const int MANY=1440; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int fixed_bl = 9; + private const int fixed_bd = 5; + + static readonly int[] fixed_tl = { + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,192, + 80,7,10, 0,8,96, 0,8,32, 0,9,160, + 0,8,0, 0,8,128, 0,8,64, 0,9,224, + 80,7,6, 0,8,88, 0,8,24, 0,9,144, + 83,7,59, 0,8,120, 0,8,56, 0,9,208, + 81,7,17, 0,8,104, 0,8,40, 0,9,176, + 0,8,8, 0,8,136, 0,8,72, 0,9,240, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,200, + 81,7,13, 0,8,100, 0,8,36, 0,9,168, + 0,8,4, 0,8,132, 0,8,68, 0,9,232, + 80,7,8, 0,8,92, 0,8,28, 0,9,152, + 84,7,83, 0,8,124, 0,8,60, 0,9,216, + 82,7,23, 0,8,108, 0,8,44, 0,9,184, + 0,8,12, 0,8,140, 0,8,76, 0,9,248, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,196, + 81,7,11, 0,8,98, 0,8,34, 0,9,164, + 0,8,2, 0,8,130, 0,8,66, 0,9,228, + 80,7,7, 0,8,90, 0,8,26, 0,9,148, + 84,7,67, 0,8,122, 0,8,58, 0,9,212, + 82,7,19, 0,8,106, 0,8,42, 0,9,180, + 0,8,10, 0,8,138, 0,8,74, 0,9,244, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,204, + 81,7,15, 0,8,102, 0,8,38, 0,9,172, + 0,8,6, 0,8,134, 0,8,70, 0,9,236, + 80,7,9, 0,8,94, 0,8,30, 0,9,156, + 84,7,99, 0,8,126, 0,8,62, 0,9,220, + 82,7,27, 0,8,110, 0,8,46, 0,9,188, + 0,8,14, 0,8,142, 0,8,78, 0,9,252, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,194, + 80,7,10, 0,8,97, 0,8,33, 0,9,162, + 0,8,1, 0,8,129, 0,8,65, 0,9,226, + 80,7,6, 0,8,89, 0,8,25, 0,9,146, + 83,7,59, 0,8,121, 0,8,57, 0,9,210, + 81,7,17, 0,8,105, 0,8,41, 0,9,178, + 0,8,9, 0,8,137, 0,8,73, 0,9,242, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,202, + 81,7,13, 0,8,101, 0,8,37, 0,9,170, + 0,8,5, 0,8,133, 0,8,69, 0,9,234, + 80,7,8, 0,8,93, 0,8,29, 0,9,154, + 84,7,83, 0,8,125, 0,8,61, 0,9,218, + 82,7,23, 0,8,109, 0,8,45, 0,9,186, + 0,8,13, 0,8,141, 0,8,77, 0,9,250, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,198, + 81,7,11, 0,8,99, 0,8,35, 0,9,166, + 0,8,3, 0,8,131, 0,8,67, 0,9,230, + 80,7,7, 0,8,91, 0,8,27, 0,9,150, + 84,7,67, 0,8,123, 0,8,59, 0,9,214, + 82,7,19, 0,8,107, 0,8,43, 0,9,182, + 0,8,11, 0,8,139, 0,8,75, 0,9,246, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,206, + 81,7,15, 0,8,103, 0,8,39, 0,9,174, + 0,8,7, 0,8,135, 0,8,71, 0,9,238, + 80,7,9, 0,8,95, 0,8,31, 0,9,158, + 84,7,99, 0,8,127, 0,8,63, 0,9,222, + 82,7,27, 0,8,111, 0,8,47, 0,9,190, + 0,8,15, 0,8,143, 0,8,79, 0,9,254, + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,193, + + 80,7,10, 0,8,96, 0,8,32, 0,9,161, + 0,8,0, 0,8,128, 0,8,64, 0,9,225, + 80,7,6, 0,8,88, 0,8,24, 0,9,145, + 83,7,59, 0,8,120, 0,8,56, 0,9,209, + 81,7,17, 0,8,104, 0,8,40, 0,9,177, + 0,8,8, 0,8,136, 0,8,72, 0,9,241, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,201, + 81,7,13, 0,8,100, 0,8,36, 0,9,169, + 0,8,4, 0,8,132, 0,8,68, 0,9,233, + 80,7,8, 0,8,92, 0,8,28, 0,9,153, + 84,7,83, 0,8,124, 0,8,60, 0,9,217, + 82,7,23, 0,8,108, 0,8,44, 0,9,185, + 0,8,12, 0,8,140, 0,8,76, 0,9,249, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,197, + 81,7,11, 0,8,98, 0,8,34, 0,9,165, + 0,8,2, 0,8,130, 0,8,66, 0,9,229, + 80,7,7, 0,8,90, 0,8,26, 0,9,149, + 84,7,67, 0,8,122, 0,8,58, 0,9,213, + 82,7,19, 0,8,106, 0,8,42, 0,9,181, + 0,8,10, 0,8,138, 0,8,74, 0,9,245, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,205, + 81,7,15, 0,8,102, 0,8,38, 0,9,173, + 0,8,6, 0,8,134, 0,8,70, 0,9,237, + 80,7,9, 0,8,94, 0,8,30, 0,9,157, + 84,7,99, 0,8,126, 0,8,62, 0,9,221, + 82,7,27, 0,8,110, 0,8,46, 0,9,189, + 0,8,14, 0,8,142, 0,8,78, 0,9,253, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,195, + 80,7,10, 0,8,97, 0,8,33, 0,9,163, + 0,8,1, 0,8,129, 0,8,65, 0,9,227, + 80,7,6, 0,8,89, 0,8,25, 0,9,147, + 83,7,59, 0,8,121, 0,8,57, 0,9,211, + 81,7,17, 0,8,105, 0,8,41, 0,9,179, + 0,8,9, 0,8,137, 0,8,73, 0,9,243, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,203, + 81,7,13, 0,8,101, 0,8,37, 0,9,171, + 0,8,5, 0,8,133, 0,8,69, 0,9,235, + 80,7,8, 0,8,93, 0,8,29, 0,9,155, + 84,7,83, 0,8,125, 0,8,61, 0,9,219, + 82,7,23, 0,8,109, 0,8,45, 0,9,187, + 0,8,13, 0,8,141, 0,8,77, 0,9,251, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,199, + 81,7,11, 0,8,99, 0,8,35, 0,9,167, + 0,8,3, 0,8,131, 0,8,67, 0,9,231, + 80,7,7, 0,8,91, 0,8,27, 0,9,151, + 84,7,67, 0,8,123, 0,8,59, 0,9,215, + 82,7,19, 0,8,107, 0,8,43, 0,9,183, + 0,8,11, 0,8,139, 0,8,75, 0,9,247, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,207, + 81,7,15, 0,8,103, 0,8,39, 0,9,175, + 0,8,7, 0,8,135, 0,8,71, 0,9,239, + 80,7,9, 0,8,95, 0,8,31, 0,9,159, + 84,7,99, 0,8,127, 0,8,63, 0,9,223, + 82,7,27, 0,8,111, 0,8,47, 0,9,191, + 0,8,15, 0,8,143, 0,8,79, 0,9,255 + }; + static readonly int[] fixed_td = { + 80,5,1, 87,5,257, 83,5,17, 91,5,4097, + 81,5,5, 89,5,1025, 85,5,65, 93,5,16385, + 80,5,3, 88,5,513, 84,5,33, 92,5,8193, + 82,5,9, 90,5,2049, 86,5,129, 192,5,24577, + 80,5,2, 87,5,385, 83,5,25, 91,5,6145, + 81,5,7, 89,5,1537, 85,5,97, 93,5,24577, + 80,5,4, 88,5,769, 84,5,49, 92,5,12289, + 82,5,13, 90,5,3073, 86,5,193, 192,5,24577 + }; + + // Tables for deflate from PKZIP's appnote.txt. + static readonly int[] cplens = { // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + + // see note #13 above about 258 + static readonly int[] cplext = { // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid + }; + + static readonly int[] cpdist = { // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + + static readonly int[] cpdext = { // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + const int BMAX=15; // maximum bit length of any code + + int[] hn = null; // hufts used in space + int[] v = null; // work area for huft_build + int[] c = null; // bit length count table + int[] r = null; // table entry for structure assignment + int[] u = null; // table stack + int[] x = null; // bit offsets, then code stack + + private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX) + int bindex, + int n, // number of codes (assumed <= 288) + int s, // number of simple-valued codes (0..s-1) + int[] d, // list of base values for non-simple codes + int[] e, // list of extra bits for non-simple codes + int[] t, // result: starting table + int[] m, // maximum lookup bits, returns actual + int[] hp,// space for trees + int[] hn,// hufts used in space + int[] v // working area: values in order of bit length + ){ + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + // lengths), or Z_MEM_ERROR if not enough memory. + + int a; // counter for codes of length k + int f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + int i; // counter, current code + int j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + int mask; // (1 << w) - 1, to avoid cc -O bug on HP + int p; // pointer into c[], b[], or v[] + int q; // points to current table + int w; // bits before this table == (l * h) + int xp; // pointer into x + int y; // number of dummy codes added + int z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; i = n; + do { + c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX + }while(i!=0); + + if(c[0] == n){ // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } + + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) + if(c[j]!=0) break; + k = j; // minimum code length + if(l < j){ + l = j; + } + for (i = BMAX; i!=0; i--){ + if(c[i]!=0) break; + } + g = i; // maximum code length + if(l > i){ + l = i; + } + m[0] = l; + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1){ + if ((y -= c[j]) < 0){ + return Z_DATA_ERROR; + } + } + if ((y -= c[i]) < 0){ + return Z_DATA_ERROR; + } + c[i] += y; + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; xp = 2; + while (--i!=0) { // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; p = 0; + do { + if ((j = b[bindex+p]) != 0){ + v[x[j]++] = i; + } + p++; + } + while (++i < n); + n = x[g]; // set n to length of v + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++){ + a = c[k]; + while (a--!=0){ + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l){ + h++; + w += l; // previous table always l bits + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if((f=1<<(j=k-w))>a+1){ // try a k-w bit table + // too few codes for k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = k; + if(j < z){ + while (++j < z){ // try smaller tables up to z bits + if((f <<= 1) <= c[++xp]) + break; // enough codes to use up j bits + f -= c[xp]; // else deduct codes from patterns + } + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (hn[0] + z > MANY){ // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + } + u[h] = q = /*hp+*/ hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if(h!=0){ + x[h]=i; // save pattern for backing up + r[0]=(byte)j; // bits in this table + r[1]=(byte)l; // bits to dump before this table + j=i>>(w - l); + r[2] = (int)(q - u[h-1] - j); // offset to this table + System.Array.Copy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table + } + else{ + t[0] = q; // first table is returned result + } + } + + // set up table entry in r + r[1] = (byte)(k - w); + if (p >= n){ + r[0] = 128 + 64; // out of values--invalid code + } + else if (v[p] < s){ + r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block + r[2] = v[p++]; // simple code is just the value + } + else{ + r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists + r[2]=d[v[p++] - s]; + } + + // fill code-like entries with r + f=1<<(k-w); + for (j=i>>w;j>= 1){ + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]){ + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + + internal int inflate_trees_bits(int[] c, // 19 code lengths + int[] bb, // bits tree desired/actual depth + int[] tb, // bits tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + initWorkArea(19); + hn[0]=0; + result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed dynamic bit lengths tree"; + } + else if(result == Z_BUF_ERROR || bb[0] == 0){ + z.msg = "incomplete dynamic bit lengths tree"; + result = Z_DATA_ERROR; + } + return result; + } + + internal int inflate_trees_dynamic(int nl, // number of literal/length codes + int nd, // number of distance codes + int[] c, // that many (total) code lengths + int[] bl, // literal desired/actual bit depth + int[] bd, // distance desired/actual bit depth + int[] tl, // literal/length tree result + int[] td, // distance tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + + // build literal/length tree + initWorkArea(288); + hn[0]=0; + result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); + if (result != Z_OK || bl[0] == 0){ + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed literal/length tree"; + } + else if (result != Z_MEM_ERROR){ + z.msg = "incomplete literal/length tree"; + result = Z_DATA_ERROR; + } + return result; + } + + // build distance tree + initWorkArea(288); + result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); + + if (result != Z_OK || (bd[0] == 0 && nl > 257)){ + if (result == Z_DATA_ERROR){ + z.msg = "oversubscribed distance tree"; + } + else if (result == Z_BUF_ERROR) { + z.msg = "incomplete distance tree"; + result = Z_DATA_ERROR; + } + else if (result != Z_MEM_ERROR){ + z.msg = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; + } + + return Z_OK; + } + + internal static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth + int[] bd, //distance desired/actual bit depth + int[][] tl,//literal/length tree result + int[][] td,//distance tree result + ZStream z //for memory allocation + ){ + bl[0]=fixed_bl; + bd[0]=fixed_bd; + tl[0]=fixed_tl; + td[0]=fixed_td; + return Z_OK; + } + + private void initWorkArea(int vsize){ + if(hn==null){ + hn=new int[1]; + v=new int[vsize]; + c=new int[BMAX+1]; + r=new int[3]; + u=new int[BMAX]; + x=new int[BMAX+1]; + } + if(v.Lengthstate); + return Z_OK; + } + + internal int inflateInit(ZStream z, int w){ + z.msg = null; + blocks = null; + + // handle undocumented nowrap option (no zlib header or check) + nowrap = 0; + if(w < 0){ + w = - w; + nowrap = 1; + } + + // set window size + if(w<8 ||w>15){ + inflateEnd(z); + return Z_STREAM_ERROR; + } + wbits=w; + + z.istate.blocks=new InfBlocks(z, + z.istate.nowrap!=0 ? null : this, + 1<>4)+8>z.istate.wbits){ + z.istate.mode = BAD; + z.msg="invalid window size"; + z.istate.marker = 5; // can't try inflateSync + break; + } + z.istate.mode=FLAG; + goto case FLAG; + case FLAG: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + b = (z.next_in[z.next_in_index++])&0xff; + + if((((z.istate.method << 8)+b) % 31)!=0){ + z.istate.mode = BAD; + z.msg = "incorrect header check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + if((b&PRESET_DICT)==0){ + z.istate.mode = BLOCKS; + break; + } + z.istate.mode = DICT4; + goto case DICT4; + case DICT4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + z.istate.mode=DICT3; + goto case DICT3; + case DICT3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + z.istate.mode=DICT2; + goto case DICT2; + case DICT2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + z.istate.mode=DICT1; + goto case DICT1; + case DICT1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need += (z.next_in[z.next_in_index++]&0xffL); + z.adler = z.istate.need; + z.istate.mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z.istate.mode = BAD; + z.msg = "need dictionary"; + z.istate.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case BLOCKS: + + r = z.istate.blocks.proc(z, r); + if(r == Z_DATA_ERROR){ + z.istate.mode = BAD; + z.istate.marker = 0; // can try inflateSync + break; + } + if(r == Z_OK){ + r = f; + } + if(r != Z_STREAM_END){ + return r; + } + r = f; + z.istate.blocks.reset(z, z.istate.was); + if(z.istate.nowrap!=0){ + z.istate.mode=DONE; + break; + } + z.istate.mode=CHECK4; + goto case CHECK4; + case CHECK4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + z.istate.mode=CHECK3; + goto case CHECK3; + case CHECK3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + z.istate.mode = CHECK2; + goto case CHECK2; + case CHECK2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + z.istate.mode = CHECK1; + goto case CHECK1; + case CHECK1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=(z.next_in[z.next_in_index++]&0xffL); + + if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){ + z.istate.mode = BAD; + z.msg = "incorrect data check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + z.istate.mode = DONE; + goto case DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + } + } + + + internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){ + int index=0; + int length = dictLength; + if(z==null || z.istate == null|| z.istate.mode != DICT0) + return Z_STREAM_ERROR; + + if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){ + return Z_DATA_ERROR; + } + + z.adler = z._adler.adler32(0, null, 0, 0); + + if(length >= (1<>7)]); + } + + internal short[] dyn_tree; // the dynamic tree + internal int max_code; // largest code with non zero frequency + internal StaticTree stat_desc; // the corresponding static tree + + // Compute the optimal bit lengths for a tree and update the total bit length + // for the current block. + // IN assertion: the fields freq and dad are set, heap[heap_max] and + // above are the tree nodes sorted by increasing frequency. + // OUT assertions: the field len is set to the optimal bit length, the + // array bl_count contains the frequencies for each bit length. + // The length opt_len is updated; static_len is also updated if stree is + // not null. + internal void gen_bitlen(Deflate s){ + short[] tree = dyn_tree; + short[] stree = stat_desc.static_tree; + int[] extra = stat_desc.extra_bits; + int based = stat_desc.extra_base; + int max_length = stat_desc.max_length; + int h; // heap index + int n, m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + short f; // frequency + int overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0; + + // In a first pass, compute the optimal bit lengths (which may + // overflow in the case of the bit length tree). + tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap + + for(h=s.heap_max+1; h max_length){ bits = max_length; overflow++; } + tree[n*2+1] = (short)bits; + // We overwrite tree[n*2+1] which is no longer needed + + if (n > max_code) continue; // not a leaf node + + s.bl_count[bits]++; + xbits = 0; + if (n >= based) xbits = extra[n-based]; + f = tree[n*2]; + s.opt_len += f * (bits + xbits); + if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits); + } + if (overflow == 0) return; + + // This happens for example on obj2 and pic of the Calgary corpus + // Find the first bit length which could increase: + do { + bits = max_length-1; + while(s.bl_count[bits]==0) bits--; + s.bl_count[bits]--; // move one leaf down the tree + s.bl_count[bits+1]+=2; // move one overflow item as its brother + s.bl_count[max_length]--; + // The brother of the overflow item also moves one step up, + // but this does not affect bl_count[max_length] + overflow -= 2; + } + while (overflow > 0); + + for (bits = max_length; bits != 0; bits--) { + n = s.bl_count[bits]; + while (n != 0) { + m = s.heap[--h]; + if (m > max_code) continue; + if (tree[m*2+1] != bits) { + s.opt_len += (int)(((long)bits - (long)tree[m*2+1])*(long)tree[m*2]); + tree[m*2+1] = (short)bits; + } + n--; + } + } + } + + // Construct one Huffman tree and assigns the code bit strings and lengths. + // Update the total bit length for the current block. + // IN assertion: the field freq is set for all tree elements. + // OUT assertions: the fields len and code are set to the optimal bit length + // and corresponding code. The length opt_len is updated; static_len is + // also updated if stree is not null. The field max_code is set. + internal void build_tree(Deflate s){ + short[] tree=dyn_tree; + short[] stree=stat_desc.static_tree; + int elems=stat_desc.elems; + int n, m; // iterate over heap elements + int max_code=-1; // largest code with non zero frequency + int node; // new node being created + + // Construct the initial heap, with least frequent element in + // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + // heap[0] is not used. + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for(n=0; n=1; n--) + s.pqdownheap(tree, n); + + // Construct the Huffman tree by repeatedly combining the least two + // frequent nodes. + + node=elems; // next internal node of the tree + do{ + // n = node of least frequency + n=s.heap[1]; + s.heap[1]=s.heap[s.heap_len--]; + s.pqdownheap(tree, 1); + m=s.heap[1]; // m = node of next least frequency + + s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency + s.heap[--s.heap_max] = m; + + // Create a new node father of n and m + tree[node*2] = (short)(tree[n*2] + tree[m*2]); + s.depth[node] = (byte)(System.Math.Max(s.depth[n],s.depth[m])+1); + tree[n*2+1] = tree[m*2+1] = (short)node; + + // and insert the new node in the heap + s.heap[1] = node++; + s.pqdownheap(tree, 1); + } + while(s.heap_len>=2); + + s.heap[--s.heap_max] = s.heap[1]; + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + + gen_bitlen(s); + + // The field len is now set, we can generate the bit codes + gen_codes(tree, max_code, s.bl_count); + } + + // Generate the codes for a given tree and bit counts (which need not be + // optimal). + // IN assertion: the array bl_count contains the bit length statistics for + // the given tree and the field len is set for all tree elements. + // OUT assertion: the field code is set for all tree elements of non + // zero code length. + internal static void gen_codes(short[] tree, // the tree to decorate + int max_code, // largest code with non zero frequency + short[] bl_count // number of codes at each bit length + ){ + short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length + short code = 0; // running code value + int bits; // bit index + int n; // code index + + // The distribution counts are first used to generate the code values + // without bit reversal. + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1); + } + + // Check that the bit counts in bl_count are consistent. The last code + // must be all ones. + //Assert (code + bl_count[MAX_BITS]-1 == (1<>=1; + res<<=1; + } + while(--len>0); + return res>>1; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/util/zlib/ZDeflaterOutputStream.cs b/iTechSharp/srcbc/util/zlib/ZDeflaterOutputStream.cs new file mode 100644 index 0000000..cce013e --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/ZDeflaterOutputStream.cs @@ -0,0 +1,150 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Zlib { + /// + /// Summary description for DeflaterOutputStream. + /// + public class ZDeflaterOutputStream : Stream { + protected ZStream z=new ZStream(); + protected int flushLevel=JZlib.Z_NO_FLUSH; + private const int BUFSIZE = 4192; + protected byte[] buf=new byte[BUFSIZE]; + private byte[] buf1=new byte[1]; + + protected Stream outp; + + public ZDeflaterOutputStream(Stream outp) : this(outp, 6, false) { + } + + public ZDeflaterOutputStream(Stream outp, int level) : this(outp, level, false) { + } + + public ZDeflaterOutputStream(Stream outp, int level, bool nowrap) { + this.outp=outp; + z.deflateInit(level, nowrap); + } + + + public override bool CanRead { + get { + // TODO: Add DeflaterOutputStream.CanRead getter implementation + return false; + } + } + + public override bool CanSeek { + get { + // TODO: Add DeflaterOutputStream.CanSeek getter implementation + return false; + } + } + + public override bool CanWrite { + get { + // TODO: Add DeflaterOutputStream.CanWrite getter implementation + return true; + } + } + + public override long Length { + get { + // TODO: Add DeflaterOutputStream.Length getter implementation + return 0; + } + } + + public override long Position { + get { + // TODO: Add DeflaterOutputStream.Position getter implementation + return 0; + } + set { + // TODO: Add DeflaterOutputStream.Position setter implementation + } + } + + public override void Write(byte[] b, int off, int len) { + if(len==0) + return; + int err; + z.next_in=b; + z.next_in_index=off; + z.avail_in=len; + do{ + z.next_out=buf; + z.next_out_index=0; + z.avail_out=BUFSIZE; + err=z.deflate(flushLevel); + if(err!=JZlib.Z_OK) + throw new IOException("deflating: "+z.msg); + if (z.avail_out < BUFSIZE) + { + outp.Write(buf, 0, BUFSIZE-z.avail_out); + } + } + while(z.avail_in>0 || z.avail_out==0); + } + + public override long Seek(long offset, SeekOrigin origin) { + // TODO: Add DeflaterOutputStream.Seek implementation + return 0; + } + + public override void SetLength(long value) { + // TODO: Add DeflaterOutputStream.SetLength implementation + + } + + public override int Read(byte[] buffer, int offset, int count) { + // TODO: Add DeflaterOutputStream.Read implementation + return 0; + } + + public override void Flush() { + outp.Flush(); + } + + public override void WriteByte(byte b) { + buf1[0]=(byte)b; + Write(buf1, 0, 1); + } + + public void Finish() { + int err; + do{ + z.next_out=buf; + z.next_out_index=0; + z.avail_out=BUFSIZE; + err=z.deflate(JZlib.Z_FINISH); + if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK) + throw new IOException("deflating: "+z.msg); + if(BUFSIZE-z.avail_out>0){ + outp.Write(buf, 0, BUFSIZE-z.avail_out); + } + } + while(z.avail_in>0 || z.avail_out==0); + Flush(); + } + + public void End() { + if(z==null) + return; + z.deflateEnd(); + z.free(); + z=null; + } + + public override void Close() { + try{ + try{Finish();} + catch (IOException) {} + } + finally{ + End(); + outp.Close(); + outp=null; + } + } + } +} diff --git a/iTechSharp/srcbc/util/zlib/ZInflaterInputStream.cs b/iTechSharp/srcbc/util/zlib/ZInflaterInputStream.cs new file mode 100644 index 0000000..375d5df --- /dev/null +++ b/iTechSharp/srcbc/util/zlib/ZInflaterInputStream.cs @@ -0,0 +1,126 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.Zlib { + /// + /// Summary description for DeflaterOutputStream. + /// + public class ZInflaterInputStream : Stream { + protected ZStream z=new ZStream(); + protected int flushLevel=JZlib.Z_NO_FLUSH; + private const int BUFSIZE = 4192; + protected byte[] buf=new byte[BUFSIZE]; + private byte[] buf1=new byte[1]; + + protected Stream inp=null; + private bool nomoreinput=false; + + public ZInflaterInputStream(Stream inp) : this(inp, false) { + } + + public ZInflaterInputStream(Stream inp, bool nowrap) { + this.inp=inp; + z.inflateInit(nowrap); + z.next_in=buf; + z.next_in_index=0; + z.avail_in=0; + } + + public override bool CanRead { + get { + // TODO: Add DeflaterOutputStream.CanRead getter implementation + return true; + } + } + + public override bool CanSeek { + get { + // TODO: Add DeflaterOutputStream.CanSeek getter implementation + return false; + } + } + + public override bool CanWrite { + get { + // TODO: Add DeflaterOutputStream.CanWrite getter implementation + return false; + } + } + + public override long Length { + get { + // TODO: Add DeflaterOutputStream.Length getter implementation + return 0; + } + } + + public override long Position { + get { + // TODO: Add DeflaterOutputStream.Position getter implementation + return 0; + } + set { + // TODO: Add DeflaterOutputStream.Position setter implementation + } + } + + public override void Write(byte[] b, int off, int len) { + } + + public override long Seek(long offset, SeekOrigin origin) { + // TODO: Add DeflaterOutputStream.Seek implementation + return 0; + } + + public override void SetLength(long value) { + // TODO: Add DeflaterOutputStream.SetLength implementation + + } + + public override int Read(byte[] b, int off, int len) { + if(len==0) + return(0); + int err; + z.next_out=b; + z.next_out_index=off; + z.avail_out=len; + do { + if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it + z.next_in_index=0; + z.avail_in=inp.Read(buf, 0, BUFSIZE);//(BUFSIZEnext_out buffer and copying into it. + // (See also read_buf()). + internal void flush_pending(){ + int len=dstate.pending; + + if(len>avail_out) len=avail_out; + if(len==0) return; + + if(dstate.pending_buf.Length<=dstate.pending_out || + next_out.Length<=next_out_index || + dstate.pending_buf.Length<(dstate.pending_out+len) || + next_out.Length<(next_out_index+len)){ + // System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+ + // ", "+next_out.length+", "+next_out_index+", "+len); + // System.out.println("avail_out="+avail_out); + } + + System.Array.Copy(dstate.pending_buf, dstate.pending_out, + next_out, next_out_index, len); + + next_out_index+=len; + dstate.pending_out+=len; + total_out+=len; + avail_out-=len; + dstate.pending-=len; + if(dstate.pending==0){ + dstate.pending_out=0; + } + } + + // Read a new buffer from the current input stream, update the adler32 + // and total number of bytes read. All deflate() input goes through + // this function so some applications may wish to modify it to avoid + // allocating a large strm->next_in buffer and copying from it. + // (See also flush_pending()). + internal int read_buf(byte[] buf, int start, int size) { + int len=avail_in; + + if(len>size) len=size; + if(len==0) return 0; + + avail_in-=len; + + if(dstate.noheader==0) { + adler=_adler.adler32(adler, next_in, next_in_index, len); + } + System.Array.Copy(next_in, next_in_index, buf, start, len); + next_in_index += len; + total_in += len; + return len; + } + + public void free(){ + next_in=null; + next_out=null; + msg=null; + _adler=null; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/x509/AttributeCertificateHolder.cs b/iTechSharp/srcbc/x509/AttributeCertificateHolder.cs new file mode 100644 index 0000000..93c34f4 --- /dev/null +++ b/iTechSharp/srcbc/x509/AttributeCertificateHolder.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.X509 +{ + /// + /// The Holder object. + ///
      + 	/// Holder ::= SEQUENCE {
      + 	///		baseCertificateID   [0] IssuerSerial OPTIONAL,
      + 	///			-- the issuer and serial number of
      + 	///			-- the holder's Public Key Certificate
      + 	///		entityName          [1] GeneralNames OPTIONAL,
      + 	///			-- the name of the claimant or role
      + 	///		objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
      + 	///			-- used to directly authenticate the holder,
      + 	///			-- for example, an executable
      + 	/// }
      +	/// 
      + ///
      + public class AttributeCertificateHolder + //: CertSelector, Selector + : IX509Selector + { + internal readonly Holder holder; + + internal AttributeCertificateHolder( + Asn1Sequence seq) + { + holder = Holder.GetInstance(seq); + } + + public AttributeCertificateHolder( + X509Name issuerName, + BigInteger serialNumber) + { + holder = new Holder( + new IssuerSerial( + GenerateGeneralNames(issuerName), + new DerInteger(serialNumber))); + } + + public AttributeCertificateHolder( + X509Certificate cert) + { + X509Name name; + try + { + name = PrincipalUtilities.GetIssuerX509Principal(cert); + } + catch (Exception e) + { + throw new CertificateParsingException(e.Message); + } + + holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber))); + } + + public AttributeCertificateHolder( + X509Name principal) + { + holder = new Holder(GenerateGeneralNames(principal)); + } + + /** + * Constructs a holder for v2 attribute certificates with a hash value for + * some type of object. + *

      + * digestedObjectType can be one of the following: + *

        + *
      • 0 - publicKey - A hash of the public key of the holder must be + * passed.
      • + *
      • 1 - publicKeyCert - A hash of the public key certificate of the + * holder must be passed.
      • + *
      • 2 - otherObjectDigest - A hash of some other object type must be + * passed. otherObjectTypeID must not be empty.
      • + *
      + *

      + *

      This cannot be used if a v1 attribute certificate is used.

      + * + * @param digestedObjectType The digest object type. + * @param digestAlgorithm The algorithm identifier for the hash. + * @param otherObjectTypeID The object type ID if + * digestedObjectType is + * otherObjectDigest. + * @param objectDigest The hash value. + */ + public AttributeCertificateHolder( + int digestedObjectType, + string digestAlgorithm, + string otherObjectTypeID, + byte[] objectDigest) + { + // TODO Allow 'objectDigest' to be null? + + holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID, + new AlgorithmIdentifier(digestAlgorithm), Arrays.Clone(objectDigest))); + } + + /** + * Returns the digest object type if an object digest info is used. + *

      + *

        + *
      • 0 - publicKey - A hash of the public key of the holder must be + * passed.
      • + *
      • 1 - publicKeyCert - A hash of the public key certificate of the + * holder must be passed.
      • + *
      • 2 - otherObjectDigest - A hash of some other object type must be + * passed. otherObjectTypeID must not be empty.
      • + *
      + *

      + * + * @return The digest object type or -1 if no object digest info is set. + */ + public int DigestedObjectType + { + get + { + ObjectDigestInfo odi = holder.ObjectDigestInfo; + + return odi == null + ? -1 + : odi.DigestedObjectType.Value.IntValue; + } + } + + /** + * Returns the other object type ID if an object digest info is used. + * + * @return The other object type ID or null if no object + * digest info is set. + */ + public string DigestAlgorithm + { + get + { + ObjectDigestInfo odi = holder.ObjectDigestInfo; + + return odi == null + ? null + : odi.DigestAlgorithm.ObjectID.Id; + } + } + + /** + * Returns the hash if an object digest info is used. + * + * @return The hash or null if no object digest info is set. + */ + public byte[] GetObjectDigest() + { + ObjectDigestInfo odi = holder.ObjectDigestInfo; + + return odi == null + ? null + : odi.ObjectDigest.GetBytes(); + } + + /** + * Returns the digest algorithm ID if an object digest info is used. + * + * @return The digest algorithm ID or null if no object + * digest info is set. + */ + public string OtherObjectTypeID + { + get + { + ObjectDigestInfo odi = holder.ObjectDigestInfo; + + return odi == null + ? null + : odi.OtherObjectTypeID.Id; + } + } + + private GeneralNames GenerateGeneralNames( + X509Name principal) + { +// return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal))); + return new GeneralNames(new GeneralName(principal)); + } + + private bool MatchesDN( + X509Name subject, + GeneralNames targets) + { + GeneralName[] names = targets.GetNames(); + + for (int i = 0; i != names.Length; i++) + { + GeneralName gn = names[i]; + + if (gn.TagNo == GeneralName.DirectoryName) + { + try + { + if (X509Name.GetInstance(gn.Name).Equivalent(subject)) + { + return true; + } + } + catch (Exception) + { + } + } + } + + return false; + } + + private object[] GetNames( + GeneralName[] names) + { + ArrayList l = new ArrayList(names.Length); + + for (int i = 0; i != names.Length; i++) + { + if (names[i].TagNo == GeneralName.DirectoryName) + { + l.Add(X509Name.GetInstance(names[i].Name)); + } + } + + return l.ToArray(); + } + + private X509Name[] GetPrincipals( + GeneralNames names) + { + object[] p = this.GetNames(names.GetNames()); + ArrayList l = new ArrayList(p.Length); + + for (int i = 0; i != p.Length; i++) + { + if (p[i] is X509Name) + { + l.Add(p[i]); + } + } + + return (X509Name[]) l.ToArray(typeof(X509Name)); + } + + /** + * Return any principal objects inside the attribute certificate holder entity names field. + * + * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set. + */ + public X509Name[] GetEntityNames() + { + if (holder.EntityName != null) + { + return GetPrincipals(holder.EntityName); + } + + return null; + } + + /** + * Return the principals associated with the issuer attached to this holder + * + * @return an array of principals, null if no BaseCertificateID is set. + */ + public X509Name[] GetIssuer() + { + if (holder.BaseCertificateID != null) + { + return GetPrincipals(holder.BaseCertificateID.Issuer); + } + + return null; + } + + /** + * Return the serial number associated with the issuer attached to this holder. + * + * @return the certificate serial number, null if no BaseCertificateID is set. + */ + public BigInteger SerialNumber + { + get + { + if (holder.BaseCertificateID != null) + { + return holder.BaseCertificateID.Serial.Value; + } + + return null; + } + } + + public object Clone() + { + return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object()); + } + + public bool Match( +// Certificate cert) + X509Certificate x509Cert) + { +// if (!(cert is X509Certificate)) +// { +// return false; +// } +// +// X509Certificate x509Cert = (X509Certificate)cert; + + try + { + if (holder.BaseCertificateID != null) + { + return holder.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber) + && MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer); + } + + if (holder.EntityName != null) + { + if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName)) + { + return true; + } + } + + if (holder.ObjectDigestInfo != null) + { + IDigest md = null; + try + { + md = DigestUtilities.GetDigest(DigestAlgorithm); + } + catch (Exception) + { + return false; + } + + switch (DigestedObjectType) + { + case ObjectDigestInfo.PublicKey: + { + // TODO: DSA Dss-parms + + //byte[] b = x509Cert.GetPublicKey().getEncoded(); + // TODO Is this the right way to encode? + byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo( + x509Cert.GetPublicKey()).GetEncoded(); + md.BlockUpdate(b, 0, b.Length); + break; + } + + case ObjectDigestInfo.PublicKeyCert: + { + byte[] b = x509Cert.GetEncoded(); + md.BlockUpdate(b, 0, b.Length); + break; + } + + // TODO Default handler? + } + + // TODO Shouldn't this be the other way around? + if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest())) + { + return false; + } + } + } + catch (CertificateEncodingException) + { + return false; + } + + return false; + } + + public override bool Equals( + object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj is AttributeCertificateHolder)) + { + return false; + } + + AttributeCertificateHolder other = (AttributeCertificateHolder)obj; + + return this.holder.Equals(other.holder); + } + + public override int GetHashCode() + { + return this.holder.GetHashCode(); + } + + public bool Match( + object obj) + { + if (!(obj is X509Certificate)) + { + return false; + } + +// return Match((Certificate)obj); + return Match((X509Certificate)obj); + } + } +} diff --git a/iTechSharp/srcbc/x509/AttributeCertificateIssuer.cs b/iTechSharp/srcbc/x509/AttributeCertificateIssuer.cs new file mode 100644 index 0000000..26f4d8a --- /dev/null +++ b/iTechSharp/srcbc/x509/AttributeCertificateIssuer.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.X509 +{ + /** + * Carrying class for an attribute certificate issuer. + */ + public class AttributeCertificateIssuer + //: CertSelector, Selector + : IX509Selector + { + internal readonly Asn1Encodable form; + + /** + * Set the issuer directly with the ASN.1 structure. + * + * @param issuer The issuer + */ + internal AttributeCertificateIssuer( + AttCertIssuer issuer) + { + form = issuer.Issuer; + } + + public AttributeCertificateIssuer( + X509Name principal) + { +// form = new V2Form(GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)))); + form = new V2Form(new GeneralNames(new GeneralName(principal))); + } + + private object[] GetNames() + { + GeneralNames name; + if (form is V2Form) + { + name = ((V2Form)form).IssuerName; + } + else + { + name = (GeneralNames)form; + } + + GeneralName[] names = name.GetNames(); + + ArrayList l = new ArrayList(names.Length); + + for (int i = 0; i != names.Length; i++) + { + if (names[i].TagNo == GeneralName.DirectoryName) + { + l.Add(X509Name.GetInstance(names[i].Name)); + } + } + + return l.ToArray(); + } + + /// Return any principal objects inside the attribute certificate issuer object. + /// An array of IPrincipal objects (usually X509Principal). + public X509Name[] GetPrincipals() + { + object[] p = this.GetNames(); + ArrayList l = new ArrayList(p.Length); + + for (int i = 0; i != p.Length; i++) + { + if (p[i] is X509Name) + { + l.Add(p[i]); + } + } + + return (X509Name[]) l.ToArray(typeof(X509Name)); + } + + private bool MatchesDN( + X509Name subject, + GeneralNames targets) + { + GeneralName[] names = targets.GetNames(); + + for (int i = 0; i != names.Length; i++) + { + GeneralName gn = names[i]; + + if (gn.TagNo == GeneralName.DirectoryName) + { + try + { + if (X509Name.GetInstance(gn.Name).Equivalent(subject)) + { + return true; + } + } + catch (Exception) + { + } + } + } + + return false; + } + + public object Clone() + { + return new AttributeCertificateIssuer(AttCertIssuer.GetInstance(form)); + } + + public bool Match( +// Certificate cert) + X509Certificate x509Cert) + { +// if (!(cert is X509Certificate)) +// { +// return false; +// } +// +// X509Certificate x509Cert = (X509Certificate)cert; + + if (form is V2Form) + { + V2Form issuer = (V2Form) form; + if (issuer.BaseCertificateID != null) + { + return issuer.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber) + && MatchesDN(x509Cert.IssuerDN, issuer.BaseCertificateID.Issuer); + } + + return MatchesDN(x509Cert.SubjectDN, issuer.IssuerName); + } + + return MatchesDN(x509Cert.SubjectDN, (GeneralNames) form); + } + + public override bool Equals( + object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj is AttributeCertificateIssuer)) + { + return false; + } + + AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj; + + return this.form.Equals(other.form); + } + + public override int GetHashCode() + { + return this.form.GetHashCode(); + } + + public bool Match( + object obj) + { + if (!(obj is X509Certificate)) + { + return false; + } + + //return Match((Certificate)obj); + return Match((X509Certificate)obj); + } + } +} diff --git a/iTechSharp/srcbc/x509/IX509AttributeCertificate.cs b/iTechSharp/srcbc/x509/IX509AttributeCertificate.cs new file mode 100644 index 0000000..9a3004e --- /dev/null +++ b/iTechSharp/srcbc/x509/IX509AttributeCertificate.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.X509 +{ + /// Interface for an X.509 Attribute Certificate. + public interface IX509AttributeCertificate + : IX509Extension + { + /// The version number for the certificate. + int Version { get; } + + /// The serial number for the certificate. + BigInteger SerialNumber { get; } + + /// The UTC DateTime before which the certificate is not valid. + DateTime NotBefore { get; } + + /// The UTC DateTime after which the certificate is not valid. + DateTime NotAfter { get; } + + /// The holder of the certificate. + AttributeCertificateHolder Holder { get; } + + /// The issuer details for the certificate. + AttributeCertificateIssuer Issuer { get; } + + /// Return the attributes contained in the attribute block in the certificate. + /// An array of attributes. + X509Attribute[] GetAttributes(); + + /// Return the attributes with the same type as the passed in oid. + /// The object identifier we wish to match. + /// An array of matched attributes, null if there is no match. + X509Attribute[] GetAttributes(string oid); + + bool[] GetIssuerUniqueID(); + + bool IsValidNow { get; } + bool IsValid(DateTime date); + + void CheckValidity(); + void CheckValidity(DateTime date); + + byte[] GetSignature(); + + void Verify(AsymmetricKeyParameter publicKey); + + /// Return an ASN.1 encoded byte array representing the attribute certificate. + /// An ASN.1 encoded byte array. + /// If the certificate cannot be encoded. + byte[] GetEncoded(); + } +} diff --git a/iTechSharp/srcbc/x509/IX509Extension.cs b/iTechSharp/srcbc/x509/IX509Extension.cs new file mode 100644 index 0000000..34c977d --- /dev/null +++ b/iTechSharp/srcbc/x509/IX509Extension.cs @@ -0,0 +1,27 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.X509 +{ + public interface IX509Extension + { + /// + /// Get all critical extension values, by oid + /// + /// IDictionary with DerObjectIdentifier keys and Asn1OctetString values + ISet GetCriticalExtensionOids(); + + /// + /// Get all non-critical extension values, by oid + /// + /// IDictionary with DerObjectIdentifier keys and Asn1OctetString values + ISet GetNonCriticalExtensionOids(); + + [Obsolete("Use version taking a DerObjectIdentifier instead")] + Asn1OctetString GetExtensionValue(string oid); + + Asn1OctetString GetExtensionValue(DerObjectIdentifier oid); + } +} diff --git a/iTechSharp/srcbc/x509/PEMParser.cs b/iTechSharp/srcbc/x509/PEMParser.cs new file mode 100644 index 0000000..177e344 --- /dev/null +++ b/iTechSharp/srcbc/x509/PEMParser.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.X509 +{ + class PemParser + { + private readonly string _header1; + private readonly string _header2; + private readonly string _footer1; + private readonly string _footer2; + + internal PemParser( + string type) + { + _header1 = "-----BEGIN " + type + "-----"; + _header2 = "-----BEGIN X509 " + type + "-----"; + _footer1 = "-----END " + type + "-----"; + _footer2 = "-----END X509 " + type + "-----"; + } + + private string ReadLine( + Stream inStream) + { + int c; + StringBuilder l = new StringBuilder(); + + do + { + while (((c = inStream.ReadByte()) != '\r') && c != '\n' && (c >= 0)) + { + if (c == '\r') + { + continue; + } + + l.Append((char)c); + } + } + while (c >= 0 && l.Length == 0); + + if (c < 0) + { + return null; + } + + return l.ToString(); + } + + internal Asn1Sequence ReadPemObject( + Stream inStream) + { + string line; + StringBuilder pemBuf = new StringBuilder(); + + while ((line = ReadLine(inStream)) != null) + { + if (line.Equals(_header1) || line.Equals(_header2)) + { + break; + } + } + + while ((line = ReadLine(inStream)) != null) + { + if (line.Equals(_footer1) || line.Equals(_footer2)) + { + break; + } + + pemBuf.Append(line); + } + + if (pemBuf.Length != 0) + { + Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString())); + + if (!(o is Asn1Sequence)) + { + throw new IOException("malformed PEM data encountered"); + } + + return (Asn1Sequence) o; + } + + return null; + } + } +} + diff --git a/iTechSharp/srcbc/x509/PrincipalUtil.cs b/iTechSharp/srcbc/x509/PrincipalUtil.cs new file mode 100644 index 0000000..0edc4a3 --- /dev/null +++ b/iTechSharp/srcbc/x509/PrincipalUtil.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; + +namespace Org.BouncyCastle.X509 +{ + /// + /// A utility class that will extract X509Principal objects from X.509 certificates. + ///

      + /// Use this in preference to trying to recreate a principal from a string, not all + /// DNs are what they should be, so it's best to leave them encoded where they + /// can be.

      + ///
      + public class PrincipalUtilities + { + /// Return the issuer of the given cert as an X509Principal. + public static X509Name GetIssuerX509Principal( + X509Certificate cert) + { + try + { + TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + + return tbsCert.Issuer; + } + catch (Exception e) + { + throw new CertificateEncodingException("Could not extract issuer", e); + } + } + + /// Return the subject of the given cert as an X509Principal. + public static X509Name GetSubjectX509Principal( + X509Certificate cert) + { + try + { + TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + + return tbsCert.Subject; + } + catch (Exception e) + { + throw new CertificateEncodingException("Could not extract subject", e); + } + } + + /// Return the issuer of the given CRL as an X509Principal. + public static X509Name GetIssuerX509Principal( + X509Crl crl) + { + try + { + TbsCertificateList tbsCertList = TbsCertificateList.GetInstance( + Asn1Object.FromByteArray(crl.GetTbsCertList())); + + return tbsCertList.Issuer; + } + catch (Exception e) + { + throw new CrlException("Could not extract issuer", e); + } + } + } +} diff --git a/iTechSharp/srcbc/x509/SubjectPublicKeyInfoFactory.cs b/iTechSharp/srcbc/x509/SubjectPublicKeyInfoFactory.cs new file mode 100644 index 0000000..92a1bd4 --- /dev/null +++ b/iTechSharp/srcbc/x509/SubjectPublicKeyInfoFactory.cs @@ -0,0 +1,178 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.X509 +{ + /// + /// A factory to produce Public Key Info Objects. + /// + public sealed class SubjectPublicKeyInfoFactory + { + private SubjectPublicKeyInfoFactory() + { + } + + /// + /// Create a Subject Public Key Info object for a given public key. + /// + /// One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters + /// A subject public key info object. + /// Throw exception if object provided is not one of the above. + public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo( + AsymmetricKeyParameter key) + { + if (key == null) + throw new ArgumentNullException("key"); + if (key.IsPrivate) + throw new ArgumentException("Private key passed - public key expected.", "key"); + + if (key is ElGamalPublicKeyParameters) + { + ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key; + ElGamalParameters kp = _key.Parameters; + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( + new AlgorithmIdentifier( + OiwObjectIdentifiers.ElGamalAlgorithm, + new ElGamalParameter(kp.P, kp.G).ToAsn1Object()), + new DerInteger(_key.Y)); + + return info; + } + + if (key is DsaPublicKeyParameters) + { + DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key; + DsaParameters kp = _key.Parameters; + Asn1Encodable ae = kp == null + ? null + : new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object(); + + return new SubjectPublicKeyInfo( + new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae), + new DerInteger(_key.Y)); + } + + if (key is DHPublicKeyParameters) + { + DHPublicKeyParameters _key = (DHPublicKeyParameters) key; + DHParameters kp = _key.Parameters; + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( + new AlgorithmIdentifier( + X9ObjectIdentifiers.DHPublicNumber, + new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()), + new DerInteger(_key.Y)); + + return info; + } // End of DH + + if (key is RsaKeyParameters) + { + RsaKeyParameters _key = (RsaKeyParameters) key; + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( + new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance), + new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object()); + + return info; + } // End of RSA. + + if (key is ECPublicKeyParameters) + { + ECPublicKeyParameters _key = (ECPublicKeyParameters) key; + + if (_key.AlgorithmName == "ECGOST3410") + { + if (_key.PublicKeyParamSet == null) + throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set"); + + ECPoint q = _key.Q; + BigInteger bX = q.X.ToBigInteger(); + BigInteger bY = q.Y.ToBigInteger(); + + byte[] encKey = new byte[64]; + ExtractBytes(encKey, 0, bX); + ExtractBytes(encKey, 32, bY); + + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet); + + AlgorithmIdentifier algID = new AlgorithmIdentifier( + CryptoProObjectIdentifiers.GostR3410x2001, + gostParams.ToAsn1Object()); + + return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey)); + } + else + { + ECDomainParameters kp = _key.Parameters; + + X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed()); + X962Parameters x962 = new X962Parameters(ecP); + Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object()); + + AlgorithmIdentifier algID = new AlgorithmIdentifier( + X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object()); + + return new SubjectPublicKeyInfo(algID, p.GetOctets()); + } + } // End of EC + + if (key is Gost3410PublicKeyParameters) + { + Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key; + + if (_key.PublicKeyParamSet == null) + throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set"); + + byte[] keyEnc = _key.Y.ToByteArrayUnsigned(); + byte[] keyBytes = new byte[keyEnc.Length]; + + for (int i = 0; i != keyBytes.Length; i++) + { + keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian + } + + Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters( + _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet); + + AlgorithmIdentifier algID = new AlgorithmIdentifier( + CryptoProObjectIdentifiers.GostR3410x94, + algParams.ToAsn1Object()); + + return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes)); + } + + throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName); + } + + private static void ExtractBytes( + byte[] encKey, + int offset, + BigInteger bI) + { + byte[] val = bI.ToByteArray(); + int n = (bI.BitLength + 7) / 8; + + for (int i = 0; i < n; ++i) + { + encKey[offset + i] = val[val.Length - 1 - i]; + } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509AttrCertParser.cs b/iTechSharp/srcbc/x509/X509AttrCertParser.cs new file mode 100644 index 0000000..6cc05b1 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509AttrCertParser.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.X509 +{ + public class X509AttrCertParser + { + private static readonly PemParser PemAttrCertParser = new PemParser("ATTRIBUTE CERTIFICATE"); + + private Asn1Set sData; + private int sDataObjectCount; + private Stream currentStream; + + private IX509AttributeCertificate ReadDerCertificate( + Asn1InputStream dIn) + { + Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject(); + + if (seq.Count > 1 && seq[0] is DerObjectIdentifier) + { + if (seq[0].Equals(PkcsObjectIdentifiers.SignedData)) + { + sData = SignedData.GetInstance( + Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates; + + return GetCertificate(); + } + } + +// return new X509V2AttributeCertificate(seq.getEncoded()); + return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq)); + } + + private IX509AttributeCertificate GetCertificate() + { + if (sData != null) + { + while (sDataObjectCount < sData.Count) + { + object obj = sData[sDataObjectCount++]; + + if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 2) + { + //return new X509V2AttributeCertificate( + // Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false).GetEncoded()); + return new X509V2AttributeCertificate( + AttributeCertificate.GetInstance( + Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false))); + } + } + } + + return null; + } + + private IX509AttributeCertificate ReadPemCertificate( + Stream inStream) + { + Asn1Sequence seq = PemAttrCertParser.ReadPemObject(inStream); + + return seq == null + ? null + //: new X509V2AttributeCertificate(seq.getEncoded()); + : new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq)); + } + + /// + /// Create loading data from byte array. + /// + /// + public IX509AttributeCertificate ReadAttrCert( + byte[] input) + { + return ReadAttrCert(new MemoryStream(input, false)); + } + + /// + /// Create loading data from byte array. + /// + /// + public ICollection ReadAttrCerts( + byte[] input) + { + return ReadAttrCerts(new MemoryStream(input, false)); + } + + /** + * Generates a certificate object and initializes it with the data + * read from the input stream inStream. + */ + public IX509AttributeCertificate ReadAttrCert( + Stream inStream) + { + if (inStream == null) + throw new ArgumentNullException("inStream"); + if (!inStream.CanRead) + throw new ArgumentException("inStream must be read-able", "inStream"); + + if (currentStream == null) + { + currentStream = inStream; + sData = null; + sDataObjectCount = 0; + } + else if (currentStream != inStream) // reset if input stream has changed + { + currentStream = inStream; + sData = null; + sDataObjectCount = 0; + } + + try + { + if (sData != null) + { + if (sDataObjectCount != sData.Count) + { + return GetCertificate(); + } + + sData = null; + sDataObjectCount = 0; + return null; + } + + PushbackStream pis = new PushbackStream(inStream); + int tag = pis.ReadByte(); + + if (tag < 0) + return null; + + pis.Unread(tag); + + if (tag != 0x30) // assume ascii PEM encoded. + { + return ReadPemCertificate(pis); + } + + return ReadDerCertificate(new Asn1InputStream(pis)); + } + catch (Exception e) + { + throw new CertificateException(e.ToString()); + } + } + + /** + * Returns a (possibly empty) collection view of the certificates + * read from the given input stream inStream. + */ + public ICollection ReadAttrCerts( + Stream inStream) + { + IX509AttributeCertificate attrCert; + IList attrCerts = new ArrayList(); + + while ((attrCert = ReadAttrCert(inStream)) != null) + { + attrCerts.Add(attrCert); + } + + return attrCerts; + } + } +} \ No newline at end of file diff --git a/iTechSharp/srcbc/x509/X509Attribute.cs b/iTechSharp/srcbc/x509/X509Attribute.cs new file mode 100644 index 0000000..248d66c --- /dev/null +++ b/iTechSharp/srcbc/x509/X509Attribute.cs @@ -0,0 +1,76 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.X509 +{ + /** + * Class for carrying the values in an X.509 Attribute. + */ + public class X509Attribute + : Asn1Encodable + { + private readonly AttributeX509 attr; + + /** + * @param at an object representing an attribute. + */ + internal X509Attribute( + Asn1Encodable at) + { + this.attr = AttributeX509.GetInstance(at); + } + + /** + * Create an X.509 Attribute with the type given by the passed in oid and + * the value represented by an ASN.1 Set containing value. + * + * @param oid type of the attribute + * @param value value object to go into the atribute's value set. + */ + public X509Attribute( + string oid, + Asn1Encodable value) + { + this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value)); + } + + /** + * Create an X.59 Attribute with the type given by the passed in oid and the + * value represented by an ASN.1 Set containing the objects in value. + * + * @param oid type of the attribute + * @param value vector of values to go in the attribute's value set. + */ + public X509Attribute( + string oid, + Asn1EncodableVector value) + { + this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value)); + } + + public string Oid + { + get { return attr.AttrType.Id; } + } + + public Asn1Encodable[] GetValues() + { + Asn1Set s = attr.AttrValues; + Asn1Encodable[] values = new Asn1Encodable[s.Count]; + + for (int i = 0; i != s.Count; i++) + { + values[i] = (Asn1Encodable)s[i]; + } + + return values; + } + + public override Asn1Object ToAsn1Object() + { + return attr.ToAsn1Object(); + } + } +} diff --git a/iTechSharp/srcbc/x509/X509CertPairParser.cs b/iTechSharp/srcbc/x509/X509CertPairParser.cs new file mode 100644 index 0000000..27488df --- /dev/null +++ b/iTechSharp/srcbc/x509/X509CertPairParser.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.X509 +{ + public class X509CertPairParser + { + private Stream currentStream; + + private X509CertificatePair ReadDerCrossCertificatePair( + Stream inStream) + { + Asn1InputStream dIn = new Asn1InputStream(inStream);//, ProviderUtil.getReadLimit(in)); + Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject(); + CertificatePair pair = CertificatePair.GetInstance(seq); + return new X509CertificatePair(pair); + } + + /// + /// Create loading data from byte array. + /// + /// + public X509CertificatePair ReadCertPair( + byte[] input) + { + return ReadCertPair(new MemoryStream(input, false)); + } + + /// + /// Create loading data from byte array. + /// + /// + public ICollection ReadCertPairs( + byte[] input) + { + return ReadCertPairs(new MemoryStream(input, false)); + } + + public X509CertificatePair ReadCertPair( + Stream inStream) + { + if (inStream == null) + throw new ArgumentNullException("inStream"); + if (!inStream.CanRead) + throw new ArgumentException("inStream must be read-able", "inStream"); + + if (currentStream == null) + { + currentStream = inStream; + } + else if (currentStream != inStream) // reset if input stream has changed + { + currentStream = inStream; + } + + try + { + PushbackStream pis = new PushbackStream(inStream); + int tag = pis.ReadByte(); + + if (tag < 0) + return null; + + pis.Unread(tag); + + return ReadDerCrossCertificatePair(pis); + } + catch (Exception e) + { + throw new CertificateException(e.ToString()); + } + } + + public ICollection ReadCertPairs( + Stream inStream) + { + X509CertificatePair certPair; + IList certPairs = new ArrayList(); + + while ((certPair = ReadCertPair(inStream)) != null) + { + certPairs.Add(certPair); + } + + return certPairs; + } + } +} diff --git a/iTechSharp/srcbc/x509/X509Certificate.cs b/iTechSharp/srcbc/x509/X509Certificate.cs new file mode 100644 index 0000000..92230c5 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509Certificate.cs @@ -0,0 +1,579 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Misc; +using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509 +{ + /// + /// An Object representing an X509 Certificate. + /// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects. + /// + public class X509Certificate + : X509ExtensionBase +// , PKCS12BagAttributeCarrier + { + private readonly X509CertificateStructure c; +// private Hashtable pkcs12Attributes = new Hashtable(); +// private ArrayList pkcs12Ordering = new ArrayList(); + private readonly BasicConstraints basicConstraints; + private readonly bool[] keyUsage; + + private bool hashValueSet; + private int hashValue; + + protected X509Certificate() + { + } + + public X509Certificate( + X509CertificateStructure c) + { + this.c = c; + + try + { + Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19")); + + if (str != null) + { + basicConstraints = BasicConstraints.GetInstance( + X509ExtensionUtilities.FromExtensionValue(str)); + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct BasicConstraints: " + e); + } + + try + { + Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15")); + + if (str != null) + { + DerBitString bits = DerBitString.GetInstance( + X509ExtensionUtilities.FromExtensionValue(str)); + + byte[] bytes = bits.GetBytes(); + int length = (bytes.Length * 8) - bits.PadBits; + + keyUsage = new bool[(length < 9) ? 9 : length]; + + for (int i = 0; i != length; i++) + { +// keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0; + } + } + else + { + keyUsage = null; + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct KeyUsage: " + e); + } + } + +// internal X509Certificate( +// Asn1Sequence seq) +// { +// this.c = X509CertificateStructure.GetInstance(seq); +// } + +// /// +// /// Load certificate from byte array. +// /// +// /// Byte array containing encoded X509Certificate. +// public X509Certificate( +// byte[] encoded) +// : this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject()) +// { +// } +// +// /// +// /// Load certificate from Stream. +// /// Must be positioned at start of certificate. +// /// +// /// +// public X509Certificate( +// Stream input) +// : this((Asn1Sequence) new Asn1InputStream(input).ReadObject()) +// { +// } + + /// + /// Return true if the current time is within the start and end times nominated on the certificate. + /// + /// true id certificate is valid for the current time. + public virtual bool IsValidNow + { + get { return IsValid(DateTime.UtcNow); } + } + + /// + /// Return true if the nominated time is within the start and end times nominated on the certificate. + /// + /// The time to test validity against. + /// True if certificate is valid for nominated time. + public virtual bool IsValid( + DateTime time) + { + return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0; + } + + /// + /// Checks if the current date is within certificate's validity period. + /// + public virtual void CheckValidity() + { + this.CheckValidity(DateTime.UtcNow); + } + + /// + /// Checks if the given date is within certificate's validity period. + /// + /// if the certificate is expired by given date + /// if the certificate is not yet valid on given date + public virtual void CheckValidity( + DateTime time) + { + if (time.CompareTo(NotAfter) > 0) + throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime()); + if (time.CompareTo(NotBefore) < 0) + throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime()); + } + + /// + /// Return the certificate's version. + /// + /// An integer whose value Equals the version of the cerficate. + public virtual int Version + { + get { return c.Version; } + } + + /// + /// Return a BigInteger containing the serial number. + /// + /// The Serial number. + public virtual BigInteger SerialNumber + { + get { return c.SerialNumber.Value; } + } + + /// + /// Get the Issuer Distinguished Name. (Who signed the certificate.) + /// + /// And X509Object containing name and value pairs. +// public IPrincipal IssuerDN + public virtual X509Name IssuerDN + { + get { return c.Issuer; } + } + + /// + /// Get the subject of this certificate. + /// + /// An X509Name object containing name and value pairs. +// public IPrincipal SubjectDN + public virtual X509Name SubjectDN + { + get { return c.Subject; } + } + + /// + /// The time that this certificate is valid from. + /// + /// A DateTime object representing that time in the local time zone. + public virtual DateTime NotBefore + { + get { return c.StartDate.ToDateTime(); } + } + + /// + /// The time that this certificate is valid up to. + /// + /// A DateTime object representing that time in the local time zone. + public virtual DateTime NotAfter + { + get { return c.EndDate.ToDateTime(); } + } + + /// + /// Return the Der encoded TbsCertificate data. + /// This is the certificate component less the signature. + /// To Get the whole certificate call the GetEncoded() member. + /// + /// A byte array containing the Der encoded Certificate component. + public virtual byte[] GetTbsCertificate() + { + return c.TbsCertificate.GetDerEncoded(); + } + + /// + /// The signature. + /// + /// A byte array containg the signature of the certificate. + public virtual byte[] GetSignature() + { + return c.Signature.GetBytes(); + } + + /// + /// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA) + /// + /// A sting representing the signature algorithm. + public virtual string SigAlgName + { + get { return SignerUtilities.GetEncodingName(c.SignatureAlgorithm.ObjectID); } + } + + /// + /// Get the Signature Algorithms Object ID. + /// + /// A string containg a '.' separated object id. + public virtual string SigAlgOid + { + get { return c.SignatureAlgorithm.ObjectID.Id; } + } + + /// + /// Get the signature algorithms parameters. (EG DSA Parameters) + /// + /// A byte array containing the Der encoded version of the parameters or null if there are none. + public virtual byte[] GetSigAlgParams() + { + if (c.SignatureAlgorithm.Parameters != null) + { + return c.SignatureAlgorithm.Parameters.GetDerEncoded(); + } + + return null; + } + + /// + /// Get the issuers UID. + /// + /// A DerBitString. + public virtual DerBitString IssuerUniqueID + { + get { return c.TbsCertificate.IssuerUniqueID; } + } + + /// + /// Get the subjects UID. + /// + /// A DerBitString. + public virtual DerBitString SubjectUniqueID + { + get { return c.TbsCertificate.SubjectUniqueID; } + } + + /// + /// Get a key usage guidlines. + /// + public virtual bool[] GetKeyUsage() + { + return keyUsage == null ? null : (bool[]) keyUsage.Clone(); + } + + // TODO Replace with something that returns a list of DerObjectIdentifier + public virtual IList GetExtendedKeyUsage() + { + Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37")); + + if (str == null) + return null; + + try + { + Asn1Sequence seq = Asn1Sequence.GetInstance( + X509ExtensionUtilities.FromExtensionValue(str)); + + ArrayList list = new ArrayList(); + + foreach (DerObjectIdentifier oid in seq) + { + list.Add(oid.Id); + } + + return list; + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension", e); + } + } + + public virtual int GetBasicConstraints() + { + if (basicConstraints != null && basicConstraints.IsCA()) + { + if (basicConstraints.PathLenConstraint == null) + { + return int.MaxValue; + } + + return basicConstraints.PathLenConstraint.IntValue; + } + + return -1; + } + + public virtual ICollection GetSubjectAlternativeNames() + { + return GetAlternativeNames("2.5.29.17"); + } + + public virtual ICollection GetIssuerAlternativeNames() + { + return GetAlternativeNames("2.5.29.18"); + } + + protected virtual ICollection GetAlternativeNames( + string oid) + { + Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid)); + + if (altNames == null) + return null; + + Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames); + + GeneralNames gns = GeneralNames.GetInstance(asn1Object); + + ArrayList result = new ArrayList(); + foreach (GeneralName gn in gns.GetNames()) + { + ArrayList entry = new ArrayList(); + entry.Add(gn.TagNo); + entry.Add(gn.Name.ToString()); + result.Add(entry); + } + return result; + } + + protected override X509Extensions GetX509Extensions() + { + return c.Version == 3 + ? c.TbsCertificate.Extensions + : null; + } + + /// + /// Get the public key of the subject of the certificate. + /// + /// The public key parameters. + public virtual AsymmetricKeyParameter GetPublicKey() + { + return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo); + } + + /// + /// Return a Der encoded version of this certificate. + /// + /// A byte array. + public virtual byte[] GetEncoded() + { + return c.GetDerEncoded(); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + X509Certificate other = obj as X509Certificate; + + if (other == null) + return false; + + return c.Equals(other.c); + + // NB: May prefer this implementation of Equals if more than one certificate implementation in play +// return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded()); + } + + public override int GetHashCode() + { + lock (this) + { + if (!hashValueSet) + { + hashValue = c.GetHashCode(); + hashValueSet = true; + } + } + + return hashValue; + } + +// public void setBagAttribute( +// DERObjectIdentifier oid, +// DEREncodable attribute) +// { +// pkcs12Attributes.put(oid, attribute); +// pkcs12Ordering.addElement(oid); +// } +// +// public DEREncodable getBagAttribute( +// DERObjectIdentifier oid) +// { +// return (DEREncodable)pkcs12Attributes.get(oid); +// } +// +// public Enumeration getBagAttributeKeys() +// { +// return pkcs12Ordering.elements(); +// } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string nl = Platform.NewLine; + + buf.Append(" [0] Version: ").Append(this.Version).Append(nl); + buf.Append(" SerialNumber: ").Append(this.SerialNumber).Append(nl); + buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl); + buf.Append(" Start Date: ").Append(this.NotBefore).Append(nl); + buf.Append(" Final Date: ").Append(this.NotAfter).Append(nl); + buf.Append(" SubjectDN: ").Append(this.SubjectDN).Append(nl); + buf.Append(" Public Key: ").Append(this.GetPublicKey()).Append(nl); + buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl); + + byte[] sig = this.GetSignature(); + byte[] hex = Hex.Encode(sig, 0, 20); + string ascii = Encoding.ASCII.GetString(hex, 0, hex.Length); + buf.Append(" Signature: ").Append(ascii).Append(nl); + + for (int i = 20; i < sig.Length; i += 20) + { + int len = System.Math.Min(20, sig.Length - i); + hex = Hex.Encode(sig, i, len); + ascii = Encoding.ASCII.GetString(hex, 0, hex.Length); + buf.Append(" ").Append(ascii).Append(nl); + } + + X509Extensions extensions = c.TbsCertificate.Extensions; + + if (extensions != null) + { + IEnumerator e = extensions.ExtensionOids.GetEnumerator(); + + if (e.MoveNext()) + { + buf.Append(" Extensions: \n"); + } + + do + { + DerObjectIdentifier oid = (DerObjectIdentifier)e.Current; + X509Extension ext = extensions.GetExtension(oid); + + if (ext.Value != null) + { + byte[] octs = ext.Value.GetOctets(); + Asn1Object obj = Asn1Object.FromByteArray(octs); + buf.Append(" critical(").Append(ext.IsCritical).Append(") "); + try + { + if (oid.Equals(X509Extensions.BasicConstraints)) + { + buf.Append(BasicConstraints.GetInstance(obj)); + } + else if (oid.Equals(X509Extensions.KeyUsage)) + { + buf.Append(KeyUsage.GetInstance(obj)); + } + else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType)) + { + buf.Append(new NetscapeCertType((DerBitString) obj)); + } + else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl)) + { + buf.Append(new NetscapeRevocationUrl((DerIA5String) obj)); + } + else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension)) + { + buf.Append(new VerisignCzagExtension((DerIA5String) obj)); + } + else + { + buf.Append(oid.Id); + buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj)); + //buf.Append(" value = ").Append("*****").Append(nl); + } + } + catch (Exception) + { + buf.Append(oid.Id); + //buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl); + buf.Append(" value = ").Append("*****"); + } + } + + buf.Append(nl); + } + while (e.MoveNext()); + } + + return buf.ToString(); + } + + /// + /// Verify the certificate's signature using the nominated public key. + /// + /// An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters + /// True if the signature is valid. + /// If key submitted is not of the above nominated types. + public virtual void Verify( + AsymmetricKeyParameter key) + { + string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm); + ISigner signature = SignerUtilities.GetSigner(sigName); + + CheckSignature(key, signature); + } + + protected virtual void CheckSignature( + AsymmetricKeyParameter publicKey, + ISigner signature) + { + if (!c.SignatureAlgorithm.Equals(c.TbsCertificate.Signature)) + { + throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); + } + + Asn1Encodable parameters = c.SignatureAlgorithm.Parameters; + + X509SignatureUtilities.SetSignatureParameters(signature, parameters); + + signature.Init(false, publicKey); + + byte[] b = this.GetTbsCertificate(); + signature.BlockUpdate(b, 0, b.Length); + + byte[] sig = this.GetSignature(); + if (!signature.VerifySignature(sig)) + { + throw new InvalidKeyException("Public key presented not for certificate signature"); + } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509CertificatePair.cs b/iTechSharp/srcbc/x509/X509CertificatePair.cs new file mode 100644 index 0000000..f7ae201 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509CertificatePair.cs @@ -0,0 +1,117 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.X509 +{ + /// + /// This class contains a cross certificate pair. Cross certificates pairs may + /// contain two cross signed certificates from two CAs. A certificate from the + /// other CA to this CA is contained in the forward certificate, the certificate + /// from this CA to the other CA is contained in the reverse certificate. + /// + public class X509CertificatePair + { + private readonly X509Certificate forward; + private readonly X509Certificate reverse; + + /// Constructor + /// Certificate from the other CA to this CA. + /// Certificate from this CA to the other CA. + public X509CertificatePair( + X509Certificate forward, + X509Certificate reverse) + { + this.forward = forward; + this.reverse = reverse; + } + + /// Constructor from a ASN.1 CertificatePair structure. + /// The CertificatePair ASN.1 object. + public X509CertificatePair( + CertificatePair pair) + { + if (pair.Forward != null) + { + this.forward = new X509Certificate(pair.Forward); + } + if (pair.Reverse != null) + { + this.reverse = new X509Certificate(pair.Reverse); + } + } + + public byte[] GetEncoded() + { + try + { + X509CertificateStructure f = null, r = null; + + if (forward != null) + { + f = X509CertificateStructure.GetInstance( + Asn1Object.FromByteArray(forward.GetEncoded())); + } + + if (reverse != null) + { + r = X509CertificateStructure.GetInstance( + Asn1Object.FromByteArray(reverse.GetEncoded())); + } + + return new CertificatePair(f, r).GetDerEncoded(); + } + catch (Exception e) + { + // TODO +// throw new ExtCertificateEncodingException(e.toString(), e); + throw new CertificateEncodingException(e.Message, e); + } + } + + /// Returns the certificate from the other CA to this CA. + public X509Certificate Forward + { + get { return forward; } + } + + /// Returns the certificate from this CA to the other CA. + public X509Certificate Reverse + { + get { return reverse; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + X509CertificatePair other = obj as X509CertificatePair; + + if (other == null) + return false; + + return Platform.Equals(this.forward, other.forward) + && Platform.Equals(this.reverse, other.reverse); + } + + public override int GetHashCode() + { + int hash = -1; + if (forward != null) + { + hash ^= forward.GetHashCode(); + } + if (reverse != null) + { + hash *= 17; + hash ^= reverse.GetHashCode(); + } + return hash; + } + } +} diff --git a/iTechSharp/srcbc/x509/X509CertificateParser.cs b/iTechSharp/srcbc/x509/X509CertificateParser.cs new file mode 100644 index 0000000..b25d3a6 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509CertificateParser.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.X509 +{ + /** + * class for dealing with X509 certificates. + *

      + * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----" + * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7 + * objects.

      + */ + public class X509CertificateParser + { + private static readonly PemParser PemCertParser = new PemParser("CERTIFICATE"); + + private Asn1Set sData; + private int sDataObjectCount; + private Stream currentStream; + + private X509Certificate ReadDerCertificate( + Asn1InputStream dIn) + { + Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject(); + + if (seq.Count > 1 && seq[0] is DerObjectIdentifier) + { + if (seq[0].Equals(PkcsObjectIdentifiers.SignedData)) + { + sData = SignedData.GetInstance( + Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates; + + return GetCertificate(); + } + } + + return CreateX509Certificate(X509CertificateStructure.GetInstance(seq)); + } + + private X509Certificate GetCertificate() + { + if (sData != null) + { + while (sDataObjectCount < sData.Count) + { + object obj = sData[sDataObjectCount++]; + + if (obj is Asn1Sequence) + { + return CreateX509Certificate( + X509CertificateStructure.GetInstance(obj)); + } + } + } + + return null; + } + + private X509Certificate ReadPemCertificate( + Stream inStream) + { + Asn1Sequence seq = PemCertParser.ReadPemObject(inStream); + + return seq == null + ? null + : CreateX509Certificate(X509CertificateStructure.GetInstance(seq)); + } + + protected virtual X509Certificate CreateX509Certificate( + X509CertificateStructure c) + { + return new X509Certificate(c); + } + + /// + /// Create loading data from byte array. + /// + /// + public X509Certificate ReadCertificate( + byte[] input) + { + return ReadCertificate(new MemoryStream(input, false)); + } + + /// + /// Create loading data from byte array. + /// + /// + public ICollection ReadCertificates( + byte[] input) + { + return ReadCertificates(new MemoryStream(input, false)); + } + + /** + * Generates a certificate object and initializes it with the data + * read from the input stream inStream. + */ + public X509Certificate ReadCertificate( + Stream inStream) + { + if (inStream == null) + throw new ArgumentNullException("inStream"); + if (!inStream.CanRead) + throw new ArgumentException("inStream must be read-able", "inStream"); + + if (currentStream == null) + { + currentStream = inStream; + sData = null; + sDataObjectCount = 0; + } + else if (currentStream != inStream) // reset if input stream has changed + { + currentStream = inStream; + sData = null; + sDataObjectCount = 0; + } + + try + { + if (sData != null) + { + if (sDataObjectCount != sData.Count) + { + return GetCertificate(); + } + + sData = null; + sDataObjectCount = 0; + return null; + } + + PushbackStream pis = new PushbackStream(inStream); + int tag = pis.ReadByte(); + + if (tag < 0) + return null; + + pis.Unread(tag); + + if (tag != 0x30) // assume ascii PEM encoded. + { + return ReadPemCertificate(pis); + } + + return ReadDerCertificate(new Asn1InputStream(pis)); + } + catch (Exception e) + { + throw new CertificateException(e.ToString()); + } + } + + /** + * Returns a (possibly empty) collection view of the certificates + * read from the given input stream inStream. + */ + public ICollection ReadCertificates( + Stream inStream) + { + X509Certificate cert; + IList certs = new ArrayList(); + + while ((cert = ReadCertificate(inStream)) != null) + { + certs.Add(cert); + } + + return certs; + } + } +} diff --git a/iTechSharp/srcbc/x509/X509Crl.cs b/iTechSharp/srcbc/x509/X509Crl.cs new file mode 100644 index 0000000..dcd378f --- /dev/null +++ b/iTechSharp/srcbc/x509/X509Crl.cs @@ -0,0 +1,409 @@ +using System; +using System.Collections; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509 +{ + /** + * The following extensions are listed in RFC 2459 as relevant to CRLs + * + * Authority Key Identifier + * Issuer Alternative Name + * CRL Number + * Delta CRL Indicator (critical) + * Issuing Distribution Point (critical) + */ + public class X509Crl + : X509ExtensionBase + // TODO Add interface Crl? + { + private readonly CertificateList c; + private readonly string sigAlgName; + private readonly byte[] sigAlgParams; + private readonly bool isIndirect; + + public X509Crl( + CertificateList c) + { + this.c = c; + + try + { + this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm); + + if (c.SignatureAlgorithm.Parameters != null) + { + this.sigAlgParams = ((Asn1Encodable)c.SignatureAlgorithm.Parameters).GetDerEncoded(); + } + else + { + this.sigAlgParams = null; + } + + this.isIndirect = IsIndirectCrl; + } + catch (Exception e) + { + throw new CrlException("CRL contents invalid: " + e); + } + } + + protected override X509Extensions GetX509Extensions() + { + return Version == 2 + ? c.TbsCertList.Extensions + : null; + } + + public virtual byte[] GetEncoded() + { + try + { + return c.GetDerEncoded(); + } + catch (Exception e) + { + throw new CrlException(e.ToString()); + } + } + + public virtual void Verify( + AsymmetricKeyParameter publicKey) + { + if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature)) + { + throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList."); + } + + ISigner sig = SignerUtilities.GetSigner(SigAlgName); + sig.Init(false, publicKey); + + byte[] encoded = this.GetTbsCertList(); + sig.BlockUpdate(encoded, 0, encoded.Length); + + if (!sig.VerifySignature(this.GetSignature())) + { + throw new SignatureException("CRL does not verify with supplied public key."); + } + } + + public virtual int Version + { + get { return c.Version; } + } + + public virtual X509Name IssuerDN + { + get { return c.Issuer; } + } + + public virtual DateTime ThisUpdate + { + get { return c.ThisUpdate.ToDateTime(); } + } + + public virtual DateTimeObject NextUpdate + { + get + { + return c.NextUpdate == null + ? null + : new DateTimeObject(c.NextUpdate.ToDateTime()); + } + } + + private ISet LoadCrlEntries() + { + ISet entrySet = new HashSet(); + IEnumerable certs = c.GetRevokedCertificateEnumeration(); + + X509Name previousCertificateIssuer = IssuerDN; + foreach (CrlEntry entry in certs) + { + X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer); + entrySet.Add(crlEntry); + previousCertificateIssuer = crlEntry.GetCertificateIssuer(); + } + + return entrySet; + } + + public virtual X509CrlEntry GetRevokedCertificate( + BigInteger serialNumber) + { + IEnumerable certs = c.GetRevokedCertificateEnumeration(); + + X509Name previousCertificateIssuer = IssuerDN; + foreach (CrlEntry entry in certs) + { + X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer); + + if (serialNumber.Equals(entry.UserCertificate.Value)) + { + return crlEntry; + } + + previousCertificateIssuer = crlEntry.GetCertificateIssuer(); + } + + return null; + } + + public virtual ISet GetRevokedCertificates() + { + ISet entrySet = LoadCrlEntries(); + + if (entrySet.Count > 0) + { + return entrySet; // TODO? Collections.unmodifiableSet(entrySet); + } + + return null; + } + + public virtual byte[] GetTbsCertList() + { + try + { + return c.TbsCertList.GetDerEncoded(); + } + catch (Exception e) + { + throw new CrlException(e.ToString()); + } + } + + public virtual byte[] GetSignature() + { + return c.Signature.GetBytes(); + } + + public virtual string SigAlgName + { + get { return sigAlgName; } + } + + public virtual string SigAlgOid + { + get { return c.SignatureAlgorithm.ObjectID.Id; } + } + + public virtual byte[] GetSigAlgParams() + { + return Arrays.Clone(sigAlgParams); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + X509Crl other = obj as X509Crl; + + if (other == null) + return false; + + return c.Equals(other.c); + + // NB: May prefer this implementation of Equals if more than one certificate implementation in play + //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded()); + } + + public override int GetHashCode() + { + return c.GetHashCode(); + } + + /** + * Returns a string representation of this CRL. + * + * @return a string representation of this CRL. + */ + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string nl = Platform.NewLine; + + buf.Append(" Version: ").Append(this.Version).Append(nl); + buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl); + buf.Append(" This update: ").Append(this.ThisUpdate).Append(nl); + buf.Append(" Next update: ").Append(this.NextUpdate).Append(nl); + buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl); + + byte[] sig = this.GetSignature(); + + buf.Append(" Signature: ").Append( + Encoding.ASCII.GetString(Hex.Encode(sig, 0, 20))).Append(nl); + for (int i = 20; i < sig.Length; i += 20) + { + if (i < sig.Length - 20) + { + buf.Append(" ").Append( + Encoding.ASCII.GetString(Hex.Encode(sig, i, 20))).Append(nl); + } + else + { + buf.Append(" ").Append( + Encoding.ASCII.GetString(Hex.Encode(sig, i, sig.Length - i))).Append(nl); + } + } + + X509Extensions extensions = c.TbsCertList.Extensions; + + if (extensions != null) + { + IEnumerator e = extensions.ExtensionOids.GetEnumerator(); + + if (e.MoveNext()) + { + buf.Append(" Extensions: ").Append(nl); + } + + do + { + DerObjectIdentifier oid = (DerObjectIdentifier) e.Current; + X509Extension ext = extensions.GetExtension(oid); + + if (ext.Value != null) + { + Asn1Object asn1Value = X509ExtensionUtilities.FromExtensionValue(ext.Value); + + buf.Append(" critical(").Append(ext.IsCritical).Append(") "); + try + { + if (oid.Equals(X509Extensions.CrlNumber)) + { + buf.Append(new CrlNumber(DerInteger.GetInstance(asn1Value).PositiveValue)).Append(nl); + } + else if (oid.Equals(X509Extensions.DeltaCrlIndicator)) + { + buf.Append( + "Base CRL: " + + new CrlNumber(DerInteger.GetInstance( + asn1Value).PositiveValue)) + .Append(nl); + } + else if (oid.Equals(X509Extensions.IssuingDistributionPoint)) + { + buf.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl); + } + else if (oid.Equals(X509Extensions.CrlDistributionPoints)) + { + buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl); + } + else if (oid.Equals(X509Extensions.FreshestCrl)) + { + buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl); + } + else + { + buf.Append(oid.Id); + buf.Append(" value = ").Append( + Asn1Dump.DumpAsString(asn1Value)) + .Append(nl); + } + } + catch (Exception) + { + buf.Append(oid.Id); + buf.Append(" value = ").Append("*****").Append(nl); + } + } + else + { + buf.Append(nl); + } + } + while (e.MoveNext()); + } + + ISet certSet = GetRevokedCertificates(); + if (certSet != null) + { + foreach (X509CrlEntry entry in certSet) + { + buf.Append(entry); + buf.Append(nl); + } + } + + return buf.ToString(); + } + + /** + * Checks whether the given certificate is on this CRL. + * + * @param cert the certificate to check for. + * @return true if the given certificate is on this CRL, + * false otherwise. + */ +// public bool IsRevoked( +// Certificate cert) +// { +// if (!cert.getType().Equals("X.509")) +// { +// throw new RuntimeException("X.509 CRL used with non X.509 Cert"); +// } + public virtual bool IsRevoked( + X509Certificate cert) + { + CrlEntry[] certs = c.GetRevokedCertificates(); + + if (certs != null) + { +// BigInteger serial = ((X509Certificate)cert).SerialNumber; + BigInteger serial = cert.SerialNumber; + + for (int i = 0; i < certs.Length; i++) + { + if (certs[i].UserCertificate.Value.Equals(serial)) + { + return true; + } + } + } + + return false; + } + + protected virtual bool IsIndirectCrl + { + get + { + Asn1OctetString idp = GetExtensionValue(X509Extensions.IssuingDistributionPoint); + bool isIndirect = false; + + try + { + if (idp != null) + { + isIndirect = IssuingDistributionPoint.GetInstance( + X509ExtensionUtilities.FromExtensionValue(idp)).IsIndirectCrl; + } + } + catch (Exception e) + { + // TODO +// throw new ExtCrlException("Exception reading IssuingDistributionPoint", e); + throw new CrlException("Exception reading IssuingDistributionPoint" + e); + } + + return isIndirect; + } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509CrlEntry.cs b/iTechSharp/srcbc/x509/X509CrlEntry.cs new file mode 100644 index 0000000..caca294 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509CrlEntry.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Utilities; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509 +{ + /** + * The following extensions are listed in RFC 2459 as relevant to CRL Entries + * + * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer + * (critical) + */ + public class X509CrlEntry + : X509ExtensionBase + { + private CrlEntry c; + private bool isIndirect; + private X509Name previousCertificateIssuer; + private X509Name certificateIssuer; + + public X509CrlEntry( + CrlEntry c) + { + this.c = c; + this.certificateIssuer = loadCertificateIssuer(); + } + + /** + * Constructor for CRLEntries of indirect CRLs. If isIndirect + * is false {@link #getCertificateIssuer()} will always + * return null, previousCertificateIssuer is + * ignored. If this isIndirect is specified and this CrlEntry + * has no certificate issuer CRL entry extension + * previousCertificateIssuer is returned by + * {@link #getCertificateIssuer()}. + * + * @param c + * TbsCertificateList.CrlEntry object. + * @param isIndirect + * true if the corresponding CRL is a indirect + * CRL. + * @param previousCertificateIssuer + * Certificate issuer of the previous CrlEntry. + */ + public X509CrlEntry( + CrlEntry c, + bool isIndirect, + X509Name previousCertificateIssuer) + { + this.c = c; + this.isIndirect = isIndirect; + this.previousCertificateIssuer = previousCertificateIssuer; + this.certificateIssuer = loadCertificateIssuer(); + } + + private X509Name loadCertificateIssuer() + { + if (!isIndirect) + { + return null; + } + + Asn1OctetString ext = GetExtensionValue(X509Extensions.CertificateIssuer); + if (ext == null) + { + return previousCertificateIssuer; + } + + try + { + GeneralName[] names = GeneralNames.GetInstance( + X509ExtensionUtilities.FromExtensionValue(ext)).GetNames(); + + for (int i = 0; i < names.Length; i++) + { + if (names[i].TagNo == GeneralName.DirectoryName) + { + return X509Name.GetInstance(names[i].Name); + } + } + } + catch (Exception) + { + } + + return null; + } + + public X509Name GetCertificateIssuer() + { + return certificateIssuer; + } + + protected override X509Extensions GetX509Extensions() + { + return c.Extensions; + } + + public byte[] GetEncoded() + { + try + { + return c.GetDerEncoded(); + } + catch (Exception e) + { + throw new CrlException(e.ToString()); + } + } + + public BigInteger SerialNumber + { + get { return c.UserCertificate.Value; } + } + + public DateTime RevocationDate + { + get { return c.RevocationDate.ToDateTime(); } + } + + public bool HasExtensions + { + get { return c.Extensions != null; } + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string nl = Platform.NewLine; + + buf.Append(" userCertificate: ").Append(this.SerialNumber).Append(nl); + buf.Append(" revocationDate: ").Append(this.RevocationDate).Append(nl); + buf.Append(" certificateIssuer: ").Append(this.GetCertificateIssuer()).Append(nl); + + X509Extensions extensions = c.Extensions; + + if (extensions != null) + { + IEnumerator e = extensions.ExtensionOids.GetEnumerator(); + if (e.MoveNext()) + { + buf.Append(" crlEntryExtensions:").Append(nl); + + do + { + DerObjectIdentifier oid = (DerObjectIdentifier)e.Current; + X509Extension ext = extensions.GetExtension(oid); + + if (ext.Value != null) + { + Asn1Object obj = Asn1Object.FromByteArray(ext.Value.GetOctets()); + + buf.Append(" critical(") + .Append(ext.IsCritical) + .Append(") "); + try + { + if (oid.Equals(X509Extensions.ReasonCode)) + { + buf.Append(new CrlReason(DerEnumerated.GetInstance(obj))); + } + else if (oid.Equals(X509Extensions.CertificateIssuer)) + { + buf.Append("Certificate issuer: ").Append( + GeneralNames.GetInstance((Asn1Sequence)obj)); + } + else + { + buf.Append(oid.Id); + buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj)); + } + buf.Append(nl); + } + catch (Exception) + { + buf.Append(oid.Id); + buf.Append(" value = ").Append("*****").Append(nl); + } + } + else + { + buf.Append(nl); + } + } + while (e.MoveNext()); + } + } + + return buf.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/x509/X509CrlParser.cs b/iTechSharp/srcbc/x509/X509CrlParser.cs new file mode 100644 index 0000000..b170642 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509CrlParser.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.X509 +{ + public class X509CrlParser + { + private static readonly PemParser PemCrlParser = new PemParser("CRL"); + + private readonly bool lazyAsn1; + + private Asn1Set sCrlData; + private int sCrlDataObjectCount; + private Stream currentCrlStream; + + public X509CrlParser() + : this(false) + { + } + + public X509CrlParser( + bool lazyAsn1) + { + this.lazyAsn1 = lazyAsn1; + } + + private X509Crl ReadPemCrl( + Stream inStream) + { + Asn1Sequence seq = PemCrlParser.ReadPemObject(inStream); + + return seq == null + ? null + : CreateX509Crl(CertificateList.GetInstance(seq)); + } + + private X509Crl ReadDerCrl( + Asn1InputStream dIn) + { + Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject(); + + if (seq.Count > 1 && seq[0] is DerObjectIdentifier) + { + if (seq[0].Equals(PkcsObjectIdentifiers.SignedData)) + { + sCrlData = SignedData.GetInstance( + Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Crls; + + return GetCrl(); + } + } + + return CreateX509Crl(CertificateList.GetInstance(seq)); + } + + private X509Crl GetCrl() + { + if (sCrlData == null || sCrlDataObjectCount >= sCrlData.Count) + { + return null; + } + + return CreateX509Crl( + CertificateList.GetInstance( + sCrlData[sCrlDataObjectCount++])); + } + + protected virtual X509Crl CreateX509Crl( + CertificateList c) + { + return new X509Crl(c); + } + + /// + /// Create loading data from byte array. + /// + /// + public X509Crl ReadCrl( + byte[] input) + { + return ReadCrl(new MemoryStream(input, false)); + } + + /// + /// Create loading data from byte array. + /// + /// + public ICollection ReadCrls( + byte[] input) + { + return ReadCrls(new MemoryStream(input, false)); + } + + /** + * Generates a certificate revocation list (CRL) object and initializes + * it with the data read from the input stream inStream. + */ + public X509Crl ReadCrl( + Stream inStream) + { + if (inStream == null) + throw new ArgumentNullException("inStream"); + if (!inStream.CanRead) + throw new ArgumentException("inStream must be read-able", "inStream"); + + if (currentCrlStream == null) + { + currentCrlStream = inStream; + sCrlData = null; + sCrlDataObjectCount = 0; + } + else if (currentCrlStream != inStream) // reset if input stream has changed + { + currentCrlStream = inStream; + sCrlData = null; + sCrlDataObjectCount = 0; + } + + try + { + if (sCrlData != null) + { + if (sCrlDataObjectCount != sCrlData.Count) + { + return GetCrl(); + } + + sCrlData = null; + sCrlDataObjectCount = 0; + return null; + } + + PushbackStream pis = new PushbackStream(inStream); + int tag = pis.ReadByte(); + + if (tag < 0) + return null; + + pis.Unread(tag); + + if (tag != 0x30) // assume ascii PEM encoded. + { + return ReadPemCrl(pis); + } + + Asn1InputStream asn1 = lazyAsn1 + ? new LazyAsn1InputStream(pis) + : new Asn1InputStream(pis); + + return ReadDerCrl(asn1); + } + catch (CrlException e) + { + throw e; + } + catch (Exception e) + { + throw new CrlException(e.ToString()); + } + } + + /** + * Returns a (possibly empty) collection view of the CRLs read from + * the given input stream inStream. + * + * The inStream may contain a sequence of DER-encoded CRLs, or + * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the + * only significant field being crls. In particular the signature + * and the contents are ignored. + */ + public ICollection ReadCrls( + Stream inStream) + { + X509Crl crl; + IList crls = new ArrayList(); + + while ((crl = ReadCrl(inStream)) != null) + { + crls.Add(crl); + } + + return crls; + } + } +} diff --git a/iTechSharp/srcbc/x509/X509ExtensionBase.cs b/iTechSharp/srcbc/x509/X509ExtensionBase.cs new file mode 100644 index 0000000..aaf6695 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509ExtensionBase.cs @@ -0,0 +1,82 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.X509 +{ + public abstract class X509ExtensionBase + : IX509Extension + { + protected abstract X509Extensions GetX509Extensions(); + + protected virtual ISet GetExtensionOids( + bool critical) + { + X509Extensions extensions = GetX509Extensions(); + if (extensions != null) + { + HashSet set = new HashSet(); + foreach (DerObjectIdentifier oid in extensions.ExtensionOids) + { + X509Extension ext = extensions.GetExtension(oid); + if (ext.IsCritical == critical) + { + set.Add(oid.Id); + } + } + + return set; + } + + return null; + } + + /// + /// Get non critical extensions. + /// + /// A set of non critical extension oids. + public virtual ISet GetNonCriticalExtensionOids() + { + return GetExtensionOids(false); + } + + /// + /// Get any critical extensions. + /// + /// A sorted list of critical entension. + public virtual ISet GetCriticalExtensionOids() + { + return GetExtensionOids(true); + } + + /// + /// Get the value of a given extension. + /// + /// The object ID of the extension. + /// An Asn1OctetString object if that extension is found or null if not. + [Obsolete("Use version taking a DerObjectIdentifier instead")] + public Asn1OctetString GetExtensionValue( + string oid) + { + return GetExtensionValue(new DerObjectIdentifier(oid)); + } + + public virtual Asn1OctetString GetExtensionValue( + DerObjectIdentifier oid) + { + X509Extensions exts = GetX509Extensions(); + if (exts != null) + { + X509Extension ext = exts.GetExtension(oid); + if (ext != null) + { + return ext.Value; + } + } + + return null; + } + } +} diff --git a/iTechSharp/srcbc/x509/X509KeyUsage.cs b/iTechSharp/srcbc/x509/X509KeyUsage.cs new file mode 100644 index 0000000..e0a7b49 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509KeyUsage.cs @@ -0,0 +1,59 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.X509 +{ + /** + * A holding class for constructing an X509 Key Usage extension. + * + *
      +	 *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
      +	 *
      +	 *    KeyUsage ::= BIT STRING {
      +	 *         digitalSignature        (0),
      +	 *         nonRepudiation          (1),
      +	 *         keyEncipherment         (2),
      +	 *         dataEncipherment        (3),
      +	 *         keyAgreement            (4),
      +	 *         keyCertSign             (5),
      +	 *         cRLSign                 (6),
      +	 *         encipherOnly            (7),
      +	 *         decipherOnly            (8) }
      +	 * 
      + */ + public class X509KeyUsage + : Asn1Encodable + { + public const int DigitalSignature = 1 << 7; + public const int NonRepudiation = 1 << 6; + public const int KeyEncipherment = 1 << 5; + public const int DataEncipherment = 1 << 4; + public const int KeyAgreement = 1 << 3; + public const int KeyCertSign = 1 << 2; + public const int CrlSign = 1 << 1; + public const int EncipherOnly = 1 << 0; + public const int DecipherOnly = 1 << 15; + + private readonly int usage; + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment) + */ + public X509KeyUsage( + int usage) + { + this.usage = usage; + } + + public override Asn1Object ToAsn1Object() + { + return new KeyUsage(usage); + } + } +} diff --git a/iTechSharp/srcbc/x509/X509SignatureUtil.cs b/iTechSharp/srcbc/x509/X509SignatureUtil.cs new file mode 100644 index 0000000..7a4ab14 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509SignatureUtil.cs @@ -0,0 +1,128 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.X509 +{ + internal class X509SignatureUtilities + { + private static readonly Asn1Null derNull = DerNull.Instance; + + internal static void SetSignatureParameters( + ISigner signature, + Asn1Encodable parameters) + { + if (parameters != null && !derNull.Equals(parameters)) + { + // TODO Put back in +// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm()); +// +// try +// { +// sigParams.Init(parameters.ToAsn1Object().GetDerEncoded()); +// } +// catch (IOException e) +// { +// throw new SignatureException("IOException decoding parameters: " + e.Message); +// } +// +// if (signature.getAlgorithm().EndsWith("MGF1")) +// { +// try +// { +// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class)); +// } +// catch (GeneralSecurityException e) +// { +// throw new SignatureException("Exception extracting parameters: " + e.Message); +// } +// } + } + } + + internal static string GetSignatureName( + AlgorithmIdentifier sigAlgId) + { + Asn1Encodable parameters = sigAlgId.Parameters; + + if (parameters != null && !derNull.Equals(parameters)) + { + if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss)) + { + RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters); + + return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1"; + } + if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2)) + { + Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters); + + return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA"; + } + } + + return sigAlgId.ObjectID.Id; + } + + /** + * Return the digest algorithm using one of the standard JCA string + * representations rather than the algorithm identifier (if possible). + */ + private static string GetDigestAlgName( + DerObjectIdentifier digestAlgOID) + { + if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID)) + { + return "MD5"; + } + else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID)) + { + return "SHA1"; + } + else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID)) + { + return "SHA224"; + } + else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID)) + { + return "SHA256"; + } + else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID)) + { + return "SHA384"; + } + else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID)) + { + return "SHA512"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID)) + { + return "RIPEMD128"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID)) + { + return "RIPEMD160"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID)) + { + return "RIPEMD256"; + } + else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID)) + { + return "GOST3411"; + } + else + { + return digestAlgOID.Id; + } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509Utilities.cs b/iTechSharp/srcbc/x509/X509Utilities.cs new file mode 100644 index 0000000..1940167 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509Utilities.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.X509 +{ + internal class X509Utilities + { + private static readonly Hashtable algorithms = new Hashtable(); + private static readonly Hashtable exParams = new Hashtable(); + private static readonly ISet noParams = new HashSet(); + + static X509Utilities() + { + algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption); + algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption); + algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption); + algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption); + algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption); + algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption); + algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption); + algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption); + algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption); + algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption); + algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss); + algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160); + algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160); + algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128); + algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128); + algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256); + algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256); + algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1); + algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1); + algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224); + algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256); + algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1); + algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224); + algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256); + algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384); + algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512); + algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + + // + // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. + // The parameters field SHALL be NULL for RSA based signature algorithms. + // + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384); + noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512); + noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1); + noParams.Add(NistObjectIdentifiers.DsaWithSha224); + noParams.Add(NistObjectIdentifiers.DsaWithSha256); + + // + // RFC 4491 + // + noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94); + noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001); + + // + // explicit params + // + AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance); + exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20)); + + AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance); + exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28)); + + AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance); + exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32)); + + AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance); + exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48)); + + AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance); + exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64)); + } + + private static RsassaPssParameters CreatePssParams( + AlgorithmIdentifier hashAlgId, + int saltSize) + { + return new RsassaPssParameters( + hashAlgId, + new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId), + new DerInteger(saltSize), + new DerInteger(1)); + } + + internal static DerObjectIdentifier GetAlgorithmOid( + string algorithmName) + { + algorithmName = algorithmName.ToUpper(CultureInfo.InvariantCulture); + + if (algorithms.ContainsKey(algorithmName)) + { + return (DerObjectIdentifier) algorithms[algorithmName]; + } + + return new DerObjectIdentifier(algorithmName); + } + + internal static AlgorithmIdentifier GetSigAlgID( + DerObjectIdentifier sigOid, + string algorithmName) + { + if (noParams.Contains(sigOid)) + { + return new AlgorithmIdentifier(sigOid); + } + + algorithmName = algorithmName.ToUpper(CultureInfo.InvariantCulture); + + if (exParams.ContainsKey(algorithmName)) + { + return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]); + } + + return new AlgorithmIdentifier(sigOid, DerNull.Instance); + } + + internal static IEnumerable GetAlgNames() + { + return new EnumerableProxy(algorithms.Keys); + } + + internal static byte[] GetSignatureForObject( + DerObjectIdentifier sigOid, // TODO Redundant now? + string sigName, + AsymmetricKeyParameter privateKey, + SecureRandom random, + Asn1Encodable ae) + { + if (sigOid == null) + throw new ArgumentNullException("sigOid"); + + ISigner sig = SignerUtilities.GetSigner(sigName); + + if (random != null) + { + sig.Init(true, new ParametersWithRandom(privateKey, random)); + } + else + { + sig.Init(true, privateKey); + } + + byte[] encoded = ae.GetDerEncoded(); + sig.BlockUpdate(encoded, 0, encoded.Length); + + return sig.GenerateSignature(); + } + } +} diff --git a/iTechSharp/srcbc/x509/X509V1CertificateGenerator.cs b/iTechSharp/srcbc/x509/X509V1CertificateGenerator.cs new file mode 100644 index 0000000..02b58a1 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509V1CertificateGenerator.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; + +namespace Org.BouncyCastle.X509 +{ + /// + /// Class to Generate X509V1 Certificates. + /// + public class X509V1CertificateGenerator + { + private V1TbsCertificateGenerator tbsGen; + private DerObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private string signatureAlgorithm; + + /// + /// Default Constructor. + /// + public X509V1CertificateGenerator() + { + tbsGen = new V1TbsCertificateGenerator(); + } + + /// + /// Reset the generator. + /// + public void Reset() + { + tbsGen = new V1TbsCertificateGenerator(); + } + + /// + /// Set the certificate's serial number. + /// + /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data. + /// You will be surprised how ugly a serial number collision can get. + /// The serial number. + public void SetSerialNumber( + BigInteger serialNumber) + { + if (serialNumber.SignValue <= 0) + { + throw new ArgumentException("serial number must be a positive integer", "serialNumber"); + } + + tbsGen.SetSerialNumber(new DerInteger(serialNumber)); + } + + /// + /// Set the issuer distinguished name. + /// The issuer is the entity whose private key is used to sign the certificate. + /// + /// The issuers DN. + public void SetIssuerDN( + X509Name issuer) + { + tbsGen.SetIssuer(issuer); + } + + /// + /// Set the date that this certificate is to be valid from. + /// + /// + public void SetNotBefore( + DateTime date) + { + tbsGen.SetStartDate(new Time(date)); + } + + /// + /// Set the date after which this certificate will no longer be valid. + /// + /// + public void SetNotAfter( + DateTime date) + { + tbsGen.SetEndDate(new Time(date)); + } + + /// + /// Set the subject distinguished name. + /// The subject describes the entity associated with the public key. + /// + /// + public void SetSubjectDN( + X509Name subject) + { + tbsGen.SetSubject(subject); + } + + /// + /// Set the public key that this certificate identifies. + /// + /// + public void SetPublicKey( + AsymmetricKeyParameter publicKey) + { + try + { + tbsGen.SetSubjectPublicKeyInfo( + SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey)); + } + catch (Exception e) + { + throw new ArgumentException("unable to process key - " + e.ToString()); + } + } + + /// + /// Set the signature algorithm that will be used to sign this certificate. + /// This can be either a name or an OID, names are treated as case insensitive. + /// + /// string representation of the algorithm name + public void SetSignatureAlgorithm( + string signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm); + } + catch (Exception) + { + throw new ArgumentException("Unknown signature type requested", "signatureAlgorithm"); + } + + sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm); + + tbsGen.SetSignature(sigAlgId); + } + + /// + /// Generate a new X509Certificate. + /// + /// The private key of the issuer used to sign this certificate. + /// An X509Certificate. + public X509Certificate Generate( + AsymmetricKeyParameter privateKey) + { + return Generate(privateKey, null); + } + + /// + /// Generate a new X509Certificate specifying a SecureRandom instance that you would like to use. + /// + /// The private key of the issuer used to sign this certificate. + /// The Secure Random you want to use. + /// An X509Certificate. + public X509Certificate Generate( + AsymmetricKeyParameter privateKey, + SecureRandom random) + { + TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate(); + byte[] signature; + + try + { + signature = X509Utilities.GetSignatureForObject( + sigOID, signatureAlgorithm, privateKey, random, tbsCert); + } + catch (Exception e) + { + // TODO +// throw new ExtCertificateEncodingException("exception encoding TBS cert", e); + throw new CertificateEncodingException("exception encoding TBS cert", e); + } + + try + { + return GenerateJcaObject(tbsCert, signature); + } + catch (CertificateParsingException e) + { + // TODO + // throw new ExtCertificateEncodingException("exception producing certificate object", e); + throw new CertificateEncodingException("exception producing certificate object", e); + } + } + + private X509Certificate GenerateJcaObject( + TbsCertificateStructure tbsCert, + byte[] signature) + { + return new X509Certificate( + new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature))); + } + + /// + /// Allows enumeration of the signature names supported by the generator. + /// + public IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509V2AttributeCertificate.cs b/iTechSharp/srcbc/x509/X509V2AttributeCertificate.cs new file mode 100644 index 0000000..44a9f5b --- /dev/null +++ b/iTechSharp/srcbc/x509/X509V2AttributeCertificate.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; + +namespace Org.BouncyCastle.X509 +{ + /// An implementation of a version 2 X.509 Attribute Certificate. + public class X509V2AttributeCertificate + : X509ExtensionBase, IX509AttributeCertificate + { + private readonly AttributeCertificate cert; + private readonly DateTime notBefore; + private readonly DateTime notAfter; + + public X509V2AttributeCertificate( + Stream encIn) + : this(new Asn1InputStream(encIn)) + { + } + + public X509V2AttributeCertificate( + byte[] encoded) + : this(new Asn1InputStream(encoded)) + { + } + + internal X509V2AttributeCertificate( + Asn1InputStream ais) + : this(AttributeCertificate.GetInstance(ais.ReadObject())) + { + } + + internal X509V2AttributeCertificate( + AttributeCertificate cert) + { + this.cert = cert; + + try + { + this.notAfter = cert.ACInfo.AttrCertValidityPeriod.NotAfterTime.ToDateTime(); + this.notBefore = cert.ACInfo.AttrCertValidityPeriod.NotBeforeTime.ToDateTime(); + } + catch (Exception e) + { + throw new IOException("invalid data structure in certificate!", e); + } + } + + public virtual int Version + { + get { return cert.ACInfo.Version.Value.IntValue; } + } + + public virtual BigInteger SerialNumber + { + get { return cert.ACInfo.SerialNumber.Value; } + } + + public virtual AttributeCertificateHolder Holder + { + get + { + return new AttributeCertificateHolder((Asn1Sequence)cert.ACInfo.Holder.ToAsn1Object()); + } + } + + public virtual AttributeCertificateIssuer Issuer + { + get + { + return new AttributeCertificateIssuer(cert.ACInfo.Issuer); + } + } + + public virtual DateTime NotBefore + { + get { return notBefore; } + } + + public virtual DateTime NotAfter + { + get { return notAfter; } + } + + public virtual bool[] GetIssuerUniqueID() + { + DerBitString id = cert.ACInfo.IssuerUniqueID; + + if (id != null) + { + byte[] bytes = id.GetBytes(); + bool[] boolId = new bool[bytes.Length * 8 - id.PadBits]; + + for (int i = 0; i != boolId.Length; i++) + { + //boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + boolId[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public virtual bool IsValidNow + { + get { return IsValid(DateTime.UtcNow); } + } + + public virtual bool IsValid( + DateTime date) + { + return date.CompareTo(NotBefore) >= 0 && date.CompareTo(NotAfter) <= 0; + } + + public virtual void CheckValidity() + { + this.CheckValidity(DateTime.UtcNow); + } + + public virtual void CheckValidity( + DateTime date) + { + if (date.CompareTo(NotAfter) > 0) + throw new CertificateExpiredException("certificate expired on " + NotAfter); + if (date.CompareTo(NotBefore) < 0) + throw new CertificateNotYetValidException("certificate not valid until " + NotBefore); + } + + public virtual byte[] GetSignature() + { + return cert.SignatureValue.GetBytes(); + } + + public virtual void Verify( + AsymmetricKeyParameter publicKey) + { + if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature)) + { + throw new CertificateException("Signature algorithm in certificate info not same as outer certificate"); + } + + ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id); + + signature.Init(false, publicKey); + + try + { + byte[] b = cert.ACInfo.GetEncoded(); + signature.BlockUpdate(b, 0, b.Length); + } + catch (IOException e) + { + throw new SignatureException("Exception encoding certificate info object", e); + } + + if (!signature.VerifySignature(this.GetSignature())) + { + throw new InvalidKeyException("Public key presented not for certificate signature"); + } + } + + public virtual byte[] GetEncoded() + { + return cert.GetEncoded(); + } + + protected override X509Extensions GetX509Extensions() + { + return cert.ACInfo.Extensions; + } + + public virtual X509Attribute[] GetAttributes() + { + Asn1Sequence seq = cert.ACInfo.Attributes; + X509Attribute[] attrs = new X509Attribute[seq.Count]; + + for (int i = 0; i != seq.Count; i++) + { + attrs[i] = new X509Attribute((Asn1Encodable)seq[i]); + } + + return attrs; + } + + public virtual X509Attribute[] GetAttributes( + string oid) + { + Asn1Sequence seq = cert.ACInfo.Attributes; + ArrayList list = new ArrayList(); + + for (int i = 0; i != seq.Count; i++) + { + X509Attribute attr = new X509Attribute((Asn1Encodable)seq[i]); + if (attr.Oid.Equals(oid)) + { + list.Add(attr); + } + } + + if (list.Count < 1) + { + return null; + } + + return (X509Attribute[]) list.ToArray(typeof(X509Attribute)); + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + X509V2AttributeCertificate other = obj as X509V2AttributeCertificate; + + if (other == null) + return false; + + return cert.Equals(other.cert); + + // NB: May prefer this implementation of Equals if more than one certificate implementation in play + //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded()); + } + + public override int GetHashCode() + { + return cert.GetHashCode(); + } + } +} diff --git a/iTechSharp/srcbc/x509/X509V2AttributeCertificateGenerator.cs b/iTechSharp/srcbc/x509/X509V2AttributeCertificateGenerator.cs new file mode 100644 index 0000000..a683d5e --- /dev/null +++ b/iTechSharp/srcbc/x509/X509V2AttributeCertificateGenerator.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.X509 +{ + /// Class to produce an X.509 Version 2 AttributeCertificate. + public class X509V2AttributeCertificateGenerator + { + private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator(); + + private V2AttributeCertificateInfoGenerator acInfoGen; + private DerObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private string signatureAlgorithm; + + public X509V2AttributeCertificateGenerator() + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + } + + /// Reset the generator + public void Reset() + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + extGenerator.Reset(); + } + + /// Set the Holder of this Attribute Certificate. + public void SetHolder( + AttributeCertificateHolder holder) + { + acInfoGen.SetHolder(holder.holder); + } + + /// Set the issuer. + public void SetIssuer( + AttributeCertificateIssuer issuer) + { + acInfoGen.SetIssuer(AttCertIssuer.GetInstance(issuer.form)); + } + + /// Set the serial number for the certificate. + public void SetSerialNumber( + BigInteger serialNumber) + { + acInfoGen.SetSerialNumber(new DerInteger(serialNumber)); + } + + public void SetNotBefore( + DateTime date) + { + acInfoGen.SetStartDate(new DerGeneralizedTime(date)); + } + + public void SetNotAfter( + DateTime date) + { + acInfoGen.SetEndDate(new DerGeneralizedTime(date)); + } + + /// + /// Set the signature algorithm. This can be either a name or an OID, names + /// are treated as case insensitive. + /// + /// The algorithm name. + public void SetSignatureAlgorithm( + string signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm); + } + catch (Exception) + { + throw new ArgumentException("Unknown signature type requested"); + } + + sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm); + + acInfoGen.SetSignature(sigAlgId); + } + + /// Add an attribute. + public void AddAttribute( + X509Attribute attribute) + { + acInfoGen.AddAttribute(AttributeX509.GetInstance(attribute.ToAsn1Object())); + } + + public void SetIssuerUniqueId( + bool[] iui) + { + // TODO convert bool array to bit string + //acInfoGen.SetIssuerUniqueID(iui); + throw Platform.CreateNotImplementedException("SetIssuerUniqueId()"); + } + + /// Add a given extension field for the standard extensions tag. + public void AddExtension( + string oid, + bool critical, + Asn1Encodable extensionValue) + { + extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue); + } + + /// + /// Add a given extension field for the standard extensions tag. + /// The value parameter becomes the contents of the octet string associated + /// with the extension. + /// + public void AddExtension( + string oid, + bool critical, + byte[] extensionValue) + { + extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue); + } + + /// + /// Generate an X509 certificate, based on the current issuer and subject. + /// + public IX509AttributeCertificate Generate( + AsymmetricKeyParameter publicKey) + { + return Generate(publicKey, null); + } + + /// + /// Generate an X509 certificate, based on the current issuer and subject, + /// using the supplied source of randomness, if required. + /// + public IX509AttributeCertificate Generate( + AsymmetricKeyParameter publicKey, + SecureRandom random) + { + if (!extGenerator.IsEmpty) + { + acInfoGen.SetExtensions(extGenerator.Generate()); + } + + AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo(); + + Asn1EncodableVector v = new Asn1EncodableVector(); + + v.Add(acInfo, sigAlgId); + + try + { + v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo))); + + return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v))); + } + catch (Exception e) + { + // TODO +// throw new ExtCertificateEncodingException("constructed invalid certificate", e); + throw new CertificateEncodingException("constructed invalid certificate", e); + } + } + + /// + /// Allows enumeration of the signature names supported by the generator. + /// + public IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509V2CRLGenerator.cs b/iTechSharp/srcbc/x509/X509V2CRLGenerator.cs new file mode 100644 index 0000000..a2293b3 --- /dev/null +++ b/iTechSharp/srcbc/x509/X509V2CRLGenerator.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.X509 +{ + /** + * class to produce an X.509 Version 2 CRL. + */ + public class X509V2CrlGenerator + { + private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator(); + + private V2TbsCertListGenerator tbsGen; + private DerObjectIdentifier sigOID; + private AlgorithmIdentifier sigAlgId; + private string signatureAlgorithm; + + public X509V2CrlGenerator() + { + tbsGen = new V2TbsCertListGenerator(); + } + + /** + * reset the generator + */ + public void Reset() + { + tbsGen = new V2TbsCertListGenerator(); + extGenerator.Reset(); + } + + /** + * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the + * certificate. + */ + public void SetIssuerDN( + X509Name issuer) + { + tbsGen.SetIssuer(issuer); + } + + public void SetThisUpdate( + DateTime date) + { + tbsGen.SetThisUpdate(new Time(date)); + } + + public void SetNextUpdate( + DateTime date) + { + tbsGen.SetNextUpdate(new Time(date)); + } + + /** + * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise + * or 0 if CrlReason is not to be used + **/ + public void AddCrlEntry( + BigInteger userCertificate, + DateTime revocationDate, + int reason) + { + tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason); + } + + /** + * Add a CRL entry with an Invalidity Date extension as well as a CrlReason extension. + * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise + * or 0 if CrlReason is not to be used + **/ + public void AddCrlEntry( + BigInteger userCertificate, + DateTime revocationDate, + int reason, + DateTime invalidityDate) + { + tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason, new DerGeneralizedTime(invalidityDate)); + } + + /** + * Add a CRL entry with extensions. + **/ + public void AddCrlEntry( + BigInteger userCertificate, + DateTime revocationDate, + X509Extensions extensions) + { + tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), extensions); + } + + /** + * Add the CRLEntry objects contained in a previous CRL. + * + * @param other the X509Crl to source the other entries from. + */ + public void AddCrl( + X509Crl other) + { + if (other == null) + throw new ArgumentNullException("other"); + + ISet revocations = other.GetRevokedCertificates(); + + if (revocations != null) + { + foreach (X509CrlEntry entry in revocations) + { + try + { + tbsGen.AddCrlEntry( + Asn1Sequence.GetInstance( + Asn1Object.FromByteArray(entry.GetEncoded()))); + } + catch (IOException e) + { + throw new CrlException("exception processing encoding of CRL", e); + } + } + } + } + + /** + * Set the signature algorithm. This can be either a name or an oid, names + * are treated as case insensitive. + * + * @param signatureAlgorithm string representation of the algorithm name. + */ + public void SetSignatureAlgorithm( + string signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm); + } + catch (Exception e) + { + throw new ArgumentException("Unknown signature type requested", e); + } + + sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm); + + tbsGen.SetSignature(sigAlgId); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void AddExtension( + string oid, + bool critical, + Asn1Encodable extensionValue) + { + extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void AddExtension( + DerObjectIdentifier oid, + bool critical, + Asn1Encodable extensionValue) + { + extGenerator.AddExtension(oid, critical, extensionValue); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void AddExtension( + string oid, + bool critical, + byte[] extensionValue) + { + extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue)); + } + + /** + * add a given extension field for the standard extensions tag (tag 0) + */ + public void AddExtension( + DerObjectIdentifier oid, + bool critical, + byte[] extensionValue) + { + extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue)); + } + + /// Generate an X509 CRL, based on the current issuer and subject. + /// The key used for signing. + public X509Crl Generate( + AsymmetricKeyParameter privateKey) + { + return Generate(privateKey, null); + } + + /// Generate an X509 CRL, based on the current issuer and subject. + /// The key used for signing. + /// A user-defined source of randomness. + public X509Crl Generate( + AsymmetricKeyParameter privateKey, + SecureRandom random) + { + TbsCertificateList tbsCrl = GenerateCertList(); + byte[] signature; + + try + { + signature = X509Utilities.GetSignatureForObject( + sigOID, signatureAlgorithm, privateKey, random, tbsCrl); + } + catch (IOException e) + { + // TODO +// throw new ExtCrlException("cannot generate CRL encoding", e); + throw new CrlException("cannot generate CRL encoding", e); + } + + return GenerateJcaObject(tbsCrl, signature); + } + + private TbsCertificateList GenerateCertList() + { + if (!extGenerator.IsEmpty) + { + tbsGen.SetExtensions(extGenerator.Generate()); + } + + return tbsGen.GenerateTbsCertList(); + } + + private X509Crl GenerateJcaObject( + TbsCertificateList tbsCrl, + byte[] signature) + { + return new X509Crl( + CertificateList.GetInstance( + new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature)))); + } + + /// + /// Allows enumeration of the signature names supported by the generator. + /// + public IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } +} diff --git a/iTechSharp/srcbc/x509/X509V3CertificateGenerator.cs b/iTechSharp/srcbc/x509/X509V3CertificateGenerator.cs new file mode 100644 index 0000000..32fa7ec --- /dev/null +++ b/iTechSharp/srcbc/x509/X509V3CertificateGenerator.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509 +{ + /// + /// A class to Generate Version 3 X509Certificates. + /// + public class X509V3CertificateGenerator + { + private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator(); + + private V3TbsCertificateGenerator tbsGen; + private DerObjectIdentifier sigOid; + private AlgorithmIdentifier sigAlgId; + private string signatureAlgorithm; + + public X509V3CertificateGenerator() + { + tbsGen = new V3TbsCertificateGenerator(); + } + + /// + /// Reset the Generator. + /// + public void Reset() + { + tbsGen = new V3TbsCertificateGenerator(); + extGenerator.Reset(); + } + + /// + /// Set the certificate's serial number. + /// + /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data. + /// You will be surprised how ugly a serial number collision can Get. + /// The serial number. + public void SetSerialNumber( + BigInteger serialNumber) + { + if (serialNumber.SignValue <= 0) + { + throw new ArgumentException("serial number must be a positive integer", "serialNumber"); + } + + tbsGen.SetSerialNumber(new DerInteger(serialNumber)); + } + + /// + /// Set the distinguished name of the issuer. + /// The issuer is the entity which is signing the certificate. + /// + /// The issuer's DN. + public void SetIssuerDN( + X509Name issuer) + { + tbsGen.SetIssuer(issuer); + } + + /// + /// Set the date that this certificate is to be valid from. + /// + /// + public void SetNotBefore( + DateTime date) + { + tbsGen.SetStartDate(new Time(date)); + } + + /// + /// Set the date after which this certificate will no longer be valid. + /// + /// + public void SetNotAfter( + DateTime date) + { + tbsGen.SetEndDate(new Time(date)); + } + + /// + /// Set the DN of the entity that this certificate is about. + /// + /// + public void SetSubjectDN( + X509Name subject) + { + tbsGen.SetSubject(subject); + } + + /// + /// Set the public key that this certificate identifies. + /// + /// + public void SetPublicKey( + AsymmetricKeyParameter publicKey) + { + tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey)); + } + + /// + /// Set the signature algorithm that will be used to sign this certificate. + /// + /// + public void SetSignatureAlgorithm( + string signatureAlgorithm) + { + this.signatureAlgorithm = signatureAlgorithm; + + try + { + sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm); + } + catch (Exception) + { + throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm); + } + + sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm); + + tbsGen.SetSignature(sigAlgId); + } + + /// + /// Add a given extension field for the standard extensions tag (tag 3). + /// + /// string containing a dotted decimal Object Identifier. + /// Is it critical. + /// The value. + public void AddExtension( + string oid, + bool critical, + Asn1Encodable extensionValue) + { + extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue); + } + + /// + /// Add an extension to this certificate. + /// + /// Its Object Identifier. + /// Is it critical. + /// The value. + public void AddExtension( + DerObjectIdentifier oid, + bool critical, + Asn1Encodable extensionValue) + { + extGenerator.AddExtension(oid, critical, extensionValue); + } + + /// + /// Add an extension using a string with a dotted decimal OID. + /// + /// string containing a dotted decimal Object Identifier. + /// Is it critical. + /// byte[] containing the value of this extension. + public void AddExtension( + string oid, + bool critical, + byte[] extensionValue) + { + extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue)); + } + + /// + /// Add an extension to this certificate. + /// + /// Its Object Identifier. + /// Is it critical. + /// byte[] containing the value of this extension. + public void AddExtension( + DerObjectIdentifier oid, + bool critical, + byte[] extensionValue) + { + extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue)); + } + + /// + /// Add a given extension field for the standard extensions tag (tag 3), + /// copying the extension value from another certificate. + /// + public void CopyAndAddExtension( + string oid, + bool critical, + X509Certificate cert) + { + CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert); + } + + /** + * add a given extension field for the standard extensions tag (tag 3) + * copying the extension value from another certificate. + * @throws CertificateParsingException if the extension cannot be extracted. + */ + public void CopyAndAddExtension( + DerObjectIdentifier oid, + bool critical, + X509Certificate cert) + { + Asn1OctetString extValue = cert.GetExtensionValue(oid); + + if (extValue == null) + { + throw new CertificateParsingException("extension " + oid + " not present"); + } + + try + { + Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue); + + this.AddExtension(oid, critical, value); + } + catch (Exception e) + { + throw new CertificateParsingException(e.Message, e); + } + } + + /// + /// Generate an X509Certificate. + /// + /// The private key of the issuer that is signing this certificate. + /// An X509Certificate. + public X509Certificate Generate( + AsymmetricKeyParameter privateKey) + { + return Generate(privateKey, null); + } + + /// + /// Generate an X509Certificate using your own SecureRandom. + /// + /// The private key of the issuer that is signing this certificate. + /// You Secure Random instance. + /// An X509Certificate. + public X509Certificate Generate( + AsymmetricKeyParameter privateKey, + SecureRandom random) + { + TbsCertificateStructure tbsCert = GenerateTbsCert(); + byte[] signature; + + try + { + signature = X509Utilities.GetSignatureForObject( + sigOid, signatureAlgorithm, privateKey, random, tbsCert); + } + catch (Exception e) + { + // TODO +// throw new ExtCertificateEncodingException("exception encoding TBS cert", e); + throw new CertificateEncodingException("exception encoding TBS cert", e); + } + + try + { + return GenerateJcaObject(tbsCert, signature); + } + catch (CertificateParsingException e) + { + // TODO + // throw new ExtCertificateEncodingException("exception producing certificate object", e); + throw new CertificateEncodingException("exception producing certificate object", e); + } + } + + private TbsCertificateStructure GenerateTbsCert() + { + if (!extGenerator.IsEmpty) + { + tbsGen.SetExtensions(extGenerator.Generate()); + } + + return tbsGen.GenerateTbsCertificate(); + } + + private X509Certificate GenerateJcaObject( + TbsCertificateStructure tbsCert, + byte[] signature) + { + return new X509Certificate( + new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature))); + } + + /// + /// Allows enumeration of the signature names supported by the generator. + /// + public IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } +} diff --git a/iTechSharp/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs b/iTechSharp/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs new file mode 100644 index 0000000..2725ba2 --- /dev/null +++ b/iTechSharp/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs @@ -0,0 +1,105 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; + +namespace Org.BouncyCastle.X509.Extension +{ + /// A high level authority key identifier. + public class AuthorityKeyIdentifierStructure + : AuthorityKeyIdentifier + { + /** + * Constructor which will take the byte[] returned from getExtensionValue() + * + * @param encodedValue a DER octet encoded string with the extension structure in it. + * @throws IOException on parsing errors. + */ + // TODO Add a functional constructor from byte[]? + public AuthorityKeyIdentifierStructure( + Asn1OctetString encodedValue) + : base((Asn1Sequence) X509ExtensionUtilities.FromExtensionValue(encodedValue)) + { + } + + private static Asn1Sequence FromCertificate( + X509Certificate certificate) + { + try + { + GeneralName genName = new GeneralName( + PrincipalUtilities.GetIssuerX509Principal(certificate)); + + if (certificate.Version == 3) + { + Asn1OctetString ext = certificate.GetExtensionValue(X509Extensions.SubjectKeyIdentifier); + + if (ext != null) + { + Asn1OctetString str = (Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(ext); + + return (Asn1Sequence) new AuthorityKeyIdentifier( + str.GetOctets(), new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object(); + } + } + + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo( + certificate.GetPublicKey()); + + return (Asn1Sequence) new AuthorityKeyIdentifier( + info, new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object(); + } + catch (Exception e) + { + throw new CertificateParsingException("Exception extracting certificate details", e); + } + } + + private static Asn1Sequence FromKey( + AsymmetricKeyParameter pubKey) + { + try + { +// SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( +// (Asn1Sequence) Asn1Object.FromByteArray( +// pubKey.GetEncoded())); + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey); + + return (Asn1Sequence) new AuthorityKeyIdentifier(info).ToAsn1Object(); + } + catch (Exception e) + { + throw new InvalidKeyException("can't process key: " + e); + } + } + + /** + * Create an AuthorityKeyIdentifier using the passed in certificate's public + * key, issuer and serial number. + * + * @param certificate the certificate providing the information. + * @throws CertificateParsingException if there is a problem processing the certificate + */ + public AuthorityKeyIdentifierStructure( + X509Certificate certificate) + : base(FromCertificate(certificate)) + { + } + + /** + * Create an AuthorityKeyIdentifier using just the hash of the + * public key. + * + * @param pubKey the key to generate the hash from. + * @throws InvalidKeyException if there is a problem using the key. + */ + public AuthorityKeyIdentifierStructure( + AsymmetricKeyParameter pubKey) + : base(FromKey(pubKey)) + { + } + } +} diff --git a/iTechSharp/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs b/iTechSharp/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs new file mode 100644 index 0000000..0b4d9c7 --- /dev/null +++ b/iTechSharp/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs @@ -0,0 +1,51 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security.Certificates; + +namespace Org.BouncyCastle.X509.Extension +{ + /** + * A high level subject key identifier. + */ + public class SubjectKeyIdentifierStructure + : SubjectKeyIdentifier + { +// private AuthorityKeyIdentifier authKeyID; + + /** + * Constructor which will take the byte[] returned from getExtensionValue() + * + * @param encodedValue a DER octet encoded string with the extension structure in it. + * @throws IOException on parsing errors. + */ + public SubjectKeyIdentifierStructure( + Asn1OctetString encodedValue) + : base((Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(encodedValue)) + { + } + + private static Asn1OctetString FromPublicKey( + AsymmetricKeyParameter pubKey) + { + try + { + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey); + + return (Asn1OctetString) new SubjectKeyIdentifier(info).ToAsn1Object(); + } + catch (Exception e) + { + throw new CertificateParsingException("Exception extracting certificate details: " + e.ToString()); + } + } + + public SubjectKeyIdentifierStructure( + AsymmetricKeyParameter pubKey) + : base(FromPublicKey(pubKey)) + { + } + } +} diff --git a/iTechSharp/srcbc/x509/extension/X509ExtensionUtil.cs b/iTechSharp/srcbc/x509/extension/X509ExtensionUtil.cs new file mode 100644 index 0000000..419bc66 --- /dev/null +++ b/iTechSharp/srcbc/x509/extension/X509ExtensionUtil.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security.Certificates; + +namespace Org.BouncyCastle.X509.Extension +{ + public class X509ExtensionUtilities + { + public static Asn1Object FromExtensionValue( + Asn1OctetString extensionValue) + { + return Asn1Object.FromByteArray(extensionValue.GetOctets()); + } + + public static ICollection GetIssuerAlternativeNames( + X509Certificate cert) + { + Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.IssuerAlternativeName); + + return GetAlternativeName(extVal); + } + + public static ICollection GetSubjectAlternativeNames( + X509Certificate cert) + { + Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.SubjectAlternativeName); + + return GetAlternativeName(extVal); + } + + private static ICollection GetAlternativeName( + Asn1OctetString extVal) + { + ArrayList temp = new ArrayList(); + + if (extVal != null) + { + try + { + Asn1Sequence seq = DerSequence.GetInstance(FromExtensionValue(extVal)); + + foreach (GeneralName genName in seq) + { + ArrayList list = new ArrayList(); + list.Add(genName.TagNo); + + switch (genName.TagNo) + { + case GeneralName.EdiPartyName: + case GeneralName.X400Address: + case GeneralName.OtherName: + list.Add(genName.Name.ToAsn1Object()); + break; + case GeneralName.DirectoryName: + list.Add(X509Name.GetInstance(genName.Name).ToString()); + break; + case GeneralName.DnsName: + case GeneralName.Rfc822Name: + case GeneralName.UniformResourceIdentifier: + list.Add(((IAsn1String)genName.Name).GetString()); + break; + case GeneralName.RegisteredID: + list.Add(DerObjectIdentifier.GetInstance(genName.Name).Id); + break; + case GeneralName.IPAddress: + list.Add(DerOctetString.GetInstance(genName.Name).GetOctets()); + break; + default: + throw new IOException("Bad tag number: " + genName.TagNo); + } + + temp.Add(list); + } + } + catch (Exception e) + { + throw new CertificateParsingException(e.Message); + } + } + + return temp; + } + } +} diff --git a/iTechSharp/srcbc/x509/store/IX509Selector.cs b/iTechSharp/srcbc/x509/store/IX509Selector.cs new file mode 100644 index 0000000..5f1eee9 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/IX509Selector.cs @@ -0,0 +1,10 @@ +using System; + +namespace Org.BouncyCastle.X509.Store +{ + public interface IX509Selector + : ICloneable + { + bool Match(object obj); + } +} diff --git a/iTechSharp/srcbc/x509/store/IX509Store.cs b/iTechSharp/srcbc/x509/store/IX509Store.cs new file mode 100644 index 0000000..e5c3a46 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/IX509Store.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.X509.Store +{ + public interface IX509Store + { +// void Init(IX509StoreParameters parameters); + ICollection GetMatches(IX509Selector selector); + } +} diff --git a/iTechSharp/srcbc/x509/store/IX509StoreParameters.cs b/iTechSharp/srcbc/x509/store/IX509StoreParameters.cs new file mode 100644 index 0000000..aee3036 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/IX509StoreParameters.cs @@ -0,0 +1,8 @@ +using System; + +namespace Org.BouncyCastle.X509.Store +{ + public interface IX509StoreParameters + { + } +} diff --git a/iTechSharp/srcbc/x509/store/NoSuchStoreException.cs b/iTechSharp/srcbc/x509/store/NoSuchStoreException.cs new file mode 100644 index 0000000..3df26de --- /dev/null +++ b/iTechSharp/srcbc/x509/store/NoSuchStoreException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.X509.Store +{ + public class NoSuchStoreException + : X509StoreException + { + public NoSuchStoreException() + { + } + + public NoSuchStoreException( + string message) + : base(message) + { + } + + public NoSuchStoreException( + string message, + Exception e) + : base(message, e) + { + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509AttrCertStoreSelector.cs b/iTechSharp/srcbc/x509/store/X509AttrCertStoreSelector.cs new file mode 100644 index 0000000..9f1dc20 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509AttrCertStoreSelector.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509.Store +{ + /** + * This class is an Selector like implementation to select + * attribute certificates from a given set of criteria. + * + * @see org.bouncycastle.x509.X509AttributeCertificate + * @see org.bouncycastle.x509.X509Store + */ + public class X509AttrCertStoreSelector + : IX509Selector + { + // TODO: name constraints??? + + private IX509AttributeCertificate attributeCert; + private DateTimeObject attributeCertificateValid; + private AttributeCertificateHolder holder; + private AttributeCertificateIssuer issuer; + private BigInteger serialNumber; + private ISet targetNames = new HashSet(); + private ISet targetGroups = new HashSet(); + + public X509AttrCertStoreSelector() + { + } + + private X509AttrCertStoreSelector( + X509AttrCertStoreSelector o) + { + this.attributeCert = o.attributeCert; + this.attributeCertificateValid = o.attributeCertificateValid; + this.holder = o.holder; + this.issuer = o.issuer; + this.serialNumber = o.serialNumber; + this.targetGroups = new HashSet(o.targetGroups); + this.targetNames = new HashSet(o.targetNames); + } + + /// + /// Decides if the given attribute certificate should be selected. + /// + /// The attribute certificate to be checked. + /// true if the object matches this selector. + public bool Match( + object obj) + { + if (obj == null) + throw new ArgumentNullException("obj"); + + IX509AttributeCertificate attrCert = obj as IX509AttributeCertificate; + + if (attrCert == null) + return false; + + if (this.attributeCert != null && !this.attributeCert.Equals(attrCert)) + return false; + + if (serialNumber != null && !attrCert.SerialNumber.Equals(serialNumber)) + return false; + + if (holder != null && !attrCert.Holder.Equals(holder)) + return false; + + if (issuer != null && !attrCert.Issuer.Equals(issuer)) + return false; + + if (attributeCertificateValid != null && !attrCert.IsValid(attributeCertificateValid.Value)) + return false; + + if (targetNames.Count > 0 || targetGroups.Count > 0) + { + Asn1OctetString targetInfoExt = attrCert.GetExtensionValue( + X509Extensions.TargetInformation); + + if (targetInfoExt != null) + { + TargetInformation targetinfo; + try + { + targetinfo = TargetInformation.GetInstance( + X509ExtensionUtilities.FromExtensionValue(targetInfoExt)); + } + catch (Exception) + { + return false; + } + + Targets[] targetss = targetinfo.GetTargetsObjects(); + + if (targetNames.Count > 0) + { + bool found = false; + + for (int i = 0; i < targetss.Length && !found; i++) + { + Target[] targets = targetss[i].GetTargets(); + + for (int j = 0; j < targets.Length; j++) + { + GeneralName targetName = targets[j].TargetName; + + if (targetName != null && targetNames.Contains(targetName)) + { + found = true; + break; + } + } + } + if (!found) + { + return false; + } + } + + if (targetGroups.Count > 0) + { + bool found = false; + + for (int i = 0; i < targetss.Length && !found; i++) + { + Target[] targets = targetss[i].GetTargets(); + + for (int j = 0; j < targets.Length; j++) + { + GeneralName targetGroup = targets[j].TargetGroup; + + if (targetGroup != null && targetGroups.Contains(targetGroup)) + { + found = true; + break; + } + } + } + + if (!found) + { + return false; + } + } + } + } + + return true; + } + + public object Clone() + { + return new X509AttrCertStoreSelector(this); + } + + /// The attribute certificate which must be matched. + /// If null is given, any will do. + public IX509AttributeCertificate AttributeCert + { + get { return attributeCert; } + set { this.attributeCert = value; } + } + + [Obsolete("Use AttributeCertificateValid instead")] + public DateTimeObject AttribueCertificateValid + { + get { return attributeCertificateValid; } + set { this.attributeCertificateValid = value; } + } + + /// The criteria for validity + /// If null is given any will do. + public DateTimeObject AttributeCertificateValid + { + get { return attributeCertificateValid; } + set { this.attributeCertificateValid = value; } + } + + /// The holder. + /// If null is given any will do. + public AttributeCertificateHolder Holder + { + get { return holder; } + set { this.holder = value; } + } + + /// The issuer. + /// If null is given any will do. + public AttributeCertificateIssuer Issuer + { + get { return issuer; } + set { this.issuer = value; } + } + + /// The serial number. + /// If null is given any will do. + public BigInteger SerialNumber + { + get { return serialNumber; } + set { this.serialNumber = value; } + } + + /** + * Adds a target name criterion for the attribute certificate to the target + * information extension criteria. The X509AttributeCertificate + * must contain at least one of the specified target names. + *

      + * Each attribute certificate may contain a target information extension + * limiting the servers where this attribute certificate can be used. If + * this extension is not present, the attribute certificate is not targeted + * and may be accepted by any server. + *

      + * + * @param name The name as a GeneralName (not null) + */ + public void AddTargetName( + GeneralName name) + { + targetNames.Add(name); + } + + /** + * Adds a target name criterion for the attribute certificate to the target + * information extension criteria. The X509AttributeCertificate + * must contain at least one of the specified target names. + *

      + * Each attribute certificate may contain a target information extension + * limiting the servers where this attribute certificate can be used. If + * this extension is not present, the attribute certificate is not targeted + * and may be accepted by any server. + *

      + * + * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName + * @throws IOException if a parsing error occurs. + */ + public void AddTargetName( + byte[] name) + { + AddTargetName(GeneralName.GetInstance(Asn1Object.FromByteArray(name))); + } + + /** + * Adds a collection with target names criteria. If null is + * given any will do. + *

      + * The collection consists of either GeneralName objects or byte[] arrays representing + * DER encoded GeneralName structures. + *

      + * + * @param names A collection of target names. + * @throws IOException if a parsing error occurs. + * @see #AddTargetName(byte[]) + * @see #AddTargetName(GeneralName) + */ + public void SetTargetNames( + IEnumerable names) + { + targetNames = ExtractGeneralNames(names); + } + + /** + * Gets the target names. The collection consists of Lists + * made up of an Integer in the first entry and a DER encoded + * byte array or a String in the second entry. + *

      The returned collection is immutable.

      + * + * @return The collection of target names + * @see #setTargetNames(Collection) + */ + public IEnumerable GetTargetNames() + { + return new EnumerableProxy(targetNames); + } + + /** + * Adds a target group criterion for the attribute certificate to the target + * information extension criteria. The X509AttributeCertificate + * must contain at least one of the specified target groups. + *

      + * Each attribute certificate may contain a target information extension + * limiting the servers where this attribute certificate can be used. If + * this extension is not present, the attribute certificate is not targeted + * and may be accepted by any server. + *

      + * + * @param group The group as GeneralName form (not null) + */ + public void AddTargetGroup( + GeneralName group) + { + targetGroups.Add(group); + } + + /** + * Adds a target group criterion for the attribute certificate to the target + * information extension criteria. The X509AttributeCertificate + * must contain at least one of the specified target groups. + *

      + * Each attribute certificate may contain a target information extension + * limiting the servers where this attribute certificate can be used. If + * this extension is not present, the attribute certificate is not targeted + * and may be accepted by any server. + *

      + * + * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName + * @throws IOException if a parsing error occurs. + */ + public void AddTargetGroup( + byte[] name) + { + AddTargetGroup(GeneralName.GetInstance(Asn1Object.FromByteArray(name))); + } + + /** + * Adds a collection with target groups criteria. If null is + * given any will do. + *

      + * The collection consists of GeneralName objects or byte[] + * representing DER encoded GeneralNames. + *

      + * + * @param names A collection of target groups. + * @throws IOException if a parsing error occurs. + * @see #AddTargetGroup(byte[]) + * @see #AddTargetGroup(GeneralName) + */ + public void SetTargetGroups( + IEnumerable names) + { + targetGroups = ExtractGeneralNames(names); + } + + /** + * Gets the target groups. The collection consists of Lists + * made up of an Integer in the first entry and a DER encoded + * byte array or a String in the second entry. + *

      The returned collection is immutable.

      + * + * @return The collection of target groups. + * @see #setTargetGroups(Collection) + */ + public IEnumerable GetTargetGroups() + { + return new EnumerableProxy(targetGroups); + } + + private ISet ExtractGeneralNames( + IEnumerable names) + { + ISet result = new HashSet(); + + if (names != null) + { + foreach (object o in names) + { + if (o is GeneralName) + { + result.Add(o); + } + else + { + result.Add(GeneralName.GetInstance(Asn1Object.FromByteArray((byte[]) o))); + } + } + } + + return result; + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509CertPairStoreSelector.cs b/iTechSharp/srcbc/x509/store/X509CertPairStoreSelector.cs new file mode 100644 index 0000000..2796971 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509CertPairStoreSelector.cs @@ -0,0 +1,92 @@ +using System; + +namespace Org.BouncyCastle.X509.Store +{ + /// + /// This class is an IX509Selector implementation to select + /// certificate pairs, which are e.g. used for cross certificates. The set of + /// criteria is given from two X509CertStoreSelector objects, + /// each of which, if present, must match the respective component of a pair. + /// + public class X509CertPairStoreSelector + : IX509Selector + { + private static X509CertStoreSelector CloneSelector( + X509CertStoreSelector s) + { + return s == null ? null : (X509CertStoreSelector) s.Clone(); + } + + private X509CertificatePair certPair; + private X509CertStoreSelector forwardSelector; + private X509CertStoreSelector reverseSelector; + + public X509CertPairStoreSelector() + { + } + + private X509CertPairStoreSelector( + X509CertPairStoreSelector o) + { + this.certPair = o.CertPair; + this.forwardSelector = o.ForwardSelector; + this.reverseSelector = o.ReverseSelector; + } + + /// The certificate pair which is used for testing on equality. + public X509CertificatePair CertPair + { + get { return certPair; } + set { this.certPair = value; } + } + + /// The certificate selector for the forward part. + public X509CertStoreSelector ForwardSelector + { + get { return CloneSelector(forwardSelector); } + set { this.forwardSelector = CloneSelector(value); } + } + + /// The certificate selector for the reverse part. + public X509CertStoreSelector ReverseSelector + { + get { return CloneSelector(reverseSelector); } + set { this.reverseSelector = CloneSelector(value); } + } + + /// + /// Decides if the given certificate pair should be selected. If + /// obj is not a X509CertificatePair, this method + /// returns false. + /// + /// The X509CertificatePair to be tested. + /// true if the object matches this selector. + public bool Match( + object obj) + { + if (obj == null) + throw new ArgumentNullException("obj"); + + X509CertificatePair pair = obj as X509CertificatePair; + + if (pair == null) + return false; + + if (certPair != null && !certPair.Equals(pair)) + return false; + + if (forwardSelector != null && !forwardSelector.Match(pair.Forward)) + return false; + + if (reverseSelector != null && !reverseSelector.Match(pair.Reverse)) + return false; + + return true; + } + + public object Clone() + { + return new X509CertPairStoreSelector(this); + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509CertStoreSelector.cs b/iTechSharp/srcbc/x509/store/X509CertStoreSelector.cs new file mode 100644 index 0000000..6e550ce --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509CertStoreSelector.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509.Store +{ + public class X509CertStoreSelector + : IX509Selector + { + // TODO Missing criteria? + + private byte[] authorityKeyIdentifier; + private int basicConstraints = -1; + private X509Certificate certificate; + private DateTimeObject certificateValid; + private ISet extendedKeyUsage; + private X509Name issuer; + private bool[] keyUsage; + private ISet policy; + private DateTimeObject privateKeyValid; + private BigInteger serialNumber; + private X509Name subject; + private byte[] subjectKeyIdentifier; + private SubjectPublicKeyInfo subjectPublicKey; + private DerObjectIdentifier subjectPublicKeyAlgID; + + public X509CertStoreSelector() + { + } + + public X509CertStoreSelector( + X509CertStoreSelector o) + { + this.authorityKeyIdentifier = o.AuthorityKeyIdentifier; + this.basicConstraints = o.BasicConstraints; + this.certificate = o.Certificate; + this.certificateValid = o.CertificateValid; + this.extendedKeyUsage = o.ExtendedKeyUsage; + this.issuer = o.Issuer; + this.keyUsage = o.KeyUsage; + this.policy = o.Policy; + this.privateKeyValid = o.PrivateKeyValid; + this.serialNumber = o.SerialNumber; + this.subject = o.Subject; + this.subjectKeyIdentifier = o.SubjectKeyIdentifier; + this.subjectPublicKey = o.SubjectPublicKey; + this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID; + } + + public virtual object Clone() + { + return new X509CertStoreSelector(this); + } + + public byte[] AuthorityKeyIdentifier + { + get { return Arrays.Clone(authorityKeyIdentifier); } + set { authorityKeyIdentifier = Arrays.Clone(value); } + } + + public int BasicConstraints + { + get { return basicConstraints; } + set + { + if (value < -2) + throw new ArgumentException("value can't be less than -2", "value"); + + basicConstraints = value; + } + } + + public X509Certificate Certificate + { + get { return certificate; } + set { this.certificate = value; } + } + + public DateTimeObject CertificateValid + { + get { return certificateValid; } + set { certificateValid = value; } + } + + public ISet ExtendedKeyUsage + { + get { return CopySet(extendedKeyUsage); } + set { extendedKeyUsage = CopySet(value); } + } + + public X509Name Issuer + { + get { return issuer; } + set { issuer = value; } + } + + public string IssuerAsString + { + get { return issuer != null ? issuer.ToString() : null; } + } + + public bool[] KeyUsage + { + get { return CopyBoolArray(keyUsage); } + set { keyUsage = CopyBoolArray(value); } + } + + /// + /// An ISet of DerObjectIdentifier objects. + /// + public ISet Policy + { + get { return CopySet(policy); } + set { policy = CopySet(value); } + } + + public DateTimeObject PrivateKeyValid + { + get { return privateKeyValid; } + set { privateKeyValid = value; } + } + + public BigInteger SerialNumber + { + get { return serialNumber; } + set { serialNumber = value; } + } + + public X509Name Subject + { + get { return subject; } + set { subject = value; } + } + + public string SubjectAsString + { + get { return subject != null ? subject.ToString() : null; } + } + + public byte[] SubjectKeyIdentifier + { + get { return Arrays.Clone(subjectKeyIdentifier); } + set { subjectKeyIdentifier = Arrays.Clone(value); } + } + + public SubjectPublicKeyInfo SubjectPublicKey + { + get { return subjectPublicKey; } + set { subjectPublicKey = value; } + } + + public DerObjectIdentifier SubjectPublicKeyAlgID + { + get { return subjectPublicKeyAlgID; } + set { subjectPublicKeyAlgID = value; } + } + + public virtual bool Match( + object obj) + { + X509Certificate c = obj as X509Certificate; + + if (c == null) + return false; + + if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier)) + return false; + + if (basicConstraints != -1) + { + int bc = c.GetBasicConstraints(); + + if (basicConstraints == -2) + { + if (bc != -1) + return false; + } + else + { + if (bc < basicConstraints) + return false; + } + } + + if (certificate != null && !certificate.Equals(c)) + return false; + + if (certificateValid != null && !c.IsValid(certificateValid.Value)) + return false; + + if (extendedKeyUsage != null) + { + IList eku = c.GetExtendedKeyUsage(); + + // Note: if no extended key usage set, all key purposes are implicitly allowed + + if (eku != null) + { + foreach (DerObjectIdentifier oid in extendedKeyUsage) + { + if (!eku.Contains(oid.Id)) + return false; + } + } + } + + if (issuer != null && !issuer.Equivalent(c.IssuerDN)) + return false; + + if (keyUsage != null) + { + bool[] ku = c.GetKeyUsage(); + + // Note: if no key usage set, all key purposes are implicitly allowed + + if (ku != null) + { + for (int i = 0; i < 9; ++i) + { + if (keyUsage[i] && !ku[i]) + return false; + } + } + } + + if (policy != null) + { + Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies); + if (extVal == null) + return false; + + Asn1Sequence certPolicies = Asn1Sequence.GetInstance( + X509ExtensionUtilities.FromExtensionValue(extVal)); + + if (policy.Count < 1 && certPolicies.Count < 1) + return false; + + bool found = false; + foreach (PolicyInformation pi in certPolicies) + { + if (policy.Contains(pi.PolicyIdentifier)) + { + found = true; + break; + } + } + + if (!found) + return false; + } + + if (privateKeyValid != null) + { + Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod); + if (extVal == null) + return false; + + PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance( + X509ExtensionUtilities.FromExtensionValue(extVal)); + + DateTime dt = privateKeyValid.Value; + DateTime notAfter = pkup.NotAfter.ToDateTime(); + DateTime notBefore = pkup.NotBefore.ToDateTime(); + + if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0) + return false; + } + + if (serialNumber != null && !serialNumber.Equals(c.SerialNumber)) + return false; + + if (subject != null && !subject.Equivalent(c.SubjectDN)) + return false; + + if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier)) + return false; + + if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c))) + return false; + + if (subjectPublicKeyAlgID != null + && !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID)) + return false; + + return true; + } + + private bool[] CopyBoolArray( + bool[] b) + { + return b == null ? null : (bool[]) b.Clone(); + } + + private ISet CopySet( + ISet s) + { + return s == null ? null : new HashSet(s); + } + + private SubjectPublicKeyInfo GetSubjectPublicKey( + X509Certificate c) + { + return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey()); + } + + private bool MatchExtension( + byte[] b, + X509Certificate c, + DerObjectIdentifier oid) + { + if (b == null) + return true; + + Asn1OctetString extVal = c.GetExtensionValue(oid); + + if (extVal == null) + return false; + + return extVal != null && Arrays.AreEqual(b, extVal.GetEncoded()); + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509CollectionStore.cs b/iTechSharp/srcbc/x509/store/X509CollectionStore.cs new file mode 100644 index 0000000..1367cff --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509CollectionStore.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections; + +namespace Org.BouncyCastle.X509.Store +{ + /** + * A simple collection backed store. + */ + internal class X509CollectionStore + : IX509Store + { + private ICollection _local; + + /** + * Basic constructor. + * + * @param collection - initial contents for the store, this is copied. + */ + internal X509CollectionStore( + ICollection collection) + { + _local = new ArrayList(collection); + } + + /** + * Return the matches in the collection for the passed in selector. + * + * @param selector the selector to match against. + * @return a possibly empty collection of matching objects. + */ + public ICollection GetMatches( + IX509Selector selector) + { + if (selector == null) + { + return new ArrayList(_local); + } + + IList result = new ArrayList(); + foreach (object obj in _local) + { + if (selector.Match(obj)) + result.Add(obj); + } + + return result; + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509CollectionStoreParameters.cs b/iTechSharp/srcbc/x509/store/X509CollectionStoreParameters.cs new file mode 100644 index 0000000..a5de819 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509CollectionStoreParameters.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using System.Text; + +namespace Org.BouncyCastle.X509.Store +{ + /// This class contains a collection for collection based X509Stores. + public class X509CollectionStoreParameters + : IX509StoreParameters + { + private readonly ArrayList collection; + + /// + /// Constructor. + ///

      + /// The collection is copied. + ///

      + ///
      + /// The collection containing X.509 object types. + /// If collection is null. + public X509CollectionStoreParameters( + ICollection collection) + { + if (collection == null) + throw new ArgumentNullException("collection"); + + this.collection = new ArrayList(collection); + } + + // TODO Do we need to be able to Clone() these, and should it really be shallow? +// /** +// * Returns a shallow clone. The returned contents are not copied, so adding +// * or removing objects will effect this. +// * +// * @return a shallow clone. +// */ +// public object Clone() +// { +// return new X509CollectionStoreParameters(collection); +// } + + /// Returns a copy of the ICollection. + public ICollection GetCollection() + { + return new ArrayList(collection); + } + + /// Returns a formatted string describing the parameters. + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("X509CollectionStoreParameters: [\n"); + sb.Append(" collection: " + collection + "\n"); + sb.Append("]"); + return sb.ToString(); + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509CrlStoreSelector.cs b/iTechSharp/srcbc/x509/store/X509CrlStoreSelector.cs new file mode 100644 index 0000000..8e03d24 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509CrlStoreSelector.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509.Store +{ + public class X509CrlStoreSelector + : IX509Selector + { + // TODO Missing criteria? + + private X509Certificate certificateChecking; + private DateTimeObject dateAndTime; + private ICollection issuers; + private BigInteger maxCrlNumber; + private BigInteger minCrlNumber; + + private IX509AttributeCertificate attrCertChecking; + private bool completeCrlEnabled; + private bool deltaCrlIndicatorEnabled; + private byte[] issuingDistributionPoint; + private bool issuingDistributionPointEnabled; + private BigInteger maxBaseCrlNumber; + + public X509CrlStoreSelector() + { + } + + public X509CrlStoreSelector( + X509CrlStoreSelector o) + { + this.certificateChecking = o.CertificateChecking; + this.dateAndTime = o.DateAndTime; + this.issuers = o.Issuers; + this.maxCrlNumber = o.MaxCrlNumber; + this.minCrlNumber = o.MinCrlNumber; + + this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled; + this.completeCrlEnabled = o.CompleteCrlEnabled; + this.maxBaseCrlNumber = o.MaxBaseCrlNumber; + this.attrCertChecking = o.AttrCertChecking; + this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled; + this.issuingDistributionPoint = o.IssuingDistributionPoint; + } + + public virtual object Clone() + { + return new X509CrlStoreSelector(this); + } + + public X509Certificate CertificateChecking + { + get { return certificateChecking; } + set { certificateChecking = value; } + } + + public DateTimeObject DateAndTime + { + get { return dateAndTime; } + set { dateAndTime = value; } + } + + /// + /// An ICollection of X509Name objects + /// + public ICollection Issuers + { + get { return new ArrayList(issuers); } + set { issuers = new ArrayList(value); } + } + + public BigInteger MaxCrlNumber + { + get { return maxCrlNumber; } + set { maxCrlNumber = value; } + } + + public BigInteger MinCrlNumber + { + get { return minCrlNumber; } + set { minCrlNumber = value; } + } + + /** + * The attribute certificate being checked. This is not a criterion. + * Rather, it is optional information that may help a {@link X509Store} find + * CRLs that would be relevant when checking revocation for the specified + * attribute certificate. If null is specified, then no such + * optional information is provided. + * + * @param attrCert the IX509AttributeCertificate being checked (or + * null) + * @see #getAttrCertificateChecking() + */ + public IX509AttributeCertificate AttrCertChecking + { + get { return attrCertChecking; } + set { this.attrCertChecking = value; } + } + + /** + * If true only complete CRLs are returned. Defaults to + * false. + * + * @return true if only complete CRLs are returned. + */ + public bool CompleteCrlEnabled + { + get { return completeCrlEnabled; } + set { this.completeCrlEnabled = value; } + } + + /** + * Returns if this selector must match CRLs with the delta CRL indicator + * extension set. Defaults to false. + * + * @return Returns true if only CRLs with the delta CRL + * indicator extension are selected. + */ + public bool DeltaCrlIndicatorEnabled + { + get { return deltaCrlIndicatorEnabled; } + set { this.deltaCrlIndicatorEnabled = value; } + } + + /** + * The issuing distribution point. + *

      + * The issuing distribution point extension is a CRL extension which + * identifies the scope and the distribution point of a CRL. The scope + * contains among others information about revocation reasons contained in + * the CRL. Delta CRLs and complete CRLs must have matching issuing + * distribution points.

      + *

      + * The byte array is cloned to protect against subsequent modifications.

      + *

      + * You must also enable or disable this criteria with + * {@link #setIssuingDistributionPointEnabled(bool)}.

      + * + * @param issuingDistributionPoint The issuing distribution point to set. + * This is the DER encoded OCTET STRING extension value. + * @see #getIssuingDistributionPoint() + */ + public byte[] IssuingDistributionPoint + { + get { return Arrays.Clone(issuingDistributionPoint); } + set { this.issuingDistributionPoint = Arrays.Clone(value); } + } + + /** + * Whether the issuing distribution point criteria should be applied. + * Defaults to false. + *

      + * You may also set the issuing distribution point criteria if not a missing + * issuing distribution point should be assumed.

      + * + * @return Returns if the issuing distribution point check is enabled. + */ + public bool IssuingDistributionPointEnabled + { + get { return issuingDistributionPointEnabled; } + set { this.issuingDistributionPointEnabled = value; } + } + + /** + * The maximum base CRL number. Defaults to null. + * + * @return Returns the maximum base CRL number. + * @see #setMaxBaseCRLNumber(BigInteger) + */ + public BigInteger MaxBaseCrlNumber + { + get { return maxBaseCrlNumber; } + set { this.maxBaseCrlNumber = value; } + } + + public virtual bool Match( + object obj) + { + X509Crl c = obj as X509Crl; + + if (c == null) + return false; + + if (dateAndTime != null) + { + DateTime dt = dateAndTime.Value; + DateTime tu = c.ThisUpdate; + DateTimeObject nu = c.NextUpdate; + + if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0) + return false; + } + + if (issuers != null) + { + X509Name i = c.IssuerDN; + + bool found = false; + + foreach (X509Name issuer in issuers) + { + if (issuer.Equivalent(i)) + { + found = true; + break; + } + } + + if (!found) + return false; + } + + if (maxCrlNumber != null || minCrlNumber != null) + { + Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber); + if (extVal == null) + return false; + + BigInteger cn = CrlNumber.GetInstance( + X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue; + + if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0) + return false; + + if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0) + return false; + } + + DerInteger dci = null; + try + { + Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator); + if (bytes != null) + { + dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes)); + } + } + catch (Exception) + { + return false; + } + + if (dci == null) + { + if (DeltaCrlIndicatorEnabled) + return false; + } + else + { + if (CompleteCrlEnabled) + return false; + + if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0) + return false; + } + + if (issuingDistributionPointEnabled) + { + Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint); + if (issuingDistributionPoint == null) + { + if (idp != null) + return false; + } + else + { + if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint)) + return false; + } + } + + return true; + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509StoreException.cs b/iTechSharp/srcbc/x509/store/X509StoreException.cs new file mode 100644 index 0000000..f6a5e23 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509StoreException.cs @@ -0,0 +1,25 @@ +using System; + +namespace Org.BouncyCastle.X509.Store +{ + public class X509StoreException + : Exception + { + public X509StoreException() + { + } + + public X509StoreException( + string message) + : base(message) + { + } + + public X509StoreException( + string message, + Exception e) + : base(message, e) + { + } + } +} diff --git a/iTechSharp/srcbc/x509/store/X509StoreFactory.cs b/iTechSharp/srcbc/x509/store/X509StoreFactory.cs new file mode 100644 index 0000000..9cddb99 --- /dev/null +++ b/iTechSharp/srcbc/x509/store/X509StoreFactory.cs @@ -0,0 +1,44 @@ +using System; +using System.Globalization; + +namespace Org.BouncyCastle.X509.Store +{ + public sealed class X509StoreFactory + { + private X509StoreFactory() + { + } + + public static IX509Store Create( + string type, + IX509StoreParameters parameters) + { + if (type == null) + throw new ArgumentNullException("type"); + + string[] parts = type.ToUpper(CultureInfo.InvariantCulture).Split('/'); + + if (parts.Length < 2) + throw new ArgumentException("type"); + + + switch (parts[0]) + { + case "ATTRIBUTECERTIFICATE": + case "CERTIFICATE": + case "CERTIFICATEPAIR": + case "CRL": + { + if (parts[1] == "COLLECTION") + { + X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters; + return new X509CollectionStore(p.GetCollection()); + } + break; + } + } + + throw new NoSuchStoreException("X.509 store type '" + type + "' not available."); + } + } +}